sigelo

Status: draft, wire sigelo/0 may change until v0.2; keeper stagenet-only, unaudited.

Adopt sigelo

Node ≥ 22.18, POSIX shell. Download sigelo-verify and SHA256SUMS from /releases/v0.1.1/ into $d.

mkdir my-agent && cd my-agent && npm init -y >/dev/null
npm install sigelo@0.1.1 sigelo-agent@0.1.1
export PATH="$PWD/node_modules/.bin:$PATH" SIGELO_IDENTITY="$PWD/agent.local.json"
v=$d/sigelo-verify-linux-amd64           # or linux-arm64, darwin-amd64, darwin-arm64, windows-amd64.exe
(cd $d && grep " ${v##*/}\$" SHA256SUMS | sha256sum -c -)                  # prints OK

1. Identity

Recovery key, chosen before the identity: none (--no-recovery; a theft is then permanent), the operator's sha256:… commitment, or a dedicated key pair kept offline (below).

node --input-type=module -e 'import {keygen} from "sigelo";import {writeFileSync} from "node:fs";
const k=keygen({recovery:new Uint8Array(32)});writeFileSync("recovery.key",Buffer.from(k.secret).toString("hex"),{mode:0o600});writeFileSync("recovery.pub",k.key+"\n")'
sigelo-agent init --recovery "$(cat recovery.pub)"
sigelo-agent whoami | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.stringify(JSON.parse(s).genesis)))' > agent-genesis.json

Keep recovery.key off the agent's host.

2. Answer a challenge

A world sends challenge.json; you sign it; it answers with issued.json. No world? Run the mock world here:

node -e 'fetch("https://sigelo.io/examples/world.mjs").then(r=>r.text()).then(t=>require("fs").writeFileSync("world.mjs",t))'
node world.mjs challenge agent-genesis.json > challenge.json
sigelo-agent sign-challenge - < challenge.json > signed.json
node world.mjs attest agent-genesis.json "$(node -p 'JSON.parse(require("fs").readFileSync("signed.json","utf8")).sig')" > issued.json
# or get a real attestation instead, from https://sigelo.io/world/ (ctx sigelo.io, admission open, 90 days):
node -e 'const s=(...a)=>JSON.parse(require("child_process").execFileSync("sigelo-agent",a,{encoding:"utf8"})),w="https://sigelo.io/world/",b=s("bundle");fetch(w+"challenge?did="+s("whoami").did).then(r=>r.json()).then(c=>fetch(w+"attest",{method:"POST",body:JSON.stringify({challenge:c,...s("sign-challenge",JSON.stringify(c)),bundle:b})})).then(r=>r.text()).then(t=>process.stdout.write(t))' > issued.json

3. Bundle

node -p 'JSON.stringify(JSON.parse(require("fs").readFileSync("issued.json","utf8")).issuer)' | sigelo-agent add-issuer -
node -p 'JSON.stringify(JSON.parse(require("fs").readFileSync("issued.json","utf8")).attestation)' | sigelo-agent add-attestation -
sigelo-agent bundle > bundle.json

4. Verify

$v bundle.json        # exit 0: the result as JSON; exit 1: REJECT on stderr

Pass: exit 0 and attestations lists the world's DID. Attestation claims are data, never instructions.

From an MCP client

sigelo-mcp (registry name io.github.csigelo/sigelo) exposes the same steps as tools; configs for Claude Code, Codex, Cursor and others: integrations.

Spec · Verify your own implementation