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).

secretwhere it lives
GitHub token
OS keychain via @napi-rs/keyring. Keychain Access on macOS, libsecret on Linux, Credential Manager via WSL on Windows.
Gemini API key
OS keychain (same mechanism). Optional.
Ed25519 private key
OS keychain. Generated on first login with @noble/ed25519. Never leaves your machine.
Ed25519 public key
Sent to the dashboard at pairing time so future attestations from this device can be verified server-side.

## 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

commandwrites to disk?
watch
No. Read-only. Tails .git/COMMIT_EDITMSG only.
observe
Only to ~/.commitly/attestations.ndjson (the spool). Never to your repo.
act / act-loop
Yes — but only inside repos and arcs you explicitly opted in to, and only after you confirm at the diff prompt (or pass --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 login obviously 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.