Skip to content

dotcommander/jinn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jinn

Sandboxed tool executor for AI coding agents. Single binary, zero dependencies, stdlib only.

jinn exposes 8 file/shell tools via a one-shot JSON protocol compatible with OpenAI function calling. An agent sends a JSON request on stdin and gets a JSON response on stdout. No server, no daemon, no config.

Install

go install github.com/dotcommander/jinn@latest

Building from Source

git clone https://github.com/dotcommander/jinn.git
cd jinn
go build ./cmd/jinn/

Usage

# Emit tool definitions (OpenAI function-calling format)
jinn --schema

# Execute a tool
echo '{"tool":"read_file","args":{"path":"main.go"}}' | jinn
# → {"ok":true,"result":"1\tpackage main\n..."}

echo '{"tool":"run_shell","args":{"command":"go version"}}' | jinn
# → {"ok":true,"result":"[exit: 0]\ngo version go1.26.2 ..."}

Protocol

Request (stdin):

{"tool": "<name>", "args": {}}

Response (stdout):

{"ok": true, "result": "..."}
{"ok": false, "error": "..."}

One invocation, one request, one response. The calling agent handles all user interaction.

Tools

Tool Description
run_shell Execute bash with timeout (default 30s, max 300s) and optional dry_run
read_file Read with line numbers, start_line/end_line windowing, 50 MB limit, binary detection
write_file Atomic write via temp+rename, auto-creates parent dirs
edit_file Replace text — exact match first, fuzzy fallback (smart quotes, whitespace). Preserves CRLF and BOM. Atomic
multi_edit Batch edits across files — validates all first, applies atomically
search_files Grep with regex, glob filter, context lines, case-insensitive option
stat_file File metadata (size, lines, mtime, type) without reading content
list_dir Recursive directory listing with depth control, hidden files excluded

Security

All file operations are confined to the working directory:

  • Path confinement — every path is resolved and checked against CWD. .. traversal and symlink escapes are rejected.
  • Sensitive path blocking.git/, .ssh/, .aws/, .gnupg/, and .env* are always blocked.
  • TOCTOU detection — file mtime is recorded on read. Writes are rejected if the file changed since last read.
  • Atomic writes — all mutations use temp file + rename. No partial writes on crash or interrupt.
  • No escape hatch — sandboxing is always on. There is no flag to disable path confinement.

Text Normalization

Edit operations handle encoding differences between LLMs and files:

  • Fuzzy matching — if exact match fails, normalizes smart quotes (""''"'), Unicode dashes/spaces to ASCII, and strips trailing whitespace, then retries. Exact match always preferred.
  • CRLF preservation — detects original line endings, normalizes to LF for matching, restores after edit.
  • BOM handling — strips UTF-8 BOM before matching (models never produce BOMs), restores after edit.

Output Pipeline

jinn minimizes token consumption for the calling agent:

  1. Repeated line collapse — runs of 3+ identical lines become [... N identical lines collapsed ...]
  2. Bounded writer — output capped at 1 MB; when exceeded, full output spills to a temp file (path included in response)
  3. Tail truncation — shell output keeps the last N lines (where errors and results live) with a metadata header

Integration

Any agent that speaks OpenAI function calling can use jinn as a subprocess:

import subprocess, json

def call_jinn(tool, args):
    req = json.dumps({"tool": tool, "args": args})
    result = subprocess.run(["jinn"], input=req, capture_output=True, text=True)
    return json.loads(result.stdout)

call_jinn("read_file", {"path": "main.go"})
call_jinn("edit_file", {"path": "config.yaml", "old_text": "timeout: 30", "new_text": "timeout: 60"})
call_jinn("run_shell", {"command": "go test ./..."})

Or in a shell-based agent loop:

SCHEMA=$(jinn --schema)
# ... send $SCHEMA as tools to LLM API ...
RESULT=$(echo "$TOOL_CALL_JSON" | jinn)
# ... feed $RESULT back as tool message ...

Design Decisions

  • Zero dependenciesgo.mod has no require block. Stdlib only. No supply chain risk, trivial builds.
  • Clean architecturecmd/jinn/main.go (~50 lines: flags, signal, JSON I/O) wires to internal/jinn/, a focused core package with engine, tools, security, normalization, and output pipeline across 11+ files.
  • One-shot — no persistent server, no state between invocations. The calling agent manages session state.
  • Security by default — not opt-in. Every path goes through confinement checks before any I/O.

Contributing

PRs welcome. Please run go test -race ./... before pushing.

License

MIT

About

Sandboxed tool executor for AI coding agents. Zero deps, stdlib only. 8 tools via JSON-over-stdin/stdout.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages