···11+# CLAUDE.md
22+33+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44+55+## Build & Test Commands
66+77+```bash
88+cargo fmt -- --check # check formatting
99+cargo clippy --all-targets -- -D warnings # lint
1010+cargo test # run all 39 tests
1111+cargo test refs::tests # run tests in a specific module
1212+cargo build --release # release build
1313+```
1414+1515+CI runs all four checks on push/PR to main (.github/workflows/ci.yml).
1616+1717+## Architecture
1818+1919+Rust CLI (`kip`) for kipclip.com, an AT Protocol bookmark manager. Uses `jacquard` for OAuth (PKCE + DPoP) and typed XRPC calls to the user's PDS.
2020+2121+```
2222+main.rs → clap parsing + command dispatch
2323+commands/* → thin handlers, each receives a PdsClient
2424+kipclip/* → core library (auth, pds, types, enrich, refs, display, config)
2525+```
2626+2727+**Data flow**: CLI parses args → command handler gets `PdsClient` → `pds.rs` builds typed jacquard requests → PDS returns records → command formats output.
2828+2929+**Sidecar pattern**: Bookmarks (`community.lexicon.bookmarks.bookmark`) and annotations (`com.kipclip.annotation`) share the same rkey. Annotations hold enrichment metadata (title, description, favicon, image). Both are created/deleted together.
3030+3131+**Ref resolution** (`refs.rs`): Users address bookmarks by rkey prefix (min 4 chars). Fetches all bookmarks and matches prefix, errors on ambiguous matches.
3232+3333+**Enrichment** (`enrich.rs`): Client-side HTML parsing via regex-lite. Extracts og:title, og:description, og:image, twitter:image, favicon. 10s timeout, 512KB body limit. Falls back gracefully on failure.
3434+3535+## Key Jacquard Patterns
3636+3737+- Session type: `OAuthSession<JacquardResolver, FileAuthStore>`
3838+- Restore session: `OAuthClient::restore(&did, &session_id)`
3939+- Rkey conversion: `RecordKey(Rkey::new(rkey)?)`
4040+- Cursor for pagination: `CowStr::from(cursor_string)`
4141+- Record values: use `.to_data()` for conversion
4242+4343+## Config & Session Storage
4444+4545+All under `~/.config/kipclip/`:
4646+- `session.json` — OAuth tokens (via jacquard's FileAuthStore)
4747+- `whoami.json` — cached DID, handle, session_id
4848+- Files written atomically with 0600 permissions (Unix)
4949+5050+## Testing
5151+5252+Tests are colocated (`#[cfg(test)]` blocks). No external services or env vars — test helpers build fake `EnrichedBookmark` instances with known data. Tests cover filtering, parsing, ref matching, and display logic.
5353+5454+## Style
5555+5656+- Rust edition 2024, max line width 100, field init shorthand enabled
5757+- MSRV: 1.85 (clippy.toml)
5858+- Errors via `miette::Result` with contextual `miette!()` wrapping
5959+- Module name is `kipclip` (not `lib`) to avoid `special_module_name` warning
+1-1
README.md
···57575858## How it works
59596060-kip authenticates via AT Protocol OAuth (PKCE + DPoP) using the [jacquard](https://crates.io/crates/jacquard) Rust SDK. Bookmarks are read from and written to your PDS directly. URL metadata (title, description, favicon) is fetched from the kipclip.com enrichment endpoint.
6060+kip authenticates via AT Protocol OAuth (PKCE + DPoP) using the [jacquard](https://crates.io/crates/jacquard) Rust SDK. Bookmarks are read from and written to your PDS directly. URL metadata (title, description, favicon, image) is extracted client-side by fetching and parsing the bookmarked page.
61616262AT Protocol collections used:
6363- `community.lexicon.bookmarks.bookmark` — bookmark records