Skip to content

feat(harness): canonical dir model, unified permissions, incremental schema (Python)#689

Merged
santoshkumarradha merged 1 commit into
mainfrom
santoshkumarradha/python-app.harness-opencode-project_dir-cwd-sche
Jun 24, 2026
Merged

feat(harness): canonical dir model, unified permissions, incremental schema (Python)#689
santoshkumarradha merged 1 commit into
mainfrom
santoshkumarradha/python-app.harness-opencode-project_dir-cwd-sche

Conversation

@santoshkumarradha

Copy link
Copy Markdown
Member

Summary

Reworks the Python harness so the directory, permission, and schema-output contracts are consistent across all four providers (claude-code, codex, gemini, opencode) and match the Go SDK reference. Defined in Python first; TS/Go ports tracked separately.

Closes #684
Closes #686
Closes #687
Closes #688

1. Directory model (#684, #686)

project_dir is the canonical agent root; cwd is the process working dir. The schema output file always lands inside the agent root: when project_dir is set the runner writes it to an isolated temp dir under project_dir (mirrors the Go runner), so providers like OpenCode no longer reject it as an external_directory write.

2. Permissions (#687)

Canonical permission_mode contract: None (safe default) | "auto" (autonomous, no prompts) | "plan" (read-only).

  • codex: "auto"--sandbox workspace-write (was the now-deprecated --full-auto); "plan"--sandbox read-only.
  • gemini: "auto"--yolo (was --sandbox, which restricts execution — backwards); "plan"--approval-mode plan.
  • claude/opencode mappings unchanged.

Flags were verified against installed codex 0.141/gemini 0.40.1 binaries plus upstream source, not from memory.

3. Incremental schema (#688)

New schema_mode: "single" (default, unchanged) | "incremental" | "auto".

  • incremental instructs the agent to build the JSON object one top-level field at a time, and recovers by patching only the missing/invalid fields instead of re-running the whole task.
  • auto switches to incremental above the large-schema threshold.

project_dir and schema_mode are now first-class params on app.harness() and HarnessConfig.

Test plan

  • ruff check . clean (the blocking CI lint).
  • Full Python SDK suite: 1631 passed, 4 skipped (unrelated), 12 deselected (harness_live).
  • New regression tests:
    • opencode: project_dir wins as --dir; runner-level Python app.harness OpenCode project_dir/cwd schema output fails for nested workdir #684 repro (nested cwd under shared root) places output under project_dir and validates.
    • codex: project_dir is -C root; plan--sandbox read-only; --skip-git-repo-check present.
    • gemini: never emits -C; project_dir is the process cwd; auto--yolo; plan--approval-mode plan.
    • claude: project_dir used as SDK root over cwd.
    • incremental schema: incremental suffix selected; auto stays single-shot for small schemas; field-level recovery patches a missing required field on retry.
  • Diff kept minimal — no unrelated reformatting churn.

Not in this PR (follow-ups)

…schema (Python)

Reworks the Python harness directory, permission, and schema-output contracts
so they are consistent across all four providers and match the Go SDK.

Directory model (#684, #686):
- project_dir is the canonical agent root; cwd is the process dir. The schema
  output file always lands inside the agent root — when project_dir is set the
  runner places it in an isolated temp dir under project_dir (mirrors Go), so
  providers like OpenCode no longer reject it as an external-directory write.
- opencode: --dir prefers project_dir over cwd (was inverted, the #684 bug).
- codex: -C uses project_dir or cwd; added --skip-git-repo-check for non-repo
  working dirs.
- gemini: removed the -C flag, which gemini rejects outright ("Unknown
  argument: C") and crashed every call; the root is now the process cwd.
- claude-code: SDK cwd uses project_dir or cwd.
- Terminal schema errors now include effective provider/project_dir/cwd/output.

Permissions (#687):
- codex: "auto" -> --sandbox workspace-write (was the deprecated --full-auto);
  "plan" -> --sandbox read-only.
- gemini: "auto" -> --yolo (was --sandbox, which RESTRICTS execution and was
  backwards); "plan" -> --approval-mode plan.

Incremental schema (#688):
- New schema_mode: "single" (default) | "incremental" | "auto".
- incremental builds the JSON object one top-level field at a time and recovers
  by patching only the missing/invalid fields instead of a full re-run.
- auto switches to incremental above the large-schema threshold.

Adds project_dir and schema_mode to app.harness() and HarnessConfig.
Full harness test coverage for every provider's flag mapping and the
incremental field-recovery path.

Closes #684
Closes #686
Closes #687
Closes #688
@santoshkumarradha santoshkumarradha requested review from a team and AbirAbbas as code owners June 24, 2026 19:22
@github-actions

Copy link
Copy Markdown
Contributor

Performance

SDK Memory Δ Latency Δ Tests Status
Python 9.4 KB +4% 0.32 µs -9%

✓ No regressions detected

@github-actions

Copy link
Copy Markdown
Contributor

📊 Coverage gate

Thresholds from .coverage-gate.toml: per-surface ≥ 84%, aggregate ≥ 85%, max per-surface regression ≤ 1.0 pp, max aggregate regression ≤ 0.50 pp.

Surface Current Baseline Δ
control-plane 87.00% 87.40% ↓ -0.40 pp 🟡
sdk-go 91.80% 92.00% ↓ -0.20 pp 🟢
sdk-python 93.87% 93.73% ↑ +0.14 pp 🟢
sdk-typescript 90.05% 90.42% ↓ -0.37 pp 🟢
web-ui 84.82% 84.79% ↑ +0.03 pp 🟡
aggregate 85.62% 85.75% ↓ -0.13 pp 🟡

✅ Gate passed

No surface regressed past the allowed threshold and the aggregate stayed above the floor.

@github-actions

Copy link
Copy Markdown
Contributor

📐 Patch coverage gate

Threshold: 80% on lines this PR touches vs origin/main (from .coverage-gate.toml:thresholds.min_patch).

Surface Touched lines Patch coverage Status
control-plane 0 ➖ no changes
sdk-go 0 ➖ no changes
sdk-python 0 ➖ no changes
sdk-typescript 0 ➖ no changes
web-ui 0 ➖ no changes

✅ Patch gate passed

Every surface whose lines were touched by this PR has patch coverage at or above the threshold.

@santoshkumarradha santoshkumarradha merged commit ff6f043 into main Jun 24, 2026
32 checks passed
@santoshkumarradha santoshkumarradha deleted the santoshkumarradha/python-app.harness-opencode-project_dir-cwd-sche branch June 24, 2026 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant