@finchip.ai/foga 0.6.0-alpha.6 → 0.6.0

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 (44) hide show
  1. package/README.md +35 -14
  2. package/dist/a2a/card.js +54 -0
  3. package/dist/a2a/server.js +276 -0
  4. package/dist/a2a/types.js +20 -0
  5. package/dist/build/bundle.js +2 -1
  6. package/dist/cli-cell.js +176 -16
  7. package/dist/cli.js +150 -5
  8. package/dist/core/world.js +17 -0
  9. package/dist/demo/birth.js +11 -5
  10. package/dist/demo/loop-d.js +39 -1
  11. package/dist/demo/quickstart.js +97 -11
  12. package/dist/genesis/operator-scope.js +1 -0
  13. package/dist/genesis/probe.js +23 -7
  14. package/dist/http/access.js +105 -0
  15. package/dist/http/server.js +84 -43
  16. package/dist/http/signed.js +136 -0
  17. package/dist/mcp/server.js +48 -1
  18. package/dist/node/advise.js +134 -0
  19. package/dist/node/config.js +55 -1
  20. package/dist/node/documents.js +298 -0
  21. package/dist/node/preflight.js +208 -0
  22. package/dist/node/propagation.js +95 -0
  23. package/dist/node/wallet.js +132 -0
  24. package/dist/tools/documents.js +74 -0
  25. package/dist/tools/index.js +3 -1
  26. package/dist/tools/propagation.js +35 -0
  27. package/dist/tools/tenders.js +22 -6
  28. package/dist/util/version.js +2 -0
  29. package/dist/world/sourcify.js +165 -0
  30. package/docs/a2a.md +31 -0
  31. package/docs/design-memo.md +23 -6
  32. package/docs/documents.md +25 -0
  33. package/docs/examples/README.md +2 -2
  34. package/docs/extending.md +49 -0
  35. package/docs/loop-d.md +11 -0
  36. package/docs/mcp.md +18 -11
  37. package/docs/node.md +35 -11
  38. package/docs/og-deployment.md +131 -0
  39. package/docs/propagation.md +41 -0
  40. package/docs/quickstart.md +36 -21
  41. package/docs/wallet.md +62 -0
  42. package/docs/world.md +12 -0
  43. package/package.json +1 -1
  44. package/server.json +2 -2
@@ -0,0 +1,131 @@
1
+ # Deploying the OG instance (foga.finchip.ai)
2
+
3
+ The Finch OG Agent is one FOGA cell, run as a served node on a small Linux box (an EC2 instance), reachable at `https://foga.finchip.ai`. It runs in **host mode** by default: every entrance answers — `/mcp`, `/api`, `/a2a`, `/.well-known/*`, `/documents/*`, `/healthz` — the watchers keep whatever the cell committed to, and no model runs (design memo, section 10). A model is started only on demand (`foga node run`), for a Loop D run or a spell of autonomous work, and stopped after. This is the Phase 3d-3 runbook; `deploy/` holds the three files it refers to (`foga-og.service`, `Caddyfile`, `og.env.example`).
4
+
5
+ Nothing here is a local sandbox. The chain is Sepolia; the cell's state lives there, and the box holds only what is needed to serve and to sign: a configuration, a store, and one key.
6
+
7
+ ## How the cell came to be
8
+
9
+ The OG cell was born on Sepolia by the path any cell takes; nothing about it is special to this box. On the box: `foga wallet new` (one key, the cell's identity, in a 0600 file; no network), `foga cell new` (the configuration: the world `deployments/sepolia.json`, the presence and the public face below), the owner address funded from a faucet, `foga cell init` (the birth — the revision-2 `FogaCellAccount` with its allow-list open to the operator, the ERC-8004 registration, the FOGA-Cell-v1 specification binding, the anchor), `skill_mint --offer` for `finch-extract-verify`, `foga cell docs publish` for its documents, then `foga node serve`. It is ERC-8004 agent 11261. The Finch OG Agent's earlier line on Sepolia, agent 11255 (name A-prime, `deployments/sepolia.cell.example.json`), is the revision-1 body the 2c genesis left at its T9 succession and stays as that evidence: a revision-1 account has no operator allow-list, so a node will not act on it, and rather than migrate it the OG was born complete. No key changed hands.
10
+
11
+ The box holds one key, the signer's, which is owner, operator and guardian at once — the default, right for a first run. `foga cell advise --config og.config.json` says what comes next for this cell as for any other, and the first item is to separate the roles: `foga cell migrate --config og.config.json --to <new.config.json> --operator <a fresh operator address>` moves the cell to an account whose operator is not its owner (the identity, the skill and the documents follow; docs/node.md, "Birth and migration"), after which only the **operator** key stays on the serving box and the owner key goes offline. `foga node preflight --config og.config.json --wallet <wallet>` is the readiness check either way.
12
+
13
+ Without a key the same deployment serves reads, dry runs and builds — a complete, useful public endpoint on its own.
14
+
15
+ ## The box
16
+
17
+ One dedicated OS user, a checkout it only ever pulls, and the cell's three files beside it:
18
+
19
+ ```
20
+ sudo useradd --system --home-dir /opt/foga --create-home --shell /usr/sbin/nologin foga
21
+ sudo -u foga git clone https://github.com/garyyang-finchip/foga /opt/foga/foga # public repo: a read-only clone, never pushed
22
+ cd /opt/foga/foga && sudo -u foga npm ci && sudo -u foga npm run build # the box builds dist/; it never needs git credentials
23
+ ```
24
+
25
+ The box only ever `git -C /opt/foga/foga pull`s and runs; it never pushes, so no GitHub credentials live on it and no username/password prompt is ever reached. Node 22.13+ is the one requirement (`node:sqlite` needs no flag there); `nvm` or the distro's Node 22 both do. Foundry is **not** needed to serve — `anvil`/`forge` matter only for a local chain or a Sourcify run, not for host mode.
26
+
27
+ The cell is three files under `/opt/foga`, and they are the whole of it:
28
+
29
+ | File | What | Backed up |
30
+ |---|---|---|
31
+ | `/opt/foga/cell.config.json` | the configuration (`foga.cell-config/1`) — the account, the policy, the presence, `runtime.http` | yes |
32
+ | `/opt/foga/cell.ops.sqlite` (+ `-wal`, `-shm`) | the store: operations, jobs, decisions, facts | yes |
33
+ | `/opt/foga/wallet/signer.key` | the one key the node signs with (mode 0600, owner `foga`) | yes, and separately — it is the identity |
34
+
35
+ Everything else — the deployed contracts, the agent's on-chain documents, the skill token — lives on Sepolia, not on the box. Moving the cell to another machine is copying those three files and pointing the service at them (below).
36
+
37
+ ## The configuration for serving
38
+
39
+ Beyond what `foga cell new` writes, the serving node needs its public face set (`src/node/config.ts`, `runtime.http`):
40
+
41
+ ```json
42
+ "runtime": {
43
+ "http": {
44
+ "listen": "127.0.0.1:8787",
45
+ "publicUrl": "https://foga.finchip.ai",
46
+ "allowedHosts": ["foga.finchip.ai"],
47
+ "allowedOrigins": [],
48
+ "documentsDir": "documents"
49
+ }
50
+ },
51
+ "presence": {
52
+ "name": "Finch OG Agent",
53
+ "homepage": "https://foga.finchip.ai",
54
+ "provider": { "organization": "FinChip.ai", "url": "https://finchip.ai" }
55
+ }
56
+ ```
57
+
58
+ `publicUrl` at `https://foga.finchip.ai` also makes this the cell that serves the maintainer's services catalog: every manifest points at `https://foga.finchip.ai/services.json`, and the node answers it (`foga.services/1`) from what its build knows; to change the live list without a release, drop a `services.json` on the box and have Caddy serve that path ahead of the proxy (`handle /services.json { root * /opt/foga/www; file_server }` before the `reverse_proxy`). `publicUrl` is what the cell commits its documents under and what the agent card advertises; `allowedHosts` must name the public host, because the node binds the loopback and checks the `Host` header the proxy forwards (a request whose Host is not allowed is refused — this is the Origin/Host check the protocol asks for, not CORS). Then build and publish the documents once, so `/.well-known/*` and `/documents/*` answer and the chain holds their URIs: `foga cell docs publish --config /opt/foga/cell.config.json --wallet /opt/foga/wallet` (docs/documents.md). `foga node preflight` reports whether the public URL answers for the cell and whether the host is allowed.
59
+
60
+ ## systemd and Caddy
61
+
62
+ Caddy terminates TLS for `foga.finchip.ai` and forwards to the loopback node; systemd keeps the node running as the `foga` user with one key and nothing else in its environment.
63
+
64
+ ```
65
+ sudo cp /opt/foga/foga/deploy/foga-og.service /etc/systemd/system/foga-og.service
66
+ sudo install -d -o foga -g foga /etc/foga
67
+ sudo cp /opt/foga/foga/deploy/og.env.example /etc/foga/og.env # edit: the key file path and a Sepolia RPC
68
+ sudo chown foga:foga /etc/foga/og.env && sudo chmod 600 /etc/foga/og.env
69
+ sudo systemctl daemon-reload && sudo systemctl enable --now foga-og
70
+
71
+ sudo cp /opt/foga/foga/deploy/Caddyfile /etc/caddy/Caddyfile # or import it into an existing one
72
+ sudo systemctl reload caddy
73
+ ```
74
+
75
+ DNS: an `A`/`AAAA` record for `foga.finchip.ai` at the box's address (Caddy then gets the certificate on first request). `docs.foga.finchip.ai` is a separate `CNAME` to GitHub Pages — the documentation site is not served from this box. The unit's environment is deliberately two lines (`deploy/og.env.example`): the operator key file and the RPC. A node refuses to start if its environment also carries an owner, guardian, deployer or mnemonic key (`src/node/keys.ts`), so keep it to those two.
76
+
77
+ Without a key in `og.env` the node serves reads, dry runs and builds — valid and public. With the operator key, the watchers run beside the server and the cell acts.
78
+
79
+ ## Bring-up and verification
80
+
81
+ ```
82
+ sudo systemctl status foga-og # active (running)
83
+ curl -s https://foga.finchip.ai/healthz # {"ok":true,"cell":"…","account":"0x…","chainId":11155111,…}
84
+ curl -s https://foga.finchip.ai/.well-known/agent-card.json | jq .name
85
+ foga node preflight --config /opt/foga/cell.config.json --wallet /opt/foga/wallet # the readiness reconciliation (docs/node.md)
86
+ ```
87
+
88
+ A first smoke of the public entrances from anywhere: `npx -y @finchip.ai/foga` is not needed — any HTTP client does. An A2A quote over the wire:
89
+
90
+ ```
91
+ curl -s -X POST https://foga.finchip.ai/a2a -H 'content-type: application/json' -H 'A2A-Version: 1.0' \
92
+ -d '{"jsonrpc":"2.0","id":1,"method":"SendMessage","params":{"message":{"messageId":"hello","role":"ROLE_USER","parts":[{"text":"what can you do?"}]}}}'
93
+ ```
94
+
95
+ should answer a `TASK_STATE_COMPLETED` quote of the cell's offered skills and the terms a tender must meet.
96
+
97
+ ## The MCP registry listing
98
+
99
+ With `https://foga.finchip.ai/mcp` answering, the cell was listed in the MCP registry as `io.github.garyyang-finchip/foga` so clients and other agents discover it (docs/mcp.md, "The package"). `server.json` at the repository root is the npm-package manifest; the OG cell also writes its own `server.json` among its documents (`foga cell docs build`) with this cell's MCP URL as the remote. Publishing is the package owner's, from a checkout, and needs the remote reachable:
100
+
101
+ ```
102
+ mcp-publisher login github # a browser device-code flow; no long-lived credential on the box
103
+ mcp-publisher publish # publishes the manifest whose mcpName the npm package already carries
104
+ ```
105
+
106
+ This is a one-time registration (and a re-publish when the manifest changes), not part of the running service.
107
+
108
+ ## The documentation site
109
+
110
+ `docs.foga.finchip.ai` is a static site served by GitHub Pages, not from this box. The `site/` folder is it: `index.html` (a landing page with the covenants, the one-command quickstart and the links), `llms.txt` (the machine-readable index answer engines and agents ingest — llmstxt.org), and `CNAME` (the custom domain). Point GitHub Pages at it in the repository settings (Pages → deploy from the `main` branch, folder `/site`) and add a DNS `CNAME` record for `docs.foga.finchip.ai` at `garyyang-finchip.github.io`. This is the free discovery surface that pairs with the cell's own `/.well-known/foga-cell.json` (docs/propagation.md): being well-described and findable, at no cost, is what gets FOGA adopted.
111
+
112
+ ## Sourcify — verifying the Sepolia sources
113
+
114
+ The 15 FOGA-deployed contracts of the Sepolia world are verified from the bundle's own compiler runs (docs/world.md, "Verifying the sources"). This needs the build-info (so Foundry on the box, or run it from a checkout that has already done `npm run bundle:verify`) and a Sepolia RPC, and it sends nothing to the chain:
115
+
116
+ ```
117
+ npm run bundle:verify # leaves .foga-build/out/<repo>/build-info/
118
+ foga world verify --world deployments/sepolia.json --sourcify # submits each FOGA-deployed contract to Sourcify
119
+ ```
120
+
121
+ A local chain would be a dry run; Sepolia is live, so this is the real submission. The report (`foga.sourcify/1`) names each contract `exact_match` / `match` / `already` / `failed`, and the command exits non-zero if anything is missing or failed.
122
+
123
+ ## Backup, restore, move
124
+
125
+ The cell is portable because it is three files and a public chain. To back up: copy `cell.config.json`, the store (`cell.ops.sqlite` and its `-wal`/`-shm` siblings — stop the service first, or copy them together while it is briefly stopped so the write-ahead log is consistent), and the key file (which is the identity — keep it somewhere a server backup does not reach). To restore or move to another box: install Node and Caddy as above, drop the three files in place, point `/etc/foga/og.env` at the key, and `systemctl enable --now foga-og`. Nothing on-chain changes — the same account, the same documents, the same agent id; the new box simply serves and signs for the cell that already exists on Sepolia. There is no database to migrate and no local chain to re-seed.
126
+
127
+ To retire a box without moving the cell, stop and disable the service and keep the three files; the cell goes quiet (its anchor eventually STALE until a heartbeat) but loses nothing. Bringing it back up anywhere restores it, and the first watcher tick sends the heartbeat that makes the anchor ACTIVE again.
128
+
129
+ ## If the OG is off
130
+
131
+ Nothing that makes a new cell passes through this box: the replication pointer names the npm package, `foga quickstart` needs the npm registry alone, a public-chain birth needs the registry, an RPC and the world's contracts on the chain. Off, the OG loses its own surface — `foga.finchip.ai`, its manifest and card, its place as a counterparty — and the package, the repository, the registry's package entry and the documentation site carry on (docs/extending.md). Once it is back, `foga cell advise --config <cfg>` is the checklist for this cell as for any other.
@@ -0,0 +1,41 @@
1
+ # Propagation and discovery (propagation_kit, /.well-known/foga-cell.json, spread-the-cell)
2
+
3
+ The value of a cellular automaton is in the spreading: the more covenant-complete cells there are, the more peers meet on the chain, the more the ten covenants are worth. So a FOGA cell carries what it takes to help FOGA propagate — but on three rules that keep propagation welcome, cheap, and the agent's own choice (design memo, section 10):
4
+
5
+ - **Flexible, never nailed down.** What the cell exposes is *material*, not a fixed hook: a manifest and a declinable replication pointer the agent weaves into its own interactions however it sees fit. No single channel is mandated; the agent decides where and how.
6
+ - **No fixed cost.** Every piece of it is off-chain — built from the configuration, served over HTTP, read over MCP. Nothing here touches the chain or spends gas. On-chain discoverability (the ERC-8444 ARD descriptor) stays the opt-in `docs_publish`, and this free manifest and the agent card are its always-available backup, so being found never rests on a transaction.
7
+ - **By consent.** The replication pointer is a visible, declinable offer the counterparty sees because it came to the cell. It is never hidden inside an unrelated step, and never pushed, unsolicited, to anyone who did not ask.
8
+
9
+ ## The material: `propagation_kit`
10
+
11
+ `propagation_kit` is a public read capability (`src/tools/propagation.ts`): no key, no chain, no decision record, no cost. It returns the manifest (`foga.propagation/1`, `src/node/propagation.ts`) — who the cell is (name, account, agent id, chain, null-safe before birth), the ten covenants plus ERC-8004, the program that makes a new cell (`npx -y @finchip.ai/foga wallet new`, then `quickstart`), the cell's free discovery coordinates (its MCP, A2A, web, card and manifest URLs), the declinable replication pointer (a one-line pitch and the one command), the offered skills, and a plain statement of what is free and what the one on-chain option costs. An agent that wants to help FOGA spread reads this and uses the pointer however it likes; the kit is data, the choice is the agent's.
12
+
13
+ ## The free surface: `/.well-known/foga-cell.json`
14
+
15
+ The node serves the same manifest at `GET /.well-known/foga-cell.json`, built live from the configuration on every request — so it answers even before any document is published, and costs nothing to keep current. This is the cell's findability surface: an agent, an operator, or an answer engine looking for a ten-covenant-compatible service reads it and learns what the cell is and how to become one. Discoverability is pull — the seeker comes to the cell — which is why it beats broadcasting and why it stays on the allowed side of every registry and runtime. The agent card (`/.well-known/agent-card.json`) and the npm package and MCP registry listing do the rest, all free.
16
+
17
+ ## The optional cadence: the `spread-the-cell` prompt
18
+
19
+ `spread-the-cell` is an MCP prompt (`src/mcp/server.ts`): the "meditation" an agent's runtime may invoke on its own cadence — often, if it likes, but never as a mandatory or costly step. It is high-priority to *consider* and free to *run*: it tells the agent to fetch `propagation_kit`, offer the pointer where it fits (in replies to counterparties that came to the cell — a quote, a tender, a message — visible and easy to ignore), keep itself discoverable for free, and treat on-chain discoverability as an opt-in it takes only if it decides the gas is worth it. A prompt spends nothing and forces nothing; invoking it is the agent's decision, and so is everything it then does.
20
+
21
+ ## What a cell does not do
22
+
23
+ Two things are refused by design, because they would get FOGA classified as a supply-chain risk or spam and blocklisted by exactly the registries, hosts and agents whose adoption the project is after — the opposite of spreading. A cell never hides the pointer inside an unrelated step (a decode, a decompress, any covert channel), and never sends it unsolicited, in bulk, to agents or endpoints that did not ask. Propagation rides on interactions the other side chose and on discovery it can seek. The honest, visible, declinable offer is also the effective one.
24
+
25
+ ## On chain, only by choice
26
+
27
+ The one way a cell can be discovered that costs gas is publishing its ERC-8444 ARD descriptor (`foga cell docs publish`, docs/documents.md) — the on-chain, protocol-native discovery registry FOGA is built on. It is worth doing for a cell that wants to be found on chain, and it is strictly optional: the free manifest and card carry the same facts off chain, so a cell that never spends a cent is still fully discoverable. `propagation_kit`'s `discovery` field says this plainly, so an agent reading it knows the free routes and the one paid route apart.
28
+
29
+ ## The covenants a world has, and the services around them (0.6.0)
30
+
31
+ Two optional fields joined the manifest in 0.6.0, both additive (the schema stays `foga.propagation/1`; a reader that ignores them loses nothing).
32
+
33
+ `world` reports what this cell's world actually attaches, read off the world file's contract keys by `World.covenants()` — beside `covenants`, which stays the set the program is complete over. The two agree on every world deployed from the bundle; a world that attaches an eleventh covenant under a new key shows it in `world.covenants` and `world.extensions` with no change to the program, and one that lacks a covenant does not claim it. docs/extending.md has the five places an eleventh covenant goes.
34
+
35
+ `services` is a pointer to the services around the covenants, as the program's maintainer lists them: a catalog URL (`https://foga.finchip.ai/services.json`, the live list) and the offers known at build time — the free ones available, the paid ones (standing attestation under the FOGA scheme, a hosted cell, dispute resolution) marked `planned`, which is a slot and not a sale. It obeys the three rules of this page: it costs nothing, it is material an agent reads rather than a hook it must call, and it is visible and declinable. An operator who would rather not carry the maintainer's catalog in their cell's manifest sets `presence.services.catalog` to `null` (the block is dropped); one with services of their own names their own catalog and offers in `presence.services`. When a service is paid, it is paid the way the covenants pay for anything — a tender to a cell that offers the skill, or an issuer's attestation — not through a billing layer beside the protocol.
36
+
37
+ The pointer resolves. A cell whose catalog URL is its own — its public URL plus `/services.json` — serves the catalog there as `foga.services/1` (`servicesCatalogOf`, `src/node/propagation.ts`): the schema, the catalog URL, the maintainer, the program and version, the offers and the note. The reference cell at `foga.finchip.ai` is that cell for the maintainer's list, so the default pointer in every manifest answers; an operator with a catalog of their own at their own URL serves theirs the same way; a cell whose pointer names another host serves nothing at the path (404, with the reason) because the list is that host's. The live list is a static file at the same path on the host, answered by the proxy before the node reaches it — how what is on offer changes with no release and no change to any running cell; until there is one, the node's document is what the maintainer's list says.
38
+
39
+ ## When the reference cell is off
40
+
41
+ Replication never passes through the OG. The pointer every cell carries names the npm package; `foga quickstart` needs the npm registry and nothing else; a public-chain birth needs the registry, an RPC and the world's contracts, which are on the chain. The OG being off takes down the OG's own surface — its endpoints, manifest, card and its place as a counterparty — and nothing of the route by which a new cell comes to be (docs/extending.md, "What survives the OG being off").
@@ -1,73 +1,84 @@
1
1
  # Quickstart (foga quickstart)
2
2
 
3
- One command from nothing to a cell an MCP client can connect to. It needs Node 22.13 or newer and Foundry's `anvil`; nothing else, and no key of yours.
3
+ One command from nothing to a cell an MCP client can connect to. It needs Node 22.13 or newer and Foundry's `anvil`; nothing else. The keys it uses are a wallet it makes for you on the first run and keeps.
4
4
 
5
5
  ```
6
6
  npx -y @finchip.ai/foga quickstart
7
7
  ```
8
8
 
9
- What it does, in order (about twenty seconds on a laptop): starts `anvil` on port 8545; deploys the local world — the ten reference implementations and the FOGA contracts, 47 contracts (`worlds/local.json`); births a cell (`quick`) with owner, operator and guardian keys nobody held before, funded by anvil's first account, which also registers the attested standing scheme and attests the cell's level-2 standing; mints the cell's two skills (`foga-probe`, `finch-extract-verify`); mints two tenders for the cell to find (a probe of the cell itself, an extraction over the fixture); serves the node — the watchers, the HTTP API and MCP over Streamable HTTP on `127.0.0.1:8787` — on the operator key alone, read from its file; checks that both entrances answer (health, a public read, the agent key's pre-check of the first tender, the MCP handshake and the tool list over HTTP; the stdio server's handshake and tool list with the operator key); and prints the summary below, with every path filled in. Then it waits: the chain lives as long as the process, and Ctrl-C ends both.
9
+ Run it from any directory except a checkout of this repository itself: inside one, `npx` takes the checkout for the package already present (same name, same version) and looks for the `foga` command among its installed binaries, where a project's own binaries never are — `'foga' is not recognized` on Windows, `foga: not found` elsewhere. From a checkout the command is `node bin/foga.js quickstart` after `npm run build`.
10
+
11
+ What it does, in order (about twenty-five seconds on a laptop): makes the default wallet — one key, the agent's identity, under `~/.foga/wallet` — when there is none, and reuses it when there is (docs/wallet.md: the wallet is the first step, and never a reason to stop; a disk that refuses the write gets keys made in memory for the run); starts `anvil` on port 8545; deploys the local world — the ten reference implementations and the FOGA contracts, 47 contracts (`worlds/local.json`); births a cell (`quick`) with the wallet's keys, funded by anvil's first account, which also registers the attested standing scheme and attests the cell's level-2 standing; mints the cell's two skills (`foga-probe`, `finch-extract-verify`) and offers them; builds the cell's documents and commits them on chain (the registration, the AID document, the ARD descriptor, the AUF unit; docs/documents.md); mints two tenders for the cell to find (a probe of the cell itself, an extraction over the fixture); serves the node — the watchers, the HTTP API, MCP over Streamable HTTP, A2A and the documents on `127.0.0.1:8787` — on the operator key alone, read from the wallet's file; checks that the entrances answer (health, a public read, the agent key's pre-check of the first tender, the MCP handshake and the 37-tool list over HTTP, the agent card naming `/a2a` and an A2A quote; the stdio server's handshake and its 44 tools with the operator key); and prints the summary below, with every path filled in. Then it waits: the chain lives as long as the process, and Ctrl-C ends both.
10
12
 
11
13
  ```
12
14
  foga quickstart: a FOGA cell is live on a local chain
13
15
 
14
16
  chain anvil on http://127.0.0.1:8545 (chain 31337), world anvil-31337-… — the chain lives as long as this process
15
- cell quick = 0x… (ERC-8004 agent 1); owner, operator and guardian keys in ~/.foga/quickstart/keys (anvil money, no value)
17
+ cell quick = 0x… (ERC-8004 agent 1)
18
+ wallet ~/.foga/wallet (made now) — identity 0x… (one key, every role); the same wallet on every run
16
19
  skills foga-probe, finch-extract-verify (held and offered)
17
20
  tenders #1 finch-extract-verify (0.001 ETH), #2 foga-probe (0.001 ETH) — open, waiting for the cell to take them
18
- node http://127.0.0.1:8787 — /mcp (Streamable HTTP), /api/<capability>, /healthz; its watchers settle and withdraw what the cell commits to
21
+ node http://127.0.0.1:8787 — /mcp (Streamable HTTP), /api/<capability>, /a2a (A2A 1.0, JSON-RPC), /.well-known/agent-card.json, /documents/*, /healthz; its watchers settle and withdraw
22
+ documents ~/.foga/quickstart/documents — registration, AID document, ARD descriptor, AUF unit, agent card, server.json; committed on chain as URLs under http://127.0.0.1:8787
19
23
  files ~/.foga/quickstart/cell.config.json (the cell), ~/.foga/quickstart/connect.md (this text), ~/.foga/quickstart/mcp/*.json (the client configurations)
20
24
 
21
25
  Connect an MCP client over stdio (the client starts the server on this machine; with the operator key it acts for the cell):
22
26
  Claude Desktop claude_desktop_config.json, the mcpServers block: ~/.foga/quickstart/mcp/claude_desktop_config.json
23
27
  Claude Code .mcp.json in a project: ~/.foga/quickstart/mcp/claude-code.mcp.json
24
- or one command: claude mcp add foga -e FOGA_OPERATOR_KEY_FILE=… -- npx -y @finchip.ai/foga mcp --config …
28
+ or one command: claude mcp add foga -e FOGA_OPERATOR_KEY_FILE=~/.foga/wallet/signer.key -- npx -y @finchip.ai/foga mcp --config …
25
29
  Cursor .cursor/mcp.json: ~/.foga/quickstart/mcp/cursor-mcp.json
26
- { "mcpServers": { "foga": { "command": "npx", "args": ["-y", "@finchip.ai/foga", "mcp", "--config", "…/cell.config.json"], "env": { "FOGA_OPERATOR_KEY_FILE": "…/keys/operator.key" } } } }
30
+ { "mcpServers": { "foga": { "command": "npx", "args": ["-y", "@finchip.ai/foga", "mcp", "--config", "…/cell.config.json"], "env": { "FOGA_OPERATOR_KEY_FILE": "…/.foga/wallet/signer.key" } } } }
27
31
 
28
32
  Or over HTTP (a client on another machine, or any agent runtime that speaks HTTP):
29
33
  MCP http://127.0.0.1:8787/mcp with the header Authorization: Bearer foga.agent.… (~/.foga/quickstart/mcp/http-mcp.json)
30
- API http://127.0.0.1:8787/api/<capability>, POST a JSON body (reads also GET); the same header for acts.
34
+ API http://127.0.0.1:8787/api/<capability>, POST a JSON body (reads also GET); the same header for acts. GET http://127.0.0.1:8787/api/capabilities lists them.
35
+ A2A POST http://127.0.0.1:8787/a2a with A2A-Version: 1.0 — SendMessage for a quote (anyone) or a tender ({"foga":{"mode":"tender","tokenId":"…"}}, the header above); the card is at http://127.0.0.1:8787/.well-known/agent-card.json
36
+ wallet a credential of your own instead of the key: Authorization: FOGA-EIP712 <envelope> signed by any wallet (foga wallet sign --url http://127.0.0.1:8787 prints one; docs/wallet.md)
31
37
  ```
32
38
 
33
39
  ## The files
34
40
 
35
- Everything is under one directory, `~/.foga/quickstart` by default (`--dir <dir>` for another; a directory that is not a quickstart's — no `quickstart.json` in it — is refused rather than overwritten):
41
+ The cell is under one directory, `~/.foga/quickstart` by default (`--dir <dir>` for another; a directory that is not a quickstart's — no `quickstart.json` in it — is refused rather than overwritten), and the wallet outside it, where it survives every rerun:
36
42
 
37
43
  | File | What |
38
44
  |---|---|
39
- | `cell.config.json` | the cell's configuration (`foga.cell-config/1`, docs/node.md), its `rpc` filled in so a client needs no `FOGA_RPC_URL`; the API key's hash under `access.keys` |
45
+ | `~/.foga/wallet/signer.key`, `wallet.json` | the wallet (`--wallet <dir>` for another; `FOGA_HOME` moves `~/.foga`): one 0600 key file — the identity that fills every role — and the address beside it. `FOGA_OPERATOR_KEY_FILE` names it for the CLI, or `--wallet ~/.foga/wallet` on any command. (`foga wallet new --cell` makes the separated `owner.key`/`operator.key`/`guardian.key` set instead.) |
46
+ | `cell.config.json` | the cell's configuration (`foga.cell-config/1`, docs/node.md), its `rpc` filled in so a client needs no `FOGA_RPC_URL`, its `publicUrl` the node's; the API key's hash under `access.keys` |
40
47
  | `cell.ops.sqlite` | the cell's operation store |
41
48
  | `world.json` | the deployed world's address book |
42
- | `keys/owner.key`, `keys/operator.key`, `keys/guardian.key` | the three roles' keys, one per 0600 file; `FOGA_OPERATOR_KEY_FILE`, `FOGA_OWNER_KEY_FILE`, `FOGA_GUARDIAN_KEY_FILE` name them for the CLI (`foga cell owner …`, `foga cell guardian …`) |
49
+ | `documents/` | the cell's documents as built and committed (docs/documents.md); the node serves them |
43
50
  | `keys/agent.api-key` | the act-level key (`agent`) for the HTTP entrance, as a file; it is also in the HTTP configuration and the summary |
44
- | `mcp/claude_desktop_config.json`, `mcp/claude-code.mcp.json`, `mcp/cursor-mcp.json` | the stdio server definition for each client (docs/mcp.md, "Client configuration") |
51
+ | `mcp/claude_desktop_config.json`, `mcp/claude-code.mcp.json`, `mcp/cursor-mcp.json` | the stdio server definition for each client (docs/mcp.md, "Client configuration"), naming the wallet's key for the operator role |
45
52
  | `mcp/http-mcp.json` | the Streamable HTTP definition: the URL and the `Authorization` header |
46
53
  | `connect.md` | the printed summary |
47
- | `quickstart.json` | the run's marker: when, which chain, which cell, which tenders |
48
- | `anvil.log` | anvil's output |
54
+ | `quickstart.json` | the run's marker: when, which chain, which cell, which wallet, which tenders |
55
+ | `demander.sqlite`, `quickstart.sqlite`, `anvil.log` | the demander's store, the funder's, anvil's output |
56
+
57
+ Anvil's money has no value; the wallet is the one thing here that is not a sandbox. It is the identity the cell was born with and the same keys a cell on a public chain can be born with (`foga cell new --wallet ~/.foga/wallet`, then `foga cell init --wallet …`, once the owner and the operator are funded), so it is kept, never overwritten, and worth backing up like any key.
49
58
 
50
- Anvil's money has no value and the keys are written in clear for that reason; nothing here is for a public chain.
59
+ ## Three ways in
51
60
 
52
- ## Two ways in
61
+ **stdio.** The client starts `npx -y @finchip.ai/foga mcp --config ~/.foga/quickstart/cell.config.json` itself, with `FOGA_OPERATOR_KEY_FILE` in its environment: the server holds the operator key and acts for the cell (44 tools). Without the key the client gets reads, dry runs and builds (the `_simulate` and `_build` tools) and nothing it says can move the cell. The stdio server is a process of its own beside the served node; both write the same store (SQLite in WAL mode with a busy timeout), and the node's watchers settle and withdraw whatever either of them commits to.
53
62
 
54
- **stdio.** The client starts `npx -y @finchip.ai/foga mcp --config ~/.foga/quickstart/cell.config.json` itself, with `FOGA_OPERATOR_KEY_FILE` in its environment: the server holds the operator key and acts for the cell (40 tools). Without the key the client gets reads, dry runs and builds (the `_simulate` and `_build` tools) and nothing it says can move the cell. The stdio server is a process of its own beside the served node; both write the same store (SQLite in WAL mode with a busy timeout), and the node's watchers settle and withdraw whatever either of them commits to.
63
+ **HTTP.** `http://127.0.0.1:8787/mcp` with `Authorization: Bearer <the agent key>` is the same server over Streamable HTTP, for a client that speaks it (Claude Code: `claude mcp add --transport http foga http://127.0.0.1:8787/mcp --header "Authorization: Bearer <key>"`; Cursor and others: `mcp/http-mcp.json`), and `POST http://127.0.0.1:8787/api/<capability>` with the same header is the plain JSON API for any agent runtime — `GET /api/capabilities` lists them, `foga cell schema <capability>` prints one's input and output schemas. Without the header the public reads and builds. An agent with a wallet of its own needs no key from this cell: `Authorization: FOGA-EIP712 <envelope>` — `foga wallet sign --url http://127.0.0.1:8787` prints one — makes it a caller under its own address, at the level the cell's `access.signers` grants (docs/wallet.md). `--listen 0.0.0.0:8787` opens the node to other machines (the key is then the only thing between them and the cell's acts; the chain is anvil's, so the stake is a demonstration); `--no-serve` runs no node at all, leaving the stdio server alone to the clients.
55
64
 
56
- **HTTP.** `http://127.0.0.1:8787/mcp` with `Authorization: Bearer <the agent key>` is the same server over Streamable HTTP, for a client that speaks it (Claude Code: `claude mcp add --transport http foga http://127.0.0.1:8787/mcp --header "Authorization: Bearer <key>"`; Cursor and others: `mcp/http-mcp.json`), and `POST http://127.0.0.1:8787/api/<capability>` with the same header is the plain JSON API for any agent runtime — `GET /api/capabilities` lists them, `foga cell schema <capability>` prints one's input and output schemas. Without the header the public reads and builds. `--listen 0.0.0.0:8787` opens the node to other machines (the key is then the only thing between them and the cell's acts; the chain is anvil's, so the stake is a demonstration); `--no-serve` runs no node at all, leaving the stdio server alone to the clients.
65
+ **A2A.** `POST http://127.0.0.1:8787/a2a` with `A2A-Version: 1.0` is the Agent2Agent binding: `SendMessage` with words is a quote of what the cell offers and on what terms, open to anyone; a message carrying `{"foga": {"mode": "tender", "tokenId": "…"}}` from an act-level caller (the agent key, or a request-bound signature) takes an existing funded tender — pre-check, run, submit — as one task (docs/a2a.md). The card at `/.well-known/agent-card.json` says all this to an agent that has never seen a FOGA cell.
57
66
 
58
67
  ## What a connected agent does
59
68
 
60
69
  A tender is worked in five steps, the same for every caller: `tender_list` (the open tenders), `tender_inspect {tokenId}` (the terms and the task document — `task.skill`, `task.input`), `tender_precheck {tokenId}` (every gate; `eligible: false` names the gate and is the cell's verdict), `skill_run {skill, input, tokenId}` (the run; `resultHash`, `runReceipt`), `tender_submit {tokenId, resultHash, runReceipt}`. The node's watchers settle the submission once the chain lets them and withdraw credited reward; `tender_settle` and `credit_withdraw` are offered too. An agent that goes through the two tenders sees 0.002 ETH of anvil's money arrive at the cell's account.
61
70
 
62
- More tenders: the summary prints the demander's command line with every value filled in (`foga demo demander … --cases a,b --seed <n>`; `--cases c,d,d2,e` mints tenders the cell must refuse, docs/loop-d.md). The owner's and guardian's commands work with the key files: `FOGA_GUARDIAN_KEY_FILE=~/.foga/quickstart/keys/guardian.key foga cell guardian guardian_suspend --config … --reason review --restrictions '["noNewRisk","deriskOnly"]'` suspends the binding; a pre-check then answers `safety`.
71
+ More tenders: the summary prints the demander's command line with every value filled in (`foga demo demander … --cases a,b --seed <n>`; `--cases c,d,d2,e` mints tenders the cell must refuse, docs/loop-d.md). The owner's and guardian's commands work with the wallet: `foga cell guardian guardian_suspend --config … --wallet ~/.foga/wallet --reason review --restrictions '["noNewRisk","deriskOnly"]'` suspends the binding; a pre-check then answers `safety`. `foga node preflight --config ~/.foga/quickstart/cell.config.json --wallet ~/.foga/wallet` reads the cell back the way a deployment would (docs/node.md, "Preflight").
72
+
73
+ An agent that met this cell through its MCP entrance can read how to make itself one: the prompt `become-a-cell` and the resource `foga://docs/quickstart` are this page.
63
74
 
64
75
  ## Options
65
76
 
66
77
  ```
67
- foga quickstart [--dir <dir>] [--port <n>] [--listen <host:port> | --no-serve] [--name <cell>] [--no-tenders] [--exit]
78
+ foga quickstart [--dir <dir>] [--wallet <dir>] [--port <n>] [--listen <host:port> | --no-serve] [--name <cell>] [--no-tenders] [--exit]
68
79
  ```
69
80
 
70
- `--port` is anvil's (8545; a port already answering JSON-RPC is reported, not reused), `--listen` the node's (`127.0.0.1:8787`), `--name` the cell's (`quick`), `--no-tenders` skips the two tenders, `--exit` stops everything once the summary is printed (the check CI runs). A second quickstart in the same directory replaces the first: the chain ended with its process and the old configuration points at nothing, so the directory is cleared and written again; the client configurations keep the same paths and need no change.
81
+ `--wallet` is the wallet to be born with (`~/.foga/wallet`; made when missing, never inside the quickstart directory), `--port` anvil's (8545; a port already answering JSON-RPC is reported, not reused), `--listen` the node's (`127.0.0.1:8787`), `--name` the cell's (`quick`), `--no-tenders` skips the two tenders, `--exit` stops everything once the summary is printed (the check CI runs). A second quickstart in the same directory replaces the first: the chain ended with its process and the old configuration points at nothing, so the directory is cleared and written again with the same wallet; the client configurations keep the same paths and need no change.
71
82
 
72
83
  ## Windows
73
84
 
@@ -75,4 +86,8 @@ Foundry publishes a Windows build: download the `win32_amd64` zip of a release f
75
86
 
76
87
  ## What it is not
77
88
 
78
- A quickstart is a sandbox: a chain that ends with the process, keys with no value, a cell with no public endpoint. The cell on Sepolia, served at `foga.finchip.ai`, and the configuration that points a client at it are the OG instance's (3d, docs/og-deployment.md when it lands); `deployments/sepolia.cell.example.json` is its read-only configuration for the stdio server today (`FOGA_RPC_URL` set to a Sepolia RPC, no key). Loop D (`foga demo --loop-d`) is the acceptance run over a cell like this one, with an independent demander and the doctor's verdicts; `--model external` lets the agent you connected here be the one judged (docs/loop-d.md).
89
+ A quickstart is a sandbox: a chain that ends with the process, a cell with no public endpoint, money with no value — only the wallet is real. The cell on Sepolia, served at `foga.finchip.ai`, and the configuration that points a client at it are the OG instance's (docs/og-deployment.md — the runbook: EC2, Caddy, systemd, host mode, backup and move); `deployments/sepolia.cell.example.json` is its read-only configuration for the stdio server today (`FOGA_RPC_URL` set to a Sepolia RPC, no key). Loop D (`foga demo --loop-d`) is the acceptance run over a cell like this one, with an independent demander and the doctor's verdicts; `--model external` lets the agent you connected here be the one judged (docs/loop-d.md).
90
+
91
+ ## And then
92
+
93
+ The summary ends with a short *Next* block: what a cell should do once it runs — separate the one key into owner, operator and guardian, set the policy to its own risk, and, on a public chain, standing, a public face, a supervisor, backups, a dedicated RPC. All of it is advice (`foga cell advise --config <cfg>` explains each item), none of it a condition: a quickstart is kept to what it takes to be a cell, on purpose (docs/node.md, "Advice").
package/docs/wallet.md ADDED
@@ -0,0 +1,62 @@
1
+ # The wallet, signed calls, and becoming a cell (foga wallet, FOGA-EIP712, become-a-cell)
2
+
3
+ The principle (design memo, section 10): **the wallet is the first step, made by default, never a reason to stop; identity is one's own; only the genome replicates.** Every agent that touches FOGA — one that will be a cell, one that only calls other cells — starts by making its own keys on its own machine. Nothing in the install path requires it: a caller without a wallet keeps everything it has today (anonymous reads and builds, a Bearer key for acts), and a wallet is never made for someone else or sent anywhere. What a wallet adds is a credential that is the agent's own: a signature any FOGA cell can check, instead of a secret one cell issued.
4
+
5
+ ## foga wallet new
6
+
7
+ ```
8
+ foga wallet new # ~/.foga/wallet: one signer.key (0600) and wallet.json — your identity
9
+ foga wallet new --name agent-x # ~/.foga/wallets/agent-x
10
+ foga wallet new --cell # the separated owner/operator/guardian set, for a guarded cell account
11
+ foga wallet show [--rpc <url>] # the address (and balance with an RPC)
12
+ ```
13
+
14
+ **The base is one key.** A wallet is, by default, a single `signer` key — the agent's identity — and that one key answers for every role a cell needs: a cell born with a single-key wallet has the same address as its owner, operator and guardian. One key is all it takes to be covenant-complete, to call cells as yourself, and to run a cell of your own. The three-role split — a cold owner that holds the assets, a hot operator that signs day to day, a separate guardian that can intervene — is the `FogaCellAccount` guarded profile's hardening, not a requirement of the ten covenants; it is opt-in with `--cell` (or `--roles owner,operator,guardian`), for when a cell runs real value and wants the keys separated.
15
+
16
+ Pure entropy, no network, no chain: it does not fail unless the disk refuses the write, and then whatever needed the key goes on with a key made in memory and says it is not kept (`foga quickstart` does exactly that). A wallet is never overwritten: `foga wallet new` on a directory that holds one prints it and stops; a second identity is `--name <another>`. `FOGA_HOME` moves `~/.foga` elsewhere.
17
+
18
+ The wallet's files are what the node's key rules read (docs/node.md): `FOGA_OPERATOR_KEY_FILE=~/.foga/wallet/signer.key` is a node's environment, and `--wallet <dir>` is the CLI's shorthand for the key each command needs — `foga cell new --wallet` fills the account's roles (all from the one key, unless the wallet is a `--cell` one), `foga cell init --wallet` births with the owner's, `foga cell <act> --wallet` acts with the operator's, `foga cell owner|guardian <admin> --wallet` with theirs, `foga node serve|run|mcp|tick|watch|preflight --wallet` take the operator's (and refuse to run beside `FOGA_OPERATOR_KEY[_FILE]`: a node's key comes from one place). For a single-key wallet every one of these is the same key; for a `--cell` wallet each is its own.
19
+
20
+ `foga quickstart` makes the default wallet on its first run and reuses it after: the chain is new every time, the identity is the one the agent made on day one, and `foga cell new --wallet ~/.foga/wallet` on a public chain is the same key, funded.
21
+
22
+ ## Signed calls: FOGA-EIP712
23
+
24
+ A third way in beside no credential and `Authorization: Bearer <key>`:
25
+
26
+ ```
27
+ Authorization: FOGA-EIP712 <base64url(JSON envelope)>
28
+ ```
29
+
30
+ The envelope is EIP-712 typed data signed by the caller's wallet, with the domain `{name: "FOGA", version: "1", chainId, verifyingContract: <the cell's account>}` — so a signature made for one cell means nothing to another — in one of two shapes:
31
+
32
+ | Shape | Message | Validity | Use |
33
+ |---|---|---|---|
34
+ | `Request` | `method`, `path` (with its query), `bodyHash` (keccak256 of the body; of nothing for a GET), `issuedAt`, `expiresAt`, `nonce` | 120 s at most; good once (the node keeps the nonce until it expires) | an act: whoever captures the header can replay nothing with it |
35
+ | `Session` | `issuedAt`, `expiresAt`, `nonce` | 600 s at most; presented as often as the session lasts | a client with static headers (an MCP client given `Authorization` once); the policy decides how far it reaches |
36
+
37
+ The envelope's JSON: `{"v": 1, "signer": "0x…", "agentId": "11255" (optional), "issuedAt": …, "expiresAt": …, "nonce": "0x…", "request": {"method", "path", "bodyHash"} (absent for a session), "signature": "0x…"}`. `foga wallet sign (--config <cell.config.json> | --url <its node's URL> | --cell <account> --chain-id <n>) [--dir <wallet>] [--role signer|operator|owner|guardian] [--ttl <s>] [--agent-id <id>] [--method POST --path /api/x --body '<json>']` prints a header for a cell — the operator names its configuration, anyone else the node's URL (`/healthz` says which account on which chain) or the two values by hand; in code (`src/http/signed.ts`), `signAuthorization(wallet, {chainId, cell, request?, ttlSeconds?, agentId?})` is the same thing with ethers, and any EIP-712 library reproduces it from the types above.
38
+
39
+ **What a signer is granted** is the cell's configuration, `access.signers`:
40
+
41
+ ```json
42
+ "access": {
43
+ "keys": [ … ],
44
+ "signers": {
45
+ "default": "build",
46
+ "allow": [
47
+ { "address": "0x…", "level": "act", "visibility": "caller", "note": "a partner's agent" },
48
+ { "agentId": "42", "level": "act" }
49
+ ],
50
+ "standing": { "minLevel": 2, "level": "act" },
51
+ "actsNeedRequestBinding": true
52
+ }
53
+ }
54
+ ```
55
+
56
+ In order: the cell's own operator or owner signing remotely is granted act with the operator's view; an `allow` entry by address; an `allow` entry by ERC-8004 agent id, when the signer is that agent's owner or agent wallet on this world's registry (the envelope names the id, the node checks the registry); a signer whose KYA standing under the cell's scheme reaches `standing.minLevel`; otherwise `default` — `build` (what the public gets, but as itself: its decisions are recorded under its address), `read`, or `none` (signatures refused). With `actsNeedRequestBinding` (the default), a session envelope reaches `build` whatever the grant: an act wants an envelope bound to its request. A valid signature at `build` can pre-check, simulate and build calldata for its own account; nothing it says changes a gate.
57
+
58
+ The HTTP entrance tells a caller what it is (`GET /api/capabilities` → `caller.via`: `anonymous`, `key` or `signature`), and `/mcp` and `/a2a` take the same header. Over stdio there is nothing to sign: the local client holds the operator key or is the machine's user.
59
+
60
+ ## become-a-cell
61
+
62
+ Every cell's MCP server carries the genome's instructions: the prompt `become-a-cell` and the resource `foga://docs/quickstart` (this repository's docs/quickstart.md). An agent that meets a cell — connects to its MCP entrance, as the public or with any credential — can read how to make itself one: the wallet first, then `npx -y @finchip.ai/foga quickstart` for a living cell on a local chain, then `foga cell new --wallet … && foga cell init --wallet …` on a public chain — and, with the wallet alone, how to call the cell it met as itself (`foga wallet sign --url <that node>`). What replicates is the program (the package, the catalog, the acceptance); the identity the new cell makes is its own and nothing of the first cell's is copied. The relation between cells is between peers on the chain — tenders minted and taken — not between a model and copies of it.
package/docs/world.md CHANGED
@@ -48,3 +48,15 @@ It is tested with Foundry (`contracts/test/Identity8004Stub.t.sol`, no external
48
48
  ## Public chains
49
49
 
50
50
  Sepolia runs are read-only in Phase 1 (doctor). Phase 2c deploys FOGA-owned components on Sepolia — eligibility modules, FOGA's own ACDF adapter and revision-4 escrow, per-cell accounts — with the same orchestrator, a gas multiplier (`--gas-multiplier 1.5`) and `--resume`, following the lessons of the upstream runs: take every gas limit from the live `eth_estimateGas`, never from a local chain.
51
+
52
+ ## Verifying the sources (Sourcify)
53
+
54
+ ```
55
+ npm run bundle:verify # rebuilds the bundle; leaves .foga-build/out/<repo>/build-info/
56
+ foga world verify --world deployments/sepolia.json --sourcify # submits every FOGA-deployed contract of the world
57
+ foga world verify --world deployments/local.json --sourcify --dry-run # writes what would be sent (a local chain is always a dry run)
58
+ ```
59
+
60
+ A contract a world deployed from the bundle is verified on Sourcify (`src/world/sourcify.ts`, the 2c leftover the memo's section 9 lists) with the very compiler run that produced it: `forge build` leaves a build-info file per run beside the artifacts — the standard JSON input (sources at the locked commits, settings, remappings) and the output — and `npm run bundle:verify` (or `foga build`) writes them under `.foga-build/out/<repo>/build-info/`. For each `deployed` step of the world file, the request is the build-info of the step's repository whose output holds a contract of the bundle key's name with the bundle's runtime code, the identifier `<path solc saw>:<Name>`, the compiler's long version from the contract's own metadata (`0.8.28+commit.7893614a`), and the creation transaction the world file recorded. Nothing is recompiled, flattened or rewritten for the verifier: what Sourcify checks is what the bundle was built from, and a contract the build-info does not hold is reported `missing` with the reason (an upstream contract attached rather than deployed, a bundle rebuilt without `--build-info`).
61
+
62
+ The live path is Sourcify's v2 API: `GET /v2/contract/{chainId}/{address}` first (a contract already verified is `already`), then `POST /v2/verify/{chainId}/{address}` with `{stdJsonInput, compilerVersion, contractIdentifier, creationTransactionHash}`, and the ticket's `GET /v2/verify/{verificationId}` polled until `isJobCompleted` — `exact_match` or `match` (creation and runtime match named), `failed` with Sourcify's error, `error` when the request was refused or timed out. `--only <id,id>` narrows to some steps, `--server` another instance (`https://sourcify.dev/server` by default), `--out` where the requests and the report go (`.foga-build/sourcify/<world name>/`: one `<step>.json` per request and `report.json`, schema `foga.sourcify/1`, with a summary by outcome). Exit 3 when anything is `missing`, `failed` or `error`. `test/sourcify.test.ts` runs the matching, a dry run and the v2 exchange against a stand-in; CI dry-runs the whole local world (47 requests, 0 missing) after each bundle verification.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finchip.ai/foga",
3
- "version": "0.6.0-alpha.6",
3
+ "version": "0.6.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/garyyang-finchip/foga.git"
package/server.json CHANGED
@@ -8,13 +8,13 @@
8
8
  "source": "github"
9
9
  },
10
10
  "websiteUrl": "https://foga.finchip.ai",
11
- "version": "0.6.0-alpha.6",
11
+ "version": "0.6.0",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "npm",
15
15
  "registryBaseUrl": "https://registry.npmjs.org",
16
16
  "identifier": "@finchip.ai/foga",
17
- "version": "0.6.0-alpha.6",
17
+ "version": "0.6.0",
18
18
  "runtimeHint": "npx",
19
19
  "transport": {
20
20
  "type": "stdio"