This file provides guidance to AI coding assistants which are modifying code in this repository.
If however you are building on top of this repository rather than
in it, then instead see
building-with-hypercerts-lexicons/SKILL.md
and the README.md.
ALWAYS CREATE A CHANGESET when making changes that affect the public API:
- Adding or modifying lexicon files
- Changing generated TypeScript exports
- Renaming constants, types, or functions
- Any change that users of this package will need to know about
Use the writing-changesets skill. DO NOT skip this step!
main is the only evergreen branch and the default branch on
GitHub. Normal releases are published from main. Note that main,
the latest npm package release, and the lexicons published on ATProto
may not always be perfectly in sync due to the multiple moving parts
in the publishing process.
mainbranch: Preparation for stable releases, which will be tagged and published from this branch.prerelease/*branches: Ephemeral branches for beta/prerelease versions (created frommain, merged back when done; see docs/PUBLISHING.md)feature/*(orfix/*) branches: Short-lived branches for development work, targeting and merged tomainor aprerelease/*branch via PR depending on whether a beta or prerelease is required.
Do not open PRs against
develop— it is a stale branch left over from a previous workflow and is no longer used.
This repository contains ATProto lexicon definitions for the Hypercerts protocol. Lexicons define record types that can be stored on the ATProto network using the ATProtocol (ATProto) standard.
The codebase consists of:
- Lexicon definitions: JSON files in
lexicons/that define record schemas - Generated TypeScript types: Auto-generated in
generated/directory (gitignored, do not edit manually) - Built output: Compiled bundles in
dist/directory (gitignored) - Documentation: Markdown files including README.md and ERD.md.
As already mentioned above, downstream applications should not depend on this document for guidance, which is intended for usage when modifying this repository.
However for the sake of clarity, consume these lexicons NOT by
reading from main or other development branches of the repository,
but instead via the following published releases:
- For TypeScript / JavaScript code — use the npm package
@hypercerts-org/lexicon, which includes generated types, validation helpers, and schema constants. - For other languages — use the tagged releases published in this GitHub repository.
Both npm releases and git tags follow SemVer. For npm, you can depend on a version range to receive compatible updates automatically. For GitHub releases/tags, pin a specific tag or upgrade manually to a newer compatible SemVer release.
The raw lexicons published on ATProto can also be used, but they are (unavoidably) missing useful context such as full documentation (including changelogs), TypeScript type definitions, SemVer guarantees, git history, and other tooling provided by the packaged releases.
The generated/ and dist/ directories contain auto-generated code.
Do not edit files in these directories directly.
To regenerate code after modifying lexicon JSON files:
npm run gen-apiThis runs lex gen-api on all lexicon JSON files and:
- Generates TypeScript types in
generated/(including vendored external lexicons fromlexicons/pub/andlexicons/app/bsky/) - Auto-generates
generated/exports.tswith clean exports
Then to build the distributable bundles:
npm run buildThis runs Rollup to compile TypeScript and bundle into ESM, CommonJS,
and type declaration files in dist/.
npm run gen-schemas-md) rather than executing Node.js files
directly (e.g., node scripts/generate-schemas.js). This ensures
proper environment setup and consistency with the project's workflow.
# Regenerate TypeScript API types from lexicons and auto-generate generated/exports.ts
npm run gen-api
# Manually regenerate just generated/exports.ts
npm run gen-index
# Build distributable bundles
npm run build
# Generate SCHEMAS.md from lexicon definitions
npm run gen-schemas-md
# Generate markdown documentation from lexicons
npm run gen-md
# List all lexicon JSON files
npm run list# Check code formatting
npm run lint
# or
npm run format:check
# Auto-fix formatting issues
npm run format# Validate lexicon definitions, regenerate types, typecheck, and build
npm run check
# Type-check TypeScript without building
npm run typecheckThis repository uses Changesets for versioning.
Use the writing-changesets skill to create changeset files. Do NOT
write changeset files manually - always use the skill to ensure proper
format.
See the writing-changesets skill for details on:
- When changesets are required
- Proper file format and conventions
- Version bump types (major, minor, patch)
Lexicons are JSON files following the ATProto lexicon schema:
- Each lexicon defines a
mainrecord type - Records specify
key,recordschema, and validation rules - Lexicons are organized by namespace (e.g.,
org.hypercerts.claim.*)
The generated/ directory (gitignored) contains:
- index.ts: Generated client class (
AtpBaseClient) - not exposed - exports.ts: Auto-generated clean exports (package entry point)
- types/: TypeScript type definitions for each lexicon
- lexicons.ts: Lexicon schema definitions, IDs, and validation
- util.ts: Utility types and helpers
The dist/ directory (gitignored) contains compiled bundles:
- index.mjs: ESM bundle
- index.cjs: CommonJS bundle
- index.d.ts: TypeScript declarations
- *.map: Source maps
Important: All files in generated/ and dist/ are auto-generated.
Changes should be made to the lexicon JSON files, then regenerated.
lexicons/ Source of truth (committed)
org/hypercerts/ Hypercerts protocol lexicons
org/hyperboards/ Hyperboards visual layer lexicons
app/certified/ Shared/certified lexicons
com/atproto/ ATProto external references
generated/ Auto-generated TypeScript (gitignored)
dist/ Built bundles (gitignored)
scripts/ Build and codegen scripts
Never edit
generated/ordist/directly — they are regenerated from lexicon JSON files.
-
Create / edit JSON file in
lexicons/following the namespace structure -
Run
npm run gen-apito:- Generate types in
generated/(including vendored external lexicons) - Auto-generate
generated/exports.tswith all exports
- Generate types in
-
Update
ERD.pumlas appropriate:- Include all fields except facet fields (they're cosmetic and don't affect structure)
-
Update
README.mdandSKILL.mdas appropriate:-
If
README.mdor.agents/skills/building-with-hypercerts-lexicons/SKILL.mdalready references that lexicon, both files must be updated to reflect the lexicon changes (modified properties updated, removed lexicons removed from docs, code examples corrected). If neither file already references the lexicon then it's recommended but not mandatory to add docs for it. -
For any newly added or modified required/public lexicon, add or update documentation in both files even if neither previously referenced it, so the docs stay in sync with the schema. The "recommended but not mandatory" exemption above applies only to optional or internal-only lexicons.
-
Document new lexicons or changes to existing ones
-
Document all properties except facet fields (facets may be omitted)
-
npm run testrunstests/validate-doc-snippets.test.tswhich auto-checks that all TypeScript code blocks in both files use valid export names,$typestrings, and API call signatures. This will catch many (but not all) documentation errors.
-
-
Run
npm run gen-schemas-mdto regenerateSCHEMAS.md -
Run
npm run formatto ensure everything is formatted correctly via Prettier -
Run
npm run checkto validate, typecheck, and build -
REQUIRED: Create a changeset file using the
writing-changesetsskill- This step is MANDATORY for ALL changes that affect users
- See the
writing-changesetsskill for details on changeset requirements - Use the skill - do NOT write changeset files manually
No manual edits needed! Everything is automatically regenerated.
After modifying lexicons:
# Check formatting
npm run lint
# Validate lexicon syntax
npm run checkTests live in tests/ with one file per lexicon, named
validate-<lexicon-slug>.test.ts (e.g. validate-link-evm.test.ts,
validate-rights.test.ts).
The generated code provides two ways to validate records:
-
validate()fromgenerated/lexicons.js— generic, untyped. The return type isValidationResult<{ $type?: string }>soresult.valuehas no lexicon-specific fields. Use this for negative tests (missing fields, bad types) where you don't need to inspect the returned value. -
validateMain()from per-lexicon type modules (e.g.generated/types/app/certified/link/evm.js) — returns a properly typedValidationResultwith all lexicon fields onresult.value. Use this for positive tests where you assert on specific field values. Note:validateMainrequires$typeto be present on the input record.
Example:
import { validate, ids } from "../generated/lexicons.js";
import * as EvmLink from "../generated/types/app/certified/link/evm.js";
// Positive test — typed result via validateMain
const result = EvmLink.validateMain({
$type: ids.AppCertifiedLinkEvm,
...record,
});
if (result.success) {
expect(result.value.address).toBe("0x..."); // ← type-safe
}
// Negative test — generic validate (no $type needed)
const bad = validate(
{ address: "0x..." }, // missing required fields
ids.AppCertifiedLinkEvm,
"main",
false,
);
expect(bad.success).toBe(false);- Lexicon JSON files should follow ATProto lexicon schema v1
- Use
npm run formatbefore committing to ensure consistent formatting - Use
npm run checkbefore committing to ensure valid lexicons - Never edit
generated/ordist/directly - all changes are lost on regeneration - The
.prettierignoreexcludesgenerated/anddist/since they're auto-generated - The
.gitignoreexcludesgenerated/anddist/to keep the repo clean
See ERD.puml for the entity relationship diagram. Key relationships:
- Claims reference collections, contributions, evidence, measurements, evaluations, and rights
- Collections group multiple claims with weights
- Contributions link to contributors (DIDs or strings)
- Evidence and measurements support claims
- Evaluations provide assessments of claims
IMPORTANT: Developers of this project sometimes use bd (beads), but not for all issue tracking. At the time of writing, the GitHub issue tracker is also used.
- Dependency-aware: Track blockers and relationships between issues
- Git-friendly: Dolt-powered version control with native sync
- Agent-optimized: JSON output, ready work detection, discovered-from links
- Prevents duplicate tracking systems and confusion
Check for ready work:
bd ready --jsonCreate new issues:
bd create "Issue title" --description="Detailed context" -t bug|feature|task -p 0-4 --json
bd create "Issue title" --description="What this issue is about" -p 1 --deps discovered-from:bd-123 --jsonClaim and update:
bd update <id> --claim --json
bd update bd-42 --priority 1 --jsonComplete work:
bd close bd-42 --reason "Completed" --jsonbug- Something brokenfeature- New functionalitytask- Work item (tests, docs, refactoring)epic- Large feature with subtaskschore- Maintenance (dependencies, tooling)
0- Critical (security, data loss, broken builds)1- High (major features, important bugs)2- Medium (default, nice-to-have)3- Low (polish, optimization)4- Backlog (future ideas)
- Check ready work:
bd readyshows unblocked issues - Claim your task atomically:
bd update <id> --claim - Work on it: Implement, test, document
- Discover new work? Create linked issue:
bd create "Found bug" --description="Details about what was found" -p 1 --deps discovered-from:<parent-id>
- Complete:
bd close <id> --reason "Done"
bd automatically syncs via Dolt:
- Each write auto-commits to Dolt history
- Use
bd dolt push/bd dolt pullfor remote sync - No manual export/import needed!
- ✅ Use bd for ALL task tracking
- ✅ Always use
--jsonflag for programmatic use - ✅ Link discovered work with
discovered-fromdependencies - ✅ Check
bd readybefore asking "what should I work on?" - ❌ Do NOT create markdown TODO lists
- ❌ Do NOT use external issue trackers
- ❌ Do NOT duplicate tracking systems
For more details, see README.md and docs/QUICKSTART.md.
When ending a work session, you MUST complete ALL steps below. Work is NOT complete until git push succeeds.
MANDATORY WORKFLOW:
- File issues for remaining work - Create issues for anything that needs follow-up
- Run quality gates (if code changed) - Tests, linters, builds
- Update issue status - Close finished work, update in-progress items
- PUSH TO REMOTE - This is MANDATORY:
git pull --rebase bd dolt push git push origin HEAD git status # MUST show "up to date with origin" - Clean up - Clear stashes, prune remote branches
- Verify - All changes committed AND pushed
- Hand off - Provide context for next session
CRITICAL RULES:
- Work is NOT complete until
git pushsucceeds - NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds