What it reads and writes

Part of team worktree — the approved copy the two subcommands read, the unapproved-change note, and how {repo} and {task} fill the folder and branch.

Reads the team file and this machine's approval store, the session's state (.agents/team.state.json), and git: the base branch, the branch names, and the worktree itself. With --session, the state of that session instead of team.session.

Every value the two subcommands read from the file is the approved copy's while a verified approval is in force, whatever the file says now and whether or not the fingerprints match: workspace (mode, path, branch, base, setup and limit), trust, the caller rules (orchestrator and operator), the session, the names a public project forbids, and the seats --seat may name. An unapproved edit — a path moved, a setup command added, a trust pattern widened or narrowed, the orchestrator or the operator changed, a seat added, removed, renamed or redefined — is never used. A seat taken out of the file is still one until the owner approves that.

project is read from the file as it is now, not from the approved copy. It is not an owner section, so renaming it needs no approval. {repo} in workspace.path is that current name, which decides the folder new creates and the directory workspace.setup runs in. It does not place a worktree outside the approved trust: the landing is still judged against the approved trust patterns, and a landing outside them is refused before anything is created. A rename that puts {repo} outside the file's own trust patterns makes the file invalid, so the command never starts. A pattern wide enough to cover the new name (for example ../worktrees/*) keeps the new folder inside the approved trust.

When an owner section or a seat was added, removed or changed, the command prints one note on stderr before its normal output and before a later refusal (the trust, the limit, an unapproved seat):

team worktree: using the approved workspace settings; the file has unapproved changes: run `team approve`

The exit code is the one the run itself has. The log line is unchanged: the note is not written to team.log. A caller the approved copy does not allow is refused before the note, and nothing is created. project itself is not this drift: a file that sets session and changes only project prints no note. When session is omitted it defaults to the project name, so a rename changes the session too. That session change is the drift, the note prints, and state is written under the approved session while {repo} is still the live name.

--seat is checked against the approved seats. The live seat list is read for one distinction: a name the file declares and the approved copy does not gets seat <name> is not in the approved file; a name neither declares gets --seat "<name>" names no declared seat.

A verified record whose stored copy this version cannot read — empty, invalid, or otherwise — refuses with the approved copy can't be read, whether or not the fingerprints match. A record whose file is not a string never becomes a verified standing. The store refuses it first, and the command prints that line unchanged: the approval record cannot be read (... "file" is not a string): run team approve once.

Writes .agents/team.log, .agents/team.state.json (one record under the session: the folder, the branch, the seat when --seat names one, and whether workspace.setup succeeded), and, with new, the worktree itself and the branch it cuts.

The folder is workspace.path with {repo} and {task} filled; the branch is workspace.branch with {kind} and {task} filled. new fetches the base's upstream when it has one, and starts from the local base, with a note in the log, when it doesn't. Nothing is created when the fetch fails.

An unapproved change

An edit to an owner-controlled value is not in effect until the owner approves it. Here the file has been changed to mode: shared and a seat has been added, neither approved; the command says so once, and goes on with the approved workspace:

.agents/team.yaml
format: 1
project: beacon
coordinator: claude-keeper
operator: claude-keeper

trust:
  - .
  - ../worktrees/beacon/*

workspace:
  mode: shared

seats:
  - role: coordinator
    name: claude-keeper
    label: coordinator
    cli: claude-code
    vendor: anthropic
    model: Claude Opus
    version: "5.5"
    launch: claude --model claude-opus-5-5

  - role: implementer
    name: claude-beacon
    label: implementer
    cli: claude-code
    vendor: anthropic
    model: Claude Opus
    version: "5.5"
    launch: claude --model claude-opus-5-5

  - role: implementer
    name: claude-later
    label: later
    cli: claude-code
    vendor: anthropic
    model: Claude Opus
    version: "5.5"
    launch: claude --model claude-opus-5-5
Terminal
 team worktree new read-back --kind fix ; echo "exit $?"
team worktree: using the approved workspace settings; the file has unapproved changes: run `team approve`
../worktrees/beacon/read-back
exit 0

The seat the file added is refused, because the approved copy doesn't declare it:

Terminal
 team worktree new later-task --kind fix --seat claude-later ; echo "exit $?"
team worktree: using the approved workspace settings; the file has unapproved changes: run `team approve`
team worktree: seat claude-later is not in the approved file: run `team approve`
exit 1