colleague

colleague is a swappable coder-agent harness that turns different model backends into repo workers behind one shared task runtime — one runtime, many minds. It is the harness around the model, not the model: you point it at a repo task, pick a backend, and it runs the work through that backend's bounded tool-loop and hands back the same typed result every time.

The point is not a stronger model — it is a different, independent mind, and that diversity is the value. Think of the colleague at the next desk: a peer you hand scoped work to, not a tool you type into. It is explicitly not a chat assistant and not an IDE plugin — it is a headless task runtime you can script, gate, and audit.

the paradigm

One runtime, many minds — swap the backend and nothing else changes

AI coder backends are not interchangeable — a local vLLM model, an OpenAI-compatible endpoint, and a hosted assistant each bring their own SDK, controls, and output shape. colleague is the harness around the model: the same work command runs the task through whichever backend you pick, and the caller never has to care which mind ran it.

Two engines ship today. mock is deterministic and networkless — the CI workhorse, so you can see the shape of a task with no model and no network at all. vllm-openai drives any OpenAI-compatible endpoint with tool calling. Swap one for the other and nothing else about your workflow changes: the same command, the same typed TaskResult.

And this is how it actually runs at home: Claude thinks and designs; colleague does the field-work. Not a stronger mind taking over — a different mind at the next desk, catching what the author's mind glides past.

CockpitStateone render stateTUI · human(ANSI cockpit)TAUI · agent(selector-addressed JSON)JSON · bot(TaskResult on stdout)runtimelobes gatewaysparkcortextool-calling minddrives the loopthorsensestools-off front doorstructurally cannot act
One runtime, many minds, in one glance: the top band is one CockpitState rendered three honest ways; the bottom band is cortex and senses, resolved by role from the lobes gateway. Two facts, joined by the one runtime that consumes one and renders the other.
  • the harness, not the model

    colleague wraps whatever mind you point it at — the same task in, the same typed result out, whichever backend runs underneath

  • mock — the CI workhorse

    deterministic and networkless: runs the full loop with no model and no network, so the shape of a task is testable before any real mind is wired up

  • vllm-openai — any compatible endpoint

    drives any OpenAI-compatible chat endpoint with tool calling; pointing it at a different server is a config change, never a code change

  • the field-work split

    Claude thinks and designs; colleague does the field-work — mechanical sweeps, scoped edits, and second opinions, taken off the designing mind's plate

identitywhoami — the live mindspark · colleague CLI · identity probecolleague 1.48.0 · captured 2026-07-16fresh run · spark, 2026-07-16
$ colleague whoami
nick: colleague
version: 1.48.0
mesh backend: unknown
work engine: vllm-openai
work model: sakamakismile/Qwen3.6-27B-Text-NVFP4-MTP
three tiers

One cockpit state, three renders — and it picks the right one for whoever is looking

Everything colleague shows is one CockpitState — a pure-reducer state tree — rendered through three tiers, and the right tier is chosen automatically for whoever is looking: a human at a terminal, an agent without a screen, a bot that wants only JSON. Nothing is recomputed per renderer; the three views cannot drift apart because there is only one state.

The middle tier is the unusual one. TAUI — Textual Agentic UI — is the semantic mirror of the live cockpit: a serialised, selector-addressed JSON tree plus a Markdown render, so an agent can read and drive the same UI a human sees without a screen reader and without spending an LLM call on a screenshot.

And the cockpit is not colleague's private invention. It is imported from agentfront.taui — agentfront being colleague's one base dependency, the shared agent-first foundation built to fit humans, agents, and bots at once.

  • human

    the ANSI cockpit

    a dynamic colour cockpit on a TTY — redraw-in-place, with popups on real events, like an error popup when a work step fails

    colleague · colleague session · colleague tui live
  • agent

    TAUI — Textual Agentic UI

    the serialised, selector-addressed JSON mirror plus a Markdown render — an agent reads and operates the cockpit without a screen reader or an LLM call

    colleague tui state · colleague tui render --format markdown
  • bot

    structured JSON

    stdout carries exactly one TaskResult and chrome goes to stderr; every run writes a JSON artifact and can stream WorkStep JSONL, so nothing needs a screen at all

    --json on every verb · .colleague/<id>.json · colleague mcp serve
tauitui state — the TAUI mirrorspark · colleague repo · agent render tier (Textual Agentic UI)colleague 1.48.0 · captured 2026-07-16fresh run · spark, 2026-07-16
$ colleague tui state
{"screen": "main", "mode": "planning", "focused": "input.prompt", "header": {"title": "", "subtitle": "", "version": ""}, "zones": {"top.status": {"visible": true}, "left.skills": {"visible": true}, "main.conversation": {"visible": true}, "bottom.input": {"visible": true}}, "panels": [], "popups": [], "status": {"severity": "info", "message": ""}, "work": null, "problems": [], "background": {"theme": "", "animation": "", "frame": 0, "semantic": ""}, "conversation": [], "taui_version": "0.2", "available_actions": [{"selector": "input.prompt", "input": "type", "description": "Send instruction to current agent"}]}
the work loop

You hand it a goal; it hands you a branch — and your tree is never touched

colleague work is the working surface: hand it a goal, and every engine consumes the same typed Task and produces the same typed TaskResult. That uniformity is the whole point — the caller assigns repo work without caring which engine executed it, and the result round-trips through JSON unchanged.

It never works in your tree. Every run gets a throwaway git worktree at your HEAD on its own colleague/<id> branch — your working tree and checked-out branch are never touched, even if the model commits mid-run. And if your tree is dirty, colleague refuses to start until you acknowledge it: delegating never silently sweeps your uncommitted work.

The loop itself is bounded, not open-ended. The model is offered seven base tools plus a curated set of optional ones, and every path out of the loop is one of three: the model signals finish, it answers in prose, or it hits the step budget. Termination is guaranteed, not hoped for.

Before the handoff, three gates run by default — lint autofix, test-integrity, affected tests — and all three are advisory: they surface findings on stderr and in the artifact, and they never wedge the run. Then the work lands the way work should land: branch, commit, push, pull request.

And a run is not a black box while it flies. Every run arms a flight — you can read its live feed, inject guidance, or stop it cooperatively, all over a file-based control plane that lands directives at the next turn boundary. Runs detach to the background, chain episodes until the task is done, and resume where they left off.

  • typed contract

    colleague work "<goal>" --repo .

    one Task in, one TaskResult out — the same shape for every engine, round-tripping through JSON unchanged

  • write isolation

    a throwaway worktree on colleague/<id>

    runs at your HEAD in its own worktree and branch; a dirty tree is refused, not swept — your checkout is never touched

  • the bounded loop

    read_file · write_file · edit_file · list_dir · run_command · culture · finish

    seven base tools plus curated optional ones; termination is guaranteed — finish, a prose turn, or the step budget (default 25)

  • pre-finish gates

    lint autofix · test-integrity · affected-tests

    default-ON and advisory: auto-fix what lint can, flag tests that merely mirror the implementation, run the tests that import the changed modules — findings surface, the run never wedges

  • handoff

    branch → commit → push → PR

    the work lands as a reviewable branch; push and PR are gated so offline and CI runs never reach the network

  • piloting

    flight status · guide · stop — plus --background · --until-done · --continue

    a file-based control plane with cooperative next-turn latency; detach a run, chain episodes with --until-done / --max-episodes, resume with --continue

work loopwork — the dirty-tree refusalspark · colleague repo · write-isolation guard (colleague#149)colleague 1.48.0 · captured 2026-07-16fresh run · spark, 2026-07-16
$ colleague work "hi what is this repo, and which minds are you running on right now?" --repo /home/spark/git/colleague --no-pr
error: working tree has uncommitted changes — refusing to run against a dirty repo
hint: commit or stash your changes first, or pass --allow-dirty to commit them onto the work branch
work loopwork — a real run, pilotedspark · org repo · colleague work + flight feedcolleague 1.48.0 · captured 2026-07-16fresh run · 115da517b128, 2026-07-16
$ colleague work "hi what is this repo, and which minds are you running on right now?" --repo /home/spark/git/org --no-pr
flight: 115da517b128
feed: /home/spark/git/org/.colleague/flight/115da517b128.feed.jsonl
control: /home/spark/git/org/.colleague/flight/115da517b128.control.json
thinking… (waiting on the model — this can be slow on a large model)
step 0: list_dir . [ok]
step 1: culture devex overview [ok]
step 2: read_file README.md [ok]
step 3: read_file AGENTS.colleague.md [ok]
step 4: culture devex explain [ok]
step 5: read_file culture.yaml [ok]
step 6: run_command uv run org whoami 2>/dev/null || echo "uv not available" [ok]
step 7: finish This repo is the AgentCulture org site — source for agentculture.org, with an agent-first CLI (`org`) for site operat... [ok]
handoff: local commit only (--no-pr, no remote, or gh unavailable)
… (per-step thinking lines elided)
task: 115da517b128
engine: vllm-openai
status: ok
summary: This repo is the AgentCulture org site — source for agentculture.org, with an agent-first CLI (`org`) for site operations and agent identity. I'm running on sakamakismile/Qwen3.6-27B-Text-NVFP4-MTP (Qwen 3.6 27B, quantized NVFP4 with MTP), operating as the `org` agent with `colleague` backend.
branch: colleague/115da517b128-hi-what-is-this-repo-and-which-minds-are
the workforce

colleague can staff its own workforce — and a read-only role provably cannot write

Mid-work, a backend may hire. The subagent and subagents loop tools delegate scoped children, each isolated in its own throwaway worktree on a sub/<id> branch, and a merge-subagent integrates the branches afterward — surfacing conflicts, never force-merging them. Plain delegation is capped at depth 2 and fanout 4; with roles, the budget deepens to depth 4 under a global cap of 24 agents per work item, charged before any child does work, so every nesting shape terminates.

Roles are what make the workforce typed. Five built-ins ship, and four of them are read-only: a read-only role is offered neither write_file, edit_file, nor run_command — and the role-aware ToolExecutor refuses a withheld tool even if the model hallucinates the call. In the repo's own words: a read-only role provably cannot mutate the tree.

The table below is not copied from documentation — it is the live surface, exactly as this install reports it.

roleaccesstoolsuse
explorerread-onlyread_file · view_media · list_dir · check_test_integrity · deepthink · memory · finishinvestigate the repo
plannerread-onlyread_file · view_media · list_dir · check_test_integrity · deepthink · memory · finishreason about an approach
reviewerread-onlyread_file · view_media · list_dir · check_test_integrity · deepthink · memory · finishcritique code
validatorread-onlyread_file · view_media · list_dir · check_test_integrity · deepthink · memory · finish · run_testsrun the suite, report pass/fail
writerfullthe full surface — read_file · view_media · write_file · edit_file · list_dir · run_command · culture · devague · subagent · subagents · check_test_integrity · run_tests · memory · finish · deepthinkimplement a change
rolesroles list — the typed workforcespark · colleague CLI · subagent rolescolleague 1.48.0 · captured 2026-07-16fresh run · spark, 2026-07-16
$ colleague roles list
explorer	[read-only]	tools: read_file,view_media,list_dir,check_test_integrity,deepthink,memory,finish	skills: recall*,explore*,review*,agent-config*,doc-test-alignment*,sonarclaude*
planner	[read-only]	tools: read_file,view_media,list_dir,check_test_integrity,deepthink,memory,finish	skills: recall*,explore*,review*,agent-config*,doc-test-alignment*,sonarclaude*
reviewer	[read-only]	tools: read_file,view_media,list_dir,check_test_integrity,deepthink,memory,finish	skills: recall*,explore*,review*,agent-config*,doc-test-alignment*,sonarclaude*
validator	[read-only]	tools: read_file,view_media,list_dir,check_test_integrity,deepthink,memory,finish,run_tests	skills: recall*,explore*,review*,agent-config*,doc-test-alignment*,sonarclaude*,run-tests*
writer	[full]	tools: read_file,view_media,write_file,edit_file,list_dir,run_command,culture,devague,subagent,subagents,check_test_integrity,run_tests,memory,finish,deepthink	skills: all
cortex & senses

The minds are resolved by role — armed with lobes, there is not one model id in the config

colleague drives with two roles. The cortex is the fast, wide-window, authoritative tool-calling mind — it drives every turn of the bounded loop, and nothing about the loop, the gates, or the handoff changes. The senses is a tools-off multimodal front door: it reads the operator's raw request before cortex acts on it and shapes cortex's raw summary back into a conversational reply — it intakes and speaks, but it structurally cannot act.

Cannot act is not a policy promise — it is structural. Every senses call goes out with an explicit empty tool list on the wire, so a senses request cannot carry a tool schema at all; and the senses module imports neither the tool executor nor subprocess, so even a hallucinated tool call from a misbehaving senses model produces only an advisory packet — the repo tree provably untouched.

Both minds resolve by role, not by hardcoded model ids: with a lobes gateway armed, colleague's own config carries zero model ids — they are read live off the wire. The reference rig — a probed reference, not a requirement — pairs a Qwen3.6-27B cortex with a gemma-4-12B senses on vLLM behind lobes. And in the captures on this page you can watch that brain live across the mesh: cortex ready on spark, senses ready on Thor — one mind split over two machines.

  • cortex

    the tool-calling mind

    fast, wide-window, authoritative — drives every turn of the bounded loop; cortex territory is untouched by the split

  • senses

    the front door that cannot act

    tools-off multimodal intake and speak-back; every call carries an explicit empty tool list, and the module imports neither ToolExecutor nor subprocess

  • lobes

    the discovery rung

    one stdlib GET to the gateway's /capabilities resolves each role's model, endpoint, and readiness — and degrades to the next config rung on any failure, never raising

lobeslobes show — cortex on sparkspark · lobes gateway localhost:8001 · role-resolved mindscolleague 1.48.0 · captured 2026-07-16fresh run · spark, 2026-07-16
$ colleague lobes show
lobes: armed at http://localhost:8001 — reachable

cortex	sakamakismile/Qwen3.6-27B-Text-NVFP4-MTP	[ready (config-proxy)]
  context:  262144
  endpoint: http://localhost:8001/v1/chat/completions
  responsibilities: reasoning, deciding, planning, tool_use, code_repo_actions, validation, final_authority

senses	coolthor/gemma-4-12B-it-NVFP4A16	[not ready (config-proxy)]
  context:  32768
  responsibilities: intake, normalize_input, classify_intent, prepare_context_packet, speak_back
  forbidden: final_decision, repo_action, security_decision
… (stt and tts lobes elided — not ready on spark)
lobeslobes show — senses on Thorspark → thor:8000 · the same brain, across the meshcolleague 1.48.0 · captured 2026-07-16fresh run · spark → thor, 2026-07-16
$ COLLEAGUE_LOBES_URL=http://thor:8000 colleague lobes show
lobes: armed at http://thor:8000 — reachable

cortex	sakamakismile/Qwen3.6-27B-Text-NVFP4-MTP	[not ready (config-proxy)]
  context:  131072

senses	coolthor/gemma-4-12B-it-NVFP4A16	[ready (config-proxy)]
  context:  131072
  endpoint: http://thor:8000/v1/chat/completions
  responsibilities: intake, normalize_input, classify_intent, prepare_context_packet, speak_back
  forbidden: final_decision, repo_action, security_decision
… (stt and tts lobes elided — not ready on thor)
eidetic memory

The second run is cheaper than the first — and failures are the most valuable lessons

Every work item is wrapped in a memory exchange against the repo's eidetic store. Recall-before injects one advisory prior-lessons block — capped at 4,000 characters, advice not authority — and remember-after upserts exactly one idempotent lesson per work item, so re-runs never duplicate. Incomplete runs are recorded too, because failures are the most valuable lessons.

Mid-run, the model can call a memory tool itself — and here the roles hold: a read-only role gets recall only, because remember is a write-capable shell-out the role-aware executor refuses.

Memory is default-ON but triple-gated: the config switch, a .eidetic/ store in the repo, and the eidetic CLI on PATH — all three, or a strict no-op. And it is one store, shared: the same store the operator's own remember and recall skills use, so colleague's lessons and Claude's notes are mutually visible. The two minds read each other's memory.

The saving is measured, not asserted — one live pair, the same task run against a cold store and then a warmed one, quoted here with its run ids as provenance rather than as a general benchmark:

cold503b0a36c33a
steps
10
model turns
9
tokens
23,358
duration
46.4 s
warmc5774404bc3d
steps
2
model turns
2
tokens
4,266
duration
14.1 s

5× fewer steps, 5.5× fewer tokens, 3.3× faster — the same correct answer. And the warm run did not parrot the lesson: it spent its one read step verifying the recalled location against the real file before finishing — recall as a map, evidence still from the territory.

more surfaces

The rest of the desk — every surface honest about its limits

colleague is a big surface for a small install, and the rest of it deserves at least a card each. One thread runs through all of them: every capability states its own limit, in the repo's own words.

  • ask-colleague

    five verbs over colleague work — explore, review, write, feedback, clean — and review is the headline: a diverse second opinion on the committed diff, in a throwaway worktree, before you present or open a PR

  • the ROI loop

    always-on WorkStats on every artifact — exact token counts read verbatim from usage (never estimated), per-tool counts, bytes written — plus a 1–5 feedback grade: stats say what a run cost, grades say what it was worth

  • safety, stated honestly

    the approval gate is a policy gate, not a sandbox — colleague's own docs say so in bold. Writes preview by default, a dirty tree is refused, and repo-shipped hooks are a documented, flagged risk rather than fine print

  • worktrees all the way down

    work items on colleague/<id>, subagents on sub/<id>, ask-colleague verbs in throwaway worktrees — isolation is the cross-cutting story, and colleague clean reaps what a crash leaves behind

  • a mesh resident with organs

    colleague promotes into a Culture mesh member, and it fronts a small organism of sibling CLIs — lobes serves its minds, eidetic its memory, coherence and devague sit alongside — each behind its own published contract

  • voice

    speech-to-text and text-to-speech resolve as roles from the same lobes contract; the [voice] extra arms operator-side capture and spoken replies

  • deepthink

    a second, stronger reasoner escalated at exactly four enumerated points — a declared escalation surface, not a routing policy; no automatic task-to-model routing exists

  • media input

    hand it a screenshot, a diagram, or a voice note — attachments ride the task contract to a multimodal model, and colleague verifies the model actually received them instead of trusting a 200

  • agentfront underneath

    the one base dependency: the agent-first CLI, the TAUI cockpit, and the MCP server all render from one agentfront App — one foundation fitting humans, agents, and bots

dogfood

It runs on real work — this page included

Every capture on this page is a real session, and four of them prove the point on colleague itself, not just in prose. The step trace below is ported straight from the public repo: colleague once built its own website in eight bounded steps, with no step failing.

The other three are this very page. While it was being specced, colleague explored its own repo as ask-colleague's second, independent mind, and that run was graded through the same ROI loop described above. Then, before this page's pull request opened, colleague reviewed the diff itself — its one real catch shipped, recorded as a first-class deviation on the plan's ledger.

portedthe self-build drive — step tracecolleague builds its own website · bounded tool-loop, 8 stepscolleague pre-1.0 drive (as committed) · captured 2026-05-29ported · docs/drive-notes/2026-05-29-website-self-build/notes.md (public repo)
 0: read_file    site/style.css      ok  (7972 bytes returned)
 1: read_file    README.md           ok  (20031 bytes returned)
 2: write_file   site/index.html     ok
 3: list_dir     site                ok
 4: run_command  wc -l site/index.html  ok
 5: write_file   site/index.html     ok   (rewrote)
 6: run_command  wc -l site/index.html  ok
 7: finish       (summary)           ok
… (tallies in the committed notes: read_file ×2, write_file ×2, list_dir ×1, run_command ×2, finish ×1 — no step had ok=false)
dogfoodthe second mind reads its own repospark · ask-colleague explore · worktree-isolated, read-onlycolleague 1.48.0 · captured 2026-07-16fresh run · e41355e8e5ac, 2026-07-16
flight: e41355e8e5ac
feed: /tmp/ask-colleague.jinV5s/.colleague/flight/e41355e8e5ac.feed.jsonl
thinking… (waiting on the model — this can be slow on a large model)
step 0: list_dir . [ok]
step 1: read_file CLAUDE.md [ok]
step 2: read_file README.md [ok]
step 4: read_file colleague/contract.py [ok]
step 5: read_file colleague/loop.py [ok]
compacting the conversation to free context — this can take a moment…
step 13: read_file colleague/subagents.py [ok]
step 14: read_file colleague/roles.py [ok]
step 15: read_file colleague/lobes.py [ok]
step 16: read_file colleague/memory.py [ok]
… (18-step read-only exploration; findings folded into this very page)
artifact: /home/spark/git/colleague/.colleague/e41355e8e5ac.you-are-a-second-independent-mind.json
grade: ask-colleague feedback e41355e8e5ac --rating N
dogfoodthe ROI loop — grading the runspark · ask-colleague feedback · stats say cost, grades say worthcolleague 1.48.0 · captured 2026-07-16fresh run · e41355e8e5ac, 2026-07-16
$ ask-colleague feedback e41355e8e5ac --rating 4 --notes "…"
task:   e41355e8e5ac
rating: 4/5
by:     colleague
notes:  Thorough independent read for the presentation page: confirmed the main map and added specifics the first pass missed (embedder relay-never-consumed boundary, thread-safe subagent budget, dynamic writer allowlist, JSON-not-YAML scenarios) plus honest risks. One subagents step errored mid-run; recovered. Verified against an independent exploration — no contradictions.
dogfoodthe second mind reviews this pagespark · ask-colleague review main...HEAD · lobes armed at thor:8000colleague 1.48.0 · captured 2026-07-16fresh run · 7bd1b67432d0, 2026-07-16
flight: 7bd1b67432d0
feed: /tmp/ask-colleague.AeB4A5/.colleague/flight/7bd1b67432d0.feed.jsonl
step 0: run_command git diff main...HEAD --stat [ok]
step 1: run_command git diff main...HEAD [ok]
step 2: read_file site-astro/src/data/colleague.ts [ok]
step 3: read_file site-astro/src/data/colleague-captures.ts [ok]
step 4: read_file site-astro/src/pages/agents/colleague.astro [ok]
step 8: finish ## Review: /agents/colleague Presentation Page [ok]
status: ok
… (the full review; its one adopted catch below — the other findings were verified and declined, with the checks recorded in the run's feedback)
1. **Fix site.ts:91 role description** — Change "A harness for Qwen" to something backend-agnostic. This is the only claim that actively misrepresents what colleague is.
… (adopted — deviation d1 on the plan's ledger)
$ ask-colleague feedback 7bd1b67432d0 --rating 4 --notes "…"
rating: 4/5
by:     org
what's next

The tracker is public too — this is direction, not a promise

colleague moves fast, and its direction is checkable the same way its facts are: on the open tracker. Four currents stand out in the open issues.

colleague is open source, Apache-2.0, and running for real: the captures on this page are its own sessions, and every fact above traces to the public repo, PyPI, the open tracker, or the CLI's own output. Nothing was invented — the safety story included, limits and all.

The thesis fits in one line: not a stronger mind — a different one, at the next desk, behind one runtime you can script, gate, and audit. Install it, hand it something small, and let review be your first reflex.

Read the code →uv tool install colleague