commits
shows platform badge (e.g., "pckt", "offprint") for non-leaflet results
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- include platform field in all document search results
- add ?platform= query param to /search endpoint
- filter by platform in-memory (simple approach for initial impl)
- publications only shown when platform=leaflet or unfiltered
- update findSimilar query to include platform
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- adds STANDARD_DOCUMENT and STANDARD_PUBLICATION constants
- isDocumentCollection() and isPublicationCollection() helper functions
- TAP now processes both pub.leaflet.* and site.standard.* records
- extractor handles both via textContent (standard) and block parsing (leaflet)
this enables indexing pckt.blog content alongside leaflet.pub
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- new extractor.zig with extractDocument() and detectPlatform()
- uses textContent field for standard.site records (no block parsing needed)
- falls back to leaflet block parsing for pub.leaflet.* records
- detects platform from content.$type prefix (leaflet, pckt, offprint)
- ExtractedDocument owns allocated memory, has deinit() method
- explicit error types (Allocator.Error) for all internal functions
- uses @tagName for Platform.name()
- StaticStringMap for plaintext block types
- indexer now stores platform and source_collection
- removed inline extraction code from tap.zig (~100 lines)
adds test infrastructure:
- zig build test step in build.zig
- tests for buildFtsQuery (8 cases)
- tests for Platform.fromContentType and Platform.name
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
portable loading.js module:
- skeleton shimmer while loading
- "waking up" message after 2s threshold (fly.io cold start)
- smooth reveal on data load
designed to be easily copied to other projects
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
prep for multi-platform indexing (standard.site ecosystem):
- platform TEXT: identifies source platform (leaflet, pckt, offprint)
- source_collection TEXT: the lexicon collection name
backfills existing records as platform='leaflet', source_collection='pub.leaflet.document'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- similarity_cache table for /similar endpoint (invalidates on doc count change)
- cache_hits/cache_misses counters in stats
- loading indicator for "related to" results in frontend
- planning doc for standard-search expansion
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- use vector_distance_cos() instead of vector_top_k() with DiskANN index
(Turso's index has ~60s write latency per row, brute-force is ~0.15s)
- add retry logic and batched writes to backfill script
- increase concurrency to 8 workers for faster embedding backfill
- document embeddings workflow in README
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- move activity.zig out of db/ (not db-related)
- move search.zig to src/ (application logic)
- rename write.zig to indexer.zig at src/
- move stats.zig to src/ (application logic)
- slim db/mod.zig to 24 lines (just init + getClient)
db/ now purely infrastructure (Client, Row, schema)
src/ has domain-focused modules (search, indexer, stats, activity)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- split db/mod.zig (527→110 lines) into activity, search, stats, write
- extract dashboard HTML/CSS/JS to site/ for Cloudflare Pages
- add /api/dashboard JSON endpoint, /dashboard redirects to CF Pages
- upgrade zat to 0.1.0 (tangled.sh), use CommitAction enum in tap.zig
- link stack section in README to bsky post
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add zat dependency for ATProto primitives
- replace hand-rolled Did/AtUri with zat.Did.parse
- use zat.json.extractAt for type-safe JSON parsing in tap.zig
- fix quoted phrase search (pass through to FTS5 unchanged)
- redirect zig-patterns.md to notes repo
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
prevents hallucination of incorrect URLs by including
the actual web URL in the response
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- use OR between search terms with BM25 ranking for better recall
- decode + as space in query params (form-urlencoded)
- lower MCP search default limit from 20 to 5
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- fix backend URL to leaflet-search-backend.fly.dev
- update pdsx to latest for target_repo support
- extract content from leaflet's pages[].blocks[].block.plaintext structure
- handle DotDict by converting to dict before accessing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- fastmcp-based server for searching leaflet publications
- tools: search, get_document, find_similar, get_tags, get_stats, get_popular
- prompts: usage_guide, search_tips
- .claude-plugin for marketplace integration
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
relay.fire.hose.cam doesn't support listReposByCollection,
which breaks the crawler's network enumeration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- inline activity tracking into db/mod.zig
- inline domain types (Did, AtUri) into tap.zig
- remove activity.zig and types.zig
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- activity.zig: ring buffer for 6s search activity window
- types.zig: Did and AtUri types with parse-time validation
- tap.zig: use domain types for better type safety
- dashboard/server: /activity endpoint and simple live display
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add /similar endpoint for finding semantically related documents
- add tombstones table for tracking deleted records
- backfill script for embedding documents via Voyage AI (3470 docs done)
- show "related to [top result]" section at bottom of search results
- helper scripts for checking vector index and testing queries
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add docs/zig-patterns.md and docs/turso-hrana.md
- mod.zig: add SearchResultJson, TagJson, PopularJson types
- mod.zig: add Doc.toJson() and Pub.toJson() methods
- mod.zig: simplify search, getTags, getPopular functions
- dashboard.zig: add TagJson, TimelineJson, PubJson types
- dashboard.zig: simplify format functions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- define Hrana protocol types (Value, Stmt, ExecuteReq, CloseReq)
- use optional args field (?[]const Value) with emit_null_optional_fields=false
- jw.write(struct) instead of manual begin/end calls
- add link to Hrana spec in comments
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This reverts commit 9af6ef294580de894fdc0abb9706470027db547f.
- add module docstring with turso api link
- define request types as structs for json serialization
- use jw.write(struct) instead of verbose begin/end calls
- extract validateArgs function
- remove redundant comments (compile time is implied)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- delete dead stats.zig (never imported)
- merge dashboard_data.zig into dashboard.zig
- rename http.zig → server.zig
- restructure turso.zig → Client.zig (file-as-type pattern)
- keep result.zig as namespace (multiple related types)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
add batch query support to turso client for pipeline API,
reduce dashboard data fetching from 5 round trips to 1.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- simplified dashboard to match main site aesthetic
- removed overwrought terminal effects (CRT lines, box-drawing)
- added bar chart favicon for stats page
- moved tap primary_region from ewr to iad
- extracted dashboard data fetching to dashboard_data.zig
- removed backend/notes directory
- reordered stack in README
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- store service_started_at timestamp in stats table (set once, never changes)
- dashboard shows "service age" calculated from that epoch
- survives deploys/restarts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
"filter by tag:" makes it clear these are content tags, not query counts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add quotes around search terms (italic)
- label as "popular searches:" not "try:"
- add separator line below suggestions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- move popular searches under search box as "try: x · y · z"
- add dashboard link to stats footer
- simplify empty state
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- change label from "trending" to "popular searches"
- add ↗ arrow prefix to search items
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- stats table: single row for lifetime search/error counts
- popular_searches table: track query counts
- /popular endpoint: returns top N searched queries
- frontend: show trending searches in empty state
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- stats.zig: atomic counters for searches, errors, uptime
- dashboard.zig: HTML template with live uptime ticker
- shows session stats, db counts, top 20 tags
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- remove FTS5 snippet highlighting (was highlighting entire matched words)
- add frontend highlighting that matches exactly what user typed
- "whats" now highlights "whats" in "WhatsApp", not the whole word
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
"whats up" now becomes "whats up*" instead of "whats* up*"
prevents false matches like "WhatsApp" from "whats"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- struct fields now match JSON output (basePath, createdAt, hasPublication)
- /tags returns error object instead of empty array on failure
- API_URL auto-detects localhost for local development
- UI shows "(documents only)" hint when filtering by tag
- added doc comments explaining type derivation logic
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- turso client now persists http connection instead of creating per query
- /stats uses single query with subselects instead of two round trips
- move fromRow to domain structs (Doc, Pub, TagCount)
- update zql hash
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- DocsByTag, DocsByFtsAndTag, DocsByFts with :name params
- PubSearch with :query param
- cleaner: `.bind(.{ .query = fts_query, .tag = tag })`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add zql dependency for column extraction and struct mapping
- refactor db.zig into db/ module (mod.zig, turso.zig, schema.zig, result.zig)
- use zql.Query for compile-time column validation
- DocQuery.fromRow(Doc, row) replaces manual index lookups
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
"cat" now matches "catch", "category", etc. by appending * to each search term.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- allow searching with just a tag (no query required)
- add tag-only SQL query in db.zig
- friendlier error message for empty search
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- og tags now include tag param when present
- clearTag refreshes results if query exists
- simplify tagline to "search for leaflet"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
shows platform badge (e.g., "pckt", "offprint") for non-leaflet results
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- include platform field in all document search results
- add ?platform= query param to /search endpoint
- filter by platform in-memory (simple approach for initial impl)
- publications only shown when platform=leaflet or unfiltered
- update findSimilar query to include platform
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- adds STANDARD_DOCUMENT and STANDARD_PUBLICATION constants
- isDocumentCollection() and isPublicationCollection() helper functions
- TAP now processes both pub.leaflet.* and site.standard.* records
- extractor handles both via textContent (standard) and block parsing (leaflet)
this enables indexing pckt.blog content alongside leaflet.pub
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- new extractor.zig with extractDocument() and detectPlatform()
- uses textContent field for standard.site records (no block parsing needed)
- falls back to leaflet block parsing for pub.leaflet.* records
- detects platform from content.$type prefix (leaflet, pckt, offprint)
- ExtractedDocument owns allocated memory, has deinit() method
- explicit error types (Allocator.Error) for all internal functions
- uses @tagName for Platform.name()
- StaticStringMap for plaintext block types
- indexer now stores platform and source_collection
- removed inline extraction code from tap.zig (~100 lines)
adds test infrastructure:
- zig build test step in build.zig
- tests for buildFtsQuery (8 cases)
- tests for Platform.fromContentType and Platform.name
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
portable loading.js module:
- skeleton shimmer while loading
- "waking up" message after 2s threshold (fly.io cold start)
- smooth reveal on data load
designed to be easily copied to other projects
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
prep for multi-platform indexing (standard.site ecosystem):
- platform TEXT: identifies source platform (leaflet, pckt, offprint)
- source_collection TEXT: the lexicon collection name
backfills existing records as platform='leaflet', source_collection='pub.leaflet.document'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- similarity_cache table for /similar endpoint (invalidates on doc count change)
- cache_hits/cache_misses counters in stats
- loading indicator for "related to" results in frontend
- planning doc for standard-search expansion
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- use vector_distance_cos() instead of vector_top_k() with DiskANN index
(Turso's index has ~60s write latency per row, brute-force is ~0.15s)
- add retry logic and batched writes to backfill script
- increase concurrency to 8 workers for faster embedding backfill
- document embeddings workflow in README
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- move activity.zig out of db/ (not db-related)
- move search.zig to src/ (application logic)
- rename write.zig to indexer.zig at src/
- move stats.zig to src/ (application logic)
- slim db/mod.zig to 24 lines (just init + getClient)
db/ now purely infrastructure (Client, Row, schema)
src/ has domain-focused modules (search, indexer, stats, activity)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- split db/mod.zig (527→110 lines) into activity, search, stats, write
- extract dashboard HTML/CSS/JS to site/ for Cloudflare Pages
- add /api/dashboard JSON endpoint, /dashboard redirects to CF Pages
- upgrade zat to 0.1.0 (tangled.sh), use CommitAction enum in tap.zig
- link stack section in README to bsky post
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add zat dependency for ATProto primitives
- replace hand-rolled Did/AtUri with zat.Did.parse
- use zat.json.extractAt for type-safe JSON parsing in tap.zig
- fix quoted phrase search (pass through to FTS5 unchanged)
- redirect zig-patterns.md to notes repo
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- fix backend URL to leaflet-search-backend.fly.dev
- update pdsx to latest for target_repo support
- extract content from leaflet's pages[].blocks[].block.plaintext structure
- handle DotDict by converting to dict before accessing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- fastmcp-based server for searching leaflet publications
- tools: search, get_document, find_similar, get_tags, get_stats, get_popular
- prompts: usage_guide, search_tips
- .claude-plugin for marketplace integration
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- activity.zig: ring buffer for 6s search activity window
- types.zig: Did and AtUri types with parse-time validation
- tap.zig: use domain types for better type safety
- dashboard/server: /activity endpoint and simple live display
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add /similar endpoint for finding semantically related documents
- add tombstones table for tracking deleted records
- backfill script for embedding documents via Voyage AI (3470 docs done)
- show "related to [top result]" section at bottom of search results
- helper scripts for checking vector index and testing queries
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add docs/zig-patterns.md and docs/turso-hrana.md
- mod.zig: add SearchResultJson, TagJson, PopularJson types
- mod.zig: add Doc.toJson() and Pub.toJson() methods
- mod.zig: simplify search, getTags, getPopular functions
- dashboard.zig: add TagJson, TimelineJson, PubJson types
- dashboard.zig: simplify format functions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- define Hrana protocol types (Value, Stmt, ExecuteReq, CloseReq)
- use optional args field (?[]const Value) with emit_null_optional_fields=false
- jw.write(struct) instead of manual begin/end calls
- add link to Hrana spec in comments
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add module docstring with turso api link
- define request types as structs for json serialization
- use jw.write(struct) instead of verbose begin/end calls
- extract validateArgs function
- remove redundant comments (compile time is implied)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- delete dead stats.zig (never imported)
- merge dashboard_data.zig into dashboard.zig
- rename http.zig → server.zig
- restructure turso.zig → Client.zig (file-as-type pattern)
- keep result.zig as namespace (multiple related types)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- simplified dashboard to match main site aesthetic
- removed overwrought terminal effects (CRT lines, box-drawing)
- added bar chart favicon for stats page
- moved tap primary_region from ewr to iad
- extracted dashboard data fetching to dashboard_data.zig
- removed backend/notes directory
- reordered stack in README
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- stats table: single row for lifetime search/error counts
- popular_searches table: track query counts
- /popular endpoint: returns top N searched queries
- frontend: show trending searches in empty state
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- remove FTS5 snippet highlighting (was highlighting entire matched words)
- add frontend highlighting that matches exactly what user typed
- "whats" now highlights "whats" in "WhatsApp", not the whole word
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- struct fields now match JSON output (basePath, createdAt, hasPublication)
- /tags returns error object instead of empty array on failure
- API_URL auto-detects localhost for local development
- UI shows "(documents only)" hint when filtering by tag
- added doc comments explaining type derivation logic
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- turso client now persists http connection instead of creating per query
- /stats uses single query with subselects instead of two round trips
- move fromRow to domain structs (Doc, Pub, TagCount)
- update zql hash
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add zql dependency for column extraction and struct mapping
- refactor db.zig into db/ module (mod.zig, turso.zig, schema.zig, result.zig)
- use zql.Query for compile-time column validation
- DocQuery.fromRow(Doc, row) replaces manual index lookups
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>