Skip to content

Transitions

Allowed transitions come from the effective installed schema; the project copy at .greatminds/schema.yaml is a diagnostic mirror. The CLI enforces the current role, current queue, target queue, and required readiness evidence.

See the generated contract reference for the current mechanical transition table and registered requirement names.

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:

schema.yaml on GitHub

# 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 the run-context compiler, 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

# Daemon-only operations are separate from agent roles and role transitions.
# An agent cannot acquire SYSTEM through a role binding or submit its approval.
system_transitions:
  resume_dependencies:
    from: feature_blocked
    to: declared_resume_to
    requires: [terminal_dependencies, declared_resume, task_readiness]

# ---------------------------------------------------------------------------
# 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. Evaluates semantic blockers; the daemon resumes mechanically ready dependencies."
    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: "Independently evaluates implementation and declared command evidence. When plan.stand_required is true, validates on the deployed stand with lease-backed evidence and gate-check. Local tasks use configured daemon commands; prompt completion alone is not passing evidence."
    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: "Diagnoses unknown infrastructure failures and proposes repairs when requested. Routine scheduling, startup recovery and dependency sweeps belong to daemon controllers. Does not claim product queues, triage user_feedback or write plans."
  lifecycles:
    interactive: "Operator-paced work through a daemon-owned ACP conversation. The role does not self-schedule."
    driven: "Assigned task work through the common ACP client. Binding scheduling controls admission; the daemon owns claims, retries, cancellation and reconciliation."
  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; the daemon evaluates readiness and applies permitted system resumes."
    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
      - resolve_dependency_cycles_and_invalid_declarations
      - 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:
        - inspect_dependency_findings_and_resolve_semantic_blockers
        - 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
    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:
      - independently_assess_implementation_and_test_adequacy
      - request_configured_daemon_checks_for_local_tasks
      - probe_feature_on_deployed_stand_when_plan_requires_it
      - fill_real_stand_evidence_when_plan_requires_it
      - run_gate_check_before_mv
    forbidden_actions:
      - deploy_stand
      - run_ansible_locally
      - fill_fake_stand_evidence
      - claim_outside_feature_test
      # Validation commands execute in the daemon's declared command service.
      # Stand-required work still needs actual deployed behavioral evidence.
      - execute_local_tests_directly_outside_declared_command_service
      - replace_required_stand_probes_with_local_checks
      - uv_run_or_active_against_fleet_venv
    event_triggers:
      on_feature_test_claim:
        - inspect_plan_stand_requirement_and_acceptance
        - request_configured_daemon_checks_and_assess_receipts_for_local_tasks
        - acquire_lease_when_plan_requires_stand
        - wait_for_state_ready_when_plan_requires_stand
        - probe_via_ssh_when_plan_requires_stand
        - fill_tests_block_with_real_observed_output
        - run_gate_check
        - release_lease_with_result_if_held
        - submit_typed_handoff_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
      - >-
        Run host-destructive or recovery actions (kill, pkill, systemctl,
        logout, reboot) against the local orchestration host or an unresolved
        target. Such scenarios require an explicitly authorized disposable
        stand and verified target identity; otherwise submit a blocker.
    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
    lifecycle: interactive
    claims_from: []
    responsibilities:
      - diagnose_unknown_infrastructure_failures
      - propose_repairs_with_explicit_preconditions
      - explain_unresolved_runtime_and_deployment_outcomes
      - infra_chat_for_user
    forbidden_actions:
      - claim_product_queues
      - triage_user_feedback
      - write_plan_blocks
      - schedule_polling_or_recovery_loops
      - infer_safe_replay_from_missing_process
    event_triggers:
      on_operator_diagnostic_request:
        - inspect_runtime_status_and_operation_evidence
        - diagnose_cause_and_propose_bounded_repair

# ---------------------------------------------------------------------------
# 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
# can inspect this rule in the pinned run contract.
# ---------------------------------------------------------------------------
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

# ---------------------------------------------------------------------------
# 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). Inspect relevant messages when requested. 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: "when referenced by assigned work or an operator request"

# ---------------------------------------------------------------------------
# Git permissions
#
# Closed set of roles that may run `git commit` / `git push` in this
# project. `greatminds check-git-permission` exposes this policy for
# explicitly configured hooks. Setup does not install a hook; direct
# harness shell access is not an OS enforcement boundary. 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:
    # Applies to deployed validation; explicit local plans use recorded local checks.
    backend:
      - functional_probes
      - stand_evidence.tester_observations
    ui:
      - functional_probes
      - stand_evidence.tester_observations
  exempt_scopes:
    - docs        # READER review covers docs
    - research
  scope_probes_required_when: plan.stand_required

# ---------------------------------------------------------------------------
# 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

# ---------------------------------------------------------------------------
# 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]

# Optional display templates for operator summaries. Frontends render durable
# runtime/domain events; agents do not have to repeat mechanical state as a
# final-line marker. These templates are presentation, never transition evidence.
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}"

# 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).

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. The stand down operation records
# inbox-info for the configured semantic owner. State inspection and scheduling
# stay in deterministic services; agents do not poll state.yaml.
stand_keeper:
  notifications:
    on_down: ARCHITECT-PLANNER