Batch 1 (High severity): - Bug 1: --audit cat3 now checks .automaton/tasks/ paths - Bug 4: Verdict PASS/FAIL uses structured ## Status: line parsing - Bug 5: register-guards.sh checks .json/.jsonc, writes plugin key, strips comments - Bug 7: --can-edit/--scope-check path prefix uses os.sep boundary Batch 2 (Medium/Low severity): - Bug 2: migrate-project.sh find command parentheses for -prune binding - Bug 3: vram_detect model prefix matching with known-suffix whitelist - Bug 6: dashboard reads .state file before artifact heuristic fallback - Bug 8: removed wildcard CORS, added security headers (nosniff, DENY) - Bug 9: stale-task detection uses .state.lastedit instead of .state mtime - Bug 10: TEST_PLAN.md maps to test_design (was implement) 249 tests pass (up from 235). All 10 tasks driven through full workflow to completion.
5.4 KiB
Harness Integration Contract
This document defines the integration contract between the automaton framework and any agent harness (opencode, aider, cursor, etc.).
Enforcement Layers
The framework provides four enforcement layers, from strongest to weakest:
- Harness pre-edit hook (blocks edits before they happen) — primary enforcement
- Git pre-push hook (blocks pushes without a task — catches
--no-verifybypasses) - Git pre-commit hook (blocks commits without a task) — safety net
- Prompt-based rules (ALLOWED/FORBIDDEN sections in phase prompts) — advisory only
Layer 1: Harness Pre-Edit Hook
Before allowing any file edit, a harness MUST call:
python ~/.automaton/scripts/status.py --can-edit --project {project} [--file {path}] [--json]
Exit Codes
| Code | Meaning |
|---|---|
| 0 | ALLOWED — edits are permitted |
| 1 | DENIED — edits are not permitted |
| 2 | ERROR — invalid arguments or task not found |
Modes
-
--can-edit --project {p}(no--task, no--file)- Checks if ANY task in the project is in
implementordoc_reviewphase - Returns ALLOWED if at least one task is in an edit-allowed phase
- Returns DENIED if no tasks allow edits
- Checks if ANY task in the project is in
-
--can-edit --project {p} --file {path}(no--task)- Same as (1) but also verifies the file is within the project scope
- Returns DENIED if the file is outside the project directory
-
--can-edit --project {p} --task {t}(no--file)- Checks if a specific task is in an edit-allowed phase
- Returns DENIED if the task phase doesn't allow edits
-
--can-edit --project {p} --task {t} --file {path}- Same as (3) but also verifies file scope
JSON Output
Add --json to any --can-edit call to get a machine-readable JSON object on the last line of output:
python ~/.automaton/scripts/status.py --can-edit --project /my/project --json
Allowed response:
{"allowed": true, "reason": "edit_task", "primary_task": {"task": "my-feature", "phase": "implement"}, "all_edit_tasks": [...]}
Denied response:
{"allowed": false, "reason": "no_edit_tasks", "tasks": []}
Out of scope response:
{"allowed": false, "reason": "out_of_scope", "task": "my-feature", "phase": "implement", "file": "/outside/project/file.py"}
Layer 2: Git Pre-Commit Hook
A pre-commit hook blocks commits when no task is in an edit-allowed phase.
Installation
# Option 1: Copy directly
cp ~/.automaton/scripts/git-hooks/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
# Option 2: Symlink (preferred — auto-updates)
ln -s ~/.automaton/scripts/git-hooks/pre-commit .git/hooks/pre-commit
What it does
Checks status.py --can-edit --project {project}. If DENIED (exit code 1), the commit is blocked with instructions to create or transition a task.
Bypass
git commit --no-verify bypasses the hook. Use only when intentionally committing framework documentation or config changes that don't require a task.
Layer 3: Prompt-Based Rules
Each phase prompt includes ALLOWED/FORBIDDEN sections. These are advisory — they rely on the agent choosing to follow them. The harness pre-edit hook and pre-commit hook provide computational enforcement that these rules describe.
Harness-Specific Integration
opencode (pi)
opencode supports plugins with tool.execute.before hooks. A plugin is provided at
~/.automaton/plugins/automaton-guard/plugin.ts.
Installation (automatic):
The framework install/update scripts auto-register the plugin in
~/.config/opencode/opencode.json or opencode.jsonc. No manual steps needed.
Manual installation:
Add to your opencode.json (or opencode.jsonc):
{
"plugin": ["~/.automaton/plugins/automaton-guard"]
}
The plugin intercepts edit and write tool calls, runs status.py --can-edit --project {dir} --file {path} --json, and blocks the edit if DENIED. The agent receives a message explaining why the edit was blocked and how to proceed.
aider
Aider supports pre-edit hooks via its command system. Before each editing session:
python ~/.automaton/scripts/status.py --can-edit --project /path/to/project
If DENIED, aider should not proceed.
Cursor / Copilot / Cline
These tools do not currently support pre-edit hooks. For these, the git pre-commit hook is the primary enforcement mechanism. Configure your project's .git/hooks/pre-commit as described above.
Generic (any harness)
Any tool that can execute shell commands before file edits should:
- Before session start:
--can-edit --project {p}— verify at least one task allows edits - Before each file edit:
--can-edit --project {p} --file {path} --json— verify the specific file is in scope - On DENIED: block the edit and show the denial message to the user
Enforcement Coverage Matrix
| Harness | Pre-edit hook | Pre-push hook | Pre-commit hook | Prompt rules |
|---|---|---|---|---|
| opencode (pi) | Plugin | Symlink | Symlink | Yes |
| Pi Dev | Plugin | Symlink | Symlink | Yes |
| aider | Manual | Symlink | Symlink | Yes |
| Cursor | — | Symlink | Symlink | Yes |
| Copilot | — | Symlink | Symlink | Yes |
| Cline | — | Symlink | Symlink | Yes |
| Raw LLM API | — | Symlink | Symlink | Yes |
Pre-push and pre-commit hooks work universally because git is universal. Pre-edit hooks require harness support.