Security model
The agent is small enough to audit in an afternoon. This page is the short version: where keys live, what the dashboard receives, and what the agent will refuse to do.
## where secrets live
Three kinds of secret matter: a GitHub OAuth token (granted by the login flow), an optional Gemini API key (only needed for act commands), and an Ed25519 private key (minted on first login).
GitHub token@napi-rs/keyring. Keychain Access on macOS, libsecret on Linux, Credential Manager via WSL on Windows.Gemini API keyEd25519 private key@noble/ed25519. Never leaves your machine.Ed25519 public key## what attestations contain
Each save produces a JSON envelope before signing. The signed payload carries:
- Path relative to the project root.
- SHA-256 of the file contents.
- Wall-clock timestamp in milliseconds.
- Device id issued by the dashboard at pairing, along with a stable per-machine identifier hashed before transmission.
The envelope does not include file contents. Files larger than 5 MB are skipped entirely — attestations are about provenance, not blob storage.
## GitHub OAuth scopes
The login flow requests read-only access to public repos only. The agent never asks for the repo write scope, never asks for workflow scopes, never asks for org admin. The dashboard cannot push, merge, or open pull requests on your behalf.
## what the agent writes
watch.git/COMMIT_EDITMSG only.observe~/.commitly/attestations.ndjson (the spool). Never to your repo.act / act-loop--yes for daemon mode).## network
Outbound HTTPS to the dashboard URL only. Every fetch call carries a 60-second AbortSignal timeout to prevent indefinite hangs. The agent does not run any inbound listener.
## what this protects against
- Server forgery. The dashboard cannot fabricate attestations after the fact — it doesn't have your private key.
- Token leak via shell history. The CLI never echoes the token; secrets enter via the OAuth callback URL fragment, not the command line.
- Multi-user systems. Generated service units are written with mode
0o600, so other users on the same host cannot read them.
## what this does not protect against
- A compromised endpoint. If your machine is owned, the keychain is owned. There is no hardware-token mode yet.
- Backdating before pairing. Attestations from before you ran
loginobviously can't exist. The dashboard knows when each device was paired. - Coordinated lying. Two paired machines colluding can sign whatever timestamps they want. The model is verifiable per-device, not Byzantine-fault-tolerant.