GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • ChatCLI home page
  • Cookbook
  • Releases
  • diillson/chatcli
  • Install
  • Quickstart
  • Docker & Kubernetes
  • Auto-Update
  • Config Migration
  • Plugin @coder
  • Atomic Tools
  • Coder Mode Security (Governance)
  • Permissions
  • Git Worktrees

This view

  • Original page
  • New address

GeezerVison is showing chatcli.edilsonfreitas.com — Plugin @coder - ChatCLI

@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.

​
Quick Reference

All subcommands and their most commonly used flags at a glance:
SubcommandDescriptionKey Flags
readRead file contents (several files in one call: --file a b c)--file (req.), --start, --end, --head, --tail
statSize, line count, text/binary, line endings, mtime — size a read before paying for it--file (req.)
findFiles by name glob or path substring (what search does not do)--pattern, --contains, --dir, --limit, --dirs
moveRename/move a file inside the workspace (backup of the source; existing destination refused without --force)--from (req.), --to (req.), --force
deleteRemove a file (never a directory) leaving a .bak that rollback restores--file (req.)
writeWrite file with backup--file (req.), --content (req.), --append, --encoding
patchApply search/replace (exact, one place — ambiguous or missing text is refused with a hint) or unified diff--file, --search, --replace, --all, --diff, --encoding
multipatchAtomic transaction of multiple search/replace edits across multiple files. All-or-nothing rollback.--edits (req., JSON array)
treeDirectory structure--dir, --glob, --max-entries
outlineSymbol skeleton of a file (declarations + line numbers)--file (req.)
mapBudgeted structural map of a whole tree, files ranked by structure--dir, --budget
searchFull-text search in files--term (req.), --dir, --glob, --max-results, --context
execExecute shell commands--cmd (req.), --command
testRun tests--dir, --pattern, --timeout
git-statusRepository status(no flags)
git-diffPending differences--file, --staged
git-logCommit history--oneline, --limit
git-changedChanged files--staged
git-branchList branches--all
git-showOne commit (message + patch, or --stat) or a file as it was at a ref--ref, --path, --stat, --dir
git-blameAuthor, commit and date of each line (or a range)--file (req.), --start, --end, --dir
rollbackRestore file from .bak backup--file (req.)
cleanRemove .bak files(no required flags)
checkpointShadow-git workspace snapshots (automatic before mutations)--list, --create, --restore, --label

​
Argument Formats

@coder accepts two argument formats: JSON and CLI-style. Both are equivalent.
  • JSON Format (recommended)
  • CLI-style Format
The JSON format is used inside the args attribute of a <tool_call>. The structure is:
{
  "cmd": "<subcommand>",
  "args": {
    "<flag>": "<value>",
    ...
  }
}
Full example:
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"main.go","start":10,"end":50}}'/>
The JSON format is recommended because it avoids escaping issues and is what language models generate most consistently.
You can also pass arguments in command-line style, separated by spaces:
read --file main.go --start 10 --end 50
Here, the cmd field is the first word and flags follow in --flag value format.Example in tool_call:
<tool_call name="@coder" args='{"cmd":"read --file main.go --start 10 --end 50"}'/>
In CLI-style format, values with spaces must be quoted: --content "hello world".

​
Subcommands — Complete Reference

read -- Read Files

Reads the contents of a file from disk. Supports partial reading by line range and byte limits.

​
Flags

FlagTypeRequiredDefaultDescription
--filestringYes—Path of the file to read
--startintNo—Start line (1-based)
--endintNo—End line (1-based)
--headintNo—First N lines
--tailintNo—Last N lines
--max-bytesintNo200000Maximum byte limit for output (the ceiling; a read that asks for no range is capped at 2,000 lines with a --start continuation hint, the way Claude Code pages reads)
--encodingstringNotextOutput encoding: text or base64

​
Examples

  • JSON
  • CLI-style
<!-- Read entire file -->
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"README.md"}}'/>

<!-- Read lines 10 to 50 -->
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"main.go","start":10,"end":50}}'/>

<!-- First 20 lines -->
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"config.yaml","head":20}}'/>

<!-- Last 30 lines -->
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"app.log","tail":30}}'/>

<!-- Output in base64 (useful for binaries) -->
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"image.png","encoding":"base64","max-bytes":500000}}'/>
read --file README.md
read --file main.go --start 10 --end 50
read --file config.yaml --head 20
read --file app.log --tail 30
read --file image.png --encoding base64 --max-bytes 500000
Use --head or --tail to avoid very large outputs. The --max-bytes limit (default 200KB) acts as a safety net even when not explicitly specified.

write -- Write Files

Writes content to a file. Automatically creates a .bak backup of the existing file before overwriting.

​
Flags

FlagTypeRequiredDefaultDescription
--filestringYes—Path of the file to write
--contentstringYes—Content to write
--encodingstringNotextContent encoding: text or base64
--appendboolNofalseIf true, appends to the file instead of overwriting

​
Examples

  • JSON
  • CLI-style
<!-- Write new file (text) -->
<tool_call name="@coder" args='{"cmd":"write","args":{"file":"hello.txt","content":"Hello, World!"}}'/>

<!-- Write with base64-encoded content -->
<tool_call name="@coder" args='{"cmd":"write","args":{"file":"data.bin","content":"SGVsbG8gV29ybGQ=","encoding":"base64"}}'/>

<!-- Append to an existing file -->
<tool_call name="@coder" args='{"cmd":"write","args":{"file":"notes.txt","content":"\nNew line appended","append":true}}'/>
write --file hello.txt --content "Hello, World!"
write --file data.bin --content "SGVsbG8gV29ybGQ=" --encoding base64
write --file notes.txt --content "New line" --append
Content is JSON text by default (newlines as \n, quotes as \") and reaches the disk byte for byte. Use --encoding base64 for binary data or content so dense with quotes and backslashes that escaping it is error-prone.
Base64 is validated, never repaired silently. Spaces and line breaks inside the payload are ignored; any other character outside the base64 alphabet fails the write with its byte offset, so a corrupted payload never reaches the disk as garbage. The model gets the error and re-encodes.The args envelope may arrive as a JSON string. When a model sends "args" as a string holding the JSON object instead of the object itself, ChatCLI decodes it and closes a missing trailing } — but only when every string in it is complete, so truncated output is never written as if it were whole. An envelope that still cannot be decoded fails naming the field, instead of being dropped.
Post-edit diagnostics. After a successful write (also patch and multipatch), ChatCLI runs the language server over the touched files and appends any findings to the tool result as a [DIAGNOSTICS] block — so a broken edit is caught immediately, in the same turn, instead of turns later when a test fails. It is silent on clean files, capped at 5 files / 3000 characters, and disabled with CHATCLI_CODER_AUTODIAG=off. A language server must be available for the file’s language (see LSP Diagnostics).

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).

​
Flags

FlagTypeRequiredDefaultDescription
--filestringConditional—File to patch. Required for search/replace; optional for diff (the diff may contain paths)
--searchstringConditional—Text to find (search/replace mode)
--replacestringConditional—Replacement text (search/replace mode); empty deletes the text
--allboolNofalseReplace every occurrence of --search. Without it, a search text that occurs more than once is refused
--diffstringConditional—Unified diff content (diff mode)
--encodingstringNotextEncoding for --search and --replace: text or base64
--diff-encodingstringNotextEncoding for --diff: text or base64
You must use either search/replace mode (--search + --replace) or diff mode (--diff). Do not combine both.

​
Where the edit lands

A search/replace edit lands in exactly one place, and the result says which line:
  • Ambiguous — the search text occurs more than once: the patch is refused with the lines it matched (occurs 2 times in auth.go (lines 14, 41)). Add surrounding lines until it is unique, or pass --all to replace every occurrence on purpose. Nothing is written on a refusal.
  • Not found — the error names the closest line of the file (closest line is 3: "func Login(user string) error {"), so the next attempt copies the real text instead of guessing.
  • Indentation differs — a search text that matches one place except for leading indentation or trailing whitespace is accepted, and the replacement is re-indented to the file (the result says so).
multipatch applies the same contract to every edit of the transaction: one ambiguous edit refuses the whole transaction, and no file changes.

​
Search/Replace Mode

  • JSON
  • CLI-style
<!-- Replace text (plain text) -->
<tool_call name="@coder" args='{"cmd":"patch","args":{"file":"main.go","search":"fmt.Println(\"old\")","replace":"fmt.Println(\"new\")"}}'/>

<!-- Replace text (base64 to avoid escaping) -->
<tool_call name="@coder" args='{"cmd":"patch","args":{"file":"main.go","search":"Zm10LlByaW50bG4oIm9sZCIp","replace":"Zm10LlByaW50bG4oIm5ldyIp","encoding":"base64"}}'/>
patch --file main.go --search "fmt.Println(\"old\")" --replace "fmt.Println(\"new\")"
patch --file main.go --search "base64str" --replace "base64str" --encoding base64

​
Unified Diff Mode

  • JSON
  • CLI-style
<!-- Apply diff as text -->
<tool_call name="@coder" args='{"cmd":"patch","args":{"diff":"--- a/main.go\n+++ b/main.go\n@@ -5,3 +5,3 @@\n-old line\n+new line"}}'/>

<!-- Apply diff as base64 -->
<tool_call name="@coder" args='{"cmd":"patch","args":{"diff":"LS0tIGEvbWFpbi5nbw...","diff-encoding":"base64"}}'/>
patch --diff "--- a/main.go\n+++ b/main.go\n@@ -5,3 +5,3 @@\n-old\n+new"
patch --diff "base64content" --diff-encoding base64
search/replace/diff are JSON text by default, multiple lines included. The base64 mode is optional, for content so dense with quotes and backslashes that escaping it is error-prone.

tree -- Directory Structure

Lists the directory structure in tree format. Useful for understanding project organization.

​
Flags

FlagTypeRequiredDefaultDescription
--dirstringNo"."Root directory to list
--globstringNo—Glob pattern to filter files (e.g., "*.go")
--max-entriesintNo2000Maximum number of entries returned

​
Examples

  • JSON
  • CLI-style
<!-- 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}}'/>
tree --dir .
tree --dir . --glob "*.go"
tree --dir ./internal --max-entries 500

search -- Full-Text Search

Searches for a term across all files in a directory. Returns snippets with surrounding context.

​
Flags

FlagTypeRequiredDefaultDescription
--termstringYes—Search term
--dirstringNo"."Directory to search in
--globstringNo—Glob pattern to filter files (e.g., "*.go", "*.ts")
--max-resultsintNo100Maximum number of results
--contextintNo2Context lines before and after each match

​
Examples

  • JSON
  • CLI-style
<!-- 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}}'/>
search --term "TODO" --dir .
search --term "func main" --dir . --glob "*.go" --context 5
search --term "error" --dir ./pkg --max-results 20

outline -- File Symbol Skeleton

Renders a file’s symbol skeleton — its declarations with line numbers — so you understand a file’s shape without reading the whole thing. For Go files the signatures are exact (parsed with Go’s go/ast: functions with their receiver, structs, interfaces, consts, vars); for Python, JS/TS/JSX, Java, Ruby, Rust, Kotlin, C# and PHP a pattern-based outline recognizes the common declaration forms. Read-only.

​
Flags

FlagTypeRequiredDefaultDescription
--filestringYes—Path of the file to outline

​
Examples

  • JSON
  • CLI-style
<tool_call name="@coder" args='{"cmd":"outline","args":{"file":"cli/cli.go"}}'/>
outline --file cli/cli.go
Reach for outline before read when you only need to know what is in a file (which functions, types, methods) and where — it costs a fraction of the tokens of reading the whole file.

map -- Repository Structure Map

Renders a character-budgeted structural map of a whole tree: every source file is outlined, files are ranked by how much structure they carry, and their skeletons are printed until the budget is spent — with an explicit note when files are elided. It ignores .git, node_modules, vendor, dist, build, hidden files and *_test.go. Read-only. Use it to orient yourself in a large codebase without reading whole files.

​
Flags

FlagTypeRequiredDefaultDescription
--dirstringNo"."Root directory to map
--budgetintNo8000Maximum characters of structure to emit

​
Examples

  • JSON
  • CLI-style
<!-- Map the whole project -->
<tool_call name="@coder" args='{"cmd":"map","args":{"dir":"."}}'/>

<!-- Map a subtree with a larger budget -->
<tool_call name="@coder" args='{"cmd":"map","args":{"dir":"./cli","budget":16000}}'/>
map --dir . --budget 8000
map --dir ./cli --budget 16000

exec -- Execute Commands

Executes an arbitrary command in the shell. Has built-in security protections against destructive commands.

​
Flags

FlagTypeRequiredDefaultDescription
--cmdstringYes—Command to execute
--commandstringNo—Alias for --cmd

​
Examples

  • JSON
  • CLI-style
<!-- 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"}}'/>
exec --cmd "go build ./..."
exec --cmd "ps aux | grep myapp"
exec --command "ls -la"
exec automatically blocks commands considered dangerous, including:
  • rm -rf / and destructive variants
  • dd targeting disk devices
  • Fork bombs (e.g., :(){ :|:& };:)
  • Other recognizably destructive patterns
These blocks exist to protect the system. Use responsibly.

test -- Run Tests

Runs project tests automatically, detecting the framework based on the directory contents.

​
Flags

FlagTypeRequiredDefaultDescription
--dirstringNo"."Directory where to run tests
--patternstringNo—Test file pattern (e.g., "*_test.go")
--timeoutintNo30Timeout in seconds

​
Examples

  • JSON
  • CLI-style
<!-- 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.

​
Examples

  • JSON
  • CLI-style
<tool_call name="@coder" args='{"cmd":"git-status","args":{}}'/>
git-status

git-diff -- Pending Differences

Shows the diff of modified files in the repository.

​
Flags

FlagTypeRequiredDefaultDescription
--filestringNo—Filter diff to a specific file
--stagedboolNofalseShow only staged changes (ready for commit)

​
Examples

  • JSON
  • CLI-style
<!-- 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}}'/>
git-diff
git-diff --file main.go
git-diff --staged

git-log -- Commit History

Displays the repository’s commit history.

​
Flags

FlagTypeRequiredDefaultDescription
--onelineboolNofalseCompact format (one line per commit)
--limitintNo10Maximum number of commits shown

​
Examples

  • JSON
  • CLI-style
<!-- 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-log
git-log --oneline --limit 5

git-changed -- Changed Files

Lists changed files in the repository (similar to git diff --name-only).

​
Flags

FlagTypeRequiredDefaultDescription
--stagedboolNofalseList only staged files

​
Examples

  • JSON
  • CLI-style
<!-- All changed files -->
<tool_call name="@coder" args='{"cmd":"git-changed","args":{}}'/>

<!-- Only staged files -->
<tool_call name="@coder" args='{"cmd":"git-changed","args":{"staged":true}}'/>
git-changed
git-changed --staged

git-branch -- Branch Listing

Lists the repository’s branches.

​
Flags

FlagTypeRequiredDefaultDescription
--allboolNofalseInclude remote branches

​
Examples

  • JSON
  • CLI-style
<!-- Local branches -->
<tool_call name="@coder" args='{"cmd":"git-branch","args":{}}'/>

<!-- All branches (local + remote) -->
<tool_call name="@coder" args='{"cmd":"git-branch","args":{"all":true}}'/>
git-branch
git-branch --all

git-show -- One Commit or a File at a Ref

Shows one commit (message and patch), only its --stat summary, or a file’s content as it was at a ref (--path), without the patch. Read-only; a ref that starts with a dash is refused.

​
Flags

FlagTypeRequiredDefaultDescription
--refstringNoHEADCommit, tag or branch
--pathstringNo—File to show as it was at the ref
--statboolNofalseOnly the summary of touched files
--dirstringNo.Repository directory

​
Examples

<tool_call name="@coder" args='{"cmd":"git-show","args":{"ref":"HEAD~1","stat":true}}'/>
<tool_call name="@coder" args='{"cmd":"git-show","args":{"ref":"v1.2.0","path":"cli/cli.go"}}'/>

git-blame -- Who Wrote These Lines

Annotates a file, or a --start/--end range of it, with the commit, author and date of every line.

​
Flags

FlagTypeRequiredDefaultDescription
--filestringYes—File to annotate
--startintNo—First line (1-based)
--endintNo—Last line (1-based)
--dirstringNo.Repository directory

​
Examples

<tool_call name="@coder" args='{"cmd":"git-blame","args":{"file":"cli/cli.go","start":120,"end":160}}'/>

stat / find / move / delete -- File Housekeeping

  • stat --file a [b c] — size, line count, text or binary, CRLF/BOM and modification time; a file longer than a whole read shows gets a hint to read it in ranges. Cheap: size a read before paying for it.
  • find --pattern "*_test.go" or --contains auth/ — files by name glob or path substring under --dir, skipping .git, node_modules, vendor and hidden entries; --limit (default 200) and --dirs to include directories. What search (content) does not do.
  • move --from a --to b — rename or move inside the workspace; the source gets a .bak, destination directories are created, an existing destination is refused without --force.
  • delete --file a — removes a file (never a directory), leaving a.bak beside it; rollback --file a brings it back. Both move and delete take an automatic checkpoint first.
<tool_call name="@coder" args='{"cmd":"stat","args":{"file":"cli/agent_mode.go"}}'/>
<tool_call name="@coder" args='{"cmd":"find","args":{"pattern":"Dockerfile*","dirs":false}}'/>
<tool_call name="@coder" args='{"cmd":"move","args":{"from":"pkg/old.go","to":"pkg/new/old.go"}}'/>
<tool_call name="@coder" args='{"cmd":"delete","args":{"file":"pkg/dead.go"}}'/>
All engine messages and the schema the model sees are in English (the model follows English instructions more reliably).

rollback -- Revert Changes

Restores a file from its .bak backup, automatically created by write or patch.

​
Flags

FlagTypeRequiredDefaultDescription
--filestringYes—Path of the file to restore

​
Examples

  • JSON
  • CLI-style
<tool_call name="@coder" args='{"cmd":"rollback","args":{"file":"main.go"}}'/>
rollback --file main.go
rollback only works if a corresponding .bak file exists. Backups are automatically created by the write and patch commands.

clean -- Remove Backups

Removes .bak files created by the backup system.No required flags.

​
Examples

  • JSON
  • CLI-style
<tool_call name="@coder" args='{"cmd":"clean","args":{}}'/>
clean

checkpoint -- Shadow-git Snapshots

Workspace snapshots into a shadow git repository, a stronger safety net than the per-file .bak rollback — it covers multi-file edits and exec side effects, not just a single file.A checkpoint is taken automatically before every mutating subcommand (write, patch, multipatch, exec). The snapshot lives in a separate GIT_DIR under ~/.chatcli/checkpoints/<hash> with your workspace as its work tree, so your own .git is never touched and your project’s .gitignore is honored.

​
Flags

FlagTypeRequiredDefaultDescription
--listboolNo(default)List snapshots, newest first
--createboolNofalseRecord a snapshot now
--restorestringNo—Rewind the working tree to the snapshot with this hash
--labelstringNomanualLabel for a --create snapshot

​
Examples

  • JSON
  • CLI-style
<!-- List snapshots -->
<tool_call name="@coder" args='{"cmd":"checkpoint","args":{"list":true}}'/>

<!-- Record one now -->
<tool_call name="@coder" args='{"cmd":"checkpoint","args":{"create":true,"label":"before refactor"}}'/>

<!-- Rewind to a snapshot -->
<tool_call name="@coder" args='{"cmd":"checkpoint","args":{"restore":"a1b2c3d"}}'/>
checkpoint --list
checkpoint --create --label "before refactor"
checkpoint --restore a1b2c3d
--restore never deletes files added after the snapshot; it only rewinds what the snapshot tracked. It goes through the security gate; --list and --create are read-only.
Auto-snapshots are best-effort (a checkpoint failure never blocks the edit), throttled to at most one per 15 seconds (a burst of writes produces one checkpoint), a no-op when git is not installed, and switched off entirely with CHATCLI_CODER_CHECKPOINTS=off.They are also bounded: workspaces as broad as your home directory (or any directory containing it) are never auto-snapshotted — hashing that much of the disk would freeze every command — and each snapshot runs under a hard deadline (10s automatic, 60s for an explicit checkpoint create, overridable in seconds via CHATCLI_CODER_CHECKPOINT_TIMEOUT). Repeated snapshot failures back off exponentially and, after three in a row, disable automatic snapshots for the rest of the session with a one-line warning.

​
Transactional multipatch

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.
{
  "cmd": "multipatch",
  "args": {
    "edits": [
      {"file": "internal/auth/login.go", "search": "loginV1", "replace": "loginV2"},
      {"file": "internal/auth/login_test.go", "search": "loginV1", "replace": "loginV2"},
      {"file": "cmd/server/main.go", "search": "auth.loginV1", "replace": "auth.loginV2"}
    ]
  }
}
Each edit applies its search→replace exactly 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.

​
Backup System

@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.

​
Path Validation and Security

@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.

​
Complete Usage Example (in /coder)

In /coder mode, the assistant responds with a reasoning block followed by a tool_call. The block is sized to the task: a single-step request (one lookup, one command, one answer) gets one line and no task list, while anything with two or more steps gets a short numbered plan with [✓] marks as it progresses. The rule lives in the stable system prompt on purpose — deciding it per query would change the prompt and rewrite the cached prefix. The same prompt binds claims to evidence: when tool results ground the answer, specific figures, dates, deadlines, rules and place names come only from that evidence, and whatever comes from the model’s own knowledge is labeled unverified or an estimate in the sentence that uses it, never presented with the authority of a fetched source. 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"}}'/>

​
JSON Recovery and Robust Parsing

@coder includes a JSON recovery system that automatically fixes malformed arguments generated by LLMs:

7 Recovery Strategies

Single quotes, unquoted keys, trailing commas, plain string wrapping, and more. See JSON Recovery for details.

Escaped Quotes in Shell

Improved handling of escaped quotes in shell commands, avoiding parsing failures when the model generates exec --cmd "echo \"hello\"".

Unicode Quote Normalization

Curly (typographic) quotes are automatically converted to straight quotes in code files, preventing compilation errors.

Concurrent Execution

Tool calls that operate on different files are executed in parallel (file-scoped parallelization), speeding up read and search operations.

​
Important Notes

@coder grants read/write power over files and command execution, all subject to rollback when requested. Use in trusted repositories.
Being builtin, @coder appears in /plugin list with the [builtin] tag. It cannot be uninstalled via /plugin uninstall.

​
Plugin @coder FAQ

Does @coder accept JSON in args?

Yes. The recommended format is JSON. Example:
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"README.md"}}'/>

When to use patch --diff vs --search/--replace?

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?

No. write and patch take JSON text by default, multiple lines and quotes included; the parser keeps JSON escapes and backtick spans inside args intact. Base64 is optional, for binary files or escape-heavy content, and costs about a third more tokens.

​
Next steps

Coder Mode

How /coder orchestrates @coder in a full ReAct loop.

Coder Security

Policies, allowlist, and execution governance.

Enhanced Permissions

40+ immune patterns and 90+ read-only allowlist.

JSON Recovery

7 strategies to recover malformed JSON in tool calls.

File Staleness

Track mtime + SHA-256 between read/write to avoid conflicts.

Cookbook: Fix tests

Practical recipe using @coder to autonomously fix tests.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.