Permissions & Safety
Chord is a coding agent that can read files, modify files, execute commands, and call external tools. Before public or shared use, make sure you understand its permission model and safety boundaries.
Principles
Section titled “Principles”- Keep high-risk actions as
askby default - Use
denyfor actions that are clearly dangerous or unnecessary - Use
allowonly for low-risk, predictable actions - Put API keys in
auth.yamlor environment variables; do not commit them into project files
Permission model
Section titled “Permission model”Typical permission states:
allow: auto-allowask: require confirmation before executiondeny: reject directly
Rules are keyed by tool name; the full list of built-in tool names is in Built-in tools.
In the TUI confirmation dialog, A opens the add-rule picker for the current tool call; press Enter in that picker to save the selected rule and allow the current call.
Permissions can be defined in Agent config. Start with this recommended personal-development template, then tighten or relax it for your project’s risk profile:
permission: "*": allow handoff: deny delegate: deny delete: ask web_fetch: "localhost:8000": ask "169.254.0.0/16": deny "10.0.0.0/8": deny "192.168.0.0/16": deny shell: "sudo *": ask "rm *": ask "rmdir *": ask "mv *": ask "git add *": ask "git checkout *": ask "git clean *": ask "git commit *": ask "git push *": ask "git reset *": ask "git restore *": ask "git tag *": askThis means: allow most tools by default; disable handoff and delegate; require confirmation for file deletion, selected WebFetch URL patterns, and common high-risk shell/git commands. Permission rules use “last match wins”, so the more specific web_fetch and shell rules above override the top-level "*": allow. This is reasonable for a single-user trusted workspace; shared repositories, team services, or automated headless deployments should tighten it further. This page starts from "*": allow as a trusted-workspace baseline; for a least-privilege baseline instead, the builder agent in Configuration — Agent config starts from "*": deny and opts in only to the tools a role needs. Pick whichever baseline matches your trust model.
WebFetch target matching
Section titled “WebFetch target matching”web_fetch rule patterns use network-aware host matching. A pattern has the
shape host[:port]:
- host: a domain (
example.com), a domain wildcard (*.internal,*), a literal IP (127.0.0.1,::1), or a CIDR range (10.0.0.0/8,169.254.0.0/16,fd00::/8). Bracket IPv6 addresses and IPv6 CIDRs when specifying a port, for example[fd00::/8]:443. - port: omit it (or use
*) for any; use a single port (8080) or a range (8000-9000). When the requested URL omits its port, the port defaults from the URL scheme (http→80, https→443). - Scheme and path patterns are not supported.
web_fetch: "*": allow # default: allow everything "0.0.0.0/8": deny "10.0.0.0/8": deny "127.0.0.0/8": deny "169.254.0.0/16": deny # cloud metadata endpoint "192.168.0.0/16": deny "*:8000-9000": ask # any host on these ports needs confirmation "*.internal": deny # internal domainsMatching happens before the request is sent, against the URL the model supplied. It is not re-checked against the resolved connection IP, so a hostname that resolves to an internal address, or an HTTP redirect to one, is not blocked by an IP/CIDR rule. Treat these rules as intent-level gating, not a network sandbox.
Special permission semantics
Section titled “Special permission semantics”Most tools use the literal allow / ask / deny meaning above, but a few orchestration tools intentionally have extra coupling so permission settings match the workflow Chord can safely run:
-
editandapply_patchare one file-editing tool family with two model-facing formats (patchis accepted as a legacy alias forapply_patch). A rule for one editor applies to the other editor when the other editor has no explicit same-tool rule. This includesdeny:*: allowfollowed byedit: denydisables botheditandapply_patch, becauseapply_patchinherits the edit-family denial. Configure both names when you want different behavior per format. For example,edit: allowplusapply_patch: denydisablesapply_patchbut keepseditavailable, so GPT/o-series models fall back toedit; conversely,apply_patch: allowplusedit: denykeepsapply_patchavailable for non-GPT models that would otherwise preferedit. -
handoffanddoneare treated as control gates. Setting either one todenyhides or disables that workflow. Setting it toalloworaskmakes the workflow available; Chord may still show local confirmation at the actual handoff/finish point (for example the loopdoneconfirmation). This meansaskis not a second, stronger workflow mode for these tools: it mainly keeps the tool visible/available while preserving Chord’s built-in confirmation gate. The trade-off avoids confusing the model with an available control tool that is later impossible to complete, while still preventing silent role switches or premature loop exits. -
delegatematches itsagent_typeargument, so a role can restrict delegation to selected SubAgent definitions. For example, the ordered rules below deny every target exceptreviewerand require confirmation before delegating totester:permission:delegate:"*": denyreviewer: allowtester: askDenied targets are omitted from the Delegate tool schema and coordination prompt. If every configured SubAgent target is denied, Delegate is hidden. Permission rules use last-match-wins ordering, so put the wildcard fallback before the specific target rules.
-
delegatealso controls the delegation workflow as a group. If it is entirely disabled by an effective wildcarddeny, Chord disables SubAgent cancellation viacancel, hides nesteddelegate/cancelfrom SubAgents, and limits SubAgentnotifyto owner-only follow-up instead of arbitrary target routing. The reason is that cancelling or targeting other delegated tasks is part of managing delegated workstreams; allowing those pieces while disabling delegation would create a partial control plane that can interfere with work the role is not allowed to orchestrate. -
canceltherefore depends ondelegate: even ifcancel: allowis configured,cancelis denied whendelegateis disabled. To allow a role to cancel delegated work, enable bothdelegateandcancel. -
question: askis normalized toallow. Thequestiontool already asks the user a structured question and waits for their answer, so adding a separate permission confirmation before asking the question would create a redundant prompt without reducing the risk of the final decision. -
YOLO does not override
handoff,delegate,cancel, ordone; those control-tool permissions remain enforced even when ordinary file/shell/web permissions are bypassed. Under YOLO, a broad"*": allowrule does not grant these protected tools by itself; configure each protected tool directly when the role should use it.
Permissions are Agent-level configuration, not a simple global switch.
For shell, a specific allow pattern such as "git *": allow does not auto-allow compound commands containing unquoted shell separators (;, &&, ||, |, &, or newlines). Those calls fall through to the next matching rule, typically ask or deny. Use this as a safety backstop, not as shell sandboxing; keep broad rules like shell: allow or shell: { "*": allow } for only fully trusted roles.
A command-specific allow does, however, cover the full capability of that command, including output redirections and inline environment-assignment prefixes. If echo * is allowed, then echo secret > ~/.bashrc, echo x >> file, data > /dev/tcp/host/port, and LD_PRELOAD=./x.so echo hi are all allowed — the redirection target and the environment prefix are part of that single shell command, not a separate tool call, so they are not matched or gated on their own. Grant a command-level allow only to commands whose worst case (arbitrary file writes via redirection, an overridden environment) you accept; otherwise keep them at ask.
Shell / shell risk
Section titled “Shell / shell risk”shell can execute system commands and should be treated carefully. shell and spawn are intentionally non-interactive: Chord does not wire model-controlled stdin into child processes, Unix child processes run without a controlling TTY, and high-confidence interactive commands are rejected before execution. Plain stdin reads such as shell read/select observe EOF instead of waiting for model input; provide data explicitly with a pipe, here-doc, file, or arguments when a command expects input. Login wizards, terminal editors, pagers/full-screen TUIs, password prompts, and commands that require /dev/tty should be run manually in a real terminal or rewritten with explicit non-interactive input/flags.
Platform notes for shell / spawn:
- On Unix, Chord starts child processes in a new session and cleans up by process group on timeout/cancellation.
- On Windows, Chord still keeps
shell/spawnnon-interactive, but there is no Unix-equivalentsetsid/process-group control path here; timeout/cancellation cleanup falls back to direct process termination and may be less complete for descendant processes.
Common rewrites:
- Use
git commit -m "message"orgit commit -F fileinstead of editor-drivengit commit - For amend flows that should preserve the existing message, use explicit non-editor forms such as
git commit --amend --no-editorgit commit --amend -C HEAD - Avoid interactive Git patch workflows (
git add -p,git commit -p,git stash -p) fromshell/spawn; stage explicit pathspecs or run them manually - Remove TTY allocation flags from container commands (
docker exec -it,docker run -t,podman run -t,kubectl exec -it) unless you are running them manually in a real terminal - Use
npm init -y/--yesor provide all required options explicitly - Use
sudo -nwhen you want sudo to fail non-interactively instead of prompting - Pipe input or use a here-doc when a command truly accepts non-interactive stdin
Recommendations:
- Keep file deletion, bulk rewrites, network downloads, and database operations as
askordenyby default - Use
web_fetchpatterns to gate local/private services or sensitive endpoints — by host/port (web_fetch: { "localhost:8000": ask }) or by address range (web_fetch: { "169.254.0.0/16": deny, "*:8000-9000": ask }) - Set
allowonly for a small set of predictable development commands - Do not treat permission matching as a security sandbox
Important: Chord’s permission matching is product-level risk control, not OS-level isolation or a security sandbox.
File modification risk
Section titled “File modification risk”edit, write, and delete directly modify workspace files. edit is for local changes to one existing file, write creates or intentionally replaces a whole file, and delete removes whole files. read, view_image, and grep are read-only, but they still operate on local filesystem paths and can expose local file contents to the transcript/model context. Path-reading tools intentionally reject blocked device-style paths such as standard-stream device files (/dev/stdin, /dev/stdout, /dev/stderr, and similar) instead of treating them as normal files. Local text file tools prefer UTF-8 or BOM-marked Unicode (UTF-8/UTF-16/UTF-32) and retain constrained support for common regional encodings such as GB18030, Big5, and Shift-JIS. Ambiguous or unsupported encodings fail fast; web_fetch still honors declared HTTP response charsets.
For existing files, write requires the model to know the current version in full: a complete read, or the file’s current content being the model’s own previous whole-file write. Paged or budget-truncated reads do not authorize whole-file replacement. When the full observation baseline is missing, or the file changed after it was observed, the write is rejected before touching the disk and a fresh complete read is requested. Creating a new file needs no prior-version observation. delete is path-authorized instead of read-gated: its safety is carried by path resolution, permission rules, tracked locks, and pre-delete backups, so removing a file does not force a full read first.
edit and apply_patch still read the current disk state at execution time and guard against stale anchors through exact-match / patch-plan validation; if drift is detected at runtime but the current anchors still validate, Chord warns instead of rejecting and makes a best-effort backup of risky non-empty pre-write contents under the active session directory. Backups are capped at 10 per path, 200 per session, 10 MiB per file, and 50 MiB per session; if a required backup would exceed those limits or otherwise fail, the localized edit can still proceed but the tool result says no backup was created and why. Session deletion/cleanup removes these backups with the session directory.
Recommendations:
- Use Git in important repositories so changes are easy to review and roll back
- Keep production config, deployment scripts, and secret files as
ask - Use finer-grained rules for generated files or test artifact directories
Credentials and config
Section titled “Credentials and config”- Store API keys in
~/.config/chord/auth.yamlwhen possible - Environment-variable references are also supported
- Do not put real secrets in example configs, scripts, or project repositories
- Restrict
auth.yamlpermissions, for examplechmod 600 ~/.config/chord/auth.yaml
Headless boundary
Section titled “Headless boundary”chord headless is suitable as a lower-level control plane for bots/gateways, but it does not provide multi-tenant isolation, browser security boundaries, or complete permission hosting by itself.
If you connect it to a chat platform, automation system, or team service, enforce additional controls in the outer layer:
- Which working directories may be accessed
- Which commands may be called
- Who can approve high-risk operations
- How events are audited and retained
Network and external integrations
Section titled “Network and external integrations”Chord can integrate with:
- provider APIs
- LSP
- MCP
- Hooks
- local shell commands
Each capability expands the runtime boundary. Before enabling one, confirm:
- Whether you really need it
- Which resources it can read or write
- How to roll back or disable it when it fails
- Whether sensitive data may be sent to an external service
Usage recommendations
Section titled “Usage recommendations”- Start with a minimal provider config and minimal permissions
- Observe behavior in a personal repository before gradually relaxing permissions
- In shared repositories or team environments, do not globally
allowby default - Expose only the minimum necessary Hook and MCP tools