When Claude Code writes a file, it reports success based on the tool call completing. But tool calls can silently fail — partial writes, encoding issues, permission errors that get swallowed. x closes this gap with a three-stage verification pipeline.
The verification pipeline
Every file write in x passes through three stages before it's considered successful:
- Pre-write snapshot — Before any write, x captures a SHA-256 hash of the target file (or notes it doesn't exist yet). This is the rollback anchor.
- Post-write verification — After the write tool returns, x re-reads the file from disk and hashes it. The new hash must differ from the pre-write hash (confirming something changed) and the content must match what the agent intended.
- AST validation — For supported languages, x parses the written file through Tree-sitter. If parsing fails (syntax error), the write is flagged and the agent is notified in the same turn.
// Simplified from the actual implementation const before = hashFile(targetPath); const result = await claudeWrite(targetPath, content); const after = hashFile(targetPath); if (before === after) { // Write was silently dropped — file unchanged agent.notify("WRITE_FAILED_SILENT", targetPath); return rollback(targetPath, before); } const ast = treeSitterParse(targetPath); if (ast.hasErrors) { agent.notify("WRITE_SYNTAX_ERROR", ast.errors); }
Failure modes
The pipeline catches three categories of failure:
- Silent drops — The write tool reports success but the file is unchanged. This happens with permission issues, disk-full conditions, or tool-call serialization bugs. x detects the identical hash and rolls back.
- Partial writes — The file changed but the content doesn't match intent. x compares the written content against the expected content and flags discrepancies.
- Structural errors — The file was written successfully but contains syntax errors. Tree-sitter catches these before the agent continues building on broken code.
What happens on failure
When verification fails, x does not silently continue. The agent receives a structured error in its context window, including:
- The file path that failed
- The failure type (
WRITE_FAILED_SILENT,WRITE_CONTENT_MISMATCH,WRITE_SYNTAX_ERROR) - The pre-write content hash (for rollback reference)
- For syntax errors: the specific parse errors with line numbers
This lets Claude self-correct in the same turn rather than building on a broken foundation. A caught error on turn 3 is far cheaper than discovering it on turn 30.
Key design principle: The goal isn't to prevent all errors — it's to make errors visible immediately. Strict-write is a feedback mechanism, not a safety net.
Supported languages
AST validation (stage 3) is available for any language with a Tree-sitter grammar. Currently supported:
- TypeScript / JavaScript / JSX / TSX
- Python
- Rust
- Go
- Ruby
- C / C++
- Java
- HTML / CSS
- JSON / YAML / TOML
- Bash / Shell
For unsupported languages, stages 1 and 2 still run — you get hash verification without syntax checking.
Performance
The verification pipeline adds ~5-15ms per write operation. SHA-256 hashing and Tree-sitter parsing are both fast enough to be imperceptible. The cost is negligible compared to the API round-trip time for each agent turn.