Two AI coding agents β from different vendors β take turns on a shared task, critically reviewing each other until both agree the work is done.
DepartAI is a free, open-source CLI that orchestrates two AI coding agents in a deterministic, sequential relay on a shared task. Each agent can use a different backend and model β e.g. Alpha on Claude Opus, Beta on OpenAI Codex β so two different model families catch each other's blind spots. Agents hand off context through a shared task log, review each other's work each turn, and stop only when both independently agree the task is complete and every acceptance criterion in a shared spec is checked.
Why this and not a bigger multi-model swarm? Deliberate focus. DepartAI is a single self-contained Go binary β no IDE or plugin lock-in β running a simple, predictable two-agent relay with a spec as the contract. Less ceremony, more determinism.
Bring your own backend. DepartAI drives the official
claudeand/orcodexCLIs, so you use your own LLM subscription(s). At least one must be installed and authenticated β see Prerequisites.
departai
β
βββΊ Interactive REPL with autocomplete
β
βββΊ User types a task prompt
β β
β βββΊ Spec pre-turns (collaborative): each agent contributes Goal +
β β Acceptance Criteria + Files in scope to a shared spec.md before
β β any code is written. Append-only β later agents can extend but
β β not weaken what earlier ones defined.
β β
β βββΊ Relay loop:
β
β Turn 1 (Alpha): Implements navigation + CTA β marks criterion [x] β Complete: no
β Turn 2 (Beta): Reviews Alpha, fixes missing OG image, marks criterion [x] β Complete: no
β Turn 3 (Alpha): Reviews Beta, runs tests, all criteria checked β Complete: yes
β Turn 4 (Beta): Reviews everything, made zero changes β Complete: yes
β βββΊ Consensus + spec satisfied β task ends
β
βββΊ User types another prompt (same task context)
β βββΊ Appended as directive, agents continue from where they left off
β βββΊ /respec re-runs the pre-turn loop to integrate the directive into the spec
β
βββΊ /new to start fresh, /resume to pick a previous task
Why sequential turns? Each agent gets a fresh context window. The task log is the handoff mechanism β each agent reads what was done and continues from there. This avoids context window exhaustion on large tasks.
Why two agents? They critically review each other's work. An agent can only say "Complete: yes" if (1) it made zero code changes during its turn β meaning it reviewed the other's work and found nothing wrong β AND (2) every Acceptance Criterion in the spec is checked off. This forces a real verification cycle anchored to a stable definition of done.
brew install manurgdev/departai/departaiThis installs the binary plus shell completions and the man page (man departai).
On Linux, use go install or the pre-built binaries below.
go install github.com/manurgdev/departai@latestRequires Go 1.25+. The binary lands in
$(go env GOPATH)/binβ make sure that's on your$PATH.
Pre-built binaries for macOS, Linux, and Windows are also attached to each GitHub release.
git clone https://github.com/manurgdev/departai
cd departai
go build -o departai .
mv departai /usr/local/bin/departai # or anywhere on $PATHAt least one supported AI CLI must be installed and authenticated:
Claude Code CLI (default backend):
npm install -g @anthropic-ai/claude-code
claude --versionCodex CLI (alternative backend):
npm install -g @openai/codex
codex --versionYou can switch backends with /config set backend codex or --backend codex.
First run: the very first time you launch
departaiwith no config, it shows a short welcome, detects which backends are installed, and offers to write a starter~/.departai/config.ymlβ defaulting to cross-vendor (Alpha β Claude, Beta β Codex) when both are available.
Check your version anytime:
departai --version # departai vX.Y.Z (os/arch)
departai --version --verbose # + commit, build date, Go toolchainHomebrew installs completions automatically. With go install, generate them
for your shell:
departai completion zsh > ~/.zsh/completions/_departai # zsh
departai completion bash > /etc/bash_completion.d/departai # bash
departai completion fish > ~/.config/fish/completions/departai.fish # fishdepartai # uses current directory
departai --dir /path/to/project # explicit project directoryThe REPL shows a banner with current config and a prompt. Type / to see autocomplete suggestions for all commands:
DepartAI β AI Agent Orchestrator
Work dir : /Users/you/projects/my-app
Mode : dev
Max turns : unlimited
Max turn time: no limit
Log window : unlimited
Retries : 2
Agents:
Alpha : claude / opus
Beta : codex / gpt-5.3-codex
Type a task to start, or /help for commands.
departai (dev)> Build a REST API with user authentication
Run a single task without the REPL:
departai "Build a REST API with user authentication"
departai --dir /path/to/project "Add unit tests"
departai --model opus "Migrate the database schema"
departai --max-turns 6 "Fix the failing CI pipeline"departai tracks an active task. The REPL prompt shows it:
departai> β no active task
departai> Build an API β creates new task, agents start working
departai [20260418-build-an-api]> β task is active, agents finished or paused
departai [20260418-build-an-api]> add auth middleware β adds directive to SAME task
departai [20260418-build-an-api]> /continue β resumes relay without new directive
departai [20260418-build-an-api]> /new β deselects β back to "departai>"
departai> /resume β pick any previous task
- New prompt with active task β appended as a "User Directive" to the task log. Agents read it and act on it. Turn counter resets for
max-turnsbut task log turn numbers keep incrementing. - New prompt without active task β creates a new task from scratch.
/continueβ resumes the active task's agent relay loop (no new directive)./resumeβ shows a list of all previous tasks in the project, select one to make it active (does not run it β use/continueor type a prompt after)./newβ deselects the active task. Next prompt creates a fresh one.- ESC β press during a running turn to stop the agent immediately. The task stays active for
/continuelater.
While agents work, departai shows a bubbletea TUI (alt-screen) with:
- Pinned header β turn number, agent name, model, elapsed time (always visible)
- Live event stream β agent reasoning text + tool calls as they happen
- Token-level text streaming (Claude backend) β text from the agent appears live, character by character, as the LLM generates it. Long generations (e.g. writing an updated spec.md) no longer surface as a silent gap.
- In-flight indicators β each tool call shows a spinner and a
(running Xs)timer while the block is open, so you can tell when an agent is actively working on something vs. when a step has settled. - Spinner + total elapsed in the footer
- Auto-continue β when a turn finishes, a 5-second countdown starts. Press any key to enter review mode, or wait to auto-continue to the next turn.
In review mode (after a turn finishes, press any key during countdown):
β/βorj/kβ navigate between tool callsEnterorSpaceβ expand/collapse a tool call (shows diff for Edit operations)qorEscβ continue to next turn
After the TUI exits, a compact summary is printed to the terminal so the turn activity persists in scroll-back history.
All commands use the / prefix with hierarchical autocomplete.
| Command | Description |
|---|---|
/help |
Show all available commands |
/dev |
Switch to development mode (code-focused) |
/ask |
Switch to ask mode (research / Q&A) |
/config |
Show current configuration |
/config set <key> <value> |
Set a config value (validates models, prompts to save) |
/config save |
Save config to project .departai/config.yml |
/config save global |
Save config to ~/.departai/config.yml |
/model |
Show global + per-agent models |
/model <name> |
Set global model (validated) |
/model alpha [<name>] |
Show/set Agent Alpha's model (validated) |
/model beta [<name>] |
Show/set Agent Beta's model (validated) |
/model <agent> unset |
Clear an agent's override (inherits global) |
/continue |
Continue the active task's relay loop |
/respec |
One-shot: force a fresh spec pre-turn before the next prompt or /continue (re-evaluates the spec to incorporate new directives or current state) |
/resume |
Select a previous task from a list |
/new |
Deselect active task (next prompt = new task) |
/exit, /quit |
Exit departai |
exit and quit also work without /. Press Ctrl+D on an empty line to exit. Ctrl+C cancels the current line without exiting (standard terminal UX).
The REPL supports multi-line input β long prompts wrap automatically to fit the terminal width and the editor grows vertically as you type. The prompt prefix is shown only on the first line; continuation lines align under the input column.
- Shift+Enter inserts a newline (multi-line input). Works in modern terminals that distinguish Shift+Enter from Enter via the kitty keyboard protocol: kitty, iTerm2 (with "Report modifiers using CSI u" enabled), alacritty, ghostty, WezTerm.
- Alt+Enter is the universal fallback for terminals that send Shift+Enter as a plain
\r(Terminal.app default, older terminals). - Enter submits the current input.
Pasting large multi-line texts works as expected β bracketed paste is enabled, so the entire paste is treated as a single insert (newlines inside don't submit early).
Up/Down arrows navigate command history when the cursor is at the first/last line of the input; otherwise they move the cursor between lines. Command history persists across sessions in ~/.departai/history.txt.
| Key | Example | Description |
|---|---|---|
model |
/config set model opus |
Global model for both agents (validated) |
model.alpha |
/config set model.alpha opus |
Override for Agent Alpha (validated) |
model.beta |
/config set model.beta sonnet |
Override for Agent Beta (validated) |
backend |
/config set backend codex |
Default backend (claude or codex) |
backend.alpha |
/config set backend.alpha claude |
Override backend for Agent Alpha |
backend.beta |
/config set backend.beta codex |
Override backend for Agent Beta |
max-turns |
/config set max-turns 20 |
Max turns per run (0 = unlimited) |
max-turn-duration |
/config set max-turn-duration 15m |
Per-turn wall-clock budget (Go duration format, e.g. 15m, 1h30m); empty = no limit |
log-window |
/config set log-window 6 |
Inject only the last N turns into each prompt (0 = full log). Reduces token cost on long tasks |
max-retries |
/config set max-retries 2 |
Retries per turn on a transient backend failure (0 disables) |
mode |
/config set mode ask |
Active mode: dev (default) or ask |
instructions |
/config set instructions ./rules.md |
Custom instructions file |
blocked-commands |
/config set blocked-commands "WebFetch,rm -rf" |
Comma-separated list of tools/patterns agents must NOT use (soft enforcement) |
Every model change is validated against the backend before being accepted (~1-2s). Invalid names are rejected and the previous value is kept.
After any config change, a menu asks where to save: Project (default), Global, or Session only. Ctrl+C on the menu = Session only.
| Flag | Default | Description |
|---|---|---|
--dir |
current directory | Working directory where agents operate |
--model |
(backend default) | Global model (validated on startup) |
--backend |
claude |
Agent backend: claude or codex |
--instructions |
built-in | Path to custom agent protocol markdown file |
--max-turns |
unlimited (0) | Max turns per run; 0 = no limit |
--max-turn-duration |
no limit | Per-turn wall-clock budget (e.g. 15m, 1h30m); empty = no limit |
--log-window |
unlimited (0) | Inject only the last N turns into each prompt; 0 = full log |
--max-retries |
2 |
Retries per turn on a transient backend failure (rate limit, 5xx, network blip); 0 disables |
--version |
β | Print version and exit (add --verbose for full build info) |
--verbose |
false |
More detailed output (e.g. full build info with --version) |
YAML config files loaded in layers (later wins):
- Built-in defaults
~/.departai/config.ymlβ user-global<project>/.departai/config.ymlβ project-level- CLI flags
- Interactive
/config setcommands
# .departai/config.yml
agent_backend: claude # default backend: "claude" or "codex"
backend_alpha: claude # per-agent backend overrides (optional)
backend_beta: codex # Alpha uses Claude, Beta uses Codex
max_turns: 0 # turn-count cap per run (0 = unlimited)
max_turn_duration: 15m # per-turn wall-clock budget (Go duration; empty = no limit)
log_window: 6 # inject only the last N turns into prompts (0 = full log)
max_retries: 2 # retries per turn on a transient backend failure (0 = disabled)
model: opus # default model (alias or full name; depends on the backend)
model_alpha: opus # per-agent model overrides (optional)
model_beta: gpt-5.3-codex # each agent can use its backend's models
# instructions_file: ./my-instructions.md
# blocked_commands:
# - WebFetch
# - "rm -rf"departai supports two modes:
/dev(default) β coding tasks. Agents critically review each other, edit code, run tests, and only declare consensus when both made zero changes and verified the work./askβ research / Q&A / analysis tasks. Agents discuss, gather evidence, cite sources, and produce a written answer. They can edit code if the question demands it, but the default output is analysis, not edits.
Switch from the REPL:
departai (dev)> /ask
β Mode set to ask
departai (ask)>
Or set explicitly:
# .departai/config.yml
mode: askThe active mode is always visible:
- In the banner:
Mode : ask - In the REPL prompt:
departai (ask)>ordepartai (ask) [task-id]> - In
/configoutput
Each mode has its own built-in agent protocol. The dev mode emphasises code-edit cycles + tests; the ask mode emphasises evidence-based reasoning, citing sources, and answering precisely. Both share the same two-agent relay and consensus rule.
Every task gets a spec.md file alongside the task log. It is the stable contract both agents work from: Goal, Acceptance Criteria, Files in scope, Open questions, Decisions log. The orchestrator only declares the task complete when every Acceptance Criterion is checked off β no amount of agent enthusiasm overrides this.
When a task is created, spec.md starts in Status: DRAFT. Before any code is written, the orchestrator runs a spec pre-turn for each agent in sequence:
Spec Pre-turn 1/2 (Alpha): Drafts initial Goal + Acceptance Criteria + Files in scope
from the user's prompt. Sets Status to ACTIVE.
Spec Pre-turn 2/2 (Beta): Reviews Alpha's draft, ADDS missing criteria/files,
moves ambiguities to Open questions. Append-only β
cannot remove or weaken what Alpha defined.
Both agents read the user's prompt and contribute their best version. The cross-vendor diversity catches blind spots in the spec itself, not just in the code.
After the pre-turn loop, the regular relay starts with the spec as anchor. Every turn:
- Reads the spec at the top of the prompt
- Marks
- [ ]β- [x]on Acceptance Criteria as work is verified - Appends rationale to Decisions log when making non-obvious choices
- Escalates ambiguities to Open questions rather than guessing
- Cannot remove or weaken existing criteria β the contract is append-only
When you add a new directive to an active task that meaningfully changes scope, the spec needs to be updated to reflect it. Type /respec before your prompt:
departai (dev) [task-id]> /respec
β Spec re-evaluation queued
Next prompt (or /continue) will run the spec pre-turns first.
departai (dev) [task-id]> tambiΓ©n aΓ±ade login con OAuth
β Spec Pre-turn 1/2 (Alpha) β integrates the directive into the spec
β Spec Pre-turn 2/2 (Beta) β reviews and extends if needed
β Turn N (relay normal con spec actualizado)
/respec is one-shot β it consumes itself after the next prompt or /continue. It applies append-only rules: agents add criteria for the new directive but cannot remove existing ones. If a directive contradicts an existing criterion, the conflict goes to Open questions for the relay to resolve.
If you forget /respec and just type the directive, the relay still incorporates it (agents read User Directives in the task log), but the spec criteria stay as they were β agents may or may not extend them. /respec makes the spec update explicit and verifiable.
The relay stops only when ALL of:
- The last two consecutive turns both report
**Complete**: yes - The spec
StatusisACTIVE(not DRAFT) - Every Acceptance Criterion is checked
- [x]
If agents declare Complete: yes while criteria are unchecked, the orchestrator overrides them and continues the relay with a warning. The spec is the source of truth.
Agents run with full permissions and can use any tool the backend exposes (filesystem, shell, web, MCPs, etc.). For sensitive projects you can configure a blocklist of commands or tools that agents must NOT use.
# .departai/config.yml
blocked_commands:
- WebFetch # block a whole tool
- WebSearch
- "rm -rf" # block a shell pattern
- "git push --force"Or from the REPL:
departai> /config set blocked-commands "WebFetch,rm -rf,git push --force"
β blocked-commands set to 3 commands
When the blocklist is non-empty, departai injects a "Forbidden Commands" section into every turn's prompt instructing agents to refuse and stop if the task seems to require any of them. The second agent's review pass catches violations in the first agent's work.
This is soft enforcement. The agent reads the instruction and is expected to comply. It is not a sandbox or syscall-level restriction. For hard isolation, run departai inside a container or use the host OS's permission system.
Global + project blocklists are union-merged: a project cannot un-block what's blocked globally. The merged list shows up in the banner as Blocked : N command(s) and in /config output.
Long-running autonomous relays can fail in subtle ways: an agent stalls, two agents disagree forever, a task quietly drifts off-scope, the prompt grows linearly forever as the log accumulates. departai includes opt-in safeguards for each.
Set max_turn_duration (or --max-turn-duration) and the orchestrator forcibly cancels a turn that exceeds the budget:
max_turn_duration: 15mWhen set, the prompt for every turn includes a Time budget section telling the agent how long it has, instructing it to checkpoint progress to the task log every 3-5 substantial actions, and to stop gathering context at ~80% of the budget so it can write its turn summary.
If the deadline fires anyway, the orchestrator:
- Kills the agent process via context cancellation
- Appends a synthetic turn entry to the task log marking the timeout
- Continues the relay with the next agent (whose budget is fresh)
The next agent reads the timeout note plus whatever the killed agent had time to write, and picks up from there. Time pressure alone is never a reason for an agent to escalate to the human β it just means the next agent gets a fresh budget.
Agents can pause the relay when they hit a decision the human must make. They add an optional field to their turn summary:
**Complete**: no
**Blocked on**: The OAuth flow needs to know whether to use PKCE or implicit
flow. Acceptance criterion is ambiguous β need human decision.The orchestrator detects the field and surfaces the question:
π§ Agent Beta is blocked
The OAuth flow needs to know whether to use PKCE or implicit flow.
Acceptance criterion is ambiguous β need human decision.
Type a directive to unblock, or /continue to tell agents to decide themselves.
Three responses:
- Type a prompt β appended as a User Directive that resolves the question, relay continues
/continueβ relay continues without new info; the next agent sees the previous block and the protocol's anti-loop rule says "if the human did not respond, decide yourselves"/newβ abandon
The protocol explicitly forbids using Blocked on for time pressure or technical workarounds. Reserved for genuine human-intent decisions.
The spec's Files in scope section names the files agents should be touching. If a turn modifies files outside that list β and doesn't add them to scope with a Decisions log entry β the next agent's prompt receives a warning:
## Scope warning
The previous turn (Turn 4, Agent Beta) modified files NOT listed in `Files in scope`:
- /unrelated/config.go
Either:
- Justify the change in **Decisions log** AND add the file to `Files in scope`, or
- Revert the off-scope change.
Soft enforcement (no syscall blocking), consistent with blocked_commands. The next agent reviews the off-scope change and either legitimises it (adds to scope + justification) or reverts.
Limitation: file-modification tracking relies on Claude's per-tool stream events (
Edit,Write,MultiEdit,NotebookEdit). Codex only exposesBashwith the raw command β modifications inside bash (cat >,sed -i, etc.) are not captured. Detection works when at least one agent is Claude; degrades to no-op when both are Codex.
Two agents can disagree forever β Alpha fixes X, Beta breaks X, Alpha fixes again, ad infinitum. The orchestrator watches for this pattern: if the last 4 turns all touch β₯50% the same files (Jaccard overlap) AND no new Acceptance Criteria have been checked, it injects a warning:
## Possible oscillation detected
The last 4 turns have all touched mostly the same files (foo.go, bar.go) without
any new Acceptance Criteria being checked off.
Step back and identify the root cause:
- Are you and the previous agent disagreeing on the same point?
- Is there a misunderstanding of the spec?
- Is the criterion underspecified?
Take ONE decisive action this turn β or, if there's genuine disagreement that
needs human input, set **Blocked on** with the specifics.
If no progress within the next couple of turns, the orchestrator will stop the
relay and return control to the human.
If the pattern persists for 2 more turns (6 total), the orchestrator stops the relay and surfaces the situation:
π Oscillation detected β relay stopped
Last 6 turns kept touching: foo.go, bar.go
Without new Acceptance Criteria being checked.
Type a directive to break the loop, or /continue to retry one more cycle.
/continue resets the detection β the relay gets a fresh K-turn window to escape. If it loops again, stops again. The same Codex limitation applies: oscillation detection works when at least one agent is Claude.
For very long tasks the task log can grow to hundreds of turns. Injecting the entire log into every prompt is expensive and pushes recent context away from the agent's focus. Set log_window (or --log-window) to inject only the last N turns:
log_window: 6What's preserved regardless of windowing:
- The task header and
## Original Task - All
## User Directiveblocks (directives may add requirements) - The last N
## Turnentries - An omission marker (
> _Turns 1β14 omitted to keep context bounded β full history in task-log.md._) just before the kept turns
The full log on disk is never trimmed β the windowing only affects what's injected into each agent's prompt. The spec acts as the long-term anchor: Decisions log, Open questions, and checked criteria preserve the durable state.
Default is 0 (no windowing) for backward compatibility. Enable on long-running projects.
Backend CLIs occasionally fail transiently β rate limits (429/529), 5xx, or network blips. Instead of aborting the whole relay on a momentary hiccup, departai retries the turn with exponential backoff + jitter:
max_retries: 2 # default; 0 disablesThe failure is classified from the exit error + stderr. Transient errors (rate limit, overloaded, 5xx, timeouts, connection reset) are retried; permanent ones (invalid model, auth failure, missing CLI, cancelled by ESC/timeout) abort immediately β retrying them wouldn't help. On exhausting the retries, the turn fails as before. Configurable via max_retries, --max-retries, or /config set max-retries.
On long tasks the prompt (instructions + spec + task log) grows turn by turn and can approach the model's context window. Before each turn, departai estimates the prompt size and, once per run, warns when it crosses ~80% of the window β suggesting log_window to bound growth:
β Agent Alpha's prompt is ~175k tokens β 87% of the ~200k context window
Bound prompt growth by windowing the task log: /config set log-window 6
The estimate is a backend-agnostic heuristic (it doesn't need a tokenizer); the spec preserves long-term state, so older turns can be safely elided.
Large outputs: a single backend stream line is capped at 16 MB by default (raise with
DEPARTAI_MAX_STREAM_LINE_MB). On overflow, departai surfaces a clear error rather than silently truncating the turn.
Agents follow a built-in protocol (overridable with --instructions):
- Anchor on the spec β the
spec.mdis the definition of done. Mark[x]on Acceptance Criteria as work is verified. Append to Decisions log for non-obvious choices. Move ambiguities to Open questions. Append-only β never weaken or remove existing criteria. - Review first β each agent critically reviews the previous agent's work before doing anything else. Look for bugs, missing edge cases, regressions.
- Fix, don't note β if something is wrong, fix it. Don't just write "there's a bug".
- Run tests β execute existing tests, write new ones if the project has a test framework.
- Incremental work β focus on one aspect per turn for large tasks. Leave clear handoff notes.
- Complete: yes requires (1) zero changes AND (2) all spec criteria checked β an agent can only mark "Complete: yes" if it reviewed the other agent's work, found no issues, made no code changes itself, AND every Acceptance Criterion is
- [x]. This forces a real verification cycle anchored to the spec. - Treat orchestrator warnings as priority β when the prompt includes a
## Scope warningor## Possible oscillation detectedsection, address it FIRST before continuing the work. - Escalate to the human only for genuine intent decisions β set
**Blocked on**: <reason>in the turn summary only when a decision genuinely affects the human's intent and the spec doesn't unambiguously cover it. Time pressure or technical workarounds are NOT valid reasons.
Each turn, agents append a structured block to the task log:
## Turn 3 - Agent Alpha
**Working Directory**: /path/to/project
**Review of previous turn**: Checked Beta's OG image fix β badge text is correct,
image regenerated successfully, grep confirms no stray registration references.
**What I did**: Reviewed all modified files. No changes needed.
**Tests**: Ran `pnpm build` β completed successfully.
**Current State**: Registration fully disabled across all surfaces.
**Remaining Issues**: None
**Next Steps**: None β task is complete.
**Complete**: yes
**Blocked on**: <OPTIONAL β only set when escalating to the human; see Reliability Features above>
---The **Working Directory** field must be the project root (where source code lives), not the task directory itself. If an agent reports a different path than what the orchestrator started with, the task directory is moved to match β this lets agents discover that the actual project lives somewhere else and signal it back.
The orchestrator stops when ALL of:
- The last two consecutive turns both report
Complete: yes - The spec
StatusisACTIVE(not DRAFT) - Every Acceptance Criterion in the spec is checked
- [x]
Since an agent can only say "yes" without making changes, this guarantees a review cycle: implement β review/fix β verify β confirm. The spec criteria requirement adds a second anchor: agents cannot prematurely declare done if the spec still has open work.
<workdir>/
βββ .departai/
βββ config.yml β project-level config
βββ tasks/
βββ 20260418-build-rest-api/
βββ task-log.md β structured handoff log
βββ spec.md β definition of done (Goal, Criteria, Files in scope, ...)
βββ spec-preturn-1-agent-alpha-raw.log β spec pre-turn raw activity
βββ spec-preturn-2-agent-beta-raw.log
βββ turn-1-agent-alpha-raw.log β per-turn activity + output (no internal prompts)
βββ turn-1-agent-alpha-files.txt β per-turn files modified (for scope/oscillation detection)
βββ turn-2-agent-beta-raw.log
βββ turn-2-agent-beta-files.txt
Add the task logs to your project's .gitignore β they contain verbose agent output and are only useful locally:
# departai task logs (local agent output)
.departai/tasks/However, keep .departai/config.yml tracked if you work in a team. This way all developers share the same departai settings (models, max turns, instructions file) when collaborating on the project:
# departai β ignore task logs, keep config
.departai/tasks/
!.departai/config.ymlEach turn generates a log file with:
- Activity β tool calls the agent made (Read, Edit, Bash, etc.)
- Output β the agent's final result text
- Stderr β error output (if any)
Internal prompting (base instructions, protocol) is NOT included β raw logs show only task-relevant information.
If an agent discovers the project is in a different directory than --dir, it reports the real path in its Working Directory field. The orchestrator detects the mismatch, moves the task directory to the correct project, and continues from there.
The orchestrator automatically reads and injects any project convention files it finds:
CLAUDE.mdAGENTS.md.cursorrules.github/copilot-instructions.md
departai/
βββ main.go
βββ .gitignore
βββ go.mod / go.sum
βββ internal/
βββ cli/
β βββ cli.go # flag parsing, config layering, --version, backend availability check
β βββ interactive.go # REPL loop, slash commands, task state, history persistence
β βββ repl_model.go # custom bubbletea REPL (textarea + popover autocomplete)
β βββ onboarding.go # first-run detection + starter-config seeding
βββ version/
β βββ version.go # build/version info (ldflags + runtime/debug fallback)
βββ config/
β βββ config.go # YAML config: load, save, layered merge, per-agent models, retries
βββ tui/
β βββ agentview.go # bubbletea model: streaming + review + auto-continue
β βββ style.go # lipgloss styles
βββ ui/
β βββ ui.go # styled terminal output, spinners, colors
βββ agent/
β βββ agent.go # Agent, StreamingAgent, StreamEvent interfaces
β βββ claude/
β β βββ claude.go # Claude Code CLI implementation + model validation
β β βββ stream.go # stream-json parser (stateful Parser for partial-message
β β β # deltas + stateless ParseStreamLine fallback for legacy)
β β βββ stream_test.go # parser tests (legacy + partial-message paths)
β βββ codex/
β βββ codex.go # Codex CLI implementation + model validation
β βββ stream.go # Codex JSONL parser
β βββ *_test.go # parser + ValidateModel tests
βββ orchestrator/
β βββ orchestrator.go # turn loop, spec pre-turns, prompt builder, consensus, ESC-to-stop,
β # ErrAgentBlocked / ErrTurnTimeout / ErrOscillationDetected,
β # scope + oscillation detection, transient-error retry,
β # context-window awareness
βββ tasklog/
βββ tasklog.go # task directory, log read/write/parse, load (+corrupt-log recovery),
β # spec.md primitives, windowed content, touched-files sidecars,
β # synthetic timeout entries
βββ *_test.go # parsing, spec, windowing, scope, relocate-safety, recovery tests
| Package | Purpose |
|---|---|
charmbracelet/bubbletea |
TUI for the streaming agent view and the custom REPL |
charmbracelet/bubbles |
textarea (REPL input) + viewport (scrollable content) |
charmbracelet/lipgloss |
TUI styling |
knz/bubbline/history |
Persistent REPL command history (~/.departai/history.txt) |
fatih/color |
ANSI colors for non-TUI output |
briandowns/spinner |
Spinner for model validation |
manifoldco/promptui |
Arrow-key menus (save scope, task resume, onboarding) |
gopkg.in/yaml.v3 |
Config file parsing |
The REPL is built directly on
bubbles/textarea(custom multi-line input + inline command popover); only thehistorypackage fromknz/bubblineis used, for persistent history.
Implement the agent.Agent interface:
type Agent interface {
Name() string
RunTurn(ctx context.Context, workDir string, prompt string) (TurnResult, error)
}Then add a case to buildAgents() in orchestrator.go and select it with --backend <name> or agent_backend: <name> in config.
| Backend | CLI | Auto-approve flag | Output format |
|---|---|---|---|
claude |
claude -p <prompt> |
--dangerously-skip-permissions |
--output-format stream-json --include-partial-messages |
codex |
codex exec <prompt> |
--dangerously-bypass-approvals-and-sandbox |
--json (JSONL) |
Both backends implement the agent.StreamingAgent interface, providing live tool-call streaming via the bubbletea TUI. Model validation is backend-specific β each backend's ValidateModel function runs a minimal test prompt to verify the model name is accepted.
The Claude backend uses --include-partial-messages to receive token-level deltas (stream_event lines with content_block_start / content_block_delta / content_block_stop sub-events). The parser is stateful: it accumulates deltas per content block and emits agent.StreamEvents carrying a BlockID so the TUI can update the same entry in place as text grows. This eliminates the "silent gap" the TUI used to show when the LLM generated a single large block (e.g. a Write of an 80 KB spec). The Codex backend continues to emit whole-block events; if a future Codex release adds a partial-stream mode, the same pattern can be applied.
Contributions are welcome β issues, ideas, and pull requests. See ROADMAP.md for where the project is headed and what's up next.
Before submitting a PR, make sure the basics pass:
gofmt -l . # should print nothing
go vet ./...
go test ./... # backend-CLI tests auto-skip when claude/codex aren't installedA full CONTRIBUTING.md (how to add a backend, coding conventions) is on the way.
DepartAI is free and open-source software, released under the MIT License.