[[task]]
agent = "opencode"
prompt = """Upgrade Gemini agent to streaming mode with native CLI flags.
## Changes to src/agent/gemini.rs
1. Change `streaming()` to return `true`:
```rust
fn streaming(&self) -> bool {
true
}
```
2. In `build_command`, change output format from `json` to `stream-json`, and add `-y` for auto-approve:
```rust
fn build_command(&self, prompt: &str, opts: &RunOpts) -> Result<Command> {
let mut cmd = Command::new("gemini");
cmd.args(["-o", "stream-json", "-y", "-p", prompt]);
if let Some(ref output) = opts.output {
let _ = output;
}
Ok(cmd)
}
```
Note: remove the `cmd.stderr(std::process::Stdio::null());` line since we want stderr for error detection now.
3. Implement `parse_event` to handle stream-json events. Gemini stream-json outputs these event types:
- `{"type":"text","content":"..."}` → Reasoning event with content text
- `{"type":"tool_call","name":"...","arguments":"..."}` → ToolCall event
- `{"type":"tool_result","name":"...","output":"..."}` → ToolCall event
- `{"type":"turn_complete","stats":{"models":[{"tokens":{"total":N,"input":N,"output":N},"model":"..."}]}}` → Completion event with tokens metadata
```rust
fn parse_event(&self, task_id: &TaskId, line: &str) -> Option<TaskEvent> {
let trimmed = line.trim();
if trimmed.is_empty() { return None; }
let v: serde_json::Value = serde_json::from_str(trimmed).ok()?;
let now = Local::now();
parse_stream_event(task_id, &v, now)
}
```
Add a `parse_stream_event` function that handles:
- `"text"` type → extract `content` or `text` field, return EventKind::Reasoning
- `"tool_call"` type → extract name + truncated args, return EventKind::ToolCall
- `"tool_result"` type → classify output (test/build/error patterns), return appropriate EventKind
- `"turn_complete"` type → extract token stats from `stats.models[0].tokens`, return EventKind::Completion with metadata `{"tokens": total, "model": model_name}`
- Other types → return None
4. Keep `parse_completion` as fallback but it won't be called for streaming agents.
5. Add `use serde_json::json;` import.
6. Update the `extract_response` function — it should also try extracting from stream-json format: look for the last `"text"` event and return its content.
7. Add tests:
- `parses_text_event` — verify text content extraction
- `parses_turn_complete_with_tokens` — verify token extraction from stats
## Changes to src/watcher.rs
In `watch_buffered`, the gemini-specific `extract_response` call is fine — it only triggers for non-streaming agents. Since gemini is now streaming, this code path won't be reached for gemini, but keep it for backward compatibility.
IMPORTANT: Only modify src/agent/gemini.rs. Do NOT touch other files."""
worktree = "v27-gemini-streaming"
verify = "auto"
context = ["src/agent/gemini.rs", "src/watcher.rs:watch_streaming,watch_buffered", "src/agent/opencode.rs:parse_json_event"]
[[task]]
agent = "opencode"
prompt = """Use native CLI flags for read-only and full-auto modes instead of prompt guards.
## Changes to src/agent/codex.rs
In `build_command`:
1. When `opts.read_only` is true, use native sandbox flag instead of prompt guard:
- Add `-s read-only` to the command args
- Remove the prompt prepend hack
2. When `opts.read_only` is false, add `--full-auto` for trusted autonomous execution:
This replaces the need for `--skip-git-repo-check` alone.
The build_command should look like:
```rust
fn build_command(&self, prompt: &str, opts: &RunOpts) -> Result<Command> {
let injected = templates::inject_codex_prompt(prompt, None);
let mut cmd = Command::new("codex");
if opts.read_only {
cmd.args(["exec", "--json", "-s", "read-only", &injected]);
} else {
cmd.args(["exec", "--json", "--full-auto", &injected]);
}
if let Some(ref dir) = opts.dir {
cmd.args(["-C", dir]);
}
Ok(cmd)
}
```
Note: `--full-auto` implies `--sandbox workspace-write` and auto-approvals. It replaces `--skip-git-repo-check`.
## Changes to src/agent/gemini.rs
In `build_command`, when `opts.read_only` is true, use `--approval-mode plan` instead of the default `-y` (yolo):
```rust
fn build_command(&self, prompt: &str, opts: &RunOpts) -> Result<Command> {
let mut cmd = Command::new("gemini");
if opts.read_only {
cmd.args(["-o", "stream-json", "--approval-mode", "plan", "-p", prompt]);
} else {
cmd.args(["-o", "stream-json", "-y", "-p", prompt]);
}
Ok(cmd)
}
```
Note: This requires the RunOpts to have `read_only` field which was added in v2.6.
## Changes to src/agent/opencode.rs
Keep the prompt guard approach for opencode (no native read-only flag exists). No changes needed.
## Changes to src/agent/cursor.rs
The cursor read-only change from v2.6 (using `--mode plan`) is already correct. No changes needed.
IMPORTANT: Only modify src/agent/codex.rs and src/agent/gemini.rs. Do NOT touch other files."""
worktree = "v27-native-flags"
verify = "auto"
context = ["src/agent/codex.rs:build_command", "src/agent/gemini.rs:build_command", "src/agent/mod.rs:RunOpts"]
[[task]]
agent = "opencode"
prompt = """Add codex output file capture using the native `-o` flag.
Codex CLI supports `-o <file>` / `--output-last-message <file>` which writes the agent's final response to a file. This is more reliable than parsing JSONL logs.
## Changes to src/agent/codex.rs
In `build_command`, when `opts.output` is Some, add the `-o` flag:
```rust
if let Some(ref output) = opts.output {
cmd.args(["-o", output]);
}
```
Add this AFTER the main args but BEFORE the `-C` dir flag.
The full build_command should look like:
```rust
fn build_command(&self, prompt: &str, opts: &RunOpts) -> Result<Command> {
let injected = templates::inject_codex_prompt(prompt, None);
let mut cmd = Command::new("codex");
if opts.read_only {
cmd.args(["exec", "--json", "-s", "read-only", &injected]);
} else {
cmd.args(["exec", "--json", "--full-auto", &injected]);
}
if let Some(ref output) = opts.output {
cmd.args(["-o", output]);
}
if let Some(ref dir) = opts.dir {
cmd.args(["-C", dir]);
}
Ok(cmd)
}
```
IMPORTANT: If the other v27 task already modified build_command, merge your changes into the new structure. Only modify src/agent/codex.rs. Do NOT touch other files."""
worktree = "v27-codex-output"
verify = "auto"
context = ["src/agent/codex.rs:build_command", "src/agent/mod.rs:RunOpts"]