Skip to main content
The local ledger stays the source of truth. Hosted sync mirrors the next decisions to the workspace so the record can be followed from any machine, and hosted policy lets an administrator publish one rule set that every connected machine verifies before adopting. Both need an API key that belongs to an entitled live workspace. The free local tier needs no connection.

Configure the workspace

Resolution order: explicit --url and --key, then ATTESSO_SYNC_URL and ATTESSO_API_KEY, then ~/.config/attesso/config.json (mode 0600). The local UI writes that file through Connect workspace; sync and policy pull read it. The key is never printed back. The URL must be https, except on loopback where http is allowed for local testing, and it may not contain credentials. A key must look like an Attesso API key; anything else is rejected before a request is made.

Sync

Each batch carries at most limit rows. A decision carries only seq, occurred_at, action, subject, capability, decision, code, task and entry_hash; a usage row carries seq, occurred_at, task, model, input_tokens, output_tokens, cached_tokens and cost_usd. Arguments, prompts, meta and amount stay on the machine. The device id is the ledger’s key id; change the key and the cursor starts again rather than claiming someone else’s history. Usage rows are mirrored but not metered. The cursor lives in .attesso/sync.json and advances to the last sent seq only after the server answers with valid integers. A failed request leaves it alone, so the next run retries the same batch; the server deduplicates by device and sequence, which makes a retry safe. accepted, skipped and metered are what the workspace counted; metered is what it booked as billable, and usage is how many usage rows it stored.

The hosted views

Once a workspace has synced a decision, the dashboard’s Bounds entry opens the hosted overview at /dashboard/<env>/bounds/hosted directly. /dashboard/<env>/bounds?setup=1 keeps the local setup instructions for a workspace that has not synced yet. The overview shows the lifetime decision and refusal counts, device sync health, the refusal reasons and tool activity for the last 24 hours, the three newest open refusals, the five newest decisions, and the token card described below.

Review queue

/dashboard/<env>/bounds/reviews lists every refusal, newest first, with filters for status (open, resolved, ignored, all), code and device. Closing an item records a resolution or an ignore on the control plane; it never changes the local verdict, the policy, the rules or the signed ledger. The overview previews the three newest open items and links here with the full count.

Decisions

/dashboard/<env>/bounds/decisions lists every mirrored decision, newest first, with filters for decision (all, ALLOW, DENY), code, device and window (24 hours, 7 days, 30 days, all time). The refusal-reason links on the overview open this page filtered to that code. Use the decision filter to see only refused calls, and the window filter to bound a long history. Both pages use a keyset cursor: Older continues exactly where the page ended, and the filters live in the URL, so a filtered view can be shared or reloaded. The overview requests three reviews and five decisions; the full pages request twenty rows per page.

Token usage and the 24-hour summary

Usage is reported by the agent, never inferred from decisions. attesso usage records one measured model request against a task (for a hook, the session id):
A harness hook can call it on every model response. Hermes delivers the usage under extra, so a one-line hook script records it without blocking the request:
The 24-hour card leads with what needs a decision: refused calls, decisions, measured coverage and open reviews, all exact. The measured token total (input, output, sessions, reported cost) is one line below it. No figure is inferred from decisions. With no reported usage the card says no token usage reported rather than showing a fabricated number.

Publish a rule set

A workspace administrator authors the rule set at /dashboard/<env>/bounds/policy. Publishing creates an immutable version signed with Attesso’s evidence key. The local engine fetches it, verifies the envelope against /.well-known/jwks.json, and only then replaces .attesso/rules.json:
Without --apply the command verifies and previews the version and digest; with it, rules.json is written (or reported as already current). A tampered signature, an unknown key, an unexpected format or an invalid rule set writes nothing. A workspace with no published policy answers 404 and the command says so. The bundle is attesso.bounds.policy.v1. Path scope and shell_scope are not in it: those stay on the machine that enforces them, set with attesso paths --set.
Local verification proves the bundle came from Attesso’s signing key and was not edited in transit. Who inside the workspace published it, and whether they had the right to, is a control-plane question the local engine does not check; treat publishing rights as the authority.

What hosted adds, and what it does not

The split is the same one Receipts and packets sets out: local proves the file was not edited, hosted proves a named human approved exact terms and lets someone who does not trust you check it.