Skip to content

chant workspace trust

llms.txt lists every page for an agent
chant workspace trust runner add <principal> --key <ssh-ed25519 line or file> [--class runner|service] [--by <principal>] [--expect <digest>] [--dry-run]
chant workspace trust runner remove <principal> [--by <principal>] [--expect <digest>] [--dry-run]

These commands write one runner entry of .chant/trust.json (#3510). A runner key signs what a machine did, such as agent-run statements or Op runs and ci tags. Under ws-074 a tool writes the repo only through chant. A box repo that trusts a lobby’s key lists it with trust runner add, and so does a host that runs chant ci serve.

CommandWhat it writes
runner add <principal>Appends { "principal", "class", "key" } to runners. With class runner, the default, it also adds the principal to roles.runner, which ci tick, ci run and chant run --key require. When the principal is already listed with the same key and class, the entry is left as it is and only a missing role is added
runner remove <principal>Removes the principal’s entry from runners, and the principal from roles.runner

--key takes the public key as an ssh-ed25519 line, or a path to the .pub that ssh-keygen -t ed25519 writes. It also takes a path to an Ed25519 key in PEM, public or private, and uses its public half, so the key a runner signs with can be given as it is. A comment after the key is dropped. Any other key type is refused, since every reader of runners verifies Ed25519 signatures. --class service lists a hosted signer such as a lobby or a steward. A service signs agent-run statements and needs no role.

The command edits .chant/trust.json in place and keeps everything else in it byte for byte. When there is no trust config yet, it writes a new one holding schema, runners and roles. The caller commits the change, as after member add, since the command never does. Changing the trust config is a protected write, so when a signers file exists the commit that carries it must be signed by an admin at base, which chant workspace verify checks. The readers take the runners from the branch tip or the commit they judge, never from the working tree, so a key listed here counts once the commit is on the branch.

Each command holds the working tree’s write lock while it reads and writes. The write scope at base judges it like any working-tree write. The write journal notes who wrote (--by, or the agent session CHANT_AGENT names).

The digest a write prints is the SHA-256 of the trust config’s bytes after the write, and previousDigest is the one before it. A missing trust config has the digest of empty text, e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855. A caller that shows a person the runners and writes what they chose passes --expect <digest>, the digest from its last write or the SHA-256 of what it read. The write goes ahead only when that digest still holds. Otherwise it is refused with trust-conflict, and conflict names the digest now and its lastWrite, the last chant write the journal knows of.

Terminal window
chant workspace trust runner add ci:acme/app --key runner.pem --by github:alex
# prints "digest": "5f0c..."
chant workspace trust runner remove ci:acme/app --expect 5f0c... --by github:alex

Each command prints one JSON document following https://intentius.io/chant/schemas/workspace/trust-write/v1/trust-write.schema.json, and exits 0 for a result and 1 for a refusal.

FieldWhat it holds
actionrunner add or runner remove
nameThe runner’s principal
path.chant/trust.json
digest, previousDigestThe file’s SHA-256 after and before the write
pathsThe file when the write changed it, else empty
changed, dryRunWhether the file changed, and whether --dry-run kept it from being written
previous, entryThe principal’s runner entry before and after the write, or null
runnerRoleWhether the principal holds the runner role after the write

Nothing is written when a write is refused, and error.code says why.

CodeWhen
not-a-git-repositoryThe directory is not in a git repository
write-usage-invalidNo principal, no --key for runner add, a --key or --class for runner remove, a --class other than runner or service, or an --expect that is not a digest
trust-config-invalid.chant/trust.json is not JSON or does not match its schema
trust-conflictThe file’s digest is not the one --expect gives
runner-key-invalid--key is not an ssh-ed25519 public key or an Ed25519 key in PEM
runner-key-is-signerThe signers file lists the key or the principal: a runner key belongs to a service or CI identity, never to a person
runner-existsrunner add names a principal listed with another key or class, or gives a key listed for another principal. Remove the entry first to change its key
runner-unknownrunner remove names a principal with no runner entry
write-scope-member, write-scope-protected, write-scope-class-unknown, agent-unknownThe write scope at base keeps the writer off .chant/trust.json
principal-unidentifiedThe declaration at base sets identity.attribution to identified, and --by names a person by a bare name
write-lock-timeout, write-lock-not-heldAnother write held the working tree’s write lock too long, or a batch’s token no longer holds it

Chant 0.124.31 and newer have these commands.

chant