Builtin engineering tool for reading, editing, patching, and executing tasks with rollback.
@coder is the engineering suite used by Coder Mode (/coder). It provides actions for reading/searching files, safely applying patches, running commands, and reverting changes.
@coder is a builtin plugin — it comes embedded in the ChatCLI binary and works immediately, without installation. If you need a custom version, simply place the binary in ~/.chatcli/plugins/ and it will take precedence over the builtin. When removed, the builtin returns automatically on the next /plugin reload.
Use --encoding base64 for content containing special characters, complex line breaks, or binary data. This avoids escaping issues in JSON.
patch -- Apply Patches
Applies changes to an existing file. Supports two modes: search/replace (replaces a specific section) and unified diff (applies a patch in diff format).
The base64 mode is strongly recommended for patches, especially when the content contains quotes, backslashes, or multiple lines. This eliminates JSON escaping issues entirely.
tree -- Directory Structure
Lists the directory structure in tree format. Useful for understanding project organization.
<!-- List current directory --><tool_call name="@coder" args='{"cmd":"tree","args":{"dir":"."}}'/><!-- List only Go files --><tool_call name="@coder" args='{"cmd":"tree","args":{"dir":".","glob":"*.go"}}'/><!-- List subdirectory with limit --><tool_call name="@coder" args='{"cmd":"tree","args":{"dir":"./internal","max-entries":500}}'/>
<!-- Simple search --><tool_call name="@coder" args='{"cmd":"search","args":{"term":"TODO","dir":"."}}'/><!-- Search in Go files with more context --><tool_call name="@coder" args='{"cmd":"search","args":{"term":"func main","dir":".","glob":"*.go","context":5}}'/><!-- Search with result limit --><tool_call name="@coder" args='{"cmd":"search","args":{"term":"error","dir":"./pkg","max-results":20}}'/>
<!-- Execute a simple command --><tool_call name="@coder" args='{"cmd":"exec","args":{"cmd":"go build ./..."}}'/><!-- List processes --><tool_call name="@coder" args='{"cmd":"exec","args":{"cmd":"ps aux | grep myapp"}}'/><!-- Using the --command alias --><tool_call name="@coder" args='{"cmd":"exec","args":{"command":"ls -la"}}'/>
<!-- Run all tests --><tool_call name="@coder" args='{"cmd":"test","args":{"dir":"."}}'/><!-- Run tests with specific pattern --><tool_call name="@coder" args='{"cmd":"test","args":{"dir":"./pkg","pattern":"*_test.go","timeout":60}}'/>
test --dir .test --dir ./pkg --pattern "*_test.go" --timeout 60
git-status -- Repository Status
Shows the Git repository status (modified, staged, untracked files, etc.).No flags required.
<!-- Full diff --><tool_call name="@coder" args='{"cmd":"git-diff","args":{}}'/><!-- Diff for a specific file --><tool_call name="@coder" args='{"cmd":"git-diff","args":{"file":"main.go"}}'/><!-- Staged diff --><tool_call name="@coder" args='{"cmd":"git-diff","args":{"staged":true}}'/>
<!-- Last 10 commits --><tool_call name="@coder" args='{"cmd":"git-log","args":{}}'/><!-- Last 5 commits in compact format --><tool_call name="@coder" args='{"cmd":"git-log","args":{"oneline":true,"limit":5}}'/>
git-loggit-log --oneline --limit 5
git-changed -- Changed Files
Lists changed files in the repository (similar to git diff --name-only).
When a refactor needs to touch multiple files as one unit (rename an identifier propagated across 5 files, update an import in every consumer, etc.), use multipatch instead of chaining patch calls. The contract:
1
Phase 1 — validation (no writes)
For each edit in declaration order, the engine loads the file, simulates the search→replace in memory, and verifies the search text is still present after prior in-flight edits to the same file. A failure on any edit aborts the transaction before any disk write.
2
Phase 2 — commit
Snapshot of each affected file in memory + write the new content. Any write failure restores all touched files from the snapshot.
3
Concurrency
Per-file mutex (keyed by absolute path), acquisition in sorted order — two transactions touching the same pair of files never deadlock. File permissions (chmod) are preserved across the rewrite.
Each edit applies its search→replaceexactly once (strings.Replace with n=1). To replace multiple occurrences in the same file, declare multiple edits. Per-edit base64 encoding is supported ("encoding":"base64") for payloads with non-UTF8 bytes.
@coder implements an automatic backup system to protect against unwanted changes.
1
Write or Patch
When you execute write or patch, the plugin checks whether the target file already exists.
2
Backup Creation
If the file exists, a copy is saved with the .bak extension (e.g., main.go -> main.go.bak).
3
Change Application
The new content is written (or the patch is applied) to the original file.
4
Rollback Available
At any point, you can use rollback --file main.go to restore the previous version from the .bak file.
5
Cleanup
Use clean to remove all .bak files when you no longer need the backups.
The backup is overwritten on each new write or patch operation on the same file. If you make multiple changes, only the version immediately before the last operation will be available for rollback.
@coder applies several security validations to all file paths:
Workspace Boundary
All paths are resolved relative to the working directory (workspace). Attempts to access files outside the workspace are blocked (e.g., ../../etc/passwd).
Symlink Resolution
Symlinks are resolved before validation. A symlink pointing outside the workspace will be rejected, even if the apparent path is within the allowed directory.
Sensitive Paths
Paths to sensitive system files (e.g., /etc/shadow, /etc/passwd) are blocked by default, preventing read or write operations.
Dangerous Commands
The exec subcommand filters known destructive patterns such as rm -rf /, dd, fork bombs, and others. These commands are rejected before execution.
In /coder mode, the assistant responds with a reasoning block followed by a tool_call. Here is a complete engineering workflow:
<!-- 1. Understand the project structure --><tool_call name="@coder" args='{"cmd":"tree","args":{"dir":".","glob":"*.go"}}'/><!-- 2. Search where a function is defined --><tool_call name="@coder" args='{"cmd":"search","args":{"term":"func HandleRequest","dir":".","glob":"*.go"}}'/><!-- 3. Read the relevant file --><tool_call name="@coder" args='{"cmd":"read","args":{"file":"handler.go","start":15,"end":45}}'/><!-- 4. Apply a fix --><tool_call name="@coder" args='{"cmd":"patch","args":{"file":"handler.go","search":"return nil","replace":"return fmt.Errorf(\"missing parameter: %s\", name)"}}'/><!-- 5. Run the tests --><tool_call name="@coder" args='{"cmd":"test","args":{"dir":".","timeout":60}}'/><!-- 6. Check what changed --><tool_call name="@coder" args='{"cmd":"git-diff","args":{}}'/><!-- 7. If something went wrong, revert --><tool_call name="@coder" args='{"cmd":"rollback","args":{"file":"handler.go"}}'/>
Use --search/--replace for simple, targeted substitutions at a single location in the file. Use --diff when you need to apply multiple changes at once or when the change involves adding/removing lines in different sections of the file. The diff can be encoded as text or base64.
Is exec dangerous?
@coder exec blocks dangerous patterns by default, such as rm -rf /, dd targeting disk devices, and fork bombs. The protection is automatic and requires no configuration.
Is there a read limit?
Yes. The default is --max-bytes 200000 (200KB). You can also use --head or --tail to read only portions of the file. This prevents very large outputs from overwhelming the model’s context window.
What happens if I write to the same file twice?
The .bak backup is overwritten on each operation. Only the version immediately before the last write will be available for rollback. If you need full history, use git for version management.
Can I use @coder outside of /coder mode?
Yes. The @coder plugin can be invoked in any mode that supports tool_calls. The /coder mode simply configures the system prompt to guide the model to use @coder as its primary tool.
How do I replace the builtin @coder with a custom version?
Place a binary with the same name in the ~/.chatcli/plugins/ directory. It will take precedence over the builtin. To revert to the builtin, remove the custom binary and run /plugin reload.
Is --encoding base64 necessary?
It is not mandatory, but strongly recommended for write and patch when the content contains special characters, quotes, backslashes, or multiple lines. Base64 completely eliminates JSON escaping issues.