(MOT-3873) feat: native code mode for the harness#423
Conversation
- coder::update-file gains { op: "str_replace", old_str, new_str,
replace_all? }: exact-literal replacement desugared onto the existing
content-op machinery (escaped-literal regex + $$-escaped replacement).
Without replace_all the op requires exactly one occurrence and fails
C210 (nothing written) on 0 or N matches with prescriptive recovery;
replace_all replaces every occurrence (>=1 required).
- new coder::context: one-call workspace snapshot (allowed roots,
platform, bounded git branch/status/log, AGENTS.md / CLAUDE.md
instruction files capped at 16 KiB) for seeding coding sessions;
git state degrades to null on non-repo roots or missing git binary.
- wire-schema goldens regenerated; catalog grows to 10 functions.
…dentity - new send/spawn mode "code": replaces the mesh identity prompt with a dedicated coding identity (prompts/code.txt) — read-before-edit, str_replace edit discipline, verify-via-tests, no-commit-unless-asked. - code mode without an explicit functions policy defaults to the curated coding surface natively exposed (coder::*, shell::exec/exec_bg/kill/ status); an explicit caller policy always wins, and spawned children still narrow through subset_policy. - code-mode turns fetch coder::context once per turn (jail-scoped via the trusted fs_scope stamp) and append a rendered <environment> block (root, platform, git state, AGENTS.md/CLAUDE.md) to the system prompt; an unavailable coder surface logs and proceeds without the block. - send/spawn wire schemas gain the "code" mode enum value (goldens).
Adds 'code' to the mode picker. A code-mode send omits the explicit functions policy so the harness applies its curated native coding toolset, and swaps in the coding identity prompt; the working-dir fs_scope metadata is unchanged.
…rimary The workspace snapshot ignored the harness-stamped filesystem scope and always described the configured primary root, so a scoped session's git state and instruction files were missing. The effective root is now the canonicalized fs_scope root (session_root confinement) when present, and instruction files resolve through resolve_opt against it.
…edundant coder::context
Adds the apply_patch (V4A) format codex-family models are trained on: *** Begin/End Patch with Add/Delete/Update File hunks, @@ context markers, optional Move to, and End of File pinning. seek_sequence and the replacement engine are ported from OpenAI's codex-rs apply-patch crate (Apache-2.0) so context matching (exact -> rstrip -> trim -> unicode-normalised) matches the reference; the parser is a compact re-implementation pinned by the reference test cases. All-or-nothing: every hunk resolves through the jail and computes before anything is written (context mismatch fails C210 with re-read guidance, filesystem untouched); writes land atomically per file and modified files return a bounded echo of the first changed region.
Git worktree lifecycle for isolated sub-agent workspaces: worktree-add creates .worktrees/<name> on branch wt/<name> from the effective root's HEAD (fs_scope-aware, name-validated, requires a git work tree); worktree-remove is clean-only — uncommitted changes keep the worktree in place and are reported dirty, and the wt/<name> branch is deleted only when fully merged so unlanded child work survives for the caller to merge. Catalog grows to 13.
- spawn options gain isolation: "worktree" (dispatch path): the child gets its own git worktree via coder::worktree-add before seeding, its fs_scope root points at it, and the worktree rides the parent's call checkpoint. On child completion (including sweep-expired children, which route through the same deliver path) the harness removes the worktree clean-only and appends a disposition note to the parent's result: merge wt/<name>, inspect a dirty tree, or nothing to do. - code mode selects a per-family identity: openai/openai-codex route to prompts/code-gpt.txt (apply_patch edit discipline); openai-codex now maps to the Gpt prompt family. Both code prompts gain a delegation section (spawn + worktree isolation + merge guidance). - code_mode_policy adds harness::spawn to the native surface.
Shipped default rules gain structured, auto-scoped allows for the read-only coder functions (context / info / read-file / search / tree / list-folder), so an auto-mode coding session prompts on writes and exec instead of every read. Manual mode is unaffected — mode-scoped rules do not match there — and writes (update-file, apply-patch, create/delete/ move, worktree-*) plus shell::exec still gate in every mode. default_rule_values() is now the single source of truth for both the compiled default specs and the configuration schema default, and the rules schema items widen to oneOf string|structured so the shipped structured defaults pass configuration::register validation.
…writes
CoderConfig gains post_write_checks ({match_glob, command, timeout_ms},
default empty, hot-reloads like every coder knob): after a successful
coder::update-file / create-file / apply-patch write, each configured
check whose glob matches a written file's root-relative path runs ONCE
per call (deduplicated by command) via /bin/sh -c with the effective
root as cwd, and its bounded (4 KiB) output lands in the response's
top-level checks array. A failing, timing-out, or unrunnable check
never fails the edit — it is feedback for the caller to act on.
Config-sourced on purpose: workspace files must not choose commands.
Also promotes the fs_scope effective-root convention into
PathResolver::effective_root (context/worktree/checks now share it),
and both harness code prompts tell the model to read the checks array.
The code prompt's no-commit rule left isolated children's worktrees dirty, so clean-only removal kept them and the parent had nothing on wt/<name> to merge. A worktree spawn now appends an explicit commit instruction to the child's task — the sanctioned exception that makes the branch the handoff artifact.
…atch
- harness: a send (or parentless spawn) that omits provider resolves it
from the router's model catalog before options freeze, so prompt-family
selection and routing agree — headless codex sends now get the
apply_patch code identity without passing provider explicitly. Router
unreachable → warn and fall back to the previous default-family
behavior.
- provider-openai-codex: coder::apply-patch travels as a freeform custom
tool named exactly apply_patch — the trained name and shape. The wire
emits { type: custom }, and the SSE state machine accumulates
custom_tool_call raw input (delta + authoritative done) into
{ patch: <raw text> }, so patches cross the wire with no JSON escaping.
Harness and shell still see an ordinary coder::apply-patch call.
Every mutating coder call (update-file, create-file, delete-file, move, apply-patch) records bounded before-images into a per-root journal (journal.dir / max_bytes 64MiB / max_records 500, hot-reloading, oldest-first eviction, raw-byte blob sidecars — binary-safe). The harness fs_scope stamp gains session_id/turn_id so records attribute to the turn that wrote them. coder::undo reverts the last N records or everything a turn changed: restores run newest-first, every path re-validates through the LIVE jail, files that did not pre-exist are removed, and the undo journals its own pre-undo state first — undoing an undo redoes the change. Unrecoverable gaps (oversized images, directory deletes/moves) are reported in skipped, never silently ignored. coder::checkpoints lists the journal (newest first) as the undo picker. Catalog grows to 15.
Full-list-replace todo semantics for multi-step coding runs: at most 50 items / 500 chars, exactly one in_progress, persisted to the harness_todo state scope and mirrored into custom session entries (type "todo", fresh entry id per update — session::append is a no-op on repeated ids). In-turn calls get the CALLING session injected at the invocation chokepoint, so a model can never write another session's list. code_mode_policy gains harness::todo and both code prompts teach the discipline; the console renders the latest todo entry as a live checklist card (done-count header, status glyphs).
router::models::get requires a provider hint, so a provider-less send resolved to None (default prompt family) — scan router::models::list by model id instead.
Models trained on TodoWrite-shaped todo tools send { todos: [{ content,
status }] }; serde aliases (todos->items, content->text) accept both
spellings, extra fields like activeForm are ignored as before.
A live code-mode session spent ~30 of 66 minutes on standalone harness::todo round trips (40 updates x ~45s of reasoning each) and most call batches carried a single call. Function execution itself measured milliseconds; the cost is round trips. - Both code prompts now require todo updates to ride along with the next action calls (never a standalone message) and push the model to batch independent calls into one message. - The dispatch loop runs in three phases: sequential policy/pre-hook/ checkpoint pass, concurrent invoke for consecutive parallel-safe calls (read-only coder surface + bookkeeping via join_all), then in-order post-hook/append/done. Mutations and shell::exec stay strictly sequential. All Triggered checkpoints land in ONE durable write before any invoke, preserving at-most-once recovery.
The 256-char excerpt clip made held coder writes unreviewable — a clipped patch can't render as a diff in the approval card. Excerpts are now function-aware: the five coder write functions keep their full arguments (secret-key redaction still applies) under a 64 KiB budget that falls back to classic clipping; everything else clips as before.
…g default Add a checkpoints dialog to the chat working-dir footer that lists the shell's file-mutation journal newest-first, grouped per turn, and reverses a group with one coder::undo call. Records authored by coder::undo are labeled "revert" and offer "redo". The trigger is disabled until a working directory is set. Also default the composer's thinking level to medium.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 42 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (98)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
# Conflicts: # harness/src/functions/spawn.rs # harness/src/subagent.rs
skill-check — worker0 verified, 33 skipped (no docs/).
Four for four. Nicely done. |
…te-aware times Dialog-initiated undos were journaled without turn attribution, so their revert rows could only be redone while newest (every older redo button rendered dead). The dialog now stamps each undo with a unique console-undo turn id, making every revert row targetable. Timestamps gain a date prefix once a record is from another day — time-only rendering made yesterday's entries read as mis-sorted.
…o "now" The silent model-key migration stamped updatedAt on every conversation whose stored model was missing from the current catalog, so a catalog change made the whole sidebar read "now" and scramble on each refresh. Migration keeps the model rewrite but leaves updatedAt untouched — ordering stays user-activity-driven.
# Conflicts: # console/web/src/hooks/use-conversations.ts
The write journal is per-workspace-root and shared by every session using that directory, so the dialog listed other chats' (and CLI) records under a description promising "this conversation". Records now filter by the conversation's session id, dialog undos stamp session attribution so their redo records stay in view, and undo always targets a turn — a global steps-undo from a filtered list could have reverted another session's newest change.
Native code mode for the harness, consolidated from the stacked branch train (#409–#422) into one reviewable PR.
Shell
str_replaceop oncoder::update-file(exact-literal, unique-match guard) andcoder::context(workspace snapshot: roots, platform, git, instruction files)coder::apply-patch(V4A patch format, all-or-nothing) +coder::worktree-add/coder::worktree-removepost_write_checks: config-sourced report-only diagnostics appended to write resultscoder::undo(by steps or turn; undo-of-undo = redo) +coder::checkpointsHarness
Mode::Code: coding system prompt, native exposure of the coder/shell surface, per-turn<environment>blockharness::spawngainsisolation:"worktree"(child works on an isolated branch and commits; parent gets a disposition note)harness::todosession checklist (full-replace semantics, live console card, TodoWrite-shaped payloads accepted)Provider (openai-codex)
coder::apply-patchemitted as the freeformapply_patchcustom tool — raw patch text on the wire, custom_tool_call SSE handlingApproval gate
Console
codemode picker; coder views for apply-patch diffs, check badges, context/worktree cards; live todo checklist cardFixes MOT-3873
Fixes MOT-3874
Fixes MOT-3875
Fixes MOT-3876
Fixes MOT-3877