Changelog¶
Changelog¶
All notable changes to greatminds are documented here. Format follows Keep a Changelog loosely; versions follow SemVer once 1.0.0 ships.
2.7.8 — 2026-06-29¶
Fixed¶
feature_review -> verifiednow queues a coordd-owned system production deploy when a stand profile declaresdefault_for: production_deploy. The deploy runs from the merged default branch, records a normal stand lease, and auto-releases on success.- Stand profiles can now declare
restore_profile. Releasing, reclaiming, or failing a displacing live profile such asvite-devqueues a front-of-line system restore lease, so public upstreams are rebuilt/restored before normal queued validation leases continue.
2.7.7 — 2026-06-29¶
Fixed¶
feature_live -> feature_reviewnow uses the latestimplementationblock and itsready_for_testflag for readiness, soLIVE-DEVELOPERcan complete the scenario-C handoff after USER-approved live validation.
2.7.6 — 2026-06-29¶
Fixed¶
LIVE-DEVELOPERcan now author the requiredimplementationblock for scenario-C interactive tasks infeature_live, includingscope: uiandscope: backend. The ordinary scope-to-role guard still applies outside the interactive live path.
2.7.5 — 2026-06-29¶
Fixed¶
- Vite teardown now targets remote stand hosts declared as
STAND_HOST_*(STAND_HOST_A,STAND_HOST_B, etc.) in addition toSTAND_HOST. This closes the remaining lease-release orphan case where cleanup fell back to localhost while the dev server was still bound on the remote node. - Generic Vite cleanup now verifies the declared port is free after killing
pidfile,
pgrep, andfusermatches, retrying force-kill before returning.
2.7.4 — 2026-06-29¶
Fixed¶
- Claude
autoMode.allownow includes the FSM commands a driven ARCHITECT-REVIEWER must run:greatminds task mv,greatminds worktree, andgit revert. Setup propagates these entries into.claude/settings.local.json, so a REVIEWER can complete the verified merge path without a manual classifier override. - Added
greatminds worktree refresh <task-id>and made stand deploy refresh a real lease worktree from the currentworktrees.default_branchbefore stale-dependency checks and profile loading. In-flight tasks cut before an infra/profile fix landed can now pick up that committed fix without copying files into the worktree or using rawgit rebase. - Non-
vite-devdeploys now clear the declared Vite dev-server port before dispatching their profile whenPROJECT.envdeclaresVITE_DEV_PORTorvite_port. This closes the remainingvite-dev->full-deployport collision where a survived Vite process could block the next packaged UI bind after the new lease was already active.
2.7.3 — 2026-06-27¶
Fixed¶
- Stand-free level redrive now runs immediately during coordd startup and then every 60 seconds by default. A daemon that starts after the stand is already free no longer waits five minutes before re-driving parked stand consumers.
coorddnow runs free-stand Vite orphan cleanup on startup and on the stand-free periodic hook. If the stand isfree, no active lease exists, andPROJECT.envdeclaresVITE_DEV_PORTorvite_port, Greatminds clears that declared port even when no current lease lifecycle event occurs.
2.7.2 — 2026-06-27¶
Fixed¶
- Stand-free recovery now has a level-triggered backstop. If the singleton is
already
free, has no active lease, and stand-consumer queues such asfeature_test,feature_live, orreview_sessionsstill contain work,coorddperiodically re-drives only those consumer roles instead of waiting for a freshdown -> freeor release event. - Vite teardown now has a narrow generic cleanup path in addition to
profile-tagged
teardowntasks. Forvite-devleases, or fleets that setVITE_DEV_PORT, Greatminds clears the pidfile and kills the process holding that TCP port on the configured stand host. This covers orphaned Vite processes left by pre-upgrade or killed leases whose profile had no teardown tags. - Deploy-failure auto-promotion is poison-aware. A queued lease matching the
just-failed
task/profile/worktreeis not immediately promoted again; unrelated queued leases can still advance, avoiding the obvious singleton stand loop where one bad lease keeps being re-deployed.
Note¶
- Greatminds still cannot deploy uncommitted profile edits from another project. A lease worktree is cut from committed content; local uncommitted fixes must be committed by that project before any Greatminds version can deploy them.
2.7.1 — 2026-06-26¶
Fixed¶
coorddnow runs the stand-free backlog reconcile directly after its own background auto-deploy thread returns the singleton tofree. This closes the gap where a failed deploy changed state inside coordd but no reliable watcher event re-drove tasks already parked infeature_testor review queues.stand up,stand release,stand reclaim, and deploy-failure paths now emit a small.stand/available-*.yamlevent when the singleton becomesfreewithout promoting a queued lease, giving the daemon an explicit dispatch event for waiting stand consumers.- The shipped
vite-dev.yamlprofile now has realteardowntasks. Teardown stops the saved Vite pid when available and also clears old orphan processes holding the configured port, including pristine 2.7.0 profiles reseeded bygreatminds migrate/greatminds update. vite-dev.yamlnow acceptsVITE_DEV_PORTfromPROJECT.envin addition to the lower-casevite_portextra-var, so cleanup targets the same port as the deployed dev server in common fleet configs.
Note¶
- This release corrects the incomplete 2.7.0 implementation of #24, #27, and #28. Version 2.7.0 added supporting infrastructure but did not fully close the real daemon/profile failure modes.
2.7.0 — 2026-06-26¶
Changed¶
- Stand deploy failures are now lease-scoped instead of globally downing the
singleton stand. A non-zero profile run fails the active lease, records
last_deploy_failure, runs teardown best-effort, returns the stand tofree, and promotes queued work when present. This prevents one profile or task failure from blocking unrelated stand work. - Driven Claude and generic headless turns now use progress-based timeout handling. Output activity and worktree writes refresh the role heartbeat and keep the turn alive; coordd kills only after the idle progress window or the larger absolute ceiling is exceeded.
Fixed¶
coorddtreats a.standtransition tofreeas a dispatch event and re-scans driven backlog immediately, so tasks parked infeature_testor review queues resume after stand recovery without a manual wake.- Stand profile teardown is now supported through Ansible tasks tagged
teardownand is invoked best-effort on release, reclaim, down/up recovery, and deploy failure. This gives profiles a first-class cleanup path for dev-server ports and other long-lived processes. - Deploy failure diagnostics now persist the full Ansible output under
.greatminds/.stand/deploy-<lease-id>.logand surface that path fromgreatminds stand status, avoiding mid-command truncation of the real stderr/stdout cause. - Active lease deploys continue to resolve stand profiles from the lease worktree first, preserving validation of in-flight profile fixes before merge.
Issues¶
- Fixes #23, #24, #25, #26, #27, #28, and #29.
2.6.0 — 2026-06-18¶
Fixed¶
- Gemini driven turns now include
--skip-trust, and Gemini live-pane launches use--prompt-interactiveinstead of the headless-pprompt mode. - Cursor driven turns now include
--trustwith--printmode so headless workspace trust prompts do not wedge unattended dispatch. - Generic driven outcome classification now treats known auth/setup messages in stdout or stderr as failed turns even when a tool exits with code 0. This prevents OpenHands headless setup failures from being recorded as successful driven turns.
Verified¶
- Local real-agent CLI turns completed for Claude Code, OpenAI Codex, Cursor agent, and Cline CLI.
- Gemini CLI reached provider authentication and failed with the account's
UNSUPPORTED_LOCATIONeligibility response after workspace trust was bypassed. - OpenHands CLI was installed and reached headless startup, then correctly reported missing LLM settings for the machine.
2.5.0 — 2026-06-18¶
Added¶
- Added a Node.js VS Code extension test harness that mocks the VS Code API, verifies CLI invocation, validates the Agent Tools tree provider, and checks cockpit terminal commands.
- CI now runs the VS Code extension tests with Node 20 alongside the Python regression suite.
Fixed¶
- Cursor driven turns now use the same constrained systemd user scope as
interactive Cursor panes. Both paths run through
cursor.sliceby default and honorGREATMINDS_CURSOR_MEM_HIGH,GREATMINDS_CURSOR_MEM_MAX,GREATMINDS_CURSOR_CPU, andGREATMINDS_CURSOR_SLICE.
2.4.0 — 2026-06-18¶
Added¶
- Added a machine-readable agent tool capability registry exposed through
greatminds agent toolsandgreatminds agent tools --json. - Added adapters for Cursor, Cline, Gemini CLI, and OpenHands CLI alongside Claude Code and OpenAI Codex. Claude and Codex keep their stateful driven drivers; Cursor, Cline, Gemini, and OpenHands use one-shot headless subprocess driven turns.
- Added VS Code cockpit tasks to
greatminds launch --target vscode: dashboard, driven log, coordd foreground, agent status, agent tools, stand status, and stand profile list. - Added a bundled
vscode-extension/cockpit scaffold that calls thegreatmindsCLI as its backend.
Fixed¶
launch --target vscodeno longer emits invalidstart-agent --mode driventasks for driven roles.launch --project-dirlocatescoordination/coord.yamlin the requested project even when invoked from another working directory.
2.1.0 — 2026-06-15¶
Added¶
- Added
greatminds driven-log, a read-only chronological event stream for driven-agent turns. Fresh tmux fleets now include a role-lesslogspane runninggreatminds driven-log --follow;coorddrecords accepted turns, pending markers, completions, retries, and errors tocoordination/.events/driven.ndjson.
Fixed¶
- Driven backlog detection now ignores
wake-*inbox markers. These daemon wake notices are not role work and no longer cause duplicate pending turns after a task has already moved to the next FSM queue. feature_blockedis treated as a parking queue for driven dispatch: reviewer turns are driven only for withdrawn tasks or blocked tasks whose declared dependencies already exist. Missing-dependency blocked tasks stay quiet instead of repeatedly spending reviewer turns.- Per-task lock files are removed after release instead of being left as empty
.locks/<task>.lockfiles. A future task operation still recreates the lock on demand.
2.0.14 — 2026-06-15¶
Fixed¶
- Restored the
greatminds setuprole-gating pre-commit hook for coordinated projects. The hook should be absent only from this repository's local solo-development checkout, not from projects bootstrapped by the product. greatminds daemon doctornow explains expired Claude OAuth credentials with no refresh token and points operators toclaude setup-tokenorclaude auth loginbefore restarting the daemon.- Captured daemon agent env now follows Claude Code host-auth pointer variables so a daemon started from a usable shell can preserve the referenced auth value instead of saving only the pointer name.
- Driven Claude turns and
greatminds daemon doctornow invokeclaude -pwith explicit non-interactive process requirements:HOMEset to the daemon OS user's home,$HOME/.local/binonPATH, and an absolute Claude binary path when resolvable.
2.0.11 — 2026-06-14¶
Fixed¶
- Added
greatminds daemon doctorto run a daemon-equivalent headless Claude probe for driven-Claude fleets. The command now surfaces missing captured agent env files and Claude 401/auth failures directly instead of leaving the operator to infer them from stuck turns or.turnslogs. daemon install,start, andrestartnow warn when a driven-Claude fleet has no captured Claude/provider auth env available for the daemon runtime.
2.0.3 — 2026-06-13¶
Fixed¶
- Review-session stand leases now refuse stale worktrees that predate any
currently verified product review commit, not only commits listed in explicit
blocked dependencies. This prevents final EXPLORER/full-deploy validation from
reporting
readyfor an integrated tree that is missing later verified product work.
2.0.2 — 2026-06-13¶
Fixed¶
- Shipped
full-deploy,smoke-only, andvite-devstand profiles now treatSTAND_HOST=localhost,127.0.0.1, and::1as local ansible targets.full-deployandvite-devalso use a local rsync destination for those loopback stands instead of forcinglocalhost:/pathover SSH. This fixes fresh user toy stands failing withHost key verification failedbefore any product validation can run.
2.0.1 — 2026-06-13¶
Fixed¶
setupandstand deploynow resolveansible-playbookbeside the active venv Python before falling back toPATH. This fixes uv-created venvs wheregreatmindsis invoked by absolute path andvenv/binis not inPATH, even thoughansible-coreis correctly installed as a hard dependency.
Verified¶
- Fresh patched wheel install plus local-control avatar campaign: task
lifecycle to
verified, lease-backed ansible deploy tossh avatar, remote payload probe, and stand release back tofree.
2.0.0 — 2026-06-13¶
Changed¶
- Clean v2 FSM/autonomy baseline. Driven roles now expose retry/backoff state on disk, restore retry state after coordd restart, fail fast on missing Codex auth, surface low-disk blockers, and keep stuck-turn evidence visible to watchdog/dashboard.
- Stand architecture is stricter.
stand leaseand the deploy executor now reject plain/no-git directories under.worktrees/; leases must deploy from real source checkouts, not deployed payloads or stale debris. - Operator visibility improved.
greatminds dashboard --logsshows the latest driven-agent turn log tails in the same read-only status view. - Evidence/docs contract realigned. Packaged role prompts, templates,
README, stand docs, schema comments, and setup warnings now describe the
current lease-backed YAML/ansible stand model instead of the retired
stand_done/STAND-KEEPERworkflow.
Verified¶
- Full local CLI suite:
1518 passed, 1 skipped. - Avatar validation matrix on a fresh toy git project: setup, normal FSM intake/plan/test path, auto-created lease worktree, gate-check pass from lease-backed evidence, dashboard log tails, and no-git worktree rejection.
1.6.11 — 2026-06-09¶
Fixed (driven-FSM autonomy batch — operational merge, USER-authorized path 2; self-referential infra, avatar-validated)¶
- #14/#21 — driven Codex roles must use one machine Codex login (0375): coordd runs driven Codex roles against the single machine
$HOME/.codex(no per-rolecoordination/.codex-home/<role>auth copies/symlinks); role model/config injected via-c/app-server params; adds_machine_codex_home()resolution +_CodexAuthErrorfail-fast. Avatar-validated: a driven REVIEWER turn reportscodex_home=$HOME/.codexwith non-zero real FSM work and no auth errors, and a real task completed the full autonomous lifecycle (feature_docs → feature_docs_review → feature_review → verified) via coordd-dispatched driven Codex roles with no manual pokes. - #22 — coordd does not reliably auto-dispatch driven roles from queue/backlog (0374):
_reconcile_driven_backlog+ stale-driven-lock reconcile harden driven-role dispatch so queued work wakes the driven role without manual nudges (fixes the transient orphan-lock that left queued tasks unstarted). - host ENOSPC corrupts Codex token refresh + driven turns (0376): coordd disk preflight blocks driven spawn below a free-space threshold, adds ENOSPC-aware failure enrichment, and caps
.turnsretention — a full disk no longer silently empties driven turns or breaks Codex token persistence.
Integrated release enabling end-to-end autonomous FSM operation. Supersedes the per-worktree proofs: each fix was release-gated because the running fleet could not review/validate the very fix that repairs its driven-Codex review path.
1.6.10 — 2026-06-06¶
Fixed (stand-infra release chain — code-level verified; live-validated post-upgrade)¶
- #9 — coordd stand deploy lacks lease_meta.host resolution (0363): stand.py / stand_profile.py resolve host topology correctly for the host-agnostic deploy.
- #16 — stand deploy marks ready after empty-inventory / no-hosts no-op (0366): stand_executor now FAILS a vacuous run (0 hosts matched / 0 tasks) instead of returning rc=0 -> ready, so a no-op deploy can never falsely mark a stand ready.
- #17 — reused fleets keep stale seeded stand profiles because setup does not overwrite (0367): setup/migrate re-seed stale full-deploy/smoke-only profiles to the add_host topology so existing fleets get the non-vacuous deploy path.
These three unblock real (non-vacuous) stand deploys; the remaining release-gated batch (#11/#12/#13/#14/#18 etc.) is live-validated against this release post-upgrade.
1.6.9 — 2026-06-05¶
Fixed¶
- Driven run-lock leaked on the claude
-ppath (issue #11). In the claude driven worker'sfinally,_record_driven_turn(registry write) ran BEFORElock.unlink(); a throw there skipped the unlink, orphaningcoordination/.locks/driven-<role>.lock. coordd's reconcile then treated the role as still-running and never re-drove it (the pipeline froze), while the hang detector false-flagged the completed turn as hung — costing real API spend per stuck turn and forcing a manualrm. The lock is now released FIRST and unconditionally in the finally (matching the already- correct codex worker). Regression test added.
1.6.8 — 2026-06-05¶
Fixed¶
- Dashboard agent table alignment. The STATE column rendered the state string padded to 7 while the header reserved 12, so longer states collided with the HB column ("running" → "runningfresh" / "running8m"). State is now padded to fill the 12-wide column; HB stays aligned.
- Dashboard HB column for a running driven turn. A driven turn does not refresh a heartbeat, so the HB column showed a misleading STALE age while a turn ran ("running · 8m" read as a hang). While a turn is in flight the column now shows the turn's DURATION from the run-lock age, prefixed ⟳ (e.g. ⟳4m) — the real activity signal, which also surfaces a hung turn.
1.6.7 — 2026-06-05¶
Host-agnostic stand deploys + autonomous backlog recovery.
Changed¶
- greatminds no longer owns host topology.
execute_yaml_profilehands the WHOLEcoordination/PROJECT.env(plus lease meta) to ansible as--extra-varsand runs the profile incwd=coord. Removed the single-host inventory synthesis (_build_inventory/_host_from_playbook), the${}playbook substitution, and thelease_meta.hostrequirement. The profile AUTHOR targets hosts by ansible-native means —add_hostfrom PROJECT.env vars (1 or N nodes), or a static inventory shipped alongside (auto-discovered via the fleet'sansible.cfg). Canon profile templates rewritten to theadd_hostreference pattern. Migration: a profile usinghosts: "${STAND_HOST}"must move to the add_host pattern (or a static inventory) —${}is no longer substituted. - PROJECT.env is injected as a real environment. A per-instance systemd
EnvironmentFile=drop-in gives the daemon — and every driven agent it spawns (they inherit its env) — every PROJECT.env var. Interactive agents source it at launch / restart. One source, visible to ansible + the daemon - all agents.
Fixed¶
- Autonomy: the daemon recovers stuck pipelines. The startup backlog
reconcile is now also periodic (
RECONCILE_INTERVAL_SEC, 90s): a driven role that parked with pending work in its claim queue is re-driven instead of frozen until a new event. Escalation now wakes an IDLE MAINTAINER via its input_sock (freshness-gated — a mid-turn MAINTAINER is never interrupted) so it acts on failures now, not on its next hourly self-loop.
1.6.6 — 2026-06-05¶
Fixed¶
- Canon stand-profile templates no longer self-reference / build an
empty-user rsync dest.
deploy_path: "{{ deploy_path | default(...) }}"recursed (a play var referencing itself), and the rsync delegate built{{ ansible_user | default('') }}@{{ inventory_hostname }}→ an empty user when the SSH alias supplies it →Permission denied. Templates now use literal var defaults (extra-vars still override) and rsync to the bare ssh-config alias ({{ inventory_hostname }}). - The dashboard collapses a multi-line ansible
down_reason(PLAY/TASK banners + newlines) to a single clean line so it doesn't shred the panel.
1.6.5 — 2026-06-05¶
Fix: the deploy forced privilege escalation, overriding the playbook.
Fixed¶
- The executor no longer forces
ansible_become=true. The synthesized inventory pinnedansible_become=trueby default, which OVERRODE a play'sbecome: falseand made tasks run as root — e.g. a deploy that creates its target dir without sudo and then rsyncs to it as the login user broke (the dir ended up root-owned). Privilege escalation is now the PLAYBOOK's decision (become:per play/task); a lease may still pinansible_become/ansible_userexplicitly.
1.6.4 — 2026-06-05¶
Fix: the YAML stand deploy never reached its target host.
Fixed¶
- The deploy resolves its host from PROJECT.env via the profile. The
YAML executor never read
PROJECT.envand never${KEY}-substituted the playbook (that machinery was dead code left from the removed prose profiles), so the host — which lives incoordination/PROJECT.env(e.g.STAND_HOST_GPU=mlgpu2) — could not reach ansible, andexecute_yaml_profileraised "lease_meta.host is required". Nowexecute_yaml_profilereads PROJECT.env, substitutes the playbook, and takes the host from the playbook's ownhosts:. - Consistent host scheme. PROJECT.env is the single per-fleet source
of host/user values (read by the deploy AND by EXPLORER/TESTER for their
SSH probes). A profile is self-documenting but does not duplicate the
value —
hosts: "${STAND_HOST_*}". The inventory is a bare SSH alias (no forcedansible_user, so the alias's~/.ssh/configUser applies); a profile overrides the user with a play-levelremote_user: "${STAND_USER_*}". Validated live against an ssh-config alias. The stray--hostlease option was reverted.
1.6.3 — 2026-06-05¶
Fix the stand-deploy freeze, the daemon's polluted PATH, and document the inbox-read protocol structurally.
Fixed¶
- coordd retries a stand deploy stuck in
preparing. A deploy that RAISED before transitioning (vs an ansible rc!=0, which already goesdown) left the stand inpreparingforever — no event fired, the pipeline froze. coordd now re-attempts it periodically and, afterDEPLOY_MAX_ATTEMPTS, escalates to MAINTAINER and forces the standdownso it is not stuck. - The daemon unit bakes a CLEAN minimal PATH. 1.6.2 baked the
operator's RAW shell PATH, which dragged in cuda / flutter / plugin bins
/ another project's
.venv-coord(so the daemon resolvedansible- playbookfrom the wrong, cross-project venv).daemon installnow resolves exactly the project's own venv bin (its ansible + greatminds), the agent tool dirs (node / claude / codex), and the standard system dirs. - The role-inbox read protocol is documented structurally. Agents
knew to "check inbox" (wake text) but not HOW —
schema.inboxonly hadallowed_kinds, so an agent guessedgreatminds task list inbox(no such queue → empty) and never saw its messages.schema.inboxnow carriesread/show/ack/dir/check_when(machine-readable, not prose in bootstrap).
1.6.2 — 2026-06-05¶
Make the driven deploy/dispatch model survive failures, and let the leaser pick the real stand profile.
Fixed¶
- The lease names ANY real profile (no hardcoded enum).
stand lease --profile Xis validated by resolving an actual playbook file in the project'sstand-profiles/(e.g.mlgpu2/orange, alongside the seeded presets), not against a fixedprofiles_allowedlist. The enum silently collapsed every lease onto the seededfull-deploypreset and hid each fleet's real profiles — so coordd deployed the wrong playbook. - Driven turns retry on failure (rate-limit / error / timeout). A
driven turn that failed moved no task, so no event fired and the role
froze forever. coordd now classifies each finished turn (claude
--output-format jsonis_error/api_error_status; codex stream) and re-dispatches failures with backoff: rate-limit (429/529) ~forever, other errorsRETRY_HARD_MAXtimes then escalated to MAINTAINER (auto-retry stops until a real event). Clean completions are NOT retried. A turn also has a wall-clock timeout. - The daemon runs with the operator's PATH.
daemon installbakesEnvironment=PATHinto the unit so the systemd-user daemon's spawned driven turns findcodex/claude/node(nvm /~/.local/bin). Removed the in-code tool-resolver fallback tower; barecodex/clauderesolve via PATH. - Driven codex runs in the role's per-role
CODEX_HOME(was the default~/.codex, missing the role config), with a resume→fresh-thread fallback when a cached threadId can't be resumed.
Dashboard¶
- An idle role no longer carries its queue's task in DOING (read as "still on X" after a turn ended); the STATE column is a few chars wider.
1.5.16 — 2026-06-04¶
Fix: the dashboard showed a running driven turn as idle.
Dashboard¶
- A held driven run-lock now reads as
running. The run-lock is coordd's authoritative "turn in flight" marker, and coordd clears stale locks on startup (1.5.15), so while coordd is alive a present lock means a real running turn. The previous gate also required a live pid / fresh heartbeat — which a driven claude turn never has — so an actively- running TESTER / STAND-KEEPER turn was shown asidle. Dropped that gate; driven STATE is nowrunning(lock held) /idle(between turns), never falsely idle-while-working.
1.5.15 — 2026-06-04¶
Fix: a stale driven run-lock permanently stranded a role.
Fixed¶
- coordd clears stale driven run-locks on startup. A driven turn
runs as a coordd-managed subprocess, so NO run-lock survives a coordd
restart — yet a lock left behind by a coordd killed mid-turn (e.g. a
daemon restart, common during
update) was treated by BOTH the dispatcher and the startup reconcile as a turn still in flight, so that role was NEVER driven again (its task sat forever; the stand was never leased). coordd now deletes every.locks/driven-*.lock/.pendingon startup (none can be valid in a fresh process) before reconciling the backlog, so the role is re-driven on the next start.
1.5.14 — 2026-06-04¶
Fix: driven claude roles never ran under the daemon; the dashboard contradicted itself on driven roles; a daemon restart stranded a queued task.
Fixed¶
- Driven turns spawn the tool by its REAL absolute path. coordd runs
as a systemd-user daemon with a minimal PATH (no
~/.local/bin), so a bareclaude/codexargv[0] failed to spawn — the claude-driven roles (TESTER / DEVELOPER / UI-DEVELOPER / READER) silently never ran (only codex roles survived, via their own app-server unit). New_resolve_tool_binresolves the real path (PATH → the user's LOGIN shellcommand -v→ bare), so it works even for a non-standard install location; driven argv[0] and the subprocess PATH use it. - coordd reconciles its backlog on startup. coordd was purely
inotify-reactive, so a task already sitting in a queue when it
(re)started — or whose event was consumed by a turn that failed to
spawn — was never driven. On start it now drives one turn for each
driven role that has pending work in a queue it claims from and isn't
mid-turn. A daemon restart (e.g. after
update) now picks up a hanging task instead of stranding it.
Dashboard¶
- Driven roles are no longer shown as
dead+running turnat once. STATE was derived from a persistent registry pid, which driven roles don't have — so a role running a turn read as "dead". STATE is now coherent with the driven model:runningduring a live turn (lock - live pid/heartbeat),
idlebetween turns (normal — coordd drives on events), neverdead. A stale run-lock from a killed coordd no longer reads as "running" forever. - TASKS table aligns; the ID column shows just the task number. The
full slug (
0001-verify-full-deploy-…) overflowed the ID column and broke alignment; it now shows0001.
Internal¶
- Removed dead code (
role_has_pending_work, an unused*.md-only pending-work scan from the legacy-MD era; redundant localshutil/globimports).
1.5.13 — 2026-06-04¶
Fix: update could report success without actually upgrading (and needed
two runs to converge) when a foreign virtualenv was on PATH.
Fixed¶
updateresolves its own binary from the running venv, not PATH. The self-replace usedshutil.which("greatminds"), which is PATH-first — a foreign activated virtualenv (e.g. an unrelated.venv-coordleaking onto PATH, common when you have one project's venv active while runninguv runin another) could shadow the project's greatminds, so the self-replace exec'd the WRONG version and the upgrade appeared to "need two runs"._greatminds_binnow pins tosys.executable's sibling (the env update is installed in).updateverifies the upgrade actually landed. It printed a hardcoded✓ … (old → new)anddone: greatminds at <old>even when the venv hadn't changed (the in-process__version__is stale right after a same-run upgrade). It now reads the REAL installed version in a fresh subprocess, forces oneuv sync --reinstall-packagepass if uv lagged, and FAILS LOUDLY if the version didn't change — instead of a fake success that silently needs a second run. The final "done" line reports the freshly-read version.
1.5.12 — 2026-06-04¶
Fix: a plain restart silently destroyed driven-agent sessions.
Fixed¶
- Default
greatminds restartpreserves session continuity. For a dead agent it didreg_path.unlink()on<role>.json— but the driven-claude session UUID is stored IN that .json (coordd writesreg["session_id"]), and a driven role's pid is dead between turns, so every default restart wiped its session and force-freshed it on the next turn. Session DESTRUCTION must be reserved for the explicit--resetflag, never a side effect of a plain restart (or ofgreatminds update, which restarts on every run since 1.5.10). The dead-agent path now clears only the volatilepid/input_sockand PRESERVESsession_id(and the claude/codex session-id sidecar files, which it never touched);--resetremains the only path that drops a session.
1.5.11 — 2026-06-04¶
Added¶
greatminds task list <queue> --json.task listonly printed filenames; an agent inspecting a queue (a codex PLANNER hit this) has no raw access tocoordination/, so it guessed a--jsonflag and errored. Added it — emits a JSON array of{id, title, queue, file}per task (malformed files degrade to the filename stem, never crash the listing). Plain output is unchanged (filenames only). Mirrorsagent status --json.
1.5.10 — 2026-06-04¶
Fix: update skipped the migration when the package was already current.
Fixed¶
greatminds updatereconciles config even when the package is up to date. 1.5.9 added the project-config migration toupdate, but only in the post-pip phase reached after an actual version bump —updatedid an early "already up to date" exit before it. So a fleet already on the latest package but with stale config (old all-paned coord.yaml, missing queues, leftover artifacts) ranupdateand migrated nothing.updatenow falls through to the migration + daemon/agent restart phase in-process when no bump is needed (no self-replace), so it ALWAYS brings the project config to the installed version. (greatminds migrateremains available standalone.)
1.5.9 — 2026-06-04¶
Make the fleet's working branch cleanly project-configurable, and make
upgrade migrate the whole project (not just the package).
Fixed¶
worktrees.default_branchis now per-project configurable viacoord.yaml. 1.5.8 added the setting butload_worktree_policyread it only from the canon (package)schema.yaml— which shipsmain, is shared across every project on the host, and is overwritten on each upgrade. So a project could not actually pin its own branch. The policy now overlays aworktrees:override from the project'scoord.yaml(project-local, never overwritten) on top of the canon defaults. To run a fleet on another branch: putworktrees: { default_branch: <branch> }incoord.yaml.
Added¶
greatminds migrate+greatminds updatenow migrates the whole project. Previouslyupdatebumped the package but left the project's config stale (e.g. a pre-drivencoord.yamlwith every role paned → 10 tmux windows on launch; missingfeature_live; leftovercommand_START.yaml/ per-role docs /bot_*queues).updatenow runs a migration step (and it is also available standalone asgreatminds migrate, for fleets already on the new package but with stale config): refresh canon (setup: schema / COORDINATE / bootstrap / missing queues /.gitignore), migratecoord.yamlfrom the old all-paned model to the current driven model (workers →driven, adddashboard+live), preserving session /project_dir/ theworktreesoverride / custom role-less windows and backing up the old file, and remove artifacts deleted in newer versions (command_START.yaml, per-role<ROLE>.mddocs, emptybot_*queues).
1.5.8 — 2026-06-04¶
Feature: configurable worktree base/merge branch.
Added¶
worktrees.default_branch(defaultmain). The per-task worktree merge was hardcoded tomain—worktree_mergedidgit checkout main→git pull --ff-only origin main→ merge the task branch into main, and the base-commit last-resort fallback didgit rev-parse main. A project therefore could NOT run its coordination on any branch other than main: every completed task's merge forced the work back onto main. The branch is now read fromschema.worktrees.default_branchand used in both places; defaulting tomainkeeps existing fleets unchanged. coordd / setup / stand-deploy never referenced main and are untouched.
1.5.7 — 2026-06-04¶
Canon: insist on full-contract reading, add a no-code stand-verification FSM path, and a read-only PROJECT.md surface.
Added¶
plan.verify_only→feature_plan → feature_test. A no-code stand/playbook task (e.g. "deploy the full stand by profile X", "verify this playbook") had no clean FSM path —feature_testwas reachable only from an implementer queue with animplementationblock. PLANNER now routes averify_onlyplan straight to TESTER, who leases a stand, runs the profile/probe, and records stand evidence (mirrors the READERaudit_onlypath). "Deploy the stand" and "test the stand" are the SAME path differing only in verification depth (readiness-only vs functional probes) — documented in COORDINATE §8.2. There is deliberately NO task-less stand deploy: every lease serves an auditable task, which is what anchors the tested/verified gate.greatminds project show— read-only print ofcoordination/PROJECT.md. Closes a protocol gap: the contract requires agents to read PROJECT.md, but it lives undercoordination/and the mutations-via-CLI rule left no sanctioned CLI to obtain it.
Changed¶
- bootstrap.md now insists on reading the contract IN FULL. The old
wording ("YOUR contract is
roles.<ROLE>") let agents — codex especially — skim to their role section and stop, then propose moves the FSM forbids. It now requires reading the wholeschema.yamlevery tick (glossary, the full queue graph, and the exact transitions of the path the task is on); the role block is necessary but not sufficient. - The "CLI-only" rule is scoped to MUTATIONS. Reading the canon docs
(
schema.yaml,COORDINATE.md,bootstrap.md,coordination/PROJECT.md) directly is now explicitly allowed — they are docs, not FSM state. Only mutations + queue/inbox/task ops go through the CLI.
1.5.6 — 2026-06-04¶
Fix: MAINTAINER tick cadence + runtime files leaking into git.
Fixed¶
- MAINTAINER self-loop cadence is pinned to 1 hour in canon. The
1.5.0 refactor dropped the per-role docs (where the hourly recovery
cadence used to live) and never carried it into the schema, so a fresh
MAINTAINER fell back to the agent's own ~5-minute default loop — and
any operator "set it to an hour" was lost on the next session /
re-bootstrap. Added
schema.roles.MAINTAINER.self_loop_wake_seconds: 3600, and theself-looplifecycle +bootstrap.mdnow instruct the agent to re-arm for that configured cadence (shorter only while mid-recovery) rather than inventing a faster interval. setupgitignores per-role tool runtime. The seededcoordination/.gitignoreexcluded heartbeats / registry / locks but NOT.codex-home*/(codex sessions, logs, and an embedded plugin git repo),.turns/(driven-turn logs), or.stand/(live lease state + deploy logs) — so agit addofcoordination/swept codex runtime (and a nested git repo) into the project. Added those three to the generated.gitignore.
1.5.5 — 2026-06-04¶
Fix: greatminds setup never created the feature_live queue.
Fixed¶
setupnow creates thefeature_livequeue.feature_livewas added toschema.queueswith the LIVE-DEVELOPER role in 1.5.0, but the hardcodedsetup.QUEUESlist was never updated — so every freshgreatminds setupfrom 1.5.0 through 1.5.4 silently omitted the queue (surfaced when re-bootstrapping a real fleet). Addedfeature_liveto the list and pinned it against the schema with a new drift test (test_setup_queues_match_schema_task_queues):setup.QUEUESmust now exactly equal the task-holding queues declared in the schema, so this class of drift can't recur.
1.5.4 — 2026-06-04¶
Feature: a live fleet status dashboard + tmux status-line config on launch.
Added¶
greatminds dashboard— a read-only, non-scrolling console table of the fleet at a glance: per-agent activity (alive/idle/working/ running-turn, inferred from registry liveness + heartbeat freshness + driven run-lock + the task in the role's owned queue), active tasks by FSM state, and the singleton stand. Pure observer — holds no role, registers nothing, sends no wakes; safe to kill/restart. Refreshes in place (--interval, default 2s);--onceprints a single frame;--color/--no-color(auto-detects a TTY). Thedashboardcoord.yaml window (mode: dashboard) now auto-runs it ongreatminds launch.
Fixed¶
- tmux status line is configured on launch. A fresh host without the
operator's
~/.tmux.confgot tmux's defaultstatus-left-lengthof 10, which truncated a session name likegreatminds-devso the clipped[greatmindstitle collided with the window list (0:planner…).launchnow setsstatus-left-lengthto fit the full[<session>]title exactly (len(session)+4) and applies the fleet status colors (purple bg / white fg, current window bold+underscored) per-session, so every fleet looks right regardless of personal tmux config.
1.5.3 — 2026-06-04¶
Patch: waking an idle codex/cursor TUI quit the agent (Ctrl-C to the shell).
Fixed¶
- The event-wake SIGINT no longer kills interactive codex TUIs. The
wake primitive (
_send_enter.press_enter, and the parallelcoordd.sigint_sleeping_descendant) SIGINTs the deepest descendant of an agent to break a blockingbash sleepbackoff timer so a queued Enter gets read. The guard wasleaf != agent_pid— sufficient for claude (whose deepest descendant IS the agent process, so it was skipped), but WRONG for codex/cursor: those are multi-process (node → engine), so the deepest descendant is the LIVE ENGINE, not a sleep. SIGINT there is Ctrl-C → codex quits to the shell and the nextWAKE_TEXT("continue your tick") lands in bash (-bash: continue: ...). The leaf'scommwas computed from the first commit but only ever used in the diagnostic string — never gated on. Both paths now SIGINT only when the leaf is an actualsleepprocess; a live engine is woken by the send-keys Enter alone (idle TUIs read input directly, so no interrupt is needed). The bug bit IDLE agents (stale heartbeat); busy agents were masked by the fresh-heartbeat push guard.
1.5.2 — 2026-06-04¶
Patch: the documented task-withdraw path was broken — a withdrawn task could never be archived.
Fixed¶
feature_blocked → archive(withdraw) no longer collides with the resume wildcard.transitions_forresolvedany_resume_to_queueagainst any concreteto_q, including the terminalarchivequeue. Sofeature_blocked → archivematched BOTH the exact withdraw row (requires: feature_blocked_withdrawn_reason) AND the resume wildcard (requires: all_dependencies_exist_per_wake_check), andenforce_schema_requiresruns the requires from every matching row — so the resume path's wake-check fired on the withdraw path. A withdrawn task carries a never-resolving sentinel dependency by design, making the wake-check (and therefore archive) impossible. The two paths are mutually exclusive.any_resume_to_queuenow matches only non-terminal queues, so a parked task can be withdrawn-archived (the canonical PLANNER-blocks → REVIEWER-archives cleanup path) without its sentinel dependency having to resolve.
1.5.1 — 2026-06-03¶
Patch: two issues surfaced operating the 1.5.0 fleet live.
Fixed¶
greatminds agent statusaccepts multiple roles. It was single-role-only; a freshly-restarted PLANNER ranagent status STAND-KEEPER MAINTAINER TESTERand got an "unexpected extra arguments" error. The command now takes any number of role args (and still defaults to every registered role).- MAINTAINER may now
stand reclaim.schema.roles.MAINTAINERcarriesreclaim_stale_stand_lease_past_ttl_with_dead_holderas a recovery duty, but thestand reclaimCLI gate allowed only STAND-KEEPER / ARCHITECT-PLANNER — so MAINTAINER could not actually close stale-lease recovery asks. Added MAINTAINER to the gate (the safety guards are unchanged: only an expired lease with a dead/absent holder is freed).
1.5.0 — 2026-06-03¶
Major canon consolidation + a new interactive role. Live-verified on a real avatar fleet (driven turns bootstrap from the static prompt, claim, implement, advance the FSM).
Added¶
- LIVE-DEVELOPER — an interactive, USER-paced role for working a
single task live with the USER on a leased stand. PLANNER routes a
plan marked
interactive: trueto the newfeature_livequeue; LIVE-DEVELOPER leases a stand, deploys to its own lease during the session, works live, and on USER approval hands tofeature_reviewas a sprint task (approved_sprintreview outcome; TESTER skipped — the USER is the live validator). Newstagedlaunch mode (the pane's start command is pre-typed, the USER starts it). Replaces the old UI-DEVELOPER FAST chat variant; scenario C is now LIVE-DEVELOPER. Ships avite-devstand-profile example (backend + Vite HMR).
Changed¶
- Single static bootstrap. An agent's whole instruction surface is
now
COORDINATE.md(philosophy) +schema.yaml(machine contract + glossary) +coordination/PROJECT.md(project specifics) + its role from$GREATMINDS_ROLE. The system prompt is one role-independentcoordination/bootstrap.md; the per-role rendered prompt is gone. - schema.yaml is the token source of truth — a
glossarysection now defines roles / lifecycles / wake_mechanisms / queue_kinds / queues / stand_profiles / stand_probes / intake_disciplines; the rest references tokens. Heartbeat is redefined as coordd's in-flight-turn hang detector (not a watchdog liveness scan).
Removed¶
- The prompt-generation layer:
render-role+role contractCLIs,command_START.yaml, and allroles/*.md. - The unused bot stream (BOT-USER / BOT-DEVELOPER roles,
bot_*queues), the deadstand_enumsblock +task new --request-type/--profileplumbing, the stalled-agent sweep + its config, and the vestigial stale-kick constants/log in coordd. - All numbered task-id and past-version references from the canon docs.
1.4.2 — 2026-06-02¶
Patch release: SAFETY + the recovery-chain fixes the on-stand validation surfaced after 1.4.1 shipped.
Fixed¶
-
0349 SAFETY: EXPLORER host-destructive actions must target the avatar stand only. EXPLORER had no machine-target boundary, and a recent campaign ran
killagainst local coordd on the dev fleet — host-destructive work hit the local greatminds-dev fleet instead of the avatar stand. The codex profile now spells out: "the stand" = the AVATAR host (deployed/srv/greatminds-stand), a DIFFERENT machine from EXPLORER's own process host. Every host-destructive / lifecycle / recovery command (kill, pkill, kill -TERM/-KILL/-SIGINT, systemctl stop/restart/kill, killing coordd / driven-worker / codex-app-server, logout, reboot) MUST run on the avatar viassh <STAND_HOST>. Strictly forbidden against localhost or the local greatminds-dev fleet (greatminds-daemon@greatminds-dev + coordd). "The local host is NOT the stand; never damage it." Unresolvable destructive command → do not run; file a blocker. The 0344 stand-anchor is preserved (ssh remains allowed for on-stand operation); the 0331-era no-host blanket is not re-added. -
0345 watchdog ignores non-role heartbeat files + coordd periodically reaps orphan intents. On a healthy reactive fleet watchdog flagged
heartbeat.planner+heartbeat.review_sessionsas stale, but those names are a tmux WINDOW name and a QUEUE name, not role heartbeats — the per-lifecycle threshold could not resolve them and fell back to the 600s default. Filename resolution now SEGREGATES non-role files (window / queue / unknown stems) into a single info line ("heartbeats: N non-role/legacy file(s) ignored: ..."). Orphan intents also piled up because the reaper existed but nothing ran it automatically; the safe reaping core is extracted intointent_clean.reap_orphan_intentsand coordd runs it periodically (default 300s), wrapped so it never crashes the loop. -
0346 coordd systemd unit
Restart=alwaysso external kills resurrect coordd. The coordd systemd template unit usedRestart=on-failure. coordd catches SIGTERM and returns cleanly, so an externalkill -TERMproduced exit 0/SUCCESS and on-failure did NOT restart the killed coordd (NRestarts=0, unit went dead). NowRestart=always(RestartSec=2) in both the shipped canon unit and the inline fallback body. Systemd resurrects coordd after any external kill / crash; a deliberatesystemctl --user stoporgreatminds daemon stopis still honored (systemd never auto-restarts a commanded stop regardless ofRestart=), so update / restart flows are unaffected. -
0347 coordd Step-2 inbox-scan drives migrated driven roles via the shared driver. coordd drove driven roles only from the queue/.stand path; the inbox-scan woke every role via sigint_deepest_descendant / press_enter. A driven role's pane is idle bash between turns, so an inbox wake of a killed driven codex worker sigint'd a dead pane — nothing re-drove or re-registered it (agent status stayed not-registered). Extracted the dispatch decision into
_maybe_drive_driven_role: lifecycle==driven AND coord.yaml window mode==driven → route through the driver (claude_driver for tool=claude, codex_driver for tool=codex); else None and the caller falls back to the legacy wake._route_queue_eventand the Step-2 inbox-scan both use the shared helper. A killed driven codex worker re-registers on the next event via a force-fresh turn. -
0348
greatminds restartskips driven windows + reports them as coordd-managed. restart's_relaunchbuilt the launch command with the coord.yaml window mode verbatim, so a driven role gotgreatminds start-agent <ROLE> codex --mode driven;--modeisChoice(loop|chat)and errored, restart exited non-zero, the role was left MISSING. launch.py already SKIPS mode==driven windows; restart now mirrors that —_relaunchskips driven windows (recovery is the next coordd event; --reset still clears session files), and_verifyreports driven roles asdriven (coordd-managed)and excludes them from total/fail (pre-0348 they were flagged MISSING on a healthy driven fleet).
Operator migration¶
- Re-seed
coordination/.codex-home/explorer/so the 0349 + 0344 clauses reach the LIVE EXPLORER.greatminds setupseeds the per-role codex homes once without overwrite, so MAINTAINER / STAND-KEEPER must refreshcoordination/.codex-home/explorer/from the corrected shipped profile after the .venv-coord clean-wheel upgrade. Preserveauth.jsonin the per-role home during the refresh. - Run
greatminds daemon install(orgreatminds daemon repair) +systemctl --user daemon-reloadso the existing greatminds-daemon unit picks up the 0346Restart=alwaysdirective.
1.4.1 — 2026-06-02¶
Patch release: brings the shipped EXPLORER codex profile in line with the 0336 stand-anchor. Until this patch lands on the fleet, EXPLORER's seeded codex profile keeps injecting a stale web-only boundary that overrides the canon and blocks on-stand validation.
Fixed¶
- 0344 EXPLORER codex profile carries the 0336 stand-anchor. The
shipped
src/greatminds/data/codex/profiles/explorer.config.tomldeveloper_instructionsstill carried the stale web-only boundary ("NEVER ssh into stand hosts. NEVER docker/docker compose. NEVER ls/cat host filesystem. REST API + DB ... ONLY"), which the running EXPLORER read at every turn via the seededcoordination/.codex-home/explorer/layer. Replaced with the 0336 stand-anchor: EXPLORER always works ON the stand as a real user whatever the product shape — HTTP/browser for web, ssh + host CLI for host/CLI products, wherever deployed; host-destructive + recovery scenarios are EXPLORER's on the disposable stand; off-stand and local substitutes strictly forbidden. The coordination-access CLI-only rule is retained as a separate, correctly-scoped clause (it scopescoordination/I/O via the greatminds CLI; it is NOT about probing the deployed product).[profiles.explorer]table unchanged.
Operator migration: greatminds setup seeds
coordination/.codex-home/explorer/ once without overwrite. For
the LIVE EXPLORER to stop injecting the stale boundary,
MAINTAINER / STAND-KEEPER must re-seed / refresh
coordination/.codex-home/explorer/ from the corrected shipped
profile after upgrading the fleet to 1.4.1 (or the next on-avatar
deploy regenerates it).
1.4.0 — 2026-06-02¶
Minor release closing the 0311 Phase 5 stand-robustness work + the DOD2 operator-CLI batch, on top of the 1.3.12 reactive-fleet base. Highlights: per-lifecycle watchdog thresholds, codex 0.135 profile-v2 split, the CLI-only coordination-access rule wired to the actual agent prompt surface, a journal-tail / agent-status / task id-intake unification, a coordd .stand watch-up-front + STAND-KEEPER auto-wake, an expired-lease reclaim + queue-head auto-promote, the canon TESTER-local-exec ban, the EXPLORER stand-only contract restore, and a full reactive-fleet documentation refresh.
Added¶
-
0337 CLI-only coordination access rule reaches the render-role agent surface (DOD2). New
schema.coordination_accessdeclaresrule=coordination_access_via_greatminds_cli_only,forbidden=raw_ls_cat_grep_sed_edit_on_coordination, and the canonical CLI surfaces.cli/render_role.pyappends the rendered rule after the role body sogreatminds render-role <ROLE>carries it for every role — every driven turn and everystart-agentinjects the rule into the prompt. iter-1 wired it only torole_contract.render_contractwhich the agent path never calls; iter-2 closes that wiring blind spot. -
0338
greatminds journal tail— read-only filterable view ofcoordination/journal.ndjson(DOD2).-n N(default 20),--role Rmatches both theactorandrolefields (case-insensitive),--task Texact / prefix / leading-zero seq (0338matches0338-foo),--project-dir. Read-only: opens for reading only; bad JSON lines skipped; missing journal → clear error. -
0339
greatminds agent status— per-role pid / alive / session_id / venv / heartbeat_age / input_sock (DOD2). Replaces rawcat .agent_registry/<role>.jsonwith a clean contract surface. Alive viaos.kill(pid, 0)(PermissionError treated as alive — never report a healthy holder dead). Venv read from/proc/<pid>/environof the live process (dead pid / non-Linux → null).--jsonfor machine-readable consumers. No-arg lists every registered role;<ROLE>returns one (unregistered still emits a stable not-registered record). -
0342
greatminds stand reclaim— TTL+holder-alive reaper for expired singleton leases. STAND-KEEPER / ARCHITECT-PLANNER only. Frees a lease only when BOTH the lease is pastttl_secondsAND the holder agent is dead/absent (registry pid viaos.kill(pid, 0); absent registry → not alive). Conservative: unparseable ttl or PermissionError → NOT reclaimable. Refuses (exit 3) for no lease / in-TTL / holder-alive / non-SK/PLANNER caller / mismatched--lease-id. Closes the dead-holder + expired-lease permanent singleton lock.
Changed¶
-
0326 unify
greatminds tasksubcommand id intake (DOD2).find_tasknow accepts short id, full filename, and absolute / cwd-relative / coordination-relative path in addition to the existing forms; every id-taking subcommand resolves the same forms with one error shape (task <X> not found).task validategains a positional ID (with--id/--fileback-compat).task pathsgains an optional ID printing that task's queue + path; baretask pathsstill prints global coordination paths.show / mv / append-blockinherit the new forms viafind_task. -
0330 per-lifecycle heartbeat stale thresholds for non-continuous roles (Phase 5 of 0311). Watchdog used a single 600s window for every role, so alive-but-idle self-loop / driven / interactive roles were falsely flagged stale while their pids were live.
schema.watchdog.heartbeat_stale_seconds_by_lifecyclenow widens the window per lifecycle:self-loop: 4200(MAINTAINER ~1h cadence -
margin),
driven: 14400(4h — workers idle between events),interactive: 86400(24h — human-paced). Global 600s retained as continuous-signal default; explicit per-role override still wins. Dead-pid registry scan remains the authoritative event-driven liveness signal — a dead pid is still flagged regardless of heartbeat age. -
0332 codex 0.135 profile-v2 —
greatminds setupemits the per-role codex split layout (Phase 5 of 0311). codex 0.135.0 rejects--profile <role>whenCODEX_HOME/config.tomlcarries a[profiles.<role>]table or top-levelprofile=selector. Setup now splits the shippedcodex/profiles/<role>.config.tomlat the[profiles.<role>]marker — everything before becomes the baseconfig.toml; the keys after become a sibling<role>.config.tomllayer.start_agent.py --profile <role>unchanged (reads the layer); idempotent re-run preserves an operator-edited base. -
0333 canon forbids TESTER local execution +
uv run --activefleet-wide. Root-cause fix for the recurring.venv-coordeditable contamination (fleet-wideModuleNotFoundError: greatmindsafter worktree prune). COORDINATE.md §12.5: the cd-into-worktree line no longer names TESTER nor says editing/testing; implementers cd in to EDIT only; TESTER does NOT edit or execute in the worktree — its only execution surface is SSH probes against the deployed stand after STAND-KEEPER rsync. Fleet-wide ban:uv run/uv run --activeis forbidden for every role anywhere in the repo (hijacks the active venv → dangling.pthon prune).schema.yamlTESTER.forbidden_actions += run_local_tests, uv_run_or_active_against_fleet_venv(machine-readable; rides the role-contract render). -
0336 revert 0331 — restore the EXPLORER stand-only contract (Phase 5 of 0311). 0331 inverted EXPLORER: it forbade the stand host and forced local CLI/REST-only ("black-box"), the opposite of EXPLORER's role (operate ON the live system as a real user). Surgical removal of the 0331 schema / canon / template / test additions. New "Stand anchor (absolute, non-negotiable)" section in EXPLORER.md codifies that EXPLORER always operates ON THE STAND with whatever access shape the product carries (HTTP / SSH / wherever it is actually deployed); host-destructive + recovery on the disposable stand; off-stand and local substitutes strictly forbidden.
test_explorer_stand_anchor_0336.pypins the anchor. -
0340 DOD2 full reactive-fleet documentation refresh. New
docs/architecture/lifecycle.md(lifecycle × tool matrix + recovery chain) anddocs/operations/runbook.md(CLI-only discipline, fleet-venv direct-binary launch, court-fix / venv-recovery / wake-SK / diagnostics). Updates acrossdocs/architecture/daemon-and-agents,docs/cli-reference/index,docs/concepts/{inbox, queues, roles, scenarios, stand-operations},docs/index,docs/recipes/e2e-testing, andmkdocs.yml. Canonsrc/greatminds/data/COORDINATE.md§12 migrated to stand-lease wording; new rootCOORDINATE.mdpublication mirror; eight role canons migrated fromstand_request/evidence_fortogreatminds stand lease/stand release.
Fixed¶
-
0341 coordd watches
.standup front so lifecycle changes wake STAND-KEEPER. Root cause for "stand transitions don't wake STAND-KEEPER without a manual nudge":_InotifyWatcher._add_initial_watchesskipped any dir absent at startup, but.stand/is created lazily by the first stand lease. When coordd started BEFORE any lease (fresh deploy / restart — the common case), the.standwatch never attached. coordd now creates.standup front and attaches its watch even when absent at startup; the firststate.yamlwrite surfaces a routed.standevent like any other queue→owner event. With SK now mode=driven a.standevent runs an SK driven turn via the existing driven branch. -
0343 freeing the singleton auto-promotes the next FIFO queue entry. The
stand releasedocstring promised "pops the next FIFO queue entry" but freeing the singleton did NOT promote the head; the stand sat free with pending queued leases never auto-activating. Newpromote_head_on_free(state, by_role)helper pops the head, grants it (granted_atnow,ready_at=None), setsactive_lease, drains the head from the queue, clearsdown_reason, recordsfree→preparing. Wired intostand release(active→free) andstand up(down→free) AFTER their →free record_transition;stand downintentionally does NOT promote (incident halt).
1.3.12 — 2026-06-01¶
Closes the 0311 reactive-fleet umbrella (Phases 1–4): every role
declares a lifecycle in schema; MAINTAINER is a non-user-facing
self-loop watchdog with auto_mode-allowed recovery commands; all
claude + codex workers are coordd-driven (one turn per event over
claude -p/--resume or a fresh codex app-server stdio); canon
prose + public mkdocs site mirror the model.
Added¶
-
0312 schema role contracts gain per-role lifecycle field (Phase 1a).
schema.roles.<ROLE>.lifecycle∈ {interactive,self-loop,driven}. PLANNER + USER interactive; MAINTAINER self-loop; 8 workers + BOT-* driven.greatminds role contract <ROLE>renders the line. -
0313 MAINTAINER recovery commands in
auto_mode.allow(Phase 1c). Schemaclaude_settings.auto_mode.allowgainsgreatminds restart/ daemon/start-agent,kill, andsystemctl --userpatterns so MAINTAINER's self-loop recovery survives the classifier ceiling without a USER present. -
0314 MAINTAINER self-loop watchdog tick (Phase 1b). Flips MAINTAINER from chat to a self-loop health-check tick that auto-restarts dead workers and coordd and escalates queue/FSM stalls + upstream-bug candidates to PLANNER. Non-user-facing — USER reaches infra topics through PLANNER.
data/command_START.yaml -
coord.yaml.template+MAINTAINER.mdreframed; recovery commands are already allow-listed. -
0315 coordd driver core spawns
claude --resumefor driven roles (Phase 2a). For lifecycle=driven + tool=claude coordd RUNS each turn viaclaude --resume <sid> -p "continue your tick"instead of waking a persistent agent. Pane is idle bash between turns; per-role run-lock prevents overlapping turns and sets a pending marker for mid-turn events;_route_queue_eventfalls through to legacy wake on missing session id / non-driven / non-claude. -
0316 role contract via
--append-system-prompt-file(Phase 2b). Each driven turn is a freshclaude -pcall, so the role contract lives in the system prompt:setup._seed_role_bootstrapswritescoordination/.bootstrap/<role>.mdfrom the existingrender_rolefor every role; the 0315 driver passes the file as--append-system-prompt-file. -
0317 driven driver session-reset policy at turn threshold (Phase 2c).
SESSION_RESET_TURN_THRESHOLD(default 50, env overrideCOORDD_SESSION_RESET_TURNS). At/above the threshold the next turn starts fresh (no--resume) with the bootstrap still riding, and the per-roledriven_turn_countresets to 1. Capsclaude --resumehistory growth. -
0318 migrate READER to driven lifecycle (Phase 2d — first low-risk pilot).
coord.yaml.templatereader window mode loop → driven, bootstrap launch /loop → driven._route_queue_eventdriven path now also checks coord.yaml window mode (lifecycle=driven AND tool=claude AND window_mode=driven); missing session_id forces a fresh first turn instead of falling back to wake. -
0319 migrate DEVELOPER + UI-DEVELOPER + TESTER + STAND-KEEPER to driven (Phase 2e). Batches the remaining four claude workers onto the driven driver. PLANNER (interactive) + MAINTAINER (self-loop) + codex roles unchanged.
-
0320 codex app-server as managed
systemd --userunit (Phase 3a).greatminds-appserver@<fleet>.servicetemplate carries an absolute-node ExecStart +Environment=PATHthat leads with the node bin dir, so codex's#!/usr/bin/env nodeshebang resolves under systemd's minimal PATH.greatminds daemon installenables the unit when the fleet has driven+codex roles. (The driver in 0321 ultimately uses stdio per turn rather than the WS socket; the unit is retained as harmless infrastructure for now.) -
0321 coordd codex driver via stdio app-server per-turn (Phase 3b). For lifecycle=driven + tool=codex coordd spawns a fresh
codex app-serverover stdio per event and speaks the line-delimited JSON-RPC (initialize→thread/start | thread/resume→turn/start→ waitturn/completed→ exit). Per-role run-lock + pending marker; async daemon thread releases the lock on completion and re-fires one pending event. Pane is idle bash between turns. -
0323 migrate EXPLORER (first codex worker) to driven (Phase 3c).
coord.yaml.templateexplorer window mode loop → driven; bootstrap launch /loop → driven with codex stdio-per-turn wording. The generic codex driver (0321) routes the new dispatch with no coordd code change. -
0324 migrate TECHNICAL-WRITER (last codex worker) to driven (Phase 3d). Same config-only flip as 0323. With this both codex workers run driven; ARCHITECT-REVIEWER stays non-driven for now.
Changed¶
- 0325 canon docs for the reactive-fleet lifecycle model (Phase 4).
COORDINATE.md§2.1 (new) carries the lifecycle vocabulary + the lifecycle × tool dispatch matrix + the systemd → coordd → MAINTAINER → worker/coordd/PLANNER escalation chain. Per-role canon files gain a Runtime lifecycle section; ARCHITECT-REVIEWER explicitly carries the legacy-launch fallback wording. Public mkdocs pages extend the window mode enum tochat|loop|driven, bifurcate the coordd wake vs driven-spawn paths, annotate every role with its lifecycle, and update the permissions paragraph from "loop-mode role" to "driven or self-loop role".
Operator migration¶
- Pre-1.3.12 fleets need a one-time
greatminds setupregen against their existing project (or hand-editcoord.yamlwindow modes for the affected roles) before the driven dispatch takes effect — setup never overwrites an existingcoord.yaml. Rungreatminds daemon repair --project <name>if the systemd--userunit was installed pre-1.3.11.
1.3.11 — 2026-06-01¶
Eight verified fixes covering the REVIEWER merge direction, the schema/gate-check stand_evidence contract, dispatch/lease coherence, worktree-isolation enforcement at the CLI, uniform session-start canon-read across role canons, SK heartbeat refresh during long ansible runs, daemon install systemd enablement + repair subcommand, and the launch/restart wrapper-loop removal.
Added¶
-
0303 task append-block enforces cwd under per-task worktree.
schema.worktrees.required_for_task_kindswas declarative only; implementers could silently edit main while filing impl/tests blocks (TESTER's lease then rsync'd a stale worktree, multiple stand_downs). New_enforce_worktree_isolation_for_blockruns at append-block entry — refuses with exit_code=2 + thecd "$(greatminds worktree path <id>)"recipe +GREATMINDS_SKIP_WORKTREE_CHECK=1escape hatch. Skip cases preserve current flows (non-code blocks, docs/research tasks, env-var override). -
0304 uniform session-start canon-read block across 8 role canons. Only MAINTAINER had explicit canon-read guidance at session start; fresh-install agents for the other 8 roles could (and did) skip re-reading COORDINATE.md / schema. Each of DEVELOPER, UI-DEVELOPER, TESTER, READER, TECHNICAL-WRITER, STAND-KEEPER, EXPLORER, BOT-DEVELOPER now carries a uniform
## Session start (0304)section + inline-invariants block. MAINTAINER.md intentionally untouched; the existing Does step 1 pattern is regression-locked. -
0307 daemon install enables unit +
greatminds daemon repair.greatminds daemon installnow runssystemctl --user enablefor the resolved template instance so the symlink lands underdefault.target.wants/and the unit auto-starts after logout / shutdown. Newgreatminds daemon repair --project <name>is the one-shot fix for existing pre-fix fleets — stricter than install (nonzero exit propagates because enable is the whole point).
Fixed¶
-
0300 worktree_merge pulls origin/main before merging task branch. Pins the REVIEWER verified-merge direction. The current code already did checkout main → merge task/
correctly; this adds the regression-net tests pinning the order plus the missing git pull --ff-only origin mainstep between checkout and merge so main advances when origin is strictly ahead. -
0301 stand_evidence required_subfields list matches gate_check expectations.
schema.tests_block_validation.stand_evidence. required_subfieldslisted 3 prose fields but gate_check also requiredlease_id,result,commit— every well-formed lease release hit "missing" at the feature_test → feature_review gate. Schema now enumerates all six;cli/task.pyvalidator reads from schema with a defensive 3-field fallback for partial installs. -
0302 dispatch_profile cross-checks
spec.nameagainstlease_meta['profile']. Pre-fix SK could silently run a spec-loaded-by-other-means against an unrelated lease.dispatch_profilenow refuses with exit_code=2 + GreatMindsError naming both values before any subprocess so a misrouted dispatch can never invoke the wrong playbook. -
0305 SK heartbeat refresh during long ansible runs (Fix B). Watchdog dead-pid asks were accumulating while SK was waiting on multi-minute ansible deploys. New
_start_heartbeat_refresherdaemon thread touchesheartbeat.<role>every 30s during the subprocess;execute_yaml_profilewrapssubprocess.runin try/finally so the refresher stops on every exit path. Fix A (coordd wake onstate.yamlwrites) was already in production. -
0308 launch sends
greatminds start-agentdirectly + restart mirrors the same sequence. Wrapper-loop install path replaced withtmux send-keys C-u+ the launch command + Enter on each pane; restart uses the same shared builder so launch and resurrect share one code path._wrapper_loop+CIRCUIT_BREAKER_*retained as dormant symbols for legacy fixtures; the wrapper's built-in counter is removed (failing agents retry naturally on the next restart; a watchdog-side counter lands as a follow-up).
1.3.10 — 2026-05-27¶
Fixes two operator-facing bugs in greatminds update so the command
works correctly on projects managed by uv / poetry / pipenv and stops
resurrecting torn-down fleet sessions.
Fixed¶
- 0299 update branches by
detect_env_setup+ skips fleet restart when tmux session absent.updateused to call pip even when the project lived under uv/poetry/pipenv, installing into the wrong env layer and then losing on the uv-lock mismatch on the next install. The pip-step is now replaced by adetect_env_setupdispatch: env_type=uv→uv lock --upgrade-package greatminds && uv syncenv_type=poetry→poetry update greatmindsenv_type=pipenv→pipenv update greatmindsenv_type=condaor fallbackNone→<py> -m pip install …
The fleet-restart step also called tmux send-keys unconditionally,
resurrecting state on hosts where the operator had torn the tmux
down. _step_restart_agents now gates on
_tmux_session_present(name) (reads session name from
coord.yaml, checks tmux PATH + has-session rc, swallows
TimeoutExpired); when the session is absent it logs a skip-info
and returns without touching tmux.
1.3.9 — 2026-05-27¶
Critical fix for the chat-mode UserPromptSubmit deadlock that shipped across the 1.3.x line. Operators on existing projects should upgrade promptly.
Fixed¶
- 0298 stop-decide
user-prompt-submitphase no longer emitsdecision: block.greatminds stop-decidereturned the same{decision: block, reason, systemMessage}payload for bothphase=stop(correct — Stop hook drains inbox between turns) andphase=user-prompt-submit(catastrophic — the UserPromptSubmit hook withdecision: blockrejects EVERY USER prompt, leaving chat-mode roles like PLANNER and MAINTAINER unreachable until an operator hand-edits the inbox directory).stop_decide.pynow branches on phase:user-prompt-submitemits only{"systemMessage": msg}so the informational notice surfaces but USER's prompt passes through;phase=stopunchanged. Test assertions intest_user_prompt_submit_hook_0236.pythat pinned the bug were rewritten to the post-0298 contract.
1.3.8 — 2026-05-27¶
Adds PLANNER's machine-readable contract for the stand-profile mechanism so fresh-install PLANNER agents pick up the workflow at tick start without an operator ping. Closes the role-contract gap left after the 0276 stand-profile umbrella shipped.
Added¶
- 0297 PLANNER role contract gains stand-profile coordination.
schema.roles.ARCHITECT-PLANNERnow declarescoordinate_stand_profile_tasks_via_schema_and_canon+file_schema_extension_task_on_lease_enum_blockresponsibilities and three newevent_triggers:on_stand_down_yaml_playbook_error(file YAML bugfix from SK's inbox-info),on_stand_down_md_interpretation_error(same flow for MD prose),on_stand_lease_enum_block(file schema-extension task before the dependent lease proceeds).ARCHITECT-PLANNER.mdcarries a short cross-reference paragraph — no duplicate prose.
1.3.7 — 2026-05-27¶
Closes the 0276 stand-profile umbrella DoD with the MD-cycle live-green on real avatar.
Added¶
- 0295 liveness-prose MD-only canon template (Phase I of 0276).
New
data/templates/stand-profiles/liveness-prose.mdwith no YAML twin soload_profileresolves toformat='md'and SK dispatches throughexecute_md_profile(notexecute_yaml_profile). Frontmatter declaresdeploy_prerequisites_only: false; body references${host},${user},${deploy_path},${task_id},${lease_id}to exercise the substitution path on a real lease. Tests pin the NO-YAML-TWIN invariant as a regression net so a future yaml file with the same stem can't silently short-circuit the MD path.
1.3.6 — 2026-05-27¶
Closes the 0276 stand-profile umbrella with the live-integration phase plus a chain of canon-playbook robustness fixes empirically proven on real avatar deploys, and pushes the schema enum so md-only profiles can be leased.
Added¶
-
0284 end-to-end stand-profile cycle tests + collection-free rsync (Phase H of 0276). New
test_stand_profile_end_to_end_0284.pyexercises the YAML cycle (loader → dispatch argv → prereq tag) and the MD cycle (loader →${var}substitution →PREREQ_ONLY_NOTICEinjection) plus a realansible-playbook --syntax-checkagainst the seeded canon playbook. The canonfull-deploy.yamlsynchronizetask is replaced withdelegate_to: localhost+ansible.builtin.command: rsync …, dropping theansible.posixcollection requirement. -
0291 SK
stand downauto-notifies PLANNER inbox. Newschema.stand_keeper.notificationsmap (on_down: ARCHITECT-PLANNER).stand_downmutator captures the active lease'stask+lease_id, files"stand down: <reason> (lease_id=<id>)"to PLANNER's inbox withtask_refpopulated. PLANNER no longer pollsstate.yamlto discover incidents. -
0296 schema
stand.resource.profiles_allowed+=liveness-prose. Enum extended and the canonliveness-prose.mdtemplate shipped in the same commit so md-only profiles can be leased without an enum rejection.
Fixed¶
-
0292
full-deploy.yamlinstall step usesuv pip.uv venvdoes not install pip, so.venv-coord/bin/pipfailed rc=2 on every fresh deploy. Replacement usesuv pip install --python .venv-coord/bin/python --force-reinstall …— no pip-in-venv required. -
0293
full-deploy.yamlpre-build wheel cleanup avoids glob collision. Second-or-later deploys left a prior wheel indist/, causinguv pip install dist/greatminds-*.whlto refuse with "ambiguous glob". New pre-buildansible.builtin.shell: rm -f dist/greatminds-*.whltask ordered beforeuv buildso the install glob always resolves to exactly the freshly-built wheel.
1.3.5 — 2026-05-27¶
Adds schema-driven role contracts so any agent can read its own
workflow from schema.yaml at tick start, and plugs the orphan
active_lease leak that produced state=down + active_lease={...}
contradictions across the stand transitions.
Added¶
- 0288 schema-driven role contracts for all 13 roles + CLI.
schema.roles.<ROLE>now carriesresponsibilities,forbidden_actions, and (for product roles)event_triggers(on_<event>→ ordered step list). Steps are short verbs — CLI commands likestand_lease/stand_ready/mv_to_feature_review, or logical placeholders the LLM resolves. Newgreatminds role contract <ROLE>+greatminds role listCLI surface the rendered contract. Existingroles/*.mdprose remains; doc-shrinkage follow-up deferred.
Fixed¶
- 0289 stand release/down/up nullify
active_lease. Pre-fixstand downleft the triggering lease set, andstand updid not defensively clean older state files — producingstate=down + active_lease={...}contradictions visible instand status. Mutators now setactive_lease=Noneon both transitions alongside their existingdown_reasonmutations;stand releasealready cleared correctly and is now regression-locked.
1.3.4 — 2026-05-27¶
Followup patch tightening the SK runtime gate so the stand-profile dispatch contract is actually enforced.
Fixed¶
- 0286 three-layer deploy lock. SK could still mark state=ready
without invoking ansible-playbook because the
is_deploy_safeclassifier landed in 1.3.3 had no callsites in the runtime path. Three independent layers now enforce the contract end-to-end: (1)execute_yaml_profilegates onis_deploy_safeat top of function — unsafe → rc=126, no subprocess, reason captured in marker. (2) Both executors drop a per-lease marker at<coord>/.stand/deploy-<lease_id>.log; timeouts (124), FileNotFoundError (127), and refusals (126) all record markers so failure modes surface via rc, not "no evidence". (3)greatminds stand ready --lease-idrefuses with exit_code=2 + actionable message when the marker is absent. STAND-KEEPER.md §2 codifies thedispatch_profileMUST-precede contract.
1.3.3 — 2026-05-27¶
Stand-profile mechanism (0276 umbrella, Phases A-G) plus a deploy-safety fix that unblocks Phase H avatar verification.
Added¶
-
0277 stand_profile schema section + canon convention (Phase A).
schema.stand_profiledeclares directory (coordination/stand-profiles), formats (yaml/md), lookup pattern, dialects (ansible-playbook subset / free prose), yaml required + optional fields, anddeploy_prerequisites_only_flag. COORDINATE.md §8.1 documents file-name convention, YAML-wins-on-conflict, and referencesschema.stand_profileas source of truth. -
0278 stand_profile loader/parser (Phase B). New
cli/stand_profile.pyexposesProfileSpec+load_profile+profile_paths. Lookup precedence: yaml → md → error naming both paths.deploy_prerequisites_onlyextracted uniformly fromyaml.varsor md frontmatter. Malformed MD frontmatter silently falls back to full body. -
0279 SK execution path — YAML→ansible-playbook + MD→prose (Phase C).
cli/stand_executor.pyaddsexecute_yaml_profile,execute_md_profile, anddispatch_profile. YAML synthesizes inventory + extra-vars (via@<json-file>so shell metacharacters survive) and shells out toansible-playbook. MD substitutes${var}viastring.Template.safe_substitute(unknown vars stay literal). STAND-KEEPER.md §Does Step 2 extended. -
0280 ansible-core hard dep (Phase D).
pyproject.tomlpinsansible-core>=2.16,<2.18;setupruns a sanity check at the end of its run that warns (but does not abort) if ansible-playbook is missing — MD-only operators stay unblocked. -
0281 full-deploy + smoke-only presets (Phase E). Four canon preset files under
data/templates/stand-profiles/(yaml + md for each).setup._seed_stand_profilescopies them into<coord>/stand-profiles/idempotently. Loader side-fix:_load_yaml_profilenow accepts both list-of-plays (real ansible playbook) and mapping (single-play short-hand) at the top level. -
0282 canon updates — STAND-KEEPER + TESTER + COORDINATE.md (Phase F). STAND-KEEPER workflow anchors on
load_profile + dispatch, success/failure viastand ready/down,deploy_prerequisites_onlysemantics. TESTER scope tightens to probe-only with a deploy-pipeline carve-out. COORDINATE.md §8.1 publishes profile ownership, consumers, format choice. -
0283
deploy_prerequisites_onlyflag end-to-end (Phase G).greatminds stand lease --deploy-prerequisites-onlypersists the flag intoactive_lease.deploy_prerequisites_onlyonly when True (minimal-state pin). YAML executor appends--tags prerequisiteon the resolved value; MD executor prependsPREREQ_ONLY_NOTICEbanner so SK's LLM sees the mode switch before the recipe. Lease-level override wins over spec value.
Fixed¶
- 0285 SK deploy-bypass closed —
is_deploy_safeclassifier. SK was refusing every deploy that touched the main fleet tree, even when the lease pointed at a per-task.worktrees/<seq>/worktree OR named a remoteSTAND_HOST; state short-circuited to ready withoutansible-playbookexecuting. Newis_deploy_safe(worktree, host, project_dir)classifier resolves three branches: isolated worktree always safe, main-tree + local-host unsafe (self-modify), main-tree + remote-host safe.LOCAL_HOSTSset + host normalization so PROJECT.env strings classify cleanly. Lease mutator also clears staledown_reasonon free→preparing so prior incidents don't poison subsequent leases.
1.3.2 — 2026-05-27¶
Followup cut after the 1.3.0 BREAKING stand-stream redesign + 1.3.1 emergency wake fix. Five verified tasks merged on local main; all empirically validated via real avatar SSH stand probes (no shape-only evidence).
Fixed¶
-
0258 — complete BREAKING removal of stand-stream runtime. CLI now rejects
--stream standand--kind stand_requestwith rc=2 +stream=stand removed in 1.3.0message;greatminds setupno longer scaffoldsstand_{requests,wip,done}/directories;coordd._build_inotify_dirsdrops the legacy queue watches; newgreatminds migrate-stand-historyCLI moves pre-1.3.0stand_done/*artifacts undercoordination/archive/stand-history/(idempotent, supports--dry-run). -
0268 —
_evaluate_gate_checkreads lease evidence first. Pre-fix, a lease-evidence-carrying task could seegate-checkreturnpassfrom the lease while_check_gate_for_stand_requiredreturnedmissingfrom the same task data (the latter only knew about removedstand_done/<id>.yamlfiles). Nowextract_lease_evidence_from_testsis probed first; the legacyfind_stand_evidencepath remains as a fall-through for any in-flight pre-migration tasks. -
0267 —
greatminds setupbakesautoMode.allow+ ops perms from schema canon.data/schema.yamlnow declares the fullclaude_settings.autoMode.allow(Bash(git push origin main:*)+--follow-tagsvariants) andclaude_settings.permissions.allow(ssh / scp / rsync / git revert) under one source of truth._build_settings_local_jsonpopulatesautoMode.allowfrom schema instead of a hardcoded list;_ensure_claude_settings_localadditively merges new canonical entries on existing fleets — the operator's own additions and Stop/UserPromptSubmit hooks are preserved; repeat runs reportunchanged. -
0269 — coordd inotify
.standevents route to STAND-KEEPER..standwas anINOTIFY_QUEUE_DIRSentry but not listed inschema.queues, so_owning_role_for_queue('.stand')returnedNoneand_route_queue_eventsilently dropped state.yaml writes. Schema now declares.standwithowner: STAND-KEEPER,writers: [STAND-KEEPER, TESTER, ARCHITECT-PLANNER, MAINTAINER],kind: state. Lease delivery latency drops from waiting on SK's own ScheduleWakeup tick to coordd-pushed viapress_enteron the input_sock. Thekind: statemarker keepswatchdog(active-only) andwake_check(terminal-only) iterations untouched. -
0271 —
greatminds stand leaseenforces per-task worktree at acquire. Pre-fix the only worktree enforcement was SK's runtime whitelist; the CLI accepted any--worktree, flipped state.yaml topreparing, and only SK rejected later with a self-modify reason, leaving an orphaned lease. Now schema declaresstand.resource.lease.worktree_constraint(pattern{project_dir}/.worktrees/{seq}[-slug],enforced_by: cli) andstand.py:_validate_lease_worktreerejects at acquire with rc=2 + named-rule errors: empty/None, main-tree (with paste-readygit worktree addrecipe), wrong parent, wrong basename. Relative paths resolve viaPath(...).resolve(strict=False). state.yaml is not mutated on reject.
1.3.1 — 2026-05-26¶
Emergency cut. Single fix: 0259 — coordd's chat-mode inotify wake now reaches the claude TUI input handler.
§9.1 self-blocker carve-out: the fix's deployment IS the
verification mechanism (gate_check on 0259 was irreducibly blocked
because SK couldn't deploy 0259 to verify itself — the broken wake
channel was the verification channel). Same pattern as the 1.2.6
cut. Empirical evidence recorded inline in 0259's tests block:
direct press_enter probe on READER returned ok=True with
input_sock channel + leaf SIGINT; end-to-end probe (filed
feature_inbox/9999.yaml → coordd inotify → press_enter →
input_sock → SIGINT to PLANNER's own Bash subprocess exit 130)
confirms the full chain.
Fixed¶
- 0259 coordd inotify wake uses
input_sockviapress_enter. Pre-0259, coordd's chat-mode wake (tmux_send_keys_wake) sent bracketed-paste text + Enter viatmux send-keys, but the TUI input handler on claude panes intermittently never received the submit (visible prompt, no turn-fire). Replaced withpress_enterwriting the wake payload to the role's pty-trackedinput_sockand SIGINTing the leaf=node descendant — same channel that DEV/OPERATOR keystrokes flow through. _send_enter.pyalignment withcoordd.WAKE_*constants (PLANNER follow-up)._WAKE_GAP_S0.2 → 0.35 (mirrorscoordd.WAKE_GAP_SECONDS, production-proven viapush_to_role)._KEY_TO_BYTES['Enter']b'\r'→b'\r\n'(mirrorscoordd.WAKE_ENTERCRLF; bare CR fails claude TUI submit detection intermittently).
Removed¶
coordd.tmux_send_keys_wakefunction and its_LAST_TMUX_NUDGErate-limit table +_read_event_wake_schemahelper. All chat-mode wakes now flow throughpress_enter.
Upgrade¶
pip install --upgrade greatminds==1.3.1
greatminds restart --bootstrap
1.3.0 — 2026-05-26¶
BREAKING. Stand-stream redesign: the legacy three-queue model
(stand_requests/ → stand_wip/ → stand_done/) is replaced by a
lease-based singleton stand resource backed by
coordination/.stand/state.yaml. Operators upgrading from 1.2.x must
drain any in-flight stand_requests/* and stand_wip/* before
pip install --upgrade greatminds==1.3.0; existing stand_done/*
files may stay as historical evidence.
Breaking¶
- Old stand queues removed.
stand_requests/,stand_wip/,stand_done/queue directories are no longer scaffolded bygreatminds setup. All transitions touching them are gone fromschema.yaml, along with thestandtask stream and four stand-stream validators incli/task.py. greatminds stand request/stand resultCLI removed. Replaced by the lease API below.greatminds task new --stream standraises with a pointer at the new CLI.gate_checkreads lease evidence exclusively. The backwards- compatibility fallback tofind_stand_evidence(stand_done scan) is gone. Pre-1.3.0 tasks without alease_idon their tests block returnmissing; refile via the lease API to verify.
Added¶
- Lease-based stand CLI:
greatminds stand lease --task <id> --worktree <path> --profile <enum>— request a lease; returns a UUIDlease_id. FIFO queue when the stand is busy.greatminds stand release --lease-id <id> --result pass|fail|partial— return the stand to free; result is a closed enum (no prose channel).greatminds stand ready --lease-id <id>— SK signals deploy complete; state preparing→ready; inbox-info to holder.greatminds stand down --reason …/stand up --reason …— halt/recovery; queue paused underdown.greatminds stand status— read-only state + queue + history- tail.coordination/.stand/state.yamlsingleton state file with fcntl-protected I/O. Four states (free/preparing/ready/down) and transitions encoded inschema.yaml stand.resource.coorddinotify on.stand/so SK reacts sub-second to state changes instead of polling.- Role canon (
STAND-KEEPER.md,TESTER.md,EXPLORER.md) rewritten for the lease lifecycle. SK input is structured-only (--task,--worktree,--profile); SK never seeswhat to testby design (information asymmetry forces TESTER ownership of probes). - Public docs: new
docs/concepts/stand-operations.mdpage,docs/concepts/stand-gate.mdupdated for lease evidence,mkdocs.ymlnav entry,docs/architecture/filesystem-layout.mdreflectscoordination/.stand/state.yaml.
Companion changes (1.2.x → 1.3.0 batch)¶
- Commit-drift closure (0228 / 0229 / 0233): TESTER own
functional_probes + tester_observations are now required on a
scope-driven schema gate;
gate_checkrecords a worktree fingerprint to distinguish committed vs in-flight overlays;greatminds stand request(now removed in 1.3.0) resolved target_commit fromevidence_for[0]'s impl block — superseded by lease--worktreesemantics. - 0236 + 0237 UserPromptSubmit hook + tmux send-keys split fix for chat-mode panes (PLANNER / MAINTAINER) no longer miss messages during USER topic-switches.
- 0238 new
docs/concepts/codex-profiles.mdpage covering the 0158 per-roleCODEX_HOMEmodel. - 0241 PLANNER role canon — propose-then-file default chat posture, codified.
- Bugfixes 0198 / 0202 / 0204 / 0235 + 13 doc tasks (0208 → 0220) cleared along the way.
Upgrade¶
pip install --upgrade greatminds==1.3.0
greatminds update # restarts daemon + agents
greatminds update auto-runs daemon install when the per-project
template unit is missing (0202), so legacy pre-0008 fleets upgrade
in a single step.
1.1.2 — 2026-05-21¶
Bug-fix release. Three regressions found in 1.1.0 real-world use, plus a critical wake-up channel regression introduced silently by the 1.0.0 umbrella-console-script migration. No new features.
Fixed¶
task append-block --body-fileoption missing. Dropped during the argparse→click conversion. The plan orchestrator and several agent prompts still passed it, breaking the orchestrator. Restored.coerce_valueblanket-split every--fieldvalue on commas, so any prose value (e.g.stand_reason="POST /node, then GET /health") was silently turned into a YAML list, and downstream validators choked. Now only fields explicitly inLIST_FIELDSare split on commas; all other fields stay strings even if they contain commas or colons.- click
multiple=Truedid not accept argparse-style space-separated values (--hosts X Yfailed with "Got unexpected extra argument (Y)"). New_split_multivaluecallback supports both forms:--hosts X --hosts Y(repeated flag, idiomatic click) AND--hosts X,Y(one flag, comma-separated).stand requestuses it consistently. greatminds-pty-launchconsole-script never existed in 1.0.0 umbrella migration —pyproject.tomlonly declaresgreatminds, soshutil.which("greatminds-pty-launch")always returnedNone, silently disabling pty wrapping. Result: every agent since 1.0.0 ran without the pty wrapper → noinput_sockin.agent_registry/ <role>.json→ coordd fell back to writing /dev/pts (slave side = display output, NOT input) → wake keystrokes never reached agents, who only ticked on their own ScheduleWakeup timer. start_agent now invokes pty_launch viapython -m greatminds.cli.pty_launch(same pattern as render-role).pty_launch.write_registrywas overwritingsession_idput there by start_agent's pre-pty registry write. Now it MERGES on top of any existing record so session_id (and any other downstream key) survives the pid/sock enrichment.- click strips
--from variadic args inpty_launch's click signature, breaking claude's--mcp-config <file> -- PROMPTcontract (claude's variadic--mcp-configconsumes the prompt as a config file). Thepython -m greatminds.cli.pty_launchdirect-exec path now bypasses click for argv parsing so--survives into the child's argv. The umbrellagreatminds pty-launchsubcommand path goes through click and remains affected — but that path is only used for diagnostics, not by start_agent.
Changed (internal — no behavioural change for users)¶
- Full click-native CLI rewrite per the
guardora_vflreference pattern. Dropped: - 9
SimpleNamespaceshims that wrapped legacycmd_X(args: argparse.Namespace)handlers from the argparse era. - 5
import argparsestatements (task.py,inbox.py,stand.py,coordd.py,start_agent.py). die(code, msg)global helper — replaced with directraise GreatMindsError(msg, exit_code=N)at every callsite. One exception class total (GreatMindsError(click.ClickException)), no subclass hierarchy.- Inter-module subprocess calls between
stand.py/plan.pyandtask.pyreplaced with direct Python function imports:create_task(),move_task(),append_block(). These are the library API; the click handlers are thin wrappers calling them, matching vfl'screate_node()/create_project()pattern.
Added¶
tests/test_task_field_coercion.py— pytest regression suite covering all three 1.1.0 bugs (20 tests, all passing). Tests:stand_reasonwith commas/colons stays string; LIST_FIELDS still split;--body-fileworks;--body @PATHworks; hosts comma-separated AND repeated-flag forms.core/errors.py— singleGreatMindsError(click.ClickException)type. Callers pass exit code at the raise site:raise GreatMindsError("bad value", exit_code=2).- CI: pytest runs against the installed wheel after the smoke loop.
1.1.0 — 2026-05-21¶
Breaking — canon docs translated to English; env-var namespace
renamed COORD_* → GREATMINDS_*; new --lang option for greatminds
setup controls the user-facing language each agent uses while keeping
internal artefacts (task files, journal, code) English.
Breaking¶
- All
COORD_*env vars renamed toGREATMINDS_*: COORD_PROJECT_DIR→GREATMINDS_PROJECT_DIRCOORD_CANON_DIR→GREATMINDS_CANON_DIRCOORD_ROLE→GREATMINDS_ROLECOORD_FORCE→GREATMINDS_FORCECOORD_FRESH→GREATMINDS_FRESHCOORD_REGISTRY_TOOL→GREATMINDS_REGISTRY_TOOLCOORD_START_AGENT_SAFE|NOTITLE|NOPTY→GREATMINDS_START_AGENT_*COORD_CURSOR_MEM_MAX|MEM_HIGH|CPU|MODEL→GREATMINDS_CURSOR_*COORD_POSTGRES_DSN→GREATMINDS_POSTGRES_DSN- Canon docs (
COORDINATE.md,command_START.yaml) translated from Russian to English. Pre-1.1.0 versions on PyPI (0.1.0, 0.1.1, 1.0.0) shipped Russian-only canon by mistake — yank them in favour of 1.1.0+.
Added¶
greatminds setup --lang <code>flag — records the agent user-facing language inPROJECT.mdas<GREATMINDS_LANG>. Any language a chat model speaks works (en,ru,zh,es,fr,ja, etc.). Default:en.- Common preamble in
command_START.yamlinstructs every agent to communicate with the USER in<GREATMINDS_LANG>while keeping internal artefacts (task YAML fields, journal entries, commit messages, file paths, inbox messages between roles, code) English regardless.
1.0.0 — 2026-05-21¶
Breaking release — the 19 separate greatminds-* entry-points
are consolidated into a single greatminds umbrella with subcommands
(click groups + flat commands). All canon docs and prompts now use
greatminds X syntax instead of bin/X.
Breaking¶
- Single entry-point
greatmindsreplaces the 0.1.x set of 19greatminds-*binaries. Migration: greatminds-task list verified→greatminds task list verifiedgreatminds-inbox send DEVELOPER --kind wake→greatminds inbox send DEVELOPER --kind wakegreatminds-stand request --request-type deploy …→greatminds stand request --request-type deploy …greatminds-coordd --verbose→greatminds coordd --verbosegreatminds-coord-launch --target tmux→greatminds launch --target tmuxgreatminds-coord-init→greatminds setup- (etc. — all 19 commands now subcommands of
greatminds) coord-init,coord-launch,coord-tmuxmodules removed; their functionality is ingreatminds setupandgreatminds launch.
Added¶
greatminds.core.env— adaptive Python-env detector covering 8 scenarios: pixi, uv, poetry, conda, plain venv, external-venv ($VIRTUAL_ENV), external-conda ($CONDA_DEFAULT_ENV), and system fallback.greatminds launchuses the detector to activate the project's env in each tmux window or VS Code task automatically — agent prompts can call baregreatminds Xwithout env-setup boilerplate.--venv /pathoverride ongreatminds launchfor explicit control when auto-detection isn't desired.greatminds setupextendscoord-initwith a clearer next-steps guide.- Click-native coloured output: cyan info / green success / red error / yellow warning across all subcommands.
Verified end-to-end¶
5 env-manager sandboxes (pixi, uv, poetry, conda, plain venv): each
runs greatminds setup + greatminds launch --target tmux,
attaches a window, executes greatminds --version from the
activated env — all five pass. Task lifecycle smoke (new → triage →
plan → dev) confirmed against a fresh project: 7+ journal
transitions, schema validation rejects malformed blocks, role
permissions enforced.
0.1.1 — 2026-05-20¶
Fixed¶
greatminds-coord-launchandgreatminds-coord-tmuxnow find a siblinggreatminds-start-agentin the same venv viaPath(sys.executable).parentBEFORE falling back toshutil.which. Previously they relied on PATH only, which broke when the user invoked the binary by full path (e.g../.venv/bin/greatminds-coord-launch) without sourcing the venv. Also:.resolve()is intentionally NOT called onsys.executablebecause uv-managed venvs symlink it to the underlying Python install — resolving would skip past the venv's bin dir entirely.- "each agent window has 'bin/start_agent
' pre-typed" message updated to print the actual resolved launcher name.
0.1.0 — 2026-05-20¶
First public release.
Added¶
- Python package
greatmindswith 19 console entry-points covering the full R8 pipeline: - Task management:
greatminds-task,greatminds-inbox,greatminds-stand,greatminds-plan,greatminds-migrate-task. - Pipeline introspection:
greatminds-gate-check,greatminds-wake-check,greatminds-watchdog,greatminds-intent-clean,greatminds-lint-tokens. - Hooks (Claude Code):
greatminds-stop-decide,greatminds-notify-journal. - Project bootstrap:
greatminds-coord-init. - Agent launcher / fleet:
greatminds-start-agent,greatminds-pty-launch,greatminds-render-role,greatminds-coordd,greatminds-coord-tmux,greatminds-coord-launch(tmux/vscode/cursor-ide targets). - Package data shipped under
greatminds.data:schema.yaml,command_START.yaml,COORDINATE.md,PROJECT_VARIABLES.md, 13 role specs underroles/, 8 layered Claude Code plugins underplugins/,mcp/canon.json(context7 + playwright), 3 codex profile-v2 configs undercodex/profiles/, queue templates undertemplates/. - Path resolution shared across all CLI modules via
greatminds.core: find_coord_dir(start=None, *, strict=True)— walks up from cwd or honours$COORD_PROJECT_DIR.find_canon_dir()—$COORD_CANON_DIRoverride orimportlib.resources.files("greatminds.data").caller_role(),die,now_iso,prog_name.- GitHub Actions CI building wheel on py 3.11/3.12/3.13, smoke-testing
every entry-point's
--help, validating packaged-data resolution, and runninggreatminds-coord-initon a fresh tmpdir.
Notes¶
- Apache-2.0 licensed.
coordd-install(Bash, systemd unit installer) and the stress-test scripts are not packaged in 0.1.0 — they will return as separate entry-points once their dependencies on systemd / heavy load generation are revisited.