Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- Added a Grok CLI provider for review, fix, revalidate, and doctor flows, thanks @ebastos.
- Added `--since <ref>` on `clawpatch review` and `clawpatch revalidate` to restrict runs to features whose owned or context files changed since the given git ref, thanks @mvanhorn.
- Added Flask route feature mapping for Python projects, including `web/` source roots, common root entry files, non-list method literals, and Python framework detection.
- Added the `acpx` provider for routing review, fix, and revalidate through ACP-compatible coding agents, thanks @mvanhorn.
- Added Next.js route mapping for `src/app` and `src/pages` layouts, thanks @obatried.
- Added first-pass Python mapping for project metadata, console scripts, source groups, pytest suites, and conservative validation defaults, thanks @xiamx.
- Added progress output for `clawpatch revalidate`, thanks @twidtwid.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ working tree during the explicit fix command.
Supported provider names today:

- `codex`: local Codex CLI
- `acpx`: any ACP-compatible coding agent (Codex / Claude / Pi / Gemini / ...) via openclaw/acpx
- `grok`: local Grok Build CLI
- `mock`: deterministic test provider
- `mock-fail`: failure test provider

Direct OpenAI, Claude, Gemini, and provider panels are not implemented yet.

## Commands

- `clawpatch init`: create `.clawpatch/`, detect project basics, write config
Expand Down
75 changes: 54 additions & 21 deletions docs/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ clawpatch doctor
Provider names today:

- `codex`: shells out to `codex exec` (default)
- `acpx`: routes through any ACP-compatible coding agent via `acpx`
- `grok`: shells out to the xAI Grok Build CLI in headless mode (`grok --prompt-file`)
- `mock`: deterministic provider for tests and fixtures
- `mock-fail`: failure provider for tests

### Codex
## Codex

Codex invocation:

Expand All @@ -28,19 +29,58 @@ Codex invocation:
- output: strict JSON schema via `--output-schema`
- final message capture: `--output-last-message`

### Grok
Model selection:

The `grok` provider shells out to the local [Grok Build CLI](https://x.ai/cli)
```bash
clawpatch review --model <model>
CLAWPATCH_MODEL=<model> clawpatch review
```

## ACPX

The `acpx` provider routes through `acpx <agent> exec`, where `<agent>` is any
ACP-compatible coding agent.

- review / revalidate: `--approve-reads` plus an explicit read-only prompt directive
- fix: `--approve-all`
- output: `--format json --json-strict --suppress-reads`, parsed from known ACP NDJSON envelope kinds
- tested envelope shape: `acpx@^0.8.0`

Permission caveat: `acpx --approve-all` is not the same as `codex --sandbox
workspace-write`. Codex's workspace-write mode is an enforced sandbox. ACPX
approval flags control ACP permission prompts; the underlying agent still has
whatever filesystem and network access its own runtime grants. For untrusted
code, run `clawpatch fix --provider acpx` inside an isolated checkout. For
review and revalidate, strict read-only behavior still depends on the underlying
agent honoring read-only permissions and the prompt directive.

Agent selection uses `--model` as `<agent>` or `<agent>:<model>`, split on the
first colon:

- unset: agent `codex`, default model
- `codex`: agent `codex`, default model
- `claude`: agent `claude`, default model
- `claude:sonnet-4-5`: agent `claude`, model `sonnet-4-5`
- `ollama:llama3:70b`: agent `ollama`, model `llama3:70b`

Migration note: `--provider codex --model gpt-5-codex` is not equivalent to
`--provider acpx --model gpt-5-codex`; the latter selects an ACP agent named
`gpt-5-codex`. Use `--provider acpx --model codex:gpt-5-codex`.

## Grok

The `grok` provider shells out to the local [Grok Build CLI](https://x.ai/cli).

Install the Grok CLI:

```bash
curl -fsSL https://x.ai/cli/install.sh | bash
```

Then ensure `grok --version` works and authenticate using the flow supported by the local Grok CLI.
Then ensure `grok --version` works and authenticate using the flow supported by
the local Grok CLI.

**Provider selection:**
Provider selection:

```bash
clawpatch review --provider grok
Expand All @@ -49,21 +89,14 @@ clawpatch fix --finding <id> --provider grok --model grok-build
clawpatch doctor --provider grok
```

**Model selection** (works for both `codex` and `grok`):

```bash
clawpatch review --model <model>
CLAWPATCH_MODEL=<model> clawpatch review
```

#### How the grok provider works
How the Grok provider works:

- **Headless mode**: Uses `--prompt-file` + `--output-format json --always-approve --verbatim --cwd <root>`.
- **Read-only operations** (`review`, `revalidate`): Adds `--disallowed-tools "search_replace,run_terminal_cmd,Agent"` so the agent cannot modify files or run shell commands.
- **Write operations** (`fix`): Uses full `--always-approve` so the agent can edit files and run validation commands.
- **Structured output**: The inner prompt includes clawpatch's JSON schema. The provider parses the text field of the JSON envelope returned by `--output-format json` and validates it with Zod (same schemas used for Codex).
- **Large prompts**: Review and fix prompts can be tens of kilobytes (they embed the full source of owned and context files). Passing such prompts via `-p`/`--single` is unreliable, so the provider always uses `--prompt-file` (the intended mechanism for automation and large inputs).
- Headless mode: `--prompt-file` plus `--output-format json --always-approve --verbatim --cwd <root>`
- Read-only operations: adds `--disallowed-tools "search_replace,run_terminal_cmd,Agent"`
- Write operations: uses full `--always-approve` so the agent can edit files and run validation commands
- Structured output: validates the returned JSON against the same Zod schemas used for Codex
- Large prompts: always uses `--prompt-file` instead of passing prompt text on the command line

Direct OpenAI, Claude, Gemini, local-model, and multi-model panel providers are
not implemented yet. The `grok` provider uses the local `grok` binary for the
best integration with the surrounding Grok Build environment.
Direct OpenAI API, local-model, and multi-model panel providers are not
implemented yet. The `acpx` provider is the generic route for ACP-compatible
agents; the `grok` provider is a direct integration for the local Grok CLI.
6 changes: 5 additions & 1 deletion docs/safety.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ Current safety rules:
- `fix` requires explicit `--finding <id>`.
- `fix` refuses a dirty source worktree by default.
- `.clawpatch/` state changes are allowed during runs.
- review and revalidate provider calls use a read-only sandbox.
- review and revalidate provider calls use a read-only sandbox for the `codex`
provider. The `acpx` provider relies on `acpx --approve-reads` plus an explicit
read-only prompt directive; underlying agents that bypass ACP permissions (e.g.
agents running in their own full-access mode) may not be strictly sandboxed.
See docs/providers.md.
- provider output must pass runtime schema validation.
- feature locks are stored in feature records and `.clawpatch/locks/`; `status`
surfaces both, and `clean-locks` clears both.
Expand Down
17 changes: 15 additions & 2 deletions src/exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ export async function runCommand(
cwd: string,
input?: string,
options: { trimOutput?: boolean } = {},
): Promise<CommandResult> {
const result = await runCommandRaw(command, cwd, input);
return {
...result,
stdout: options.trimOutput === false ? result.stdout : trimOutput(result.stdout),
stderr: options.trimOutput === false ? result.stderr : trimOutput(result.stderr),
};
}

export async function runCommandRaw(
command: string,
cwd: string,
input?: string,
): Promise<CommandResult> {
const started = Date.now();
const child = spawn(command, {
Expand Down Expand Up @@ -47,8 +60,8 @@ export async function runCommand(
cwd,
exitCode,
durationMs: Date.now() - started,
stdout: options.trimOutput === false ? stdout : trimOutput(stdout),
stderr: options.trimOutput === false ? stderr : trimOutput(stderr),
stdout,
stderr,
};
}

Expand Down
Loading