Getting started
One pass from nothing to an agent signing through serve, first the short path with the install script’s --setup, then each step by hand. It runs everything as your own OS user, which suits testnet: an agent running as you can read the keys (see Isolation before using anything of value). Choosing a setup explains what each setup below can lose.
The short path
scripts/installer/install.sh --setup # install, create the agent token, add the MCP server to Claude Code, install the skill
sfs config init
sfs key new alice-session --class session # or a testnet wallet, as in step 3
Then, as in step 3, add the key’s block and the [[serve.tokens]] block that --setup showed to config.toml, with keys = ["alice-session"], and grant and fund the key. Check it with sfs config show, leave sfs-serve running, and restart Claude Code. Connecting Claude Code says what --setup does and how --uninstall undoes it. The steps below are the same by hand, and the reference for each part: after --setup, skip token new in step 3 and claude mcp add in step 4.
1. Install
scripts/installer/install.sh # from a checkout; see Install and update for other ways
It installs sa-forge-signer, sa-forge-signer-serve, sa-forge-signer-mcp and sa-forge-signer-console into ~/.local/bin and links sfs, sfs-serve, sfs-mcp and sfs-console to them (Install and update). The commands below use sfs.
2. Create the config
sfs config init # writes ~/.config/sa-forge-signer/config.toml, with no keys yet
sfs config show
Keys go in ~/.config/sa-forge-signer/keys/ and the audit log in ~/.config/sa-forge-signer/state/ (see Configuration).
3. Add a key and a token
Pick one setup. Each ends with the whole block to add to config.toml; everything else in the file can stay as config init wrote it.
Testnet: the agent holds a throwaway wallet
The agent’s wallet is the profile authority and signs everything through serve, unattended. Use this only for a testnet burner: anything that controls the agent can sign as the profile authority.
sfs key new alice-wallet --class wallet # or, for a keypair file you have:
sfs key import alice-wallet --class wallet --from ~/path/to/keypair.json
sfs token new agent --out ~/.config/sa-forge-signer/agent.token
Fund the wallet with testnet ZINK: it pays the fees. Then add:
[keys.alice-wallet]
class = "wallet"
pubkey = "<pubkey printed by key new or key import>"
approval = "auto" # sign without a person at a terminal
allow_unattended = true # lets a wallet key be "auto" and sit on a serve token; throwaway testnet keys only
[serve]
[[serve.tokens]]
name = "agent"
sha256 = "<hash printed by token new>"
keys = ["alice-wallet"]
Both extra lines are needed. A wallet key defaults to approval = "confirm", which asks on the terminal running serve for every signature and refuses when there is none. And the config refuses to load a wallet key that is auto or on a token without allow_unattended = true: the signer cannot see what a profile grant gives away.
Recommended: you hold the wallet (Path B)
Your own wallet stays outside the signer and grants the agent a narrow, expiring session key.
sfs key new alice-session --class session
sfs token new agent --out ~/.config/sa-forge-signer/agent.token
Grant the key on your profile with forge-mcp build_add_profile_key (the narrowest permission mask and a short expiry), signed by your wallet, and send it a small amount of ZINK for fees (Key lifecycle). Then add:
[keys.alice-session]
class = "session"
pubkey = "<pubkey printed by key new>"
[serve]
[[serve.tokens]]
name = "agent"
sha256 = "<hash printed by token new>"
keys = ["alice-session"]
A session key defaults to approval = "auto", so nothing else is needed.
Path A as Choosing a setup describes it combines the two: the wallet key stays on confirm and off the token, and you add a session key as above, granted and funded by the wallet through sfs sign --key alice-wallet at a terminal.
4. Check, run and connect
sfs config show
For the testnet setup it ends like this (the session setup shows class: session, approval: auto and no allow_unattended line):
[keys.alice-wallet]
pubkey: 6YAf723681zcJjFrd9UDJCtymiTGov8FL9Ed6XvA2evw
class: wallet
approval: auto
key file: present
profile: -
rate limit: 30 per minute
daily cap: 50000000 lamports (0.05 ZINK)
transfer_to: -
extra_programs: -
allow_unattended: true (throwaway testnet keys only)
[serve]
listen: 127.0.0.1:8790
allowed_hosts: 127.0.0.1, localhost
token: agent (keys: alice-wallet)
key file: missing means the key is in the config but not in the key directory. The daily cap and rate limit are the defaults; raise them per key if the agent hits them (Configuration).
sfs-serve # leave it running; 127.0.0.1:8790
claude mcp add --transport http sa-forge-signer http://127.0.0.1:8790/mcp \
--header "Authorization: Bearer $(cat ~/.config/sa-forge-signer/agent.token)"
The agent passes each forge-mcp build_* payload to the check tool, then sign (Serving over HTTP and MCP). To watch it, run sfs-console in another window (Console).