Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ rtk init -g # Install hook + RTK.md (recommended)
rtk init -g --opencode # OpenCode plugin (instead of Claude Code)
rtk init -g --auto-patch # Non-interactive (CI/CD)
rtk init -g --hook-only # Hook only, no RTK.md
rtk init -g --codex # Codex hook + RTK.md + AGENTS.md
rtk init --show # Verify installation
```

Expand Down Expand Up @@ -375,7 +376,7 @@ RTK supports 15 AI coding tools. Each integration rewrites shell commands to `rt
| **GitHub Copilot CLI** | `rtk init -g --copilot` | PreToolUse deny-with-suggestion (CLI limitation) |
| **Cursor** | `rtk init -g --agent cursor` | preToolUse hook (hooks.json) |
| **Gemini CLI** | `rtk init -g --gemini` | BeforeTool hook |
| **Codex** | `rtk init -g --codex` | AGENTS.md + RTK.md instructions |
| **Codex** | `rtk init -g --codex` | PreToolUse hook (`rtk hook codex`) + AGENTS.md |
| **Windsurf** | `rtk init -g --agent windsurf` | .windsurfrules (project-scoped) |
| **Cline / Roo Code** | `rtk init --agent cline` | .clinerules (project-scoped) |
| **OpenCode** | `rtk init -g --opencode` | Plugin TS (tool.execute.before) |
Expand Down
4 changes: 2 additions & 2 deletions docs/contributing/TECHNICAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ Start here, then drill down into each README for file-level details.
| [`cursor/`](../hooks/cursor/README.md) | Cursor IDE | Shell hook, empty JSON response requirement |
| [`cline/`](../hooks/cline/README.md) | Cline / Roo Code | Rules file (prompt-level, no programmatic hook) |
| [`windsurf/`](../hooks/windsurf/README.md) | Windsurf / Cascade | Rules file (workspace-scoped) |
| [`codex/`](../hooks/codex/README.md) | OpenAI Codex CLI | Awareness document, AGENTS.md integration |
| [`codex/`](../hooks/codex/README.md) | OpenAI Codex CLI | Native PreToolUse hook, AGENTS.md integration |
| [`opencode/`](../hooks/opencode/README.md) | OpenCode | TypeScript plugin, zx library, in-place mutation |

---
Expand All @@ -333,7 +333,7 @@ RTK supports the following LLM agents through hook integrations:
| Gemini CLI | Rust binary | `rtk hook gemini` reads JSON | Yes (`hookSpecificOutput`) |
| Cline/Roo Code | Rules file | Prompt-level guidance | N/A (prompt) |
| Windsurf | Rules file | Prompt-level guidance | N/A (prompt) |
| Codex CLI | Awareness doc | AGENTS.md integration | N/A (prompt) |
| Codex CLI | Rust binary hook | `rtk hook codex` + AGENTS.md integration | Yes (`updatedInput`) |
| OpenCode | TS plugin | `tool.execute.before` event | Yes (in-place mutation) |

> **Details**: [`hooks/README.md`](../hooks/README.md) has the full JSON schemas for each agent. [`src/hooks/README.md`](../src/hooks/README.md) covers installation, integrity verification, and the rewrite command.
Expand Down
12 changes: 8 additions & 4 deletions docs/guide/getting-started/supported-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Agent runs "cargo test"
| Factory Droid | Shell hook (`PreToolUse`, matcher `Execute`) | Yes |
| Cline / Roo Code | Rules file (prompt-level) | N/A |
| Windsurf | Rules file (prompt-level) | N/A |
| Codex CLI | AGENTS.md instructions | N/A |
| Codex CLI | PreToolUse hook + AGENTS.md instructions | Yes (`updatedInput`) |
| Kilo Code | Rules file (prompt-level) | N/A |
| Google Antigravity | Rules file (prompt-level) | N/A |
| Mistral Vibe | Planned ([#800](https://github.com/rtk-ai/rtk/issues/800)) | Pending upstream |
Expand Down Expand Up @@ -175,10 +175,14 @@ rtk init --global --agent windsurf # creates .windsurfrules in current projec
### Codex CLI

```bash
rtk init --codex # project-scoped (AGENTS.md)
rtk init --global --codex # user-global (~/.codex/AGENTS.md)
rtk init --codex # project-scoped (AGENTS.md + .codex/hooks.json)
rtk init --global --codex # user-global (~/.codex/AGENTS.md + hooks.json)
```

Restart Codex, open `/hooks`, and trust the new RTK command hook. Eligible single,
non-mutating Bash commands are then rewritten transparently through
`rtk hook codex`; other commands retain Codex's native approval flow.

### Kilo Code

```bash
Expand Down Expand Up @@ -207,7 +211,7 @@ Support is blocked on upstream `BeforeToolCallback` ([mistral-vibe#531](https://
| **Plugin** | TypeScript, JavaScript, or Python in agent's plugin system | Transparent, in-place mutation when the agent allows it |
| **Rules file** | Prompt-level instructions | Guidance only — agent is told to prefer `rtk <cmd>` |

Rules file integrations (Cline, Windsurf, Codex, Kilo Code, Antigravity) rely on the model following instructions. Full hook integrations (Claude Code, Cursor, Gemini) are guaranteed — the command is rewritten before the agent sees it. Plugin integrations (OpenCode, Pi) use in-place mutation via the agent's TypeScript extension API.
Rules file integrations (Cline, Windsurf, Kilo Code, Antigravity) rely on the model following instructions. Full hook integrations (Claude Code, Cursor, Gemini, Codex) rewrite the command before execution. Plugin integrations (OpenCode, Pi) use in-place mutation via the agent's TypeScript extension API.

## Windows support

Expand Down
29 changes: 25 additions & 4 deletions hooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Each agent subdirectory has its own README with hook-specific details:
- **[`cursor/`](cursor/README.md)** — Shell hook, Cursor JSON format, empty `{}` response requirement
- **[`cline/`](cline/README.md)** — Rules file (prompt-level), `.clinerules` project-local installation
- **[`windsurf/`](windsurf/README.md)** — Rules file (prompt-level), `.windsurfrules` workspace-scoped
- **[`codex/`](codex/README.md)** — Awareness document, `AGENTS.md` integration, `$CODEX_HOME` or `~/.codex/` location
- **[`codex/`](codex/README.md)** — Native `PreToolUse` hook, `AGENTS.md` integration, `$CODEX_HOME` or `~/.codex/` location
- **[`opencode/`](opencode/README.md)** — TypeScript plugin, `zx` library, `tool.execute.before` event, in-place mutation
- **[`pi/`](pi/README.md)** — TypeScript extension, `tool_call` event, `isToolCallEventType` guard, in-place mutation, `~/.pi/agent/extensions/`
- **[`hermes/`](hermes/README.md)** — Python plugin, `pre_tool_call` hook, in-place terminal command mutation
Expand All @@ -54,7 +54,7 @@ Each agent subdirectory has its own README with hook-specific details:
| Gemini CLI | Rust binary (`rtk hook gemini`) | Transparent rewrite | Yes (`hookSpecificOutput`) |
| Cline / Roo Code | Custom instructions (rules file) | Prompt-level guidance | N/A |
| Windsurf | Custom instructions (rules file) | Prompt-level guidance | N/A |
| Codex CLI | AGENTS.md / instructions | Prompt-level guidance | N/A |
| Codex CLI | Rust binary (`rtk hook codex`) + AGENTS.md | Transparent rewrite for eligible single, non-mutating commands | Yes (`updatedInput`) |
| OpenCode | TypeScript plugin (`tool.execute.before`) | In-place mutation | Yes |
| Pi | TypeScript extension (`tool_call` event) | In-place mutation | Yes |
| Hermes | Python plugin (`pre_tool_call`) | In-place mutation | Yes |
Expand Down Expand Up @@ -157,6 +157,27 @@ Returns `{}` when no rewrite (Cursor requires JSON for all paths).

**No rewrite**: `{"decision": "allow"}`

### Codex CLI (Rust Binary)

**Input** uses the standard `PreToolUse` shape with Codex fields such as
`turn_id` and `tool_use_id`. For Bash calls, the command is in
`tool_input.command`.

**Output** (when rewritten):

```json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "RTK auto-rewrite",
"updatedInput": { "command": "rtk git status" }
}
}
```

Codex requires `permissionDecision: "allow"` whenever `updatedInput` is returned.

### OpenCode (TypeScript Plugin)

Mutates `args.command` in-place via the zx library:
Expand Down Expand Up @@ -240,9 +261,9 @@ New integrations must follow the [Exit Code Contract](#exit-code-contract) and [

| Tier | Mechanism | Maintenance | Examples |
|------|-----------|-------------|----------|
| **Full hook** | Shell script or Rust binary, intercepts commands via agent's hook API | High — must track agent API changes | Claude Code, Cursor, Copilot, Gemini |
| **Full hook** | Shell script or Rust binary, intercepts commands via agent's hook API | High — must track agent API changes | Claude Code, Cursor, Copilot, Gemini, Codex |
| **Plugin** | TypeScript/JS/Python plugin in agent's plugin system | Medium — agent manages loading | OpenCode, Hermes, Pi |
| **Rules file** | Prompt-level instructions the agent reads | Low — no code to break | Cline, Windsurf, Codex |
| **Rules file** | Prompt-level instructions the agent reads | Low — no code to break | Cline, Windsurf |

### Eligibility

Expand Down
25 changes: 24 additions & 1 deletion hooks/codex/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,29 @@

## Specifics

- Prompt-level guidance via awareness document -- no programmatic hook
- Native `PreToolUse` processor via `rtk hook codex`
- Transparent Bash command rewriting through `permissionDecision: "allow"` + `updatedInput`
- Hook registration in `.codex/hooks.json` (project) or `$CODEX_HOME/hooks.json` (global)
- `rtk-awareness.md` is injected into `AGENTS.md` with an `@RTK.md` reference
- Installed to `$CODEX_HOME` when set, otherwise `~/.codex/`, by `rtk init --codex`

Codex requires users to review and trust non-managed hooks through `/hooks` before
they run. Hook failures and unsupported commands produce no output, so the original
tool call continues unchanged.

Because Codex requires `permissionDecision: "allow"` when applying
`updatedInput`, RTK only rewrites a conservative set of single, non-mutating
commands transparently. Compound commands and commands that may change state pass
through unchanged so Codex retains its native approval behavior.

## Live verification

The opt-in smoke test starts a real Codex turn and may consume API credits. It
records the Codex version, asks Codex to issue a raw `git status --short`, and
uses an isolated tracking database to verify that `rtk git status --short`
actually executed:

```bash
rtk cargo build
RTK_CODEX_E2E=1 scripts/test-codex-hook-e2e.sh
```
5 changes: 5 additions & 0 deletions hooks/codex/rtk-awareness.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

**Usage**: Token-optimized CLI proxy for shell commands.

When installed with `rtk init --codex`, a trusted Codex `PreToolUse` hook
automatically rewrites eligible single, non-mutating Bash commands. These
instructions remain as a fallback for commands that retain Codex's native
approval flow and for shell paths that hooks do not intercept.

## Rule

Always prefix shell commands with `rtk`.
Expand Down
6 changes: 3 additions & 3 deletions src/hooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ LLM agent integration layer that installs, validates, and executes command-rewri
| Claude-MD (legacy) | `rtk init --claude-md` | 134-line RTK block | CLAUDE.md |
| Windsurf | `rtk init -g --agent windsurf` | `.windsurfrules` | -- |
| Cline | `rtk init --agent cline` | `.clinerules` | -- |
| Codex | `rtk init --codex` | RTK.md in `$CODEX_HOME` or `~/.codex` | AGENTS.md |
| Codex | `rtk init --codex` | RTK.md + hooks.json | AGENTS.md |
| Cursor | `rtk init -g --agent cursor` | Cursor hook | hooks.json |
| Pi | `rtk init --agent pi` | `.pi/extensions/rtk.ts` | -- |
| Hermes | `rtk init --agent hermes` | Python plugin in `~/.hermes/plugins/rtk-rewrite/` | `config.yaml` `plugins.enabled` |
Expand Down Expand Up @@ -89,13 +89,13 @@ Rules are loaded from all Claude Code `settings.json` files (project + global, i
| Cursor (rtk hook cursor) | Ready | `permission: "ask",` — users will be prompted when Cursor enforces the permission; in the meantime, allow |
| Gemini CLI (rtk hook gemini) | No (allow/deny only) | allow (limitation — no ask mode in Gemini) |
| Copilot CLI (rtk hook copilot) | No updatedInput | deny-with-suggestion (unchanged) |
| Codex | ask parsed but no-op | allow (limitation — fails open) |
| Codex (`rtk hook codex`) | No (`ask` is unsupported with `updatedInput`) | required `allow` only for eligible single, non-mutating commands; otherwise defer |

### Implementation

- `permissions.rs` — loads deny/ask/allow rules, evaluates precedence, returns `PermissionVerdict`
- `rewrite_cmd.rs` — maps verdict to exit code (consumed by shell hook)
- `hook_cmd.rs` — maps verdict to JSON `permissionDecision` field (Copilot/Gemini)
- `hook_cmd.rs` — maps rewrite decisions to each host's JSON protocol (Claude/Codex/Copilot/Gemini/Cursor/Droid)

## Exit Code Contract

Expand Down
2 changes: 2 additions & 0 deletions src/hooks/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub const BEFORE_TOOL_KEY: &str = "BeforeTool";

/// Native Rust hook command for Claude Code (replaces rtk-rewrite.sh).
pub const CLAUDE_HOOK_COMMAND: &str = "rtk hook claude";
/// Native Rust hook command for Codex CLI.
pub const CODEX_HOOK_COMMAND: &str = "rtk hook codex";
/// Native Rust hook command for Cursor (replaces rtk-rewrite.sh).
pub const CURSOR_HOOK_COMMAND: &str = "rtk hook cursor";
/// Native Rust hook command for Factory Droid.
Expand Down
Loading