From 17af16ce947b4960adafb19d976e3af6fc486014 Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Fri, 6 Mar 2026 13:16:57 +0800 Subject: [PATCH 1/8] =?UTF-8?q?docs:=20split=20quickstart=20into=20grouped?= =?UTF-8?q?=20pages=20=E2=80=94=20code=20and=20scaffold=20app?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .beads/issues.jsonl | 2 +- lib/navigation.js | 15 +- .../creating-your-first-hypercert.md | 192 +++++++++++ pages/getting-started/quickstart.md | 304 +----------------- .../getting-started/using-the-scaffold-app.md | 103 ++++++ 5 files changed, 321 insertions(+), 295 deletions(-) create mode 100644 pages/getting-started/creating-your-first-hypercert.md create mode 100644 pages/getting-started/using-the-scaffold-app.md diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index ab749fb..18824d5 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -118,7 +118,7 @@ {"id":"docs-yzy.1","title":"Create architecture/planned-funding-and-tokenization.md — the dedicated page for all planned on-chain content","description":"## Files\n- documentation/pages/architecture/planned-funding-and-tokenization.md (create)\n\n## What to do\n\nCreate a new page that consolidates ALL planned/TBD content about the on-chain funding and tokenization layer. This page is the single source of truth for what's planned but not yet built.\n\nThe page should have this structure:\n\n### Frontmatter\n```\n---\ntitle: \"Planned: Funding \u0026 Tokenization\"\ndescription: How hypercerts will be frozen, anchored on-chain, and funded. This layer is not yet implemented.\n---\n```\n\n### Page content (write this in full):\n\n**Opening paragraph:** The on-chain funding and tokenization layer is not yet implemented. This page describes the planned design. The theory and architecture are sound — the implementation is in progress. For what exists today (the ATProto data layer), see [Architecture Overview](/architecture/overview).\n\n**Section: The Freeze-Then-Fund Model**\nThe core concept: before a hypercert can be funded, its ATProto records must be frozen. Freezing means taking a cryptographic snapshot (CID) of the activity claim and all its associated records at a point in time. This snapshot is then anchored on-chain.\n\nWhy freezing is necessary: a funder must know exactly what they are funding. If the cert's contents could change after funding, the funder might end up paying for a different cert than what they committed to. A hypercert cannot be funded if its contents are still changing.\n\nWhat freezing preserves: the core activity claim — who did what, when, where. The frozen state is what funders commit to.\n\nWhat continues after freezing: evaluations and evidence can still accumulate. These are separate records that reference the frozen claim. The claim's reputation can evolve while its core content remains fixed.\n\n**Section: On-Chain Anchoring**\nWhen a hypercert is frozen, its snapshot CID will be anchored on-chain via a smart contract. The contract stores the AT-URI and the frozen snapshot CID, creating a verifiable link between the data layer and the ownership layer.\n\nThis creates an immutable reference point. Anyone can verify that the on-chain record matches the ATProto data by comparing CIDs.\n\n**Section: Tokenization**\nOnce frozen and anchored, the hypercert can be represented as a transferable token on-chain. A token could represent full ownership or fractional shares. Token holders would have rights defined in the hypercert's org.hypercerts.claim.rights record.\n\nThe specific token standard (ERC-1155, ERC-721, or a custom standard) is being designed. The protocol intends to support multiple token standards for different use cases — from non-transferable recognition to fully tradable certificates.\n\n**Section: Funding Mechanisms**\nOnce frozen and anchored, various funding models can operate on the ownership layer:\n- Direct funding — funders acquire shares directly from the contributor\n- Retroactive funding — rewarding past work based on demonstrated outcomes\n- Impact certificates — creating markets for outcomes\n- Quadratic funding — amplifying small donations through matching pools\n- Milestone-based payouts — releasing funds as work progresses\n\nSmart contracts will enforce rules and distribute payments. The specific implementations are being designed.\n\n**Section: Funding Readiness Patterns**\nDifferent applications may use different patterns for when to freeze:\n\nPattern 1: Freeze-on-create — the claim is frozen immediately upon creation. Simple but means the claim can't be enriched before funding.\n\nPattern 2: Freeze-when-ready — the claim exists on ATProto, accumulates evidence and evaluations, and is frozen only when a funder expresses interest or the contributor decides it's ready. This is the expected default pattern.\n\nPattern 3: Batch freezing — multiple claims are frozen and anchored together periodically. Cost-efficient for high-volume use cases.\n\nPattern 4: Partial freezing — some aspects of the claim are frozen (e.g., the core activity and rights) while others remain mutable (e.g., ongoing measurements). The frozen portion is what funders commit to.\n\n**Section: Multi-Chain Support**\nThe protocol is designed to be chain-agnostic. Different communities may use different chains. The ATProto data layer remains the same regardless of which chain anchors the frozen snapshot. The specific multi-chain architecture is being designed.\n\n**Section: Cross-Layer Example**\nWalk through the full planned flow:\n1. Alice creates an activity claim on her PDS → gets AT-URI\n2. Bob evaluates Alice's claim from his PDS\n3. Alice decides the claim is ready for funding → freezes it\n4. An application anchors the frozen snapshot on-chain → gets token ID\n5. Carol funds the frozen cert on-chain\n6. New evaluations continue accumulating on ATProto, referencing the frozen claim\n7. Carol can verify her funded cert matches the frozen snapshot by comparing CIDs\n\nInclude the ASCII diagram:\n```\nATProto (exists today) On-chain (planned)\n────────────────────── ──────────────────\nActivity Claim Frozen Snapshot\nat://did:alice/... CID: bafyrei...\n ↓ ↓\nEvidence, Evaluations Ownership Record\nMeasurements, Rights Funder: 0xCarol...\n Metadata: { uri, cid }\n```\n\n**Section: What This Will Enable**\n- Retroactive funding of past contributions\n- Composable funding mechanisms across platforms\n- Portable proof of funding (funders can prove what they funded)\n- Independent evolution of data and ownership layers\n\n**Closing:** For the current architecture (what exists today), see [Architecture Overview](/architecture/overview). For the data lifecycle, see [Data Flow \u0026 Lifecycle](/architecture/data-flow-and-lifecycle).\n\n## Test\ntest -f documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\ngrep -q 'not yet implemented' documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\ngrep -q 'Freeze-Then-Fund' documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\ngrep -q 'cannot.*funded.*chang\\|can.t.*funded.*chang\\|exactly what' documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\ngrep -q 'Funding Readiness Patterns\\|Funding.*Pattern' documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\ngrep -q 'Multi-Chain' documentation/pages/architecture/planned-funding-and-tokenization.md \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Present any of this as implemented/live\n- Invent specific contract addresses or deployed details\n- Make it too short — this is THE comprehensive reference for all planned on-chain work\n- Forget the cross-layer example with the ASCII diagram","status":"closed","priority":1,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T17:12:25.547762+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T17:16:00.16776+13:00","closed_at":"2026-02-16T17:16:00.16776+13:00","close_reason":"d937d10 Created comprehensive planned funding and tokenization architecture page","labels":["scope:medium"],"dependencies":[{"issue_id":"docs-yzy.1","depends_on_id":"docs-yzy","type":"parent-child","created_at":"2026-02-16T17:12:25.549901+13:00","created_by":"sharfy-test.climateai.org"}]} {"id":"docs-yzy.2","title":"Update navigation and rewrite blockchain-integration.md to redirect to planned page","description":"## Files\n- documentation/lib/navigation.js (modify)\n- documentation/pages/getting-started/infrastructure/blockchain-integration.md (modify)\n- documentation/pages/getting-started/infrastructure/portability-and-scaling.md (modify)\n- documentation/pages/getting-started/the-hypercerts-infrastructure.md (modify — just the link on line 78)\n\n## What to do\n\n### 1. Update navigation.js\n\nChange line 25 from:\n```js\n{ title: 'Blockchain Integration', path: '/getting-started/infrastructure/blockchain-integration' },\n```\nto:\n```js\n{ title: 'Funding \u0026 Tokenization (Planned)', path: '/architecture/planned-funding-and-tokenization' },\n```\n\nAlso add the new page to the Understand section, after \"Data Flow \u0026 Lifecycle\" (line 30). Add:\n```js\n{ title: 'Planned: Funding \u0026 Tokenization', path: '/architecture/planned-funding-and-tokenization' },\n```\n\nWait — actually, since it's already linked as a child of \"The Hypercerts Infrastructure\", just update that child entry. Don't add a duplicate. So the only change is line 25.\n\n### 2. Rewrite blockchain-integration.md\n\nThis file currently has the old mint-on-create / lazy minting / batch anchoring / hybrid ownership patterns. Replace the entire content with a redirect notice:\n\n```markdown\n---\ntitle: Funding \u0026 Tokenization\n---\n\n# Funding \u0026 Tokenization\n\nThis content has moved to [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\n```\n\n### 3. Update portability-and-scaling.md\n\nLines 36-38 have \"Blockchain scalability\" section that says \"On-chain operations (minting, transfers, sales) are expensive...\" — this is planned content. Replace with:\n\n```markdown\n#### On-chain scalability (planned)\n\nThe on-chain funding and tokenization layer is not yet implemented. When built, on-chain operations will be expensive, so hypercerts will minimize on-chain activity by keeping rich data on ATProto. Only frozen snapshots and funding flows will touch the blockchain. For details on the planned on-chain design, see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\n```\n\nAlso lines 50-52 have \"Access control via smart contracts\" with token-gated data. Replace with:\n\n```markdown\n#### Access control via smart contracts (planned)\n\nIn the planned design, on-chain tokens could have access control logic — for example, granting read access to private ATProto records only to token holders. This is a potential future feature. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for details.\n```\n\n### 4. Update the-hypercerts-infrastructure.md line 78\n\nChange:\n```\n- [Blockchain Integration](/getting-started/infrastructure/blockchain-integration) — minting patterns and on-chain ownership\n```\nto:\n```\n- [Funding \u0026 Tokenization (Planned)](/architecture/planned-funding-and-tokenization) — freeze-then-fund model and on-chain ownership design\n```\n\n## Test\ngrep -q 'planned-funding-and-tokenization' documentation/lib/navigation.js \u0026\u0026 \\\ngrep -q 'moved to' documentation/pages/getting-started/infrastructure/blockchain-integration.md \u0026\u0026 \\\ngrep -q 'planned-funding-and-tokenization' documentation/pages/getting-started/the-hypercerts-infrastructure.md \u0026\u0026 \\\ngrep -q 'not yet implemented' documentation/pages/getting-started/infrastructure/portability-and-scaling.md \u0026\u0026 \\\n! grep -q 'mints an NFT\\|Mint-on-create\\|Lazy minting' documentation/pages/getting-started/infrastructure/blockchain-integration.md \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Add duplicate nav entries\n- Delete blockchain-integration.md (keep it as a redirect so old links work)\n- Change anything else in navigation.js\n- Change anything else in the-hypercerts-infrastructure.md besides line 78\n- Change anything else in portability-and-scaling.md besides the blockchain scalability and token-gated sections","status":"closed","priority":1,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T17:12:50.318417+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T17:18:08.762614+13:00","closed_at":"2026-02-16T17:18:08.762614+13:00","close_reason":"e8dd74d Update navigation and redirect blockchain-integration to planned funding page","labels":["scope:small"],"dependencies":[{"issue_id":"docs-yzy.2","depends_on_id":"docs-yzy","type":"parent-child","created_at":"2026-02-16T17:12:50.31972+13:00","created_by":"sharfy-test.climateai.org"},{"issue_id":"docs-yzy.2","depends_on_id":"docs-yzy.1","type":"blocks","created_at":"2026-02-16T17:14:24.044876+13:00","created_by":"sharfy-test.climateai.org"}]} {"id":"docs-yzy.3","title":"Strip planned content from architecture/overview.md and architecture/data-flow-and-lifecycle.md — link to planned page","description":"## Files\n- documentation/pages/architecture/overview.md (modify)\n- documentation/pages/architecture/data-flow-and-lifecycle.md (modify)\n\n## What to do\n\nRemove detailed planned/TBD content from these two architecture pages. Replace with brief mentions and links to /architecture/planned-funding-and-tokenization. The main docs should describe what EXISTS TODAY (ATProto data layer) and only briefly note that on-chain funding is planned.\n\n### architecture/overview.md\n\n**Line 8:** Change to: \"The Hypercerts Protocol uses AT Protocol for data portability. On-chain anchoring for ownership and funding is [planned](/architecture/planned-funding-and-tokenization).\"\n\n**Line 18 (Ownership Layer):** Condense to 1-2 sentences max: \"The **Ownership Layer** is planned but not yet implemented. The intended design uses a freeze-then-fund model where hypercerts are frozen and anchored on-chain before funding — ensuring funders know exactly what they are paying for. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for details.\"\n\n**Lines 48-70 (Ownership Layer Deep Dive):** DELETE this entire section (Anchoring, Tokenization, Funding Mechanisms, Multi-Chain Support). Replace with a single short paragraph:\n\n\"## Ownership Layer (Planned)\n\nThe ownership layer is not yet implemented. The planned design freezes ATProto records and anchors them on-chain before funding, ensuring funders know exactly what they are paying for. For the full planned design — including anchoring, tokenization, funding mechanisms, and multi-chain support — see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\"\n\n**Lines 72-95 (How the Layers Connect):** Keep the first paragraph about content living on ATProto (line 76). Remove lines 78-80 (detailed planned flow) and the cross-layer example (lines 86-95). Replace with:\n\n\"A hypercert's **ownership and funding state** will live on-chain once the tokenization layer is built. The planned bridge is a freeze-then-fund mechanism. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for the full cross-layer design.\"\n\nKeep the callout (lines 82-84) but simplify: \"The separation matters. ATProto provides data portability — users can switch servers, applications can read across the network, and records outlive any single platform. On-chain anchoring will provide ownership and funding guarantees. Neither layer can provide both properties alone.\"\n\n**Lines 105-107 (Why Not Fully Off-Chain?):** Condense. Keep the core point (mutable records are fine for collaboration but funding requires immutability) but remove the detailed freeze-then-fund explanation. Add link.\n\n**Lines 115-119 (Why This Separation):** Simplify. Remove \"through the planned freeze-then-fund mechanism\" and \"Once the tokenization layer is built\". Just say: \"Each layer does what it does best. ATProto handles identity, data portability, and schemas. On-chain anchoring will handle ownership, funding, and immutability. This separation reduces costs, increases flexibility, and maintains portability.\"\n\n**Lines 121-131 (What This Enables):** Remove \"(Planned)\" labels and the detailed planned descriptions. Keep the 4 bullet points but make them concise. For the two that work today, keep as-is. For the two that are planned, just say \"planned\" in one phrase and link to the planned page.\n\n**Add to Next Steps:** Add a link: \"For the planned on-chain funding and tokenization design, see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\"\n\n### architecture/data-flow-and-lifecycle.md\n\n**Line 22 (Funding summary):** Condense to: \"**Funding** connects ownership to the claim. The on-chain funding layer is [planned but not yet implemented](/architecture/planned-funding-and-tokenization). The intended design freezes ATProto records before funding to ensure funders know exactly what they are paying for.\"\n\n**Line 24 (Accumulation):** Simplify to: \"**Accumulation** continues indefinitely. More evaluations arrive. Additional evidence gets attached. The data layer continues evolving.\"\n\n**Line 29 (diagram):** Change \"On-chain (planned)\" to just \"On-chain*\" and add a footnote: \"*On-chain layer is planned. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\"\n\n**Lines 146-187 (Stage 5: Funding \u0026 Ownership):** DELETE the detailed content. Replace with a short section:\n\n\"## Stage 5: Funding \u0026 Ownership (Planned)\n\nThe on-chain funding layer is not yet implemented. The planned design: before a hypercert can be funded, its ATProto records are frozen and the snapshot is anchored on-chain. This ensures funders know exactly what they are paying for — the cert's contents cannot change after freezing.\n\nFor the full planned design — including anchoring, tokenization, funding mechanisms, funding readiness patterns, and multi-chain support — see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\"\n\n**Lines 205-218 (Ownership Transfers, Long-Term Value in Stage 6):** Remove the \"Ownership Transfers\" subsection entirely (it's all planned content). Keep \"Long-Term Value\" but simplify: \"The separation of data and ownership enables long-term value accumulation. A hypercert's reputation can grow as evaluations accumulate. The data remains portable and accessible regardless of future ownership changes.\"\n\nRemove the timeline diagram (lines 213-218) or simplify it to only show what exists today:\n```\nTime →\n─────────────────────────────────────────────────────────\nCreation Evaluation 1 Discovery Evaluation 2 Evidence Evaluation 3\n ↓ ↓ ↓ ↓ ↓ ↓\n PDS PDS-Eva1 Indexer PDS-Eva2 PDS PDS-Eva3\n```\n\n## Test\n! grep -q 'Multi-Chain Support' documentation/pages/architecture/overview.md \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/architecture/overview.md | grep -qv '^0$' \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/architecture/data-flow-and-lifecycle.md | grep -qv '^0$' \u0026\u0026 \\\n! grep -q 'Anchoring (Planned)' documentation/pages/architecture/overview.md \u0026\u0026 \\\n! grep -q 'Tokenization (Planned)' documentation/pages/architecture/overview.md \u0026\u0026 \\\n! grep -q 'Funding Mechanisms (Planned)' documentation/pages/architecture/overview.md \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Remove the Data Layer sections — those describe what exists today\n- Remove the Key Design Decisions section entirely — just simplify it\n- Remove the \"What This Enables\" section — just simplify it\n- Add new planned content — we're REMOVING it and linking to the dedicated page\n- Change Stages 1-4 in data-flow-and-lifecycle.md\n- Change the Cross-PDS References or \"What This Flow Enables\" sections in data-flow-and-lifecycle.md","status":"closed","priority":1,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T17:13:45.724521+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T17:19:22.582072+13:00","closed_at":"2026-02-16T17:19:22.582072+13:00","close_reason":"4ed89bd Strip planned content from architecture docs and link to planned page","labels":["scope:medium"],"dependencies":[{"issue_id":"docs-yzy.3","depends_on_id":"docs-yzy","type":"parent-child","created_at":"2026-02-16T17:13:45.725402+13:00","created_by":"sharfy-test.climateai.org"},{"issue_id":"docs-yzy.3","depends_on_id":"docs-yzy.1","type":"blocks","created_at":"2026-02-16T17:14:24.15891+13:00","created_by":"sharfy-test.climateai.org"}]} -{"id":"docs-yzy.4","title":"Strip planned content from 5 getting-started and reference pages — link to planned page","description":"## Files\n- documentation/pages/getting-started/the-hypercerts-infrastructure.md (modify)\n- documentation/pages/getting-started/why-atproto.md (modify)\n- documentation/pages/getting-started/why-were-building-hypercerts.md (modify)\n- documentation/pages/getting-started/introduction-to-impact-claims.md (modify)\n- documentation/pages/reference/faq.md (modify)\n\n## What to do\n\nRemove detailed planned/TBD content from these 5 pages. Replace with brief mentions and links to /architecture/planned-funding-and-tokenization.\n\n### the-hypercerts-infrastructure.md\n\n**Line 7:** Change to: \"Hypercerts runs on AT Protocol for data. On-chain anchoring for ownership and funding is [planned](/architecture/planned-funding-and-tokenization).\"\n\n**Lines 19-23 (The funding layer section):** Condense to 2-3 sentences max:\n\n\"#### The funding layer: on-chain anchoring (planned)\n\nThe on-chain funding layer is not yet implemented. The planned design uses a freeze-then-fund model: before a hypercert can be funded, its ATProto records are frozen and anchored on-chain, ensuring funders know exactly what they are paying for. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for the full design.\"\n\n**Lines 25-29 (How the layers connect):** Condense. Keep the AT-URI example. Remove the detailed planned flow. Just say: \"A claim can exist on ATProto without ever being frozen for funding. The two layers are loosely coupled and complement each other.\"\n\n**Lines 53-57 (Step 4):** Condense to:\n\n\"#### 4. The hypercert is frozen and funded (planned)\n\nIn the planned design, Carol's funding app will freeze Alice's hypercert and anchor the snapshot on-chain. Carol knows exactly what she is paying for because the frozen claim cannot change. The tokenization layer is not yet implemented — see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for details.\"\n\n### why-atproto.md\n\n**Lines 49-51 (ATProto + Blockchain section):** Condense to:\n\n\"ATProto handles the data layer — claims, evidence, evaluations, trust signals. On-chain anchoring is planned to handle the funding layer. The intended design: hypercerts are frozen and anchored on-chain before funding, ensuring funders know exactly what they're paying for. The tokenization layer is not yet implemented — see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for the full design.\"\n\n### why-were-building-hypercerts.md\n\n**Line 182:** Keep as-is: \"That's where onchain anchoring comes in — and eventually, tokenization.\"\n\n**Lines 184-192 (The Ownership \u0026 Funding Layer):** Condense to:\n\n\"#### The Funding Layer: On-chain Anchoring (Planned)\n\nATProto provides the data layer. But funding requires a stronger guarantee: funders need to know that what they're paying for won't change after the fact. The planned approach is freeze-then-fund — before a hypercert can be funded, its ATProto records are frozen and anchored on-chain. The tokenization layer is not yet implemented. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for the full design.\"\n\n### introduction-to-impact-claims.md\n\n**Line 21:** Condense to: \"Hypercerts can exist as a standalone activity claim, or they can be [frozen and funded](/architecture/planned-funding-and-tokenization) on-chain (planned).\"\n\n### faq.md\n\n**Line 18 (How is this different):** Condense to: \"The new protocol is built on AT Protocol instead of purely on-chain. This gives data portability, richer schemas, and lower costs. On-chain anchoring for funding is [planned](/architecture/planned-funding-and-tokenization) but not yet implemented.\"\n\n**Lines 20-22 (Do I need a blockchain wallet?):** Condense to: \"Not to create or evaluate hypercerts — you only need an ATProto account (DID). A blockchain wallet will be needed for on-chain funding once the [tokenization layer](/architecture/planned-funding-and-tokenization) is built.\"\n\n**Lines 37-38 (How do I fund?):** Condense to: \"The on-chain funding layer is not yet implemented. The planned design freezes ATProto records before funding to ensure funders know exactly what they are paying for. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for details.\"\n\n**Lines 44-46 (What chains?):** Condense to: \"The protocol intends to be chain-agnostic. The on-chain layer is not yet implemented — see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\"\n\n## Test\ngrep -c 'planned-funding-and-tokenization' documentation/pages/getting-started/the-hypercerts-infrastructure.md | grep -qv '^0$' \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/getting-started/why-atproto.md | grep -qv '^0$' \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/getting-started/why-were-building-hypercerts.md | grep -qv '^0$' \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/getting-started/introduction-to-impact-claims.md | grep -qv '^0$' \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/reference/faq.md | grep -qv '^0$' \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Remove the data layer sections — those describe what exists today\n- Remove the data flow walkthrough (Steps 1-3 in infrastructure) — those are accurate\n- Remove the Data Integrity and Trust section in infrastructure — accurate\n- Change anything in why-were-building-hypercerts.md before line 172\n- Add new planned content — we're condensing and linking\n- Change the \"Keep Reading\" links in infrastructure (except the blockchain-integration link which is handled by another task)","status":"closed","priority":2,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T17:14:18.331984+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-03-03T14:42:32.355416674+06:00","closed_at":"2026-02-17T05:24:43.922182+13:00","labels":["scope:medium"],"dependencies":[{"issue_id":"docs-yzy.4","depends_on_id":"docs-yzy","type":"parent-child","created_at":"2026-02-16T17:14:18.333338+13:00","created_by":"sharfy-test.climateai.org"},{"issue_id":"docs-yzy.4","depends_on_id":"docs-yzy.1","type":"blocks","created_at":"2026-02-16T17:14:24.250458+13:00","created_by":"sharfy-test.climateai.org"}]} +{"id":"docs-yzy.4","title":"Strip planned content from 5 getting-started and reference pages — link to planned page","description":"## Files\n- documentation/pages/getting-started/the-hypercerts-infrastructure.md (modify)\n- documentation/pages/getting-started/why-atproto.md (modify)\n- documentation/pages/getting-started/why-were-building-hypercerts.md (modify)\n- documentation/pages/getting-started/introduction-to-impact-claims.md (modify)\n- documentation/pages/reference/faq.md (modify)\n\n## What to do\n\nRemove detailed planned/TBD content from these 5 pages. Replace with brief mentions and links to /architecture/planned-funding-and-tokenization.\n\n### the-hypercerts-infrastructure.md\n\n**Line 7:** Change to: \"Hypercerts runs on AT Protocol for data. On-chain anchoring for ownership and funding is [planned](/architecture/planned-funding-and-tokenization).\"\n\n**Lines 19-23 (The funding layer section):** Condense to 2-3 sentences max:\n\n\"#### The funding layer: on-chain anchoring (planned)\n\nThe on-chain funding layer is not yet implemented. The planned design uses a freeze-then-fund model: before a hypercert can be funded, its ATProto records are frozen and anchored on-chain, ensuring funders know exactly what they are paying for. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for the full design.\"\n\n**Lines 25-29 (How the layers connect):** Condense. Keep the AT-URI example. Remove the detailed planned flow. Just say: \"A claim can exist on ATProto without ever being frozen for funding. The two layers are loosely coupled and complement each other.\"\n\n**Lines 53-57 (Step 4):** Condense to:\n\n\"#### 4. The hypercert is frozen and funded (planned)\n\nIn the planned design, Carol's funding app will freeze Alice's hypercert and anchor the snapshot on-chain. Carol knows exactly what she is paying for because the frozen claim cannot change. The tokenization layer is not yet implemented — see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for details.\"\n\n### why-atproto.md\n\n**Lines 49-51 (ATProto + Blockchain section):** Condense to:\n\n\"ATProto handles the data layer — claims, evidence, evaluations, trust signals. On-chain anchoring is planned to handle the funding layer. The intended design: hypercerts are frozen and anchored on-chain before funding, ensuring funders know exactly what they're paying for. The tokenization layer is not yet implemented — see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for the full design.\"\n\n### why-were-building-hypercerts.md\n\n**Line 182:** Keep as-is: \"That's where onchain anchoring comes in — and eventually, tokenization.\"\n\n**Lines 184-192 (The Ownership \u0026 Funding Layer):** Condense to:\n\n\"#### The Funding Layer: On-chain Anchoring (Planned)\n\nATProto provides the data layer. But funding requires a stronger guarantee: funders need to know that what they're paying for won't change after the fact. The planned approach is freeze-then-fund — before a hypercert can be funded, its ATProto records are frozen and anchored on-chain. The tokenization layer is not yet implemented. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for the full design.\"\n\n### introduction-to-impact-claims.md\n\n**Line 21:** Condense to: \"Hypercerts can exist as a standalone activity claim, or they can be [frozen and funded](/architecture/planned-funding-and-tokenization) on-chain (planned).\"\n\n### faq.md\n\n**Line 18 (How is this different):** Condense to: \"The new protocol is built on AT Protocol instead of purely on-chain. This gives data portability, richer schemas, and lower costs. On-chain anchoring for funding is [planned](/architecture/planned-funding-and-tokenization) but not yet implemented.\"\n\n**Lines 20-22 (Do I need a blockchain wallet?):** Condense to: \"Not to create or evaluate hypercerts — you only need an ATProto account (DID). A blockchain wallet will be needed for on-chain funding once the [tokenization layer](/architecture/planned-funding-and-tokenization) is built.\"\n\n**Lines 37-38 (How do I fund?):** Condense to: \"The on-chain funding layer is not yet implemented. The planned design freezes ATProto records before funding to ensure funders know exactly what they are paying for. See [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization) for details.\"\n\n**Lines 44-46 (What chains?):** Condense to: \"The protocol intends to be chain-agnostic. The on-chain layer is not yet implemented — see [Planned: Funding \u0026 Tokenization](/architecture/planned-funding-and-tokenization).\"\n\n## Test\ngrep -c 'planned-funding-and-tokenization' documentation/pages/getting-started/the-hypercerts-infrastructure.md | grep -qv '^0$' \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/getting-started/why-atproto.md | grep -qv '^0$' \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/getting-started/why-were-building-hypercerts.md | grep -qv '^0$' \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/getting-started/introduction-to-impact-claims.md | grep -qv '^0$' \u0026\u0026 \\\ngrep -c 'planned-funding-and-tokenization' documentation/pages/reference/faq.md | grep -qv '^0$' \u0026\u0026 \\\necho \"PASS\" || echo \"FAIL\"\n\n## Don't\n- Remove the data layer sections — those describe what exists today\n- Remove the data flow walkthrough (Steps 1-3 in infrastructure) — those are accurate\n- Remove the Data Integrity and Trust section in infrastructure — accurate\n- Change anything in why-were-building-hypercerts.md before line 172\n- Add new planned content — we're condensing and linking\n- Change the \"Keep Reading\" links in infrastructure (except the blockchain-integration link which is handled by another task)","status":"closed","priority":2,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T17:14:18.331984+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-17T05:24:43.922182+13:00","closed_at":"2026-02-17T05:24:43.922182+13:00","close_reason":"Superseded by PR #4 merge — all planned-funding-and-tokenization references updated to funding-and-tokenization","labels":["scope:medium"],"dependencies":[{"issue_id":"docs-yzy.4","depends_on_id":"docs-yzy","type":"parent-child","created_at":"2026-02-16T17:14:18.333338+13:00","created_by":"sharfy-test.climateai.org"},{"issue_id":"docs-yzy.4","depends_on_id":"docs-yzy.1","type":"blocks","created_at":"2026-02-16T17:14:24.250458+13:00","created_by":"sharfy-test.climateai.org"}]} {"id":"docs-z1q","title":"Epic: Search Improvements","description":"Fix search UX: no keyboard navigation of results (arrow keys dont work), no fuzzy matching (typo = 0 results), empty state shows all pages instead of popular links, no result grouping by section. Covers UX findings #21, 22, 36, 37.","status":"closed","priority":2,"issue_type":"epic","assignee":"einstein.climateai.org","owner":"einstein.climateai.org","created_at":"2026-02-20T19:54:59.33049+08:00","created_by":"einstein.climateai.org","updated_at":"2026-02-20T20:06:38.262731+08:00","closed_at":"2026-02-20T20:06:38.262731+08:00","close_reason":"1094f5d all search tasks complete","labels":["scope:medium"]} {"id":"docs-z1q.1","title":"Search keyboard nav + fuzzy matching + result grouping + empty state","description":"## Files\n- components/SearchDialog.js (modify)\n- styles/globals.css (modify)\n- lib/navigation.js (modify — add section info to flattenNavigation)\n\n## What to do\n\n### Keyboard navigation of results (finding #21)\nAdd arrow key support to the search dialog. Track a `selectedIndex` state (default -1 = none selected):\n\n1. Add `const [selectedIndex, setSelectedIndex] = useState(-1)` state\n2. Reset selectedIndex to 0 when results change (in a useEffect on results.length or query)\n3. In the `onKeyDown` handler on the input, add:\n - ArrowDown: `e.preventDefault(); setSelectedIndex(i =\u003e Math.min(i + 1, results.length - 1))`\n - ArrowUp: `e.preventDefault(); setSelectedIndex(i =\u003e Math.max(i - 1, 0))`\n - Enter: navigate to `results[selectedIndex]` (or results[0] if selectedIndex is -1)\n4. Add class `search-result-item-selected` to the item at `selectedIndex`\n5. Use a ref to scroll the selected item into view: `itemRefs[selectedIndex]?.scrollIntoView({ block: \"nearest\" })`\n\nCSS for `.search-result-item-selected`:\n```css\n.search-result-item-selected {\n background: var(--hover-bg);\n}\n```\n\n### Fuzzy matching (finding #22)\nReplace the exact substring match with a simple fuzzy algorithm. Do NOT add external dependencies.\n\nImplement a `fuzzyMatch(query, text)` function:\n- Convert both to lowercase\n- Check if all characters of query appear in text in order (not necessarily contiguous)\n- Return true/false\n\n```js\nfunction fuzzyMatch(query, text) {\n const q = query.toLowerCase();\n const t = text.toLowerCase();\n let qi = 0;\n for (let ti = 0; ti \u003c t.length \u0026\u0026 qi \u003c q.length; ti++) {\n if (t[ti] === q[qi]) qi++;\n }\n return qi === q.length;\n}\n```\n\nUse fuzzyMatch for filtering, then sort by: exact substring match first, then fuzzy-only matches.\n\n### Result grouping by section (finding #37)\nModify `flattenNavigation` in `lib/navigation.js` to also return the section name for each page. Change the return type from `{ title, path }` to `{ title, path, section }`.\n\nIn `flattenNavigation`, track the current section:\n```js\nexport function flattenNavigation(nav = navigation, currentSection = \"\") {\n const result = [];\n for (const item of nav) {\n const section = item.section || currentSection;\n if (item.path) {\n result.push({ title: item.title, path: item.path, section });\n }\n if (item.children) {\n result.push(...flattenNavigation(item.children, section));\n }\n }\n return result;\n}\n```\n\nIn SearchDialog, group results by section. Render section headers between groups:\n```jsx\n{Object.entries(groupedResults).map(([section, items]) =\u003e (\n \u003cli key={section}\u003e\n \u003cdiv className=\"search-result-section\"\u003e{section || \"General\"}\u003c/div\u003e\n \u003cul className=\"search-results-list\"\u003e\n {items.map(page =\u003e (/* existing result item */))}\n \u003c/ul\u003e\n \u003c/li\u003e\n))}\n```\n\nCSS for `.search-result-section`: font-size 11px, font-weight 700, text-transform uppercase, letter-spacing 0.06em, color var(--color-text-secondary), padding 8px 12px 4px, margin-top 4px.\n\n### Empty state (finding #36)\nWhen query is empty, instead of showing ALL pages, show a curated set of 5-6 popular pages grouped as \"Quick Links\":\n- Quickstart\n- What are Hypercerts?\n- Core Data Model\n- Scaffold Starter App\n- Architecture Overview\n- Glossary\n\nFilter these from allPages by path. Show them under a \"Quick Links\" section header.\n\nWhen query has no matches, show \"No results for [query]\" with the quick links below it as fallback.\n\n## Dont\n- Do NOT add any npm dependencies (no fuse.js, no external fuzzy library)\n- Do NOT change the Escape key behavior\n- Do NOT change the ⌘K shortcut\n- Do NOT change the search dialog visual layout (width, position, overlay)","acceptance_criteria":"1. Arrow Down/Up keys move a visual highlight through search results\n2. Enter navigates to the currently highlighted result\n3. Typing a partial/misspelled query still returns relevant results (e.g., \"quikstart\" matches \"Quickstart\")\n4. Results are grouped under section headers (e.g., \"Get Started\", \"Core Concepts\", \"Tools\")\n5. Empty state shows 5-6 Quick Links instead of dumping all 40 pages\n6. No external dependencies were added\n7. selectedIndex resets when query changes\n8. Build passes: npm run build -- --webpack","status":"closed","priority":2,"issue_type":"task","assignee":"einstein.climateai.org","owner":"einstein.climateai.org","estimated_minutes":50,"created_at":"2026-02-20T19:55:26.436073+08:00","created_by":"einstein.climateai.org","updated_at":"2026-02-20T20:06:32.852484+08:00","closed_at":"2026-02-20T20:06:32.852484+08:00","close_reason":"1094f5d search keyboard nav + fuzzy + grouping","labels":["scope:medium"],"dependencies":[{"issue_id":"docs-z1q.1","depends_on_id":"docs-z1q","type":"parent-child","created_at":"2026-02-20T19:55:26.437153+08:00","created_by":"einstein.climateai.org"}]} {"id":"docs-z6h","title":"Epic: Mobile Responsiveness Fixes","status":"closed","priority":1,"issue_type":"epic","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T23:33:01.220879+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T23:41:13.491601+13:00","closed_at":"2026-02-16T23:41:13.491601+13:00","close_reason":"b2ca35e All 5 mobile responsiveness tasks complete"} diff --git a/lib/navigation.js b/lib/navigation.js index 0500fe7..3750eaf 100644 --- a/lib/navigation.js +++ b/lib/navigation.js @@ -3,7 +3,20 @@ export const navigation = [ section: "Get Started", children: [ { title: "Welcome", path: "/" }, - { title: "Quickstart", path: "/getting-started/quickstart" }, + { + title: "Quickstart", + path: "/getting-started/quickstart", + children: [ + { + title: "Creating Your First Hypercert", + path: "/getting-started/creating-your-first-hypercert", + }, + { + title: "Using the Scaffold App", + path: "/getting-started/using-the-scaffold-app", + }, + ], + }, { title: "Working with Evaluations", path: "/getting-started/working-with-evaluations", diff --git a/pages/getting-started/creating-your-first-hypercert.md b/pages/getting-started/creating-your-first-hypercert.md new file mode 100644 index 0000000..a69459d --- /dev/null +++ b/pages/getting-started/creating-your-first-hypercert.md @@ -0,0 +1,192 @@ +--- +title: Creating Your First Hypercert +description: Create a hypercert using TypeScript and the ATProto API. +--- + +# Creating Your First Hypercert + +This guide walks through creating a complete hypercert using code. Make sure you've completed the [setup steps](/getting-started/quickstart) first. Prefer a UI? See [Using the Scaffold App](/getting-started/using-the-scaffold-app). + +## Create the activity claim + +The activity claim is the core record — it describes what work was done, when, and in what scope. Here's how each field maps to the [activity lexicon](/lexicons/hypercerts-lexicons/activity-claim): + +- **Contributors** are embedded directly in the activity claim as a `contributors` array. Each entry has a `contributorIdentity` (inline DID string, or a strong reference to a [`contributorInformation`](/lexicons/hypercerts-lexicons/contribution) record), an optional `contributionWeight`, and an optional `contributionDetails` (inline role string, or a strong reference to an [`org.hypercerts.claim.contribution`](/lexicons/hypercerts-lexicons/contribution) record for richer detail). +- **Work scopes** can be a simple free-form string (`{ scope: "Documentation" }`) or a structured [CEL expression](/core-concepts/work-scopes) for machine-evaluable queries across the network. +- **Time** is expressed as `startDate` and `endDate` in ISO 8601 format. +- **Locations** are separate [`app.certified.location`](/lexicons/certified-lexicons/location) records referenced from the activity claim. They support coordinates, GeoJSON, and other formats. + +```typescript +const result = await agent.com.atproto.repo.createRecord({ + repo: agent.did, + collection: "org.hypercerts.claim.activity", + record: { + $type: "org.hypercerts.claim.activity", + title: "NumPy documentation maintenance, Q1 2026", + shortDescription: "Updated API docs and fixed 15 broken examples.", + description: "Created 12 new documentation pages covering quickstart, use cases, evaluations, and architecture. Migrated from GitBook to a custom Next.js + Markdoc site.", + workScope: { + $type: "org.hypercerts.claim.activity#workScopeString", + scope: "Documentation", + }, + startDate: "2026-01-01T00:00:00Z", + endDate: "2026-03-31T23:59:59Z", + createdAt: new Date().toISOString(), + }, +}); + +console.log(result.data.uri); +// → at://did:plc:abc123/org.hypercerts.claim.activity/3k2j4h5g6f7d8s9a + +console.log(result.data.cid); +// → bafyreiabc123... +``` + +Each AT-URI is a permanent, globally unique identifier. Other records (evaluations, attachments, measurements) reference your hypercert using its URI. The CID is a content hash that makes references tamper-evident. Save both — you'll need them to link other records to this hypercert. See the [Activity Claim lexicon](/lexicons/hypercerts-lexicons/activity-claim) for the complete schema. + +## Add contributions + +Contributors are embedded directly in the activity claim's `contributors` array. Each entry uses inline identity and role objects: + +```typescript +const result = await agent.com.atproto.repo.createRecord({ + repo: agent.did, + collection: "org.hypercerts.claim.activity", + record: { + $type: "org.hypercerts.claim.activity", + title: "NumPy documentation maintenance, Q1 2026", + shortDescription: "Updated API docs and fixed 15 broken examples.", + workScope: { + $type: "org.hypercerts.claim.activity#workScopeString", + scope: "Documentation", + }, + startDate: "2026-01-01T00:00:00Z", + endDate: "2026-03-31T23:59:59Z", + contributors: [ + { + contributorIdentity: { + $type: "org.hypercerts.claim.activity#contributorIdentity", + identity: "did:plc:alice123", + }, + contributionWeight: "70", + contributionDetails: { + $type: "org.hypercerts.claim.activity#contributorRole", + role: "Lead author", + }, + }, + { + contributorIdentity: { + $type: "org.hypercerts.claim.activity#contributorIdentity", + identity: "did:plc:bob456", + }, + contributionWeight: "30", + contributionDetails: { + $type: "org.hypercerts.claim.activity#contributorRole", + role: "Technical reviewer", + }, + }, + ], + createdAt: new Date().toISOString(), + }, +}); +``` + +Each contributor entry has: +- `contributorIdentity` — inline `#contributorIdentity` with a DID string, or a strong reference to an `org.hypercerts.claim.contributorInformation` record +- `contributionWeight` — relative weight as a string (weights don't need to sum to 100) +- `contributionDetails` — inline `#contributorRole` with a role string, or a strong reference to an `org.hypercerts.claim.contribution` record for richer detail + +## Attach supporting documentation + +Attachments link supporting documents, reports, or URLs to any record. Create an attachment record that references the hypercert: + +```typescript +await agent.com.atproto.repo.createRecord({ + repo: agent.did, + collection: "org.hypercerts.context.attachment", + record: { + $type: "org.hypercerts.context.attachment", + subjects: [{ uri: result.data.uri, cid: result.data.cid }], + title: "Documentation site repository", + shortDescription: "Source code and content for the Hypercerts Protocol documentation.", + content: [ + { + $type: "org.hypercerts.defs#uri", + uri: "https://github.com/hypercerts-org/hypercerts-atproto-documentation", + }, + ], + createdAt: new Date().toISOString(), + }, +}); +``` + +The `subjects` field is an array of strong references (AT-URI + CID). The `content` field is an array of `org.hypercerts.defs#uri` objects (for URLs) or `org.hypercerts.defs#smallBlob` objects (for file uploads). You can create multiple attachment records — one for the repo, one for the deployed site, one for a methodology document, etc. + +## Add a measurement + +Measurements record quantitative data about the work. Create a measurement record that references the hypercert: + +```typescript +await agent.com.atproto.repo.createRecord({ + repo: agent.did, + collection: "org.hypercerts.context.measurement", + record: { + $type: "org.hypercerts.context.measurement", + subjects: [{ uri: result.data.uri, cid: result.data.cid }], + metric: "Documentation pages written", + value: "12", + unit: "pages", + startDate: "2026-01-01T00:00:00Z", + endDate: "2026-03-31T23:59:59Z", + methodType: "manual-count", + createdAt: new Date().toISOString(), + }, +}); +``` + +Required fields are `metric`, `value`, and `unit`. The `subjects` array links the measurement to your hypercert via strong references. You can attach multiple measurements to the same hypercert — one per metric. + +## Add an evaluation + +Evaluations are third-party assessments of the work. They reference the hypercert via a single `subject` strong reference and are typically created by someone other than the hypercert author: + +```typescript +await agent.com.atproto.repo.createRecord({ + repo: agent.did, + collection: "org.hypercerts.context.evaluation", + record: { + $type: "org.hypercerts.context.evaluation", + subject: { uri: result.data.uri, cid: result.data.cid }, + evaluators: [{ did: "did:plc:ragtjsm2j2vknwkz3zp4oxrd" }], + summary: "High-quality documentation with clear examples and thorough coverage.", + score: { min: 1, max: 5, value: 4 }, + content: [ + { + $type: "org.hypercerts.defs#uri", + uri: "https://example.com/evaluation-report.pdf", + }, + ], + createdAt: new Date().toISOString(), + }, +}); +``` + +Required fields are `evaluators`, `summary`, and `createdAt`. Unlike attachments and measurements, `subject` is a single strong reference (not an array). The optional `score` object takes integer `min`, `max`, and `value` fields. + +## What you've built + +Your hypercert now has a complete structure: + +```text +Activity Claim (the core record) +├── contributors[] (embedded) +│ ├── Alice — identity: did:plc:alice123, weight: 70, role: Lead author +│ └── Bob — identity: did:plc:bob456, weight: 30, role: Technical reviewer +├── Attachment: GitHub repository link ← strong reference (AT-URI + CID) +├── Measurement: 12 pages written ← strong reference (AT-URI + CID) +└── Evaluation: "High-quality documentation" (by Carol) ← strong reference (AT-URI + CID) +``` + +Contributors live inside the activity claim record itself. External records — attachments, measurements, evaluations — link to the activity claim via **strong references** (AT-URI + CID). The CID is a content hash: if the referenced record changes, the hash won't match, making the entire structure tamper-evident. + +This is the same pattern described in the [Core Data Model](/core-concepts/hypercerts-core-data-model#how-records-connect). As the hypercert grows over time, third parties can add measurements, evaluations, and more attachments — each as a separate record referencing your activity claim. diff --git a/pages/getting-started/quickstart.md b/pages/getting-started/quickstart.md index da232a0..8868c2f 100644 --- a/pages/getting-started/quickstart.md +++ b/pages/getting-started/quickstart.md @@ -1,17 +1,22 @@ --- title: Quickstart -description: Create your first hypercert in under 5 minutes. +description: Get set up to create hypercerts — via code or the Scaffold app. --- # Quickstart -Create your first hypercert. This guide uses TypeScript and Node.js v20+. +There are two ways to create a hypercert: - +Both approaches create the same records on your PDS. Pick whichever fits your workflow. -## Install dependencies +## Setup (for the code path) + +If you're using the Scaffold app, skip this — just go to [hypercerts-scaffold.vercel.app](https://hypercerts-scaffold.vercel.app) and sign in with your ATProto handle. + +### Install dependencies ```bash pnpm add @atproto/oauth-client-node @atproto/jwk-jose @atproto/api @@ -21,7 +26,7 @@ pnpm add @atproto/oauth-client-node @atproto/jwk-jose @atproto/api Building a React app? Use `@atproto/oauth-client-browser` instead, alongside `@tanstack/react-query` for data fetching and caching. {% /callout %} -## Authenticate +### Authenticate Authentication uses AT Protocol OAuth. Your app needs a client metadata document hosted at a public URL: @@ -65,290 +70,3 @@ const agent = new Agent(session); ``` See the [AT Protocol OAuth documentation](https://atproto.com/specs/oauth) for full details on client metadata, session storage, and keyset configuration. For further info on how to set up OAuth you can check out [AT Protos node.js implementation tutorial](https://atproto.com/guides/oauth-cli-tutorial) or the [scaffold app](/tools/scaffold). - -## Create your first hypercert - -The activity claim is the core record — it describes what work was done, when, and in what scope. Here's how each field maps to the [activity lexicon](/lexicons/hypercerts-lexicons/activity-claim): - -- **Contributors** are embedded directly in the activity claim as a `contributors` array. Each entry has a `contributorIdentity` (inline DID string, or a strong reference to a [`contributorInformation`](/lexicons/hypercerts-lexicons/contributor-information) record), an optional `contributionWeight`, and an optional `contributionDetails` (inline role string, or a strong reference to an [`org.hypercerts.claim.contribution`](/lexicons/hypercerts-lexicons/contribution) record for richer detail). -- **Work scopes** can be a simple free-form string (`{ scope: "Documentation" }`) or a structured [CEL expression](/core-concepts/work-scopes) for machine-evaluable queries across the network. -- **Time** is expressed as `startDate` and `endDate` in ISO 8601 format. -- **Locations** are separate [`app.certified.location`](/lexicons/certified-lexicons/location) records referenced from the activity claim. They support coordinates, GeoJSON, and other formats. - -```typescript -const result = await agent.com.atproto.repo.createRecord({ - repo: agent.did, - collection: "org.hypercerts.claim.activity", - record: { - $type: "org.hypercerts.claim.activity", - title: "NumPy documentation maintenance, Q1 2026", - shortDescription: "Updated API docs and fixed 15 broken examples.", - description: "Created 12 new documentation pages covering quickstart, use cases, evaluations, and architecture. Migrated from GitBook to a custom Next.js + Markdoc site.", - workScope: { - $type: "org.hypercerts.claim.activity#workScopeString", - scope: "Documentation", - }, - startDate: "2026-01-01T00:00:00Z", - endDate: "2026-03-31T23:59:59Z", - createdAt: new Date().toISOString(), - }, -}); - -console.log(result.data.uri); -// → at://did:plc:abc123/org.hypercerts.claim.activity/3k2j4h5g6f7d8s9a - -console.log(result.data.cid); -// → bafyreiabc123... -``` - -Each AT-URI is a permanent, globally unique identifier. Other records (evaluations, attachments, measurements) reference your hypercert using its URI. The CID is a content hash that makes references tamper-evident. Save both — you'll need them to link other records to this hypercert. See the [Activity Claim lexicon](/lexicons/hypercerts-lexicons/activity-claim) for the complete schema. - -## Add contributions - -Contributors are embedded directly in the activity claim's `contributors` array. Each entry uses inline identity and role objects: - -```typescript -const result = await agent.com.atproto.repo.createRecord({ - repo: agent.did, - collection: "org.hypercerts.claim.activity", - record: { - $type: "org.hypercerts.claim.activity", - title: "NumPy documentation maintenance, Q1 2026", - shortDescription: "Updated API docs and fixed 15 broken examples.", - workScope: { - $type: "org.hypercerts.claim.activity#workScopeString", - scope: "Documentation", - }, - startDate: "2026-01-01T00:00:00Z", - endDate: "2026-03-31T23:59:59Z", - contributors: [ - { - contributorIdentity: { - $type: "org.hypercerts.claim.activity#contributorIdentity", - identity: "did:plc:alice123", - }, - contributionWeight: "70", - contributionDetails: { - $type: "org.hypercerts.claim.activity#contributorRole", - role: "Lead author", - }, - }, - { - contributorIdentity: { - $type: "org.hypercerts.claim.activity#contributorIdentity", - identity: "did:plc:bob456", - }, - contributionWeight: "30", - contributionDetails: { - $type: "org.hypercerts.claim.activity#contributorRole", - role: "Technical reviewer", - }, - }, - ], - createdAt: new Date().toISOString(), - }, -}); -``` - -Each contributor entry has: -- `contributorIdentity` — inline `#contributorIdentity` with a DID string, or a strong reference to an `org.hypercerts.claim.contributorInformation` record -- `contributionWeight` — relative weight as a string (weights don't need to sum to 100) -- `contributionDetails` — inline `#contributorRole` with a role string, or a strong reference to an `org.hypercerts.claim.contribution` record for richer detail - -## Attach supporting documentation - -Attachments link supporting documents, reports, or URLs to any record. Create an attachment record that references the hypercert: - -```typescript -await agent.com.atproto.repo.createRecord({ - repo: agent.did, - collection: "org.hypercerts.context.attachment", - record: { - $type: "org.hypercerts.context.attachment", - subjects: [{ uri: result.data.uri, cid: result.data.cid }], - title: "Documentation site repository", - shortDescription: "Source code and content for the Hypercerts Protocol documentation.", - content: [ - { - $type: "org.hypercerts.defs#uri", - uri: "https://github.com/hypercerts-org/hypercerts-atproto-documentation", - }, - ], - createdAt: new Date().toISOString(), - }, -}); -``` - -The `subjects` field is an array of strong references (AT-URI + CID). The `content` field is an array of `org.hypercerts.defs#uri` objects (for URLs) or `org.hypercerts.defs#smallBlob` objects (for file uploads). You can create multiple attachment records — one for the repo, one for the deployed site, one for a methodology document, etc. - -## Add a measurement - -Measurements record quantitative data about the work. Create a measurement record that references the hypercert: - -```typescript -await agent.com.atproto.repo.createRecord({ - repo: agent.did, - collection: "org.hypercerts.context.measurement", - record: { - $type: "org.hypercerts.context.measurement", - subjects: [{ uri: result.data.uri, cid: result.data.cid }], - metric: "Documentation pages written", - value: "12", - unit: "pages", - startDate: "2026-01-01T00:00:00Z", - endDate: "2026-03-31T23:59:59Z", - methodType: "manual-count", - createdAt: new Date().toISOString(), - }, -}); -``` - -Required fields are `metric`, `value`, and `unit`. The `subjects` array links the measurement to your hypercert via strong references. You can attach multiple measurements to the same hypercert — one per metric. - -## Add an evaluation - -Evaluations are third-party assessments of the work. They reference the hypercert via a single `subject` strong reference and are typically created by someone other than the hypercert author: - -```typescript -await agent.com.atproto.repo.createRecord({ - repo: agent.did, - collection: "org.hypercerts.context.evaluation", - record: { - $type: "org.hypercerts.context.evaluation", - subject: { uri: result.data.uri, cid: result.data.cid }, - evaluators: [{ did: "did:plc:ragtjsm2j2vknwkz3zp4oxrd" }], - summary: "High-quality documentation with clear examples and thorough coverage.", - score: { min: 1, max: 5, value: 4 }, - content: [ - { - $type: "org.hypercerts.defs#uri", - uri: "https://example.com/evaluation-report.pdf", - }, - ], - createdAt: new Date().toISOString(), - }, -}); -``` - -Required fields are `evaluators`, `summary`, and `createdAt`. Unlike attachments and measurements, `subject` is a single strong reference (not an array). The optional `score` object takes integer `min`, `max`, and `value` fields. - -## What you've built - -Your hypercert now has a complete structure: - -```text -Activity Claim (the core record) -├── contributors[] (embedded) -│ ├── Alice — identity: did:plc:alice123, weight: 70, role: Lead author -│ └── Bob — identity: did:plc:bob456, weight: 30, role: Technical reviewer -├── Attachment: GitHub repository link ← strong reference (AT-URI + CID) -├── Measurement: 12 pages written ← strong reference (AT-URI + CID) -└── Evaluation: "High-quality documentation" (by Carol) ← strong reference (AT-URI + CID) -``` - -Contributors live inside the activity claim record itself. External records — attachments, measurements, evaluations — link to the activity claim via **strong references** (AT-URI + CID). The CID is a content hash: if the referenced record changes, the hash won't match, making the entire structure tamper-evident. - -This is the same pattern described in the [Core Data Model](/core-concepts/hypercerts-core-data-model#how-records-connect). As the hypercert grows over time, third parties can add measurements, evaluations, and more attachments — each as a separate record referencing your activity claim. - -## Create via the Scaffold App - -If you don't want to write code, the [Scaffold app](https://hypercerts-scaffold.vercel.app) lets you create a full hypercert through a guided wizard. Visit [hypercerts-scaffold.vercel.app](https://hypercerts-scaffold.vercel.app) to get started. - -### Step 1 — Sign in - -Enter your ATProto handle (e.g. `yourname.certified.app` or `yourname.bsky.social`) on the sign-in screen. You'll be redirected to your PDS to authorize the app. Once you approve, you'll land on the home screen with your DID and display name visible. - -![Scaffold sign-in screen showing handle input field](/images/scaffold/sign-in.png) -*Enter your ATProto handle to authenticate via OAuth.* - -### Step 2 — Basic info - -Click **"Create a new hypercert"** on the home screen (or go directly to [hypercerts-scaffold.vercel.app/hypercerts/create](https://hypercerts-scaffold.vercel.app/hypercerts/create)). This opens a multi-step wizard. The first step collects the core fields that form the `org.hypercerts.claim.activity` record on your PDS. - -![Hypercert creation form showing title, description, work scope, and date fields](/images/scaffold/create-cert.png) -*Step 1: Define the basic claim — what work was done, when, and in what scope.* - -| Field | Description | -|---|---| -| **Title** | A specific name for this piece of work. Be verbose — a project may have many hypercerts over time. Max 256 characters. Example: `NumPy documentation maintenance, Q1 2026`. | -| **Short description** | A 1–3 sentence summary suitable for card previews and list views. Max 300 characters. | -| **Description** | A longer narrative of what was done, by whom, and how. Supports rich text. Max 3,000 characters. | -| **Work scope** | One or more tags that precisely define what work is included. Multiple tags are conjunctive — e.g. `Trees` + `Germany` means only tree-planting in Germany. Leave empty for an unconstrained scope. | -| **Start date** | When the work began (ISO 8601). | -| **End date** | When the work ended (ISO 8601). | -| **Cover image** | An optional image for the hypercert card — URL or file upload. | -| **Rights Information** | Required information about the rights to this hypercert | -| **Contributors** *(optional)* | The people or organizations that did the work. Each contributor has an identity (DID or name), an optional relative weight, and an optional role description. You can add multiple contributors here or leave this empty. | - -### Step 3 — Add attachments - -Attach supporting documentation that backs up the claim — reports, URLs, files, or other references. Each attachment becomes an `org.hypercerts.context.attachment` record linked to your hypercert. - -![Evidence form for attaching supporting documentation](/images/scaffold/add-evidence.png) -*Step 2: Attach supporting documentation to back up the claim.* - -| Field | Description | -|---|---| -| **Title** | A label for this attachment. Max 256 characters. Example: `GitHub repository`. | -| **Attachment type** | The kind of attachment: `report`, `audit`, `evidence`, `testimonial`, `methodology`, etc. Max 64 characters. | -| **Short description** | A brief summary of what this attachment contains. Max 300 characters. | -| **Detailed description** | A detailed summary of what this attachment contains. (optional) | -| **Content** | One or more URLs or file uploads that make up the attachment. Max 100 items. | - -### Step 4 — Add location *(optional)* - -Optionally anchor the work geographically. This creates an `app.certified.location` record referenced from your hypercert. - -![Location form for adding geographic context](/images/scaffold/add-location.png) -*Step 3: Add location data to anchor the work geographically.* - -| Field | Description | -|---|---| -| **Name** | A human-readable place name. Example: `Amazon Basin, Brazil`. Max 100 characters. | -| **Location type** | The format of the location data: `coordinate-decimal`, `geojson`, `address`, `h3`, `geohash`, `wkt`, etc. | -| **Location Data** | The location data in the chosen format. Example for `coordinate-decimal`: `-3.47, -62.21`. | -| **Location Description** | Optional context about the location. Max 500 characters. | - -### Step 5 — Add measurements *(optional)* - -Add quantitative data that makes the impact concrete — metrics, values, units, and measurement methods. Each entry becomes an `org.hypercerts.context.measurement` record. - -![Measurement form for adding quantitative impact data](/images/scaffold/add-measurement.png) -*Step 4: Add measurements to quantify the impact.* - -| Field | Description | -|---|---| -| **Metric** | What is being measured. Example: `pages written`, `CO₂e avoided`, `users reached`. Max 500 characters. | -| **Value** | The measured numeric value. Example: `12`. | -| **Unit** | The unit of measurement. Example: `pages`, `kg CO₂e`, `hectares`, `count`. Max 50 characters. | -| **Start / end date** | The period during which this measurement was taken. | -| **Method type** | A short identifier for how it was measured. Example: `automated-count`, `manual-survey`. Max 30 characters. | -| **Method URI** | A link to the methodology documentation or standard protocol. | - -### Step 6 — Add evaluations *(optional)* - -Add third-party assessments of the work. Evaluations are authored by evaluators and can reference measurements. Each entry becomes an `org.hypercerts.context.evaluation` record. - -![Evaluation form for adding third-party assessments](/images/scaffold/add-evaluation.png) -*Step 5: Add evaluations from third-party assessors.* - -| Field | Description | -|---|---| -| **Evaluators** | DIDs or handles of the users who contributed to this evaluation | -| **Summary** | A brief written assessment of the work. Max 1,000 characters. Example: `High-quality documentation with clear examples and thorough coverage.` | -| **Score** *(optional)* | A numeric score on a defined scale. Set a minimum, maximum, and value — e.g. min 1, max 5, value 4. | -| **Content** *(optional)* | Links to detailed evaluation reports or methodology documents — URLs or file uploads. | -| **Measurement** *(optional)* | URI to the measurement tied to this evaluation. It can also be a normal URL. | - -### Step 7 — Done - -Your hypercert is now created and stored on your PDS. The completion screen shows the finalized record — copy the AT-URI to reference it from other records (attachments, measurements, evaluations) or to share it. - -![Completion screen showing the finished hypercert](/images/scaffold/finalized-cert.png) -*The hypercert is created and stored on your PDS.* - -For full details on the Scaffold app — including self-hosting, environment setup, and extending the codebase — see the [Scaffold app documentation](/tools/scaffold). - -## Next steps - -Third parties can now [evaluate your hypercert](/getting-started/working-with-evaluations) by creating evaluation records and measurements on their own PDS. diff --git a/pages/getting-started/using-the-scaffold-app.md b/pages/getting-started/using-the-scaffold-app.md new file mode 100644 index 0000000..6d6c231 --- /dev/null +++ b/pages/getting-started/using-the-scaffold-app.md @@ -0,0 +1,103 @@ +--- +title: Using the Scaffold App +description: Create a hypercert using the Scaffold app — no code required. +--- + +# Using the Scaffold App + +The [Scaffold app](https://hypercerts-scaffold.vercel.app) lets you create a full hypercert through a guided wizard — no code required. For the code-based approach, see [Creating Your First Hypercert](/getting-started/creating-your-first-hypercert). + +### Step 1 — Sign in + +Enter your ATProto handle (e.g. `yourname.certified.app` or `yourname.bsky.social`) on the sign-in screen. You'll be redirected to your PDS to authorize the app. Once you approve, you'll land on the home screen with your DID and display name visible. + +![Scaffold sign-in screen showing handle input field](/images/scaffold/sign-in.png) +*Enter your ATProto handle to authenticate via OAuth.* + +### Step 2 — Basic info + +Click **"Create a new hypercert"** on the home screen (or go directly to [hypercerts-scaffold.vercel.app/hypercerts/create](https://hypercerts-scaffold.vercel.app/hypercerts/create)). This opens a multi-step wizard. The first step collects the core fields that form the `org.hypercerts.claim.activity` record on your PDS. + +![Hypercert creation form showing title, description, work scope, and date fields](/images/scaffold/create-cert.png) +*Step 1: Define the basic claim — what work was done, when, and in what scope.* + +| Field | Description | +|---|---| +| **Title** | A specific name for this piece of work. Be verbose — a project may have many hypercerts over time. Max 256 characters. Example: `NumPy documentation maintenance, Q1 2026`. | +| **Short description** | A 1–3 sentence summary suitable for card previews and list views. Max 300 characters. | +| **Description** | A longer narrative of what was done, by whom, and how. Supports rich text. Max 3,000 characters. | +| **Work scope** | One or more tags that precisely define what work is included. Multiple tags are conjunctive — e.g. `Trees` + `Germany` means only tree-planting in Germany. Leave empty for an unconstrained scope. | +| **Start date** | When the work began (ISO 8601). | +| **End date** | When the work ended (ISO 8601). | +| **Cover image** | An optional image for the hypercert card — URL or file upload. | +| **Rights Information** | Required information about the rights to this hypercert | +| **Contributors** *(optional)* | The people or organizations that did the work. Each contributor has an identity (DID or name), an optional relative weight, and an optional role description. You can add multiple contributors here or leave this empty. | + +### Step 3 — Add attachments + +Attach supporting documentation that backs up the claim — reports, URLs, files, or other references. Each attachment becomes an `org.hypercerts.context.attachment` record linked to your hypercert. + +![Evidence form for attaching supporting documentation](/images/scaffold/add-evidence.png) +*Step 2: Attach supporting documentation to back up the claim.* + +| Field | Description | +|---|---| +| **Title** | A label for this attachment. Max 256 characters. Example: `GitHub repository`. | +| **Attachment type** | The kind of attachment: `report`, `audit`, `evidence`, `testimonial`, `methodology`, etc. Max 64 characters. | +| **Short description** | A brief summary of what this attachment contains. Max 300 characters. | +| **Detailed description** | A detailed summary of what this attachment contains. (optional) | +| **Content** | One or more URLs or file uploads that make up the attachment. Max 100 items. | + +### Step 4 — Add location *(optional)* + +Optionally anchor the work geographically. This creates an `app.certified.location` record referenced from your hypercert. + +![Location form for adding geographic context](/images/scaffold/add-location.png) +*Step 3: Add location data to anchor the work geographically.* + +| Field | Description | +|---|---| +| **Name** | A human-readable place name. Example: `Amazon Basin, Brazil`. Max 100 characters. | +| **Location type** | The format of the location data: `coordinate-decimal`, `geojson`, `address`, `h3`, `geohash`, `wkt`, etc. | +| **Location Data** | The location data in the chosen format. Example for `coordinate-decimal`: `-3.47, -62.21`. | +| **Location Description** | Optional context about the location. Max 500 characters. | + +### Step 5 — Add measurements *(optional)* + +Add quantitative data that makes the impact concrete — metrics, values, units, and measurement methods. Each entry becomes an `org.hypercerts.context.measurement` record. + +![Measurement form for adding quantitative impact data](/images/scaffold/add-measurement.png) +*Step 4: Add measurements to quantify the impact.* + +| Field | Description | +|---|---| +| **Metric** | What is being measured. Example: `pages written`, `CO₂e avoided`, `users reached`. Max 500 characters. | +| **Value** | The measured numeric value. Example: `12`. | +| **Unit** | The unit of measurement. Example: `pages`, `kg CO₂e`, `hectares`, `count`. Max 50 characters. | +| **Start / end date** | The period during which this measurement was taken. | +| **Method type** | A short identifier for how it was measured. Example: `automated-count`, `manual-survey`. Max 30 characters. | +| **Method URI** | A link to the methodology documentation or standard protocol. | + +### Step 6 — Add evaluations *(optional)* + +Add third-party assessments of the work. Evaluations are authored by evaluators and can reference measurements. Each entry becomes an `org.hypercerts.context.evaluation` record. + +![Evaluation form for adding third-party assessments](/images/scaffold/add-evaluation.png) +*Step 5: Add evaluations from third-party assessors.* + +| Field | Description | +|---|---| +| **Evaluators** | DIDs or handles of the users who contributed to this evaluation | +| **Summary** | A brief written assessment of the work. Max 1,000 characters. Example: `High-quality documentation with clear examples and thorough coverage.` | +| **Score** *(optional)* | A numeric score on a defined scale. Set a minimum, maximum, and value — e.g. min 1, max 5, value 4. | +| **Content** *(optional)* | Links to detailed evaluation reports or methodology documents — URLs or file uploads. | +| **Measurement** *(optional)* | URI to the measurement tied to this evaluation. It can also be a normal URL. | + +### Step 7 — Done + +Your hypercert is now created and stored on your PDS. The completion screen shows the finalized record — copy the AT-URI to reference it from other records (attachments, measurements, evaluations) or to share it. + +![Completion screen showing the finished hypercert](/images/scaffold/finalized-cert.png) +*The hypercert is created and stored on your PDS.* + +For full details on the Scaffold app — including self-hosting, environment setup, and extending the codebase — see the [Scaffold app documentation](/tools/scaffold). From 4d9e88d77f39f6a87f347abb58260416522e981c Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Fri, 6 Mar 2026 13:23:05 +0800 Subject: [PATCH 2/8] docs: rename group to 'Creating Your First Hypercert', children to 'Using Code' and 'Using the Scaffold App' --- lib/navigation.js | 4 ++-- pages/getting-started/creating-your-first-hypercert.md | 4 ++-- pages/getting-started/quickstart.md | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/navigation.js b/lib/navigation.js index 3750eaf..ccf18ef 100644 --- a/lib/navigation.js +++ b/lib/navigation.js @@ -4,11 +4,11 @@ export const navigation = [ children: [ { title: "Welcome", path: "/" }, { - title: "Quickstart", + title: "Creating Your First Hypercert", path: "/getting-started/quickstart", children: [ { - title: "Creating Your First Hypercert", + title: "Using Code", path: "/getting-started/creating-your-first-hypercert", }, { diff --git a/pages/getting-started/creating-your-first-hypercert.md b/pages/getting-started/creating-your-first-hypercert.md index a69459d..beb231c 100644 --- a/pages/getting-started/creating-your-first-hypercert.md +++ b/pages/getting-started/creating-your-first-hypercert.md @@ -1,9 +1,9 @@ --- -title: Creating Your First Hypercert +title: Using Code description: Create a hypercert using TypeScript and the ATProto API. --- -# Creating Your First Hypercert +# Using Code This guide walks through creating a complete hypercert using code. Make sure you've completed the [setup steps](/getting-started/quickstart) first. Prefer a UI? See [Using the Scaffold App](/getting-started/using-the-scaffold-app). diff --git a/pages/getting-started/quickstart.md b/pages/getting-started/quickstart.md index 8868c2f..9e9c622 100644 --- a/pages/getting-started/quickstart.md +++ b/pages/getting-started/quickstart.md @@ -1,13 +1,13 @@ --- -title: Quickstart +title: Creating Your First Hypercert description: Get set up to create hypercerts — via code or the Scaffold app. --- -# Quickstart +# Creating Your First Hypercert There are two ways to create a hypercert: -- **[Creating Your First Hypercert](/getting-started/creating-your-first-hypercert)** — using TypeScript and the ATProto API directly +- **[Using Code](/getting-started/creating-your-first-hypercert)** — TypeScript and the ATProto API - **[Using the Scaffold App](/getting-started/using-the-scaffold-app)** — a guided UI wizard, no code required Both approaches create the same records on your PDS. Pick whichever fits your workflow. From 3ebfa3d2282c97ad74c9b37448ea6db7a876543e Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Fri, 6 Mar 2026 13:52:53 +0800 Subject: [PATCH 3/8] docs: move setup into Using Code, slim parent page, rename to Using the UI --- lib/navigation.js | 2 +- .../creating-your-first-hypercert.md | 57 ++++++++++++++++- pages/getting-started/quickstart.md | 63 +------------------ .../getting-started/using-the-scaffold-app.md | 6 +- 4 files changed, 62 insertions(+), 66 deletions(-) diff --git a/lib/navigation.js b/lib/navigation.js index ccf18ef..8842c24 100644 --- a/lib/navigation.js +++ b/lib/navigation.js @@ -12,7 +12,7 @@ export const navigation = [ path: "/getting-started/creating-your-first-hypercert", }, { - title: "Using the Scaffold App", + title: "Using the UI", path: "/getting-started/using-the-scaffold-app", }, ], diff --git a/pages/getting-started/creating-your-first-hypercert.md b/pages/getting-started/creating-your-first-hypercert.md index beb231c..7754158 100644 --- a/pages/getting-started/creating-your-first-hypercert.md +++ b/pages/getting-started/creating-your-first-hypercert.md @@ -5,7 +5,62 @@ description: Create a hypercert using TypeScript and the ATProto API. # Using Code -This guide walks through creating a complete hypercert using code. Make sure you've completed the [setup steps](/getting-started/quickstart) first. Prefer a UI? See [Using the Scaffold App](/getting-started/using-the-scaffold-app). +This guide walks through creating a complete hypercert using TypeScript and Node.js v20+. Prefer a UI? See [Using the UI](/getting-started/using-the-scaffold-app). + +## Install dependencies + +```bash +pnpm add @atproto/oauth-client-node @atproto/jwk-jose @atproto/api +``` + +{% callout type="info" %} +Building a React app? Use `@atproto/oauth-client-browser` instead, alongside `@tanstack/react-query` for data fetching and caching. +{% /callout %} + +## Authenticate + +Authentication uses AT Protocol OAuth. Your app needs a client metadata document hosted at a public URL: + +```typescript +import { NodeOAuthClient } from "@atproto/oauth-client-node"; +import { JoseKey } from "@atproto/jwk-jose"; +import { Agent } from "@atproto/api"; + +const client = new NodeOAuthClient({ + clientMetadata: { + client_id: "https://your-app.example.com/client-metadata.json", + client_name: "My App", + client_uri: "https://your-app.example.com", + redirect_uris: ["https://your-app.example.com/callback"], + grant_types: ["authorization_code", "refresh_token"], + scope: "atproto transition:generic", + response_types: ["code"], + application_type: "web", + token_endpoint_auth_method: "private_key_jwt", + token_endpoint_auth_signing_alg: "RS256", + dpop_bound_access_tokens: true, + jwks_uri: "https://your-app.example.com/jwks.json", + }, + keyset: await Promise.all([ + JoseKey.fromImportable(process.env.PRIVATE_KEY_1, "key1"), + JoseKey.fromImportable(process.env.PRIVATE_KEY_2, "key2"), + JoseKey.fromImportable(process.env.PRIVATE_KEY_3, "key3"), + ]), + stateStore: { /* ... your state store implementation */ }, + sessionStore: { /* ... your session store implementation */ }, +}); + +// Redirect the user to their PDS to authorize +const url = await client.authorize("alice.certified.app"); + +// After the user approves, exchange the callback params for a session +const { session } = await client.callback(new URLSearchParams(callbackQuery)); + +// Wrap the session in an Agent to make authenticated calls +const agent = new Agent(session); +``` + +See the [AT Protocol OAuth documentation](https://atproto.com/specs/oauth) for full details on client metadata, session storage, and keyset configuration. For further info on how to set up OAuth you can check out [AT Protos node.js implementation tutorial](https://atproto.com/guides/oauth-cli-tutorial) or the [scaffold app](/tools/scaffold). ## Create the activity claim diff --git a/pages/getting-started/quickstart.md b/pages/getting-started/quickstart.md index 9e9c622..bbeade6 100644 --- a/pages/getting-started/quickstart.md +++ b/pages/getting-started/quickstart.md @@ -1,6 +1,6 @@ --- title: Creating Your First Hypercert -description: Get set up to create hypercerts — via code or the Scaffold app. +description: Create your first hypercert — via code or the UI. --- # Creating Your First Hypercert @@ -8,65 +8,6 @@ description: Get set up to create hypercerts — via code or the Scaffold app. There are two ways to create a hypercert: - **[Using Code](/getting-started/creating-your-first-hypercert)** — TypeScript and the ATProto API -- **[Using the Scaffold App](/getting-started/using-the-scaffold-app)** — a guided UI wizard, no code required +- **[Using the UI](/getting-started/using-the-scaffold-app)** — a guided wizard, no code required Both approaches create the same records on your PDS. Pick whichever fits your workflow. - -## Setup (for the code path) - -If you're using the Scaffold app, skip this — just go to [hypercerts-scaffold.vercel.app](https://hypercerts-scaffold.vercel.app) and sign in with your ATProto handle. - -### Install dependencies - -```bash -pnpm add @atproto/oauth-client-node @atproto/jwk-jose @atproto/api -``` - -{% callout type="info" %} -Building a React app? Use `@atproto/oauth-client-browser` instead, alongside `@tanstack/react-query` for data fetching and caching. -{% /callout %} - -### Authenticate - -Authentication uses AT Protocol OAuth. Your app needs a client metadata document hosted at a public URL: - -```typescript -import { NodeOAuthClient } from "@atproto/oauth-client-node"; -import { JoseKey } from "@atproto/jwk-jose"; -import { Agent } from "@atproto/api"; - -const client = new NodeOAuthClient({ - clientMetadata: { - client_id: "https://your-app.example.com/client-metadata.json", - client_name: "My App", - client_uri: "https://your-app.example.com", - redirect_uris: ["https://your-app.example.com/callback"], - grant_types: ["authorization_code", "refresh_token"], - scope: "atproto transition:generic", - response_types: ["code"], - application_type: "web", - token_endpoint_auth_method: "private_key_jwt", - token_endpoint_auth_signing_alg: "RS256", - dpop_bound_access_tokens: true, - jwks_uri: "https://your-app.example.com/jwks.json", - }, - keyset: await Promise.all([ - JoseKey.fromImportable(process.env.PRIVATE_KEY_1, "key1"), - JoseKey.fromImportable(process.env.PRIVATE_KEY_2, "key2"), - JoseKey.fromImportable(process.env.PRIVATE_KEY_3, "key3"), - ]), - stateStore: { /* ... your state store implementation */ }, - sessionStore: { /* ... your session store implementation */ }, -}); - -// Redirect the user to their PDS to authorize -const url = await client.authorize("alice.certified.app"); - -// After the user approves, exchange the callback params for a session -const { session } = await client.callback(new URLSearchParams(callbackQuery)); - -// Wrap the session in an Agent to make authenticated calls -const agent = new Agent(session); -``` - -See the [AT Protocol OAuth documentation](https://atproto.com/specs/oauth) for full details on client metadata, session storage, and keyset configuration. For further info on how to set up OAuth you can check out [AT Protos node.js implementation tutorial](https://atproto.com/guides/oauth-cli-tutorial) or the [scaffold app](/tools/scaffold). diff --git a/pages/getting-started/using-the-scaffold-app.md b/pages/getting-started/using-the-scaffold-app.md index 6d6c231..5ec63ce 100644 --- a/pages/getting-started/using-the-scaffold-app.md +++ b/pages/getting-started/using-the-scaffold-app.md @@ -1,11 +1,11 @@ --- -title: Using the Scaffold App +title: Using the UI description: Create a hypercert using the Scaffold app — no code required. --- -# Using the Scaffold App +# Using the UI -The [Scaffold app](https://hypercerts-scaffold.vercel.app) lets you create a full hypercert through a guided wizard — no code required. For the code-based approach, see [Creating Your First Hypercert](/getting-started/creating-your-first-hypercert). +The [Scaffold app](https://hypercerts-scaffold.vercel.app) lets you create a full hypercert through a guided wizard — no code required. For the code-based approach, see [Using Code](/getting-started/creating-your-first-hypercert). ### Step 1 — Sign in From 1b0117549d58de92320fef353aaf009611d7d680 Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Fri, 6 Mar 2026 13:57:27 +0800 Subject: [PATCH 4/8] =?UTF-8?q?docs:=20fix=20intro=20=E2=80=94=20any=20ATP?= =?UTF-8?q?roto=20tool=20can=20create=20hypercerts,=20these=20are=20two=20?= =?UTF-8?q?common=20approaches?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/getting-started/quickstart.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pages/getting-started/quickstart.md b/pages/getting-started/quickstart.md index bbeade6..666786b 100644 --- a/pages/getting-started/quickstart.md +++ b/pages/getting-started/quickstart.md @@ -5,9 +5,7 @@ description: Create your first hypercert — via code or the UI. # Creating Your First Hypercert -There are two ways to create a hypercert: +A hypercert is a set of ATProto records on your PDS — any tool that can write ATProto records can create one. These guides cover two common approaches: - **[Using Code](/getting-started/creating-your-first-hypercert)** — TypeScript and the ATProto API - **[Using the UI](/getting-started/using-the-scaffold-app)** — a guided wizard, no code required - -Both approaches create the same records on your PDS. Pick whichever fits your workflow. From e907eb272928c4692150d3cc8777588f7880b80c Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Fri, 6 Mar 2026 14:00:43 +0800 Subject: [PATCH 5/8] =?UTF-8?q?docs:=20simplify=20intro=20=E2=80=94=20just?= =?UTF-8?q?=20link=20to=20the=20two=20guides?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/getting-started/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/getting-started/quickstart.md b/pages/getting-started/quickstart.md index 666786b..1ba77d7 100644 --- a/pages/getting-started/quickstart.md +++ b/pages/getting-started/quickstart.md @@ -5,7 +5,7 @@ description: Create your first hypercert — via code or the UI. # Creating Your First Hypercert -A hypercert is a set of ATProto records on your PDS — any tool that can write ATProto records can create one. These guides cover two common approaches: +These guides cover two common approaches: - **[Using Code](/getting-started/creating-your-first-hypercert)** — TypeScript and the ATProto API - **[Using the UI](/getting-started/using-the-scaffold-app)** — a guided wizard, no code required From 60306393738ce5f36452d79a4b25096ee6837895 Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Fri, 6 Mar 2026 14:01:50 +0800 Subject: [PATCH 6/8] docs: add CLI as third approach on quickstart intro --- pages/getting-started/quickstart.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pages/getting-started/quickstart.md b/pages/getting-started/quickstart.md index 1ba77d7..26ffc96 100644 --- a/pages/getting-started/quickstart.md +++ b/pages/getting-started/quickstart.md @@ -5,7 +5,8 @@ description: Create your first hypercert — via code or the UI. # Creating Your First Hypercert -These guides cover two common approaches: +These guides cover three common approaches: - **[Using Code](/getting-started/creating-your-first-hypercert)** — TypeScript and the ATProto API - **[Using the UI](/getting-started/using-the-scaffold-app)** — a guided wizard, no code required +- **[Using the CLI](/tools/hypercerts-cli)** — the `hc` command-line tool From 744d06db8c13eb7e39ced321296ab5d5eac844db Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Fri, 6 Mar 2026 14:09:20 +0800 Subject: [PATCH 7/8] docs: add CLI to sidebar under Creating Your First Hypercert --- lib/navigation.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/navigation.js b/lib/navigation.js index 8842c24..2a75e55 100644 --- a/lib/navigation.js +++ b/lib/navigation.js @@ -15,6 +15,10 @@ export const navigation = [ title: "Using the UI", path: "/getting-started/using-the-scaffold-app", }, + { + title: "Using the CLI", + path: "/tools/hypercerts-cli", + }, ], }, { From e0ce7efa8c68590330c86fbc5134738d1d9f6c0d Mon Sep 17 00:00:00 2001 From: Sharfy Adamantine Date: Fri, 6 Mar 2026 14:11:33 +0800 Subject: [PATCH 8/8] =?UTF-8?q?beads:=20plan=20hypercerts-atproto-document?= =?UTF-8?q?ation-pzc=20=E2=80=94=20TOC=20heading=20hierarchy=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .beads/issues.jsonl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 18824d5..434c35f 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -129,6 +129,8 @@ {"id":"docs-z6h.5","title":"Add small mobile breakpoint (\u003c 480px) and pagination stacking","description":"## Files\n- documentation/styles/globals.css (modify)\n\n## What to do\nAdd a small mobile breakpoint for very narrow screens (iPhone SE at 375px, older Android at 360px). Also stack pagination cards vertically on mobile.\n\nAdd a new media query AFTER the existing mobile block (after line 1034):\n\n```css\n/* Small mobile: extra narrow screens */\n@media (max-width: 480px) {\n .sidebar {\n width: 85vw;\n min-width: 85vw;\n }\n\n .layout-header-inner {\n padding: 0 var(--space-3);\n }\n\n .layout-content {\n padding: var(--space-4) var(--space-3);\n }\n}\n```\n\nAlso add pagination stacking inside the existing `@media (max-width: 768px)` block (before line 1034):\n\n```css\n/* Stack pagination on mobile */\n.pagination {\n flex-direction: column;\n}\n\n.pagination-link {\n width: 100%;\n}\n\n.pagination-link-next {\n text-align: left;\n}\n```\n\nContext:\n- The sidebar is fixed at 250px width (line 108). On a 375px screen, that leaves only 125px visible content — too cramped. Using 85vw gives ~319px sidebar with some visible background.\n- Header inner padding is `0 var(--space-8)` (32px, line 195). On tiny screens, reduce to 12px.\n- Pagination uses `display: flex` with `justify-content: space-between` (lines 527-534). On mobile, prev/next cards should stack vertically.\n\n## Test\n```bash\ncd documentation \u0026\u0026 node -e \"\nconst fs = require(\\\"fs\\\");\nconst css = fs.readFileSync(\\\"styles/globals.css\\\", \\\"utf8\\\");\nconst hasSmallMobile = css.includes(\\\"max-width: 480px\\\");\nconst has85vw = /\\\\.sidebar[^}]*width:\\\\s*85vw/.test(css);\nconst mobileBlock = css.split(\\\"@media (max-width: 768px)\\\").slice(1).join(\\\"\\\");\nconst hasPaginationStack = /\\\\.pagination[^}]*flex-direction:\\\\s*column/.test(mobileBlock);\nif (!hasSmallMobile) { console.error(\\\"FAIL: no 480px breakpoint\\\"); process.exit(1); }\nif (!has85vw) { console.error(\\\"FAIL: no 85vw sidebar\\\"); process.exit(1); }\nif (!hasPaginationStack) { console.error(\\\"FAIL: no pagination stacking\\\"); process.exit(1); }\nconsole.log(\\\"PASS\\\");\n\"\n```\n\n## Dont\n- Do not modify the existing breakpoints\n- Do not change desktop styles\n- Do not modify any JS files\n- Do not change the sidebar width CSS variable — override the width directly on .sidebar","status":"closed","priority":2,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-16T23:34:17.12088+13:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-16T23:39:44.212351+13:00","closed_at":"2026-02-16T23:39:44.212351+13:00","close_reason":"b2ca35e Add small mobile breakpoint (\u003c480px) and pagination stacking","labels":["scope:small"],"dependencies":[{"issue_id":"docs-z6h.5","depends_on_id":"docs-z6h","type":"parent-child","created_at":"2026-02-16T23:34:17.122179+13:00","created_by":"sharfy-test.climateai.org"}]} {"id":"hypercerts-atproto-documentation-kqm","title":"Epic: Replace Hyperscan links with GitHub lexicon repo links across all lexicon pages","description":"All 15 individual lexicon pages currently link to the Hyperscan lexicon browser for their schema. These should instead link directly to the JSON file in the GitHub lexicon repo (https://github.com/hypercerts-org/hypercerts-lexicon). The two index pages and introduction page have no Hyperscan links and need no changes.","status":"open","priority":1,"issue_type":"epic","owner":"sharfy-test.climateai.org","created_at":"2026-03-05T19:44:35.507703+08:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-03-05T19:44:35.507703+08:00","labels":["scope:small"]} {"id":"hypercerts-atproto-documentation-kqm.1","title":"Replace Hyperscan browser links with GitHub lexicon repo links in all 15 lexicon pages","description":"## Files\n- pages/lexicons/hypercerts-lexicons/activity-claim.md (modify)\n- pages/lexicons/hypercerts-lexicons/contribution.md (modify)\n- pages/lexicons/hypercerts-lexicons/attachment.md (modify)\n- pages/lexicons/hypercerts-lexicons/measurement.md (modify)\n- pages/lexicons/hypercerts-lexicons/evaluation.md (modify)\n- pages/lexicons/hypercerts-lexicons/collection.md (modify)\n- pages/lexicons/hypercerts-lexicons/rights.md (modify)\n- pages/lexicons/hypercerts-lexicons/funding-receipt.md (modify)\n- pages/lexicons/hypercerts-lexicons/acknowledgement.md (modify)\n- pages/lexicons/certified-lexicons/profile.md (modify)\n- pages/lexicons/certified-lexicons/shared-defs.md (modify)\n- pages/lexicons/certified-lexicons/location.md (modify)\n- pages/lexicons/certified-lexicons/badge-definition.md (modify)\n- pages/lexicons/certified-lexicons/badge-award.md (modify)\n- pages/lexicons/certified-lexicons/badge-response.md (modify)\n\n## What to do\nIn each file, replace the last line which currently reads:\n`For the full schema, see the [Hyperscan lexicon browser](https://www.hyperscan.dev/agents/lexicon/\u003cNSID\u003e).`\n\nWith:\n`For the full schema, see [`\u003cNSID\u003e`](\u003cgithub-url\u003e) in the lexicon repo.`\n\nWhere \u003cgithub-url\u003e is `https://github.com/hypercerts-org/hypercerts-lexicon/blob/main/lexicons/\u003cpath\u003e.json`\n\nThe exact NSID → GitHub path mapping:\n- org.hypercerts.claim.activity → lexicons/org/hypercerts/claim/activity.json\n- org.hypercerts.claim.contributorInformation → lexicons/org/hypercerts/claim/contributorInformation.json\n- org.hypercerts.claim.contributionDetails → lexicons/org/hypercerts/claim/contribution.json\n- org.hypercerts.context.attachment → lexicons/org/hypercerts/context/attachment.json\n- org.hypercerts.context.measurement → lexicons/org/hypercerts/context/measurement.json\n- org.hypercerts.context.evaluation → lexicons/org/hypercerts/context/evaluation.json\n- org.hypercerts.claim.collection → lexicons/org/hypercerts/collection.json\n- org.hypercerts.claim.rights → lexicons/org/hypercerts/claim/rights.json\n- org.hypercerts.funding.receipt → lexicons/org/hypercerts/funding/receipt.json\n- org.hypercerts.context.acknowledgement → lexicons/org/hypercerts/context/acknowledgement.json\n- app.certified.actor.profile → lexicons/app/certified/actor/profile.json\n- app.certified.defs → lexicons/app/certified/defs.json\n- app.certified.location → lexicons/app/certified/location.json\n- app.certified.badge.definition → lexicons/app/certified/badge/definition.json\n- app.certified.badge.award → lexicons/app/certified/badge/award.json\n- app.certified.badge.response → lexicons/app/certified/badge/response.json\n\nNote: contribution.md has TWO links (one for contributorInformation, one for contributionDetails). Both must be updated.\n\n## Dont\n- Do not change any other content on the pages\n- Do not change the index pages or introduction page\n- Do not reword the surrounding sentence — just swap the link target and anchor text","acceptance_criteria":"All 15 lexicon pages link to the correct GitHub JSON file in https://github.com/hypercerts-org/hypercerts-lexicon/blob/main/lexicons/. No Hyperscan links remain in pages/lexicons/. npm run build succeeds.","status":"closed","priority":1,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","estimated_minutes":30,"created_at":"2026-03-05T19:44:51.254641+08:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-03-05T19:48:03.329015+08:00","closed_at":"2026-03-05T19:48:03.329015+08:00","close_reason":"1514237 Replace Hyperscan links with GitHub lexicon repo links in all 15 lexicon pages","labels":["scope:small"],"dependencies":[{"issue_id":"hypercerts-atproto-documentation-kqm.1","depends_on_id":"hypercerts-atproto-documentation-kqm","type":"parent-child","created_at":"2026-03-05T19:44:51.263686+08:00","created_by":"sharfy-test.climateai.org"}]} +{"id":"hypercerts-atproto-documentation-pzc","title":"Epic: Fix TOC sidebar heading hierarchy — add visual distinction between h2 and h3","description":"## Problem\nThe right-side table of contents (TOC) sidebar shows all headings at the same visual level — there is no indentation or meaningful visual distinction between h2 and h3 entries. The `toc-link-h3` CSS class only reduces font-size by 1px (13px vs 14px) with zero indentation, making the hierarchy invisible.\n\n## Goals\n1. Add clear visual indentation for h3 entries in the TOC so users can see section hierarchy at a glance\n2. Ensure the fix works across all pages that have mixed h2/h3 headings (scaffold, testing-and-deployment, architecture pages, etc.)\n3. Keep the design clean and consistent with the existing site aesthetic\n\n## Key files\n- `styles/globals.css` (lines 938-940: `.toc-link-h3` rule)\n- `components/TableOfContents.js` (renders TOC with level-aware classes)\n\n## Scope\nCSS-only fix for the visual distinction. No changes to the TOC component logic needed — it already correctly tracks heading levels and applies the right classes.","status":"open","priority":1,"issue_type":"epic","owner":"sharfy-test.climateai.org","created_at":"2026-03-06T14:11:10.366951+08:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-03-06T14:11:10.366951+08:00","labels":["scope:small"]} +{"id":"hypercerts-atproto-documentation-pzc.1","title":"Add CSS indentation and visual distinction for h3 entries in TOC sidebar","description":"## Files\n- styles/globals.css (modify — lines 938-940)\n\n## What to do\nUpdate the `.toc-link-h3` CSS rule and add a new `.toc-item` variant to create clear visual hierarchy for h3 entries in the right-side TOC sidebar.\n\n### Current CSS (line 938-940):\n```css\n.toc-link-h3 {\n font-size: 13px;\n}\n```\n\n### Required changes:\n1. Add `padding-left: 12px` to `.toc-link-h3` to indent h3 entries under their parent h2\n2. Reduce the font-size slightly more to `12.5px` or `0.8125rem` (13px is too close to 14px to notice)\n3. Optionally reduce the opacity or use `var(--color-text-tertiary)` for non-active h3 links to further differentiate\n\n### Context:\n- The `TableOfContents.js` component already applies `toc-link-h3` class to h3 entries (line 96)\n- The `.toc-item` div wraps each link and provides the left border + padding\n- Pages with h3 headings include: using-the-scaffold-app.md (Step 1-7), testing-and-deployment.md, building-on-hypercerts.md, architecture pages, tools/scaffold.md, cel-work-scopes.md\n- The border-left on `.toc-item` should still align for h3 items — the indentation should be on the text/link, not the border\n\n## Don't\n- Modify TableOfContents.js — the component logic is correct\n- Change the h2 styling — only add distinction for h3\n- Add JavaScript-based indentation — this is CSS-only\n- Break the active state highlighting (`.toc-link-active` and `.toc-item-active` must still work)","acceptance_criteria":"1. On pages with mixed h2/h3 headings (e.g. /getting-started/using-the-scaffold-app), h3 entries in the right TOC sidebar are visually indented relative to h2 entries\n2. The indentation is at least 10px of additional left padding on the link text\n3. h2 entries remain at their current position (no regression)\n4. Active state highlighting still works correctly for both h2 and h3 entries\n5. The site builds without errors: pnpm build succeeds\n6. Dark mode and light mode both render the TOC correctly","status":"open","priority":1,"issue_type":"task","owner":"sharfy-test.climateai.org","estimated_minutes":20,"created_at":"2026-03-06T14:11:28.829438+08:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-03-06T14:11:28.829438+08:00","labels":["scope:trivial"],"dependencies":[{"issue_id":"hypercerts-atproto-documentation-pzc.1","depends_on_id":"hypercerts-atproto-documentation-pzc","type":"parent-child","created_at":"2026-03-06T14:11:28.83069+08:00","created_by":"sharfy-test.climateai.org"}]} {"id":"hypercerts-atproto-documentation-qu1","title":"Epic: Draft pages system — unlisted pages with /drafts index","description":"Add a draft page system to the documentation site. Pages with `draft: true` in frontmatter should be excluded from the sidebar navigation and prev/next pagination, but remain accessible by direct URL. A /drafts index page lists all draft pages so devs can find them. This lets the team write documentation ahead of time without exposing it to public visitors. Success: draft pages are invisible in sidebar/pagination, accessible by URL, and discoverable at /drafts.","status":"open","priority":2,"issue_type":"epic","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","created_at":"2026-02-23T16:52:19.61403+08:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-23T17:11:42.24997+08:00","labels":["needs-integration-review","scope:medium"]} {"id":"hypercerts-atproto-documentation-qu1.1","title":"Add getDraftPages() utility to lib/navigation.js","description":"## Files\n- documentation/lib/navigation.js (modify)\n\n## What to do\nAdd a new exported function `getDraftPages()` that:\n1. Uses Node.js `fs` and `path` to recursively scan `pages/` directory for `.md` and `.mdoc` files\n2. Reads the frontmatter of each file (parse YAML between `---` fences)\n3. Returns an array of `{ title, path, description }` for files where `draft: true` is in frontmatter\n4. The `path` should be the URL path (e.g., `pages/drafts/my-page.md` → `/drafts/my-page`)\n\nIMPORTANT: This function will only be called at build time (in getStaticProps), so using `fs` is fine. Do NOT import `fs` at the top level — use dynamic require inside the function body so it does not break client-side bundles.\n\nExample return value:\n```js\n[\n { title: \"Token Bridge Design\", path: \"/drafts/token-bridge\", description: \"Early design notes...\" },\n { title: \"Governance Model\", path: \"/architecture/governance\", description: undefined }\n]\n```\n\n## Don't\n- Import fs/path at the module top level (breaks client bundle)\n- Modify the existing `navigation`, `flattenNavigation`, or `getPrevNext` exports\n- Add any npm dependencies","acceptance_criteria":"1. `getDraftPages()` is exported from `lib/navigation.js`\n2. It returns an array of objects with `title`, `path`, and `description` keys\n3. It only includes pages where frontmatter has `draft: true`\n4. It does NOT include pages where `draft` is missing or `false`\n5. The path values are correct URL paths (no `.md` extension, no `pages/` prefix, `index.md` maps to parent dir)\n6. No top-level `fs` or `path` import exists in the file\n7. Existing exports (`navigation`, `flattenNavigation`, `getPrevNext`) still work unchanged","status":"closed","priority":2,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","estimated_minutes":30,"created_at":"2026-02-23T16:52:36.411067+08:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-23T17:04:55.059341+08:00","closed_at":"2026-02-23T17:04:55.059341+08:00","close_reason":"e03fb4a Add getDraftPages() utility function","labels":["scope:small"],"dependencies":[{"issue_id":"hypercerts-atproto-documentation-qu1.1","depends_on_id":"hypercerts-atproto-documentation-qu1","type":"parent-child","created_at":"2026-02-23T16:52:36.411868+08:00","created_by":"sharfy-test.climateai.org"}]} {"id":"hypercerts-atproto-documentation-qu1.2","title":"Create /drafts index page","description":"## Files\n- documentation/pages/drafts/index.js (create)\n\n## What to do\nCreate a Next.js page at `/drafts` that lists all draft pages. This is a `.js` page (not `.md`) because it needs `getStaticProps` to call `getDraftPages()`.\n\nThe page should:\n1. Import and call `getDraftPages()` from `../../lib/navigation` inside `getStaticProps`\n2. Return the list as a prop\n3. Render a simple page with:\n - Title: \"Draft Pages\" (set via frontmatter-like props so Layout picks it up)\n - A subtitle/description: \"These pages are work-in-progress and not yet listed in the sidebar.\"\n - A list of draft pages, each showing:\n - The page title as a clickable link (use Next.js `Link`)\n - The description underneath (if available), in secondary text color\n - The URL path in small monospace text (so devs can reference it)\n - If no draft pages exist, show a message: \"No draft pages yet.\"\n4. Pass `markdoc: { frontmatter: { title: \"Draft Pages\" } }` in the props so the Layout component picks up the page title correctly\n\nStyle the page using the existing CSS variables and class conventions from globals.css. Use inline styles or a `\u003cstyle jsx\u003e` block — do NOT modify globals.css for this page.\n\n## Don't\n- Use .md/.mdoc format (needs getStaticProps for dynamic content)\n- Add this page to the `navigation` array in lib/navigation.js (it should be unlisted)\n- Modify globals.css\n- Add any npm dependencies","acceptance_criteria":"1. Visiting /drafts in the browser renders a page titled \"Draft Pages\"\n2. The page lists all .md files that have `draft: true` in frontmatter\n3. Each listed page shows its title as a clickable link, optional description, and URL path\n4. Clicking a link navigates to the draft page\n5. The page title appears in the browser tab as \"Draft Pages - Hypercerts Protocol\"\n6. The /drafts page does NOT appear in the sidebar navigation\n7. When no draft pages exist, the message \"No draft pages yet.\" is shown\n8. The page uses the site Layout (header, sidebar visible but /drafts not highlighted)","status":"closed","priority":2,"issue_type":"task","assignee":"sharfy-test.climateai.org","owner":"sharfy-test.climateai.org","estimated_minutes":45,"created_at":"2026-02-23T16:52:53.435836+08:00","created_by":"sharfy-test.climateai.org","updated_at":"2026-02-23T17:09:18.570394+08:00","closed_at":"2026-02-23T17:09:18.570394+08:00","close_reason":"8951cf5 Create /drafts index page","labels":["scope:small"],"dependencies":[{"issue_id":"hypercerts-atproto-documentation-qu1.2","depends_on_id":"hypercerts-atproto-documentation-qu1","type":"parent-child","created_at":"2026-02-23T16:52:53.436646+08:00","created_by":"sharfy-test.climateai.org"},{"issue_id":"hypercerts-atproto-documentation-qu1.2","depends_on_id":"hypercerts-atproto-documentation-qu1.1","type":"blocks","created_at":"2026-02-23T16:52:53.437875+08:00","created_by":"sharfy-test.climateai.org"}]}