Install
$ agentstack add skill-ngerakines-atproto-skills-atproto-lexicon ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
AT Protocol Lexicon + XRPC + Records
An AT Protocol lexicon is a JSON document that declares the shape of one record type or one XRPC method. Every record's $type, every XRPC path, and every ref between them ties back to an NSID. The lexicon is the protocol's type system; validation against it is the contract between clients, servers, and the repository layer.
This skill routes to per-language guides for Rust, TypeScript, and Go, sitting on top of a language-neutral spec in shared/.
Defaults
- Lexicon doc —
{lexicon: 1, id: , revision?, defs: {...}}. Primary types (record,query,procedure,subscription) live undermain. Secondary types can use any name. - NSID — reversed-DNS authority + name segment. ASCII only, 317 bytes max, name segment allows no hyphens. See
shared/nsid.md. $type— required on every record. Bare NSID implies#main. Used for union dispatch. Missing$type= invalid record.- AT-URIs in records — DIDs strongly preferred over handles for the authority. Query strings forbidden. See
shared/at-uri.md. - strongRef —
{uri, cid}wherecidis a plain string, not acid-link. Common bug source. - Blob refs (modern) —
{$type:"blob", ref:{$link:}, mimeType, size}. Legacy{cid, mimeType}only accepted with an opt-in lenient flag. - XRPC wire —
/xrpc/path. GET for queries, POST for procedures, WebSocket for subscriptions. Errors as{error, message}. Subscription frames are two concatenated DAG-CBOR objects per WS binary message. - Validation — strict by default on write, lenient on read.
ALLOW_LEGACY_BLOBandALLOW_LENIENT_DATETIMEare the typical lenient opt-ins.
Full normative rules: shared/lexicon-spec.md, shared/nsid.md, shared/at-uri.md, shared/record-model.md, shared/xrpc-wire.md, shared/backward-compat.md. Fixtures: shared/test-vectors.md. Cross-language differences: shared/divergence-matrix.md.
Language detection
Before generating or reviewing any lexicon / XRPC / record code, determine the target language from project files or the file being edited:
Cargo.toml,*.rs, any mention ofatproto-lexicon/atproto-client/atproto-record/atproto-jetstream→ Rust — read fromrust/.package.json,tsconfig.json,*.ts,*.tsx, imports of@atproto/lexicon/@atproto/xrpc/@atproto/xrpc-server/@atproto/api/@atproto/lex-cli→ TypeScript — read fromtypescript/. Also*.js/*.jsxwhen there is no.tspresent.go.mod,*.go, imports ofgithub.com/bluesky-social/indigo/atproto/lexicon/atproto/data/xrpc/api/atproto/api/agnostic/events→ Go — read fromgo/.
Prefer the file being edited over the repo root when they disagree: a .go consumer inside a TypeScript monorepo still means Go for that task.
If multiple languages are present and the task does not point at one unambiguously, ask which one applies. Never mix lexicon libraries across languages in generated code.
If an unsupported language is detected (Python, Java, Swift, …), point the user at shared/lexicon-spec.md, shared/record-model.md, and shared/xrpc-wire.md for the wire format, and offer indigo/atproto/lexicon (Go) as the most complete reference implementation to transliterate from.
Reading guide
For every lexicon / records / XRPC task:
- Read the relevant
shared/*.mdfirst. They are short and define the rules your code must enforce. - Read the relevant task file in the detected language directory:
- Authoring a new lexicon, loading into the catalog, codegen →
{lang}/authoring.md - Validating records and XRPC payloads →
{lang}/validation.md - Invoking XRPC methods, consuming subscriptions, server handlers →
{lang}/xrpc-client.md - AT-URIs, TIDs, strongRef, blob refs, typed
$typedispatch →{lang}/records.md - Library setup, public API at a glance, idioms →
{lang}/README.md
- Consult
shared/divergence-matrix.mdwhenever porting between languages or reviewing cross-stack interop. The legacy-blob shape,BlobRef-class-vs-plain-object, and the Go two-stack (data.Blobvs.lex/util.LexBlob) split are the highest-frequency traps.
Always prefer the official library over hand-rolling: atproto-lexicon + atproto-client in Rust, @atproto/lexicon + @atproto/xrpc in TypeScript, indigo/atproto/lexicon + indigo/xrpc in Go.
The conceptual stack
┌──────────────────────────────┐
Lexicon (JSON) ───▶ │ {lexicon:1, id:, │
authoring / resolve │ revision, defs:{main,...}} │
└──────────────────────────────┘
│
▼
┌──────────────────────────────┐
Catalog ──────────▶ │ Lexicons / BaseCatalog — │
(runtime) │ resolves [#def] → def │
└──────────────────────────────┘
│ validates ↓ ↓ schemas XRPC
▼ ▼
┌──────────────────────────────┐ ┌──────────────────────────────┐
Record value ──────▶ │ {$type:, ...fields...} │ │ XRPC transport │
(record def) │ DAG-CBOR → CID stability │ │ GET/POST/WS @ /xrpc/ │
└──────────────────────────────┘ │ JSON in/out; frames on WS │
└──────────────────────────────┘
Validation runs at both ends: on write (strict, reject unknowns) and on read (lenient, tolerate unknowns from older producers). The catalog is shared across both paths.
Cross-language hazards to flag up front
High-frequency failure modes; full detail in shared/divergence-matrix.md:
- strongRef
cidis a string, not a cid-link. Emitting{$link: ...}forstrongRef.cidproduces a different CID. Seeshared/record-model.md §3. - Blob shape divergence. Modern
{$type:"blob", ref:{$link}, mimeType, size}is the only shape for new writes. Legacy{cid, mimeType}is accepted on read only withALLOW_LEGACY_BLOB/AllowLegacyBlob/ equivalent. BlobRefis a class in TypeScript. Plain-object blobs failassertValidRecord. Construct withnew BlobRef(cid, mime, size).- Go has two data-model stacks.
atproto/data(modern) andlex/util(legacy, still emitted by generated code). Convert at the boundary between validator and generated code. xrpc.Client.Doarg order (Go).(ctx, kind, inpenc, method, params, body, out)—kindbeforemethod. Easy to invert.@atproto/xrpcSubscriptionexport has moved. Regrepnode_moduleson version bumps.- Closed vs. open unions. Adding a ref to a closed union is breaking; open unions tolerate unknown
$type. Default to open. $typemissing on a record. Strict validators reject; lenient validators have nothing to dispatch on. Never omit.- Bluesky-domain records are out of scope.
app.bsky.*facets, richtext, embeds, threadgates — point users at the Bluesky appview or@atproto/apiREADME rather than trying to cover them here.
Tools you can call
Prefer these MCP tools when the goal is to compute or validate rather than teach an implementation how:
lexicon-garden→describe_lexicon(nsid),validate_lexicon(doc),invoke_xrpc(method, params, input?),create_record_cid(record),transmogrify_record(record),check_compatibility(old, new).atpmcp→get_lexicon(nsid),validate_lexicon_schema(doc),validate_xrpc(method, params, input?),get_record(uri),invoke_xrpc(method, params, input?),generate_tid(),create_record_cid(record),parse_facets(text),transmogrify_record(record).
For record-side helpers (TIDs, AT-URI parsing), prefer in-language libraries — see the per-language records.md. For lexicon authoring or compatibility review, lexicon-garden is the fastest way to validate without spinning up a stack.
Directory layout
atproto-lexicon/
├── SKILL.md # this file — router
├── shared/
│ ├── lexicon-spec.md # lexicon doc structure + validation rules
│ ├── nsid.md # NSID grammar and reserved prefixes
│ ├── at-uri.md # AT-URIs in records and refs
│ ├── record-model.md # $type, strongRef, blob refs
│ ├── xrpc-wire.md # HTTP + WebSocket wire format
│ ├── backward-compat.md # breaking-vs-non-breaking matrix
│ ├── test-vectors.md # canonical fixtures
│ └── divergence-matrix.md # cross-language differences
├── rust/
│ ├── README.md # atproto-lexicon / atproto-client setup
│ ├── authoring.md # BaseCatalog, load_directory, refs
│ ├── validation.md # validate_record, ValidateFlags, DataValue
│ ├── xrpc-client.md # Auth::{None,DPoP,AppPassword}, atproto-jetstream
│ └── records.md # ATURI, Tid, strongRef, Blob, typed dispatch
├── typescript/
│ ├── README.md # @atproto/{lexicon,xrpc,xrpc-server,api,lex-cli}
│ ├── authoring.md # Lexicons, lex-cli gen-api
│ ├── validation.md # assertValidRecord, BlobRef class, ValidationError
│ ├── xrpc-client.md # XrpcClient, AtpAgent, createServer, Subscription
│ └── records.md # AtUri, TID, BlobRef, strongRef
└── go/
├── README.md # indigo/atproto/lexicon + xrpc + events
├── authoring.md # BaseCatalog, LoadDirectory, lexgen
├── validation.md # ValidateRecord, ValidateFlags
├── xrpc-client.md # xrpc.Client.Do, api/atproto, HandleRepoStream
└── records.md # data.Blob vs lex/util.LexBlob, typed dispatch
References
All reachable from the tree above. Listed here for quick grep:
shared/lexicon-spec.md,shared/nsid.md,shared/at-uri.md,shared/record-model.md,shared/xrpc-wire.md,shared/backward-compat.md,shared/test-vectors.md,shared/divergence-matrix.mdrust/README.md,rust/authoring.md,rust/validation.md,rust/xrpc-client.md,rust/records.mdtypescript/README.md,typescript/authoring.md,typescript/validation.md,typescript/xrpc-client.md,typescript/records.mdgo/README.md,go/authoring.md,go/validation.md,go/xrpc-client.md,go/records.md
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ngerakines
- Source: ngerakines/atproto-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.