# Using it in place of `claude` A lot of CI jobs and shell scripts run an agent as `claude -p`. Codey reads the same flags with the same meaning, so pointing one of them at Codey is meant to be a matter of changing the binary's name: ```bash codey -p --output-format json "why does TestFoo fail?" | jq -r .result echo "summarise the last commit" | codey -p --allowedTools "Bash(git log:*)" "Bash(git show:*)" codey -c -p "now fix it" # same session ``` | Claude Code flag | In Codey | | --- | --- | | `-p`, `--print` | One prompt, then exit. The prompt may follow `-p` — Codey's own spelling — or be a positional argument anywhere on the line, as `claude` takes it, or arrive on stdin when there is no other | | `--output-format text` | The final answer and nothing else on stdout | | `--output-format json` | One result object at the end | | `--output-format stream-json` | One JSON line per message as the run goes, then the result object | | `--verbose` | The same as `-v`. With `json` it prints every line `stream-json` would have, as one array, which is what Claude Code does; `stream-json` does not need it | | `-c`, `--continue` | `-resume latest`: the most recent session in this working root | | `--resume ` | Unchanged; the id is a Codey session id, which is what `session_id` in the output holds | | `--model`, `--max-turns` | Codey's own flags, already spelled the same | | `--allowedTools`, `--allowed-tools` | Calls to approve without asking, as rules | | `--disallowedTools`, `--disallowed-tools` | Tools to take away, or calls to refuse, as rules | | `--permission-mode` | `default`; `acceptEdits`, which lets edits and writes through and still asks before a command — the mode the ACP front end has by the same name; `bypassPermissions`, which is `-yolo`; `dontAsk`, which refuses whatever no rule allows | | `--dangerously-skip-permissions` | `-yolo` | | `--append-system-prompt`, `--system-prompt` | Add to the end of Codey's system prompt, or replace it. The session's own agent only: a subagent's prompt is its preset's | | `--include-partial-messages` | Accepted, with a warning, and ignored | Without `--output-format`, `-p` prints what it always has: the transcript as it streams, the tool calls, a usage line — for a person watching, not a parser. Asking for a format is asking for Claude Code's behaviour, and then stdout holds the format and nothing else; notices, warnings and any approval prompt go to stderr. The shapes are Claude Code's, because the programs reading them were written against it. The result object carries `type`, `subtype` (`success`, `error_max_turns` or `error_during_execution`), `is_error`, `result`, `session_id`, `num_turns`, `duration_ms`, `duration_api_ms`, `total_cost_usd` and `usage` with the four token counts. In `stream-json` it is preceded by a `system`/`init` line — working directory, model, tools, MCP servers, permission mode — then an `assistant` line per response, holding the message as the Messages API returned it, and a `user` line per batch of tool results. Numbers are this invocation's: a resumed session reports what the resume cost, not everything before it. A run that fails exits 1, whatever the format, and the JSON formats still print their result object — with `is_error: true`, the error in `errors`, and in `result` whatever the model last said, or the error itself when it said nothing. That includes failing before the model was ever asked: no credentials gives a result object, with an empty `session_id` because there was no session yet. Check `is_error` rather than `subtype`: it is the field that means failure in both, where the subtypes for a failure are not guaranteed to agree between the two. A flag Codey does not know stops the run before any of this, with exit 2, and so does a value it cannot use — `--permission-mode plan`, say — with exit 1 and a message on stderr. **Who gets asked.** Claude Code never prompts in `-p` mode, and with `--output-format` neither does Codey when stdin is not a terminal: what no rule allows is refused, and the model is told so and carries on. That is the case in CI. At a terminal the prompt still comes up, on stderr. Codey's own `-p` without a format keeps reading answers from stdin, so `yes | codey -p ...` works as it always has — except when the prompt itself came from stdin, which leaves nothing there to answer with. **Rules.** `--allowedTools` and `--disallowedTools` take Claude Code's rule syntax, comma- or space-separated, as many as you like after one flag: `Bash`, `Bash(git status)`, `Bash(npm run test:*)`, `Read`, `Read(./src/**)`, `Edit(./docs/**)`, `Write`, `Glob`, `Grep`, `WebFetch(domain:example.com)`, `WebSearch`, `TodoWrite`, `Task`, `mcp__github`, `mcp__github__create_issue`. Claude Code's names map onto Codey's tools — `Bash` is `bash`, `Read` `read_file`, `Write` `write_file`, and `Edit` both `edit_file` and `write_file`, because Claude Code applies its Edit rules to every tool that edits files. Codey's own names work as well. A rule naming a tool Codey does not have, `NotebookEdit` say, is a warning, and the rest of the list still applies. A rule for a whole tool on the disallowed list takes the tool away: the model is never shown it. A narrower one — `Bash(git push:*)`, `Read(./.env)` — is checked at approval time, before anything else, `-yolo` included, and a call it matches is refused. On the allowed list a rule stands in for the "yes" you would otherwise have been asked for. `Bash(prefix:*)` matches word by word, so `Bash(ls:*)` covers `ls -la` and not `lsof`. A compound command is allowed only when every simple command in it is covered, so `git status; rm -rf ~` does not ride in on `Bash(git status:*)`, and anything the [shell analysis](safety.md) cannot see through — command substitution, a variable in command position, an inline `bash -c` script, an assignment like `PATH=...`, output redirected into a file — is never allowed by a narrower rule than `Bash`. A deny rule is the other way round: one matching part is enough, and it looks inside `bash -c` and `eval`, past `sudo`, `env` and `timeout`, and at `/bin/rm` as `rm`. That catches the command a model would ordinarily write. It is not a sandbox, for the reason the Safety section gives. Path rules read like gitignore, as Claude Code's do: `./` and `/` are the working root, `//` an absolute path, `~/` your home, and a pattern with no slash in it — `.env`, `*.pem` — matches a name at any depth. Path rules on `Read` apply to `glob` and `grep` too, as far as their `path` argument goes. What does not work: - `--permission-mode plan`. Codey has no read-only planning mode, and says so rather than run a mode it does not have. Ask for a plan in the prompt, and `--disallowedTools Edit,Write,Bash` holds the run to it. - `--input-format stream-json`, and so a conversation fed in over stdin. The prompt is text. - `--include-partial-messages`: there are no `stream_event` lines, only whole messages. - `--mcp-config` and `--strict-mcp-config`. MCP servers come from [Codey's config](mcp.md). - `--settings`, `--setting-sources`, `--add-dir`, `--fallback-model`, `--session-id`, `--fork-session`, and `--resume` with no id, which in Claude Code opens a picker. - Piping a file in alongside a prompt. `cat log | claude -p "explain"` hands Claude Code both; Codey reads stdin only when there is no prompt otherwise, because a CI runner can leave stdin as a pipe nobody ever closes, and a run that waited on it would hang there for good. Put it in the prompt: `codey -p "explain: $(cat log)"`. - A prompt without `-p`, which in Claude Code starts an interactive session with that prompt. Codey ignores it and says so. - Tool names in the output are Codey's — `bash`, `read_file` — not Claude Code's. A script that looks for `"name":"Bash"` in the stream needs to look for `bash`. - The result object has no `permission_denials` or `modelUsage`, and lines carry no `parent_tool_use_id` other than `null`: subagents report through a tool result rather than in the parent's stream.