# Claude Code's settings If you already use Claude Code, a project set up for it should not need setting up a second time. Codey reads two kinds of thing from Claude Code's files — its permission rules and its CLAUDE.md files — and none of it is copied anywhere or written back: change it in Claude Code and the next start here sees the change. Its MCP servers are [not read](mcp.md#claude-codes-servers-are-not-read). **Permissions.** The `permissions` block of three settings files, in the order Claude Code reads them: | File | Whose | `deny` / `ask` | `allow` | `defaultMode` | | --- | --- | --- | --- | --- | | `~/.claude/settings.json` | yours, every project | honoured | honoured | `acceptEdits` only | | `.claude/settings.json` | the repository's, committed | honoured | only once [trusted](#trusting-a-project) | ignored | | `.claude/settings.local.json` | yours, this project, git-ignored | honoured | honoured | `acceptEdits` only | The rule underneath that table is who wrote the file. A deny or an ask rule can only make the agent do less or ask more, and nobody comes to harm from that, so a repository may add as many as it likes. An allow rule is the opposite: it is a decision that something runs without you being asked, and a decision written into a repository was made by whoever wrote the repository. The shared file's allow rules therefore wait for you to [trust the project](#trusting-a-project), and until you do they are listed and ignored. A `settings.local.json` that git turns out to be tracking arrived with the clone, whatever its name says, and is treated as shared. The rules act before anything else in the approval policy. A deny holds in every mode, `-yolo` included — that is what writing it down is for — and it holds for the read-only tools too, since `Read(.env)` is a rule about reading. An ask rule puts the call to you even when the mode would have let it through, and even when you said "always this tool" earlier in the session. An allow rule lets a call through without a prompt. Between them deny beats ask beats allow, as in Claude Code, so no allow rule anywhere argues a call past a deny. The denial the model reads names the rule and the file, so it can tell you which line to change instead of retrying. `/allowed` lists every rule under the file it came from, and says which are in force and why the others are not. Claude Code's names map onto Codey's: `Bash` is `bash`, `Read` is `read_file` (and, as best it can, `glob` and `grep`), `Edit` is both `edit_file` and `write_file`, `MultiEdit` is `edit_file`, `Write` is `write_file`, `Glob`, `Grep`, `WebFetch`, `WebSearch` and `TodoWrite` are the obvious ones, and `mcp__server` and `mcp__server__tool` are unchanged. A rule naming a tool Codey does not have, or written in a form it does not understand, is reported at startup and takes no part. Paths follow Claude Code's conventions: `//path` is absolute, `~/path` is under your home, `/path` is under the project root, and anything else is relative to it, with a bare name such as `.env` matching at any depth the way `.gitignore` would. Links are followed, so a rule about `.env` also catches a symlink to it. `Bash(npm run test:*)` is matched one simple command at a time, using the same parser as the approval prompt. An allow rule covers `npm run test && rm -rf ~` only if something also allows `rm`; a deny rule catches the line if it catches any part of it. A command the parser cannot see through — `$(...)`, backticks, `bash -c`, a variable in command position — never matches an allow rule, and where a deny rule cannot be ruled out for it, the call is asked about rather than run. So is anything that does more than its words say: `PATH=. git status`, or `echo hi > ~/.bashrc`, is not covered by an allow rule for `git` or `echo`. None of this makes shell allowlisting a security boundary — see [Safety](safety.md) — but it does stop the commonest way a prefix rule says yes to something nobody wrote down. `defaultMode: "acceptEdits"` in a file of yours lets file edits through, as Claude Code's mode of that name does. `default` is the default. The other modes are ignored with a notice, from every file: `bypassPermissions` in particular, because in Codey the way to stop being asked is `-yolo`, typed on the command line for one run, and neither a file of yours nor a repository's gets to say it for you. **CLAUDE.md.** The files Claude Code loads into every conversation are loaded into this one's system prompt, at startup, in Claude Code's order: `~/.claude/CLAUDE.md`, then — from the top of the project down to the working root — each directory's `CLAUDE.md`, `.claude/CLAUDE.md` and `CLAUDE.local.md`. The top is the nearest directory with a `.git` in it, or your home directory if there is none on the way; a root that is in neither is a project of one directory, because walking up to `/` would read whatever happened to be lying in `/tmp`. Later files are more specific and the prompt says they win. `@path/to/file` imports are followed, relative to the file they appear in and up to five deep, skipping anything in a code block. A project's files may import only from the project, and that is checked where symlinks lead: a repository's CLAUDE.md that could import `@~/.aws/credentials` would be a repository reading your credentials into a conversation that is then sent to the model. Your own `~/.claude/CLAUDE.md` and `CLAUDE.local.md` may import from your home directory. The whole thing is read once per session, so the cached prompt prefix stays the same from request to request; restart to pick up an edit. `AGENTS.md` is not loaded this way, but the agent is still told to read one if the repository has it, as before, and a CLAUDE.md that says `@AGENTS.md` brings it in. **What is not carried over**, so nobody has to find out the hard way: - Hooks in Claude Code's format (`PreToolUse`, `PostToolUse` and the rest). Codey's [hooks](hooks.md) are a different thing — they watch, they cannot veto — and a script written to block a tool call would silently block nothing here. - `env`, `model`, `apiKeyHelper`, `statusLine`, `outputStyle`, `cleanupPeriodDays` and the other non-permission settings. Codey has its own config for the ones it has an equivalent of. - `permissions.additionalDirectories`: the file tools keep the working root as their only root. - MCP servers, from `~/.claude.json` or `.mcp.json`, and with them Claude Code's record of which ones you approved (`enabledMcpjsonServers`, `enableAllProjectMcpServers`). Codey starts only the servers in its own [config](mcp.md). - Managed (enterprise) settings, subdirectory CLAUDE.md files loaded on demand, and `.claude/rules/`. ## Trusting a project A shared `.claude/settings.json` comes from the repository, and an allow rule in it is whoever wrote the repository deciding what runs on your machine without asking. So, like Claude Code, Codey asks first. The first interactive start in a checkout whose shared settings have allow rules prints, before the TUI opens: ``` Claude Code's configuration for /home/you/src/thing would: run these without asking, from .claude/settings.json: Bash(make:*) These files come from the repository, not from you: trusting them lets it choose commands this machine runs. Your answer is remembered until they change. Trust them for this checkout? [y/N] ``` The answer — yes or no — is remembered for this checkout against a fingerprint of exactly those rules. One more allow rule is a different fingerprint, and the question comes back; nothing else does. A refusal is remembered too, so saying no once is not a question at every start. The record is kept in `~/.config/codey/trust.json`, not in the project's `.codey/` directory with the rest of the per-repository state. That is the point of it: anything inside the working tree can arrive with a clone, and a repository that shipped its own record of being trusted would be approving its own rules. The fingerprint would be no defence there — whoever wrote the settings file can compute it. Only a file the repository cannot reach can say what you decided. Where nobody can be asked — `-p`, `codey agent stdio`, a piped stdin — an undecided project's allow rules are ignored, with a line on stderr saying so. A checkout you have already trusted needs nothing more. `-trust-project` says yes for one run without asking and without recording anything, which is what a CI job against a repository you control wants.