Docs Concepts

Approvals and security

Agents can edit the files in your repo, and teammates push them. So what decides how work moves counts on your machine only once you approved it there.

#What only you approve

WhatWhere you approve itUntil then
Check commands in verification.jsonSettings → Project → Approvals, or teamtrail approveNo check runs. Completions wait (waiting-approval); the work is kept.
A risk policy that lowers what needs youApprovalsThe stricter levels hold.
A verification level lowered below the one you approvedApprovalsThe approved level holds.
Briefs marked accepted, criteria marked confirmed, knowledge marked liveApprovals (or accept them in the Lookout as usual)They open no gate and don't reach agents as trusted.
A trail that runs without discoveryApprovals, on its ownDiscovery gates it.
Guide catalogs in guides.jsonApprovals, on its ownThe catalogs it adds aren't searched.
Trail files changed outside TeamtrailApprovals: Accept this change or RevertTeamtrail uses the values it signed. See Changes outside Teamtrail.
trackers.json naming another tracker, repo or teamApprovals: Use the new one or Keep the current oneNothing is read from or sent to the new one.
Guides and the check commands they proposeSettings → Project → Guides, or teamtrail guides addAgents can't use the guide; its checks don't run. See Guides.
Settings someone else changed on a GitHub or Linear issueWaiting on you: Accept as is or Keep stricterYour accepted settings stay in force. See GitHub Issues and Linear.

Approvals is at ?settings=approvals, and anything waiting there also shows in Waiting on you as a trust item. Check commands and changed trail files block work, so they rank high.

#Where approvals live

In your config folder, under projects/<project id>/, never in the repo. An agent that can only write repo files, or a teammate's push, can't approve anything for you.

  • Each item shows exactly what it would approve: the commands, the lowered levels, the changed fields (old → new). Approving records what you saw. If the files change while you read, the page says so and asks you to Review again.
  • A repo moved to another folder is asked again.
  • Approvals are made on the machine Teamtrail runs on. A paired phone sees them but can't approve them.

#The first run

On a fresh clone, a new machine or the upgrade, committed files say they were approved somewhere else. Approvals then offers Approve all N committed to adopt them in one step.

  • It covers only content committed in git, as committed. An uncommitted change is shown whole and approved on its own.
  • It never includes a trail that runs without discovery, guide catalogs, or check commands Teamtrail can't place or the lint warns about. Those are approved one at a time.
  • It lasts until your first approval. After that, each item is approved on its own.

#In a terminal

bash
teamtrail approve

Shows each item waiting, exactly as it would be approved, and asks y/N for each. Without a terminal (CI, a server) it approves nothing unless you name an item by the hash it printed:

bash
teamtrail approve --hash sha256:…

An agent that can run the CLI can pass a printed hash too. That's why connect keeps agents out of the config folder, where approvals are written.

#Check commands

The commands in verification.json run on your machine when an agent completes work.

  • They run only once approved here. A new or changed command waits in Approvals. Until you approve it, completions end with waiting-approval and the agent moves on; nothing is lost.

  • They get an allowlisted environment: the shell, locale and toolchain basics (PATH, HOME, LANG, NODE_*, proxies, …). Tokens, keys and anything named like a secret are left out, and so are Teamtrail's own credentials.

  • Extra variables come from your machine, not the repo. Name them in TEAMTRAIL_CHECK_ENV where you start teamtrail:

    bash
    TEAMTRAIL_CHECK_ENV="DATABASE_URL, REDIS_URL, APP_*" teamtrail

    An exact name passes even if it looks like a secret: that's your call. A pattern such as APP_* passes what it matches, except names that look like secrets. A failed check's log ends with the names of the variables it didn't get, never their values.

The honest limit. Checks run as you, without a sandbox. The allowlist keeps secrets out of the environment, but a check can still read files your account can read (~/.aws, ~/.ssh, ~/.npmrc, Teamtrail's credentials.json) and reach your SSH agent. And approval covers the command line, not what it runs: npm run check runs package.json scripts, which an agent can edit. Approve commands you'd run yourself, and review changes to what they run.

#Your decisions

Teamtrail never answers or approves for you. What counts as your call:

  • Answers count toward gates only when you give them in the Lookout or Slack. You can also answer in an agent's chat: the agent passes your words on with answer_question, and the Lookout shows them. A chat answer guides agents, but it never passes a gate: closing a ticket that's yours to decide needs your answer in the Lookout or Slack.
  • High-risk calls need the Lookout. A decision your risk policy rates high, by its category or by the files it changed, counts only with your answer in the Lookout. Slack shows these with Open in Lookout, and Teamtrail refuses a Slack answer for them. See Slack.
  • Tickets that need a person close only with your answer. A junction, a prototype or a HITL task closes only after you answered, in the Lookout or Slack, a question the agent asked on that ticket. If the ticket is high risk, only an answer in the Lookout closes it.
  • Skipping discovery, or changing a trail's mode or destination, is a request. When an agent asks for it, you get a request to Approve or Decline. You approve it in the Lookout; you can decline it in the Lookout or Slack. Nothing changes until you approve, and no answer to a question stands in for it. Meanwhile the trail carries on as it is.
  • A trail that runs without discovery needs its own approval. It's never part of approving everything at once.

#Changes outside Teamtrail

With the default markdown tracker, a trail is plain files in .teamtrail/. What gates read counts only as Teamtrail wrote it on your machine, through the Lookout or an agent's MCP tools. Teamtrail keeps a signed record of it in your config folder.

If an agent or a teammate edits these fields in the files directly, the edit has no effect until you decide:

  • a ticket's type, its human (HITL) flag, its blockers, claim, state and status, and how it was closed;
  • a trail's mode, destination, verification level and guides;
  • decisions and assumptions.

The ticket is held, the signed values apply, and Settings → Approvals shows what changed (old → new) with Accept this change and Revert. Revert writes the signed values back into the file. A ticket added by copying a file in is held until you accept it, or delete it after confirming the file by name.

  • Text edits are marked, not held. Titles, bodies and comments can be edited freely; the ticket inspector says Text edited outside Teamtrail.
  • Decisions read from text show as Unverified. A resolution comment or a line in Decisions so far was written by whoever could edit the files, so the Logbook never shows it as your call.
  • Teammates. A teammate's pushed change shows as changed outside Teamtrail on every other machine until it's accepted there. On a fresh clone, a new machine or the upgrade, existing trails are adopted with the first run.

GitHub Issues and Linear use the tracker's own authorship instead: see Who counts as you.

#Devices on your network

With --host, a paired phone or laptop can read the trail, answer questions, approve finished work and edit text. Of what gates read, it can only change a ticket's status, or close or reopen it. It can't create trails or tickets.

It never changes what runs on your machine or whom it trusts. These are set on the machine itself, and Settings says so:

  • Approvals, the tracker connection and anything looked up with its credentials;
  • Slack;
  • the risk policy and verification levels;
  • workspaces;
  • installing and approving guides, and a ticket's guide;
  • remote agents' tokens, and pairing or revoking browsers;
  • your attention settings;
  • the projects list.

What a device reads leaves out absolute paths and the tracker account.

#Guides

  • A proposed check that runs a program Teamtrail doesn't know needs your acknowledgement: I know what it runs. In the CLI, it's asked only at a terminal.
  • A guide from another catalog shows Verified by <host>'s catalog: that catalog's own review, not Teamtrail's. Verified alone means the official catalog's maintainers reviewed it.
  • guides.json is an approval item: the catalogs it adds are searched only once you approve it.

See Guides.

#Keep agents out of the config folder

Your config folder holds this machine's key, which signs your answers, approvals and trail state, plus your tracker credentials. teamtrail connect keeps the agents it registers out of it:

  • Claude Code: deny rules in ~/.claude/settings.json. Without Claude Code's sandbox they stop its own file tools, but a shell command can still read the folder.
  • Codex: it prints a permissions profile to add. Until you add it, Codex's commands can read the folder, the machine key included.

#Slack

Slack reaches your machine through Teamtrail's Scout service (scout.teamtrail.app): Slack sends it every click and command, and your Teamtrail keeps an outbound connection to it. That puts the service in the path of your Slack answers, so:

  • The owner is the Slack account you connect, and you confirm it. Connecting starts from this machine's signed-in Lookout, which keeps a one-time secret (PKCE) that only it holds, and shows Connect as @you in Workspace? before anything is saved. A code from someone else's connect can't finish yours.
  • High-risk calls need the Lookout. An answer that arrives from Slack never backs a high-risk decision, never approves high-risk work, and never approves a change to a trail's settings, even if the service were compromised. Teamtrail checks this in its own gates, not only in Slack's buttons.
  • Clicks reach only the Teamtrail that posted the message. The service routes each click by its own record of who posted what, and your Teamtrail accepts a click only on a message it posted, from its owner or the people they allowed.
  • The service stores no message text. Questions, answers and threads pass through it in memory. It stores your workspace's bot token (encrypted), Slack ids, and your link as a hash. Its code is public in the Teamtrail repo.
  • The link token goes only to the service it was made with, and lives in credentials.json (mode 0600).

The trust you add: for everything that isn't high risk, an answer from Slack counts as yours, so you rely on the Scout service to pass Slack's events on faithfully. If that's not acceptable for a project, don't connect Slack, or rate the categories you care about as high in policy.json. See Slack and the privacy policy.

#Security model and limits

Teamtrail protects against:

  • an agent that can only write files in the repo: it can't approve its own checks, briefs or criteria, change gate fields, or record your decisions;
  • a teammate's push: committed approvals and state changes wait for you on your machine;
  • other devices on your network: they need pairing, and even then can't change what runs on your machine or whom it trusts;
  • other programs on your machine reaching the Lookout: they need a paired browser's session, which is never a cookie and is sent only to a server that proved it is your Lookout;
  • a compromised Scout service: it can't approve high-risk calls or trail settings, or reach another person's Teamtrail.

It doesn't protect against:

  • an agent that can read your config folder: it can read the machine key, make a pairing code and approve for itself. For up to 60 seconds after teamtrail or teamtrail pair opens your browser, it could also use that sign-in page's code first. That's why every sign-in through the opened page is announced in the terminal and marked in Settings → You → Browsers & devices (revoke one you didn't make), and why teamtrail connect keeps agents out of the folder;
  • a program that can read your browser's profile on disk: it can copy a session;
  • an unrestricted shell on your account: anything that runs as you can do what you can. Any local agent can also pass your words with answer_question; those answers guide, but never pass a gate;
  • a compromised Scout service, for what isn't high risk: if you connect Slack, it could pass on an answer or click you didn't give, on a question or approval below high risk. See Slack.

Run agents in a sandbox that blocks the config folder where you can. Where the sandbox blocks it, Teamtrail fails closed and tells both you and the agent why.