sethji
v0.1.1
Published
Multi-agent terminal orchestrator: run AI coding CLIs as a role-based crew (architect, coder, QA) from one terminal.
Maintainers
Readme
sethji
Run several AI coding CLIs as a role-based crew from one terminal. One agent is the
architect, another the coder, another QA. sethji spawns each agent's CLI as a
child process, relays their outputs to one another through a shared transcript, and loops
QA → coder until the work passes.
- Zero runtime dependencies. Pure Node ≥ 18, ESM, raw ANSI for color.
- Safe spawning. Children run with
shell: falseand the prompt is always a single argv element, so prompt content can never trigger shell injection. - Bring your own agents. Built-in adapters for
claude,codex, andgemini; override or add agents in a crew config.
Quickstart
npx sethji list # which agent CLIs are installed?
npx sethji init # write a crew.json you can edit
npx sethji run "add a /health endpoint and a test for it"run drives the default crew (architect → coder → qa, looping back to coder on a QA fail).
You watch each agent live under a colored header like ▌ CODER (codex · write).
One-off, single agent:
npx sethji ask claude "explain what this repo does" --mode readCommands
| Command | What it does |
| --- | --- |
| sethji run "<task>" | Drive the crew over a task. Flags: --crew crew.json --cwd dir --no-color --timeout sec --json |
| sethji ask <agent> "<prompt>" | Run one agent once. Flags: --mode read\|write\|yolo --cwd dir --crew crew.json --timeout sec |
| sethji list [--crew crew.json] | Show known agents (+ ones you declared) and whether each CLI is on your PATH |
| sethji init [--out crew.json] | Write the default crew config to edit |
| sethji help / sethji version | Help / version |
Modes (how much a delegated agent may touch)
| Mode | Access | Maps to |
| --- | --- | --- |
| read | inspect only — default, safe | claude --allowedTools Read,Grep,Glob · codex --sandbox read-only · gemini -p |
| write | may edit files | claude --permission-mode acceptEdits · codex --sandbox workspace-write |
| yolo | full access | claude --dangerously-skip-permissions · codex --sandbox danger-full-access · gemini -y |
⚠️ Safety.
writelets an agent edit files in--cwd;yoloremoves the agent's own guardrails entirely (full file + command access). Only use them in a repo you can revert (commit first), and never pointyoloat a directory you can't afford to lose. Default toread. Headless flags for each CLI drift — confirm with<cli> --helpbefore trusting them.
Crew config
{
"roles": {
"architect": { "agent": "claude", "mode": "read", "persona": "..." },
"coder": { "agent": "codex", "mode": "write", "persona": "..." },
"qa": { "agent": "gemini", "mode": "read", "persona": "..." }
},
"workflow": ["architect", "coder", "qa"],
"loop": { "from": "qa", "to": "coder", "maxRounds": 2 }
}- roles — each maps a role name to an
agent(adapter), amode, and apersona(the system instruction for that role). Optionalmodeloverrides the model for that role. - workflow — the order roles run in.
- loop — after
from(QA) runs, its verdict is parsed. OnVERDICT: FAILwith rounds left, control jumps back toto(coder) and continues. An unknown or missing verdict counts as PASS, so the loop can never spin forever.
Personas
- architect — writes a numbered plan + acceptance criteria, no full code.
- coder — implements the plan exactly and addresses QA feedback.
- qa — reviews and ends with EXACTLY one line:
VERDICT: PASSorVERDICT: FAIL: <reason>.
Each turn's prompt is: role persona + the task + the full transcript so far +
"respond as <ROLE>". The transcript is the relay channel between agents.
Declare the AIs you have — the agents roster
The optional agents block in your crew config is where you list the AIs available on
your machine. Add brand-new agents or override a built-in's bin/modes. Each entry is
pure data — bin plus a modes map whose arrays are argv templates; the literal {prompt}
token is replaced with the real prompt as one argv element:
{
"agents": {
"claude": { "bin": "claude" },
"qwen": {
"bin": "ollama",
"modes": {
"read": ["run", "qwen2.5-coder", "{prompt}"],
"write": ["run", "qwen2.5-coder", "{prompt}"],
"yolo": ["run", "qwen2.5-coder", "{prompt}"]
}
}
},
"roles": {
"architect": { "agent": "claude", "mode": "read", "persona": "..." },
"coder": { "agent": "qwen", "mode": "write", "persona": "..." },
"qa": { "agent": "claude", "mode": "read", "persona": "..." }
},
"workflow": ["architect", "coder", "qa"],
"loop": { "from": "qa", "to": "coder", "maxRounds": 2 }
}A role's agent must name either a built-in (claude, codex, gemini) or something you
declared here. Check what's wired up with sethji list --crew crew.json — your custom
agents show with a (custom) tag and an installed/not-found status.
Using a local model (ollama + qwen)
ollama serve & ; ollama pull qwen2.5-coder # install the model
sethji list --crew crew.json # confirm "ollama installed"
sethji run "add /health endpoint" --crew crew.jsonHow collaboration actually works. sethji is an orchestrator, not a router — it does not make Claude internally call qwen. It runs each CLI as a separate child process and relays text between them through the transcript: claude's plan → fed as the prompt to qwen → qwen's output → fed back to claude QA. They cooperate via passed text.
Caveat for local models as the coder.
claude/codexedit files themselves in--cwd.ollama run qwenonly prints to stdout — it has no file-write tool, so a qwen "coder" emits code as text without writing it to disk. Keep local models in text roles (architect/QA) and letclaude/codexbe the writer, unless you wrap the model in your own apply-the-diff step.
Programmatic API
import { orchestrate, DEFAULT_CREW } from "sethji";
const { transcript, verdict, rounds } = await orchestrate({
task: "add a /health endpoint",
crew: DEFAULT_CREW,
cwd: process.cwd(),
});Develop
npm test # node --test, no network, uses a stub agentLicense
MIT © Yashwant Midha. Free to use, modify, and distribute — see the LICENSE file for the full text.
