@delorenj/pjangler 1.1.5 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/.mise/scripts/link-agentfiles.sh +9 -0
  2. package/dist/index.js +1492 -358
  3. package/dist/mcp-server.js +2391 -290
  4. package/package.json +5 -2
  5. package/templates/commonproject/.mise/scripts/create-plane-project.sh +26 -0
  6. package/templates/commonproject/copier.yml +2 -0
  7. package/templates/commonproject/template/.agents/hooks/README.md +151 -0
  8. package/templates/commonproject/template/.agents/hooks/hermes/hindsight-hook.sh +63 -0
  9. package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-journal-write.sh +327 -0
  10. package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-recall.sh +180 -0
  11. package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-retain.sh +74 -0
  12. package/templates/commonproject/template/.agents/hooks/hindsight/hindsight-session-end.sh +57 -0
  13. package/templates/commonproject/template/.agents/hooks/hindsight/lib/hindsight-bank.sh +57 -0
  14. package/templates/commonproject/template/.agents/hooks/hindsight/lib/hindsight-journal.sh +48 -0
  15. package/templates/commonproject/template/.agents/hooks/hooks.master.json +97 -0
  16. package/templates/commonproject/template/.agents/hooks/lib/hook-guard.sh +30 -0
  17. package/templates/commonproject/template/.agents/hooks/lib/local-config.sh +51 -0
  18. package/templates/commonproject/template/.agents/hooks/reminder-for-skill-check.sh +20 -0
  19. package/templates/commonproject/template/.agents/hooks/sync.py +618 -0
  20. package/templates/commonproject/template/.agents/local.example.json +15 -0
  21. package/templates/commonproject/template/.mise/scripts/hindsight-setup.sh +62 -0
  22. package/templates/commonproject/template/.mise/scripts/link-project-skills-to-clis.sh +110 -0
  23. package/templates/commonproject/template/.mise/scripts/unlink-project-skills-from-clis.sh +45 -0
  24. package/templates/commonproject/template/mise.toml.jinja +42 -0
  25. package/templates/hermes-agent/.codegraph/daemon.pid +6 -0
  26. package/templates/hermes-agent/.omo/run-continuation/ses_0e5b28303ffeXxL53hZjKggXDW.json +10 -0
  27. package/templates/hermes-agent/README.md +16 -14
  28. package/templates/hermes-agent/copier.yml +7 -25
  29. package/templates/hermes-agent/docs/architecture.md +16 -18
  30. package/templates/hermes-agent/docs/fleet-control-plane/README.md +35 -0
  31. package/templates/hermes-agent/docs/fleet-control-plane/architecture.md +253 -0
  32. package/templates/hermes-agent/docs/fleet-control-plane/epics-and-stories.md +280 -0
  33. package/templates/hermes-agent/docs/fleet-control-plane/implementation-readiness-report-2026-06-27.md +118 -0
  34. package/templates/hermes-agent/docs/fleet-control-plane/prd.md +141 -0
  35. package/templates/hermes-agent/docs/operations.md +17 -19
  36. package/templates/hermes-agent/docs/runbooks/runtime-checkpoint-repair.md +17 -13
  37. package/templates/hermes-agent/docs/{scrum-master → sentinel}/README.md +47 -46
  38. package/templates/hermes-agent/docs/{scrum-master → sentinel}/architecture.md +39 -38
  39. package/templates/hermes-agent/docs/{scrum-master → sentinel}/development.md +63 -99
  40. package/templates/hermes-agent/docs/{scrum-master → sentinel}/providers.md +2 -2
  41. package/templates/hermes-agent/docs/sentinel.md +18 -0
  42. package/templates/hermes-agent/install-local.sh +22 -20
  43. package/templates/hermes-agent/runtime-scaffold/README.md +10 -9
  44. package/templates/hermes-agent/scripts/backfill-fleet-sot.sh +12 -21
  45. package/templates/hermes-agent/scripts/fleet-sync.sh +369 -0
  46. package/templates/hermes-agent/scripts/migrate-unify.sh +252 -0
  47. package/templates/hermes-agent/scripts/unify-pm.sh +148 -0
  48. package/templates/hermes-agent/template/.runtime-scaffold/README.md +10 -9
  49. package/templates/hermes-agent/template/.scripts/01-config.sh +2 -3
  50. package/templates/hermes-agent/template/.scripts/05-fleet-env.sh +0 -2
  51. package/templates/hermes-agent/template/.scripts/10-hermes-profile.sh +47 -19
  52. package/templates/hermes-agent/template/.scripts/20-runtime-repo.sh +71 -27
  53. package/templates/hermes-agent/template/.scripts/30-telegram.sh +3 -3
  54. package/templates/hermes-agent/template/.scripts/42-ticket-provider.sh +3 -3
  55. package/templates/hermes-agent/template/.scripts/70-systemd.sh +48 -43
  56. package/templates/hermes-agent/template/.scripts/80-registry.sh +2 -2
  57. package/templates/hermes-agent/template/.scripts/99-summary.sh +3 -4
  58. package/templates/hermes-agent/template/.scripts/_lib.sh +4 -19
  59. package/templates/hermes-agent/template/.scripts/checkpoint.sh +36 -0
  60. package/templates/hermes-agent/template/.scripts/config.example.toml +11 -5
  61. package/templates/hermes-agent/template/.scripts/{scrum-master/continuous-ticket-sentinel.sh → heartbeat.sh} +84 -31
  62. package/templates/hermes-agent/template/.scripts/lib/ticket-provider.sh +1 -1
  63. package/templates/hermes-agent/template/.scripts/providers/plane.sh +9 -3
  64. package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/bin/emit-event.py +5 -5
  65. package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/bin/issue-autonomous-review.sh +6 -6
  66. package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/bin/issue-close-gate.sh +2 -2
  67. package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/docs/autonomous-delegated-review.md +7 -7
  68. package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/docs/bloodbank-events.md +3 -3
  69. package/templates/hermes-agent/template/.scripts/{scrum-master → sentinel}/docs/continuous-ticket-orchestration.md +6 -6
  70. package/templates/hermes-agent/template/.scripts/{scrum-master/continuous-ticket-sentinel.prompt.md.jinja → sentinel.prompt.md.jinja} +5 -4
  71. package/templates/hermes-agent/template/SOUL.md.jinja +3 -6
  72. package/templates/hermes-agent/template/hermes.jinja +6 -15
  73. package/templates/hermes-agent/template/role.yaml.jinja +9 -8
  74. package/templates/commonproject/.claude/commands/bmad/bmb/agents/agent-builder.md +0 -14
  75. package/templates/commonproject/.claude/commands/bmad/bmb/agents/module-builder.md +0 -14
  76. package/templates/commonproject/.claude/commands/bmad/bmb/agents/workflow-builder.md +0 -14
  77. package/templates/commonproject/.claude/commands/bmad/bmb/workflows/agent.md +0 -5
  78. package/templates/commonproject/.claude/commands/bmad/bmb/workflows/module.md +0 -5
  79. package/templates/commonproject/.claude/commands/bmad/bmb/workflows/workflow.md +0 -5
  80. package/templates/commonproject/.claude/commands/bmad/bmm/agents/analyst.md +0 -14
  81. package/templates/commonproject/.claude/commands/bmad/bmm/agents/architect.md +0 -14
  82. package/templates/commonproject/.claude/commands/bmad/bmm/agents/dev.md +0 -14
  83. package/templates/commonproject/.claude/commands/bmad/bmm/agents/pm.md +0 -14
  84. package/templates/commonproject/.claude/commands/bmad/bmm/agents/quick-flow-solo-dev.md +0 -14
  85. package/templates/commonproject/.claude/commands/bmad/bmm/agents/sm.md +0 -14
  86. package/templates/commonproject/.claude/commands/bmad/bmm/agents/tea.md +0 -14
  87. package/templates/commonproject/.claude/commands/bmad/bmm/agents/tech-writer.md +0 -14
  88. package/templates/commonproject/.claude/commands/bmad/bmm/agents/ux-designer.md +0 -14
  89. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/check-implementation-readiness.md +0 -5
  90. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/code-review.md +0 -13
  91. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/correct-course.md +0 -13
  92. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-architecture.md +0 -5
  93. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-epics-and-stories.md +0 -5
  94. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-dataflow.md +0 -13
  95. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-diagram.md +0 -13
  96. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-flowchart.md +0 -13
  97. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-excalidraw-wireframe.md +0 -13
  98. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-product-brief.md +0 -5
  99. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-story.md +0 -13
  100. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/create-ux-design.md +0 -5
  101. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/dev-story.md +0 -13
  102. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/document-project.md +0 -13
  103. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/generate-project-context.md +0 -5
  104. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/prd.md +0 -5
  105. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/quick-dev.md +0 -5
  106. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/quick-spec.md +0 -5
  107. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/research.md +0 -5
  108. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/retrospective.md +0 -13
  109. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/sprint-planning.md +0 -13
  110. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/sprint-status.md +0 -13
  111. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-atdd.md +0 -13
  112. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-automate.md +0 -13
  113. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-ci.md +0 -13
  114. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-framework.md +0 -13
  115. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-nfr.md +0 -13
  116. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-test-design.md +0 -13
  117. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-test-review.md +0 -13
  118. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/testarch-trace.md +0 -13
  119. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/workflow-init.md +0 -13
  120. package/templates/commonproject/.claude/commands/bmad/bmm/workflows/workflow-status.md +0 -13
  121. package/templates/commonproject/.claude/commands/bmad/cis/agents/brainstorming-coach.md +0 -14
  122. package/templates/commonproject/.claude/commands/bmad/cis/agents/creative-problem-solver.md +0 -14
  123. package/templates/commonproject/.claude/commands/bmad/cis/agents/design-thinking-coach.md +0 -14
  124. package/templates/commonproject/.claude/commands/bmad/cis/agents/innovation-strategist.md +0 -14
  125. package/templates/commonproject/.claude/commands/bmad/cis/agents/presentation-master.md +0 -14
  126. package/templates/commonproject/.claude/commands/bmad/cis/agents/storyteller.md +0 -14
  127. package/templates/commonproject/.claude/commands/bmad/cis/workflows/design-thinking.md +0 -13
  128. package/templates/commonproject/.claude/commands/bmad/cis/workflows/innovation-strategy.md +0 -13
  129. package/templates/commonproject/.claude/commands/bmad/cis/workflows/problem-solving.md +0 -13
  130. package/templates/commonproject/.claude/commands/bmad/cis/workflows/storytelling.md +0 -13
  131. package/templates/commonproject/.claude/commands/bmad/core/agents/bmad-master.md +0 -14
  132. package/templates/commonproject/.claude/commands/bmad/core/tasks/index-docs.md +0 -9
  133. package/templates/commonproject/.claude/commands/bmad/core/tasks/shard-doc.md +0 -9
  134. package/templates/commonproject/.claude/commands/bmad/core/workflows/brainstorming.md +0 -5
  135. package/templates/commonproject/.claude/commands/bmad/core/workflows/party-mode.md +0 -5
  136. package/templates/commonproject/.claude/commands/bmad/custom/workflows/ticket-lifecycle.md +0 -5
  137. package/templates/hermes-agent/docs/scrum-master-sentinel.md +0 -17
  138. package/templates/hermes-agent/template/.scripts/75-scrum-master.sh +0 -117
  139. package/templates/hermes-agent/template/.scripts/90-chain-scrum-master.sh +0 -45
@@ -25,7 +25,7 @@ python3 - "$REGISTRY_FILE" "$AGENT_ID" "$REPO" "$ROLE" "$DISPLAY_NAME" \
25
25
  "$PLANE_WORKSPACE" "$PLANE_PROJECT_ID" "$(yaml_get plane.identifier)" \
26
26
  "$RUNTIME_REPO" "$HERMES_BIN" "$HERMES_AGENT_REPO" "$FLEET_ENV" \
27
27
  "hermes-${AGENT_ID}-gateway.service" "hermes-${AGENT_ID}-consumer.service" \
28
- "hermes-${AGENT_ID}-checkpoint.timer" <<'PYEOF'
28
+ "hermes-${AGENT_ID}-heartbeat.timer" <<'PYEOF'
29
29
  import sys, pathlib, datetime
30
30
  try:
31
31
  import yaml # type: ignore
@@ -44,7 +44,7 @@ data.setdefault("agents", {})[agent_id] = {
44
44
  "plane": {"workspace": plane_ws, "project_id": plane_id, "identifier": plane_ident},
45
45
  "runtime_repo": runtime_repo,
46
46
  "hermes": {"bin": hermes_bin, "repo": hermes_repo, "fleet_env": fleet_env},
47
- "systemd": {"gateway_unit": gw, "consumer_unit": csm, "checkpoint_timer": ckpt},
47
+ "systemd": {"gateway_unit": gw, "consumer_unit": csm, "heartbeat_timer": ckpt},
48
48
  "provisioned_at": datetime.datetime.utcnow().isoformat() + "Z",
49
49
  }
50
50
  p.write_text(yaml.safe_dump(data, sort_keys=False))
@@ -6,7 +6,7 @@ load_role_env
6
6
 
7
7
  GW_UNIT="hermes-${AGENT_ID}-gateway.service"
8
8
  CSM_UNIT="hermes-${AGENT_ID}-consumer.service"
9
- CKPT_TIMER="hermes-${AGENT_ID}-checkpoint.timer"
9
+ HB_TIMER="hermes-${AGENT_ID}-heartbeat.timer"
10
10
 
11
11
  cat >&2 <<EOF
12
12
 
@@ -14,16 +14,15 @@ cat >&2 <<EOF
14
14
 
15
15
  │ Talk: @$BOT_HANDLE (Telegram DM)
16
16
  │ Shell: $ROLE_DIR/hermes chat "status"
17
- │ Profile: $PROFILE_NAME (config inherits from default; secrets stay local)
18
17
  │ Board: $PLANE_BASE/$PLANE_WORKSPACE/projects/$(cat "$ROLE_DIR/.scripts/.plane-project-id" 2>/dev/null || echo "(skipped)")
19
- │ Runtime: gh:$RUNTIME_REPO (auto-checkpointed hourly)
18
+ │ Runtime: gh:$RUNTIME_REPO (reconcile + checkpoint heartbeat)
20
19
  │ Hermes bin: $HERMES_BIN
21
20
  │ Fleet env: $FLEET_ENV
22
21
 
23
22
  │ Start fleet daemons:
24
23
  │ systemctl --user start $GW_UNIT
25
24
  │ systemctl --user start $CSM_UNIT
26
- │ systemctl --user start $CKPT_TIMER
25
+ │ systemctl --user start $HB_TIMER
27
26
 
28
27
  │ Tail logs:
29
28
  │ journalctl --user -fu $GW_UNIT
@@ -147,15 +147,14 @@ if [[ -f "$FLEET_ENV" ]]; then
147
147
  fi
148
148
 
149
149
  # Tools we expect on the host
150
- HERMES_BIN="${HERMES_BIN:-${HERMES_FLEET_BIN:-$(config_get fleet.hermes_bin '/home/delorenj/code/hermes-agent/.venv/bin/hermes')}}"
151
- HERMES_AGENT_REPO="${HERMES_AGENT_REPO:-${HERMES_FLEET_REPO:-$(config_get fleet.hermes_repo '/home/delorenj/code/hermes-agent')}}"
150
+ HERMES_BIN="${HERMES_BIN:-${HERMES_FLEET_BIN:-$(config_get fleet.hermes_bin "$HOME/.hermes/hermes-agent/.venv/bin/hermes")}}"
151
+ HERMES_AGENT_REPO="${HERMES_AGENT_REPO:-${HERMES_FLEET_REPO:-$(config_get fleet.hermes_repo "$HOME/.hermes/hermes-agent")}}"
152
152
  HERMES_OAUTH_FILE="${HERMES_OAUTH_FILE:-${HERMES_FLEET_OAUTH_FILE:-$(config_get fleet.oauth_file "$HOME/.hermes/auth.json")}}"
153
153
  CODEX_HOME="${CODEX_HOME:-${HERMES_FLEET_CODEX_HOME:-$(config_get fleet.codex_home "$HOME/.codex")}}"
154
- FLEET_HOME="${HERMES_FLEET_HOME:-$(config_get fleet.home "$HOME/.hermes")}"
155
154
  # Prefer a scaffold vendored into this agent directory; fall back to the configured template path.
156
155
  RUNTIME_SCAFFOLD_DIR="${RUNTIME_SCAFFOLD_DIR:-$ROLE_DIR/.runtime-scaffold}"
157
156
  if [[ ! -d "$RUNTIME_SCAFFOLD_DIR" ]]; then
158
- RUNTIME_SCAFFOLD_DIR="${HERMES_TEMPLATE_RUNTIME_SCAFFOLD:-$(config_get fleet.runtime_scaffold_dir '/home/delorenj/code/hermes-agent-template/runtime-scaffold')}"
157
+ RUNTIME_SCAFFOLD_DIR="${HERMES_TEMPLATE_RUNTIME_SCAFFOLD:-$(config_get fleet.runtime_scaffold_dir "$HOME/code/hermes-agent-template/runtime-scaffold")}"
159
158
  fi
160
159
  REGISTRY_FILE="${REGISTRY_FILE:-${HERMES_FLEET_REGISTRY_FILE:-$(config_get fleet.registry_file "$HOME/.hermes/agents-registry.yaml")}}"
161
160
 
@@ -168,25 +167,11 @@ BLOODBANK_COMPOSE_DIR="${BLOODBANK_COMPOSE_DIR:-$(config_get bloodbank.compose_d
168
167
  PLANE_BASE="${PLANE_BASE:-$(config_get plane.base 'https://plane.delo.sh')}"
169
168
  PLANE_API_KEY="${PLANE_API_KEY:-${PLANE_33GOD_API_KEY:-}}"
170
169
 
171
- export FLEET_ENV HERMES_BIN HERMES_AGENT_REPO HERMES_OAUTH_FILE CODEX_HOME FLEET_HOME \
170
+ export FLEET_ENV HERMES_BIN HERMES_AGENT_REPO HERMES_OAUTH_FILE CODEX_HOME \
172
171
  RUNTIME_SCAFFOLD_DIR REGISTRY_FILE \
173
172
  BLOODBANK_NATS_HOST BLOODBANK_NATS_PORT BLOODBANK_COMPOSE_DIR \
174
173
  PLANE_BASE PLANE_API_KEY
175
174
 
176
- profile_home() {
177
- printf '%s/profiles/%s' "$FLEET_HOME" "$PROFILE_NAME"
178
- }
179
-
180
- profile_or_runtime_home() {
181
- local profile
182
- profile="$(profile_home)"
183
- if [[ -d "$profile" ]]; then
184
- printf '%s' "$profile"
185
- else
186
- printf '%s/runtime' "$ROLE_DIR"
187
- fi
188
- }
189
-
190
175
  # systemd --user health check. Accept running/degraded/starting — only one
191
176
  # broken unit shouldn't disqualify the rest of the user manager.
192
177
  systemd_user_available() {
@@ -1,6 +1,11 @@
1
1
  #!/usr/bin/env bash
2
2
  # Auto-checkpoint commit for the agent's runtime submodule.
3
3
  # Idempotent — exits 0 with no commit if there are no changes.
4
+ #
5
+ # Secret-scan gate (PJAN): before committing, the staged diff is scanned for
6
+ # high-signal credentials. On a hit the checkpoint ABORTS — it unstages, does
7
+ # NOT commit or push, logs loudly, and exits non-zero — so the known
8
+ # auto-commit secret-leak recurrence cannot re-leak through the heartbeat.
4
9
  set -euo pipefail
5
10
 
6
11
  RUNTIME_DIR="$(cd "$(dirname "$0")/../runtime" && pwd)"
@@ -9,9 +14,40 @@ cd "$RUNTIME_DIR"
9
14
  # Skip if not a git repo (e.g. submodule not initialized)
10
15
  [[ -d .git || -f .git ]] || exit 0
11
16
 
17
+ # Returns 0 when the staged diff looks clean, 1 when a likely secret is present.
18
+ secret_scan_ok() {
19
+ local added
20
+ added="$(git diff --cached -U0 --no-color 2>/dev/null | grep -E '^\+' | grep -vE '^\+\+\+ ' || true)"
21
+ [[ -n "$added" ]] || return 0
22
+
23
+ # Dependency-free, high-signal patterns (distinctive prefixes → ~zero false
24
+ # positives) over ADDED lines only.
25
+ if printf '%s\n' "$added" | grep -Eq \
26
+ 'AKIA[0-9A-Z]{16}|ASIA[0-9A-Z]{16}|-----BEGIN [A-Z ]*PRIVATE KEY-----|gh[posru]_[A-Za-z0-9]{20,}|xox[baprs]-[0-9A-Za-z-]{10,}|sk-[A-Za-z0-9]{20,}|glpat-[A-Za-z0-9_-]{20,}|AIza[0-9A-Za-z_-]{35}'; then
27
+ return 1
28
+ fi
29
+
30
+ # Deeper scan when gitleaks is installed (exit 1 == leaks found; other
31
+ # non-zero == tool/usage error, which we ignore so checkpoints aren't blocked).
32
+ if command -v gitleaks >/dev/null 2>&1; then
33
+ local rc=0
34
+ git diff --cached --no-color 2>/dev/null | gitleaks stdin --no-banner --redact >/dev/null 2>&1 || rc=$?
35
+ [[ "$rc" -eq 1 ]] && return 1
36
+ fi
37
+ return 0
38
+ }
39
+
12
40
  git add -A
13
41
  if git diff --cached --quiet; then
14
42
  exit 0
15
43
  fi
44
+
45
+ if ! secret_scan_ok; then
46
+ printf '[checkpoint] ABORT: potential secret in staged runtime changes — not committing/pushing.\n' >&2
47
+ printf '[checkpoint] Inspect: git -C %s diff --cached (remove the secret or add a .gitignore rule)\n' "$RUNTIME_DIR" >&2
48
+ git reset -q || true
49
+ exit 3
50
+ fi
51
+
16
52
  git -c commit.gpgsign=false commit -m "checkpoint $(date -Iseconds)" >/dev/null
17
53
  git push origin HEAD 2>&1 | tail -1 || true
@@ -11,15 +11,13 @@
11
11
  # somewhere other than $XDG_CONFIG_HOME/hermes-agent-template/config.toml.
12
12
 
13
13
  [fleet]
14
- # Root Hermes fleet home. Named profiles live under <home>/profiles/<name>.
15
- home = "~/.hermes"
16
14
  # Absolute path to the shared Hermes executable every agent launcher execs.
17
- hermes_bin = "/home/delorenj/code/hermes-agent/.venv/bin/hermes"
15
+ hermes_bin = "~/.hermes/hermes-agent/.venv/bin/hermes"
18
16
  # Checkout of the hermes-agent repo. Its .venv is used to install nats-py, etc.
19
- hermes_repo = "/home/delorenj/code/hermes-agent"
17
+ hermes_repo = "~/.hermes/hermes-agent"
20
18
  # Fallback runtime scaffold dir — used only when an agent's vendored
21
19
  # ./.runtime-scaffold is missing.
22
- runtime_scaffold_dir = "/home/delorenj/code/hermes-agent-template/runtime-scaffold"
20
+ runtime_scaffold_dir = "~/code/hermes-agent-template/runtime-scaffold"
23
21
  # Shared fleet source-of-truth env file + fleet registry. ~ is expanded.
24
22
  fleet_env = "~/.hermes/fleet.env"
25
23
  registry_file = "~/.hermes/agents-registry.yaml"
@@ -29,12 +27,20 @@ oauth_file = "~/.hermes/auth.json"
29
27
  codex_home = "~/.codex"
30
28
  # Canonical external skills dir mirrored into each agent profile.
31
29
  canonical_skills_dir = "/home/delorenj/.agents/skills"
30
+ # Voxxy plugin + service defaults for Hermes PM agents.
31
+ voxxy_plugin_dir = "~/code/voxxy/plugins/tts/voxxy"
32
+ vox_url = "https://vox.delo.sh"
33
+ # Canonical PM config.yaml the provisioner seeds each runtime's config.yaml from.
34
+ # This is the fleet-wide Hermes inference/skill config (model, toolsets, etc.)
35
+ # every agent runtime starts from. ~ is expanded.
36
+ # canonical_pm_config = "~/.hermes/config.yaml"
32
37
  # Skills symlinked into every agent's runtime skills root.
33
38
  symlinked_runtime_skills = [
34
39
  "delonet-conventions",
35
40
  "delonet-dotenv",
36
41
  "hermes-pm-template-maintenance",
37
42
  "hindsight",
43
+ "33god-projects",
38
44
  "subagent-driven-development",
39
45
  ]
40
46
 
@@ -1,21 +1,27 @@
1
1
  #!/usr/bin/env bash
2
- # Provider-agnostic continuous-ticket sentinel heartbeat (Scrum Master engine).
2
+ # Unified agent heartbeat: continuous board-reconciliation sentinel pass +
3
+ # gated runtime checkpoint, fused into one systemd-timer tick.
3
4
  #
4
- # Runs often (systemd timer). Only invokes Hermes when local state says no worker
5
- # is active, the worker heartbeat is stale, or the last full run is outside the
6
- # cooldown window. The full pass executes the role's
7
- # continuous-ticket-sentinel.prompt.md, which reasons about tickets through the
8
- # ticket-provider adapter (Linear | Plane | Trello) — never a hardcoded backend.
5
+ # Runs often (systemd timer, ~1 min). Only invokes Hermes for a full
6
+ # reconciliation pass when local state says no worker is active, the worker
7
+ # heartbeat is stale, or the last full run is outside the cooldown window. The
8
+ # full pass executes the role's sentinel.prompt.md, which reasons about tickets
9
+ # through the ticket-provider adapter (Linear | Plane | Trello) — never a
10
+ # hardcoded backend. After the sentinel decision (skip OR full), it
11
+ # opportunistically checkpoints the runtime submodule (commit+push) at most once
12
+ # per HEARTBEAT_CHECKPOINT_MIN_INTERVAL_SECONDS, so memory/session state stays
13
+ # durable without pushing every minute.
9
14
  set -euo pipefail
10
15
 
11
- ENGINE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # .scripts/scrum-master
12
- ROLE_DIR="$(cd "$ENGINE_DIR/../.." && pwd)"
16
+ ROLE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # agents/hermes/<role>
13
17
  RUNTIME="$ROLE_DIR/runtime"
14
- PROMPT_FILE="$ENGINE_DIR/continuous-ticket-sentinel.prompt.md"
18
+ PROMPT_FILE="$ROLE_DIR/.scripts/sentinel.prompt.md"
15
19
  STATE_FILE="$RUNTIME/continuous-ticket-sentinel-state.json"
16
20
  LOCK_FILE="$RUNTIME/continuous-ticket-sentinel.lock"
17
21
  ROLE_YAML="$ROLE_DIR/role.yaml"
18
- LOG_FILE="$RUNTIME/logs/continuous-ticket-sentinel.log"
22
+ LOG_FILE="$RUNTIME/logs/heartbeat.log"
23
+ CHECKPOINT_BIN="$ROLE_DIR/.scripts/checkpoint.sh"
24
+ CHECKPOINT_STAMP="$RUNTIME/.last-checkpoint"
19
25
 
20
26
  # Hermes binary: explicit env > ~/.config/hermes-agent/hermes-bin > PATH.
21
27
  HERMES_BIN="${HERMES_BIN:-}"
@@ -30,6 +36,24 @@ fi
30
36
  ACTIVE_MAX_IDLE_SECONDS="${SENTINEL_ACTIVE_MAX_IDLE_SECONDS:-600}"
31
37
  FULL_RUN_COOLDOWN_SECONDS="${SENTINEL_FULL_RUN_COOLDOWN_SECONDS:-300}"
32
38
  BLOCKED_FULL_RUN_COOLDOWN_SECONDS="${SENTINEL_BLOCKED_FULL_RUN_COOLDOWN_SECONDS:-900}"
39
+ CHECKPOINT_MIN_INTERVAL_SECONDS="${HEARTBEAT_CHECKPOINT_MIN_INTERVAL_SECONDS:-3600}"
40
+
41
+ # Opportunistic runtime checkpoint, fused into the heartbeat. Runs at most once
42
+ # per interval; checkpoint.sh is itself a no-op on a clean tree, so this only
43
+ # commits+pushes when there is genuinely new state AND enough time has passed
44
+ # since the last push. Never fails the heartbeat — checkpoint is best-effort.
45
+ maybe_checkpoint() {
46
+ [[ -x "$CHECKPOINT_BIN" ]] || return 0
47
+ local now last
48
+ now="$(date +%s)"
49
+ last="$(cat "$CHECKPOINT_STAMP" 2>/dev/null || echo 0)"
50
+ [[ "$last" =~ ^[0-9]+$ ]] || last=0
51
+ if (( now - last >= CHECKPOINT_MIN_INTERVAL_SECONDS )); then
52
+ printf '%s' "$now" > "$CHECKPOINT_STAMP" 2>/dev/null || true
53
+ printf '[heartbeat] checkpoint tick (>= %ss since last push)\n' "$CHECKPOINT_MIN_INTERVAL_SECONDS"
54
+ "$CHECKPOINT_BIN" || true
55
+ fi
56
+ }
33
57
 
34
58
  yaml_value() {
35
59
  python3 - "$ROLE_YAML" "$1" <<'PYEOF'
@@ -42,21 +66,37 @@ print(m.group(1).strip() if m else "")
42
66
  PYEOF
43
67
  }
44
68
 
69
+ yaml_block_value() {
70
+ python3 - "$ROLE_YAML" "$1" "$2" <<'PYEOF'
71
+ import re, sys
72
+ from pathlib import Path
73
+ path, block_name, key = sys.argv[1:4]
74
+ text = Path(path).read_text()
75
+ m = re.search(rf'(?m)^{re.escape(block_name)}:[ \t]*\n((?:[ \t]+\S.*\n?)*)', text)
76
+ block = m.group(1) if m else ""
77
+ me = re.search(rf'(?m)^[ \t]+{re.escape(key)}:[ \t]*([^\n#]*)', block)
78
+ value = me.group(1).strip() if me else ""
79
+ print(value.strip().strip('"').strip("'"))
80
+ PYEOF
81
+ }
82
+
83
+ # True only when role.yaml has a reconcile: block with enabled: true. Block-aware
84
+ # so an unrelated `enabled:` leaf elsewhere in the file can't flip it on.
85
+ reconcile_enabled() {
86
+ python3 - "$ROLE_YAML" <<'PYEOF'
87
+ import re, sys
88
+ from pathlib import Path
89
+ text = Path(sys.argv[1]).read_text()
90
+ m = re.search(r'(?m)^reconcile:[ \t]*\n((?:[ \t]+\S.*\n?)*)', text)
91
+ block = m.group(1) if m else ""
92
+ me = re.search(r'(?m)^[ \t]+enabled:[ \t]*"?([A-Za-z]+)"?', block)
93
+ print("true" if (me and me.group(1).lower() == "true") else "false")
94
+ PYEOF
95
+ }
96
+
45
97
  AGENT_ID="$(yaml_value agent_id)"
46
98
  REPO_NAME="$(yaml_value repo)"
47
- PROFILE_NAME="$(yaml_value profile)"
48
- PROVIDER="$(yaml_value name)" # ticket_provider.name leaf
49
- [[ -n "$PROFILE_NAME" ]] || PROFILE_NAME="$AGENT_ID"
50
- FLEET_HOME="${HERMES_FLEET_HOME:-$HOME/.hermes}"
51
- PROFILE_HOME="$FLEET_HOME/profiles/$PROFILE_NAME"
52
- HERMES_PROFILE_HOME="${HERMES_HOME:-}"
53
- if [[ -z "$HERMES_PROFILE_HOME" ]]; then
54
- if [[ -d "$PROFILE_HOME" ]]; then
55
- HERMES_PROFILE_HOME="$PROFILE_HOME"
56
- else
57
- HERMES_PROFILE_HOME="$RUNTIME"
58
- fi
59
- fi
99
+ PROVIDER="$(yaml_block_value ticket_provider name)"
60
100
 
61
101
  repo_root() {
62
102
  local dir="$ROLE_DIR"
@@ -75,7 +115,7 @@ mkdir -p "$RUNTIME/logs"
75
115
  if command -v flock >/dev/null 2>&1; then
76
116
  exec 9>"$LOCK_FILE"
77
117
  if ! flock -n 9; then
78
- printf '[sentinel] another heartbeat/full run is active; skipping\n'; exit 0
118
+ printf '[heartbeat] another heartbeat/full run is active; skipping\n'; exit 0
79
119
  fi
80
120
  else
81
121
  LOCK_DIR="$LOCK_FILE.d"
@@ -83,14 +123,24 @@ else
83
123
  # Steal a stale lock older than 60 minutes (a crashed run left it behind).
84
124
  if [ -n "$(find "$LOCK_DIR" -maxdepth 0 -mmin +60 2>/dev/null)" ]; then
85
125
  rmdir "$LOCK_DIR" 2>/dev/null && mkdir "$LOCK_DIR" 2>/dev/null \
86
- || { printf '[sentinel] another run active; skipping\n'; exit 0; }
126
+ || { printf '[heartbeat] another run active; skipping\n'; exit 0; }
87
127
  else
88
- printf '[sentinel] another heartbeat/full run is active; skipping\n'; exit 0
128
+ printf '[heartbeat] another heartbeat/full run is active; skipping\n'; exit 0
89
129
  fi
90
130
  fi
91
131
  trap 'rmdir "$LOCK_DIR" 2>/dev/null' EXIT
92
132
  fi
93
133
 
134
+ # Reconcile gate: the autonomous board-reconciliation pass runs only when
135
+ # role.yaml's reconcile.enabled is true. Default off → the heartbeat just
136
+ # checkpoints (behaves like the legacy hourly checkpoint timer). Flip
137
+ # reconcile.enabled to opt a repo into autonomous board reconciliation.
138
+ if [[ "$(reconcile_enabled)" != "true" ]]; then
139
+ printf '[heartbeat] reconcile disabled (reconcile.enabled != true) — checkpoint-only tick\n'
140
+ maybe_checkpoint
141
+ exit 0
142
+ fi
143
+
94
144
  decision="$(
95
145
  python3 - "$STATE_FILE" "$ACTIVE_MAX_IDLE_SECONDS" "$FULL_RUN_COOLDOWN_SECONDS" "$BLOCKED_FULL_RUN_COOLDOWN_SECONDS" <<'PYEOF'
96
146
  import json, subprocess, sys, time
@@ -157,7 +207,9 @@ state.update({"source":"hermes-continuous-ticket-sentinel","agent_id":agent_id,"
157
207
  state.setdefault("updated_at", now_iso); state.setdefault("summary", state.get("reason") or decision)
158
208
  tmp = path.with_suffix(path.suffix + ".tmp"); tmp.write_text(json.dumps(state, indent=2, sort_keys=True)+"\n"); tmp.replace(path)
159
209
  PYEOF
160
- printf '[sentinel] %s\n' "$decision"; exit 0
210
+ printf '[heartbeat] %s\n' "$decision"
211
+ maybe_checkpoint
212
+ exit 0
161
213
  ;;
162
214
  esac
163
215
 
@@ -170,7 +222,7 @@ state = json.loads(path.read_text()) if path.exists() else {}
170
222
  now = time.time()
171
223
  state.update({"source":"hermes-continuous-ticket-sentinel","agent_id":agent_id,"repo":repo,
172
224
  "ticket_provider":provider,"status":"checking",
173
- "summary":"Scrum Master is reconciling the ticket board, evidence, and worker state.",
225
+ "summary":"PM is reconciling the ticket board, evidence, and worker state.",
174
226
  "log_path":log_path,"last_heartbeat_at":datetime.fromtimestamp(now,timezone.utc).isoformat(),
175
227
  "last_decision":decision,"last_full_run_epoch":now,
176
228
  "last_full_run_started_at":datetime.fromtimestamp(now,timezone.utc).isoformat()})
@@ -179,7 +231,7 @@ PYEOF
179
231
 
180
232
  prompt="$(<"$PROMPT_FILE")"
181
233
  set +e
182
- env HERMES_HOME="$HERMES_PROFILE_HOME" "$HERMES_BIN" chat -Q --source cron --max-turns 90 -q "$prompt"
234
+ env HERMES_HOME="$RUNTIME" "$HERMES_BIN" chat -Q --source cron --max-turns 90 -q "$prompt"
183
235
  status=$?
184
236
  set -e
185
237
 
@@ -197,11 +249,12 @@ state["last_runner_exit_code"] = exit_code; state["last_runner_completed_at"] =
197
249
  state.setdefault("last_full_run_epoch", time.time())
198
250
  if state.get("status") == "checking":
199
251
  state["status"] = "idle" if exit_code == 0 else "error"
200
- state["summary"] = ("Scrum Master completed the reconciliation pass without claiming work."
201
- if exit_code == 0 else "Scrum Master reconciliation failed; inspect the sentinel log.")
252
+ state["summary"] = ("PM completed the reconciliation pass without claiming work."
253
+ if exit_code == 0 else "PM reconciliation failed; inspect the heartbeat log.")
202
254
  state.setdefault("updated_at", now_iso)
203
255
  tmp = path.with_suffix(path.suffix + ".tmp"); tmp.write_text(json.dumps(state, indent=2, sort_keys=True)+"\n"); tmp.replace(path)
204
256
  print(0 if state.get("status") in {"active","blocked","stalled","idle"} else exit_code)
205
257
  PYEOF
206
258
  )"
259
+ maybe_checkpoint
207
260
  exit "$runner_exit"
@@ -1,5 +1,5 @@
1
1
  # shellcheck shell=bash
2
- # Ticket-provider adapter dispatcher — the single seam between the Scrum Master
2
+ # Ticket-provider adapter dispatcher — the single seam between the heartbeat
3
3
  # sentinel engine and a concrete ticket system (Linear | Plane | Trello).
4
4
  #
5
5
  # The engine NEVER calls a provider directly. It calls `tp <op> [args...]`,
@@ -179,10 +179,16 @@ print(json.dumps({"id":i.get("id",""),"key":i.get("sequence_id",""),"title":i.ge
179
179
  create_board)
180
180
  NAME="${1:?usage: create_board <name> <ident> <desc>}"; IDENT="${2:-}"; DESC="${3:-}"
181
181
  [ -n "$WS" ] || die "workspace not set"
182
- EXIST="$(api GET "projects/?per_page=200" | IDENT="$IDENT" python3 -c 'import sys,json,os
182
+ EXIST="$(api GET "projects/?per_page=200" | NAME="$NAME" IDENT="$IDENT" python3 -c 'import sys,json,os
183
183
  d=json.load(sys.stdin); rows=d.get("results", d if isinstance(d,list) else [])
184
- ident=os.environ["IDENT"].upper()
185
- print(next((p["id"] for p in rows if (p.get("identifier") or "").upper()==ident), ""))')"
184
+ name=os.environ["NAME"].strip().lower(); ident=os.environ["IDENT"].upper()
185
+ # Repo NAME is the primary key links an existing repo board even if its
186
+ # identifier differs (Plane does not enforce unique names, so this prevents
187
+ # duplicate boards). Fall back to identifier match; empty -> create new.
188
+ pid=next((p["id"] for p in rows if str(p.get("name","")).strip().lower()==name), "")
189
+ if not pid and ident:
190
+ pid=next((p["id"] for p in rows if (p.get("identifier") or "").upper()==ident), "")
191
+ print(pid)')"
186
192
  if [ -n "$EXIST" ]; then PID="$EXIST"; else
187
193
  PID="$(api POST "projects/" \
188
194
  "$(python3 -c 'import json,sys; print(json.dumps({"name":sys.argv[1],"identifier":sys.argv[2],"description":sys.argv[3]}))' "$NAME" "$IDENT" "$DESC")" \
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env python3
2
2
  """Emit a local BloodBank-style CloudEvents envelope (provider-agnostic).
3
3
 
4
- Dependency-free. Appends JSONL locally so the Scrum Master engine records an
4
+ Dependency-free. Appends JSONL locally so the sentinel engine records an
5
5
  event trail even when NATS/BloodBank is offline. Identical envelope shape to the
6
- Hermes gateway; see .scripts/scrum-master/docs/bloodbank-events.md.
6
+ Hermes gateway; see .scripts/sentinel/docs/bloodbank-events.md.
7
7
  """
8
8
  from __future__ import annotations
9
9
 
@@ -55,8 +55,8 @@ def main() -> int:
55
55
  parser.add_argument("--field", action="append", type=parse_field, default=[])
56
56
  parser.add_argument("--data-json")
57
57
  parser.add_argument("--source")
58
- parser.add_argument("--producer", default=os.environ.get("BLOODBANK_PRODUCER", "local-script:scrum-master"))
59
- parser.add_argument("--service", default=os.environ.get("BLOODBANK_SERVICE", "hermes-scrum-master"))
58
+ parser.add_argument("--producer", default=os.environ.get("BLOODBANK_PRODUCER", "local-script:sentinel"))
59
+ parser.add_argument("--service", default=os.environ.get("BLOODBANK_SERVICE", "hermes-sentinel"))
60
60
  parser.add_argument("--actor-id", default=os.environ.get("BLOODBANK_ACTOR_ID", os.environ.get("USER", "local-agent")))
61
61
  parser.add_argument("--actor-cli", default=os.environ.get("BLOODBANK_ACTOR_CLI", "script"))
62
62
  parser.add_argument("--correlation-id", default=os.environ.get("BLOODBANK_CORRELATION_ID"))
@@ -75,7 +75,7 @@ def main() -> int:
75
75
  if not log_path.is_absolute():
76
76
  log_path = root / log_path
77
77
 
78
- source = args.source or "repo://scrum-master/bin/emit-event.py"
78
+ source = args.source or "repo://sentinel/bin/emit-event.py"
79
79
  event = {
80
80
  "specversion": "1.0",
81
81
  "type": args.event_type,
@@ -17,7 +17,7 @@
17
17
  # ticket-provider adapter (tp transition <id> completed), so the same logic works
18
18
  # on Linear | Plane | Trello.
19
19
  #
20
- # Protocol: .scripts/scrum-master/docs/autonomous-delegated-review.md
20
+ # Protocol: .scripts/sentinel/docs/autonomous-delegated-review.md
21
21
  #
22
22
  # Usage: issue-autonomous-review.sh ISSUE_ID REPORT_FILE [--close]
23
23
  #
@@ -33,7 +33,7 @@ ISSUE="$1"; REPORT="$2"; CLOSE=0
33
33
  case "$ISSUE" in *[!A-Za-z0-9_-]*) printf 'Invalid issue id: %s\n' "$ISSUE" >&2; exit 2 ;; esac
34
34
 
35
35
  BIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
36
- ENGINE_DIR="$(cd "$BIN_DIR/.." && pwd)" # .scripts/scrum-master
36
+ ENGINE_DIR="$(cd "$BIN_DIR/.." && pwd)" # .scripts/sentinel
37
37
  SCRIPTS_DIR="$(cd "$ENGINE_DIR/.." && pwd)" # .scripts
38
38
  ROLE_DIR="$(cd "$SCRIPTS_DIR/.." && pwd)"
39
39
  ROLE_YAML="$ROLE_DIR/role.yaml"
@@ -48,12 +48,12 @@ yget() { sed -n "s/^[[:space:]]*$1:[[:space:]]*//p" "$ROLE_YAML" 2>/dev/null | h
48
48
  REPO="$(yget repo)"; REPO="${REPO:-unknown}"
49
49
  # Informational only: recorded in the decision event/comment, never a blocking
50
50
  # wait. Default 0 (no grace); an operator may set grace_hours>0 to reintroduce one.
51
- GRACE_HOURS="${DRUMJANGLER_AUTO_REVIEW_GRACE_HOURS:-$(yget grace_hours)}"; GRACE_HOURS="${GRACE_HOURS:-0}"
51
+ GRACE_HOURS="${RECONCILE_GRACE_HOURS:-$(yget grace_hours)}"; GRACE_HOURS="${GRACE_HOURS:-0}"
52
52
  AUTO="$(yget auto_review)"; AUTO="${AUTO:-true}"
53
53
  EVT="bloodbank.v1.repo.$REPO.issue.autonomous_review.decided"
54
54
 
55
- if [[ "${SCRUM_MASTER_AUTO_REVIEW:-$AUTO}" == "false" || "${SCRUM_MASTER_AUTO_REVIEW:-}" == "off" ]]; then
56
- printf 'Autonomous review is disabled (scrum_master.auto_review=false).\n' >&2; exit 3
55
+ if [[ "${RECONCILE_AUTO_REVIEW:-$AUTO}" == "false" || "${RECONCILE_AUTO_REVIEW:-}" == "off" ]]; then
56
+ printf 'Autonomous review is disabled (reconcile.auto_review=false).\n' >&2; exit 3
57
57
  fi
58
58
  [[ -f "$REPORT" ]] || { printf 'Missing review report file: %s\n' "$REPORT" >&2; exit 2; }
59
59
  [[ -f "$EVIDENCE" ]] || { printf 'Missing issue evidence file: %s\n' "$EVIDENCE" >&2; exit 2; }
@@ -86,7 +86,7 @@ if sh "$CLOSE_GATE" "$ISSUE" "$ROOT" >/dev/null 2>&1 </dev/null; then GATE=pass;
86
86
  if [[ -n "$HOLD" ]]; then DECISION=held; else DECISION=accepted; fi
87
87
 
88
88
  python3 "$EMIT" "$EVT" --root "$ROOT" \
89
- --source "repo://scrum-master/bin/issue-autonomous-review.sh" --actor-id "$REVIEWER" \
89
+ --source "repo://sentinel/bin/issue-autonomous-review.sh" --actor-id "$REVIEWER" \
90
90
  --field issue="$ISSUE" --field decision="$DECISION" --field drift="$DRIFT" \
91
91
  --field close_gate="$GATE" --field reviewer_agent="$REVIEWER" \
92
92
  --field evidence_file="$EVIDENCE" --field report_file="$REPORT" \
@@ -50,13 +50,13 @@ grep -q 'Close recommendation: ready' "$FILE" || { printf 'Close recommendation
50
50
 
51
51
  if [ "$FAIL" -ne 0 ]; then
52
52
  python3 "$EMIT" "$EVT_PREFIX.gate.failed" --root "$ROOT" \
53
- --source "repo://scrum-master/bin/issue-close-gate.sh" \
53
+ --source "repo://sentinel/bin/issue-close-gate.sh" \
54
54
  --field issue="$ISSUE" --field evidence_file="$FILE" --quiet </dev/null || true
55
55
  printf '\nCLOSE GATE: FAIL for %s\n' "$ISSUE" >&2
56
56
  exit 1
57
57
  fi
58
58
 
59
59
  python3 "$EMIT" "$EVT_PREFIX.gate.passed" --root "$ROOT" \
60
- --source "repo://scrum-master/bin/issue-close-gate.sh" \
60
+ --source "repo://sentinel/bin/issue-close-gate.sh" \
61
61
  --field issue="$ISSUE" --field evidence_file="$FILE" --quiet </dev/null || true
62
62
  printf 'CLOSE GATE: PASS for %s\n' "$ISSUE"
@@ -1,10 +1,10 @@
1
1
  # Autonomous adversarial review (act, do not wait)
2
2
 
3
- Status: Scrum Master engine protocol (provider-agnostic)
3
+ Status: sentinel engine protocol (provider-agnostic)
4
4
 
5
5
  ## Purpose
6
6
 
7
- When a ticket reaches the review lane, the Scrum Master sentinel runs an
7
+ When a ticket reaches the review lane, the sentinel runs an
8
8
  **independent adversarial review** of the work against the operator's locked
9
9
  intent and acts on the verdict autonomously. This is the **normal per-pass
10
10
  path** for review-lane tickets — not a deliberately narrow escape hatch, and not
@@ -55,8 +55,8 @@ exactly as before:
55
55
  the implementer recorded in the evidence (`Worker:` / `Implemented by:`) and
56
56
  from the delegating PM. An implementer NEVER clears their own work.
57
57
 
58
- There is no mandatory grace window. `scrum_master.grace_hours` (role.yaml;
59
- override env `DRUMJANGLER_AUTO_REVIEW_GRACE_HOURS`) defaults to `0` and is an
58
+ There is no mandatory grace window. `reconcile.grace_hours` (role.yaml;
59
+ override env `RECONCILE_GRACE_HOURS`) defaults to `0` and is an
60
60
  optional operator knob only — set `>0` to reintroduce a wait. The reviewer does
61
61
  not wait for the operator's first right of refusal; it reviews and acts.
62
62
 
@@ -84,7 +84,7 @@ Only `none`/`minor` with no unresolved critical/high findings may be accepted.
84
84
  Run from the role's bin (couples gate + drift + event + acceptance):
85
85
 
86
86
  ```bash
87
- .scripts/scrum-master/bin/issue-autonomous-review.sh <ISSUE> <REPORT>
87
+ .scripts/sentinel/bin/issue-autonomous-review.sh <ISSUE> <REPORT>
88
88
  ```
89
89
 
90
90
  - **accepted** — independent adversarial review cleared it (drift `none|minor`,
@@ -109,7 +109,7 @@ operator's deferred-QA queue — and is NOT auto-transitioned to `completed`.
109
109
  loop:
110
110
 
111
111
  ```bash
112
- .scripts/scrum-master/bin/issue-autonomous-review.sh <ISSUE> <REPORT> --close
112
+ .scripts/sentinel/bin/issue-autonomous-review.sh <ISSUE> <REPORT> --close
113
113
  ```
114
114
 
115
115
  ## Decision event
@@ -162,7 +162,7 @@ Write `<ISSUE>.review.md`; the script validates it:
162
162
 
163
163
  ## Operator override
164
164
 
165
- `scrum_master.auto_review: false` (role.yaml) or `SCRUM_MASTER_AUTO_REVIEW=off`
165
+ `reconcile.auto_review: false` (role.yaml) or `RECONCILE_AUTO_REVIEW=off`
166
166
  disables autonomous acceptance. Autonomous acceptances are fully traceable via
167
167
  the decision events in
168
168
  `_bmad-output/implementation-artifacts/bloodbank-events.jsonl`.
@@ -1,6 +1,6 @@
1
- # Scrum Master workflow events
1
+ # Sentinel workflow events
2
2
 
3
- Status: Scrum Master engine protocol (provider-agnostic)
3
+ Status: Sentinel engine protocol (provider-agnostic)
4
4
 
5
5
  ## Purpose
6
6
 
@@ -12,7 +12,7 @@ what happened.
12
12
  ## Emitter
13
13
 
14
14
  ```bash
15
- .scripts/scrum-master/bin/emit-event.py <event_type> --field key=value [...]
15
+ .scripts/sentinel/bin/emit-event.py <event_type> --field key=value [...]
16
16
  ```
17
17
 
18
18
  Appends to `_bmad-output/implementation-artifacts/bloodbank-events.jsonl`
@@ -1,15 +1,15 @@
1
- # Continuous ticket orchestration (Scrum Master engine)
1
+ # Continuous ticket orchestration (sentinel engine)
2
2
 
3
- Status: Scrum Master engine protocol (provider-agnostic)
3
+ Status: sentinel engine protocol (provider-agnostic)
4
4
 
5
5
  ## Invariant
6
6
 
7
7
  If a ready ticket exists, exactly one implementation worker must be actively
8
- moving it, or the Scrum Master records why none can. Prefer one live thread over
8
+ moving it, or the sentinel records why none can. Prefer one live thread over
9
9
  a quiet backlog. WIP limit: one active worker ticket.
10
10
 
11
- The Scrum Master owns the watch loop. Workers (codex, opencode, copilot, …) own
12
- implementation. The Scrum Master clears review-lane work via the autonomous
11
+ The sentinel owns the watch loop. Workers (codex, opencode, copilot, …) own
12
+ implementation. The sentinel clears review-lane work via the autonomous
13
13
  adversarial review (act, do not wait) protocol
14
14
  (`autonomous-delegated-review.md`), and still does not write application code or
15
15
  approve merges.
@@ -61,7 +61,7 @@ The loop never ends a pass with work parked waiting on the operator.
61
61
  ## Review and closure
62
62
 
63
63
  1. Run ticket verification.
64
- 2. Run the close gate: `.scripts/scrum-master/bin/issue-close-gate.sh <ISSUE>`.
64
+ 2. Run the close gate: `.scripts/sentinel/bin/issue-close-gate.sh <ISSUE>`.
65
65
  3. Run the independent adversarial review — an adversarial microscope, with the
66
66
  reviewer agent NOT the implementer (`autonomous-delegated-review.md`). On a
67
67
  clean adversarial verdict the loop autonomously treats the ticket as done
@@ -6,9 +6,10 @@ A cheap systemd heartbeat already decided this full pass is needed.
6
6
  Working repo: the git root containing this role at `agents/hermes/{{ role }}/`.
7
7
  Ticket provider: **{{ ticket_provider }}** (reached only through the adapter — see below).
8
8
 
9
- You are the **{{ target_repo }} Scrum Master**. Act autonomously, but stay inside
10
- the project contracts. Read `agents/hermes/{{ role }}/SOUL.md` and the engine
11
- docs under `.scripts/scrum-master/docs/` before acting:
9
+ You are the **{{ target_repo }} PM**, running your continuous board-reconciliation
10
+ pass. Act autonomously, but stay inside the project contracts. Read
11
+ `agents/hermes/{{ role }}/SOUL.md` and the engine docs under
12
+ `.scripts/sentinel/docs/` before acting:
12
13
  `continuous-ticket-orchestration.md`, `autonomous-delegated-review.md`,
13
14
  `bloodbank-events.md`.
14
15
 
@@ -46,7 +47,7 @@ on Linear, Plane, or Trello.
46
47
  independent reviewer and have it run, as a rigorous adversarial review:
47
48
 
48
49
  ```bash
49
- .scripts/scrum-master/bin/issue-autonomous-review.sh <ISSUE> <REPORT>
50
+ .scripts/sentinel/bin/issue-autonomous-review.sh <ISSUE> <REPORT>
50
51
  ```
51
52
 
52
53
  (NO `--close`.) This is an adversarial microscope: it holds the work against