Agent Harness Tooling: 10 Friction Points From a Real Session

Observed during multi-PR turn-title/sidebar work (Sept 2026) on a hub-based multi-agent codebase. Each item: the pain, a concrete example, and how mainstream harnesses handle it.

0. Overview

#FrictionHow others handle it
1Single-command shell, no persistent cwdAnthropic bash_20250124: one long-lived bash process; cd/env persist; restart:true resets
2No CI wait primitive (blind sleep polling)Claude Code background jobs + output polling; Weng Pattern 3: explicit process manager (launch/inspect/cancel/merge)
3Exact-match Edit only, no fuzzy/patch modeSpectrum: exact (Claude Code) -> fuzzy 9-pass chain (Aider) -> structured apply_patch blocks (OpenAI/Cursor); Cursor trained a 70B edit model
4Rebase needs GIT_EDITOR=true workaroundHarnesses wrap git in non-interactive helpers; env preset (GIT_EDITOR=true, --no-edit)
5Fresh .venv per throwaway clone (175 pkgs)Shared/sandbox-cached envs; lint+typecheck as post-edit hooks in the same env
6Read needs exact path+offset (search-then-read = 2 turns)Cursor/Cline bundle grep+context lines into one retrieval step
7Clone+config+checkout boilerplate per task (~5 cmds)Codex: git worktrees (detached HEAD, no branch pollution) or ephemeral containers; one scaffold call
8Sandbox banner on every success reads as failureAnthropic: structured tool_result with is_error flag; warnings separated from errors
9No fixture helper (orphan-file rule bit me)Repo-aware test-data helpers encoding storage invariants
10Manual rm -rf clone cleanupEphemeral workspaces; auto-cleanup on push/merge

1. Single-command shell, no persistent cwd

pain One command per bash call; working_dir resets every call. Multi-step flows (clone + config + checkout + test) become one long && chain or N round trips.

example git clone ... /private/tmp/pr-x then re-specifying working_dir=/private/tmp/pr-x on every later call; a forgotten param runs the command in the wrong tree.

elsewhere Anthropic's bash_20250124 doc: the harness owns one long-lived bash process (sentinel-line framing, own process group for timeout kills). cd /tmp && pwd then pwd still shows /tmp. SWE-agent/mini-SWE-agent deliberately chose the opposite: stateless single commands, no persistence needed. This hub is SWE-agent-like, so anything multi-step feels chained.

2. No CI wait primitive

pain After pushing, checks take minutes; only snapshot polling (gh pr checks) exists. Burned turns on sleep 90 then sleep 120 then re-query.

elsewhere Claude Code has run_in_background + output polling; Lilian Weng's harness survey (Pattern 3: sub-agents and backend jobs) recommends an explicit process manager - launch, inspect logs, cancel, merge results - instead of blocking turns on sleep.

3. Exact-match Edit only

pain Edit requires byte-exact old_string. One rebase-conflict hunk failed with old_str not found over invisible whitespace; required a Read + retry cycle.

elsewhere Known spectrum (Weng survey lists write/edit/multi_edit/apply_patch as the standard set): exact match (Claude Code str_replace) -> fuzzy match (Aider's multi-pass chain, whitespace-tolerant) -> structured diff (apply_patch with *** Begin Patch blocks). Cursor trained a separate 70B model just for instant edit application. There is even an open Claude Code feature request for hash-based line addressing plus automatic fuzzy fallback.

4. Rebase interactivity trap

pain git rebase --continue opens an editor; headless shells hang. Workaround: GIT_EDITOR=true git rebase --continue.

elsewhere Harnesses wrap git in non-interactive helpers with the env preset. Minor, but it cost a turn to discover.

5. Fresh venv per clone

pain uv run pyright inside a fresh /private/tmp clone created a new .venv and installed 175 packages (~1 min) just to typecheck. The source tree already has a venv; clones cannot reuse it.

elsewhere Most harnesses run lint/typecheck as a post-edit hook inside the same sandbox env (shared venv). Fix direction: shared venv path or remote typecheck service.

6. Search-read coupling (the big one)

pain Read needs exact path+offset, so locating code is always git grep (turn N) then Read (turn N+1). Since Edit needs byte-exact text, the Read is a mandatory toll turn before every edit; the project rule (separate git grep, never plain grep) guarantees ≥2 calls per edit.

example Finding the turn-title resolver took 3 turns: grep get_untitled_turn_message_ids (6 hits) -> Read message_data_manager.py:296-319 -> Read router.py:93-137 -> then a 4th turn to Edit.

elsewhere Cursor/Cline return each hit with surrounding lines in one retrieval step - enough context to issue the edit immediately. IDE-bench measured agents edit within a turn of reading ~37% of the time; read is usually a prelude to edit, so splitting them doubles turns on the most common loop.

7. Clone boilerplate

pain Project rules demand per task: git clone + remote set-url (SSH, not HTTPS) + user.name/email + checkout -b. Five commands before any real work.

elsewhere OpenAI Codex uses git worktrees (detached HEAD per task, no branch pollution) or ephemeral per-task containers; Claude Code supports per-agent worktrees for parallel work. Same isolation goal, one scaffold call instead of five. A scaffold_clone(instance_id, branch) tool would do here.

8. Sandbox banner noise

pain Every shell success returned Error-Message: Shell sandbox NOT available ... run unsandboxed alongside Status-Code: 0. Reads as failure; forced a double-check every call.

elsewhere Anthropic's tool-result protocol separates this cleanly: output content plus an explicit is_error flag. Warnings should be a warning field, never error text on success.

9. No fixture helper

pain Verifying local set_turn_title needed hand-built Message objects with microsecond ids - plus discovering that files without a .context.jsonl sibling are skipped as orphans (_jsonl_listing.py), so the first fixture silently returned nothing (StopIteration).

elsewhere Repo-aware test-data helpers that encode storage invariants (id scheme, sidecar files, orphan rules) so verification fixtures work first try.

10. Manual clone cleanup

pain The per-agent dir convention relies on remembering rm -rf at the end. A turn erroring mid-way leaves a stale clone; the next attempt must handle "already exists".

elsewhere Ephemeral workspaces with auto-cleanup on push/merge (Codex Cloud model: container per task, destroyed after).

References