Repository navigation
Releases
0.18.0 — Audit r5 hardening
Cohort 0.18.0 — Audit r5 hardening
Installing
Clone this repo, then ./installer/bootstrap.sh --ide claude.
Or hand an AI agent AGENTS.md and ask it to install Cohort for you.
Do not
pip install cohort. That name on PyPI belongs to a different project by different authors, an unrelated multi-agent orchestration tool. Installing it will look like it worked but won't install this software. There is no PyPI release of Cohort, by design; cloning this repository is the only supported path.
Highlights
- Audit r5 remediated. A 15-worker crew closed the r5 findings and the actionable r4 leftovers (#305), and the residuals followed in #308:
- my-office quarantine hardened against symlinked artifacts
- ratchet evaluator jailed
- dashboard token kept to the URL fragment, never sent to the server
- staging swapped in under a lock
- global
--dry-runhonoured by every command or refused
/consult-gptis code, not prose. ChatGPT consults go throughcohort engine consult gpt: the egress, secret and size gates run first, then codex runs inside a bubblewrap jail that can see only the prompt.- The grok doer is xAI's Grok Build (#307). The old community grok-cli's API path was retired. Grok now runs again under Cohort's jail, which no longer mounts your saved
~/.groklogin. - Local records never reach an engine.
.cohort/sessions,feedback,proposalsandstate(git author identity, private notes) are excluded from every engine worktree and refused by the agentic read tools (#308).
Known limitations
- No PyPI package. Deliberate; see the warning above.
- codex reads outside the prompt when bubblewrap is absent. The consult says so before it starts. Install
bwrapfor the jailed path.
Changelog
Changed
- The grok CLI doer is now xAI's Grok Build. The community
grok-cliCohort used to
drive is unmaintained and its API path was retired (every dispatch returned a 410), and
Grok Build's installer takes over thegrokcommand — so Cohort was building argv the
new binary rejects outright. It now speaks Grok Build's flags (--cwd,--max-turns,
--permission-mode bypassPermissions,--disable-web-search), invokes the resolved
binary rather than a PATH lookup, and accepts eitherXAI_API_KEY(what Grok Build
reads) orGROK_API_KEY(what Cohort's registry declares). Confinement is unchanged and
still Cohort's bubblewrap jail, not the vendor's own sandbox. - Compiled project doers are labelled "(project doer — write-capable)" instead of "advisory
office agent"; my-office help derives the gated kinds fromGATED_KINDS;--layerand
--toare accepted as aliases on the add-* andeditcommands (#300). - Dashboard aggregate cache TTL is 30 s (above the poll), session/feedback feeds parse only the
newest records, parity parses canonical once per poll, and the YAML loader uses libyaml when
available (#295). - CI: bubblewrap can sandbox on ubuntu-24.04 (user namespaces unlocked), the confinement tests
fail rather than skip there, and the real-venv bootstrap round-trip runs on Linux (#277).
Security
- The grok jail no longer mounts the user's real
~/.grok. Grok Build stores its saved
login there, so the previous read-only bind exposed that credential to the engine — and
still broke it, since it writes session state to the same directory. The ephemeral HOME
now gives the engine its own, and the API key reaches it through the scrubbed environment. - No engine path is handed Cohort's local records any more (#306, completing #275).
.cohort/sessions,feedback,proposalsandstate(git author name and email, private
notes) are excluded at the single worktree creation point, so one-shot and agentic
proposeand the ratchet get the same exclusion the CLI doers had; a worktree whose records
could not be excluded is discarded. The agentic read tools refuse those paths by spelling
(case-folded) and by symlink target, and hide them from listings, grep and find. - A quoted
signed_bykey is no longer read as absent (#306).'signed_by' = [...]is
valid TOML; the array reader now unquotes keys like the scalar reader (#276), so signature
pinning no longer silently fails open. - A symlinked artifact no longer walks through the my-office quarantine (#285). Discovery
(compile and quarantine alike) reads only<canonical>/<kind-dir>/*.md, refuses an entry
whose ownlstatis a symlink, never descends a linked directory, and a pull that touches a
symlink falls back to a whole-tree record.my-office review --reset/office review --resetrebuild a corrupt pending store fail-closed from disk (#294); the office baseline
now folds at approve time, and--reset --allwithholds everything regardless of a legacy
baseline. The remedy text no longer says "delete the file". ratchetconfines the evaluator (#286, #237). The evaluator executes engine-written
code, so it now runs under the scrubbed environment with an ephemeral HOME and, where
bubblewrap is present, inside a no-network jail;_githas a timeout, non-interactive git
hardening andcommit.gpgsign=false; the evaluator is killed as a process group; the codex
path applies the wire cap and worktree secret scan; the egress opt-out is read from the repo./consult-gptis gated in code (#266). OpenAI Codex is a registered engine
(gpt/chatgpt/openaialiases;xaifor grok) andcohort engine consult gptruns the
egress marker, size cap and secret scan on the assembled prompt beforecodex exec --sandbox read-only, jailed under bubblewrap to an empty scratch root and an ephemeral HOME
holding only codex's auth; without bwrap it says so. The command file no longer runscodex execitself.engine reviewchecks thereviewrole, so a consult-only engine cannot be
routed to the xAI review transport.- Doer preflight refuses tracked symlinks (#288) before reading anything; the doer
worktree no longer ships.cohort/sessions,feedback,proposalsorstate(#275). - Secret scanner catches escaped JSON, YAML block scalars, bracketed and prefixed literals,
:=, lowercasebearer, AWSASIA…andxai-…keys (#289). - The dashboard token is no longer served to any loopback client (#293): it travels only
in the URL fragment the CLI prints and opens. - Executor refuses a destination whose parent escapes the declared root via a symlink
(#276);[update]honours quoted TOML keys.
Fixed
cohort gc --scan-deadline SECONDSexposes the scan budget (finite, > 0) and reports how
many candidates went unexamined, in text and--json; a timed-out scan no longer prints
"Nothing to reclaim" (#306).- The dashboard says when the office feed is partial: "⚠ N projects unreadable", with the
names on hover (#306). - Engine worktrees tolerate non-UTF-8 tracked file names instead of crashing the dispatch.
import cohort.clino longer loadsurllib.request; the xAI transport imports it on
first use, trimming every hook invocation (#306).- The test suite no longer leaks
cohort-proposal-*worktrees into the system temp dir;
pytest keeps only failed runs' temp dirs (#306). - Global
--dry-runis honoured by every command or refused with exit 2 (#267);status
exits 1 when it printed a!diagnostic and--jsoncarriesok;my-office syncnames a
real remedy and exits non-zero on a failed recompile;/api/statelists skipped projects (#270). - Staging is swapped in under the manifest lock (#291); roster and adopt append under the
lock (#292); the rollback ledger is locked and atomic; quarantine reconcile scans under the
lock (#290). - Duplicate YAML keys are an E001; an unknown
toolsname is E021 (the vocabulary is declared
incanonical/schema/agent.json);_SHARED_KEYSderives from the schema; the frontmatter
delimiter is only recognised at column 0;docs/quick-reference.*shows each command's own
description (#297, #299). - Unquoted YAML timestamps no longer drop records or 500 the dashboard; quoted
auto_capture
is read correctly;gckeeps the newest transcripts by number and has a scan budget;
reportsays an issue may already exist on a timeout (#299, #268, #269). - Docs:
AGENTS.mddocuments the comma form of--ide(repeats keep only the last);
staleness-checkalways exits 0; the orchestration-cap lint scans README and docs; RFC
0001's prerequisite is marked resolved; the autonomy memory states the machine-local truth;
README qualifies "no phone-home" and listsreport/update-checkegress (#296, #271, #279, #280). - Dashboard: every dialog control has a label,
--faintmeets AA inside cards, action buttons
carryaria-label, the three homes are OFFICE / MY OFFICE / PROJECT;--helpuses plain
formatting underNO_COLORorTERM=dumb(#298, #300). - Secret scanner: quoted keys and label-glued assignments were exempt (#265). The
generic-assignment rule required the separator to follow the identifier directly, so
{"password": "..."}(JSON, the shape a config dump or API error body takes) and quoted
YAML/TOML keys never matched. And because a harmless label's value token runs to the next
whitespace,WARN: DB_PASSWORD=...,x=1;PASSWORD=...and a backtickedPASSWORD=...
were consumed as the label's value and skipped over. Every egress path that relies on the
rule was affected:cohort reportbodies, the CLI-doer tracked-file scan, the API toolbox
per-read scan, and/consult-*prompts. The identifier may now be closed by a quote, and
a consumed value is rescanned from its start so an embeddedKEY=valueis a candidate in
its own right. Two escaped-source fixtures the old scanner missed in this repo's own tests
are now declared in the suppression manifes...
0.16.0 — Agent-driven install
Cohort 0.16.0 — Agent-driven install
Installing
Clone this repo, then ./installer/bootstrap.sh --ide claude.
Or hand an AI agent AGENTS.md and ask it to install Cohort for you — that is a supported path as of this release, and it is how most people here actually install it.
Do not
pip install cohort. That name on PyPI belongs to a different project by different authors — an unrelated multi-agent orchestration tool. Installing it will look like it worked and will not install this software. There is no PyPI release of Cohort, by design; cloning this repository is the only supported path.
Why a minor bump for a mostly-fixes release
AGENTS.md establishes a supported install contract. Since Cohort is distributed by asking an agent to install it rather than through a package index, those instructions are part of the product surface rather than documentation about it — a new supported surface, not a bug fix.
Every step in it carries a check the agent must pass before continuing, because a step you can perform but cannot verify is not finished.
Known limitations, unchanged
- The grok CLI still does not reach xAI. This release fixes the half that was ours — the bubblewrap jail never bound the launcher, so a grok installed the documented way (
npm install -g --prefix ~/.local) was invisible to it and had, in fact, never worked. It now runs, authenticates, and reaches the API — where xAI rejects it with410 Live search is deprecated. That part is upstream. Cohort detects the failure and announces the fallback to API-direct rather than serving you an error string as a review. - No PyPI package. Deliberate. See the warning above.
Added
AGENTS.md— the install contract for an AI agent. Cohort is distributed by asking an
agent to install it, not via a package index, which makes the install instructions part of
the product surface. Every step carries a check the agent must pass before continuing,
because a step you can perform but cannot verify is not finished. It also states, up front,
what an installer should tell the user before installing: that this writes into their home
directory, and that consult commands send source to a third-party vendor by default.- A prominent warning that
pip install cohortis a different project. The name on PyPI
belongs to an unrelated multi-agent orchestration tool. Under a package-index model that is
a naming annoyance; under agent-driven install it is a correctness bug — an agent told
"install cohort" will plausibly run it, install the other package, and report success. - An inbound-licence statement in
CONTRIBUTING.md. No CLA, no copyright assignment —
opening a pull request is the agreement, and contributors keep their copyright. The clause
that earns its place is right-to-license: work written on an employer's time may belong to
the employer, and that cannot be undone after a merge and a release.
Fixed
- The grok CLI is reachable inside its sandbox. The bubblewrap jail bound
/usrbut not
the real home, so a grok installed the documented way (npm install -g --prefix ~/.local)
was invisible and every run died atexecvp. The CLI doer had therefore never worked for a
user-local install. Binding the launcher alone is not enough — npm installs it as a symlink
into a package tree — so the launcher's directory and thenode_modulesroot above its
target are both bound read-only, skipping anything already under/usr. - A grok CLI run that fails at the vendor is no longer served as a review. grok-cli reports
API errors as an ordinary assistant turn and still exits 0, so a well-formed transcript could
contain nothing butSorry, I encountered an error: … 410and be handed back as the answer.
Only an entirely failed run counts, so a transient error followed by real analysis is still
a review rather than discarded work. cohort initno longer scaffolds repos that commit their engine transcripts. Transcripts
record what an external engine read and was sent — excerpts of the repo's source plus the
model's analysis. They are a local audit trail, and nothing else in the scaffold ignored
them, so a routinegit add -Acommitted them and a repo that later went public published
the lot.- Office quarantine prunes records whose artifact no longer exists.
office_reconcilewas
written for this and called from nowhere, so office pending records only ever grew and
cohort office reviewlisted identities a reviewer could not resolve — the artifact they
would approve had been deleted upstream or superseded by a later pull. - Removed
ToolPolicyError, an exception class defined once and never raised or caught, left
behind when tool refusals became return values.
0.15.0 — Multi-vendor unblock
Cohort 0.15.0 — Multi-vendor unblock
Install by cloning this repo, then ./installer/bootstrap.sh --ide claude.
Do not
pip install cohort. That name on PyPI belongs to a different project by different authors — an unrelated multi-agent orchestration tool. Installing it will look like it worked and will not install this software. There is no PyPI release of Cohort; cloning this repository is the only supported path.
⚠️ Behaviour changes — read before upgrading
This release changes things people rely on. That is why it is a minor bump rather than a patch, quite apart from 1.0.0 being deliberately postponed.
- A secret-scan suppression can no longer authorise its own egress. Entries reachable from the default branch apply silently; entries committed only on your current branch now require an interactive confirmation on a TTY. CI, git hooks and agent shells are refused — none of them has one.
- The API reviewer enforces the same gate as the CLI doer, and reads the manifest from a committed ref rather than your working tree.
- A vendor CLI that is present but broken now fails loudly and falls back to the API transport with a printed note, instead of reporting success with an empty body.
If you script against cohort engine …, read the Security section below first.
Known limitations in this release
- The grok CLI does not work. The bundled grok CLI is rejected by xAI's current API (
410 Live search is deprecated), so grok runs API-direct. Cohort detects this and announces the fallback rather than failing silently. Fixes for the sandbox reachability side landed after this tag. - Python 3.10 is genuinely supported again.
weekly-reportandmonthly-reportused to crash there, and the feedback trend silently discarded every record. Both are fixed in this release.
Added
/barney— explain a complex topic so simply nobody can get it wrong. Encodes the
method (name the one idea, decide what to omit, say where the analogy breaks, order steps
so each uses only what is already explained) rather than just asking for simpler words.
Bans "it's simple" and "just", and holds accuracy above simplicity: a danger or an
irreversible step survives the simplification.- A declared, digest-bound secret-scan manifest (
.cohort/secret-scan-allow.txt). A repo
whose fixtures are credential-shaped by construction — any secret scanner, this one
included — could not send itself to an external engine at all. Each entry binds a value
digest to a path, so exempting a file is not a blind spot: a real credential added beside
a declared fake still blocks. Refusals print the exact declaration lines, so unblocking
never means guessing a digest. - A
reasoninggrok tier (grok-4.20-0309-reasoning), probed live and confirmed to
serve back its own name.grok-4-heavydoes not exist on the account, and
grok-4.20-multi-agent-0309is deliberately unregistered — chat/completions rejects it, so
naming it would hand callers a model that fails at dispatch. - A
vendor-reachabilityaudit dimension, always-on, whose only acceptable evidence is a
command that ran and the output it produced (#243). Reading the dispatch path and
concluding a vendor works is the exact failure it exists to catch. - Model-tier rotation across audit runs —
balanced→complex-heavy→simple-heavy,
with the tier recorded per dimension in the ledger so the false-positive rate becomes
tier-aware (#240). - A README section stating what leaves your machine, to whom, per command, and the exact
cohort:egress=denymarker that stops it — with the warning that prose does not work,
only the literal marker.
Fixed
- The secret scanner no longer flags ordinary code. Self-referential keyword arguments
(max_tokens=max_tokens), forwarded attribute references (token=srv.token) and type
annotations (token: bytes) read as credential assignments. Detection is unchanged —
aGITHUB_TOKEN:orDATABASE_PASSWORD=carrying a real value still trips. Two exemptions that
went too far were caught by the audit and closed the same day: aname.surnamepassword
and any value merely starting with a type name both slipped through, the latter in:
form — which is how YAML, the dominant secrets-config format, writes every assignment. - A failing vendor CLI no longer reports success. No doer path checked the exit code, so a
broken engine read as "reviewed your repo, had nothing to say". A CLI that is present but
broken now raisesDoerFailedErrorand falls back to the vendor's API transport with a
printed note — never silently. Gate refusals are still never retried elsewhere. my-office syncno longer reports success when placement failed. A post-sync recompile
failure returned the same empty list that means "nothing installed"; it now reports
recompile_failedand says the IDE files are stale.- A corrupt manifest fails closed instead of crashing.
load_manifestraised a raw
JSONDecodeErrorout of whichever command touched it; it now raises a typed error naming
the file and the recovery, andpersistkeeps a.json.bakso there is something to
restore from. "Absent" remains a legitimate state, distinct from unreadable. - Concurrent engine reviews no longer overwrite each other's transcripts. Slots are
reserved atomically instead of computed; five parallel reviews previously produced four
transcripts, losing the record of what was egressed exactly when the fan-out was widest. - A timed-out doer now takes its whole process group with it. Only the direct child was
killed, so helpers an agentic CLI spawned outlived the wall-clock cap — still spending
against the vendor API, still writing into a worktree about to be deleted. - Bounded work that was unbounded: a 32MB client-side cap on the response body both xAI
transports buffer (max_tokensis a request hint, not a resource bound), and timeouts on
the worktree and post-doer git calls, which sit on paths a user waits on. - A failed rollback-ledger write is reported. It was swallowed, so the advertised one-shot
undo silently did not exist until someone reached for it. - Dashboard controls are keyboard-operable — the "create" cards were click-wired
<div>s
and the reload chip a bare<span>; action results and errors now announce via a live
region instead of being silent visual toasts. /consult-gptno longer appears to hang. Codex was never the problem: the command
lacked a stdin redirect and a timeout budget, so a slow consult looked identical to a hung
one.- Documentation that asserted something false:
(no local file access)was printed on paths
that do send file contents,DESIGN.mddescribed a narrower quarantine scope than
GATED_KINDSenforces, andconsult-grokrecommendedgrok-4-latest— an alias that
resolves togrok-4.3, not the flagship.
Security
- A secret-scan suppression can no longer authorise its own egress. The refusal prints
paste-ready declaration lines into the caller's context, so an agent atsupervisedor
autopilotcould commit them and re-dispatch with nobody looking — and egress is
irreversible. Entries reachable from the default branch apply silently; entries
committed only on the current branch require an interactive confirmation on a TTY, so
an agent's shell, CI and hooks are refused. Confirmation authorises declared fixtures
only — a credential nothing declares is never waved through. - The API reviewer honours the same gate as the CLI doer. Its toolbox scanned without the
manifest, so on a repo with credential-shaped fixturesread_filerefused its own source
andgrepskipped it silently — a review could look complete while missing exactly the
files it was asked to check. It also read the live tree, letting an uncommitted edit widen
what may be sent; it now reads a committed ref, like the doer.
v0.14.0 — Dashboard usability
Changed
- Dashboard UI/UX overhaul (from a multi-vendor UX
/scout). The dashboard now
answers "is anything wrong / what do I do?" at a glance: a "needs attention" strip
under the header surfaces only the non-green states (source broken, IDE output behind,
unmanaged files, commits behind, stale context, low-rated agents), each linking to its
fix, and collapses to a quiet line when all's well. The static "Under the hood" explainer
is demoted to a closed disclosure at the bottom (its "wire" now animates only during a
pending recompile/update), and sections are reordered to the company/you/project mental
model with telemetry last. Status vocabulary is now plain and actionable —parity→
compiled ("IDE output is behind your source — recompile"),wiring→ connected,
not on roster→ inactive — with explanatory role-chip tooltips (advisor / doer /
router) and a plain-English Recompile tooltip. The trust-critical⚡ doerflag is now
amber and legible; kind-tag colours no longer collide with the green/amber/red state
palette; the project switcher looks clickable; the sparkline grows from a true zero
baseline; dialog dropdowns are themed.
Fixed
- Dashboard no longer blanks on a degraded response (a regression from 0.13.0's
/api/statefailure-isolation): the client now detects the degraded 200, shows a
persistent error banner, and keeps the last good view instead of throwing on the missing
roster and rendering a blank page. - Keyboard focus and an open project switcher survive the 6-second poll — the auto-refresh
no longer dumps a keyboard user back to the top of the page every poll (it was silently
undercutting the accessibility work). - The dashboard "live" indicator now reflects real poll health — after a server restart
(or any 401 / repeated poll failure) it flips to "disconnected — reload" with a one-time
toast, instead of pulsing green while every request silently fails.
v0.13.0 — Sandbox & dashboard hardening
Security
- External-engine doers hardened (audit r2). Closed a TIOCSTI jail-to-host escape:
the grok bubblewrap argv gains--new-sessionand both the grok and codex doers now run
withstdin=DEVNULL+start_new_session=True, so a compromised sandboxed engine has no
controlling TTY to inject host shell commands through. Narrowed the grok jail's readable
/etc: instead of binding all of/etc, only the TLS + resolver paths are bound
(existence-guarded), so machine secrets under/etcare no longer exposed to a model over
the open network. The egress opt-out is now derived fromrepo_root/.cohort/project_context.md
when a caller omits the context (fail-closed), so a doer can't silently ship an opted-out
repo. (#225, #227, #229)
Fixed
- Dashboard
/api/stateno longer re-scans everything every poll, and one bad file can't
500 the whole dashboard (audit r2). A short-TTL aggregate cache memoizes the office-wide
read-only scans (parity re-parse, cross-project activity/scorecards,list_projects) —
invalidated on every mutating action — instead of O(projects × files) work every 6s; and
per-project reads now skip+log a corrupt/non-UTF-8 file with ado_GETbackstop that
degrades gracefully rather than failing the whole response. (#226) - filelock stale-steal / token-release made atomic (audit r2). Every lock removal now
goes through an atomicos.replacecapture + verify +O_EXCLreinstate, so two waiters
can no longer delete each other's fresh lock in a stale-gated race. (#230) - The agentic engine loop now has an overall wall-clock deadline (default 600s, checked
each round) and a bounded retry backoff, so a slow vendor API can't pin a user-waited
consult/propose for ~90 minutes. (#231)
Changed
- Dashboard accessibility (audit r2): the feedback sparkline no longer conveys up/down by
color alone (per-bar labels + direction), aprefers-reduced-motionpath stops the
continuous animations, low-contrast--fainttext now meets WCAG AA, focusable cards show a
visible focus ring, and the project switcher is labeled. (#232) - Raised the external-engine wire-byte cap 5 MB → 50 MB so
engine review/propose grok
isn't refused on ordinary repos (the cap targets runaway data blobs, not normal source);
still fail-closed. Recorded the grok-cli-as-doer decision as an amendment to RFC 0004
(it reversed the RFC's "grok is API-direct, never a doer" decision), and corrected stale
in-code docstrings. (#233, #228)
v0.12.0 — CLI-first external engines
Changed
- External engines prefer the local sandboxed CLI over the API-direct path. When an
engine's CLI is installed, agents now run it locally (real, worktree-scoped repo access)
instead of packaging a payload to the vendor API — because a CLI-driven engine can read
and edit the actual repo, while the API only ever sees what's sent. Codex was already
CLI-first; grok was the gap.cohort engine review / consult / propose groknow prefer
the bubblewrap-sandboxed local grok CLI (a new read-onlyrun_grok_reviewruns grok
in a throwaway worktree and keeps only its answer; propose emits the worktree diff,
never auto-applied) and fall back to the xAI API-direct path with a printed note when
grok/bwraparen't present. The read and write paths share one gate helper, so both
run the identical egress/secret/wire-byte gates before grok — and the API path is
reachable only when the CLI is absent: a gate refusal on the CLI path never falls back to
the API. A--footprintviolation on the CLI propose path now exits non-zero, matching
the API path's rejection. Security-reviewed; the "grok-cli is broken/unsandboxed"
guidance (a pre-0.10.0 leftover) is removed.
v0.11.0 — Generative brainstorming
Added
/brainstorm— the generative sibling of/audit. A recurring, rotating,
ledger-backed command for generating and pursuing new opportunities and ideas. Where
/auditfinds what's wrong with what exists,/brainstormfinds what could exist,
running the same machinery (cross-vendor, coordinator-synthesized, read-only/advisory)
inverted for creativity: diverge wide across ten creative lenses (jobs-to-be-done,
cross-industry analogy, inversion, first-principles, constraint-shift, tech-leverage,
moat/network-effect, adjacent-expansion, persona, timing) with judgment deferred and
cross-vendor used for divergence not convergence; converge via cluster/score/
red-team; then pursue — each survivor becomes a pursuit plan (riskiest assumption →
cheapest validating experiment → hand-off to/scout, a spike, or/crew). Keeps
docs/brainstorm/ledger.mdso it compounds run over run and never re-generates a killed
idea. Read-only and advisory — it points at what to build or learn next, never builds.
v0.10.0 — Recurring audit & the supervision dial
Added
- Working memory: continuous mid-session capture, consolidated at boundaries.
Context is now staged as you work, not only at a boundary. A new global
working-memorymemory prompts the model to stage durable context at task milestones
(cohort working-note "…"), and a deterministicStophook (cohort working-capture)
records what changed each turn as a backstop — both into a git-ignored, disposable
.cohort/state/working-memory/. At the next compaction or session start,
compact-recall/session-recallsurface the staged notes so the durable ones are
promoted into memory and the rest cleared. This captures the reasoning an exit can't
(there's no model turn at exit) because it's written during turns. Adds a canonical
stophook event, mapped across all three adapters. Governed by the sameauto_capture
opt-out. session-recall— the exit→next-session memory bridge. AtSessionEndthe
model gets no turn and its context is already gone, so nothing model-authored can be
saved at exit — which is how a closed session lost its context. A new global
session-recallhook closes the gap from the next session's side: on a
non-compactionsession_startit surfaces the prior session's auto-captured record
once and injects a nudge to promote its key decisions, in-flight state, and open
questions into durable memory before resuming. It writes nothing but a git-ignored
marker (so each record surfaces at most once) and stays silent on thecompact
source, wherepost-compact-memoryalready owns the recall. The exit-time analog of
thepre-compact-capture/post-compact-memorypair.- Grok can write code natively, sandboxed by bubblewrap.
cohort engine work grok
now dispatches grok-cli as a write doer that edits a throwaway worktree directly — the
Codex-equivalent "native filesystem" path, so Grok can implement and review with real
file access, not only propose a gated patch. Because grok-cli has no sandbox of its
own, Cohort imposes one with bubblewrap: every write is kernel-confined to the
worktree, the user's real home (SSH keys, other repos) is not mounted, and only the
network for the xAI API is left up. The API key rides the environment, never argv.
Requiresbwrap(Linux); where it's absent the doer refuses rather than run grok
unconfined, andengine propose grok --agenticremains the gated fallback. - Supervision dial:
cohort autonomy(paired → autopilot). Choose how often Cohort
stops to ask, from confirm-every-step to run-up-to-the-PR. It tunes discretionary
friction over cheaply-reversible actions only, on a fixed safety floor no level can
lower: the human PR-merge gate, the code egress/secret/footprint gates, verification of
every foreign diff, and the operational hard-limits — and confirm-for-irreversible stays
stop-and-ask at every level. "Full autopilot, no checks" is deliberately not offered
(merge is human by construction; the honest ceiling is autopilot up-to-PR). The level
is machine-local (stored understate/, never synced) and fail-closed, so a pulled
config can never raise a machine's autonomy. A newautonomy-levelsmemory + a
session-start hook make the current level ambient to the coordinator. /audit— recurring, rotating whole-application adversarial audit. The recurring
sibling of/scout: rather than reviewing a target you name, it audits the app you
didn't, on a staleness rotation with a coverage ledger (docs/audit/ledger.md) so no
dimension goes more than ~4 runs unlooked-at — and it sweeps the project's declared
critical path (whatever can move money, write prod data, grant access, deploy, or
act irreversibly) every run. Fourteen distinct dimensions, each with a diagnostic
"tell" (critical-path, security, correctness, concurrency, resilience, dead-ends,
honesty, performance, naming, docs, tests, supply-chain, accessibility, ops),
cross-vendor fan-out, round-two refutation, and a close-the-loop step (file tickets,
update the ledger, record per-dimension false-positive rate). Read-only and advisory,
coordinator-verified — same posture as/scout. Generalized from a project-specific
audit command so it fits any application, not one domain.- GitHub Copilot CLI renderer (
--ide copilot, experimental). A fourth renderer
alongside Claude/Codex/Cursor, doc-verified 2026-07-24 against the official Copilot
CLI docs (docs.github.com/en/copilot). Agents compile to
~/.copilot/agents/<name>.mdwith a realtools:alias allow-list
(read/search/web/edit/execute); advisory is enforced mechanically by
restricting that list to the read-only aliases, the same invariant Claude/Codex/Cursor
apply via their own mechanisms. Skills compile to~/.copilot/skills/<name>/SKILL.md.
Hooks compile to their own dedicated~/.copilot/hooks/cohort-hooks.json— Copilot
loads every*.jsonunderhooks/independently, so no merge op is needed there,
unlike Codex/Cursor. Memory merges an@importinto
~/.copilot/copilot-instructions.md, mirroring Claude'sCLAUDE.mdshape.command
is a declared parity gap (Copilot CLI has no user-definable slash-command mechanism).
Same experimental, doc-cited-but-not-live-verified caveat Codex/Cursor already carry. /auditgains a business track (go-to-market, business-ops, privacy). The audit now
reviews the business that ships the app, not only the code, as a second track with
its own evidence standard — a named artifact or a searched-and-documented absence
rather thanfile:line— budgeted separately so a business dimension never displaces a
code one. Adds a privacy code dimension (are the rights the law grants actually
executable in code — deletion, export, opt-out — with the deletion-vs-retention trap
named), go-to-market and business-ops business dimensions, a business-context
declaration in the ledger (stage, jurisdictions, entity/filings, data categories,
regulatory posture), top-tier + web-search + two-vendor routing for the business track,
and a hard "no legal/compliance conclusions" guardrail — reviewers frame questions
and tag anything needing counselREQUIRES PROFESSIONAL OPINION, and never touch personal
data to test a privacy claim. Go-to-market joins critical-path as always-on.
Changed
- Session capture is on by default now (opt-out, was opt-in).
auto_capture
flips fromfalsetotruein the scaffold and in the read default, so a session
end writes its minimal record (branch, change summary, timestamp) to
.cohort/sessions/unless a repo setsauto_capture = false. This is what feeds the
newsession-recallbridge — exit context is no longer lost silently. - Orchestration cap raised to 20, with an optional federated three-tier mode. The
global in-flight cap moves from 10 to 20, and/crewgains a Director→Manager→Agent
mode for large work: the Director delegates task-groups to ephemeral manager
sub-coordinators (≤5 agents per manager, ≤20 global), each verifying its own group while
the Director re-verifies group contracts and every foreign-engine diff. It stays
coordination discipline — no declared graph, no persisted status, no durable-session
scheduler (that's the design a prior panel rejected). Requires the platform to permit
nested agents (CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=2, or Agent Teams for the top
tier); flat single-coordinator is the fallback. Both cap numbers are single-sourced in
docs/model-tiers.mdand lint-checked for drift. Newdocs/orchestration-patterns.md
documents when federation pays off (and when it's over-engineering);ship.md's stale
"subagents cannot spawn subagents" is corrected to "not by default." - Supply-chain hardened. Floating dependency ranges are bounded (
PyYAML<7,
pytest<10,jsonschema<5) so a build can't silently pull a new major; a new
requirements.lockpins the exact runtime dependency closure for reproducible installs
(pyproject.tomlkeeps the human-authored ranges);jsonschemamoved to dev-only (it
was an unused runtime dependency); and CI installsbubblewrapso the grok
confinement test runs instead of silently skip-gating.
Fixed
- Concurrent-writer races on all JSON state, closed with a portable file lock. A new
stdlibfilelock.py(anO_CREAT|O_EXCLlock-file — the one primitive identical on
POSIX and Windows — plus a stale-steal and an acquire timeout) serializes every
read-modify-write on the project registry, the install manifest, and the sync
quarantine. Two concurrentcohortprocesses could previously lose a manifest op record
(a placed file with no reversal entry, breaking uninstall) or drop a quarantine record
(a gate bypass). The manifest guard covers every RMW call site, with the fresh-init
bootstrap and the full-uninstallstate/teardown correctly left unlocked. - Sync quarantine no longer trusts a just-pulled artifact.
cohort updateseeds the
trusted-office baseline from the pre-pull tree, so an artifact a pull introduces is
measured as a delta and withheld for review instead of folded into "trusted" on the
first update. - Python 3.10 floor restored. The
tomllibimport (3.11+) is guarded with a minimal
fallback parser, socohortno longer crashes at import on the declared 3.10 floor; CI
now tests 3.10 alongside 3.12. - Assorted audit LOW fixes: the egress opt-out fails closed on any indentation and a
.gitpath can't be smuggled past the gate via a Windows trailing-dot segment;
dangling-symlink uninstall only removes a link still pointing at our recorded target;
SCAFFOLDops default to preserved on pre-migration manifests;--forcehook restore
replaces a diverged entry instead of duplicating it (it would otherwise fire twice).
Security
- **External-engine egress ...
v0.9.0 — Project memory visibility
Added
cohort lintsingle-sources the orchestration in-flight cap. The "≤10 agents
in flight" cap is restated across five canonical files; the lint now declares the
number once indocs/model-tiers.mdand fails if any canon file drifts to a
different one — anti-drift only, not runtime enforcement. A DESIGN[S]note records
that the orchestration invariants (the cap, footprint-disjointness, signoff) are
coordinator discipline plus the human PR gate by design: a declared orchestration
graph and aPreToolUsehook counter were both evaluated and rejected (static checks
are vacuous/impossible/duplicate; a hook counter is install-global and deadlocks on a
crashed subagent).- Dashboard surfaces each project's agent-memory store. Project cards now show a
🧠 N memorieschip for the Claude Code per-project memory store
(~/.claude/projects/<slug>/memory/) — where a project's session memory actually
accumulates at compaction — with the newest-write time in the tooltip. This is a
different tier from Cohort's own.cohort/canonical/memories/, and was previously
invisible, so an active project looked memory-less. Read-only and content-free (count
and freshness only, never file contents — the same posture as the project-memory
git-state chip).
v0.8.0 — External engines & guardrails
Added
-
Grok as an agentic doer:
cohort engine propose --agentic. The external engine
now EXPLORES the repository read-only (list_dir/read_file/grep/find_files, each
read egress-gated, the whole exploration recorded to an inspectable transcript) to
gather its own multi-file context, then proposes a patch — instead of working from a
Claude-packaged bundle. The trust boundary is unchanged: the proposed patch is parsed,
re-gated (footprint + sensitive class + secret backstop), and applied only inside an
isolated worktree by the same path the one-shot proposer uses. Grok writes real code
that lands, coordinator-verified and PR-reviewed; it is never handed a write tool. -
/crewis the single orchestration command (renamed from/orchestrate), carrying
the full protocol plus the cross-vendor doer rule: Claude subagents write directly,
external engines only ever propose gated patches. -
External engines (RFC 0004): Grok, API-direct.
/consult-grokbrings xAI's
Grok into the office as an advisory second opinion (a sibling of/consult-gpt), and
cohort engine proposelets Grok act as apatch_proposalengine — Cohort, never the
engine, parses its reply and applies it inside a throwaway git worktree behind
code-enforced gates (egress opt-out block, fail-closed secret scan, footprint +
sensitive-path denylist) and the unchanged human PR gate. Reached over the xAI HTTP API
(stdliburllib,GROK_API_KEYfrom the environment); the community grok-cli was
rejected on security/privacy/procurement review (a 400-round agentic editor with no
read-only mode conflicts with the untrusted-input invariant). Stdlib-only, no new deps. -
Orchestration gains a worker kickback (escalation from below). A non-Fable
worker that judges a task genuinely beyond its tier returns it — with a specific
reason — instead of shipping a plausible-but-uncertain attempt; the coordinator
escalates a tier immediately (skipping the same-tier retry), or raises a
Fable-suited one to the user. Complements the coordinator's top-down routing and
signoff so a tier mismatch is caught before the attempt, not only after. Lives in
fable-mode's scope gate, with an abuse guard (name the mismatch, never "too hard"). -
Dashboard: project memories show their git state. A
tracked/untracked/
uncommitted/no gitchip on project-memory cards, so "this instruction ships to
everyone who clones" vs "local-only, no audit trail" reads at a glance. Batched git
lookup (constant calls, not per-file) since the endpoint is polled. Informs, never
gates (#182). -
Project-scoped memories are authorable:
cohort add-memory --to project.
Writes ascope: projectmemory into<repo>/.cohort/canonical/memories/; the project
tier compiles it and wires@import cohort/CLAUDE.cohort.mdinto the repo'sCLAUDE.md
(and unwires it when the last one goes) — the compile half already existed, only the
authoring path was missing. A project memory loads in every session in the repo and
travels with it, so Cohort surfaces the newgit_statesignal (tracked / untracked /
uncommitted) at authoring time — tracked means changes are reviewable, untracked means no
audit trail. It reports and never blocks: the choice is the user's (#182). -
docs/model-tiers.md— the single tier→model mapping, lint-guarded. One
documented home for both the agentmodel:tiers and/orchestrate's routing
tiers;cohort lintfails if it drifts from the renderer's_MODEL_MAPor lists
an orchestration tier the canon no longer uses, so a model-generation sweep is
enumerable and can't miss a file. -
cohort lint— documentation-parity check. Guards the drift the golden
locks don't: counts stated in human docs (an "N-agent roster" line) must match
the real number of canonical artifacts, derived from the filesystem. Runs in CI. -
operational-hard-limitsmemory — blast-radius rules in every session.
Non-negotiable limits (no destructive data ops, prod read-only, PR-only changes,
no force-push, secrets never move) compiled into the memory corpus. Complements
theadvisoryinvariant (which governs tools) by governing actions; a coordinator
restates them per fanned-out worker.
Fixed
- RFC 0004 gate hardening (pre-merge review). Five defects found reviewing the
Grok engine before merge, each with a regression test that fails without the fix:
cohort engine consultran no gates at all — the per-repo egress opt-out and the
secret scan existed only as prose in the compiled command, so an opted-out repo still
egressed; a proposed path could traverse a symlink to redirect an in-footprint
write to a sensitive location inside the worktree while the manifest reported the
lexical path, showing the reviewer a file that was not the one on disk; a footprint
entry sensitive in one class laundered paths sensitive in another (authors/**
granted.gitwrites, via prefix matching that also mis-classified innocuous names);
a Windows drive-qualified path (C:\…) passed the scope gate on every platform; the
proposal worktree leaked on any unanticipated exception or Ctrl-C, and is now
created only once the reply is parsed and gated; andapply_patchwrote CRLF on
Windows, violating the repo'seol=lfbyte-stability invariant. Also: engine replies
are now escaped before reaching the terminal on the consult path, and non-PatchError
stdlib exceptions (UnicodeDecodeError,OSError) fold intoPatchApplyError. - Dashboard: a project-scoped artifact in a focused project now loads. The
detail pane rendered an agent's card from the focused project's inventory but then
reportedno agent '<name>' in project, because/api/artifactdropped the
projectparam and resolved against the dashboard's launch directory instead of
the switched-to repo. It now carries the focused project through, resolved via the
registry index like/api/stateandrun_actionalready did (never a client path).