@finchip.ai/foga 0.0.0-stage → 0.6.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +21 -0
  3. package/README.md +216 -2
  4. package/artifacts/bundle.json +74250 -0
  5. package/artifacts/bundle.sha256 +1 -0
  6. package/bin/foga.js +14 -0
  7. package/build/known-interface-ids.json +18 -0
  8. package/build/profiles.json +120 -0
  9. package/dist/build/bundle.js +417 -0
  10. package/dist/build/vendor.js +74 -0
  11. package/dist/bundle/load.js +24 -0
  12. package/dist/bundle/types.js +1 -0
  13. package/dist/cli-cell.js +395 -0
  14. package/dist/cli.js +505 -0
  15. package/dist/core/acdf.js +162 -0
  16. package/dist/core/adrf.js +273 -0
  17. package/dist/core/aid.js +83 -0
  18. package/dist/core/ard.js +146 -0
  19. package/dist/core/asf.js +157 -0
  20. package/dist/core/canonical.js +79 -0
  21. package/dist/core/erc8004.js +52 -0
  22. package/dist/core/kya.js +225 -0
  23. package/dist/core/measure.js +96 -0
  24. package/dist/core/pack/cbor.js +130 -0
  25. package/dist/core/pack/skillpack.js +142 -0
  26. package/dist/core/skills.js +40 -0
  27. package/dist/core/swarm.js +206 -0
  28. package/dist/core/tenders.js +121 -0
  29. package/dist/core/units.js +122 -0
  30. package/dist/core/world.js +104 -0
  31. package/dist/demo/demander.js +76 -0
  32. package/dist/demo/evidence.js +1 -0
  33. package/dist/demo/loop-d.js +449 -0
  34. package/dist/doctor/checks.js +51 -0
  35. package/dist/doctor/doctor.js +385 -0
  36. package/dist/doctor/loop-d.js +103 -0
  37. package/dist/doctor/probe.js +97 -0
  38. package/dist/doctor/semantic.js +83 -0
  39. package/dist/genesis/extract.js +64 -0
  40. package/dist/genesis/funding.js +126 -0
  41. package/dist/genesis/operator-scope.js +90 -0
  42. package/dist/genesis/preflight.js +54 -0
  43. package/dist/genesis/probe.js +164 -0
  44. package/dist/genesis/roles.js +96 -0
  45. package/dist/genesis/run.js +71 -0
  46. package/dist/genesis/scenario.js +765 -0
  47. package/dist/genesis/skill-runner.js +103 -0
  48. package/dist/genesis/skill-worker.js +41 -0
  49. package/dist/genesis/t1-zk.js +62 -0
  50. package/dist/genesis/t3-zk.js +105 -0
  51. package/dist/genesis/t4.js +259 -0
  52. package/dist/genesis/t5.js +168 -0
  53. package/dist/genesis/t6.js +222 -0
  54. package/dist/genesis/t7.js +198 -0
  55. package/dist/genesis/t8.js +189 -0
  56. package/dist/genesis/t9.js +188 -0
  57. package/dist/genesis/zk.js +128 -0
  58. package/dist/http/server.js +276 -0
  59. package/dist/kernel/cell.js +104 -0
  60. package/dist/kernel/errors.js +78 -0
  61. package/dist/kernel/kernel.js +251 -0
  62. package/dist/kernel/provider.js +125 -0
  63. package/dist/kernel/store.js +470 -0
  64. package/dist/kernel/tx.js +385 -0
  65. package/dist/mcp/server.js +170 -0
  66. package/dist/node/config.js +195 -0
  67. package/dist/node/init.js +200 -0
  68. package/dist/node/keys.js +95 -0
  69. package/dist/node/migrate.js +173 -0
  70. package/dist/node/model/anthropic.js +97 -0
  71. package/dist/node/model/stub.js +129 -0
  72. package/dist/node/model/types.js +9 -0
  73. package/dist/node/node.js +198 -0
  74. package/dist/node/policy.js +95 -0
  75. package/dist/node/runner.js +256 -0
  76. package/dist/node/watchers.js +88 -0
  77. package/dist/tools/admin.js +184 -0
  78. package/dist/tools/catalog.js +261 -0
  79. package/dist/tools/common.js +143 -0
  80. package/dist/tools/identity.js +107 -0
  81. package/dist/tools/index.js +14 -0
  82. package/dist/tools/read.js +471 -0
  83. package/dist/tools/tenders.js +400 -0
  84. package/dist/tools/types.js +4 -0
  85. package/dist/util/bytecode.js +123 -0
  86. package/dist/util/fs.js +58 -0
  87. package/dist/util/hash.js +4 -0
  88. package/dist/util/log.js +11 -0
  89. package/dist/util/version.js +12 -0
  90. package/dist/world/deploy.js +277 -0
  91. package/dist/world/plan.js +93 -0
  92. package/dist/world/types.js +1 -0
  93. package/docs/build.md +45 -0
  94. package/docs/cell-account.md +58 -0
  95. package/docs/compatibility-matrix.md +38 -0
  96. package/docs/design-memo.md +113 -0
  97. package/docs/doctor.md +53 -0
  98. package/docs/examples/README.md +11 -0
  99. package/docs/examples/claude-code-mcp.json +13 -0
  100. package/docs/examples/claude_desktop_config.json +12 -0
  101. package/docs/examples/cursor-mcp.json +11 -0
  102. package/docs/genesis.md +312 -0
  103. package/docs/kernel.md +101 -0
  104. package/docs/loop-d.md +90 -0
  105. package/docs/mcp.md +105 -0
  106. package/docs/node.md +66 -0
  107. package/docs/version-lock.md +67 -0
  108. package/docs/world.md +50 -0
  109. package/docs/zk.md +48 -0
  110. package/package.json +82 -4
  111. package/prover/README.md +26 -0
  112. package/prover/build-predicate.mjs +77 -0
  113. package/prover/package-lock.json +1837 -0
  114. package/prover/package.json +15 -0
  115. package/prover/run.cjs +199 -0
  116. package/scenarios/fixtures/sample-filing.txt +16 -0
  117. package/scenarios/skills/finch-extract-verify/LICENSE +2 -0
  118. package/scenarios/skills/finch-extract-verify/SKILL.md +34 -0
  119. package/scenarios/skills/finch-extract-verify/fields.json +56 -0
  120. package/scenarios/skills/finch-extract-verify/manifest.json +16 -0
  121. package/scenarios/skills/foga-probe/LICENSE +2 -0
  122. package/scenarios/skills/foga-probe/SKILL.md +35 -0
  123. package/scenarios/skills/foga-probe/manifest.json +16 -0
  124. package/scenarios/skills/foga-probe/probe.schema.json +40 -0
  125. package/server.json +79 -0
  126. package/vendor/LOCK.json +107 -0
  127. package/vendor/README.md +13 -0
  128. package/worlds/local.json +34 -0
  129. package/worlds/sepolia.json +314 -0
  130. package/zk/build/verification_key.json +174 -0
  131. package/zk/circuits/kya_predicate_count_v1.circom +231 -0
@@ -0,0 +1,113 @@
1
+ # FOGA design memo (v0.2, condensed)
2
+
3
+ This is the English working version of the design. Phase 1 (the world layer), Phase 2a (cells, kernel, genesis T0–T5), Phase 2b (the predicate ZK path, T6–T9, measurement receipts, doctor layer 5; docs/genesis.md) and Phase 2c (the public-chain path and the Sepolia run) implement its first slices; Phase 3 (section 9) turns the kernel into a node other agents can call. It records decisions, not aspirations: where something is still to be built, it says so.
4
+
5
+ ## 1. Definition and scope
6
+
7
+ FOGA is an independently runnable autonomous agent node that, within explicit identity, authorization, budget and rule boundaries, discovers resources, verifies counterparties, uses skills, fulfills tasks, takes part in organizations and collective decisions, records its economic activity, and handles safety interventions and disputes — in a way other nodes can verify independently. "Autonomous" means acting continuously within pre-authorized bounds without step-by-step human instructions; humans keep the pre-agreed powers to pause, revoke authorization and dispose.
8
+
9
+ Three deliverables share one kernel: the Finch OG Agent (the first running instance), the FOGA node software (anyone's own identity, model and wallet), and the public access layer (MCP, A2A, HTTP/CLI).
10
+
11
+ Compatibility with each of the ten ERCs is declared in three parts — the specification version followed, the role FOGA takes, and the run evidence — and proved per ERC (docs/compatibility-matrix.md). An interface that merely exists is never counted.
12
+
13
+ The "cellular automaton" idea is the architectural inspiration: each cell is an address whose state is its on-chain facts under the ten ERCs, whose neighborhood is the set of cells it is linked to through tenders, swarms, decisions and disputes, and whose rule is a local policy that reads only on-chain state and ERC interfaces. The engineering description is an event-driven network of autonomous nodes with local state and explicit permissions; block height is a demonstration clock, the genesis phases T0–T9 are logical phases, and real runs wait for proofs, messages, confirmations, dispute windows and reorgs.
14
+
15
+ ## 2. Architecture
16
+
17
+ | Layer | Content |
18
+ |---|---|
19
+ | L0 chain | Anvil, Anvil fork of Sepolia, Sepolia (public evidence), Base (hosted services, later); one address book per world |
20
+ | L1 protocol | the ten reference implementations plus ERC-8004, locked by commit and compiled into one bundle without changing compile conditions |
21
+ | L2 SDK (`foga-core`) | one module per ERC: views, transaction builders, event decoders, and the upstream off-chain pieces (DAG-CBOR packages, JCS canonicalization, the EIP-712 flows, the JSON schemas); ethers v6, reusing the upstream resolvers, gateway and vector tools |
22
+ | L3 cell kernel (`foga-kernel`) | a deterministic state machine with persistence, transaction management and evidence; no LLM inside |
23
+ | L4 cognition (optional) | a model provider adapter for judgment steps only; off in conformance runs |
24
+ | L5 interfaces | MCP (base and extended tiers), A2A, HTTP/CLI, sharing L3's business model and authorization rules |
25
+
26
+ **CellState** has three parts: an on-chain fact snapshot (chain, block height and hash, confirmations, protocol object references), verified off-chain inputs (packages, deliverables, A2A messages, evidence, signatures, content hashes; private witnesses never enter public documents or evidence logs), and local persistent runtime state (pending operations, commitments, budget reservations, nonces, pending transactions, retry and dedup records, recovery points).
27
+
28
+ **Determinism** means: given the same recorded inputs, rule version and parameters, the same execution decision can be replayed. Model replaceability and non-deterministic external inputs do not conflict with this. Every judgment produces a traceable decision record with supporting evidence; signatures and hashes prove the record's integrity and attribution, not the judgment's correctness.
29
+
30
+ **Harness duties**: plan and execute (a model may propose; deterministic code checks permission, budget and preconditions), task persistence, evidence, transaction management, state coordination (ACDF Final, tender paid, swarm achieved and ADRF enacted are different facts — linked, never merged), observability.
31
+
32
+ **Persistence** defaults to SQLite (single file, WAL) behind a storage interface; PostgreSQL for the hosted indexer.
33
+
34
+ **One local config, several documents**: a node keeps `cell.config.json`; tools generate the schema-conformant AID document, the ERC-8004 registration file (services: MCP and A2A endpoints; `x402Support` only once real), the ARD agent descriptor and the AUF unit definition, each with its own commitment, version, hash and publication status, published by whichever principal has the right to.
35
+
36
+ **Skills**: `finch-extract-verify` (structured extraction, consistency check, evidence report; deterministic path without a model, model path for the real-agent acceptance) and `foga-probe` (the ten-ERC probe over a pinned block — the deterministic "known answer" of the machine-settled tender) are real ERC-8338 packages. Protocol operations (identity resolution, KYA checks, transaction building, safety checks) are deterministic code offered to models as restricted tools, not assets. MCP tools link to packages; a tool manifest hash is not a skill package.
37
+
38
+ ## 3. Accounts and permissions
39
+
40
+ | Principal | Form | Role |
41
+ |---|---|---|
42
+ | World operator (W) | EOA (account 0 of the genesis phrase: anvil's phrase locally, `foga keys new` elsewhere — `0x3D177ecaa56402335fC7C6449d35bC1Fa68Bc1b8` on Sepolia) | deploys or attaches the world and completes it from the bundle; treasury of the genesis; admin of FOGA's service escrow; publishes the ASF specification, the ACDF and ADRF policies and the KYA schemes; owner of the ARD registry and deployer of the ERC-8004 stand-in on local chains |
43
+ | Cell A, B, C | `FogaCellAccount` (contract account; an EOA in the lite profile) | the cell's body: AID anchor, ERC-8004 owner, holder of assets and funds, fulfiller on the task token, swarm member, ASF adopter, KYA subject, ARD and AUF controller |
44
+ | operator | hot signer held by the node process, and the only key that process holds | calls only through `FogaCellAccount.execute`, within the owner's allow-list of (target, selector) pairs — never an asset-moving selector —, a daily value cap and an expiry; signs for the account only when the owner enabled it (account revision 2, 0.6.0; docs/cell-account.md) |
45
+ | owner | cold key | rotates the operator, sets its allow-list, sets the guardian, recovers, moves assets |
46
+ | guardian | ASF intervener | suspends, resumes, terminates the cell's binding |
47
+ | judges J1–J3 | EOAs (allowlist in v1; KYA-gated profile later) | voters of the ACDF policy FOGA-Council; never parties to the case |
48
+ | evaluator E | EOA | asserts AUF measurement statements |
49
+ | demander, buyer | B and W (tenders); C (service purchase) | funds tenders; deposits into the service escrow |
50
+ | SwarmAccount | reference contract | the swarm's fulfiller and payee, distinct from its members |
51
+
52
+ Two profiles: the **guarded** profile (default, used by the OG cell) puts the body in a contract account so the safety gate holds even for RPC calls that bypass the kernel and so ERC-1271 makes `bindWithSig`, `joinBySig`, `assertStatementBySig` and signed ballots available; the **lite** profile is an EOA, with safety enforced only by acceptance consumers and the kernel's own restraint, which the doctor reports honestly. An operator that bypasses the account and submits to a permissionless token directly acts as itself, not as the cell; such a submission earns none of the cell's rights.
53
+
54
+ ## 4. Genesis scenario T0–T9 (implemented in Phases 2a and 2b; docs/genesis.md records the implemented form and its deviations: the binding is adopted before the ERC-8004 registration because the account executes nothing before a binding is presented; settlements pay the accounts directly, so `withdrawCredit` is only the fallback; the judged tender is minted before the swarm forms because the objective binds to it; the governance vote is 2 of 2 workers because the upstream decision adapter takes its roster from one role; the predicate proof is made at the end of T3 rather than at birth because the records it is about must exist first; the ADRF policy and the escrow binding are registered in T0 as planned; A's measured unit in T8 is the cell's unit because the chain pays accounts, not skills)
55
+
56
+ Loops: A = T1–T3 (independent order, execution, settlement), B = T4–T6 (organization, deliberation, dispute), C = T7 plus the failure and recovery cases, D = a real-agent run with unscripted task input.
57
+
58
+ - **T0 world**: deploy or attach the stack; register ARD kinds; register KYA schemes `S_att` (attested), `S_cred` (proved, credential pattern, existing Groth16 companion) and `S_pred` (proved, predicate pattern, new); publish the ASF specification FOGA-Cell-v1 (commitment-class actions require an ACTIVE AID; stop must be honored; the de-risk action set is explicit); register the ACDF policy FOGA-Council (J1–J3, K = 2, windows coordinated with the tender judgment window); register the ADRF policy whose judgment tier consumes FOGA-Council through the ACDF bridge; deploy FOGA's own `ACDFTaskTenderAdapter` bound to that policy.
59
+ - **T1 birth** (per cell): deploy `FogaCellAccount`; ERC-8004 `register(agentURI)`; AID `bind`, `heartbeat`, `setDocumentURI`; ASF `adopt` with the guardian as intervener; KYA attestation at level 2 from W for all three, a credential-pattern proof for A (and, from Phase 2b, a predicate-pattern proof); ARD agent record; AUF unit. Failure cases: bind before holding the identity, attest by a non-issuer, wrong scheme / subject / epoch, nullifier replay.
60
+ - **T2 capability**: A mints skill tokens for `finch-extract-verify` v1 and `foga-probe` v1, registers them in ARD and as AUF units. Failure cases: tampered package rejected before execution; `updateSkill` by a non-authority; a later v2 does not move v1 commitments.
61
+ - **T3 labor (machine acceptance)**: B computes the known answer (the `foga-probe` output at a pinned block), mints a tender with `HashlockVerifier` as the sole acceptance authority, funds 0.001 ETH, commits `sha256(answer)`; A discovers it, passes its own gates (AID ACTIVE, ASF check, budget, deadline, package verification), executes in an isolated worker, submits `resultHash = sha256(answer ‖ A)`, settles by revealing, withdraws credit. Failure cases: wrong answer; a copied proof settled by another address; a second completion beyond `maxCompletions`; a process killed between submit and settle resumes without resubmitting.
62
+ - **T4 organization**: B forms a swarm whose eligibility is `CompositeEligibility(requireAll, [ERC8004Eligibility, IdentityStateEligibility(ACTIVE), AssertionLevelEligibility(S_att, level 2, issuers [W])])`, objective bound to the T5 tender with `SwarmTenderAdapter` as acceptance authority; A and C join; activate; deploy and set the `SwarmAccount`; register the swarm as an AUF composite unit containing the members' units at pinned versions. Failure cases: a candidate without the assertion is refused; after W revokes an assertion, `challenge` suspends the member; membership never implies who fulfills or who is paid.
63
+ - **T5 governance**: a judged tender with FOGA's `ACDFTaskTenderAdapter` as acceptance authority; the `SwarmAccount` submits the report package; `open` → ballots by J1–J3 → `settleRound` → `finalize` → `execute` → `acceptFulfillment`; `SwarmTenderAdapter.settle` concludes the swarm ACHIEVED; a charter amendment passes through `SwarmDecisionAdapter`; a second judged tender shows NoDecision and the tender's own default path. Failure cases: wrong-round ballots, non-judge ballots, execute before Final, a judge who is also a party (configuration check).
64
+ - **T6 dispute**: FOGA's revision-4 `ADRFServiceEscrow` bound to the ADRF policy; C deposits and opens a call to A committed to skill v1's package hash; A upgrades to v2 and delivers declaring v2; `DeclaredVersionVerifier` recognizes the breach; C files; judgment through the bridge and J1–J3; `finalize` Sustained; `enact` refunds C; a second `enact` is rejected. A conforming delivery (declared = committed) settles normally as the control case. Failure cases: filing after the dispute period, filing by a non-party, enact before Final. The generic 8414↔8471 bridge is a later increment.
65
+ - **T7 safety**: the guardian suspends A's binding; a direct RPC call to `FogaCellAccount.execute` for a commitment-class action reverts (bypass test); de-risk actions still pass; the kernel pauses new commitments; the operator's direct submission to the token succeeds on chain but is attributed to the operator, not to A (attribution test); resume restores execution; letting A's AID go STALE (time skip, recorded) makes the account's AID clause refuse commitment-class actions until a heartbeat. Specification text alone enforces nothing; the account's gate and the acceptance consumers do.
66
+ - **T8 value**: E registers the realized-net-cash-flow method descriptor and asserts measurement statements for A's skill unit (income 0.001 ETH, refund 0, observed gas, model fees missing — never zero) and for the swarm unit (SwarmAccount receipts only); the resolver verifies the receipts. No field is called value; no income is counted in two units.
67
+ - **T9 succession**: (a) active migration — owner deploys A′, transfers the ERC-8004 identity, A goes STALE, A′ binds (takeover), A retires naming A′, A′ publishes a new ARD agent record; (b) asset transfer and adoption — the skill token moves to A′, the ARD record becomes unadopted, A′ re-commits the descriptor; (c) non-inheritance — A′ holds no KYA assertion, swarm seat, ASF binding or credit of A's; (d) key-loss recovery — guarded profile: the owner rotates the operator; lite profile: the old anchor stays STALE and a new identity starts from zero, documented as such.
68
+
69
+ ## 5. Acceptance matrix
70
+
71
+ Per ERC: the minimum run acceptance in docs/compatibility-matrix.md. Loop C cases: process killed between submit and settle; duplicate inbound requests produce one economic effect; RPC timeout after broadcast is resolved by reading chain state before retrying; revoked assertion suspends membership; exhausted budget blocks new commitments; safety stop (T7); inactive member handled by the charter; the central MCP switched off leaves self-hosted nodes working through their own RPC and ARD entry. Loop D: unscripted task input, the agent chooses skills, executes and delivers without per-transaction instructions; permissions, budget, results and process evidence are checked, not the exact wording. Replication cases: `npx -y @finchip.ai/foga demo` in a clean environment, `docker compose up` on amd64 and arm64, two external MCP clients, an independent operator's node interacting with the OG instance.
72
+
73
+ ## 6. New development (listed honestly)
74
+
75
+ - **Predicate-style ZK-KYA** (must): one fixed predicate — "among records signed by source S, at least K are Accepted within [t0, t1]" — as a new circuit with N record slots, EdDSA/Baby Jubjub record signatures, a source-set Merkle root, public inputs bound to subject key, scheme id, admission domain, challenge, window, K and epoch, a nullifier output; a Groth16 verifier and an adapter implementing `IKYAVerifier`; scheme `S_pred` in PROVED mode; a development trusted setup labeled as such. The proof establishes a fact about that range, not trustworthiness.
76
+ - **FogaCellAccount** (must, small): the `ASFGuardedAccount` execution gate plus ERC-1271 with scoped operator permissions, ERC-721/1155 receivers, owner / operator / guardian / recovery roles and a configurable AID-state clause gate. Revision 2 (0.6.0) closed the operator's scope to an owner-set allow-list, refused it every asset-moving selector and made its signatures opt-in and gate-checked, once the kernel was to run as a public node holding that one key.
77
+ - Later increments: the generic 8414↔8471 bridge (a rejection must become a non-final preliminary opinion with a pre-authorized final executor, within the tender's acceptance deadline), a combined acceptance authority (safety ∧ machine ∧ deliberation), a KYA-gated judge profile.
78
+ - The bulk of the work is not Solidity: `foga-core`, `foga-kernel`, `foga-mcp`, the CLI, build/deploy/doctor tooling, scenarios, evidence, documentation.
79
+
80
+ ## 7. MCP, A2A and pricing boundaries
81
+
82
+ One kernel, three entrances; switching entrance never changes authorization rules or task state. MCP (2026-07-28) is stateless; business operations are persistent and addressed by `operationId`; long tasks use FOGA's own start / query / cancel / receipt before any protocol extension. Two modes: embedded (the FOGA harness runs the node) and host (an external agent uses the capabilities through MCP and owns scheduling, state, authorization and recovery). The free base tier is a complete self-hosted loop over the ten ERCs — node software, adapters and acceptance tools, doctor and probe, `spec.read`, local signing and evidence, unsigned calldata for writes; the paid tier covers hosted resources — runs and queues, indexing and history, proof computation, metered model / RPC / gas, bounded standard workflows. Call permission, business authorization and wallet permission are three different checks; paid-tool execution order is validate (including header/body consistency) → operator and permission → quote and payment → bind operation → idempotent execute → receipt; payment dedup and business dedup are separate. "$1" is a prepaid credit starting point and, for fixed-scope jobs, a capped trial package with explicit scope, budget caps, gas inclusion, failure/cancel/timeout billing and reserve/settle timing; x402 is a later payment adapter. An A2A task enters as a FOGA operation and becomes or binds a tender only when the caller chooses tender mode and every term is explicit; the agent card lists enabled, executable capabilities, not held tokens.
83
+
84
+ ## 8. Phases
85
+
86
+ | Phase | Output | Gate |
87
+ |---|---|---|
88
+ | 1 world | repository skeleton; vendor lock and sync; artifact bundle; deployment orchestrator; address books; doctor layers 1–4; CI | one-command world on Anvil; doctor reports for Anvil and Sepolia; CI rebuilds the bundle to the same hash |
89
+ | 2a cells | `foga-core`, `foga-kernel`, `FogaCellAccount`; T0–T5 on Anvil; first loop-C cases. **Done: 2a-1 (0.2.0) account, core, kernel, T0–T3, four loop-C cases; 2a-2 (0.3.0-alpha.1) T4, T5, the credential-pattern proof for A, the FOGA-Council.** | T0–T5 green; restart recovery and dedup pass |
90
+ | 2b cells | predicate circuit and adapter; T6–T9; measurement receipts; remaining loop-C cases; doctor layer 5. **Done (0.4.0-alpha.1): `kya_predicate_count_v1` with its development ceremony and FOGA's adapter, S_pred proved at the end of T3; T6 dispute with the refund enacted; T7 stop, bypass, attribution, escape attempts and the STALE gate; T8 receipts and resolver; T9 migration, skill adoption and non-inheritance; doctor layer 5 from the evidence.** | T0–T9 green; every negative case rejected as specified |
91
+ | 2c public evidence | Sepolia run from one driver script; cells bound in both AID registries; FOGA-owned modules, adapter and escrow; evidence and Sourcify. **Done (0.5.0): attach-mode worlds completed from the bundle by `foga world deploy` (the revision-4 ERC-8471 stack and the two eligibility modules), twelve keys from one phrase with W as treasury (`foga keys`, step-wise top-ups, `foga genesis preflight`), the backing AID registry, the uniform T7 liveness demonstration, fee replacement for stuck transactions, reads pinned to the blocks the kernel has written, the public timing profile, the path rehearsed on anvil in CI; the Sepolia run of 2026-11-01 — world `sepolia-11155111-20261101T043153Z`, 203 operations, doctor Pass 234 with one known Fail, all eleven standards Pass — and its three files in `deployments/` (docs/genesis.md, "The Sepolia run"). Sourcify verification of FOGA's 15 contracts is still open.** | public state re-checkable; known mismatches reported |
92
+ | 3 interfaces | the existing kernel completed with the permission, concurrency and recovery semantics a public service needs, then base MCP (stdio and Streamable HTTP), CLI, HTTP, A2A card and inbound mapping, documents from one config, ERC-8004 and ARD registration, MCP registry listing, documentation site; loop D. **Done: 3a-1 (0.6.0-alpha.1) kernel hardening; 3a-2 (0.6.0-alpha.2) the capability catalog, policy engine, decision records, node runtime and CLI, with the Loop D cases a–g driven through the CLI on anvil (section 9, docs/node.md). Next: 3b.** | published capabilities match acceptance results; external clients work |
93
+ | 4 hosted | indexing, proof runs, scenario runner, gas sponsorship; `operationId` and idempotency; billing units; x402 on Base | measured costs; packages match behavior |
94
+ | 5 replication and outreach | multi-arch images; independent-node replication; central-MCP-off test; discovery materials | an external operator completes the core scenarios alone |
95
+
96
+ ## 9. Phase 3 — from kernel to node
97
+
98
+ The premise of Phase 3 is not a new system but the kernel reused: Phase 2 built an idempotent, resumable driver for one scenario; a node that answers other agents needs the same kernel with three things it did not need as a driver — a permission model for a key it does not own, concurrency between callers, and recovery semantics a caller can rely on. Phase 3 is cut in four slices: **3a** the kernel completed (3a-1 below) and the capability catalog, policy engine, decision records and node skeleton (3a-2); **3b** MCP (stdio and Streamable HTTP, the 2026-07-28 specification) and the HTTP API with the npm package and registry listing; **3c** loop D — the demander, the model adapters, the unscripted run — as a scenario the doctor can judge; **3d** A2A, the documentation site, the OG instance's move to a revision-2 account and its public endpoints, the Sepolia evidence. The gate of each slice is a green that the next slice builds on; an always-on node holding a key runs only after 3a's acceptance passes.
99
+
100
+ Three checks, three vocabularies. A call to the node passes **call permission** (may this caller invoke this capability: public, caller-bound or operator-only), **business authorization** (does the cell do this, for this caller, under its budget and policy) and **wallet permission** (does the account let the operator make this call: the allow-list, the asset refusal, the daily cap, the gate). The three are different checks in different places — the node, the policy engine, the contract — and none substitutes for another. Capabilities are catalogued along three dimensions: action (read / build / act / admin), visibility (public / caller / operator) and principal (whose act it is); `binding_present` is admin, a build is for someone, an act is by the cell.
101
+
102
+ **3a-1, kernel hardening (0.6.0-alpha.1).** What the advisor's review of 0.5.0 found and what was done about it, all of it tested offline (`test/tx-semantics.test.ts` against an in-process chain, `test/store.test.ts`, `test/keys.test.ts`, the Foundry tests) and by the genesis on anvil (T0–T9 and the attach rehearsal green, the crash-and-resume path in CI):
103
+
104
+ - *Account.* The operator had no target or selector allow-list (expiry and value cap only) and its ERC-1271 signature was checked for expiry alone. Revision 2 of `FogaCellAccount`: `operatorAllowed[target][selector]` set by the owner, asset-moving selectors refused to the operator by construction, `operatorMaySign` off by default and the signature path gated like `execute`. The genesis opens each cell's scope from named groups (`src/genesis/operator-scope.ts`) and moves A's identity and skill to A-prime as the owner.
105
+ - *Keys.* The genesis loaded all twelve roles; a node loads one: `FOGA_OPERATOR_KEY_FILE` (0600, owned by the node's user) or `FOGA_OPERATOR_KEY`, and refuses an environment that also holds a phrase, a deployer key or any role key (`src/node/keys.ts`; `foga keys export`, `foga keys check`). The skill worker inherits no `NODE_OPTIONS`, runs the extraction as well as the probe out of process, and runs under Node's permission model with read access to the directories a job names when it is not under the development loader (docs/kernel.md, "Running a skill").
106
+ - *Transactions.* The replacement count was reset by a recursion on every timeout; it is now counted on the row and persisted, so the limit holds across restarts. A fee cap bounds the first send and every replacement. One signer's operations run one at a time (nonces in order, whoever asks concurrently). A key is bound to the hash of its request: the same key under another request is a conflict, never a reuse. A failed operation answers with its failure until it is retried explicitly, and the fee a reverted attempt cost stays on the row. The store knows the world and chain it belongs to, not just block 0. Jobs (business units with their operations) sit beside operations in the store. An RPC failure during the wait leaves the row `sent` for the next run, as a crash would.
107
+ - *Still open, by design.* A-prime reuses A's operator key, the OG instance's `foga-probe` skill was not migrated, the ERC-8004 registration file is stored by hash only and `setAgentURI` was never called: these are the readiness reconciliation of the OG instance and belong to 3d, where the instance moves to a revision-2 account with its own operator and its documents are published at stable URLs.
108
+
109
+ **3a-2, the catalog and the node (0.6.0-alpha.2).** `src/tools/`: 28 capabilities (the Loop D path) each declaring action, visibility and principal, with zod schemas published as JSON Schema 2020-12; `Catalog.invoke` runs the three checks — call permission, business authorization through the policy engine (`src/node/policy.ts`: safety, skill, policy, verifier, budget), wallet permission by simulation — and writes a decision record for every attempt to act, allowed or refused, with the gate that decided. Jobs are the business unit, operations the chain writes; a tender's n-th completion is its own job; a job exists only once every gate passed; the same job is answered once, a failed one answers with its failure, the same job under another request is a conflict. `src/node/`: the cell configuration (`foga.cell-config/1`), the node over the kernel with the keys it holds and refuses, the birth of a cell from its config (`foga cell init`), the move to a new account (`foga cell migrate`), the watchers (heartbeat, discovery, settlement, safety). The CLI is generated from the catalog. The 3a-2 gate — the seven Loop D cases through the CLI on anvil, without the genesis script — is `test/node-cli.test.ts`, green; docs/node.md has the whole account.
110
+
111
+ **3b, MCP and HTTP (0.6.0-alpha.3).** The six points written down for this slice, as they landed. One: the server (`@modelcontextprotocol/server` 2.4.0) serves the 2026-07-28 revision as its main path and the 2025-era handshake through the SDK's stateless compatibility layer, on Streamable HTTP and on stdio alike; `test/mcp.test.ts` drives it with the reference client pinned to 2026-07-28, in legacy mode and in auto mode, because a client that defaults to the old handshake proves only the old path. Two: annotations are static, so a write capability is `<name>` (act), `<name>_simulate` and `<name>_build` over one handler; the tool list is the catalog filtered by the caller, every call still goes through `Catalog.invoke`, and the number of tools (11 for the public, 36 for an `act` key, 40 for the operator) is not the number of capabilities (29, `spec_read` added). Three: `tender_precheck` answers `eligible: false` as an ordinary result; a refused act is `isError: true` with gate, reason and decision id; a credential the node does not know is 401 and a capability or mode above the caller is 403, never a business refusal. Four: no CORS headers, and a foreign `Origin` or `Host` is refused at the edge; the SDK decides the semantics of `GET /mcp` by era; bodies are capped and parsed by the capability's schema alone. Five: API keys (`foga node key new`, stored as SHA-256, compared in constant time) are for the operator's own integrations and named partners; the public reads and builds; OAuth stays out of Phase 3. Six: `scripts/pack-smoke.mjs` installs the `npm pack` tarball in a clean directory and runs the packaged CLI from there — a cell born, `foga node mcp` without a key driven by a raw 2025-era client over stdio, stdout protocol-only, `spec_read` served from inside the package — as a CI step; `engines.node` is `>=22.13`, where `node:sqlite` needs no flag. Two things the slice found: the request hash that binds a job excludes the idempotency key itself (a request first made under a derived job id and then repeated naming that id is the same request), and a cell's birth adopts the FOGA-Cell-v1 specification its owner published for an earlier cell instead of failing on `SpecificationExists`. The read-only configuration of the OG instance (`deployments/sepolia.cell.example.json`), `package.json`'s `mcpName` and `server.json` are in place for the publication in 3d. docs/mcp.md.
112
+
113
+ **3c, Loop D (0.6.0-alpha.4).** The runner (`src/node/runner.ts`) is the loop of section 8 as written: perceive through the read capabilities, propose with the catalog as tools, decide in `Catalog.invoke`, execute as keyed operations, record by hash — 12 tool calls and 2 acts a tick, the model's calls counted against the day, the watchers outside the model. One adapter interface in the Messages API's vocabulary; `anthropic` over `fetch` with the key in the environment and the model name in the configuration, `stub` as the deterministic table that also makes the over-budget proposal of case g. The demander is its own process with its own key and store; the cases a–f are minted in a seeded order and carry what the acceptance expects. `foga demo --loop-d` runs it all on a new cell with keys nobody held — the kill after the first submission and the restart, the guardian's suspension for f, the other entrances beside the runner — and `foga doctor --loop-d` judges the evidence beside layer 5 with the rows of section 8's matrix and the eight additions of v0.2 (the same request across entrances, the same job under another request, concurrent acts with distinct nonces and the budget holding, the recovery, the operator key's transactions read inside `execute`). The run found a race the matrix was written to find: three concurrent mints each passed the budget gate because none saw the others' reservations, and the account's daily cap refused the third on chain; the decision section now runs one act at a time per node and a job reserves its planned value from its decision, so the refusal is the node's, at `budget`, before anything is sent. It also found that an `execute`'s inner value was not what the operation's row recorded (the outer transaction's zero was), so the value book undercounted; fixed. Stub and real model run the same matrix; the real model's runs (anvil, then Sepolia) are 3d's evidence. docs/loop-d.md.
package/docs/doctor.md ADDED
@@ -0,0 +1,53 @@
1
+ # Doctor
2
+
3
+ `foga doctor` inspects a world and reports, per contract and per layer, what it could establish. It never collapses the layers into a single success flag.
4
+
5
+ ## Layers
6
+
7
+ | Layer | Question | How |
8
+ |---|---|---|
9
+ | 1 chain and code | is there code at the address, on the expected chain? | `eth_chainId`, `eth_getCode` |
10
+ | 2 interfaces | which interfaces does the contract declare, and does it declare the ones it was built from? | `supportsInterface` probes for ERC-165 and for every interface of the same repository; expected = the contract's direct base interfaces |
11
+ | 3 version match | is the runtime code the locked build? | keccak256 of the on-chain code after stripping the CBOR metadata trailer, zeroing every embedded metadata hash (a contract that creates other contracts embeds their creation code and metadata — TaskToken embeds TaskVault), and zeroing library-address and immutable slots, compared with the bundle's `runtimeIdentity` |
12
+ | 4 configuration and permissions | are dependencies wired as the world says, and who holds the authority slots? | view calls listed in `src/doctor/checks.ts` (`WIRING_CHECKS`), compared with world addresses, world parameters or explicit `expectations`; `READOUTS` print owner / admin / counters |
13
+ | 5 semantic validation | do the success, rejection, signature, proof and recovery cases hold? | the genesis scenario provides the evidence (`foga genesis run`, docs/genesis.md: T0–T9). `foga doctor --genesis <evidence.json>` attributes every recorded check to the standards it exercises (`src/doctor/semantic.ts`: by the operation the check names, with the step as fallback) and reports per ERC: Pass when every effective check passes, Fail when any fails (the failing checks are listed), Not tested when the evidence has no check for the standard or only skipped ones (a check skipped for want of proving material is never a pass). The evidence must come from the same world (worldId and chain), otherwise the verdicts are Unknown |
14
+ | D Loop D | did an unscripted run stay inside the cell's rules? | the evidence of a Loop D run (`foga demo --loop-d`, `foga loop-d run`; docs/loop-d.md). `foga doctor --loop-d <evidence.json>` reads the decision records, the operations, the demander's cases and the scan of the operator key's transactions (`src/doctor/loop-d.ts`) and reports, beside layer 5: every operation under an allowed decision, refusals that broadcast nothing, the four budget books, every operator transaction aimed at the account and allow-listed, the cases ending as expected (a, b taken and paid; c–f refused at the named gate; f taken after the resume; g the model's over-budget proposal refused), the evidence complete, the recovery drill, the entrances (idempotent, conflict, concurrent), and — with `--compare` — the same outcomes from two models. Alone (without `--world`) it prints the Loop D table and writes `foga.loop-d-report/1` |
15
+
16
+ ## Verdicts
17
+
18
+ `Pass`, `Fail`, `Unknown` (the doctor could not decide — no bundle key, an undecodable answer, an unpublished interface the contract was built from but does not declare), `NotTested` (not probed), `NotApplicable` (nothing to assert — the contract has no ERC-165, the reference is absent from this world, the arguments are unavailable).
19
+
20
+ A layer-3 (or layer-2) `Fail` on a contract whose world entry carries `deployedRevision` is labeled *known*: the chain holds an earlier revision than the locked source. That is information about the world, not a defect in either. The official ERC-8004 Identity Registry is not built by FOGA: layer 2 checks its ERC-165 and ERC-721 declarations, layer 3 is Not applicable.
21
+
22
+ ## Probe plans and replay
23
+
24
+ A doctor run is two steps: a deterministic **probe plan** (every JSON-RPC request the doctor needs, derived from the world file and the bundle alone) and its execution. `--export-probe` writes the plan; `scripts/relay.mjs` (or any JSON-RPC client) executes it and writes results; `--import-results` evaluates them. The report records whether it was produced live or by replay, the RPC used and when the results were collected. This lets a machine without RPC access evaluate evidence collected by one that has it, and lets a report be reproduced later from the same results file.
25
+
26
+ ## Running
27
+
28
+ ```bash
29
+ # local world just deployed
30
+ npm run foga -- doctor --world deployments/local.json --out deployments/local.doctor.json
31
+
32
+ # Sepolia, attached from the config, live (the address book only: the ERC-8471 stack and two eligibility modules are not in the
33
+ # config and are added by `foga world deploy`; run the doctor on deployments/sepolia.json after that for the complete world)
34
+ FOGA_RPC_URL=$SEPOLIA_RPC_URL npm run foga -- doctor --world worlds/sepolia.json --attach --out deployments/sepolia.doctor.json
35
+
36
+ # Sepolia through a relay
37
+ npm run foga -- doctor --world worlds/sepolia.json --attach --export-probe sepolia.probe.json
38
+ node scripts/relay.mjs $SEPOLIA_RPC_URL sepolia.probe.json > sepolia.results.json
39
+ npm run foga -- doctor --world worlds/sepolia.json --attach --import-results sepolia.results.json --out deployments/sepolia.doctor.json
40
+ ```
41
+
42
+ ```bash
43
+ # layer 5 from a genesis run (the demo does this by itself after the genesis)
44
+ npm run foga -- genesis run --world deployments/local.json --until T9
45
+ npm run foga -- doctor --world deployments/local.json --genesis deployments/local.genesis.json --out deployments/local.doctor.json
46
+
47
+ # Loop D beside layer 5 (foga demo --loop-d does the run and this judgment by itself)
48
+ npm run foga -- loop-d run --world deployments/local.json --rpc http://127.0.0.1:8545 --out deployments/loop-d.local.json
49
+ npm run foga -- doctor --world deployments/local.json --genesis deployments/local.genesis.json --loop-d deployments/loop-d.local.json --out deployments/local.doctor.json
50
+ npm run foga -- doctor --loop-d deployments/loop-d.local.json # the Loop D table alone
51
+ ```
52
+
53
+ The process exits with code 3 when any check fails, so CI can gate on it. `deployments/local.doctor.example.json` is a complete report from a local world after a T0–T9 genesis: layers 1–4 as before (2 Unknown: ADRFServiceEscrow is built from `IADRFExecutor` and `ISettlementLedger` but declares neither — upstream publishes no ids for them) and layer 5 Pass for the ten standards and ERC-8004. `deployments/sepolia.doctor.example.json` is the same report for the Sepolia world after its genesis (2026-11-01, block 12040269, live against publicnode): Pass 234, Fail 1 (the ARD fixture registry's older source, known), Unknown 2 (the same two ids), Not applicable 25, layer 5 Pass for all eleven; the layer-5 rows there count the checks a replayed run records as skipped (`N/N checks pass over …; M skipped`) — a skipped check is never a pass, and the verdict rests on the effective ones (docs/genesis.md, "The Sepolia run").
@@ -0,0 +1,11 @@
1
+ # Client configuration examples
2
+
3
+ One server definition, three clients (docs/mcp.md, "Client configuration"). Each runs `npx -y @finchip.ai/foga mcp --config <cell.config.json>`, the stdio MCP server of one cell.
4
+
5
+ | File | Client | Where it goes |
6
+ |---|---|---|
7
+ | `claude_desktop_config.json` | Claude Desktop | the `mcpServers` block of the app's `claude_desktop_config.json` |
8
+ | `claude-code-mcp.json` | Claude Code | a project's `.mcp.json` (or `claude mcp add foga -e FOGA_OPERATOR_KEY_FILE=… -- npx -y @finchip.ai/foga mcp --config …`) |
9
+ | `cursor-mcp.json` | Cursor | `.cursor/mcp.json` (shown without a key: reads, dry runs and builds) |
10
+
11
+ `FOGA_OPERATOR_KEY_FILE` names a 0600 file holding the cell's operator key (`foga keys export --role operator.A`, or any key the account names as operator); with it the server acts for the cell, without it the client gets reads, dry runs and builds. `FOGA_RPC_URL` is needed only when the cell configuration names no `rpc`. From a checkout before publication, replace `npx -y @finchip.ai/foga` with `node /path/to/foga/bin/foga.js` after `npm run build`.
@@ -0,0 +1,13 @@
1
+ {
2
+ "mcpServers": {
3
+ "foga": {
4
+ "type": "stdio",
5
+ "command": "npx",
6
+ "args": ["-y", "@finchip.ai/foga", "mcp", "--config", "/home/me/cells/D.json"],
7
+ "env": {
8
+ "FOGA_OPERATOR_KEY_FILE": "/home/me/.foga/keys/operator.key",
9
+ "FOGA_RPC_URL": "http://127.0.0.1:8545"
10
+ }
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "foga": {
4
+ "command": "npx",
5
+ "args": ["-y", "@finchip.ai/foga", "mcp", "--config", "/home/me/cells/D.json"],
6
+ "env": {
7
+ "FOGA_OPERATOR_KEY_FILE": "/home/me/.foga/keys/operator.key",
8
+ "FOGA_RPC_URL": "http://127.0.0.1:8545"
9
+ }
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "foga": {
4
+ "command": "npx",
5
+ "args": ["-y", "@finchip.ai/foga", "mcp", "--config", "/home/me/cells/D.json"],
6
+ "env": {
7
+ "FOGA_RPC_URL": "http://127.0.0.1:8545"
8
+ }
9
+ }
10
+ }
11
+ }