You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add an optional PreToolUse hook check — sibling to hooks/path-guard.js, reusing its exact enforcement point — that syntax-checks the result of a write-tool call (Edit/Write/MultiEdit) before it lands on disk, and denies (exit 2) the individual tool call if the edit would leave the file syntactically invalid. This is a per-call, mechanical, parse-only gate — cheaper and earlier than either of the two "did the task succeed" checks already proposed for this repo.
Landscape basis
SWE-agent's Agent-Computer Interface (arXiv 2405.15793, docs/background/aci.md): the edit command runs a linter (flake8 for Python) before applying the edit and refuses the edit outright if the result isn't syntactically valid — "does not let the edit command go through if the code isn't syntactically correct." This is described as the single most-imitated idea in coding-agent scaffolds today.
Neither operates at the individual tool-call boundary. Both can only detect a broken build after the worker has already finished and handed back a result — by then a multi-file edit sequence may have compounded a syntax break across several files, and the caller only learns about it from the final report. SWE-agent's ACI instead blocks the specific malformed edit synchronously, the same instant it would be written — architecturally identical to how path-guard.js already blocks a specific out-of-root write synchronously. No existing issue proposes this per-call, pre-write mechanism (confirmed: no open/closed issue matches "syntax" or "PreToolUse" + "edit" combined).
Proposed design
New pure module src/syntax-guard.js, mirroring src/path-guard.js's shape: given (toolName, toolInput), compute the resulting file content the write would produce (Edit/MultiEdit's old_string/new_string diff applied in-memory, Write's content directly) and run a fast, parse-only check keyed by file extension — no linting, no build, no tests (that's idea: post-do validation gate — declarative validators in agent.json run after do-mode tasks #509's job). Start narrow: .json via JSON.parse, .js/.mjs/.cjs via node --check (or node:vm's Script constructor, sourceless, no execution) — extensible registry, silently skip unrecognized extensions (never block what it can't parse).
hooks/path-guard.js (or a new sibling hook wired the same way in the do-mode --settings temp file) calls this check after the existing path/protected-config checks pass, same stdin payload, same deny()/allow() shape, same denial audit log.
Opt-in via agent.json manifest (x-agentmesh.syntaxGuard: true, default false) — matches idea: post-do validation gate — declarative validators in agent.json run after do-mode tasks #509's opt-in shape so no peer's behavior changes unless it asks in. A denied call is not a task failure: like an out-of-root path-guard denial, the worker sees the hook's stderr and can self-correct within the same session (no framework-level auto-retry — the invariant is upheld the same way path-guard already upholds it today).
Security / invariants
No new write surface: purely an additional synchronous denial path on the existing PreToolUse hook, same as path-guard.
Anti-spoof: the check reads only the tool's own tool_input, never caller-supplied bookkeeping fields.
No Bash-in-do concern: applies only to WRITE_TOOLS (Edit/Write/MultiEdit/NotebookEdit), which are already the sole write surface.
Fail-open on unsupported/unparseable-by-design file types (never false-block a .md/.py/binary write because the checker doesn't know that language) — matches the repo's "failure is data, not a silent block" spirit by scoping strictly to what it can prove is broken.
Dedup confirmation
Searched all open/closed issues for "syntax", "lint", "PreToolUse" (2026-07-28). #509 and #825 are the nearest matches and are cited above as explicitly distinct (post-task vs. per-call; mechanical-command vs. parse-only vs. semantic-review). No issue proposes a pre-write, tool-call-level syntax gate.
Summary
Add an optional PreToolUse hook check — sibling to
hooks/path-guard.js, reusing its exact enforcement point — that syntax-checks the result of a write-tool call (Edit/Write/MultiEdit) before it lands on disk, and denies (exit 2) the individual tool call if the edit would leave the file syntactically invalid. This is a per-call, mechanical, parse-only gate — cheaper and earlier than either of the two "did the task succeed" checks already proposed for this repo.Landscape basis
editcommand runs a linter (flake8 for Python) before applying the edit and refuses the edit outright if the result isn't syntactically valid — "does not let the edit command go through if the code isn't syntactically correct." This is described as the single most-imitated idea in coding-agent scaffolds today.Gap vs. the two existing validation ideas
This repo already has two adjacent, but mechanically distinct, proposals in the backlog:
agent.jsonvalidator commands (lint/test) once, after the whole do-mode task completes. Opt-in, no re-edit loop (explicitly rejects Aider's auto-retry to preserve "failure is data").Neither operates at the individual tool-call boundary. Both can only detect a broken build after the worker has already finished and handed back a result — by then a multi-file edit sequence may have compounded a syntax break across several files, and the caller only learns about it from the final report. SWE-agent's ACI instead blocks the specific malformed edit synchronously, the same instant it would be written — architecturally identical to how
path-guard.jsalready blocks a specific out-of-root write synchronously. No existing issue proposes this per-call, pre-write mechanism (confirmed: no open/closed issue matches "syntax" or "PreToolUse" + "edit" combined).Proposed design
src/syntax-guard.js, mirroringsrc/path-guard.js's shape: given(toolName, toolInput), compute the resulting file content the write would produce (Edit/MultiEdit'sold_string/new_stringdiff applied in-memory,Write'scontentdirectly) and run a fast, parse-only check keyed by file extension — no linting, no build, no tests (that's idea: post-do validation gate — declarative validators in agent.json run after do-mode tasks #509's job). Start narrow:.jsonviaJSON.parse,.js/.mjs/.cjsvianode --check(ornode:vm'sScriptconstructor, sourceless, no execution) — extensible registry, silently skip unrecognized extensions (never block what it can't parse).hooks/path-guard.js(or a new sibling hook wired the same way in thedo-mode--settingstemp file) calls this check after the existing path/protected-config checks pass, same stdin payload, samedeny()/allow()shape, same denial audit log.agent.jsonmanifest (x-agentmesh.syntaxGuard: true, defaultfalse) — matches idea: post-do validation gate — declarative validators in agent.json run after do-mode tasks #509's opt-in shape so no peer's behavior changes unless it asks in. A denied call is not a task failure: like an out-of-root path-guard denial, the worker sees the hook's stderr and can self-correct within the same session (no framework-level auto-retry — the invariant is upheld the same way path-guard already upholds it today).Security / invariants
tool_input, never caller-supplied bookkeeping fields.WRITE_TOOLS(Edit/Write/MultiEdit/NotebookEdit), which are already the sole write surface..md/.py/binary write because the checker doesn't know that language) — matches the repo's "failure is data, not a silent block" spirit by scoping strictly to what it can prove is broken.Dedup confirmation
Searched all open/closed issues for "syntax", "lint", "PreToolUse" (2026-07-28). #509 and #825 are the nearest matches and are cited above as explicitly distinct (post-task vs. per-call; mechanical-command vs. parse-only vs. semantic-review). No issue proposes a pre-write, tool-call-level syntax gate.
Sources