Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 46 additions & 33 deletions .agents/skills/building-with-hypercerts-lexicons/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ const record = {
};

// Validate before writing
const result = validate(ACTIVITY_NSID, record);
if (!result.valid) throw new Error(JSON.stringify(result.errors));
const result = validate(record, ACTIVITY_NSID, "main");
if (!result.success) throw new Error(String(result.error));

// Write to the network
await agent.api.com.atproto.repo.createRecord({
Expand All @@ -86,9 +86,9 @@ lexicon type on the AT Protocol network.
```typescript
import {
ACTIVITY_NSID,
COLLECTION_NSID,
ATTACHMENT_NSID,
RECEIPT_NSID,
HYPERCERTS_COLLECTION_NSID,
CONTEXT_ATTACHMENT_NSID,
FUNDING_RECEIPT_NSID,
} from "@hypercerts-org/lexicon";
```

Expand Down Expand Up @@ -155,9 +155,9 @@ const doc = HYPERCERTS_LEXICON_DOC.ACTIVITY;
```typescript
import { validate, ACTIVITY_NSID } from "@hypercerts-org/lexicon";

const result = validate(ACTIVITY_NSID, record);
if (!result.valid) {
console.error(result.errors);
const result = validate(record, ACTIVITY_NSID, "main");
if (!result.success) {
console.error(result.error);
}
```

Expand Down Expand Up @@ -198,7 +198,7 @@ if (result.success) {
| --------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| **Activity** | `org.hypercerts.claim.activity` | The main hypercert record — title, description, contributors, work scope, timeframe, locations, rights |
| **Contribution** | `org.hypercerts.claim.contribution` | Details about a specific contribution: role, description, timeframe |
| **Contributor Information** | `org.hypercerts.claim.contributorInformation` | Identity record: DID or URI identifier, display name, avatar |
| **Contributor Information** | `org.hypercerts.claim.contributorInformation` | Identity record: DID or URI identifier, display name, image |
| **Rights** | `org.hypercerts.claim.rights` | Licensing terms (e.g. "CC BY-SA 4.0") attached to an activity |

### Collections
Expand Down Expand Up @@ -243,7 +243,7 @@ if (result.success) {
| **Location** | `app.certified.location` | Geographic reference via [Location Protocol](https://spec.decentralizedgeo.org) |
| **Profile** | `app.certified.actor.profile` | User profile: display name, bio, avatar, banner |
| **Organization** | `app.certified.actor.organization` | Organization metadata: legal structure, URLs, location |
| **Badge Definition** | `app.certified.badge.definition` | Defines a badge type with title, icon, optional issuer allowlist |
| **Badge Definition** | `app.certified.badge.definition` | Defines a badge with type, title, icon, optional issuer allowlist |
| **Badge Award** | `app.certified.badge.award` | Awards a badge to a user, project, or activity |
| **Badge Response** | `app.certified.badge.response` | Recipient accepts or rejects a badge award |
| **EVM Link** | `app.certified.link.evm` | Verifiable ATProto DID to EVM wallet link via EIP-712 signature |
Expand All @@ -256,18 +256,18 @@ CLAIMS
(the hypercert) │ │ │
│ v │
├──> contribution (role, timeframe)
├──> contributorInformation (identity, avatar)
├──> contributorInformation (identity, image)
├──> rights (licensing terms)
└──> workScope
├── cel (CEL expression)
└── tag (reusable scope atom)
├── cel ──> tag (CEL expression referencing tags)
└── string (free-form scope)

CONTEXT
attachment ────────────> activity / evaluation / ...
measurement ───────────> activity / ...
evaluation ────────────> activity / attachment
attachment ────────────> any record (activity, evaluation, …)
measurement ───────────> any record (activity, …)
evaluation ────────────> any record (activity, measurement, …)
└──────> measurement
acknowledgement ───────> activity / collection (bidirectional)
acknowledgement ───────> any record (bidirectional)

FUNDING
receipt ───────────────> activity (from funder -> to recipient)
Expand All @@ -276,6 +276,13 @@ HYPERBOARDS
board ─────────────────> activity / collection
└── contributorConfig > contributorInformation
displayProfile (per-user visual defaults)

CERTIFIED
location (geo coordinates, GeoJSON, H3, …)
link/evm (ATProto DID <-> EVM wallet link)
actor/profile (user profile)
actor/organization (org metadata)
badge/response ──> badge/award ──> badge/definition
```

Every arrow is a `strongRef` or union reference stored on AT Protocol.
Expand Down Expand Up @@ -313,10 +320,10 @@ const activity = {
### Creating a Collection

```typescript
import { COLLECTION_NSID } from "@hypercerts-org/lexicon";
import { HYPERCERTS_COLLECTION_NSID } from "@hypercerts-org/lexicon";

const project = {
$type: COLLECTION_NSID,
$type: HYPERCERTS_COLLECTION_NSID,
type: "project",
title: "Carbon Offset Initiative",
shortDescription: "Activities focused on carbon reduction",
Expand All @@ -342,15 +349,17 @@ const project = {
### Creating an Acknowledgement

```typescript
import { ACKNOWLEDGEMENT_NSID } from "@hypercerts-org/lexicon";
import { CONTEXT_ACKNOWLEDGEMENT_NSID } from "@hypercerts-org/lexicon";

const ack = {
$type: ACKNOWLEDGEMENT_NSID,
$type: CONTEXT_ACKNOWLEDGEMENT_NSID,
subject: {
uri: "at://did:plc:bob/org.hypercerts.claim.activity/3k2abc",
cid: "bafy...",
},
// context is a union — use $type to specify the variant
context: {
$type: "com.atproto.repo.strongRef",
uri: "at://did:plc:alice/org.hypercerts.collection/7x9def",
cid: "bafy...",
},
Expand All @@ -369,7 +378,10 @@ const location = {
lpVersion: "1.0",
srs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
locationType: "coordinate-decimal",
location: { string: "-3.4653, -62.2159" },
location: {
$type: "app.certified.location#string",
string: "-3.4653, -62.2159",
},
name: "Amazon Research Station",
createdAt: new Date().toISOString(),
};
Expand Down Expand Up @@ -402,10 +414,10 @@ const evmLink = {
### Creating an Attachment

```typescript
import { ATTACHMENT_NSID } from "@hypercerts-org/lexicon";
import { CONTEXT_ATTACHMENT_NSID } from "@hypercerts-org/lexicon";

const attachment = {
$type: ATTACHMENT_NSID,
$type: CONTEXT_ATTACHMENT_NSID,
title: "Field Survey Report",
contentType: "report",
subjects: [
Expand All @@ -414,9 +426,13 @@ const attachment = {
cid: "...",
},
],
// content items are a union — use $type to specify the variant
content: [
{ uri: "https://example.com/reports/survey-2024.pdf" },
{ uri: "ipfs://Qm..." },
{
$type: "org.hypercerts.defs#uri",
uri: "https://example.com/reports/survey-2024.pdf",
},
{ $type: "org.hypercerts.defs#uri", uri: "ipfs://Qm..." },
],
shortDescription: "Quarterly field survey documenting project progress",
createdAt: new Date().toISOString(),
Expand All @@ -426,20 +442,17 @@ const attachment = {
### Recording a Funding Receipt

```typescript
import { RECEIPT_NSID } from "@hypercerts-org/lexicon";
import { FUNDING_RECEIPT_NSID } from "@hypercerts-org/lexicon";

const receipt = {
$type: RECEIPT_NSID,
subject: {
uri: "at://did:plc:alice/org.hypercerts.claim.activity/abc123",
cid: "...",
},
$type: FUNDING_RECEIPT_NSID,
to: "did:plc:recipient",
amount: "1000.00",
currency: "USD",
paymentRail: "ethereum",
transactionId: "0xabc...",
paidAt: new Date().toISOString(),
for: "at://did:plc:alice/org.hypercerts.claim.activity/abc123",
occurredAt: new Date().toISOString(),
createdAt: new Date().toISOString(),
};
```
Expand Down
23 changes: 18 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,18 +239,31 @@ scripts/ Build and codegen scripts
- **Include all fields except facet fields** (they're cosmetic and
don't affect structure)

4. Update `README.md` as appropriate:
- If README.md already references that lexicon, it must be updated
4. Update `README.md` and `SKILL.md` as appropriate:
- If `README.md` or
`.agents/skills/building-with-hypercerts-lexicons/SKILL.md`
already references that lexicon, **both files must be updated**
to reflect the lexicon changes (modified properties updated,
removed lexicons removed from docs). If it doesn't already then
it's _recommended_ but _not mandatory_ to add some docs to it for
the lexicon in question.
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.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- 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 test` runs `tests/validate-doc-snippets.test.ts` which
auto-checks that all TypeScript code blocks in both files use
valid export names, `$type` strings, and API call signatures.
This will catch many (but not all) documentation errors.

5. Run `npm run gen-schemas-md` to regenerate `SCHEMAS.md`

6. Run `npm run format` to ensure everything is formatted correctly
Expand Down
62 changes: 39 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ CLAIMS ─ the core impact record and its parts
(the hypercert) │ │ │
│ ▼ │
├──► contribution (role, timeframe)
├──► contributorInformation (identity, avatar)
├──► contributorInformation (identity, image)
├──► rights (licensing terms)
└──► workScope
├── cel (CEL expression)
└── tag (reusable scope atom)
├── cel ───► tag (CEL expression referencing tags)
└── string (free-form scope)

CONTEXT ─ evidence, data, and social verification
──────────────────────────────────────────────────────────────────────
attachment ─────────────► activity / evaluation / ...
measurement ────────────► activity / ...
evaluation ─────────────► activity / attachment
attachment ─────────────► any record (activity, evaluation, …)
measurement ────────────► any record (activity, …)
evaluation ─────────────► any record (activity, measurement, …)
└──────► measurement
acknowledgement ────────► activity / collection (bidirectional link)
acknowledgement ────────► any record (bidirectional link)

FUNDING ─ payment records
──────────────────────────────────────────────────────────────────────
Expand All @@ -41,9 +41,10 @@ HYPERBOARDS ─ visual display layer (hyperboards.org)
CERTIFIED ─ shared lexicons (certified.app)
──────────────────────────────────────────────────────────────────────
location (geo coordinates, GeoJSON, H3, …)
link/evm (ATProto DID ↔ EVM wallet link)
actor/profile (user profile)
actor/organization (org metadata)
badge/definition ──► badge/award ──► badge/response
badge/response ──► badge/award ──► badge/definition
```

Every arrow (`►`) is a `strongRef` or union reference stored on the
Expand Down Expand Up @@ -206,8 +207,8 @@ const record = {
};

// Validate before writing
const result = validate(ACTIVITY_NSID, record);
if (!result.valid) throw new Error(JSON.stringify(result.errors));
const result = validate(record, ACTIVITY_NSID, "main");
if (!result.success) throw new Error(String(result.error));

// Write to the network
await agent.api.com.atproto.repo.createRecord({
Expand All @@ -225,7 +226,7 @@ await agent.api.com.atproto.repo.createRecord({
| --------------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **Activity** | `org.hypercerts.claim.activity` | The main hypercert record — describes impact work with title, description, contributors, work scope, timeframe, locations, and rights. |
| **Contribution** | `org.hypercerts.claim.contribution` | Details about a specific contribution: role, description, and timeframe. |
| **Contributor Information** | `org.hypercerts.claim.contributorInformation` | Identity record for a contributor: identifier (DID or URI), display name, and avatar. |
| **Contributor Information** | `org.hypercerts.claim.contributorInformation` | Identity record for a contributor: identifier (DID or URI), display name, and image. |
| **Rights** | `org.hypercerts.claim.rights` | Licensing and rights terms (e.g. "CC BY-SA 4.0") attached to an activity. |

### Collections (`org.hypercerts.*`)
Expand Down Expand Up @@ -270,7 +271,7 @@ await agent.api.com.atproto.repo.createRecord({
| **Location** | `app.certified.location` | Geographic reference using the [Location Protocol](https://spec.decentralizedgeo.org) (coordinates, GeoJSON, H3, WKT, etc.). |
| **Profile** | `app.certified.actor.profile` | User account profile with display name, bio, avatar, and banner. |
| **Organization** | `app.certified.actor.organization` | Organization metadata: legal structure, URLs, location, founding date. |
| **Badge Definition** | `app.certified.badge.definition` | Defines a badge type with title, icon, and optional issuer allowlist. |
| **Badge Definition** | `app.certified.badge.definition` | Defines a badge with type, title, icon, and optional issuer allowlist. |
| **Badge Award** | `app.certified.badge.award` | Awards a badge to a user, project, or activity. |
| **Badge Response** | `app.certified.badge.response` | Recipient accepts or rejects a badge award. |
| **EVM Link** | `app.certified.link.evm` | Verifiable ATProto DID ↔ EVM wallet link via EIP-712 signature. Extensible for future proof methods (e.g. ERC-1271, ERC-6492). |
Expand All @@ -295,7 +296,10 @@ await agent.api.com.atproto.repo.createRecord({
Individual constants (recommended):

```typescript
import { ACTIVITY_NSID, COLLECTION_NSID } from "@hypercerts-org/lexicon";
import {
ACTIVITY_NSID,
HYPERCERTS_COLLECTION_NSID,
} from "@hypercerts-org/lexicon";
```

Semantic object:
Expand Down Expand Up @@ -387,10 +391,10 @@ const activity = {
### Creating Collections (Projects, Portfolios, etc.)

```typescript
import { COLLECTION_NSID } from "@hypercerts-org/lexicon";
import { HYPERCERTS_COLLECTION_NSID } from "@hypercerts-org/lexicon";

const project = {
$type: COLLECTION_NSID,
$type: HYPERCERTS_COLLECTION_NSID,
type: "project",
title: "Carbon Offset Initiative",
shortDescription: "Activities focused on carbon reduction and reforestation",
Expand Down Expand Up @@ -430,7 +434,10 @@ const location = {
lpVersion: "1.0",
srs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
locationType: "coordinate-decimal",
location: { string: "-3.4653, -62.2159" },
location: {
$type: "app.certified.location#string",
string: "-3.4653, -62.2159",
},
name: "Amazon Research Station",
createdAt: new Date().toISOString(),
};
Expand All @@ -441,7 +448,10 @@ const geoLocation = {
lpVersion: "1.0",
srs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
locationType: "geojson-point",
location: { string: '{"type":"Point","coordinates":[-62.2159,-3.4653]}' },
location: {
$type: "app.certified.location#string",
string: '{"type":"Point","coordinates":[-62.2159,-3.4653]}',
},
name: "Research Station Alpha",
createdAt: new Date().toISOString(),
};
Expand All @@ -453,15 +463,17 @@ When one user includes another's record (e.g. adding an activity to a
collection), the owner can confirm or reject with an acknowledgement:

```typescript
import { ACKNOWLEDGEMENT_NSID } from "@hypercerts-org/lexicon";
import { CONTEXT_ACKNOWLEDGEMENT_NSID } from "@hypercerts-org/lexicon";

const ack = {
$type: ACKNOWLEDGEMENT_NSID,
$type: CONTEXT_ACKNOWLEDGEMENT_NSID,
subject: {
uri: "at://did:plc:bob/org.hypercerts.claim.activity/3k2abc",
cid: "bafy...",
},
// context is a union — use $type to specify the variant
context: {
$type: "com.atproto.repo.strongRef",
uri: "at://did:plc:alice/org.hypercerts.collection/7x9def",
cid: "bafy...",
},
Expand All @@ -473,10 +485,10 @@ const ack = {
### Creating Attachments

```typescript
import { ATTACHMENT_NSID } from "@hypercerts-org/lexicon";
import { CONTEXT_ATTACHMENT_NSID } from "@hypercerts-org/lexicon";

const attachment = {
$type: ATTACHMENT_NSID,
$type: CONTEXT_ATTACHMENT_NSID,
title: "Field Survey Report",
contentType: "report",
subjects: [
Expand All @@ -485,9 +497,13 @@ const attachment = {
cid: "...",
},
],
// content items are a union — use $type to specify the variant
content: [
{ uri: "https://example.com/reports/survey-2024.pdf" },
{ uri: "ipfs://Qm..." },
{
$type: "org.hypercerts.defs#uri",
uri: "https://example.com/reports/survey-2024.pdf",
},
{ $type: "org.hypercerts.defs#uri", uri: "ipfs://Qm..." },
],
shortDescription: "Quarterly field survey documenting project progress",
createdAt: new Date().toISOString(),
Expand Down
Loading
Loading