# Code map

## Repository

| Path | Holds |
|---|---|
| `src/` | The signer: one crate, a library and the binaries built on it, mapped module by module below |
| `tables/` | The instruction table per cluster (`zink-testnet.json`), generated by `apps/idl-table` from the programs' IDLs, which are not checked in ([IDL table](../apps/idl-table.md)). Not part of the crate yet |
| `config.example.toml` | The annotated example config, embedded in the binary and written by `config init` |
| `skills/sa-forge-signer/` | The skill that teaches an agent to use the MCP tools (`SKILL.md` and `references/tools.md`), embedded in the binaries, served as MCP resources and written by `sa-forge-signer-mcp skill install` ([Resources and the skill](../serve.md#resources-and-the-skill)) |
| `apps/` | Extras a human runs beside the signer, each its own crate and workspace, kept out of the signer's build ([Building an app](apps.md)): `apps/console/`, `apps/grant/` and `apps/idl-table/` |
| `docs/` | This book (choices about the signer's shape are in [Design decisions](design.md)): `docs/src/` for chapters, `docs/src/dev/` for working on the signer, `docs/src/apps/` for the apps ([Writing the docs](writing-docs.md)) |
| `.mcp.json`, `scripts/dev/` | A Claude Code session's link to the debug build: the `sa-forge-signer-debug` MCP server, and the script behind `just mcp-dev` that runs the debug service on a throwaway home in `target/dev` ([Contributing](contributing.md)) |
| `justfile` | Recipes: `just check` (the gate), plus the `docs` and `apps` modules in `docs/justfile` and `apps/justfile` (`just docs check`, `just apps console`) |
| `scripts/ci/` | `check.sh` (the gate run by `just check` and CI), `crate-age.sh` (dependency age), `docs-check.sh` (`just docs check`), `docker-toolchain.sh` (the Dockerfile's Rust matches `rust-toolchain.toml`) |
| `scripts/installer/` | `install.sh`: installs, updates or uninstalls the signer and the console on a host ([Install and update](../install.md)) |
| `scripts/skills/` | `gpui-kit.sh`: installs GPUI Kit's Claude skills at the console's `gpui-kit` version ([GPUI Kit skills](../appendix/gpui-kit-skills.md)) |
| `scripts/git-review/` | The local review workflow, `just mr-open` to `just mr-approve` ([Local review with git-review](../appendix/git-review.md)) |
| `.github/workflows/` | `ci.yml` (the gate and a Docker build), `pages.yml` (publishes this book), `release-plz.yml` (release PRs and tags), `release-binaries.yml` (attested binaries for each tag) |
| `Dockerfile` | The container image ([Running in Docker](../docker.md)) |
| `PLAN.md`, `CHANGELOG.md`, `CONTRIBUTING.md`, `SECURITY.md` | Included in this book as [Plan](plan.md), [Changelog](changelog.md), [Contributing](contributing.md) and [Security](../security.md) |

## Modules

One crate: a library (`lib.rs`, not a public API) that each binary calls into. Each module's `//!` comment is the authority if this page drifts.

| Module | Owns |
|---|---|
| `main.rs` | The `sa-forge-signer` binary: only calls `cli::main` |
| `cli.rs` | The CLI (`check`, `sign`, `halt`, `resume`, `key`, `token`, `audit`, `config`) and exit codes |
| `bin/serve.rs` | The `sa-forge-signer-serve` binary: only calls `serve_cli::main` |
| `serve_cli.rs` | `sa-forge-signer-serve`'s command line (`--config`) |
| `bin/mcp.rs` | The `sa-forge-signer-mcp` binary: only calls `mcp_cli::main` |
| `mcp_cli.rs` | `sa-forge-signer-mcp`: MCP on standard input and output, forwarded to a running service's `/mcp` with a bearer token; reads no key or config. Also `skill print` and `skill install` |
| `config.rs` | Loading and validating `config.toml`: keys, classes, approval, limits, serve tokens, each key's policy digest; `config init` and `config show` |
| `cluster.rs` | Built-in cluster profiles: genesis hash, default RPC, explorer, and the programs any key may call |
| `payload.rs` | The forge-mcp `build_*` payload (version 1): an instruction list, not a serialized transaction |
| `transfer.rs` | Funding payloads: a plain System Program transfer in the same shape forge-mcp returns |
| `checks.rs` | Structural checks on the compiled message; none decode game instructions |
| `policy.rs` | Every check `check` and `sign` make, as one pure `evaluate` over the request, the key's policy and `Facts`, at a stage (`Check`, `BeforeSimulation`, `AfterSimulation`); returns every result in order. New checks go here |
| `instruction_table.rs` | The hash-checked instruction table from `apps/idl-table`, and its findings (`instructions`, `accounts`, `profile`) on a compiled message, without decoding anything |
| `facts.rs` | The reads behind `evaluate`: the halt, the approved policy, the key's usage from the audit log, and the RPC facts, read one at a time in check order |
| `engine/mod.rs` | The check and sign pipeline and its report: gather facts and evaluate, simulate, the cap gate, the intent, in that order |
| `engine/fresh.rs` | The gates that may rebuild the transaction with a fresh blockhash: approval, the stale-blockhash guard and the duplicate guard |
| `engine/approval.rs` | The `confirm` prompt at the controlling terminal |
| `engine/send.rs` | Sending, and polling until the outcome is proven or `unknown` |
| `engine/tests.rs` | The pipeline's tests, in one file because they share its fakes |
| `rpc.rs` | The minimal Solana JSON-RPC client: only the calls the signer needs |
| `keystore.rs` | The file key store: `<key_dir>/<name>.json`, 0700 directory, 0600 files; key create, import and destroy |
| `audit.rs` | The append-only, hash-chained JSONL audit log, read back from the end for the checks (`recent`, `walk_back`), and the per-key signing lock |
| `halt.rs` | Halts under `state_dir/halts/`: setting one, `resume` at the terminal, and the `halt_after_unknown` trip |
| `policy_approval.rs` | Policy approvals under `state_dir/policy/`: `key approve` at the terminal, and the `policy` refusal |
| `trace.rs` | Opt-in tracing on stderr from `SA_FORGE_SIGNER_LOG`: the subscriber, and what spans may never carry |
| `bench.rs` | Test-only: `just bench`, timings of the audit log's reads on synthetic logs |
| `serve/mod.rs` | `serve`: the listener and its drain on shutdown, JSON over HTTP at `/v1/check`, `/v1/sign` and `/v1/halt`, bearer-token auth, and the Host and Origin check |
| `serve/mcp.rs` | MCP at `/mcp`, revision `2026-07-28`: the JSON-RPC handler, `server/discover`, the tools `check`, `sign`, `key_show` and `halt`, and the resources ([MCP conformance](mcp-conformance.md)) |
| `serve/mcp_sdk_tests.rs` | Tests only: the handler's messages read back with the Rust MCP SDK's types |
| `mcp_wire.rs` | What the service and the stdio relay share of that revision: its `_meta` keys, header names and error codes, and how a header value mirrors the body |
| `skill.rs` | The agent skill built in from `skills/sa-forge-signer/`: the `llms.txt` and `llms-full.txt` texts made from it, and `skill install` |
| `url.rs` | URL rules shared by the config, the service and the stdio proxy: https, or http only to a loopback host |
| `text.rs` | Caller text (`summary`, `intent`, a halt `reason`): escaped and capped for a terminal, clipped for the audit log |

Checks and gates: `just check` runs `scripts/ci/check.sh` (fmt, clippy, tests, shellcheck, advisories, dependency age), the same gate as CI.
