Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Install and update

Not published on crates.io: install from GitHub, pinned to a release tag (vX.Y.Z). Unix only (macOS, Linux).

Install script

scripts/installer/install.sh installs or updates the signer and the console on the host it runs on, into ~/.local/bin by default. The signer is three binaries from one release: sa-forge-signer, the command line, sa-forge-signer-serve, the service, and sa-forge-signer-mcp, the stdio relay an MCP client starts. It downloads the prebuilt signer for the host and verifies it as below (the attestation needs gh), or builds it from the tag with cargo when there is no prebuilt binary for the host. It builds the console with cargo from the same tag, and skips it for a tag that does not include it. It also links sfs to sa-forge-signer, sfs-serve to sa-forge-signer-serve, sfs-mcp to sa-forge-signer-mcp and sfs-console to sa-forge-signer-console in the same directory (--no-alias skips them), and never replaces an existing file or link of those names. Run it again to update: it skips a signer that is already at that version.

# From a checkout, or download the script from the tag you want and read it first
scripts/installer/install.sh                    # the latest tag
scripts/installer/install.sh --tag vX.Y.Z --no-console
scripts/installer/install.sh --from-checkout    # build both from this checkout's working tree, not a release
scripts/installer/install.sh --setup            # then connect Claude Code, as below
scripts/installer/install.sh --help             # --prefix, --from-source, --console-ref, --skip-attestation, --force

It installs binaries only. The config, keys and audit log stay in ~/.config/sa-forge-signer/ (see Configuration). Nothing about logging is set at install: tracing is switched on per run with SA_FORGE_SIGNER_LOG in the environment of whatever starts the signer, such as your shell, the serve service, a container or an MCP client’s config (Tracing).

--uninstall removes the binaries and their links, and what --setup added, and never touches the config, keys, tokens or audit log. While key files remain it keeps the signer, which key destroy needs, and lists the steps to retire them (see Key lifecycle): revoke each grant, sa-forge-signer key destroy <name>, then remove the config directory. Run it again afterwards, or add --force to remove the signer anyway.

Connecting Claude Code

--setup makes the agent’s side work in one step once the binaries are in place, after a release install or --from-checkout:

scripts/installer/install.sh --setup                  # stdio relay, user scope, with the skill
scripts/installer/install.sh --setup --dry-run        # print the commands, install and change nothing
scripts/installer/install.sh --setup-http --scope project --replace

It does three things, in this order:

  1. Creates the agent’s token file with sa-forge-signer token new agent --out <file> if the file does not exist (--token-file, default agent.token beside the config: ~/.config/sa-forge-signer/agent.token), and shows the [[serve.tokens]] block it prints. It never edits the config or creates a key: add that block to the config yourself, listing in keys the keys the agent may use (a session key, or a wallet key only with allow_unattended = true, for a throwaway testnet key), then restart sa-forge-signer-serve.
  2. Adds the sa-forge-signer MCP server to Claude Code with claude mcp add --scope <scope> (--scope user by default; local and project belong to the current directory). By default that is the stdio relay, sa-forge-signer-mcp --token-file <file>, so Claude Code stores only the token’s path; --setup-http adds the HTTP route with the bearer header instead, which stores the token itself in Claude Code’s config. It refuses when a sa-forge-signer server is already added in another scope, and leaves one in the same scope as it is. --replace replaces it: a server in another scope is removed only after the new one is added, so a failed add keeps it; one in the same scope has to be removed first, so a failed add there leaves none and says to rerun --setup.
  3. Installs the skill with sa-forge-signer-mcp skill install (into the current directory with --scope project); --no-skill skips it.

It records what it added in installer-setup beside the config, and --uninstall removes exactly that: the server, from the scope and directory it was added in, and the skill, only while its SKILL.md still carries the mark skill install writes. Uninstall asks before removing anything (-y skips the question); declining, or no terminal to ask on, removes nothing, binaries included, so the server is never left pointing at removed binaries, and --uninstall --dry-run prints what it would remove.

Run --setup as the agent’s OS user, whose Claude Code it configures. The service still runs as the signer’s user (Isolation) and must be running for any call to answer; when that user’s config directory is not the agent’s, pass --token-file a path the agent can read. Without --setup, the manual steps are in Getting started and Serving over HTTP and MCP.

Prebuilt binary

Each release carries sa-forge-signer-vX.Y.Z-<target>.tar.gz for x86_64-unknown-linux-musl, aarch64-unknown-linux-musl (static, any distribution), aarch64-apple-darwin and x86_64-apple-darwin, a SHA256SUMS file, and a build provenance attestation. The archive holds the three binaries, sa-forge-signer, sa-forge-signer-serve and sa-forge-signer-mcp (an older release holds fewer, and the install script then removes any of the other two left from a newer install). Verify before you run it:

gh release download vX.Y.Z --repo ttdonovan/sa-forge-signer --pattern '*-aarch64-apple-darwin.tar.gz' --pattern SHA256SUMS
shasum -a 256 -c --ignore-missing SHA256SUMS
gh attestation verify sa-forge-signer-vX.Y.Z-aarch64-apple-darwin.tar.gz --repo ttdonovan/sa-forge-signer \
  --signer-workflow ttdonovan/sa-forge-signer/.github/workflows/release-binaries.yml
tar -xzf sa-forge-signer-vX.Y.Z-aarch64-apple-darwin.tar.gz

The attestation proves the archive was built by this repository’s release-binaries.yml workflow, as run from main; that workflow checks out the tag and refuses one that does not match the version in Cargo.toml. The checksum alone only proves the archive matches the file next to it. The macOS binaries are not signed or notarized: a copy downloaded with a browser is quarantined by Gatekeeper (gh and curl do not set the quarantine flag).

From source

Needs Rust 1.89 or later.

# Find the latest release tag
git ls-remote --tags --refs --sort=-version:refname https://github.com/ttdonovan/sa-forge-signer 'v*' | head -1

cargo install --locked --git https://github.com/ttdonovan/sa-forge-signer --tag vX.Y.Z sa-forge-signer
sa-forge-signer --version

That installs sa-forge-signer, sa-forge-signer-serve and sa-forge-signer-mcp (MCP over stdio). Install a tag, not a branch: main can hold unreleased changes, and a tag is what the changelog describes. --locked builds with the dependency versions in Cargo.lock, the ones CI tested and audited.

Updates

Compare sa-forge-signer --version (or cargo install --list, which shows the installed tag) with the latest tag, read the changelog for anything breaking, then download and verify the new release’s binary, or run the same cargo install with the new tag (it replaces the installed binary). To be notified of new versions, watch the repository on GitHub for releases only (Watch, Custom, Releases), or subscribe to https://github.com/ttdonovan/sa-forge-signer/releases.atom. A running serve keeps the old binary until it is restarted.

To build from a clone instead, cargo build --release --locked uses the toolchain pinned in rust-toolchain.toml.