pub const HERMES_WORKFLOW: &str = "# Hermes\'s kanban dispatcher as data (hermes_cli/kanban_db.py, read as the reference): the workflow a home runs\n# when it declares none. Each transition names the Hermes function it transcribes. Beyond Hermes, and marked\n# \"ours\": pane sessions (session slots, loss and resume), the idle heartbeat and goal nudges, triage by a session,\n# machine capacity. A home\'s config.yaml `kanban:` keys override `params` by name.\n#\n# Conditions and quantities (guard, validate, roles, limits, order, max) are expressions; targets and action\n# arguments are templates, literal text with `{{expr}}` parts, one whole `{{expr}}` giving the expression\'s value.\ndescription: Hermes Kanban\'s lifecycle and dispatcher, with supercode\'s session lanes\n\nparams:\n dispatch_in_gateway: true # kanban.dispatch_in_gateway\n dispatch_interval_seconds: 60 # kanban.dispatch_interval_seconds\n dispatch_stale_timeout_seconds: null\n failure_limit: 2 # kanban.failure_limit (a card\'s max_retries wins)\n claim_ttl_seconds: 900 # kanban.claim_ttl_seconds (HERMES_KANBAN_CLAIM_TTL_SECONDS)\n max_in_progress: null # unset: host.max_in_progress (one per 512 MiB, 2..8)\n max_in_progress_per_profile: null\n max_spawn: null\n default_assignee: null\n review_dispatch: true # kanban.review_dispatch\n review_skills: [sdlc-review] # claim_review_task force-loads it\n auto_decompose: true\n auto_decompose_per_tick: 3\n reconcile_orphans: true # kanban.reconcile_orphans\n block_recurrence_limit: 2 # the same block kind this many times in a row routes to triage\n rate_limit_cooldown_seconds: 300 # HERMES_KANBAN_RATE_LIMIT_COOLDOWN_SECONDS\n recent_success_seconds: 3600 # the respawn guard\'s fresh-completion window\n active_pr_seconds: 86400 # the respawn guard\'s open-pull-request window\n blocker_pattern: \'(?i)\\b(quota|rate[\\s_-]?limit|429|403|auth\\w*|unauthorized|forbidden|billing|subscription|access[\\s_]denied|permission[\\s_]denied|invalid[\\s_]api[\\s_]key)\\b\'\n pr_pattern: \'(?i)https?://github\\.com/[^/\\s]+/[^/\\s]+/pull/\\d+\'\n session_grace_seconds: 120 # ours\n goal_mode_default: false # ours\n goal_max_turns: 20 # ours\n heartbeat_quiet_seconds: 1800 # ours: after a heartbeat the idle heartbeat leaves the session be this long\n managers: [] # ours: sessions (addresses) that are the board\'s manager on every card\n machine_offline_grace_seconds: 3600 # ours\n machines: {} # ours: <machine>: {capacity: n}\n\nroles:\n implementer: card.assignee ?? params.default_assignee\n reviewer: card.assignee ?? params.default_assignee\n creator: card.created_by\n\ninitial: # where a new card starts; a new card is a goal card when it asks, or by params.goal_mode_default (never a subtask)\n - guard: \"event.initial_status == \'blocked\'\"\n target: blocked\n actions: [{ assign: { field: goal_mode, value: \"{{event.goal ?? (event.subtask_of == null && params.goal_mode_default)}}\" } }]\n - guard: event.triage\n target: triage\n actions: [{ assign: { field: goal_mode, value: \"{{event.goal ?? (event.subtask_of == null && params.goal_mode_default)}}\" } }]\n - guard: \"!card.parents.all(p, p.status in [\'done\', \'archived\'])\"\n target: todo\n actions: [{ assign: { field: goal_mode, value: \"{{event.goal ?? (event.subtask_of == null && params.goal_mode_default)}}\" } }]\n - target: ready\n actions: [{ assign: { field: goal_mode, value: \"{{event.goal ?? (event.subtask_of == null && params.goal_mode_default)}}\" } }]\n\non:\n # edits that keep the card where it is; each records Hermes\'s own event kind\n comment: [{ actions: [{ record: commented }] }]\n assign:\n - validate: [{ expr: \"!(card.status in [\'running\', \'reviewing\'])\", message: \"the card is running; reclaim it before reassigning\" }]\n guard: \"event.assignee != card.assignee\"\n actions: [{ assign: { field: assignee, value: \"{{event.assignee}}\" } }, { reset: [failures] }, { assign: { field: last_failure_error, value: \"{{null}}\" } }, { record: assigned }]\n - actions: [{ record: assigned }]\n set_model: [{ actions: [{ assign: { field: model_override, value: \"{{event.model}}\" } }, { assign: { field: provider_override, value: \"{{event.provider}}\" } }, { record: model_override_set }] }]\n set_goal: [{ actions: [{ assign: { field: goal_mode, value: \"{{event.goal}}\" } }, { assign: { field: goal_max_turns, value: \"{{event.max_turns}}\" } }, { record: goal_set }] }]\n link: [{ actions: [{ link: \"{{event.parent}}\" }, { record: linked }] }]\n unlink: [{ actions: [{ unlink: \"{{event.parent}}\" }, { record: unlinked }] }]\n archive:\n - target: archived\n actions: [{ end_run: { outcome: reclaimed, summary: task archived with run still active } }, { record: archived }]\n adopt: # ours: a live session the board did not start is put on the card as its implementer\n - by: [manager]\n validate: [{ expr: \"card.status in [\'todo\', \'ready\', \'blocked\', \'scheduled\', \'triage\', \'review\']\", message: \"only an open card takes a session\" }]\n target: running\n actions: [{ claim: implementer }]\n\nstatuses:\n triage:\n stored_as: triage\n description: a rough idea waiting to be specified (Hermes asks its auxiliary model; here a session writes it)\n on:\n specify:\n - target: todo\n actions: [{ specify: \"{{event}}\" }, { record: specified }]\n decompose:\n - target: todo\n actions: [{ decompose: \"{{event}}\" }, { record: decomposed }]\n start:\n - by: [platform]\n guard: params.auto_decompose\n target: triaging\n - by: [manager] # specify or decompose asked with no spec: a session writes it\n target: triaging\n\n triaging: # ours: triage by a session in the card\'s lane\n stored_as: running\n run:\n role: implementer\n session: worker\n prompt: |\n Card {{card.id}} on the {{board}} board is in triage: a rough idea to split. Read it, then file the cards it\n breaks into and make it wait on them, or write its spec.\n {{doors}}\n\n {{context}}\n on:\n specify: [{ by: [implementer], target: todo, actions: [{ end_run: { outcome: specified } }, { specify: \"{{event}}\" }, { record: specified }] }]\n decompose: [{ by: [implementer], target: todo, actions: [{ end_run: { outcome: decomposed } }, { decompose: \"{{event}}\" }, { record: decomposed }] }]\n spawn_failed: # the launch itself failed: back where it came from, counted against the breaker\n - by: [platform]\n guard: \"card.counters.failures + 1 >= (card.max_retries ?? params.failure_limit)\"\n target: blocked\n actions: [{ end_run: { outcome: spawn_failed } }, { count: failures }, { record: spawn_failed }, { record: gave_up }]\n - by: [platform]\n target: triage\n actions: [{ end_run: { outcome: spawn_failed } }, { count: failures }, { record: spawn_failed }]\n session_idle: # ours: the heartbeat, with the same budget as the implementer\'s\n - by: [platform]\n guard: \"event.turns >= (card.goal_max_turns ?? params.goal_max_turns)\"\n target: blocked\n actions: [{ end_run: { outcome: blocked } }, { assign: { field: block_kind, value: needs_input } }, { record: { kind: blocked, payload: { reason: \"its triage session went idle {{event.turns}} times without deciding; review it\", kind: needs_input, source_status: triage } } }]\n - by: [platform]\n actions:\n - count: goal_turns\n - send_to_actor: \"Card {{card.id}} ({{card.title}}) is waiting for you to decide ({{event.turns + 1}} of {{card.goal_max_turns ?? params.goal_max_turns}}).\\n{{doors}}\"\n - record: { kind: decision_asked, payload: { turn: \"{{event.turns + 1}}\", budget: \"{{card.goal_max_turns ?? params.goal_max_turns}}\" } }\n machine_offline: # ours: a session whose machine stays off the fleet past the grace\n - by: [platform]\n guard: \"event.seconds >= params.machine_offline_grace_seconds\"\n target: blocked\n actions: [{ end_run: { outcome: reclaimed } }, { assign: { field: block_kind, value: capability } }, { record: { kind: blocked, payload: { reason: \"machine {{event.machine}} has been off the fleet for {{event.seconds}}s\", kind: capability, source_status: triage } } }]\n session_lost: [{ by: [platform], target: triage, actions: [{ end_run: { outcome: reclaimed } }, { record: session_lost }] }]\n orphaned: [{ by: [platform], guard: params.reconcile_orphans, target: triage, actions: [{ end_run: { outcome: reclaimed } }, { record: reconciled }, { comment: \"Requeued: the card was running with no claim and nothing live behind it.\" }] }]\n exited: [{ by: [platform], target: triage, actions: [{ end_run: { outcome: crashed } }, { record: crashed }] }]\n\n todo:\n stored_as: todo\n description: waiting on its parents\n always:\n - guard: \"card.arc != null && card.arc.status in [\'done\', \'archived\']\" # ours: a subtask whose arc ended with it open\n target: blocked\n actions: [{ assign: { field: block_kind, value: needs_input } }, { record: { kind: blocked, payload: { reason: \"its arc {{card.arc.id}} ended with it open\", kind: needs_input, source_status: ready } } }]\n - guard: \"card.parents.all(p, p.status in [\'done\', \'archived\'])\" # recompute_ready\n target: ready\n actions: [{ record: promoted }]\n on:\n promote:\n - validate: [{ expr: \"event.force || card.parents.all(p, p.status in [\'done\', \'archived\'])\", message: \"parents not done (force to override)\" }]\n target: ready\n actions: [{ record: promoted_manual }]\n schedule: [{ target: scheduled, actions: [{ record: scheduled }] }]\n\n ready:\n stored_as: ready\n description: waiting for the dispatcher to start it\n always:\n - guard: \"card.arc != null && card.arc.status in [\'done\', \'archived\']\" # ours: a subtask whose arc ended with it open\n target: blocked\n actions: [{ assign: { field: block_kind, value: needs_input } }, { record: { kind: blocked, payload: { reason: \"its arc {{card.arc.id}} ended with it open\", kind: needs_input, source_status: ready } } }]\n - guard: \"!card.parents.all(p, p.status in [\'done\', \'archived\'])\" # a parent linked after it was ready\n target: todo\n on:\n start: # claim_task, under dispatch_once\'s respawn guard\n - by: [platform]\n validate:\n - expr: \"!(card.last_run.outcome == \'rate_limited\' && now - card.last_run.ended_at < params.rate_limit_cooldown_seconds)\"\n message: rate_limit_cooldown\n - expr: \"!matches(card.last_failure_error, params.blocker_pattern)\"\n message: blocker_auth\n - expr: \"!(card.last_completed != null && now - card.last_completed.ended_at < params.recent_success_seconds && card.events_since(card.last_completed.ended_at, [\'status\', \'promoted\', \'unblocked\', \'reclaimed\']).size() == 0)\"\n message: recent_success\n - expr: \"!card.comments_since(now - params.active_pr_seconds).exists(c, matches(c.body, params.pr_pattern))\"\n message: active_pr\n target: running\n actions: [{ claim: implementer }]\n block:\n - guard: \"event.kind == \'dependency\'\"\n target: todo\n actions: [{ assign: { field: block_kind, value: \"{{event.kind}}\" } }, { record: dependency_wait }]\n - guard: \"card.block_kind == event.kind && card.counters.block_recurrences + 1 >= params.block_recurrence_limit\"\n target: triage\n actions: [{ count: block_recurrences }, { record: block_loop_detected }]\n - target: blocked\n actions: [{ count: block_recurrences }, { assign: { field: block_kind, value: \"{{event.kind}}\" } }, { record: blocked }]\n request_review:\n - target: review\n actions: [{ assign: { field: assignee, value: \"{{event.reviewer ?? (card.last_reviewer in lanes ? card.last_reviewer : null) ?? card.assignee}}\" } }, { record: review_requested }]\n complete:\n - validate: [{ expr: \"card.parents.all(p, p.status in [\'done\', \'archived\'])\", message: \"the card waits on parents that are not done\" }]\n target: done\n actions: [{ end_run: { outcome: completed } }, { set_result: \"{{event}}\" }, { reset: [failures, block_recurrences] }, { assign: { field: last_failure_error, value: \"{{null}}\" } }, { assign: { field: block_kind, value: \"{{null}}\" } }, { cleanup_workspace: null }, { record: completed }, { check_references: \"{{event}}\" }]\n schedule: [{ target: scheduled, actions: [{ record: scheduled }] }]\n\n running:\n stored_as: running\n description: its implementer is working it\n run:\n role: implementer\n session: worker\n prompt: |\n You are the session working card {{card.id}} on the {{board}} board. The board started you; updates to the\n card and to the cards it waits on reach you as board notices.\n {{doors}}\n Leave a note on it with `supercode workflow comment {{card.id}} \"<text>\" {{where}}`; file a subtask with\n `supercode workflow create \"<title>\" --subtask-of {{card.id}} {{where}}`.\n\n {{context}}\n limits:\n runtime: card.max_runtime_seconds\n stale: \"run.surface == \'headless\' ? params.dispatch_stale_timeout_seconds : null\"\n grace: params.session_grace_seconds\n on:\n heartbeat: [{ by: [implementer], description: \'still working on a long step, or waiting on something outside (a person, a run): the board leaves you be for a while (`--note \"<what>\"`)\', actions: [{ extend_claim: null }, { reset: [goal_turns] }, { record: heartbeat }] }]\n complete:\n - by: [implementer, manager]\n description: \'the work is done: `--summary \"<what you did and how it was verified>\"`\'\n validate:\n - { expr: \"event.run_id == null || event.run_id == card.current_run_id\", message: \"that run is no longer the card\'s current run\" }\n - { expr: \"card.parents.all(p, p.status in [\'done\', \'archived\'])\", message: \"the card waits on parents that are not done\" }\n target: done\n actions: [{ end_run: { outcome: completed } }, { set_result: \"{{event}}\" }, { reset: [failures, block_recurrences] }, { assign: { field: last_failure_error, value: \"{{null}}\" } }, { assign: { field: block_kind, value: \"{{null}}\" } }, { cleanup_workspace: null }, { record: completed }, { check_references: \"{{event}}\" }]\n block:\n - by: [implementer, manager]\n description: \'you cannot go on: `\"<why>\" --kind needs_input|capability|transient|dependency`\'\n guard: \"event.kind == \'dependency\'\"\n target: todo\n actions: [{ end_run: { outcome: blocked } }, { assign: { field: block_kind, value: \"{{event.kind}}\" } }, { record: dependency_wait }]\n - by: [implementer, manager]\n guard: \"card.block_kind == event.kind && card.counters.block_recurrences + 1 >= params.block_recurrence_limit\"\n target: triage\n actions: [{ end_run: { outcome: blocked } }, { count: block_recurrences }, { record: block_loop_detected }]\n - by: [implementer, manager]\n target: blocked\n actions: [{ end_run: { outcome: blocked } }, { count: block_recurrences }, { assign: { field: block_kind, value: \"{{event.kind}}\" } }, { record: blocked }]\n request_review:\n - by: [implementer, manager]\n description: \'the work is ready for review: `--summary \"<what to review>\"`\'\n validate: [{ expr: \"event.run_id == card.current_run_id || event.force\", message: \"the card is running under a live claim; its worker requests review, or pass --force\" }]\n target: review\n actions: [{ end_run: { outcome: review_requested } }, { assign: { field: assignee, value: \"{{event.reviewer ?? (card.last_reviewer in lanes ? card.last_reviewer : null) ?? card.assignee}}\" } }, { record: review_requested }]\n reclaim: [{ by: [manager], target: ready, actions: [{ end_run: { outcome: reclaimed } }, { reset: [failures] }, { record: reclaimed }] }]\n schedule: [{ by: [manager], target: scheduled, actions: [{ end_run: { outcome: scheduled } }, { record: scheduled }] }]\n # detect_crashed_workers / enforce_max_runtime / release_stale_claims, with the breaker (a card\'s max_retries wins)\n exited:\n - by: [platform]\n guard: \"event.code == 75\"\n target: ready\n actions: [{ end_run: { outcome: rate_limited } }, { record: rate_limited }]\n - by: [platform] # a clean exit that left the card running is a protocol violation: the breaker trips at once\n guard: \"event.code == 0\"\n target: blocked\n actions: [{ end_run: { outcome: protocol_violation } }, { count: failures }, { record: crashed }, { record: gave_up }]\n - by: [platform]\n guard: \"card.counters.failures + 1 >= (card.max_retries ?? params.failure_limit)\"\n target: blocked\n actions: [{ end_run: { outcome: \"{{event.code == 0 ? \'protocol_violation\' : \'crashed\'}}\" } }, { count: failures }, { record: crashed }, { record: gave_up }]\n - by: [platform]\n target: ready\n actions: [{ end_run: { outcome: \"{{event.code == 0 ? \'protocol_violation\' : \'crashed\'}}\" } }, { count: failures }, { record: crashed }]\n spawn_failed: # the launch itself failed: back where it came from, counted against the breaker\n - by: [platform]\n guard: \"card.counters.failures + 1 >= (card.max_retries ?? params.failure_limit)\"\n target: blocked\n actions: [{ end_run: { outcome: spawn_failed } }, { count: failures }, { record: spawn_failed }, { record: gave_up }]\n - by: [platform]\n target: ready\n actions: [{ end_run: { outcome: spawn_failed } }, { count: failures }, { record: spawn_failed }]\n timed_out:\n - by: [platform]\n guard: \"card.counters.failures + 1 >= (card.max_retries ?? params.failure_limit)\"\n target: blocked\n actions: [{ stop_run: null }, { end_run: { outcome: timed_out } }, { count: failures }, { record: timed_out }, { record: gave_up }]\n - by: [platform]\n target: ready\n actions: [{ stop_run: null }, { end_run: { outcome: timed_out } }, { count: failures }, { record: timed_out }]\n orphaned: [{ by: [platform], guard: params.reconcile_orphans, target: ready, actions: [{ end_run: { outcome: reclaimed } }, { record: reconciled }, { comment: \"Requeued: the card was running with no claim and nothing live behind it.\" }] }]\n stale: [{ by: [platform], target: ready, actions: [{ stop_run: null }, { end_run: { outcome: stale } }, { record: stale }] }]\n session_lost: # ours: a pane session gone past its grace is resumed at the next start, never replaced first\n - by: [platform] # a fresh session that never came up is a failure\n guard: \"event.never_came_up && card.counters.failures + 1 >= (card.max_retries ?? params.failure_limit)\"\n target: blocked\n actions: [{ end_run: { outcome: reclaimed } }, { count: failures }, { record: session_lost }, { record: gave_up }]\n - by: [platform]\n guard: event.never_came_up\n target: ready\n actions: [{ end_run: { outcome: reclaimed } }, { count: failures }, { record: session_lost }]\n - by: [platform]\n target: ready\n actions: [{ end_run: { outcome: reclaimed } }, { record: session_lost }]\n machine_offline: # ours: a session whose machine stays off the fleet past the grace\n - by: [platform]\n guard: \"event.seconds >= params.machine_offline_grace_seconds\"\n target: blocked\n actions: [{ end_run: { outcome: reclaimed } }, { assign: { field: block_kind, value: capability } }, { record: { kind: blocked, payload: { reason: \"machine {{event.machine}} has been off the fleet for {{event.seconds}}s\", kind: capability, source_status: ready } } }]\n session_idle: # ours: the heartbeat. event.turns: asks so far this run; event.worked: seen working since the last ask\n - by: [platform] # a session that said it is working or waiting (a heartbeat) is left be for a while\n guard: \"card.last_heartbeat_at != null && now - card.last_heartbeat_at < params.heartbeat_quiet_seconds\"\n - by: [platform]\n guard: \"(card.goal_mode || !event.worked) && event.turns >= (card.goal_max_turns ?? params.goal_max_turns)\"\n target: blocked\n actions:\n - end_run: { outcome: blocked }\n - assign: { field: block_kind, value: needs_input }\n - record: { kind: blocked, payload: { reason: \"its session went idle {{event.turns}} times without deciding done or blocked; review it\", kind: needs_input, source_status: ready } }\n - by: [platform]\n guard: card.goal_mode\n actions:\n - count: goal_turns\n - send_to_actor: \"Card {{card.id}} ({{card.title}}) is not done yet: keep working toward it (goal turn {{event.turns + 1}} of {{card.goal_max_turns ?? params.goal_max_turns}}).\\n{{doors}}\"\n - record: { kind: goal_continued, payload: { turn: \"{{event.turns + 1}}\", budget: \"{{card.goal_max_turns ?? params.goal_max_turns}}\" } }\n - by: [platform]\n actions:\n - reset: \"{{event.worked ? [\'goal_turns\'] : []}}\"\n - count: goal_turns\n - send_to_actor: \"Card {{card.id}} ({{card.title}}) is still running and you are idle: decide ({{(event.worked ? 0 : event.turns) + 1}} of {{card.goal_max_turns ?? params.goal_max_turns}}). If there is more to do, keep working. A session that stays idle without deciding has its card blocked for its creator.\\n{{doors}}\"\n - record: { kind: decision_asked, payload: { turn: \"{{(event.worked ? 0 : event.turns) + 1}}\", budget: \"{{card.goal_max_turns ?? params.goal_max_turns}}\" } }\n\n review:\n stored_as: review\n description: its implementer asked for review\n on:\n start: # claim_review_task\n - by: [platform]\n guard: params.review_dispatch\n validate:\n - expr: \"!(card.last_run.outcome == \'rate_limited\' && now - card.last_run.ended_at < params.rate_limit_cooldown_seconds)\"\n message: rate_limit_cooldown\n - expr: \"!matches(card.last_failure_error, params.blocker_pattern)\"\n message: blocker_auth\n target: reviewing\n actions: [{ claim: reviewer }]\n complete:\n - by: [reviewer, manager]\n description: \'the work is done: `--summary \"<what you did and how it was verified>\"`\'\n validate: [{ expr: \"card.parents.all(p, p.status in [\'done\', \'archived\'])\", message: \"the card waits on parents that are not done\" }]\n target: done\n actions: [{ end_run: { outcome: completed, summary: \"{{event.summary ?? \'Review approved without additional evidence.\'}}\" } }, { set_result: \"{{event}}\" }, { reset: [failures, block_recurrences] }, { assign: { field: last_failure_error, value: \"{{null}}\" } }, { assign: { field: block_kind, value: \"{{null}}\" } }, { cleanup_workspace: null }, { record: completed }, { check_references: \"{{event}}\" }]\n request_changes: # request_changes: back to the recorded implementer\n - by: [reviewer, manager]\n target: \"{{card.parents.all(p, p.status in [\'done\', \'archived\']) ? \'ready\' : \'todo\'}}\"\n actions: [{ assign: { field: assignee, value: \"{{card.implementer}}\" } }, { record: changes_requested }]\n reopen_review:\n - by: [manager]\n target: \"{{card.parents.all(p, p.status in [\'done\', \'archived\']) ? \'ready\' : \'todo\'}}\"\n actions: [{ assign: { field: assignee, value: \"{{card.implementer}}\" } }, { record: review_reopened }]\n block:\n - target: blocked\n actions: [{ assign: { field: block_kind, value: \"{{event.kind}}\" } }, { record: blocked }]\n\n reviewing:\n stored_as: running\n description: a reviewer is reviewing it\n run:\n role: reviewer\n session: reviewer\n prompt: |\n You are reviewing card {{card.id}} on the {{board}} board: its implementer asked for review. Verify the\n handoff against the card\'s acceptance, then give the verdict.\n {{doors}}\n\n {{context}}\n skills: [sdlc-review]\n limits:\n runtime: card.max_runtime_seconds\n grace: params.session_grace_seconds\n exit: [{ close_session: reviewer }]\n on:\n complete:\n - by: [reviewer, manager]\n description: \'the work is done: `--summary \"<what you did and how it was verified>\"`\'\n validate: [{ expr: \"card.parents.all(p, p.status in [\'done\', \'archived\'])\", message: \"the card waits on parents that are not done\" }]\n target: done\n actions: [{ end_run: { outcome: completed } }, { set_result: \"{{event}}\" }, { reset: [failures, block_recurrences] }, { assign: { field: last_failure_error, value: \"{{null}}\" } }, { assign: { field: block_kind, value: \"{{null}}\" } }, { cleanup_workspace: null }, { record: completed }, { check_references: \"{{event}}\" }]\n request_changes:\n - by: [reviewer, manager]\n description: \'send it back to its implementer: `\"<what must change>\"`\'\n target: \"{{card.parents.all(p, p.status in [\'done\', \'archived\']) ? \'ready\' : \'todo\'}}\"\n actions: [{ end_run: { outcome: changes_requested } }, { assign: { field: assignee, value: \"{{card.implementer}}\" } }, { record: changes_requested }]\n block:\n - by: [reviewer, manager]\n description: \'you cannot go on: `\"<why>\" --kind needs_input|capability|transient|dependency`\'\n target: blocked\n actions: [{ end_run: { outcome: blocked } }, { assign: { field: block_kind, value: \"{{event.kind}}\" } }, { record: blocked }]\n exited:\n - by: [platform]\n target: review\n actions: [{ end_run: { outcome: crashed } }, { count: failures }, { record: crashed }]\n spawn_failed: # the launch itself failed: back where it came from, counted against the breaker\n - by: [platform]\n guard: \"card.counters.failures + 1 >= (card.max_retries ?? params.failure_limit)\"\n target: blocked\n actions: [{ end_run: { outcome: spawn_failed } }, { count: failures }, { record: spawn_failed }, { record: gave_up }]\n - by: [platform]\n target: review\n actions: [{ end_run: { outcome: spawn_failed } }, { count: failures }, { record: spawn_failed }]\n timed_out: [{ by: [platform], target: review, actions: [{ stop_run: null }, { end_run: { outcome: timed_out } }, { count: failures }, { record: timed_out }] }]\n session_lost: [{ by: [platform], target: review, actions: [{ end_run: { outcome: reclaimed } }, { record: session_lost }] }]\n orphaned: [{ by: [platform], guard: params.reconcile_orphans, target: review, actions: [{ end_run: { outcome: reclaimed } }, { record: reconciled }, { comment: \"Requeued: the card was running with no claim and nothing live behind it.\" }] }]\n session_idle: # ours: the heartbeat, with the same budget as the implementer\'s\n - by: [platform]\n guard: \"event.turns >= (card.goal_max_turns ?? params.goal_max_turns)\"\n target: blocked\n actions: [{ end_run: { outcome: blocked } }, { assign: { field: block_kind, value: needs_input } }, { record: { kind: blocked, payload: { reason: \"its reviewer went idle {{event.turns}} times without deciding; review it\", kind: needs_input, source_status: review } } }]\n - by: [platform]\n actions:\n - count: goal_turns\n - send_to_actor: \"Card {{card.id}} ({{card.title}}) is waiting for you to decide ({{event.turns + 1}} of {{card.goal_max_turns ?? params.goal_max_turns}}).\\n{{doors}}\"\n - record: { kind: decision_asked, payload: { turn: \"{{event.turns + 1}}\", budget: \"{{card.goal_max_turns ?? params.goal_max_turns}}\" } }\n machine_offline: # ours: a session whose machine stays off the fleet past the grace\n - by: [platform]\n guard: \"event.seconds >= params.machine_offline_grace_seconds\"\n target: blocked\n actions: [{ end_run: { outcome: reclaimed } }, { assign: { field: block_kind, value: capability } }, { record: { kind: blocked, payload: { reason: \"machine {{event.machine}} has been off the fleet for {{event.seconds}}s\", kind: capability, source_status: review } } }]\n blocked:\n stored_as: blocked\n description: waiting on a person, a capability, or a transient cause\n always: # recompute_ready: a card not blocked by a person, under its failure limit, comes back when its parents are done\n - guard: \"card.last_block_event != \'blocked\' && card.counters.failures < (card.max_retries ?? params.failure_limit) && card.parents.all(p, p.status in [\'done\', \'archived\'])\"\n target: \"{{card.resume_status ?? \'ready\'}}\"\n actions: [{ record: promoted }]\n on:\n unblock: # unblock_task: back where it was blocked from\n - target: \"{{card.parents.all(p, p.status in [\'done\', \'archived\']) ? (card.resume_status ?? \'ready\') : \'todo\'}}\"\n actions: [{ reset: [failures] }, { assign: { field: last_failure_error, value: \"{{null}}\" } }, { record: unblocked }]\n promote:\n - validate: [{ expr: \"event.force || card.parents.all(p, p.status in [\'done\', \'archived\'])\", message: \"parents not done (force to override)\" }]\n target: ready\n actions: [{ record: promoted_manual }]\n complete:\n - validate: [{ expr: \"card.parents.all(p, p.status in [\'done\', \'archived\'])\", message: \"the card waits on parents that are not done\" }]\n target: done\n actions: [{ set_result: \"{{event}}\" }, { reset: [failures, block_recurrences] }, { assign: { field: last_failure_error, value: \"{{null}}\" } }, { assign: { field: block_kind, value: \"{{null}}\" } }, { record: completed }, { check_references: \"{{event}}\" }]\n schedule: [{ target: scheduled, actions: [{ record: scheduled }] }]\n\n scheduled:\n stored_as: scheduled\n description: set aside until someone brings it back\n on:\n unblock: [{ target: ready, actions: [{ record: unblocked }] }]\n\n done:\n stored_as: done\n description: finished\n on:\n edit: [{ actions: [{ set_result: \"{{event}}\" }, { record: edited }] }]\n reopen: # the dashboard\'s reopen, with invalidate_descendants_for_parent_reopen\n - target: \"{{card.parents.all(p, p.status in [\'done\', \'archived\']) ? \'ready\' : \'todo\'}}\"\n actions: [{ invalidate_descendants: null }, { record: status }]\n\n archived:\n stored_as: archived\n description: out of the way\n on:\n reopen:\n - target: \"{{card.parents.all(p, p.status in [\'done\', \'archived\']) ? \'ready\' : \'todo\'}}\"\n actions: [{ invalidate_descendants: null }, { record: status }]\n\ndispatch:\n serve: params.dispatch_in_gateway\n tick: params.dispatch_interval_seconds\n start: start\n # a subtask is worked by its arc\'s session; a card this machine\'s memory cannot take waits (dispatch_once)\n eligible: \"card.claim_lock == null && card.subtask_of == null && !(run.local && (host.memory_pressure == \'critical\' || (host.memory_pressure == \'elevated\' && tick.local_started >= 1)))\"\n order: [\"card.status == \'review\' ? 1 : 0\", \"-card.priority\", \"card.created_at\"]\n limits:\n - description: the home runs this many cards at most across its boards (kanban.max_in_progress)\n group: \"\'home\'\"\n counts: \"card.stored_as == \'running\'\"\n max: params.max_in_progress ?? host.max_in_progress\n reserve: { for: \"card.status == \'review\'\", slots: 1 }\n - description: the board runs this many cards at most (kanban.max_spawn)\n group: card.board\n counts: \"card.stored_as == \'running\'\"\n max: params.max_spawn\n - description: the profile\'s capacity (worker.capacity, else kanban.max_in_progress_per_profile)\n group: card.assignee\n counts: \"card.stored_as == \'running\'\"\n max: lane.capacity ?? params.max_in_progress_per_profile\n - description: the machine\'s capacity; an idle session on a done or blocked card holds its place until closed (ours)\n group: card.machine\n counts: \"card.stored_as == \'running\' || card.session_live\"\n max: \"params.machines[card.machine].capacity\"\n - description: triage sessions started per tick (kanban.auto_decompose_per_tick)\n group: \"\'triage\'\"\n counts: \"card.status == \'triaging\' && card.started_this_tick\"\n max: params.auto_decompose_per_tick\n\n# Who is told what (dispatch.mjs\'s notifier renders these): each audience\'s event kinds and the words for each.\n# The creator hears its card\'s course, the working session its card\'s thread, a dependent session the cards it waits on,\n# a chat what Hermes\'s notifier tells one. A kind not named here is not sent.\nnotify:\n creator:\n completed: \"\u{2714} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} done \u{2014} {{card.title}}{{event.summary ? \'\\n\' + cut(event.summary, 300) : \'\'}}\"\n blocked: \"\u{23f8} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} blocked{{event.reason ? \': \' + cut(event.reason, 300) : \'\'}}\"\n gave_up: \"\u{2716} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} gave up after {{event.failures}} failures{{event.error ? \'\\n\' + cut(event.error, 300) : \'\'}}\"\n crashed: \"\u{2716} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}}: its worker exited without completing it; the board will retry\"\n timed_out: \"\u{23f1} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} timed out (max_runtime {{event.limit_seconds}}s); the board will retry\"\n status: \"\u{1f504} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} \u{2192} {{event.status}}\"\n block_loop_detected: \"\u{1f6d1} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} went to triage: blocked {{event.recurrences}}x for the same cause{{event.reason ? \': \' + cut(event.reason, 200) : \'\'}}\"\n review_requested: \"\u{1f440} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} ready for review \u{2014} {{card.title}}{{event.summary ? \'\\n\' + cut(event.summary, 300) : \'\'}}\"\n changes_requested: \"\u{1f6d1} card {{card.id}}: review asked for changes: {{cut(event.reason ?? \'reviewer feedback\', 300)}}\"\n session_started: \"\u{25b6} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} \u{2014} {{card.title}}: the board started session {{event.session_id}} on {{event.machine}} (pane {{event.pane}}; {{event.address}}).\"\n session_resumed: \"\u{25b6} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} \u{2014} {{card.title}}: the board resumed session {{event.session_id}} on {{event.machine}} (pane {{event.pane}}; {{event.address}}).\"\n session_replaced: \"\u{25b6} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} \u{2014} {{card.title}}: the board could not resume the card\'s last session and started session {{event.session_id}} on {{event.machine}} (pane {{event.pane}}; {{event.address}}).\"\n session_adopted: \"\u{25b6} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} \u{2014} {{card.title}}: the board found session {{event.session_id}} still live on {{event.machine}} and kept it ({{event.address}}).\"\n session_lost: \"\u{2716} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}}: session {{event.session_id}} is gone from {{event.machine}}; the board resumes it, and replaces it from the card only when it cannot.\"\n spawn_failed: \"\u{2716} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}}: its session did not start: {{cut(event.error, 300)}}\"\n worker:\n commented: \"\u{1f4ac} card {{card.id}}, {{event.author}}:\\n{{comment.body}}\"\n assigned: \"card {{card.id}} is now assigned to {{event.assignee ?? \'nobody\'}}\"\n machine_set: \"card {{card.id}} now runs on {{event.machine ?? \'no machine\'}}\"\n blocked: \"\u{23f8} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} blocked{{event.reason ? \': \' + cut(event.reason, 300) : \'\'}}\"\n unblocked: \"\u{25b6} card {{card.id}} unblocked\"\n completed: \"\u{2714} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} done \u{2014} {{card.title}}{{event.summary ? \'\\n\' + cut(event.summary, 300) : \'\'}}\"\n archived: \"card {{card.id}} archived\"\n changes_requested: \"\u{1f6d1} card {{card.id}}: review asked for changes: {{cut(event.reason ?? \'reviewer feedback\', 300)}}\"\n linked: \"card {{card.id}}: dependency linked ({{event.parent}} \u{2192} {{event.child}})\"\n unlinked: \"card {{card.id}}: dependency unlinked ({{event.parent}} \u{2192} {{event.child}})\"\n promoted_manual: \"card {{card.id}} promoted to ready by {{event.actor}}\"\n subtask_added: \"card {{card.id}} has a new subtask {{event.subtask}}: {{event.title}}\"\n session_adopted: \"\u{25b6} card {{card.id}} \u{2014} {{card.title}} is running again, with you: carry it on from where it stands (`supercode workflow show {{card.id}}` reads it).\"\n dependency:\n completed: \"\u{2714} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} done \u{2014} {{card.title}}{{event.summary ? \'\\n\' + cut(event.summary, 300) : \'\'}}\"\n blocked: \"\u{23f8} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} blocked{{event.reason ? \': \' + cut(event.reason, 300) : \'\'}}\"\n unblocked: \"\u{25b6} card {{card.id}} unblocked\"\n review_requested: \"\u{1f440} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} ready for review \u{2014} {{card.title}}{{event.summary ? \'\\n\' + cut(event.summary, 300) : \'\'}}\"\n changes_requested: \"\u{1f6d1} card {{card.id}}: review asked for changes: {{cut(event.reason ?? \'reviewer feedback\', 300)}}\"\n commented: \"\u{1f4ac} card {{card.id}}, {{event.author}}:\\n{{comment.body}}\"\n chat:\n completed: \"\u{2714} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} done \u{2014} {{card.title}}{{event.summary ? \'\\n\' + cut(event.summary, 300) : \'\'}}\"\n blocked: \"\u{23f8} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} blocked{{event.reason ? \': \' + cut(event.reason, 300) : \'\'}}\"\n gave_up: \"\u{2716} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} gave up after {{event.failures}} failures{{event.error ? \'\\n\' + cut(event.error, 300) : \'\'}}\"\n crashed: \"\u{2716} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}}: its worker exited without completing it; the board will retry\"\n timed_out: \"\u{23f1} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} timed out (max_runtime {{event.limit_seconds}}s); the board will retry\"\n status: \"\u{1f504} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} \u{2192} {{event.status}}\"\n block_loop_detected: \"\u{1f6d1} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} went to triage: blocked {{event.recurrences}}x for the same cause{{event.reason ? \': \' + cut(event.reason, 200) : \'\'}}\"\n review_requested: \"\u{1f440} {{card.assignee ? \'@\' + card.assignee + \' \' : \'\'}}card {{card.id}} ready for review \u{2014} {{card.title}}{{event.summary ? \'\\n\' + cut(event.summary, 300) : \'\'}}\"\n changes_requested: \"\u{1f6d1} card {{card.id}}: review asked for changes: {{cut(event.reason ?? \'reviewer feedback\', 300)}}\"\n";Expand description
The built-in Hermes workflow’s source.