From 83d1c5abe623fed74fec919742f8041cc2df6e2e Mon Sep 17 00:00:00 2001 From: Isaac Corbrey Date: Mon, 17 Aug 2026 09:22:55 -0400 Subject: [PATCH] skills: Dump new ones --- modules/home/skills/atproto.md | 155 +++++++++++++++++++++++++++ modules/home/skills/code-comments.md | 104 ++++++++++++++---- 2 files changed, 237 insertions(+), 22 deletions(-) create mode 100644 modules/home/skills/atproto.md diff --git a/modules/home/skills/atproto.md b/modules/home/skills/atproto.md new file mode 100644 index 0000000..d8b40b5 --- /dev/null +++ b/modules/home/skills/atproto.md @@ -0,0 +1,155 @@ +--- +name: atproto +description: Load this skill for any task touching AT Protocol data — writing or auditing lexicon schema modules, fetching or resolving records, handling blobs or rich-text facets, caching remote records, designing conversions between vocabulary-specific record types, or exploring published data across the network. +--- + +# Accurate Atproto for Autonomous Agents + +Web reflexes (memoize URLs, fetch by identifier, one semantic per key) +mostly transfer to atproto; failures cluster where identity, content +addressing, and open vocabulary are layered on top. Each section names one +such place. + +## A strong ref pins a CID, not a resource + +An `at://` URI plus CID pins exactly one revision of a record; the URI +alone resolves to whatever currently exists, and edits move the CID while +every quotation carries the old ref — so URI-only serving silently renders +the wrong revision once anything upstream changes. + +Recipes: + +- Fetching because a ref pointed there? Compare the response's returned + CID against the ref's. Equal → proceed; different → the quotation + diverged: render-with-marker or degrade to the bare link — never + silently substitute current-state for pinned-state. +- Cache in two tiers: CID-keyed entries are written once, after CID + verification, and are effectively permanent (content-addressed copies + survive later deletion); URI-keyed entries carry a TTL. Negative-cache + missing records briefly (minutes-scale) — deletions are routine; + permanent caching of absence is a policy decision. +- Cache raw record JSON, not converted application models, re-validating + through the caller's current schema on every read — raw JSON fails + loudly when the schema tightens; cached converted shapes quietly render + stale structure forever. + +## Decompose the AT URI before fetching + +Derive `{repo, collection, rkey}` by parsing the URI; never supply them +from ambient defaults. References point into foreign repositories — a +fetch helper defaulting the repo to the local user's DID works in tests +and breaks at the first foreign citation. Beware validation-only URI +schemas too: a branded type that checks shape without exposing components +forces callers back onto guesswork. Normalize handle authorities through +DID resolution when the call must be repo-precise. + +## DIDs have methods; blobs live on the author's PDS + +1. **Identity resolution is method-dispatched.** Directory-based lookup + answers `did:plc:` only; `did:web:` resolves via + `https:///.well-known/atproto-did`. Both occur in the wild, so + a single-method resolver is a latent outage. +2. **Blobs are server-local.** An embedded post's images resolve against + the post *author's* PDS via + `/xrpc/com.atproto.sync.getBlob?did=&cid=` — never + the viewing site's own PDS. Endpoint construction is resolver + knowledge; renderers cannot reconstruct it. + +Memoize the DID→PDS mapping in-process; identity documents change almost +never, and per-record re-resolution multiplies latency. + +## Convert offline; resolve online + +Keep synchronous conversion (records → internal model) strictly IO-free; +put all fetching in a second async pass that walks the converted tree, +collects pointers, and fills payloads. Mixing them makes every unit test +a network test. + +Pass design: resolve references concurrently under a small bound with +in-flight deduplication; recurse into embeds with a depth cap and a +visited set (quote cycles occur). On failure, leave the pointer variant in +place — an un-upgraded pointer *is* the failure state, and every renderer +already knows how to show one. No parallel "unresolved" wrapper types; the +pointer-plus-optional-payload pair keeps both states representable. + +## Know where the bytes live + +Three layers cover all reading: XRPC primitives every PDS/relay must serve, +community frontends built on them, and identity infrastructure. Explore +through the frontends (fast, human-shaped); ship through the primitives — +a vanished third-party service should never take down a production fetch +path. + +- **Direct reads** — `com.atproto.repo.getRecord` / `listRecords` against + any repo's PDS, and `com.atproto.sync.listReposByCollection` on the + relay. Always-available ground truth; debug wrapper surprises here. +- **[atproto.md](https://atproto.md)** — auth-free markdown views over + the same PDS data: `at://{actor}[/{collection}[/{rkey}]]`, + `/backlinks/{uri}`, `/discover/{collection}`, `/lexicon/{nsid}`, + `/resolve/{actor}`, `/plc/audit/{actor}`. Cheapest way to inspect a + record, size a vocabulary's adoption, or diff a published definition. +- **Constellation** ([microcosm.blue](https://constellation.microcosm.blue)) + — firehose-indexed backlink search: every link on the network by target, + source collection, and JSON path, via + `https://constellation.microcosm.blue/xrpc/blue.microcosm.links.getBacklinks?subject=` + (params include `source`, `did`, `reverse`, pagination). Answers + who-replies/-likes/-quotes-target beyond any one repo; also the source + for "posts citing this document" surfaces. +- **PLC directory** (`plc.directory`) — DID documents plus the full + operation log (`/{did}/audit-data`: PDS migrations, handle changes, key + rotations). Useful when something that worked yesterday resolves + elsewhere today. + +For vocabulary truth specifically, two independent paths converge on the +same bytes: fetch the publisher's `com.atproto.lexicon.schema` record from +any repo hosting it, or resolve DNS `_lexicon.` TXT to the +publishing DID and read it there. Disagreement between hand-written +schema modules and either path means the module loses. + +## The wire outruns your schema + +- **Unknown vocabulary arrives regardless.** Every union member carries a + `$type`, including members you never enumerated. An unrecognized `$type` + is skipped, not errored. Drop features that fail parsing; drop spans + left empty by the drops. +- **Facet offsets are UTF-8 byte offsets**, not JS string indices. They + agree on pure ASCII and diverge once any earlier character is multibyte. + Convert before any `.slice()`. +- **Memory is not a lexicon.** Hand-written schema modules drift from the + published definition. Cross-check against the vocabulary's + `com.atproto.lexicon.schema` record before trusting a remembered field + shape. + +## Enumeration beats sampling for adoption questions + +Listing one repo's records answers "does this record exist", not "is this +vocabulary used". Evidence comes from network-wide enumeration: +relay-backed `com.atproto.sync.listReposByCollection` for adopting repos, +firehose-indexed backlink indexes (Constellation-style) for links into a +target. A vocabulary publisher's own repository may hold zero records of +its most-adopted lexicon — single-repo sampling misleads both ways. Check +adoption breadth before scoping a converter, cache tier, or renderer +branch. + +## Quick reference + +| Situation | What to actually do | +| --- | --- | +| Fetched a record because a strong ref pointed there | Compare response CID to ref CID; surface divergence explicitly | +| Building a persistent record cache | CID-keyed write-once tier + URI-keyed TTL tier; brief negative caching | +| Tempted to cache converted shapes | Cache raw JSON; re-validate through the current schema on read | +| About to fetch by a record reference | Parse the AT URI into parts; no implicit repo default | +| Resolving a DID to a PDS | Dispatch on method (plc → directory, web → well-known); memoize | +| Constructing an embedded blob's URL | Author's PDS + `com.atproto.sync.getBlob`, never the viewer's | +| Conversion function wants to `await` | Split: pure conversion now, async resolution pass after | +| A fetched-embed request failed | Leave the pointer variant in place; renderers already handle it | +| Walking an embed/quote graph | Depth cap + visited set on uri+cid | +| Encountered unknown `$type` in a union | Skip it; never throw on unrecognized vocabulary | +| Slicing text at a facet boundary | Convert UTF-8 byte offsets → string indices first | +| Wrote a lexicon schema module from memory | Verify against the published `com.atproto.lexicon.schema` record | +| Need to inspect a record or list a collection | PDS `getRecord`/`listRecords` first; markdown proxy for a readable view | +| Sizing whether a vocabulary is worth supporting | `discover/{collection}` / `listReposByCollection` — enumerate, don't sample | +| Finding who quotes/likes/replies to a target | Firehose backlink index by target URI; source collection + JSON path tell you which field | +| Suspecting lexicon drift in a schema module | Fetch the published `com.atproto.lexicon.schema` record; hand-written version loses | +| Something resolved differently than yesterday | PLC audit log (`/{did}/audit-data`) — migrations, handle changes, key rotations | +| Judging whether a lexicon merits support | Enumerate adopting repos network-wide; distrust single-repo samples | diff --git a/modules/home/skills/code-comments.md b/modules/home/skills/code-comments.md index d49d0df..df44d8d 100644 --- a/modules/home/skills/code-comments.md +++ b/modules/home/skills/code-comments.md @@ -5,46 +5,106 @@ description: Load this skill before writing or substantially revising a code com # Code Comments for Cohabiting Robots -Write comments that brief the reader, not document your work. +A comment is a label of intent, not a proof of correctness. Its job is to +stop a future reader from deleting deliberate code as dead weight or a +no-op — not to pre-argue every consequence so nobody ever has to think. -The reader is a future engineer about to modify or rely on this code. Give -them context the code can't — fast. Don't reconstruct how the code works; -the code shows that. +The reader is a competent engineer about to modify or rely on this code. +They can read the language, and they have working intuition about the +domain. Write for that reader, not for one who needs the mechanism +re-derived from scratch. -## The four ingredients +## Default to one line -- **Observation** — a fact about the world that makes the constraint legible. -- **Consequence** — what breaks if you do the naive thing. +State what the code is *for*, in plain words, and stop. Don't chase the +consequence chain down to why it matters — a competent reader either +already has that intuition, or can rebuild it faster from the code than +from your paragraph about it. + +``` +// Bad — pre-argues a consequence the reader can derive unassisted. +// Ranks resources by how disruptive it is to preempt them: a lock +// holder mid-transaction can't be preempted without corrupting state, +// while a prefetch task tolerates being paused and resumed for free. +priority(resource) -> ... + +// Good — states intent, trusts the reader with the rest. +// Ranks resources by how okay it is to preempt them. +priority(resource) -> ... +``` + +Appeal to the reader's own sense of the domain instead of reciting +mechanism. "Don't retry a write that already partially landed, that's not +safe" tells a competent reader *that* an exclusion is deliberate; it +doesn't need to walk them through every corruption scenario a retry could +cause — they already know retries and partial writes don't mix. + +The comment does not have to remain the sole record if the full reasoning +is ever needed. Version-control history — blame, log, whatever your VCS +calls it — and the diff that introduced the code are legitimate pointers +even when nothing inline says so. Don't write a paragraph today to save a +future reader one history lookup later. + +## Escalate only when intuition won't bridge the gap + +Some constraints aren't derivable from domain sense — a fact about the +world that a reader can't be expected to already hold (an external +system's quirk, a spec's parsing rule, a platform limitation). For those, +and only those, spell out the piece that's genuinely missing: + +- **Observation** — the non-obvious fact about the world. +- **Consequence** — what breaks if you do the naive thing instead. - **Response** — one imperative: what this code does about it. -- **Pointer** — a ticket, PR, or commit hash. The escape hatch for readers - who need the full story. +- **Pointer** — a ticket, commit, or search term for the full story. + +Use as many of these as the gap actually requires — often just Observation +plus Response is enough; save all four for constraints a reader has no way +to intuit on their own. -## Four principles +## Principles -- **Why, not what.** If the comment restates what the code says, don't write - it. -- **Trust the reader.** They can read the language. Don't enumerate lines or - spell out implications they can derive. +- **Why, not what.** If the comment restates what the code already says, + don't write it. +- **Trust the reader.** They can read the language and reason about the + domain. Don't enumerate lines, don't spell out implications, and don't + pre-argue consequences they can derive themselves. - **Index, don't transcribe.** Point at forensic stories with stable identifiers; don't copy them into the comment. -- **Describe what the code is, not what it was.** A comment is read months or - years after authoring; phrases like "now that X exists" or "after the +- **Describe what the code is, not what it was.** A comment is read months + or years after authoring; phrases like "now that X exists" or "after the refactor" frame the rule as a change rather than a property, and read as past-tense narrative to a future reader. State the present invariant directly. -## Three failure modes +## Failure modes - **Spec-sheet** — exhaustive mechanical detail that reads as defensive, dates badly, and is hard to skim. - **Tautological** — just a wrapper around a ticket reference that doesn't actually brief anyone. - **Temporal narrative** — anchors the rule to a transition ("previously…", - "now that…", "since the migration…") instead of a standing fact. Rewrite as - the property the code currently enforces. + "now that…", "since the migration…") instead of a standing fact. Rewrite + as the property the code currently enforces. +- **Over-justifying** — escalating to the full Observation → Consequence → + Response → Pointer shape for a constraint the reader could've inferred + from a one-line label. The paragraph isn't wrong, it's just work the + reader didn't need done for them. ## The target shape -Observation → consequence → response → pointer. Three or four lines. -Conversational but precise. Readable without effort, actionable without -opening the ticket. +One line by default: what this is for, in the plainest words that survive +contact with a competent reader. Escalate a line at a time — only as far +as the actual gap in derivable intuition requires, never straight to the +full four-part form out of habit. + +## Quick reference + +| Situation | What to actually do | +|---|---| +| About to write a comment | Try one line stating intent; stop if that's enough | +| Constraint feels obvious to anyone in the domain | One line, appeal to intuition, no mechanism | +| Constraint depends on an external fact the reader can't intuit | Add Observation; add Consequence only if the failure mode itself is non-obvious | +| Tempted to explain why removing this would break something | Ask if a competent reader would already guess that; if yes, cut it | +| Full reasoning exists but is long | Point at it (commit, ticket, search term) instead of inlining it | +| Comment restates the next line of code | Delete the comment | +| Comment anchors to "now"/"previously"/"after the migration" | Rewrite as the standing property, not the transition | -- 2.51.2