Skip to content

feat(opencode): guard parity via tool.execute.before/after #321

Description

@thewrz

This was written agentically; verify its assertions:

Why

On Claude Code, agent-kit's PreToolUse/PostToolUse hooks provide the write-boundary guard and the paths-touched.ndjson forensic evidence that parallel-issues' cross-write Collect check depends on. Under OpenCode those hooks never fire, so a dispatched worker runs with no ownership-boundary evidence at all — the Collect check degrades to mtime archaeology.

What

  • Port the guard layer to OpenCode's typings-verified hooks: tool.execute.before (record + optionally refuse a content-bearing write whose target escapes the contracted worktree) and tool.execute.after (append the same paths-touched.ndjson record shape the Claude hooks write, so cross-write-check.sh consumes one format).
  • permission.ask hook: surface (not silently allow) out-of-boundary writes when interactive; degrade to record-only when unattended.
  • Scope guard logic to parse tool argv as data, matching the existing guards' data-vs-executed discipline (see the guard-class fixes Pinned-plugin-path hook matches quoted paths in data payloads, not just executed ones #299/post-receipt.sh and finding-ledger.sh address the same run directory two different ways #300 — do not regress into whole-command-text matching).
  • Reuse the guard shell helpers where possible by invoking them from the plugin ($ Bun shell) rather than reimplementing matching logic in JS; where JS-side matching is unavoidable, pin parity with fixture tests shared across both implementations.

Acceptance

  • A write inside the worktree under OpenCode produces a paths-touched.ndjson record identical in shape to the Claude-hook record (fixture diff test)
  • An out-of-worktree write is recorded and surfaced per the mode (interactive ask / unattended record)
  • cross-write-check.sh collect consumes OpenCode-produced evidence unchanged
  • Guard parity fixtures run against both implementations in CI
  • Unit tests pass; CI green

Blocked by the contract-injection slice (S3).

🤖 Co-authored by Claude Fable 5.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/skillsThe three skills and their proceduresenhancementNew feature or requestp2Wanted before public release

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions