# Configuration

Start without configuration. ACC identifies a workspace from its Git common directory, or
from the directory itself when Git is absent. Sessions can communicate only when they run
as the same operating-system user on the same machine and resolve that same local
workspace.

Create `acc.workspace.json` only for stable workspace identity, roots, or shared
context budget. It is optional project configuration that `acc config init` may write
at your request; runtime state remains in platform app data outside the repository. The
file never defines agents, messages, execution state, or delivery endpoints. Project map:
[README](index.md). Terms used below: [Glossary](GLOSSARY.md).

## Decide whether you need a config

- **Identity that survives a local move.** Without a config, the same non-Git project at two
  paths is two workspaces. `workspaceId` lets the same OS user move or reopen it locally.
  Matching ids never connect different machines or OS users.
- **More than one root.** A monorepo whose apps live in separate directories, or a
  workspace that spans sibling checkouts.
- **Shared context budget.** Set the ceiling for supported injected turn context once for
  the workspace.

### Define the file

`acc.workspace.json`, at the root of the workspace. One name, so discovery is a lookup and
not a search. It is found by walking up from the working directory, because sessions start
wherever the human happens to be — a config that only counted at the top would apply to
some sessions in a project and not others. A config reached through a symlink is refused: a
link can point anywhere, including at a file the repository does not control.

```json
{
  "schemaVersion": 1,
  "workspaceId": "workspace_9pQ2f1xJ",
  "displayName": "Example",
  "roots": ["."],
  "policy": {
    "contextBudgetBytes": 6000
  }
}
```

| Field | Meaning | Default |
|---|---|---|
| `schemaVersion` | Must be `1` | required |
| `workspaceId` | Stable identity, portable id | required |
| `displayName` | What peers see in a roster | the directory name |
| `roots` | Directories in this workspace, relative to the config | `["."]` |
| `policy.claimMode` | Validated compatibility metadata (`advisory` or `guarded`); does not select claim enforcement | `advisory` |
| `policy.contextBudgetBytes` | Ceiling on injected turn context, 1–64000 | `6000` |
| `requiredAdapters` | Validated compatibility metadata; does not affect `acc doctor` diagnostics | `[]` |
| `extensions` | Anything else, namespaced by whoever wrote it | `{}` |

`policy.claimMode` and `requiredAdapters` are stored but have no claim or doctor effect in
0.4. CLI claims default to advisory; request `--enforcement guarded` on each claim when
appropriate, subject to every live participant's certified guard. MCP claims remain
advisory. Do not use these metadata fields to configure protection or missing-client checks.

Roots are refused if they are absolute or escape the workspace. An absolute root is one
machine's layout committed to a shared repository, and `packages/../../elsewhere` reaches
outside the boundary the workspace is supposed to be. The check counts path segments, so an
escape spelled in the middle is caught rather than only a leading `..`.

An unrecognised key is an error, not a shrug. `clam_mode` reads like a typo to a human and
like nothing at all to a parser that ignores what it does not know, and the result is a
team whose policy quietly stopped applying. `extensions` is the one declared door for
anything ACC does not define.

### Keep runtime state out

Sessions, participants, messages, claims, receipts, intents, events, tokens, credentials.
All of it is refused, by name, with the key that caused it, for two reasons. Runtime state
belongs under the platform data directory, so a checkout can be deleted, cloned, or synced
without carrying presence and locks along. And a config lives in a repository, where anyone
who can open a pull request can edit it — a file that could declare sessions would be a way
to hand a peer state it should have had to earn.

### Change identity safely

The config carries the workspace identity, so writing one moves the project to a new
workspace. Sessions already attached stay on the old one: they keep heartbeating it, they
drop off everyone else's roster, and claims they hold stop being seen. They do not recover
by themselves either — a session attaches when its client starts and at no other point.

So `init` refuses while sessions are attached, and names them:

```text
2 session(s) are attached here and would stop seeing each other: graphics (claude_code),
physics (codex). They re-attach only when their client starts, so close them first, or
pass --force to write anyway.
```

Close them, or pass `--force` if you mean it — and restart them afterwards.

### Create or validate it

<!-- test:illustration asks a person to confirm; there is nobody to ask in a test -->
```bash
acc config init        # preview, then write after you agree
acc config validate    # read-only; checks acc.workspace.json in the selected directory
```

`init` and `validate` operate only on `acc.workspace.json` directly inside the selected
`--cwd` directory (the current directory when omitted). Unlike ordinary workspace discovery,
they do not walk upward. Pass `--cwd` with the directory containing the config you intend
to inspect or create. A nested `init` can create a new config that shadows an ancestor;
check the ancestor first.

`init` shows the exact file it would write and waits. In a non-interactive run — a pipe, a
CI job, an agent — there is nobody to ask, so it refuses unless you pass `--yes`. It never
overwrites an existing config: a committed identity is shared by everyone on the project,
and replacing it on a mistyped command would split one workspace into two.

`validate` only reads. If that selected directory has no config, it reports
`no acc.workspace.json in selected directory; ancestors not checked`.
The JSON result returns default config metadata for that missing local file. Ordinary
commands may still discover an ancestor config; this is not an effective-policy report.
Run validation with `--cwd` set to that ancestor directory to check its file.

## Keep delivery consent user-owned

Live delivery may start a model turn and spend that recipient's tokens, so it is configured
through the recipient's user-owned client installation:

```bash
acc install --adapter codex --delivery off
```

The allowed values are `off`, `actionable`, and `all`; the default is `off`. This setting
does not belong in `acc.workspace.json`, where a pull request could opt someone else into
spending a turn. It also cannot create a capability. Every adapter reads live-delivery
consent from this installation record, and only from it. Exact-version evidence governs
ordinary hook features. Claude Code live delivery separately requires version 2.1.282 or
newer on macOS or Linux (on native Windows its inbox is a named pipe, so delivery stays
next-turn), and a current feature probe before installation applies the requested
policy. If those install-time checks fail, effective policy remains `off` and the installer
reports next-turn or inbox fallback. Each later session must also pass its own
generation-bound handshake. A failed session handshake clears or refuses that binding and
reports degraded reachability. It does not rewrite the installed consent.

Claude Code live delivery wakes the session through the inbox socket that the session opens
itself. ACC changes no launch argument, shell profile or `PATH` entry for it. Claude Code's
own inbound controls still apply to each wake. A session in `bypassPermissions` mode holds
each wake for your approval unless its `crossSessionInbound` setting is `accept`. A
`crossSessionInbound` setting of `refuse` drops wakes. These controls belong to you, and ACC
never overrides them. See
[held or dropped wakes](TROUBLESHOOTING.md#a-claude-code-session-holds-or-drops-acc-wakes).

Codex LocalDaemon delivery separately requires Codex 0.152.1 or newer, a
current feature probe, and exact thread, canonical cwd, process, version and protocol
checks. On Codex 0.154.0 through 0.157.0, explicit complete setup can download a missing
matching standalone package and prepare a definitely absent service. Codex 0.157.1 and newer
install the service's own package when it first starts, so setup only starts it. The setup choice names the
download. Existing service-start consent alone does not permit it. Codex files remain
under the selected `CODEX_HOME`; the existing CLI command and shell profiles are preserved.
Message delivery does not install Codex, start it, or stop it.
Explicit update maintenance can restart a verified service after separate confirmation.
Unavailable or ineligible sessions retain durable inbox fallback. Use
`acc install --adapter codex --delivery off` to stop new native offers.

### Codex outgoing permissions

Receiving a native message and sending from the agent's sandbox are separate operations.
On Codex 0.153.4 or newer, live opt-in also configures outgoing access
for default workspace permissions. This happens even when the daemon is not yet available.
Installation, its preview, and the interactive consent question disclose this change.

ACC selects a permission profile named `acc-workspace`, extending `:workspace`. It grants
write access to the ACC state directory and allows only the Unix sockets ACC delivers to.
Each receiving adapter declares its own, and the profile lists all of them even when an
install names Codex alone:

| Receiver | Allowed path |
|---|---|
| Codex | the control socket, `<CODEX_HOME>/app-server-control/app-server-control.sock` |
| Antigravity CLI relay | the ACC channel directory, `/tmp/acc-ch-<uid>` on macOS |
| Claude Code inbox | `/tmp/cc-socks`, `/tmp/cc-socks-<uid>`, `$XDG_RUNTIME_DIR/cc-socks` or else `$CLAUDE_CODE_TMPDIR/cc-socks` when set, `/run/user/<uid>/cc-socks` on Linux, and the directory of every Claude Code inbox ACC has bound on this machine |

ACC writes each path with its existing parent resolved, so on macOS the entries read
`/private/tmp/...`. Codex resolves a granted path only if it exists when Codex builds the
sandbox policy, and the sandbox compares resolved paths: a `/tmp/cc-socks-<uid>` entry
written before that directory existed never matched. A socket that is a link, such as the
Codex control socket, keeps its own name.

A command in the Codex sandbox can therefore connect to any of your Claude Code sessions'
inbox sockets. Claude Code's own inbound settings still decide what a received frame may do,
and ACC checks Claude Code's session registry before each wake it sends.

The profile enables networking through `features.network_proxy = true`, with no external
domains allowed. The proxy and socket grants must stay together: enabling networking
without the proxy changes its scope.

Doctor reports outgoing delivery as configured only while the profile allows every socket
above. A profile that ACC 0.8.0 or 0.8.1 wrote lacks the Claude Code inbox directories;
doctor names the missing paths and `acc install --adapter codex`. That command and
`acc update` rewrite ACC's own profile under the recorded delivery policy, `off` included.
Start a new Codex session afterwards.

The environment variables above are read from the process that runs `acc install` or
`acc doctor`. A Claude Code session started with its own `CLAUDE_CODE_TMPDIR` or
`XDG_RUNTIME_DIR` binds its inbox elsewhere. ACC learns that directory when its hooks first
bind the session, from its own endpoint record. From then on doctor names the directory
until `acc install --adapter codex` or `acc update` adds it. Only a directory named as Claude
Code names its inboxes, `cc-socks` or `cc-socks-<uid>`, is taken from a record.

An existing legacy workspace-write configuration is migrated only when its sole writable
root is ACC's state directory. Custom permission/configuration profiles, additional roots,
inline settings and uncaptured clients are preserved and reported as unverified. ACC does
not merge arbitrary security policies or verify overrides in an already running session.
For a custom policy, grant the same state and socket access through the proxy in the
client's effective workspace profile; do not combine it with legacy sandbox settings.

Restart Codex after changing permissions. Disabling incoming delivery retains unchanged
ACC-owned outgoing grants that you approved earlier. A fresh `--delivery off` install does
not add live socket grants. Uninstall restores the previous configuration only while every
generated permission component is unchanged.
If any component was edited or another setting depends on it, ACC preserves the entire
bundle and reports it for review. Plugin registration can still be removed independently.

### Codex command approval

Codex asks before a command that wants to leave its sandbox. With
`approvals_reviewer = "auto_review"`, a model reviews that request instead of you, and it can
refuse an ACC message that names a branch or a path as disclosure to an outside party. So
`acc install` adds ACC's own rules file on macOS and Linux:

```text
~/.codex/rules/agents-can-communicate.rules
  prefix_rule(pattern = ["<home>/.agents/acc-local/plugins/agents-can-communicate/acc-cli.sh",
                         ["work", "claim", "release", "message", "request", "inbox", "reply",
                          "ack", "status", "sync", "finish"]],
              decision = "allow")
```

Codex loads every `*.rules` file in that directory. A command the rule allows needs no
approval, so no reviewer sees it. Only ACC's wrapper and only the commands a participant runs
are allowed: `acc install`, `uninstall`, `update` and `config` still ask. Install does not ask
about the rule; it is part of ACC's Codex integration, as its hooks are. A file of that name
that ACC did not write stays yours, and ACC adds no rule then. So does ACC's file once you edit
it, for example to take a command out: reinstall and update leave it as it is, and doctor
reports it as edited. A wrapper path that a rule cannot
hold as it is gets none either. `acc uninstall` removes the file while it is unchanged, and
`acc doctor` asks for `acc install --adapter codex` when it is missing. Windows gets no rule:
how Codex matches a PowerShell command against one is unmeasured.

### Antigravity CLI command approval

Antigravity CLI asks for approval before each shell command, ACC's included. A session that
live delivery wakes while you are away would therefore stop at the agent's first ACC command,
and the peer would get no answer until someone approved it. The relay that lets ACC wake an
idle session is started by the agent too, with a command the client would also ask about. So
when `acc install` installs the Antigravity adapter, it always adds two rules to the client's
own settings:

```text
~/.gemini/antigravity-cli/settings.json
  permissions.allow: command(<home>/.gemini/config/acc/acc-cli.sh)
                     command(sh "<home>/.gemini/config/acc/acc-relay.sh" start)
```

A one-word rule is a prefix: every command that starts with that path runs without asking.
The agent then runs every ACC command without asking you, including one a peer's message
prompts. The second rule is the exact command that starts live delivery, in the words the
client itself saves when you choose to always allow it. Every other command still asks.
Install does not ask about the rules, and the delivery policy does not change them: they are
part of ACC's Antigravity integration, as its hooks are.

ACC keeps every other key and rule in the file, leaves a rule you already had as yours, and
records what it added in its own data home. `acc uninstall` removes every copy of each rule (one
in the same words cannot be told from ACC's), and a
container or file ACC created only if nothing else is in it. A rule removed by hand comes back
at the next `acc install` or automatic refresh; uninstall is what keeps it out. A file that is
not valid JSON, or whose `permissions.allow` is not a list, is left as it is and reported. The
client reads the file when it starts, so restart `agy` after install.

The rule matches only a command whose first word is the path without quotes, so ACC's skill
for this client writes the path without quotes. When your home path contains a space or a
shell metacharacter, the path needs quotes, no rule can match it, and ACC adds neither rule:
without the wrapper's, the agent would still ask before each ACC command.
`acc doctor` reports each rule as present, absent, or unable to apply, and asks for
`acc install --adapter antigravity` when one of ACC's rules is missing.

## Override local paths and identity

Nothing in `acc.workspace.json` says where state is stored, and nothing there can — that is
the job of these variables, or the platform's own locations, and ACC refuses any of them
that resolves inside a workspace.

| Variable | Purpose |
|---|---|
| `ACC_DATA_HOME` | Base directory under which ACC creates `acc/` for runtime and coordination state. Defaults: `~/Library/Application Support` on macOS; `~/.local/share` on Linux, or `XDG_DATA_HOME`; `%LOCALAPPDATA%` on Windows |
| `ACC_CONFIG_HOME` | Parsed and validated path override; no current configuration-storage consumer |
| `ACC_CACHE_HOME` | Parsed and validated path override; no current cache-storage consumer |
| `ACC_PARTICIPANT` | Which participant a session belongs to, when the client does not say |
| `ACC_WORKSPACE_ROOT` | The project to work in, instead of discovering one from the working directory. Absolute, or it is refused |
| `ACC_SESSION` · `ACC_GENERATION` | Explicit CLI owner credentials, supplied together by the operator for this session. Hooks do not set them. A public session ID alone never resolves a generation; see [CLI ownership](CLI.md#coordinate-from-a-session) |
| `ACC_MCP_PARTICIPANT` | Who `acc-mcp` takes part as. `mcp` by default |
| `ACC_MCP_WORKSPACE` | The project `acc-mcp` joins. Without it the server takes the directory the client launched it in, which is rarely the project |
| `ACC_NO_UPDATE_CHECK=1` | Disables update networking and background scheduling; manual recovery of an already downloaded update remains available |
| `ACC_PROBE_TIMEOUT_MS` | How long to wait for a client to print its version. Three seconds by default: generous on an idle machine, and not always enough on a busy one, where a client that overruns it is reported as not installed |
| `ACC_ANTIGRAVITY_HOOKS` | Where `acc install` registers Antigravity CLI hooks. `global`, the default, writes `~/.gemini/config/hooks.json`, which always loads and applies to every Antigravity session on the machine. `workspace` writes `<project>/.agents/hooks.json`, which is scoped to the project the command ran in and loads only while that project is an open Antigravity workspace - in print mode, only when it is passed with `--add-dir`. Any other value is refused by name rather than replaced by the default, and that client is skipped. The two cannot be combined: both files use the namespace `acc`, and a name in both is kept only once |
| `CODEX_HOME` | Codex's own home, honoured when locating the Codex App Server daemon's control socket for native delivery. Codex sets it; ACC only reads it |
| `CLAUDE_CONFIG_DIR` | Claude Code's own configuration directory, `~/.claude` by default. ACC reads the session registry `sessions/<pid>.json` under it to verify a session's inbox. ACC reads the value from the hook environment and never sets it |
| `CLAUDE_CODE_MESSAGING_SOCKET` | The inbox socket of one Claude Code session, which Claude Code exports to that session's hooks. ACC reads it in the hook environment and checks it against the session registry. ACC never reads `CLAUDE_CODE_MESSAGING_TOKEN` |
