go install github.com/dotcommander/jinn@latest
echo '{"tool":"read_file","args":{"path":"go.mod"}}' | jinn
echo '{"tool":"run_shell","args":{"command":"go test ./..."}}' | jinnjinn is a single-binary tool executor for AI coding agents. It reads one JSON
request on stdin, runs one tool inside the current workspace, and writes one JSON
response on stdout.
Use it when you need a small, deterministic tool layer for an agent loop, subagent, hook, CI job, or harness integration.
- No daemon: spawn
jinnonce per tool call. - No runtime dependencies: built with the Go standard library.
- Workspace confinement: paths stay inside the working directory.
- Safer mutation: file writes use atomic replacement and undo snapshots.
- Shell guardrails:
run_shellclassifies commands assafe,caution, ordangerousbefore execution.
go install github.com/dotcommander/jinn@latest
jinn --versionBuild from source:
git clone https://github.com/dotcommander/jinn.git
cd jinn
go build -o jinn ./cmd/jinn/Read a file:
echo '{"tool":"read_file","args":{"path":"go.mod"}}' | jinnRun a command:
echo '{"tool":"run_shell","args":{"command":"go test ./..."}}' | jinnInspect a command without running it:
echo '{"tool":"run_shell","args":{"command":"rm -rf build","dry_run":true}}' | jinnThe response is always a JSON envelope:
{"ok": true, "result": "..."}run_shell also includes risk and exit-code classifications:
{"ok": true, "result": "[dry-run] would execute: rm -rf build", "risk": "dangerous", "classification": "success"}Errors use the same envelope and often include a next-step hint:
{"ok": false, "error": "file not found: missing.go", "suggestion": "verify the path exists with list_dir on the parent, or check for typos"}Print the OpenAI-compatible function schema:
jinn --schemaAsk from inside the protocol:
echo '{"tool":"list_tools","args":{"include_schema":false}}' | jinnStart the browser inspector:
jinn --inspect 127.0.0.1:8787Use MCP discovery mode:
{
"mcpServers": {
"jinn": {
"command": "jinn",
"args": ["--mcp"]
}
}
}jinn --mcp exposes one MCP tool, jinn_route. It recommends matching jinn
tools for a task and can return lean schemas for only those tools. It does not
execute filesystem or shell operations itself.
Claude Code, Codex, pi, and similar tools already have native read/edit/shell surfaces. Add jinn for gaps that are useful as one-shot subprocesses:
lsp_queryfor definition, references, hover, diagnostics, symbols, and rename previews without running an MCP server.run_shellwithdry_run: truefor permission hooks that need semantic risk classification before a shell command runs.memoryfor scoped SQLite-backed facts, directives, and lessons with optional expiry and garbage collection.apply_patchto validate and atomically apply Codex-style patches outside the Codex harness.list_toolsor--schemawhen a custom loop needs a compact tool surface.
Recipes for Claude Code, Codex CLI, pi, and custom loops: docs/harness-integrations.md.
jinn exposes 18 specialized tools for coding agents:
| Tool | Description |
|---|---|
read_file |
Read windowed chunks of a file with line numbers (max 50MB). Supports tail, line_numbers, and a truncate strategy (head/tail/middle/none). Images detected by content; PDFs return a structured error. |
multi_read |
Read up to 20 files in one call with per-file windows, partial success, and structured per-file errors. |
write_file |
Atomic full-file write. Creates parent directories automatically. |
edit_file |
Targeted text replacement. Handles fuzzy whitespace/quotes, CRLF/BOM preservation, dry_run diff preview. Rejects empty old_text and no-op edits. |
multi_edit |
Apply batch edits with validate-first semantics and per-file atomic writes. Detects overlapping regions, rejects empty or no-op entries. |
apply_patch |
Apply a Codex-style patch (*** Begin Patch … *** End Patch) to create, delete, or update files. Validates all operations first; writes are per-file atomic. |
search_files |
Fast grep/regex search with glob filtering, context lines, and a literal flag for fixed-string matching. |
search_replace |
Regex search-and-replace across explicit files or glob patterns. Supports capture groups, dry runs, and per-file atomic writes. |
run_shell |
Controlled bash execution with risk classification. Process-group kill ensures background children are also terminated on timeout. Dangerous commands blocked unless force: true. |
stat_file |
Get metadata (size, lines, mtime) without reading contents. |
list_dir |
Recursive directory tree exploration (skips hidden files). Directories suffixed with / in output. |
find_files |
Find files by glob pattern. Uses fd when available (respects .gitignore), falls back to POSIX find. |
diff_files |
Unified diff between two files with is_identical and first_changed_line metadata. |
detect_project |
Auto-detect language, frameworks, and build/test/lint commands. |
list_tools |
Programmatic tool capability metadata; can include the compact schema on request. |
memory |
Persistent, project-scoped key/value store across sessions. Actions: save, recall, list, forget. |
undo |
Browse, preview, and restore file snapshots captured automatically before every mutation. |
lsp_query |
Query a language server for definition, references, hover, symbols, diagnostics, or rename. |
Security is not an opt-in feature; it is the core of the engine.
- Path Confinement: Every path is resolved via
EvalSymlinksand checked against the working directory. Traversal attempts (e.g.,../../etc/passwd) are hard-blocked. - Sensitive Blocklist: Direct access to
.git,.ssh,.aws,.env, and.gnupgis always denied. - TOCTOU Protection:
jinnrecords filemtimeduringread_file. If a file is modified externally before an agent callswrite_fileoredit_file, the update is rejected. - Environment Scrubbing:
run_shellruns with a minimal allowlist of environment variables (e.g.,PATH,LANG,TMPDIR). API keys and tokens are not inherited by child commands. - Risk Classifier: Every
run_shellcommand is classified assafe,caution, ordangerous. Dangerous commands (e.g.,rm -rf,dd,sudo) are blocked outright unless the caller passes"force": true. - Output Caps: Stdout/stderr is capped at 1MB. Excess output spills to a temp file, and the agent receives a truncated tail.
import subprocess, json
def call_jinn(tool: str, args: dict):
req = json.dumps({"tool": tool, "args": args})
# Run as a subprocess — no daemon or server needed
proc = subprocess.run(["jinn"], input=req, capture_output=True, text=True)
return json.loads(proc.stdout)
# Automate a refactor
project = call_jinn("detect_project", {})
if "Go" in project["languages"]:
call_jinn("run_shell", {"command": "go mod tidy"})For TypeScript, Go, PHP, and shell-script integrations, see docs/getting-started.md.
jinn aims for zero dependencies and maximum reliability. Please ensure go test -race ./... passes before submitting PRs.
MIT