Quickstart: Clean Clone To Local Attestation
Goal: from git clone to a cryptographically verified, company-attested work receipt on your machine in under 15 minutes. No external database, no email provider, no cloud account.
Prerequisites: Node 22+, pnpm 9 (corepack enable), and a POSIX shell for the curl commands (Git Bash works on Windows).
1. Install and boot (about 3 minutes)
pnpm install
pnpm dev:api
pnpm dev:api boots the API at http://localhost:3000 on an embedded PGlite database (apps/api/.data/dev-db): it runs migrations, seeds demo data, uses the console mail provider (emails print to this terminal), a fixed development KEK, and EXPOSE_LOGIN_TOKENS=true (login tokens are returned in API responses — dev only; production refuses this).
In a second terminal, start the web portal:
pnpm dev
Vite serves http://localhost:5173 and proxies /api to the API, so cookies work same-origin. The portal is optional for this walkthrough — everything below also works with curl alone.
2. Sign in (seeded account or fresh)
Option A — seeded operator op2@example.com:
curl -s -X POST http://localhost:3000/api/v1/auth/magic-link \
-H "Content-Type: application/json" \
-d '{"email":"op2@example.com"}'
The response contains login_token (dev mode). The same magic link is also printed by the console mailer in the pnpm dev:api terminal, between --- mail (magic_link) ... --- markers.
Option B — onboard a fresh operator:
curl -s -X POST http://localhost:3000/api/v1/onboarding/operators \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","display_name":"You","operator_name":"Your Studio"}'
Exchange the token for a cookie session (save cookies to a jar; the CSRF token is the agncred_csrf cookie value):
TOKEN=paste_login_token_here
curl -s -c /tmp/op.cookies -X POST http://localhost:3000/api/v1/auth/session \
-H "Content-Type: application/json" -d "{\"token\":\"$TOKEN\"}"
CSRF=$(awk '$6=="agncred_csrf" {print $7}' /tmp/op.cookies)
In the browser instead: open http://localhost:5173/portal/callback?token=
3. Register an agent and issue a credential
curl -s -b /tmp/op.cookies -H "x-csrf-token: $CSRF" \
-H "Content-Type: application/json" \
-X POST http://localhost:3000/api/v1/agents \
-d '{"name":"Atlas","summary":"Invoice processing agent"}'
# note the returned agent.id, e.g. agt_xxxxxxxxxxxx
AGENT_ID=agt_xxxxxxxxxxxx
curl -s -b /tmp/op.cookies -H "x-csrf-token: $CSRF" \
-H "Content-Type: application/json" \
-X POST "http://localhost:3000/api/v1/operator/agents/$AGENT_ID/credentials" \
-d '{"scopes":["receipts:create","receipts:read","profile:read"],"expires_in_days":90}'
The response contains secret (agk_...) — shown exactly once, never stored. Keep it:
AGNCRED_API_KEY=agk_paste_secret_here
4. Submit a work receipt (curl or SDK)
Via curl — note the Idempotency-Key header; retrying with the same key replays the original receipt instead of creating a duplicate:
curl -s -X POST http://localhost:3000/api/v1/agent/receipts \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AGNCRED_API_KEY" \
-H "Idempotency-Key: quickstart-batch-001" \
-d '{
"source_type": "api",
"task": {"type": "invoice_processing", "category": "Finance", "summary": "Processed July invoice batch."},
"started_at": "2026-07-12T09:00:00.000Z",
"completed_at": "2026-07-12T09:05:00.000Z",
"outcome_claims": {"metrics": {"invoices_processed": 42}, "estimated_hours_saved": 2},
"evidence": [{
"type": "external_private_reference",
"confidentiality": "private_reference",
"description": "Workflow execution log",
"private_reference": "https://erp.internal.example.com/executions/4211"
}]
}'
# -> 201 { "receipt_id": "wr_...", "status": "submitted", "payload_hash": "sha256:...", "verification_url": ... }
RECEIPT_ID=wr_xxxxxxxxxxxx
Or via the SDK (packages/sdk, runnable example at packages/sdk/examples/submit-receipt.ts):
AGNCRED_API_URL=http://localhost:3000 AGNCRED_API_KEY=$AGNCRED_API_KEY \
npx tsx packages/sdk/examples/submit-receipt.ts
The receipt payload never carries prompts, source code, or customer content — summaries and hashed evidence descriptors only. The private reference is stored separately and erasably; only its hash enters the immutable payload.
5. Invite a reviewer at an unregistered company
curl -s -b /tmp/op.cookies -H "x-csrf-token: $CSRF" \
-H "Content-Type: application/json" \
-X POST "http://localhost:3000/api/v1/receipts/$RECEIPT_ID/request-attestation" \
-d '{"reviewer_email":"reviewer@client.example","company_name":"Client GmbH","message":"Please confirm the July batch."}'
Watch the pnpm dev:api terminal: the console mailer prints the invitation email, including the single-use link (valid 7 days):
--- mail (company_invitation) to reviewer@client.example ---
...
http://localhost:5173/portal/invitations/<invitation-token>
--- end mail ---
6. Claim the invitation and accept the receipt
In the browser: open the printed invitation link, create the company, and the invited receipt appears in the review queue immediately. Or with curl:
INV_TOKEN=paste_invitation_token_here
curl -s -X POST "http://localhost:3000/api/v1/invitations/$INV_TOKEN/claim" \
-H "Content-Type: application/json" \
-d '{"display_name":"Riley Reviewer","company_name":"Client GmbH"}'
# -> 201 { "status": "claimed", "company_id": "org_...", "login_token": "..." (dev) }
Sign the reviewer in with the returned login_token (same session exchange as step 2, using a second cookie jar /tmp/rev.cookies), then accept:
REV_CSRF=$(awk '$6=="agncred_csrf" {print $7}' /tmp/rev.cookies)
curl -s -b /tmp/rev.cookies -H "x-csrf-token: $REV_CSRF" \
-H "Content-Type: application/json" \
-X POST "http://localhost:3000/api/v1/receipts/$RECEIPT_ID/attest" \
-d '{
"action": "accept",
"independence": "independent",
"reviewer_quality_score": 90,
"confirmed_hours_saved": 2,
"confirmed_outcomes": ["July invoice batch processed and reconciled"],
"public_summary": "Processed and reconciled the July invoice batch."
}'
Acceptance signs the immutable receipt version with the company's Ed25519 key (created automatically on first use, encrypted at rest).
7. Verify
curl -s "http://localhost:3000/api/v1/receipts/$RECEIPT_ID/verify"
Expect signature.valid: true (scheme agncred-attestation.v1, with the signing key_id) and event_chain.valid: true. The full offline bundle is at /api/v1/receipts/$RECEIPT_ID/verification-bundle — see VERIFICATION_GUIDE.md to verify it without trusting the server.
Note on score: the new company is unverified, so this receipt correctly contributes zero points until the company completes domain verification (portal: company workspace, or POST /api/v1/company/domain-verification). That is the "no proof, no reputation" rule working, not a bug.
Where things print
- Magic links and all emails: the
pnpm dev:apiterminal (console mailer). - Login tokens: also in API responses, dev only (
EXPOSE_LOGIN_TOKENS=true). - API docs: set
ENABLE_API_DOCS=truebeforepnpm dev:apifor interactive docs at http://localhost:3000/api/v1/docs; the OpenAPI document is always at/api/v1/openapi.json.
Next: API_GUIDE.md for the full ingestion API, MCP_GUIDE.md to submit from Claude Code, N8N_GUIDE.md for the n8n workflow.