Transitions¶
Allowed transitions are encoded in the packaged schema copied to
.greatminds/schema.yaml in an installed project. The CLI enforces the current
role, current queue, target queue, and required readiness evidence.
verified/ is not an absolute sink. If later review finds that verified work
is wrong, invalid, or already reverted, ARCHITECT-REVIEWER can append a
rollback block with a non-empty reason and move the task from verified/
to either archive/ or feature_review/. Use archive/ for withdrawn work
whose code state already matches the rollback; use feature_review/ when the
task needs another amendment or review cycle.
Read the source schema when changing the workflow:
# Coordination pipeline schema
#
# Machine-readable source of truth for queues, roles, transitions, and stand
# profiles. Read by the greatminds CLI (gate-check, wake-check, watchdog,
# lint-tokens), by each agent at tick start, and by humans cross-referencing
# COORDINATE.md prose.
#
# Invariants in COORDINATE.md must match what's encoded here. If they drift,
# the schema is normative — fix the prose, not the schema.
version: 1
# ---------------------------------------------------------------------------
# Glossary
#
# Single home for the text definition of every token used elsewhere in
# this file. A section that references a token (roles, queues, steps,
# enums, …) carries ONLY the token; its meaning is defined here, once.
# Agents read schema.yaml directly and resolve tokens against this
# glossary — there is no separate render step.
# ---------------------------------------------------------------------------
glossary:
roles:
ARCHITECT-PLANNER: "Intake triage, planning (writes the plan block, sets stand_required), and per-scope routing from feature_plan to feature_dev / feature_ui_dev / feature_docs. Interactive chat partner for the USER. Writes review_sessions but does not claim from it — EXPLORER owns review-session iteration."
ARCHITECT-REVIEWER: "Final review with stand-evidence verification (gate_check result in the tests block), commit, and push if policy allows. Owns feature_blocked wake-up: runs greatminds wake-check at the start of each tick."
DEVELOPER: "Backend / product-code implementation. Claims from feature_dev/ (placed there by ARCHITECT-PLANNER routing scope:backend tasks)."
UI-DEVELOPER: "UI implementation. Claims from feature_ui_dev/ (placed there by ARCHITECT-PLANNER routing scope:ui tasks), writes the implementation block, hands off to feature_test/."
LIVE-DEVELOPER: "Interactive, USER-paced developer for a single task on a leased stand (scenario C and ad-hoc live work). Claims from feature_live/, holds a stand lease and deploys to it during the session, chats live with the USER, and on USER approval hands to feature_review/ as a sprint task (REVIEWER no-regression review, no TESTER)."
TECHNICAL-WRITER: "Documentation implementation. Claims from feature_docs/ (placed there by ARCHITECT-PLANNER routing scope:docs tasks); hands off to feature_docs_review/."
TESTER: "Validates implemented features on a deployed stand. Acquires the stand by lease, probes once it is ready, and runs greatminds gate-check before mv to feature_review/."
READER: "Reads docs as a fresh user; validates clarity and accuracy; routes the result out of feature_docs_review/."
EXPLORER: "Uses the live system on the stand as a real user (scenario B), whatever the stand's shape. Files bugs as kind:bugfix tasks in feature_inbox/."
USER: "Writes user_feedback/ or initiates an ARCHITECT-PLANNER chat. Never creates implementation tasks directly."
MAINTAINER: "System operator, self-loop watchdog. Handles infrastructure the product pipeline cannot self-heal: agent restart, dead-pid recovery, greatminds CLI + schema.yaml maintenance, cutover orchestration. Receives asks at inbox/maintainer/ from coordd and from product agents when an issue is structural/schema rather than product. Sweeps PROACTIVELY every tick (an empty inbox is NOT 'nothing to do'): reclaims stale stand leases past TTL with a dead/absent holder, restarts dead agents and coordd, and escalates stalled task/queue chains to ARCHITECT-PLANNER. Does NOT claim product queues, triage user_feedback, or write plans."
lifecycles:
interactive: "Human-paced chat in a tmux pane; the USER drives each turn. coordd never runs its turns. The agent waits for USER input between turns — it does not self-schedule."
self-loop: "Runs its own loop in a tmux pane. After each tick it MUST re-arm its next wake (sleep / ScheduleWakeup) for roles.<ROLE>.self_loop_wake_seconds (default 3600s = 1h) so it ticks again on that cadence — a shorter delay is allowed ONLY while actively mid-recovery, then return to the configured cadence; the agent must NOT invent a faster interval. coordd may nudge it (tmux_send_keys) but never runs its turns."
driven: "No tmux pane; coordd runs each turn as a managed subprocess on queue / inbox / .stand events, holding the per-role run-lock for the full turn. Claude and Codex use stateful drivers; Cursor, Cline, Gemini, and OpenHands use one-shot headless subprocess drivers. The turn MUST return promptly — NEVER sleep / ScheduleWakeup / loop, or the run-lock never releases and the hang detector flags the turn."
wake_mechanisms:
tmux_send_keys: "Wake by typing WAKE_TEXT then Enter into the role's tmux pane. The only safe mechanism for interactive / self-loop roles (SIGINT to a live TUI is Ctrl-C → quit); also claude's default."
sigint_deepest_descendant: "Wake a loop agent blocked on a bash sleep by sending SIGINT to its deepest descendant (the sleep). Safe only when that descendant is not a live TUI — never for interactive / self-loop."
queue_kinds:
active: "Normal hand-off queue: the owner claims tasks and moves them out per the transitions table."
parking: "Holding queue for tasks waiting on explicit dependencies; re-activated by a wake-up, not claimed in the normal flow."
terminal: "End state (e.g. verified, archive); tasks are not moved out."
state: "Watch-only directory for a state / lease file, not tasks. coordd watches it to wake the owner on changes; nothing is claimed from it."
queues:
feature_inbox: "Unplanned product work and bug reports (from EXPLORER)."
feature_plan: "Planned product work; PLANNER reviews and routes by scope to feature_dev / feature_ui_dev / feature_docs."
feature_blocked: "Tasks parked on explicit dependencies; ARCHITECT-REVIEWER runs the wake-up."
feature_dev: "Backend implementation."
feature_ui_dev: "UI implementation."
feature_docs: "Documentation implementation."
feature_test: "Implemented code ready for TESTER validation on a deployed stand. Two entry paths: from an implementer queue (feature_dev / feature_ui_dev with an implementation block), or directly from feature_plan when plan.verify_only — a no-code stand/playbook verification task TESTER runs on a leased stand (no implementer step)."
feature_docs_review: "Docs ready for READER review."
feature_live: "Interactive single-task work for LIVE-DEVELOPER (routed by PLANNER when plan.interactive). The role leases a stand, works live with the USER, and hands to feature_review as a sprint task on USER approval."
feature_review: "Final review; ARCHITECT-REVIEWER approves or hands back."
verified: "Approved and committed product work."
archive: "Duplicate, abandoned, superseded, or triaged-away product work."
user_feedback: "Product feedback awaiting PLANNER triage."
review_sessions: "Scenario-B review sessions; EXPLORER iterates live-stand exploration and files bugs to feature_inbox."
.stand: "Singleton stand resource state.yaml + lease bookkeeping; coordd watches it and runs the deploy itself on lease lifecycle events."
stand_profiles:
full-deploy: "Full backend deployment on the target hosts with service health checks; scenarios A and B."
vite-dev: "Backend deployed plus a Vite UI dev server with HMR (UI changes reload, no per-change redeploy); scenario C."
smoke-only: "Fast reachability + CLI-responds probe — no rsync, no install. Warmup leases and post-deploy liveness checks."
stand_probes:
# Deploy/readiness checks (allowed) — GET / observe only.
docker_ps: "Container liveness via docker ps / docker compose ps."
http_health_get_200: "GET the health endpoint and require HTTP 200 — the one allowed status check."
ssh_reachable: "SSH reachability of the stand host plus a remote docker ps."
gpu_check: "GPU availability via nvidia-smi, when the profile requests it."
endpoint_presence: "Presence of an endpoint / bundle / bootstrap artifact — existence only, never exercising it."
get_only_route_status: "GET-only HTTP status on routes (e.g. 200 on SPA paths); no POST, no body validation."
# Forbidden for deploy/readiness — TESTER / EXPLORER territory.
any_post: "ANY POST to the product API — zero exceptions (auth, bootstrap, login, business endpoints all included). Readiness is GET / observe only."
response_body_validation: "Checking response body shape / fields / counts / status beyond the one allowed health 200."
acceptance_criteria: "Running acceptance / regression criteria (layer-1 pass, AC checks, dedup re-POST, error paths)."
followup_bug_filing: "Filing follow-up bugs / product gaps from readiness checks — triage is ARCHITECT-PLANNER's (note observations only)."
e2e_browser_flow: "Full end-to-end browser / Playwright product flows."
regression_scenario: "Regression scenarios that EXPLORER would run."
gate_check: "greatminds gate-check — TESTER-only; reads TESTER's tests-block lease evidence."
intake_disciplines:
propose_then_file: "Present design / options / scope in chat first; WAIT for an explicit USER approval marker (ok / yes / file / go / do it, or a chosen option) before any FSM mutation (task new / plan / mv). Read-only ops (inbox list, queue inspection, gate-check) need no approval. Exception: a standing USER instruction that explicitly authorizes auto-filing within a scope."
# ---------------------------------------------------------------------------
# Queues
#
# Each queue is a directory under .greatminds/. Field meanings:
#
# owner — role responsible for the queue's content AND the single
# role that claims from it (moves files out). Location =
# ownership; content fields (scope, etc.) never determine
# ownership.
# writers — roles allowed to write into the queue (own files + add
# blocks to files they own).
# kind — a glossary.queue_kinds token (active / parking /
# terminal / state).
#
# Authoritative source for OUTGOING moves is the `transitions:` table
# (the `by:` field there names the role allowed to perform each move).
# ---------------------------------------------------------------------------
# Per-queue purpose lives in glossary.queues; `kind` values in
# glossary.queue_kinds. Entries below are pure structure.
queues:
feature_inbox:
owner: ARCHITECT-PLANNER
writers: [ARCHITECT-PLANNER, EXPLORER]
kind: active
feature_plan:
owner: ARCHITECT-PLANNER
writers: [ARCHITECT-PLANNER]
kind: active
feature_blocked:
owner: ARCHITECT-REVIEWER
writers: [DEVELOPER, UI-DEVELOPER, TECHNICAL-WRITER, TESTER, READER, ARCHITECT-REVIEWER, ARCHITECT-PLANNER]
kind: parking
feature_dev:
owner: DEVELOPER
writers: [DEVELOPER]
kind: active
feature_ui_dev:
owner: UI-DEVELOPER
writers: [UI-DEVELOPER]
kind: active
feature_docs:
owner: TECHNICAL-WRITER
writers: [TECHNICAL-WRITER]
kind: active
feature_test:
owner: TESTER
writers: [DEVELOPER, UI-DEVELOPER, TESTER]
kind: active
feature_docs_review:
owner: READER
writers: [TECHNICAL-WRITER, READER]
kind: active
feature_live:
owner: LIVE-DEVELOPER
writers: [LIVE-DEVELOPER, ARCHITECT-PLANNER]
kind: active
feature_review:
owner: ARCHITECT-REVIEWER
writers: [TESTER, READER, LIVE-DEVELOPER, ARCHITECT-REVIEWER]
kind: active
verified:
owner: ARCHITECT-REVIEWER
writers: [ARCHITECT-REVIEWER]
kind: terminal
archive:
owner: ARCHITECT-PLANNER
writers: [ARCHITECT-PLANNER, ARCHITECT-REVIEWER]
kind: terminal
user_feedback:
owner: ARCHITECT-PLANNER
writers: [USER]
kind: active
review_sessions:
owner: EXPLORER
writers: [ARCHITECT-PLANNER, EXPLORER]
kind: active
# .stand is a state-kind watch path, NOT a claim-from queue. coordd
# watches state.yaml and runs the deploy itself on a `preparing` lease.
.stand:
writers: [TESTER, ARCHITECT-PLANNER, MAINTAINER, LIVE-DEVELOPER, EXPLORER, ARCHITECT-REVIEWER]
kind: state
# ---------------------------------------------------------------------------
# Roles
#
# Each role lists its category, lifecycle, and the queues it may claim
# from. `lifecycle` is a glossary.lifecycles token (how the agent is
# driven); launch mechanics = f(lifecycle, coord.yaml tool).
# ---------------------------------------------------------------------------
# Per-role machine-readable contracts.
#
# Each role declares:
# - responsibilities: list[str] — high-level duties.
# - forbidden_actions: list[str] — things the role MUST NOT do.
# - event_triggers: map[event → list[step_name]]
# — ordered steps the role takes
# on each event.
#
# The keys are intentionally short identifiers (snake_case verbs);
# they don't carry executable semantics — they're a checklist the
# LLM-driven agents follow + a regression-net against role drift.
# Step IDs that match CLI commands (``stand lease``,
# ``greatminds task mv``, etc.) hint at the runtime path; arbitrary
# verbs (``probe_via_ssh``) describe the logical step the LLM owns.
roles:
ARCHITECT-PLANNER:
category: product
# lifecycle: a glossary.lifecycles token (orthogonal to coord.yaml's
# `tool`; launch mechanics = f(lifecycle, tool)).
lifecycle: interactive
claims_from: [user_feedback, feature_inbox, feature_plan]
# USER-interaction discipline (def: glossary.intake_disciplines).
intake_discipline: propose_then_file
responsibilities:
- triage_user_feedback
- write_plan_blocks
- route_tasks_per_scope
- chat_partner_for_user
- file_review_sessions
# PLANNER must know the stand-profile mechanism out of the box.
- coordinate_stand_profile_tasks_via_registry_and_canon
- file_profile_registry_task_on_unregistered_profile
forbidden_actions:
- implement_code
- run_ansible
- mark_stand_ready
- claim_review_sessions
# Exception: a scope:release UMBRELLA already decomposed into its
# implementer sub-task(s) MAY be closed to archive — it is a tracking
# gate, not in-flight work. Otherwise a release umbrella dead-ends in
# feature_plan (no implementer route AND no close path).
- archive_in_lifecycle_work_directly_except_decomposed_release_umbrella
event_triggers:
on_user_feedback_claim:
- read_user_feedback_block
- append_triage_block
- mv_user_feedback_to_feature_inbox_or_archive
on_feature_inbox_claim:
- append_triage_block
- mv_to_feature_plan_or_archive
on_feature_plan_claim:
- write_plan_block
- set_stand_required
- route_to_feature_dev_or_feature_ui_dev_or_feature_docs
# scope:release is an umbrella GATE, not implementer work — there is
# no single implementer queue for it. Decompose it into the concrete
# implementer sub-task(s) that perform the release (packaging / smoke
# / push), then close the umbrella to archive once its children are
# verified. Without this a scope:release task parks forever in
# feature_plan with no route and no close path.
- decompose_scope_release_umbrella_into_subtasks_then_archive_umbrella
# stand_down classifiers — PLANNER reads coordd's auto-notification
# and routes the fix per the down_reason signature.
on_stand_down_yaml_playbook_error:
- read_down_reason_from_inbox_info
- file_bugfix_task_for_coordination_stand_profiles_yaml
- assign_to_developer
on_stand_unregistered_profile:
- read_registry_error
- file_feature_dev_task_for_stand_profile_registry_entry
- include_required_profile_name_file_used_for_default_for
ARCHITECT-REVIEWER:
category: product
lifecycle: driven
claims_from: [feature_review, feature_blocked]
responsibilities:
- verify_evidence_chain
- commit_and_merge
- resume_blocked_tasks_via_wake_check
- rollback_verified_tasks
forbidden_actions:
- implement_code
- claim_outside_review_queues
- approve_without_gate_check_pass_when_stand_required
event_triggers:
on_feature_review_claim:
- verify_blocks_chain
- run_gate_check
- append_review_block_approved_or_changes_requested
- mv_to_verified_on_approved
- mv_back_to_implementer_queue_on_changes_requested
on_feature_blocked_claim:
- run_wake_check
- mv_to_resume_to_queue_when_dependencies_satisfied
- archive_when_withdrawn_reason_present
on_verified_rollback:
- append_rollback_block_with_reason
- mv_to_archive_or_feature_review
stand_profile_selection:
required_for:
- final_review_when_stand_required
- production_review
default_for:
final_review_when_stand_required: reviewer
production_review: production_review
allowed_used_for:
- reviewer_validation
- tester_validation
- explorer_review
- production_post_deploy_review
must_select_from: coordination/stand-profiles.yaml
DEVELOPER:
category: product
lifecycle: driven
claims_from: [feature_dev]
responsibilities:
- implement_backend_features
- write_unit_tests
- file_implementation_block_with_files_list
forbidden_actions:
- claim_ui_or_docs_or_stand_tasks
- deploy_stand
- run_product_validation_on_stand
- read_or_move_from_feature_plan
- commit_to_main_directly
event_triggers:
on_feature_dev_claim:
- implement_code_in_worktree
- run_pytest_suite
- append_implementation_block
- mv_to_feature_test
UI-DEVELOPER:
category: product
lifecycle: driven
claims_from: [feature_ui_dev]
responsibilities:
- implement_ui_features
- run_ui_tests
- file_implementation_block
forbidden_actions:
- claim_backend_or_docs_tasks
- deploy_stand
- commit_to_main_directly
event_triggers:
on_feature_ui_dev_claim:
- implement_ui_in_worktree
- run_ui_test_suite
- append_implementation_block
- mv_to_feature_test
LIVE-DEVELOPER:
category: product
# Interactive, USER-paced: works a single task live with the USER on
# a leased stand. As the lease HOLDER it may deploy to its own stand
# during the session (deploy_to_own_leased_stand_during_session) —
# the only relaxation of centralized deploy ownership, scoped to
# an active interactive lease. On USER "ok" it hands to feature_review
# as a sprint task (REVIEWER does a no-regression review, outcome
# approved_sprint; TESTER is skipped — the USER was the live validator).
lifecycle: interactive
claims_from: [feature_live]
responsibilities:
- work_a_single_task_live_with_user_on_leased_stand
- deploy_to_own_leased_stand_during_session
- hand_to_review_as_sprint_on_user_ok
# Scenario-C is cross-scope live work: once PLANNER routed an
# interactive task to feature_live, LIVE-DEVELOPER owns the live
# implementation evidence for backend/ui changes on that leased stand.
- append_implementation_block_for_interactive_backend_or_ui_task
forbidden_actions:
- claim_outside_feature_live
- commit_to_main_directly
- skip_sprint_review
event_triggers:
on_feature_live_claim:
- create_worktree
- acquire_lease_via_stand_lease
- deploy_to_own_leased_stand_during_session
- interactive_chat_with_user
- on_user_ok_append_implementation_block
- release_lease
- mv_to_feature_review
stand_profile_selection:
required_for:
- feature_live
default_for:
feature_live: live_developer
allowed_used_for:
- live_ui
- ui_iteration
must_select_from: coordination/stand-profiles.yaml
TECHNICAL-WRITER:
category: product
lifecycle: driven
claims_from: [feature_docs]
responsibilities:
- write_documentation
- file_implementation_block
forbidden_actions:
- claim_backend_or_ui_tasks
- commit_to_main_directly
event_triggers:
on_feature_docs_claim:
- write_docs_in_worktree
- run_docs_build_if_configured
- append_implementation_block
- mv_to_feature_docs_review
TESTER:
category: product
lifecycle: driven
claims_from: [feature_test]
responsibilities:
- probe_feature_on_deployed_stand
- fill_real_stand_evidence
- run_gate_check_before_mv
forbidden_actions:
- deploy_stand
- run_ansible_locally
- fill_fake_stand_evidence
- claim_outside_feature_test
# TESTER's only execution surface is SSH probes against the
# DEPLOYED stand — never a local test run. `uv run`/`uv run
# --active` from a worktree syncs it into the active fleet environment,
# dangling its editable .pth on worktree prune →
# fleet-wide ModuleNotFoundError. Evidence is stand-probe only.
- run_local_tests
- uv_run_or_active_against_fleet_venv
event_triggers:
on_feature_test_claim:
- acquire_lease_via_stand_lease
- wait_for_state_ready
- probe_via_ssh_using_project_env_host
- fill_tests_block_with_real_observed_output
- run_gate_check
- release_lease_with_result
- mv_to_feature_review
stand_profile_selection:
required_for:
- plan.stand_required
- plan.verify_only
default_for:
plan.stand_required: feature_test
plan.verify_only: verify_only
allowed_used_for:
- tester_validation
- deploy_only
- warmup
- quick_readiness
must_select_from: coordination/stand-profiles.yaml
READER:
category: product
lifecycle: driven
claims_from: [feature_docs_review]
responsibilities:
- validate_doc_clarity_as_fresh_user
- append_reader_review_block
forbidden_actions:
- claim_implementer_queues
- write_code
event_triggers:
on_feature_docs_review_claim:
- read_docs_fresh_no_prior_context
- append_reader_review_block
- mv_to_feature_review_on_pass
- mv_back_to_feature_docs_on_fail_or_partial
# Audit-only tasks have no WRITER plan to bounce back to —
# always route them to feature_review, never to feature_docs.
- route_audit_only_to_feature_review_never_feature_docs
EXPLORER:
category: product
lifecycle: driven
claims_from: [review_sessions]
# STAND-ANCHOR (absolute). EXPLORER ALWAYS works ON the stand
# as a real user, WHATEVER the stand's shape — the access method
# follows the product (HTTP/browser for a web app, SSH for a host,
# or wherever the software is deployed); host-destructive/recovery
# scenarios are EXPLORER's own on the disposable stand. EXPLORER is
# strictly forbidden from validating off-stand / local substitutes.
responsibilities:
- run_review_sessions_on_live_stand
- operate_on_the_stand_as_real_user_whatever_its_shape
- file_bugs_to_feature_inbox
forbidden_actions:
- implement_code
- deploy_stand
- claim_outside_review_sessions
- validate_off_stand_or_local_substitutes
event_triggers:
on_review_sessions_claim:
- acquire_lease_via_stand_lease
- run_scenarios_against_deployed_stand
- file_bugs_as_feature_inbox_tasks
- append_session_iteration_block
- release_lease
- mv_to_archive_when_complete
stand_profile_selection:
required_for:
- review_session
default_for:
review_session: explorer
allowed_used_for:
- explorer_review
- full_product_validation
must_select_from: coordination/stand-profiles.yaml
USER:
category: entry
# USER is the human entry point — interactive by definition.
lifecycle: interactive
claims_from: []
responsibilities:
- file_user_feedback
- chat_with_planner
forbidden_actions:
- claim_any_queue
- implement_code
- write_blocks_directly_to_active_queues
event_triggers: {}
MAINTAINER:
category: system
# MAINTAINER is self-loop — it wakes itself to drain its inbox +
# run recovery (no queue-claim, USER-absent operation). It
# self-paces a recovery tick; it is not a human-paced chat seat.
lifecycle: self-loop
# Self-loop cadence (seconds). The recovery watchdog ticks HOURLY —
# it is not a busy-poll. Pinned here because the agent otherwise
# defaults to its own ~5-min loop; the cadence must live in canon so
# it survives fresh sessions and re-bootstraps. A shorter delay is
# allowed ONLY while actively mid-recovery, then return to this.
self_loop_wake_seconds: 3600
claims_from: []
responsibilities:
- agent_restart
- dead_pid_recovery
- schema_yaml_maintenance
- cutover_orchestration
- infra_chat_for_user
# proactive watchdog sweep each self-loop tick (not reactive-only)
- proactive_stall_sweep
forbidden_actions:
- claim_product_queues
- triage_user_feedback
- write_plan_blocks
event_triggers:
on_inbox_dead_pid_ask:
- diagnose_pid_state
- restart_agent_via_greatminds_restart
on_inbox_stand_blocked_ask:
- escalate_or_diagnose_infra
on_release_cut_ask:
- run_release_pipeline
# the self-loop tick itself is a trigger — proactively sweep
# every tick, before idling, even with an empty inbox.
on_self_loop_tick:
- reclaim_stale_stand_lease_past_ttl_with_dead_holder
- restart_dead_agents_and_coordd_via_greatminds_restart
- escalate_stalled_or_stuck_chains_to_planner_via_inbox
# ---------------------------------------------------------------------------
# Transitions
#
# Allowed file moves between queues. The `by` field names the only role
# permitted to perform the move. `requires` lists evidence that must be
# present in the task file (front-matter fields or appended blocks) before
# the move is legal.
# ---------------------------------------------------------------------------
transitions:
# `requires:` is LOAD-BEARING. Each name must have a
# registered validator in cli/task.py SCHEMA_REQUIRES_VALIDATORS;
# unknown names raise an error at mv time (no silent documentary
# keys). The validators run AFTER can_role_move and after the
# existing require_target_readiness path — they're additive, not a
# replacement, so adding a new require name today does not need to
# retire the existing hardcoded check for it.
#
# The hardcoded checks in require_target_readiness still handle
# block-presence + ready_for_* flags for the standard block kinds
# (triage, plan, implementation, tests, reader_review) — the
# registry maps those names to no-op validators that just record
# them as known. The names that get REAL enforcement at the
# registry layer:
# - gate_check_pass_if_stand_required (re-runs the gate-check
# evaluation; TESTER cannot bypass by writing pass into the
# field manually).
- from: user_feedback
to: feature_inbox
by: ARCHITECT-PLANNER
requires: [triage_block]
- from: user_feedback
to: archive
by: ARCHITECT-PLANNER
requires: [triage_block]
# PLANNER may archive any task in its own intake/draft area when USER
# decides not to pursue it (split, duplicate, superseded, withdrawn).
- from: feature_inbox
to: archive
by: ARCHITECT-PLANNER
requires: []
- from: feature_plan
to: archive
by: ARCHITECT-PLANNER
requires: []
# review_sessions archive requires terminal-state evidence
# (at least one session_iteration block, or a blocked block whose
# reason names "withdrawn"/"abandoned"/"superseded"). Prevents a
# single role silently wiping an empty or in-progress session.
- from: review_sessions
to: archive
by: ARCHITECT-PLANNER
requires: [review_session_terminal_block]
# F: EXPLORER may self-close its own review session when the review
# campaign is complete (instead of only signalling PLANNER via inbox).
- from: review_sessions
to: archive
by: EXPLORER
requires: [review_session_terminal_block]
# Withdrawal path for in-lifecycle work: PLANNER may NOT
# archive directly from per-scope implementer queues — that silently
# discards already-written impl/tests/review blocks. The canonical
# withdraw path is:
# 1. PLANNER appends a `blocked` block with reason "withdrawn" and
# a sentinel `dependencies` that wake-check will never satisfy.
# 2. PLANNER mv → feature_blocked.
# 3. ARCHITECT-REVIEWER archives from feature_blocked (the existing
# feature_blocked → archive transition by ARCHITECT-REVIEWER).
# Two roles must agree to terminate in-flight work, never one.
# REVIEWER may archive blocked tasks that USER decides not to unblock
# (dependency was retracted, task was superseded, etc).
# Latest blocked.reason must name a withdrawn-class token; refuses
# single-role wipe of waiting-but-recoverable work.
- from: feature_blocked
to: archive
by: ARCHITECT-REVIEWER
requires: [feature_blocked_withdrawn_reason]
# The lease-based stand model has no terminal-queue transition —
# release evidence lands on the product task's tests block directly.
# Entering feature_plan needs a triage block (the plan block is
# written IN feature_plan, then it routes OUT to a per-scope queue).
- from: feature_inbox
to: feature_plan
by: ARCHITECT-PLANNER
requires: [triage_block]
# ARCHITECT-PLANNER routes from feature_plan into per-scope queues.
# Location = ownership: once in feature_dev/ it is DEVELOPER's; once
# in feature_ui_dev/ it is UI-DEVELOPER's; once in feature_docs/ it
# is TECHNICAL-WRITER's. No claim_filter, no content lookup.
- from: feature_plan
to: feature_dev
by: ARCHITECT-PLANNER
requires: [plan_block, scope_backend]
- from: feature_plan
to: feature_ui_dev
by: ARCHITECT-PLANNER
requires: [plan_block, scope_ui]
- from: feature_plan
to: feature_docs
by: ARCHITECT-PLANNER
requires: [plan_block, scope_docs]
# Independent READER audit: a `kind: docs` task marked audit-only
# (plan.audit_only: true) is routed straight to READER's queue, with
# NO prior TECHNICAL-WRITER write. READER audits reality-vs-docs and
# records findings in a reader_review block; the audit then flows the
# normal feature_docs_review exits (→ feature_review, or back so
# PLANNER spawns a WRITER fix task from the findings).
- from: feature_plan
to: feature_docs_review
by: ARCHITECT-PLANNER
requires: [plan_block, scope_docs, plan.audit_only]
# Interactive single-task work: a plan marked plan.interactive: true is
# routed to LIVE-DEVELOPER's queue regardless of scope (backend or ui).
- from: feature_plan
to: feature_live
by: ARCHITECT-PLANNER
requires: [plan_block, plan.interactive]
# No-code stand/playbook verification: a plan marked plan.verify_only:
# true has NO implementer step — PLANNER routes it straight to TESTER,
# who leases a stand, runs the playbook/probe, and records real stand
# evidence on a tests block, then advances via the normal feature_test
# → feature_review → verified path. Mirrors the audit_only feature_docs
# _review path (skip the implementer, go straight to the verifier).
- from: feature_plan
to: feature_test
by: ARCHITECT-PLANNER
requires: [plan_block, plan.verify_only]
- from: feature_dev
to: feature_test
by: DEVELOPER
requires: [implementation_block]
- from: feature_ui_dev
to: feature_test
by: UI-DEVELOPER
requires: [implementation_block]
- from: feature_docs
to: feature_docs_review
by: TECHNICAL-WRITER
requires: [implementation_block]
# LIVE-DEVELOPER hands the USER-approved sprint task to review (no
# TESTER step). The verified gate accepts review outcome approved_sprint
# and the sprint review satisfies gate_check_pass_if_stand_required.
- from: feature_live
to: feature_review
by: LIVE-DEVELOPER
requires: [implementation_block]
- from: feature_test
to: feature_review
by: TESTER
requires: [tests_block, gate_check_pass_if_stand_required]
- from: feature_test
to: feature_dev
by: TESTER
requires: [tests_block_fail_or_partial, scope_backend]
- from: feature_test
to: feature_ui_dev
by: TESTER
requires: [tests_block_fail_or_partial, scope_ui]
- from: feature_docs_review
to: feature_review
by: READER
requires: [reader_block_pass]
- from: feature_docs_review
to: feature_docs
by: READER
requires: [reader_block_fail_or_partial]
- from: feature_review
to: verified
by: ARCHITECT-REVIEWER
requires: [review_block_approved, gate_check_pass_if_stand_required]
- from: feature_review
to: feature_dev
by: ARCHITECT-REVIEWER
requires: [review_block_changes_requested, scope_backend]
- from: feature_review
to: feature_ui_dev
by: ARCHITECT-REVIEWER
requires: [review_block_changes_requested, scope_ui]
- from: feature_review
to: feature_docs
by: ARCHITECT-REVIEWER
requires: [review_block_changes_requested, scope_docs]
- from: any_active_queue
to: feature_blocked
by: current_owner
requires: [blocked_block_with_dependencies_and_resume_to]
# User-requested cancellation / withdrawal path. PLANNER may park
# in-lifecycle work only with a withdrawn-class blocked.reason; REVIEWER
# remains the only role that can archive it from feature_blocked.
- from: any_active_queue
to: feature_blocked
by: ARCHITECT-PLANNER
requires: [blocked_block_withdrawn_reason_and_resume_to]
- from: feature_blocked
to: any_resume_to_queue
by: ARCHITECT-REVIEWER
requires: [all_dependencies_exist_per_wake_check]
# Stand state transitions happen on the singleton stand resource via
# the lease API (greatminds stand lease/ready/release/down/up) — see
# schema.stand.resource.transitions, not this product-task table.
# Rollback paths from verified/. Two destinations:
# - archive — "withdraw" (the verified work has been reverted
# at code level; FSM record now matches reality)
# - feature_review — "revisit" (REVIEWER decides verified work
# needs further amendment; bounce back for fix)
# Both gated on a rollback block with non-empty reason — operators
# must record WHY before the FSM exits verified.
- from: verified
to: archive
by: ARCHITECT-REVIEWER
requires: [rollback_block_with_reason]
- from: verified
to: feature_review
by: ARCHITECT-REVIEWER
requires: [rollback_block_with_reason]
# ---------------------------------------------------------------------------
# Task front-matter requirements
#
# Required fields when a task enters a given state (queue). Schema validators
# may read this to lint task files. Inline `*_TEMPLATE.md` snippets in
# templates/coordination/<queue>/_TEMPLATE.md show concrete YAML shape.
# ---------------------------------------------------------------------------
task_kinds:
product:
required_initial_fields:
- id
- stream # product
- kind # feature | bugfix | docs | ops | research
- scope # backend | ui | docs | stand | research
- reporter
- opened_at
- priority
- title
plan_block_required_fields:
- written_by
- written_at
- base_commit
- assignee_role
- stand_required # true | false
- stand_reason
- plan_kind # full | bugfix (new in this refactor)
- mode # A | B | C (new in this refactor)
- ready_for_implementation
implementation_block_required_fields:
- closed_by
- closed_at
- base_commit
- files
- ready_for_test
tests_block_required_fields:
- closed_by
- closed_at
- base_commit
- test_files
- test_command
- test_result
- stand_evidence
- gate_check_result # new: pass | fail | missing | n/a
- gate_check_at # new: ISO timestamp of greatminds gate-check run
- gate_check_commit # new: commit checked against stand evidence
- ready_for_review
reader_block_required_fields:
- reviewed_by
- reviewed_at
- outcome
- docs_checked
- stand_checked
- command_or_flow
- ready_for_architect
review_block_required_fields:
- reviewed_by
- reviewed_at
- outcome
- commit
blocked_block_required_fields:
- blocked_by
- blocked_at
- reason
- dependencies # list of "<queue>/<task-id>.md"
- resume_to # queue name from this schema
# There is no stand task-kind: the singleton stand resource is
# lease-based, not a per-request task file — see schema.stand.resource.
review_session:
required_initial_fields:
- id
- stream # review_session
- opened_by
- opened_at
- target_functionality
- scenarios # list of exploration scenarios
- stand_target # host/profile/commit expected
- mode # B (scenario B)
# ---------------------------------------------------------------------------
# Scenarios
#
# Three top-level modes of operation. Each task carries `plan.mode: A|B|C`.
# Scenarios are described in prose in COORDINATE.md §6; here only the
# machine-readable mapping to roles and queues.
# ---------------------------------------------------------------------------
scenarios:
A:
label: feature_or_refactor
active_roles: [ARCHITECT-PLANNER, ARCHITECT-REVIEWER, DEVELOPER, UI-DEVELOPER, TECHNICAL-WRITER, TESTER, READER]
stand_profile: full-deploy
B:
label: intensive_review
active_roles: [ARCHITECT-PLANNER, ARCHITECT-REVIEWER, EXPLORER, DEVELOPER, UI-DEVELOPER, TESTER]
stand_profile: full-deploy
C:
label: ui_rapid_iteration
active_roles: [LIVE-DEVELOPER]
stand_profile: vite-dev
# ---------------------------------------------------------------------------
# Runtime access
#
# Hard rule for EVERY role (incl. ARCHITECT-PLANNER): mutation and queue
# inspection for .greatminds/ runtime state is ONLY via the greatminds CLI;
# raw ls/cat/grep/sed/edit on runtime queues/inbox/stand state is forbidden.
# Why: a raw relative path breaks from a per-task worktree cwd; the CLI
# resolves the project root regardless of cwd;
# and a direct task-yaml edit bypasses FSM validation. Every agent
# reads this rule from canon at tick start (machine-readable, no prose).
# ---------------------------------------------------------------------------
runtime_access:
cli_only: true
rule: runtime_access_via_greatminds_cli_only
forbidden:
- raw_ls_cat_grep_sed_edit_on_runtime_state
surfaces:
- greatminds inbox list|show|ack|send
- greatminds task list|show|mv|append-block
- greatminds stand status
# ---------------------------------------------------------------------------
# Heartbeat — in-flight-turn hang detection (driven model)
#
# heartbeat is NOT a periodic liveness signal. Between turns a driven
# pane is idle bash — that is normal, not "stale". heartbeat matters in
# exactly one situation: coordd dispatched a turn to an agent and holds
# that role's run-lock. The agent touches .greatminds/heartbeat.<role>
# as a side effect of every greatminds CLI call, so a progressing turn
# keeps it fresh. If a turn is in-flight (run-lock held) AND the
# heartbeat has not advanced for `hang_threshold_seconds`, the turn is
# hung: coordd escalates to MAINTAINER (it does NOT kill or re-drive —
# MAINTAINER decides). When no turn is in-flight, heartbeat age is
# ignored. Liveness of a persistent process is the dead-pid registry
# scan, not heartbeat.
# ---------------------------------------------------------------------------
heartbeat:
hang_threshold_seconds: 300 # in-flight turn with no heartbeat progress → escalate MAINTAINER
# ---------------------------------------------------------------------------
# Watchdog thresholds
#
# Read by greatminds watchdog. Times in seconds.
# ---------------------------------------------------------------------------
watchdog:
intent_orphan_seconds: 300 # 5 min
task_stale_in_active_queue_seconds: 86400 # 24 h
task_stale_in_review_queue_seconds: 43200 # 12 h
# ---------------------------------------------------------------------------
# Inbox
#
# Inter-role messaging via per-role inbox/<role>/ mailboxes.
# `allowed_kinds` is the closed set of message kinds the inbox CLI accepts;
# any other value is rejected at send time. Mirrored in COORDINATE.md §10.
# ---------------------------------------------------------------------------
inbox:
allowed_kinds: [wake, ask, info]
# Per-role message inbox: coordd and other roles message YOU here
# (wakes, asks, infos). Read it FIRST every tick. It is NOT a task
# queue — `greatminds task list inbox` is wrong (no such queue).
dir: ".greatminds/inbox/${GREATMINDS_ROLE}/"
read: "greatminds inbox list" # role from $GREATMINDS_ROLE
show: "greatminds inbox show <path>"
ack: "greatminds inbox ack <path>" # after acting on the message
check_when: "first each tick (wake text: 'check inbox and continue your tick')"
# ---------------------------------------------------------------------------
# Git permissions
#
# Closed set of roles that may run `git commit` / `git push` in this
# project. Enforced by a pre-commit hook (installed by `greatminds setup`)
# that calls `greatminds check-git-permission commit` and exits non-zero
# when $GREATMINDS_ROLE is not in the allowed list. Forbidden verbs are
# `git` subcommands the project never wants any agent to use (force
# operations, history rewrites).
# ---------------------------------------------------------------------------
git_permissions:
commit: [ARCHITECT-REVIEWER]
push: [ARCHITECT-REVIEWER]
forbidden_verbs:
- reset
- restore
- checkout
- stash
- rebase
- revert
- branch
- tag
# ---------------------------------------------------------------------------
# Tests block — required-field validation for stand_required tasks
#
# When plan.stand_required is true, the appended tests block MUST contain a
# stand_evidence mapping with the subfields below. Enforced by
# require_block_cross_state in cli/task.py at append-block time and rechecked
# by gate-check during feature_test → feature_review / feature_review →
# verified transitions.
# ---------------------------------------------------------------------------
# Systemic commit-drift fix. The lease deploy path uses the active lease's
# source worktree / task evidence, not whatever main HEAD happens to be at
# deploy time. gate-check compares tests.stand_evidence.commit with the
# task's implementation/plan commit, and compares worktree_fingerprint when
# both sides carry one.
#
# Pairs with worktree_fingerprint: the committed-state identity covers
# what was deployed, the uncommitted-overlay identity covers the
# worktree. Either passing proves «stand tested what impl describes».
stand:
deploy_strategy:
target_commit_resolution: evidence_for_impl_base_commit
post_stand_main_revert: true
# Stand resource state machine. Singleton resource per project;
# FIFO lease queue; token-gated access.
resource:
states: [free, preparing, ready, down]
transitions:
- from: free
to: preparing
by: COORDD
requires: [active_lease_set]
- from: preparing
to: ready
by: COORDD
requires: [deploy_smoke_ok]
- from: preparing
to: down
by: COORDD
requires: [deploy_failure_logged]
- from: ready
to: free
by: lease_holder_or_coordd_auto
- from: ready
to: down
by: COORDD
requires: [infra_incident_logged]
- from: down
to: free
by: COORDD
requires: [recovery_logged]
lease:
ttl_seconds_default: 14400 # 4h
ttl_warn_window_seconds: 300 # 5min warn before auto-release
auto_release_on_no_response: true
# Worktree-path constraint. Stand deploys MUST come from a
# per-task isolated branch checkout under .worktrees/<seq>; the
# main fleet tree would self-modify the running host (the very
# processes we're deploying). The CLI validates the worktree
# path at acquire-time so a wrong path never reaches state.yaml
# and never leaves TESTER's lease orphaned in preparing/.
worktree_constraint:
pattern: "{project_dir}/.worktrees/{seq}[-<slug>]"
description: |
Resolved worktree path's parent dir must be
``<project_dir>/.worktrees`` AND its basename must equal the
task's seq prefix or start with ``<seq>-`` (the slug variant
``git worktree add`` produces by default). The CLI rejects
any other path — including the project_dir itself — with
exit_code=2 + a message naming the correct path.
enforced_by: cli
queue: fifo
access_control:
operations:
- stand_probe_*: requires holder of active_lease's lease_id
enforcement_layer: cli
state_file: .stand/state.yaml # under .greatminds/
# Profile names are project-defined in coordination/stand-profiles.yaml.
# The lease CLI accepts a profile only when the registry contains that
# profile and the referenced YAML playbook exists.
tests_block_validation:
stand_evidence:
# Aligned with what gate_check.extract_lease_evidence_from_tests
# actually validates: the three free-form prose fields below PLUS
# ``lease_id`` (from the release flow). If lease_id is absent,
# gate-check returns ``missing`` at the mv-to-feature_review gate.
required_subfields:
# Free-form prose (TESTER writes during the lease cycle).
- reproduction_steps
- observed_without_fix
- observed_with_fix
# Lease-release evidence (lease_id is the gate's hard
# requirement; ``result`` and ``commit`` are derived with
# fallbacks but listed here for the contract surface).
- lease_id
- result
- commit
required_when: plan.stand_required
# TESTER must run own functional probes against the
# prepared stand. Deploy/readiness observed_with_fix is infra-
# readiness only (UP, version, /health 200). TESTER's
# functional_probes + tester_observations are TESTER's own
# behavior verification, distinct from readiness checks.
required_for_scopes:
backend:
- functional_probes
- stand_evidence.tester_observations
ui:
- functional_probes
- stand_evidence.tester_observations
exempt_scopes:
- docs # READER review covers docs
- research
# ---------------------------------------------------------------------------
# Filesystem layout
#
# Paths relative to <COORDINATION_DIR>. Used by the unified `greatminds` CLI
# and daemon to locate artifacts.
# ---------------------------------------------------------------------------
layout:
journal: journal.ndjson
intent_dir: intent/
inbox_dir: inbox/
stand_status: stand.status
# ---------------------------------------------------------------------------
# Event-wake dispatch table
#
# coord.yaml's ``tool:`` field per window selects which wake mechanism
# coordd uses for that role on inbox/queue events. Chat-mode (claude)
# roles are woken via the tmux-send-keys mechanism that injects a
# literal keystroke + Enter into the chat-mode pane, identical to
# operator-typed input.
#
# Mechanisms live as functions in cli/coordd.py
# (sigint_sleeping_descendant, tmux_send_keys_wake). This table maps
# tool → mechanism name; the dispatcher picks the function by name.
# ---------------------------------------------------------------------------
event_wake:
# Default wake mechanism per tool (token defs: glossary.wake_mechanisms).
# LIFECYCLE WINS: interactive / self-loop roles always use tmux_send_keys
# regardless of tool — enforced by coordd._wake_mechanism_for_tool.
by_tool:
codex: sigint_deepest_descendant
cursor: sigint_deepest_descendant
claude: tmux_send_keys
cline: tmux_send_keys
gemini: tmux_send_keys
openhands: tmux_send_keys
tmux_send_keys:
keys: "check inbox and continue your tick"
enter: true
rate_limit_seconds: 5
# ---------------------------------------------------------------------------
# FSM single-source-of-truth tables.
#
# These tables are the DATA the FSM runs on (stream block kinds,
# block-kind roles, queue block kinds, impl role by scope, product
# kinds/scopes/priorities, plan kinds, modes, stand enums, test
# results, gate-check results, review/reader outcomes). cli/task.py
# loads + reads them at module-import.
# Validator FUNCTION bodies stay in code (registered by name in the
# transitions[*].requires lists). Adding a new block_kind / scope /
# enum value becomes a schema-only edit — no code change needed for
# the data parts.
# ---------------------------------------------------------------------------
# Streams = top-level task categories. Each declares which block kinds
# its tasks may carry + which header fields are required.
streams:
product:
allowed_block_kinds:
[triage, plan, implementation, tests, reader_review, review, blocked, rollback]
intake_queues: [feature_inbox, user_feedback]
# There is no stand stream: the singleton stand resource is
# lease-based (schema.stand.resource), not a task stream.
review_session:
allowed_block_kinds: [session_iteration, blocked]
intake_queues: [review_sessions]
# Block kinds. Each declares which roles may author it + per-block
# enum constraints. `blocked` is special-cased in code (current owner
# of the queue is the only allowed author) and intentionally omits
# `authored_by` here.
block_kinds:
triage:
authored_by: [ARCHITECT-PLANNER]
plan:
authored_by: [ARCHITECT-PLANNER]
implementation:
authored_by: [DEVELOPER, UI-DEVELOPER, TECHNICAL-WRITER, LIVE-DEVELOPER]
tests:
authored_by: [TESTER]
allowed_test_results: [pass, fail, partial]
allowed_gate_check_results: [pass, fail, missing, "n/a"]
reader_review:
authored_by: [READER]
allowed_outcomes: [pass, fail, partial]
review:
authored_by: [ARCHITECT-REVIEWER]
# approved_sprint: the light no-regression approval for a LIVE-DEVELOPER
# sprint task (USER already validated it live; REVIEWER only checks it
# broke nothing external). Treated as an approve → verified.
allowed_outcomes: [approved, approved_sprint, changes_requested]
stand_result:
authored_by: [COORDD]
allowed_results: [ok, partial, fail]
allowed_statuses: [READY, DEGRADED, DOWN, BLOCKED]
session_iteration:
authored_by: [EXPLORER]
blocked:
# author = current owner of the queue, resolved at runtime
# rollback block — REVIEWER's withdraw/revisit marker for a
# task already in verified/. Must carry non-empty ``reason:``.
rollback:
authored_by: [ARCHITECT-REVIEWER]
# Which block kinds may be appended to a task currently sitting in
# each queue. Terminal queues accept nothing (empty list). Mirrors
# the prior cli/task.py:QUEUE_BLOCK_KINDS hardcode.
queue_accepts_blocks:
feature_inbox: [triage, blocked]
feature_plan: [plan, blocked]
feature_dev: [implementation, blocked]
feature_ui_dev: [implementation, blocked]
feature_docs: [implementation, blocked]
feature_live: [implementation, blocked]
feature_test: [tests, blocked]
feature_docs_review: [reader_review, blocked]
feature_review: [review, blocked]
feature_blocked: [blocked]
user_feedback: [triage, blocked]
review_sessions: [session_iteration, blocked]
verified: [rollback] # rollback only; terminal otherwise
archive: []
# Implementation-block scope → which role's queue feeds it. Used by
# intake-rejection + the role-of-implementer dispatch.
assignee_role_by_scope:
backend: DEVELOPER
ui: UI-DEVELOPER
docs: TECHNICAL-WRITER
# Product-stream enums for validate_header + validate_block.
product_enums:
kinds: [feature, bugfix, docs, ops, research, release]
scopes: [backend, ui, docs, stand, research, release]
priorities: [low, normal, high]
plan_kinds: [full, bugfix]
modes: [A, B, C]
# ---------------------------------------------------------------------------
# Per-task git worktree policy.
#
# Each task gets its own working tree under <project_dir>/<base_path>/
# <task-id>/ on branch <branch_prefix><task-id>. Implementer agents
# cd into their worktree at claim time. Working-tree contamination
# becomes physically impossible across tasks; no locks needed.
#
# Lifecycle is wired into `greatminds task mv` transitions:
# * mv → feature_dev / feature_ui_dev / feature_docs → worktree create
# * mv → verified by REVIEWER → worktree merge
# * mv → archive → worktree remove
#
# All operator-facing operations are exposed by `greatminds worktree
# {create|remove|merge|list|prune}`.
# ---------------------------------------------------------------------------
worktrees:
base_path: .worktrees # relative to project_dir; gitignored
branch_prefix: task/ # task ids become task/<id> branches
default_branch: main # branch task worktrees base off + merge back into; set to run coordination on another branch
merge_strategy: --no-ff # explicit per-task boundary in history
cleanup_on_archive: true
cleanup_on_verified: true # after successful merge
conflict_handback_to: feature_dev # where REVIEWER hands back on conflict
required_for_task_kinds: [feature, bugfix, ops]
# USER-curated marketplace plugin lists for `greatminds setup`.
# Verified 2026-05-25 against anthropics/claude-plugins-official.
# Codex side deferred — operator hasn't curated yet, empty list per
# role logs deferral and continues.
plugins:
claude_marketplace:
ARCHITECT-PLANNER: [sourcegraph, sentry, huggingface-skills]
ARCHITECT-REVIEWER: [sourcegraph, sentry]
DEVELOPER: [postman]
UI-DEVELOPER: [playwright, chrome-devtools-mcp, postman]
TESTER: [playwright, sentry, postman, codspeed]
READER: []
MAINTAINER: []
codex_marketplace:
TECHNICAL-WRITER: []
EXPLORER: []
# Agent-uttered visual markers.
#
# After each successful greatminds task mv / append-block / inbox
# send, the agent ends its turn-reply with one markdown line per
# the schema-defined template. Unicode colored emoji + markdown
# bold + inline code = TUI (claude / codex / tmux) renders this
# natively — no ANSI escapes (which most TUIs strip). Operator
# scrolling through any agent pane scans by the emoji color and
# spots major lifecycle events without parsing tool-output blocks.
#
# Detection rules (which event for which CLI verb):
# - task mv → implementer queue from non-claim queue → claimed
# - task mv → feature_test / feature_docs_review from
# an implementer queue → finished
# - task mv → verified → accepted
# - task append-block tests --field test_result=fail|partial
# OR review --field outcome=changes_requested
# OR mv back to implementer queue from review queue → rejected
# - inbox send → message_sent
#
# Templates use Python str.format placeholders. Available context:
# {emoji}, {task_id}, {from_queue}, {to_queue}, {from_role},
# {to_role}, {kind}, {task_ref}, {reason}. Agents pick the right
# placeholders for each event.
visual_events:
claimed:
emoji: "🔵"
template: "{emoji} **CLAIMED** `{task_id}` ({from_queue} → {to_queue})"
finished:
emoji: "🟢"
template: "{emoji} **FINISHED** `{task_id}` → `{to_queue}`"
accepted:
emoji: "🟩"
template: "{emoji} **ACCEPTED** `{task_id}` → `verified`"
rejected:
emoji: "🔴"
template: "{emoji} **REJECTED** `{task_id}` ← {from_role} ({reason})"
message_sent:
emoji: "🟣"
template: "{emoji} **SENT** {kind} → {to_role} {task_ref}"
# Claude Code auto-mode permissions for claude-host roles.
#
# /loop REVIEWER (and any other claude-host role that needs to run
# destructive git ops) cannot do `git commit/tag/push/merge` without
# an explicit allow rule — Claude Code's auto-mode classifier blocks
# destructive Bash by default, and a /loop session has no operator to
# answer an AskUserQuestion prompt. `greatminds setup` writes/extends
# `<project>/.claude/settings.local.json` with these rules per the
# structured-config-first directive. Operator may extend per-project
# by editing settings.local.json directly; setup merges via union,
# never overwriting existing operator entries.
# coordd periodic PyPI version check. Every
# `check_interval_seconds`, coordd compares the installed greatminds
# version against PyPI's latest; if newer, it sends ONE info-message
# to `notify_target`. Notify-only — MAINTAINER decides when to
# actually run `greatminds update`. coordd tracks the last-notified
# version in process memory so a still-un-acted-upon newer release
# doesn't spam every poll.
auto_update:
check_interval_seconds: 14400 # 4h
notify_target: MAINTAINER
mode: notify_only # future: auto_execute
source: pypi # future: git_tag
# Gate `greatminds report-upstream` to MAINTAINER only. Other
# roles file bug-suspects via `greatminds inbox send MAINTAINER
# --kind ask`. CLI refuses for non-allowed agent roles; operator-
# mode (no GREATMINDS_ROLE) bypasses the gate.
report_upstream:
permissions:
invoke: [MAINTAINER]
triage_inbox_target: MAINTAINER
upstream_repo_required: true
# Canonical list of system variables greatminds reads out of
# the box. ``setup`` generates ``.greatminds/PROJECT.env`` from this
# section, pre-populating each var with its description / acquire
# instructions. Users add their own KEY=value to PROJECT.env after
# setup; only the entries listed here come from canon.
project_env:
system_vars:
GREATMINDS_UPSTREAM_TOKEN:
required: false
description: |
GitHub PAT for `greatminds report-upstream --mode api-token`.
Skip if using --mode gh (gh auth login) instead.
usage_locations: [src/greatminds/cli/report_upstream.py]
acquire_instructions: |
github.com → Settings → Developer settings → Personal access
tokens. Scope: issues:write on the upstream repo
(default veryviolet/greatminds).
claude_settings:
permissions:
allow:
# Broad default: allow ALL Bash for every project. Driven /
# headless agents (TESTER stand probes, coordd deploys —
# sudo/docker/compose/rsync, MAINTAINER recovery) repeatedly
# stalled because a needed command wasn't in a narrow allow-list
# and a headless turn can't answer a permission prompt. These are
# the operator's own dev fleets; agents must never block on Bash.
# The specific git/ssh/rsync rules below are redundant under this
# but kept as documentation of the original intent.
- "Bash"
- "Bash(git add:*)"
- "Bash(git commit:*)"
- "Bash(git tag:*)"
- "Bash(git push:*)"
- "Bash(git merge:*)"
- "Bash(git worktree:*)"
- "Bash(git checkout:*)"
- "Bash(git branch:*)"
# REVIEWER's rollback path (verified → revert) needs git
# revert; TESTER's stand probe needs ssh/scp; coordd's
# deploy uses rsync. Without these allow rules they had to be
# typed manually with the `!` prefix on every invocation.
- "Bash(git revert:*)"
- "Bash(ssh:*)"
- "Bash(scp:*)"
- "Bash(rsync:*)"
# Classifier auto-mode ceiling. Without explicit auto_mode
# entries the classifier blocks `git push origin main` even when
# permissions.allow contains `Bash(git push:*)`. These rules raise
# the ceiling so REVIEWER's automated cut-and-push pipeline works
# without manual `!` prefix on each push.
auto_mode:
allow:
- "$defaults"
# NOTE: deliberately NOT a bare "Bash" here — auto_mode is the
# classifier's OWN ceiling for USER-present interactive turns, and a
# wildcard there is an auto-mode bypass (rightly refused). Driven /
# headless agents are gated by permissions.allow (which DOES allow
# all Bash), not by this ceiling, so the deploy/probe unblocking
# works without widening the interactive classifier gate.
- "Bash(git push origin main:*)"
- "Bash(git push origin main --follow-tags:*)"
- "Bash(git push --follow-tags:*)"
# REVIEWER's canonical terminal transition is not raw git: it is
# `greatminds task mv <id> verified`, which performs the sanctioned
# worktree merge. Driven Claude REVIEWER sessions must be able to run
# that FSM command, and the related worktree lifecycle commands, under
# auto-mode.
- "Bash(greatminds task mv:*)"
- "Bash(greatminds worktree:*)"
- "Bash(git revert:*)"
# ssh/scp/rsync also need to live in auto_mode.allow, not just
# permissions.allow — the classifier's auto-mode ceiling is a
# SEPARATE gate. Without the parallel entries a stand probe from
# a --permission-mode auto pane is still challenged for USER
# session auth on every invocation.
- "Bash(ssh:*)"
- "Bash(scp:*)"
- "Bash(rsync:*)"
# MAINTAINER is self-loop (USER-absent) and runs recovery —
# agent restart, daemon control, dead-pid
# SIGTERM. The classifier's auto-mode ceiling blocked these
# without explicit entries, so MAINTAINER's autonomous
# recovery stalled waiting for a USER who isn't there. These
# patterns unblock the recovery path.
- "Bash(greatminds restart:*)"
- "Bash(greatminds daemon:*)"
- "Bash(greatminds start-agent:*)"
- "Bash(kill:*)"
- "Bash(systemctl --user:*)"
stand_profile_registry:
path: coordination/stand-profiles.yaml
environment_values:
stand: "Disposable or staging-like live stand."
production: "Production environment; requires explicit approval policy."
used_for_values:
deploy_only: "Deploy/readiness check without product behavior validation."
warmup: "Prepare prerequisites before a validation lease."
quick_readiness: "Cheap liveness/reachability check."
tester_validation: "TESTER product validation for stand-required tasks."
explorer_review: "EXPLORER scenario-B live product review."
live_ui: "LIVE-DEVELOPER scenario-C UI iteration."
ui_iteration: "UI-focused live iteration."
reviewer_validation: "ARCHITECT-REVIEWER final stand verification."
full_product_validation: "End-to-end deployed product validation."
production_deploy: "Production deployment task."
production_post_deploy_review: "Post-deploy production verification."
default_for_values:
verify_only: "No-code stand/playbook verification task."
feature_test: "TESTER validation after implementation."
explorer: "EXPLORER review-session lease."
live_developer: "LIVE-DEVELOPER interactive lease."
ui_iteration: "UI-focused live iteration."
reviewer: "ARCHITECT-REVIEWER final verification lease."
production_deploy: "Deployment to production."
production_review: "Review that production deployment is complete and healthy."
# Stand profile files. coordd reads the YAML file referenced by
# ``coordination/stand-profiles.yaml`` for ``lease.profile`` and executes it as
# part of the lease deploy.
#
# * ``yaml`` — a subset of ansible-playbook syntax, run by coordd's
# deterministic deploy engine.
#
stand_profile:
directory: coordination/stand-profiles
formats: [yaml]
lookup: "coordination/stand-profiles.yaml profiles.<lease.profile>.file"
yaml_dialect: ansible_playbook
yaml_required_fields: [name, hosts, tasks]
yaml_optional_fields: [vars, handlers, gather_facts]
# Opt-out flag carried on lease metadata so the deploy path runs only the
# "prerequisites" subset of the profile (used by warmup leases
# that prepare the stand for the real probe).
deploy_prerequisites_only_flag: deploy_prerequisites_only
# Stand lifecycle notification policy. coordd files inbox-info
# automatically on these events so PLANNER (or another role) does not need to
# poll state.yaml. Keep the map small — only events PLANNER must react to.
stand_keeper:
notifications:
on_down: ARCHITECT-PLANNER