No description
  • Shell 67%
  • Dockerfile 33%
Find a file
2026-08-17 20:19:17 +12:00
brown@83946ce391 bump brown 2026-08-15 19:18:37 +12:00
image Modify the installed packages 2026-08-17 20:10:55 +12:00
themes Changes mostly around volume path mounts, also brought in themes 2026-07-02 12:56:43 +12:00
.dockerignore building bond I hope 2026-07-01 18:01:52 +12:00
.gitignore Updated from vtcoder pod ideas 2026-07-01 19:21:55 +12:00
.gitmodules Update .gitmodules to public URL (removing bond) 2026-07-07 08:10:12 +12:00
AGENTS.md FIX AGENTS.md 2026-07-08 14:00:25 +12:00
james multi-line input 2026-08-17 20:19:17 +12:00
LICENSE.md MIT license 2026-07-07 17:35:10 +12:00
README.md tokens command 2026-07-09 08:28:40 +12:00
TODO.txt TODO 2026-07-09 08:51:47 +12:00

James Brown

brown is an AI coding agent/harness and james orchestrates its containerization.

User ←→ james (bash) ←→ container ←→ brown (rust) ←→ OpenAI-compatible API

James Brown ain't no big deal — AI coding agents are commodity software now. This one was written in about a week. But it serves me better than anything else I've tried.

Table of contents

Features

Backend

  • OpenAI-compatible API — tested with llama-server and openrouter.ai
  • Configurable temperature, reasoning_effort, and verbosity
  • Fetches context-window size from the API and displays token usage as a percentage of the window

Containment & safety

  • Runs in a docker or podman container
  • The current directory and everything below it is exposed to the agent
  • The top-level .git directory is mounted read-only so the agent can't corrupt your repo. (You can put read-only ssh keys in the container so it can still clone, pull, and submodule.)
  • Container has lots of development tools for the agent.
  • Manage the agent's homedir at ~/.local/share/james/homedir/ or shell into the container with james shell

Terminal UX

  • Returns control to your terminal prompt after each agent loop completes
  • Renders stylized markdown: colors, syntax-highlighted code blocks, tables that don't wrap, and configurable margins
  • Two themes bundled: opencode (dark, default) and one-dark
  • Thinking streams live so you can detect the agent going off the rails and interrupt it

Tools available to the LLM

  • shell — no permission gating; containment handles safety
  • read_file / write_file / edit_file — four edit variants (diff, append, insert, remove)
  • search — regex search across the workspace
  • symbols / ast_query — tree-sitter-powered source-code inspection (Rust, Python, TypeScript/JavaScript, JSON)
  • web_search — SearXNG-backed, works with or without format=json, handles many bot-protection schemes
  • web_fetch — fetch URLs and save to file
  • todowrite — the agent maintains its own task list
  • question — the agent can ask you questions
  • skill — on-demand loading of SKILL.md runbooks
  • context_compact — the agent can compact its own context

Context management

  • Persistent — context is stored as a sequence of timestamped directories under ~/.local/share/james/container-context/. You can inspect, edit, or delete files manually.
  • Clear — wipe the entire context and start fresh
  • Strip — remove a single Q&A pair without losing the rest
  • Compact — summarize older turns while keeping recent ones in full
  • Re-render — replay the entire session with full tool outputs visible
  • Stable early context — the developer prompt and frozen timestamp don't change during a session, so backend caches remain valid

Context priming

  • Short developer prompt (the agent is told to respond in markdown)
  • Frozen date and time injected once at session start (doesn't invalidate caches on replay)
  • Configurable system prompt
  • Supports AGENTS.md and SKILL.md (see below)

How to use this

What you need:

  • Linux (no other platforms supported)
  • Podman or docker
  • An OpenAI-compatible API endpoint

Install / setup:

  • Clone this repo
  • Symlink the james script somewhere on your $PATH, e.g. ln -s /path/to/repo/james ~/bin/james
  • Run james build to build the container image
  • Run james ask hello — this will write a default config to ~/.config/james/config.toml (it's expected to fail on the first run since you haven't configured a backend yet)
  • Edit ~/.config/james/config.toml — at minimum set openai_base_url, model, and openai_api_key if your provider requires one

Where things live:

  • ~/.config/james/config.toml — your config (backend, model, prompts, etc.)
  • ~/.local/share/james/homedir/ — the agent's home directory inside the container
  • ~/.local/share/james/container-context/ — the conversation context (sequence of turns)
  • ~/.cache/james/ — HTTP and other caches
  • ~/.config/james/skills/ — global SKILL.md files (optional)
  • .james/skills/ in your project — project-local skills (optional)
  • There is also a docker image to delete if you want a full clean-out.

james mounts these into the container at the paths brown expects, so you only need to think about the host-side locations above.

Now it works like this:

  • Change to the directory you want the agent to have access to. Beware, it has access to all subdirectories too.
  • Run james ask and type your message.
  • The agent streams its response, calls tools as needed, and renders the final answer.
  • Repeat to continue the conversation.

Commands

Run james with no arguments to see the full list. The important ones:

  • ask — send a message to the agent
  • build — rebuild the container image (needed after brown code changes)
  • history — list user messages in the current context
  • clear — clear the context and start over
  • strip <n> — remove question n and its answers (useful if a bad turn is confusing the agent)

Others:

  • run <args...> — pass arbitrary arguments to brown in the container
  • compact [focus] — summarize older context, optionally with a focus hint
  • continue — resume the last turn without adding a new user message
  • rerender — replay the full session with tool outputs shown
  • shell — open an interactive shell inside the container
  • config — open the config file in your editor
  • tokens — print token usage and context window size

Profiles

The config file is organized into named profiles — [default], [work], [personal], etc. Other profiles inherit from default. default inherits from built-in values.

The [default] profile is used when no --profile flag is given.

# ~/.config/james/config.toml

[default]
openai_base_url = "https://openrouter.ai/api/v1"
model = "openrouter/fusion"
model_parameters = { temperature = 0.8, reasoning_effort = "Minimal", verbosity = "Medium" }
# ...

[work]
openai_base_url = "https://api.openai.com/v1"
model = "claude-opus-4.6"
model_parameters = { reasoning_effort = "Medium" }

[local]
openai_base_url = "http://localhost:8080/v1"
searxng_base_url = "http://localhost:8081"
model = "coder"

Switch profiles with --profile:

james --profile work ask "add rate limiting"

To avoid passing --profile every time, set the JAMES_PROFILE environment variable:

export JAMES_PROFILE=work
james ask "add rate limiting"

--profile overrides JAMES_PROFILE when both are set.

Skills and AGENTS.md

AGENTS.md — if a file named AGENTS.md exists in your project root, its content is injected as a system message at the start of every conversation. Use it for project-specific instructions the agent should always know.

SKILL.md — skills are on-demand runbooks the agent can load with the skill tool. Each skill is a SKILL.md file with YAML frontmatter:

---
name: rust-style
description: Rust coding conventions for this project
---

# Rust Style Guide

Use 4-space indentation. Prefer `impl Trait` over generics when possible.

Place skills in ~/.config/james/skills/ (global, available everywhere) or .james/skills/ in your project root (project-local). Only the name and description are primed into the context; the full body is loaded only when the agent asks for it, so skills don't bloat the context window.

Compatibility

Tested with llama-server (llama.cpp) and openrouter.ai. Any OpenAI-compatible API should work.

GitHub Copilot's API does not expose a standard chat completions endpoint. If you want to use Copilot as a backend, bridges like ericc-ch/copilot-api may help.

License

MIT — see LICENSE.md.