feed-the-machine 1.6.1 → 1.7.1

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 (272) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +262 -170
  3. package/bin/__pycache__/tasks_db.cpython-314.pyc +0 -0
  4. package/bin/brain.py +1340 -0
  5. package/bin/convert_claude_skills_to_codex.py +490 -0
  6. package/bin/generate-manifest.mjs +463 -463
  7. package/bin/harden_codex_skills.py +141 -0
  8. package/bin/install.mjs +491 -491
  9. package/bin/migrate-eng-buddy-data.py +875 -0
  10. package/bin/playbook_engine/__init__.py +1 -0
  11. package/bin/playbook_engine/conftest.py +8 -0
  12. package/bin/playbook_engine/extractor.py +33 -0
  13. package/bin/playbook_engine/manager.py +102 -0
  14. package/bin/playbook_engine/models.py +84 -0
  15. package/bin/playbook_engine/registry.py +35 -0
  16. package/bin/playbook_engine/test_extractor.py +72 -0
  17. package/bin/playbook_engine/test_integration.py +129 -0
  18. package/bin/playbook_engine/test_manager.py +85 -0
  19. package/bin/playbook_engine/test_models.py +166 -0
  20. package/bin/playbook_engine/test_registry.py +67 -0
  21. package/bin/playbook_engine/test_tracer.py +86 -0
  22. package/bin/playbook_engine/tracer.py +93 -0
  23. package/bin/tasks_db.py +456 -0
  24. package/docs/HOOKS.md +243 -243
  25. package/docs/INBOX.md +233 -233
  26. package/ftm/SKILL.md +125 -122
  27. package/ftm-audit/SKILL.md +673 -623
  28. package/ftm-audit/references/protocols/PROJECT-PATTERNS.md +91 -91
  29. package/ftm-audit/references/protocols/RUNTIME-WIRING.md +66 -66
  30. package/ftm-audit/references/protocols/WIRING-CONTRACTS.md +135 -135
  31. package/ftm-audit/references/strategies/AUTO-FIX-STRATEGIES.md +69 -69
  32. package/ftm-audit/references/templates/REPORT-FORMAT.md +96 -96
  33. package/ftm-audit/scripts/run-knip.sh +23 -23
  34. package/ftm-audit.yml +2 -2
  35. package/ftm-brainstorm/SKILL.md +1003 -498
  36. package/ftm-brainstorm/evals/evals.json +180 -100
  37. package/ftm-brainstorm/evals/promptfoo.yaml +109 -109
  38. package/ftm-brainstorm/references/agent-prompts.md +552 -224
  39. package/ftm-brainstorm/references/plan-template.md +209 -121
  40. package/ftm-brainstorm.yml +2 -2
  41. package/ftm-browse/SKILL.md +454 -454
  42. package/ftm-browse/daemon/browser-manager.ts +206 -206
  43. package/ftm-browse/daemon/bun.lock +30 -30
  44. package/ftm-browse/daemon/cli.ts +347 -347
  45. package/ftm-browse/daemon/commands.ts +410 -410
  46. package/ftm-browse/daemon/main.ts +357 -357
  47. package/ftm-browse/daemon/package.json +17 -17
  48. package/ftm-browse/daemon/server.ts +189 -189
  49. package/ftm-browse/daemon/snapshot.ts +519 -519
  50. package/ftm-browse/daemon/tsconfig.json +22 -22
  51. package/ftm-browse.yml +4 -4
  52. package/ftm-capture/SKILL.md +370 -370
  53. package/ftm-capture.yml +4 -4
  54. package/ftm-codex-gate/SKILL.md +361 -361
  55. package/ftm-codex-gate.yml +2 -2
  56. package/ftm-config/SKILL.md +422 -345
  57. package/ftm-config.default.yml +125 -82
  58. package/ftm-config.yml +44 -2
  59. package/ftm-council/SKILL.md +416 -416
  60. package/ftm-council/references/prompts/CLAUDE-INVESTIGATION.md +60 -60
  61. package/ftm-council/references/prompts/CODEX-INVESTIGATION.md +58 -58
  62. package/ftm-council/references/prompts/GEMINI-INVESTIGATION.md +58 -58
  63. package/ftm-council/references/prompts/REBUTTAL-TEMPLATE.md +57 -57
  64. package/ftm-council/references/protocols/PREREQUISITES.md +47 -47
  65. package/ftm-council/references/protocols/STEP-0-FRAMING.md +46 -46
  66. package/ftm-council-chat.yml +2 -0
  67. package/ftm-council.yml +2 -2
  68. package/ftm-dashboard/SKILL.md +163 -163
  69. package/ftm-dashboard.yml +4 -4
  70. package/ftm-debug/SKILL.md +1037 -1037
  71. package/ftm-debug/references/phases/PHASE-0-INTAKE.md +58 -58
  72. package/ftm-debug/references/phases/PHASE-1-TRIAGE.md +46 -46
  73. package/ftm-debug/references/phases/PHASE-2-WAR-ROOM-AGENTS.md +279 -279
  74. package/ftm-debug/references/phases/PHASE-3-TO-6-EXECUTION.md +436 -436
  75. package/ftm-debug/references/protocols/BLACKBOARD.md +86 -86
  76. package/ftm-debug/references/protocols/EDGE-CASES.md +103 -103
  77. package/ftm-debug.yml +2 -2
  78. package/ftm-diagram/SKILL.md +277 -277
  79. package/ftm-diagram.yml +2 -2
  80. package/ftm-executor/SKILL.md +777 -777
  81. package/ftm-executor/references/STYLE-TEMPLATE.md +73 -73
  82. package/ftm-executor/references/phases/PHASE-0-VERIFICATION.md +62 -62
  83. package/ftm-executor/references/phases/PHASE-2-AGENT-ASSEMBLY.md +34 -34
  84. package/ftm-executor/references/phases/PHASE-3-WORKTREES.md +38 -38
  85. package/ftm-executor/references/phases/PHASE-4-5-AUDIT.md +81 -72
  86. package/ftm-executor/references/phases/PHASE-4-DISPATCH.md +66 -66
  87. package/ftm-executor/references/phases/PHASE-5-5-CODEX-GATE.md +73 -73
  88. package/ftm-executor/references/protocols/DOCUMENTATION-BOOTSTRAP.md +36 -36
  89. package/ftm-executor/references/protocols/MODEL-PROFILE.md +59 -59
  90. package/ftm-executor/references/protocols/PROGRESS-TRACKING.md +66 -66
  91. package/ftm-executor/runtime/ftm-runtime.mjs +252 -252
  92. package/ftm-executor/runtime/package.json +8 -8
  93. package/ftm-executor.yml +2 -2
  94. package/ftm-git/SKILL.md +441 -441
  95. package/ftm-git/evals/evals.json +26 -26
  96. package/ftm-git/evals/promptfoo.yaml +75 -75
  97. package/ftm-git/hooks/post-commit-experience.sh +92 -92
  98. package/ftm-git/references/patterns/SECRET-PATTERNS.md +104 -104
  99. package/ftm-git/references/protocols/REMEDIATION.md +139 -139
  100. package/ftm-git/scripts/pre-commit-secrets.sh +110 -110
  101. package/ftm-git.yml +2 -2
  102. package/ftm-inbox/backend/__pycache__/main.cpython-314.pyc +0 -0
  103. package/ftm-inbox/backend/adapters/_retry.py +64 -64
  104. package/ftm-inbox/backend/adapters/base.py +230 -230
  105. package/ftm-inbox/backend/adapters/freshservice.py +104 -104
  106. package/ftm-inbox/backend/adapters/gmail.py +125 -125
  107. package/ftm-inbox/backend/adapters/jira.py +136 -136
  108. package/ftm-inbox/backend/adapters/registry.py +192 -192
  109. package/ftm-inbox/backend/adapters/slack.py +110 -110
  110. package/ftm-inbox/backend/db/connection.py +54 -54
  111. package/ftm-inbox/backend/db/schema.py +78 -78
  112. package/ftm-inbox/backend/executor/__init__.py +7 -7
  113. package/ftm-inbox/backend/executor/engine.py +149 -149
  114. package/ftm-inbox/backend/executor/step_runner.py +98 -98
  115. package/ftm-inbox/backend/main.py +103 -103
  116. package/ftm-inbox/backend/models/__init__.py +1 -1
  117. package/ftm-inbox/backend/models/unified_task.py +36 -36
  118. package/ftm-inbox/backend/planner/__init__.py +6 -6
  119. package/ftm-inbox/backend/planner/__pycache__/__init__.cpython-314.pyc +0 -0
  120. package/ftm-inbox/backend/planner/__pycache__/generator.cpython-314.pyc +0 -0
  121. package/ftm-inbox/backend/planner/__pycache__/schema.cpython-314.pyc +0 -0
  122. package/ftm-inbox/backend/planner/generator.py +127 -127
  123. package/ftm-inbox/backend/planner/schema.py +34 -34
  124. package/ftm-inbox/backend/requirements.txt +5 -5
  125. package/ftm-inbox/backend/routes/__pycache__/plan.cpython-314.pyc +0 -0
  126. package/ftm-inbox/backend/routes/execute.py +186 -186
  127. package/ftm-inbox/backend/routes/health.py +52 -52
  128. package/ftm-inbox/backend/routes/inbox.py +68 -68
  129. package/ftm-inbox/backend/routes/plan.py +271 -271
  130. package/ftm-inbox/bin/launchagent.mjs +91 -91
  131. package/ftm-inbox/bin/setup.mjs +188 -188
  132. package/ftm-inbox/bin/start.sh +10 -10
  133. package/ftm-inbox/bin/status.sh +17 -17
  134. package/ftm-inbox/bin/stop.sh +8 -8
  135. package/ftm-inbox/config.example.yml +55 -55
  136. package/ftm-inbox/package-lock.json +2898 -2898
  137. package/ftm-inbox/package.json +26 -26
  138. package/ftm-inbox/postcss.config.js +6 -6
  139. package/ftm-inbox/src/app.css +199 -199
  140. package/ftm-inbox/src/app.html +18 -18
  141. package/ftm-inbox/src/lib/api.ts +166 -166
  142. package/ftm-inbox/src/lib/components/ExecutionLog.svelte +81 -81
  143. package/ftm-inbox/src/lib/components/InboxFeed.svelte +143 -143
  144. package/ftm-inbox/src/lib/components/PlanStep.svelte +271 -271
  145. package/ftm-inbox/src/lib/components/PlanView.svelte +206 -206
  146. package/ftm-inbox/src/lib/components/StreamPanel.svelte +99 -99
  147. package/ftm-inbox/src/lib/components/TaskCard.svelte +190 -190
  148. package/ftm-inbox/src/lib/components/ui/EmptyState.svelte +63 -63
  149. package/ftm-inbox/src/lib/components/ui/KawaiiCard.svelte +86 -86
  150. package/ftm-inbox/src/lib/components/ui/PillButton.svelte +106 -106
  151. package/ftm-inbox/src/lib/components/ui/StatusBadge.svelte +67 -67
  152. package/ftm-inbox/src/lib/components/ui/StreamDrawer.svelte +149 -149
  153. package/ftm-inbox/src/lib/components/ui/ThemeToggle.svelte +80 -80
  154. package/ftm-inbox/src/lib/theme.ts +47 -47
  155. package/ftm-inbox/src/routes/+layout.svelte +76 -76
  156. package/ftm-inbox/src/routes/+page.svelte +401 -401
  157. package/ftm-inbox/svelte.config.js +12 -12
  158. package/ftm-inbox/tailwind.config.ts +63 -63
  159. package/ftm-inbox/tsconfig.json +13 -13
  160. package/ftm-inbox/vite.config.ts +6 -6
  161. package/ftm-intent/SKILL.md +241 -241
  162. package/ftm-intent.yml +2 -2
  163. package/ftm-manifest.json +3794 -3794
  164. package/ftm-map/SKILL.md +291 -291
  165. package/ftm-map/scripts/db.py +712 -712
  166. package/ftm-map/scripts/index.py +415 -415
  167. package/ftm-map/scripts/parser.py +224 -224
  168. package/ftm-map/scripts/queries/go-tags.scm +20 -20
  169. package/ftm-map/scripts/queries/javascript-tags.scm +35 -35
  170. package/ftm-map/scripts/queries/python-tags.scm +31 -31
  171. package/ftm-map/scripts/queries/ruby-tags.scm +19 -19
  172. package/ftm-map/scripts/queries/rust-tags.scm +37 -37
  173. package/ftm-map/scripts/queries/typescript-tags.scm +41 -41
  174. package/ftm-map/scripts/query.py +301 -301
  175. package/ftm-map/scripts/ranker.py +377 -377
  176. package/ftm-map/scripts/requirements.txt +5 -5
  177. package/ftm-map/scripts/setup-hooks.sh +27 -27
  178. package/ftm-map/scripts/setup.sh +56 -56
  179. package/ftm-map/scripts/test_db.py +364 -364
  180. package/ftm-map/scripts/test_parser.py +174 -174
  181. package/ftm-map/scripts/test_query.py +183 -183
  182. package/ftm-map/scripts/test_ranker.py +199 -199
  183. package/ftm-map/scripts/views.py +591 -591
  184. package/ftm-map.yml +2 -2
  185. package/ftm-mind/SKILL.md +201 -1943
  186. package/ftm-mind/evals/promptfoo.yaml +142 -142
  187. package/ftm-mind/references/blackboard-protocol.md +110 -0
  188. package/ftm-mind/references/blackboard-schema.md +328 -328
  189. package/ftm-mind/references/complexity-guide.md +110 -110
  190. package/ftm-mind/references/complexity-sizing.md +138 -0
  191. package/ftm-mind/references/decide-act-protocol.md +172 -0
  192. package/ftm-mind/references/direct-execution.md +51 -0
  193. package/ftm-mind/references/environment-discovery.md +77 -0
  194. package/ftm-mind/references/event-registry.md +319 -319
  195. package/ftm-mind/references/mcp-inventory.md +300 -296
  196. package/ftm-mind/references/ops-routing.md +47 -0
  197. package/ftm-mind/references/orient-protocol.md +234 -0
  198. package/ftm-mind/references/personality.md +40 -0
  199. package/ftm-mind/references/protocols/COMPLEXITY-SIZING.md +72 -72
  200. package/ftm-mind/references/protocols/MCP-HEURISTICS.md +32 -32
  201. package/ftm-mind/references/protocols/PLAN-APPROVAL.md +80 -80
  202. package/ftm-mind/references/reflexion-protocol.md +249 -249
  203. package/ftm-mind/references/routing/SCENARIOS.md +22 -22
  204. package/ftm-mind/references/routing-scenarios.md +35 -35
  205. package/ftm-mind.yml +2 -2
  206. package/ftm-ops.yml +4 -0
  207. package/ftm-pause/SKILL.md +395 -395
  208. package/ftm-pause/references/protocols/SKILL-RESTORE-PROTOCOLS.md +186 -186
  209. package/ftm-pause/references/protocols/VALIDATION.md +80 -80
  210. package/ftm-pause.yml +2 -2
  211. package/ftm-researcher/SKILL.md +275 -275
  212. package/ftm-researcher/evals/agent-diversity.yaml +17 -17
  213. package/ftm-researcher/evals/synthesis-quality.yaml +12 -12
  214. package/ftm-researcher/evals/trigger-accuracy.yaml +39 -39
  215. package/ftm-researcher/references/adaptive-search.md +116 -116
  216. package/ftm-researcher/references/agent-prompts.md +193 -193
  217. package/ftm-researcher/references/council-integration.md +193 -193
  218. package/ftm-researcher/references/output-format.md +203 -203
  219. package/ftm-researcher/references/synthesis-pipeline.md +165 -165
  220. package/ftm-researcher/scripts/score_credibility.py +234 -234
  221. package/ftm-researcher/scripts/validate_research.py +92 -92
  222. package/ftm-researcher.yml +2 -2
  223. package/ftm-resume/SKILL.md +518 -518
  224. package/ftm-resume/references/protocols/VALIDATION.md +172 -172
  225. package/ftm-resume.yml +2 -2
  226. package/ftm-retro/SKILL.md +380 -380
  227. package/ftm-retro/references/protocols/SCORING-RUBRICS.md +89 -89
  228. package/ftm-retro/references/templates/REPORT-FORMAT.md +109 -109
  229. package/ftm-retro.yml +2 -2
  230. package/ftm-routine/SKILL.md +170 -170
  231. package/ftm-routine.yml +4 -4
  232. package/ftm-state/blackboard/capabilities.json +5 -5
  233. package/ftm-state/blackboard/capabilities.schema.json +27 -27
  234. package/ftm-state/blackboard/context.json +37 -23
  235. package/ftm-state/blackboard/experiences/doom-statusline-fix.json +26 -0
  236. package/ftm-state/blackboard/experiences/hackathon-pages-site.json +26 -0
  237. package/ftm-state/blackboard/experiences/hindsight-sso-kickoff.json +42 -0
  238. package/ftm-state/blackboard/experiences/index.json +58 -9
  239. package/ftm-state/blackboard/experiences/learning-ragnarok-api-access.json +23 -0
  240. package/ftm-state/blackboard/experiences/nordlayer-members-auto-assign.json +26 -0
  241. package/ftm-state/blackboard/experiences/saml2aws-stale-session-fix.json +41 -0
  242. package/ftm-state/blackboard/patterns.json +6 -6
  243. package/ftm-state/schemas/context.schema.json +130 -130
  244. package/ftm-state/schemas/experience-index.schema.json +77 -77
  245. package/ftm-state/schemas/experience.schema.json +78 -78
  246. package/ftm-state/schemas/patterns.schema.json +44 -44
  247. package/ftm-upgrade/SKILL.md +194 -194
  248. package/ftm-upgrade/scripts/check-version.sh +76 -76
  249. package/ftm-upgrade/scripts/upgrade.sh +143 -143
  250. package/ftm-upgrade.yml +2 -2
  251. package/ftm-verify.yml +2 -2
  252. package/ftm.yml +2 -2
  253. package/hooks/ftm-auto-log.sh +137 -0
  254. package/hooks/ftm-blackboard-enforcer.sh +93 -93
  255. package/hooks/ftm-discovery-reminder.sh +90 -90
  256. package/hooks/ftm-drafts-gate.sh +61 -61
  257. package/hooks/ftm-event-logger.mjs +107 -107
  258. package/hooks/ftm-install-hooks.sh +240 -0
  259. package/hooks/ftm-learning-capture.sh +117 -0
  260. package/hooks/ftm-map-autodetect.sh +79 -79
  261. package/hooks/ftm-pending-sync-check.sh +22 -22
  262. package/hooks/ftm-plan-gate.sh +92 -92
  263. package/hooks/ftm-post-commit-trigger.sh +57 -57
  264. package/hooks/ftm-post-compaction.sh +138 -0
  265. package/hooks/ftm-pre-compaction.sh +147 -0
  266. package/hooks/ftm-session-end.sh +52 -0
  267. package/hooks/ftm-session-snapshot.sh +213 -0
  268. package/hooks/ftm-task-loader.sh +100 -0
  269. package/hooks/settings-template.json +91 -81
  270. package/install.sh +363 -363
  271. package/package.json +84 -84
  272. package/uninstall.sh +25 -25
@@ -1,76 +1,76 @@
1
- #!/usr/bin/env bash
2
- # check-version.sh — Check for feed-the-machine updates via GitHub Releases
3
- # Outputs: UP_TO_DATE | UPGRADE_AVAILABLE <version> <changelog_url> | CHECK_FAILED <reason>
4
-
5
- set -uo pipefail
6
-
7
- CACHE_DIR="${HOME}/.cache/ftm-brain"
8
- CACHE_FILE="${CACHE_DIR}/version-check"
9
- VERSION_FILE="${HOME}/.claude/skills/ftm-version.txt"
10
- REPO="kkudumu/ftm-brain"
11
-
12
- # Ensure cache directory exists
13
- mkdir -p "${CACHE_DIR}"
14
-
15
- # Check if cache is fresh (less than 60 minutes old)
16
- if [ -f "${CACHE_FILE}" ]; then
17
- STALE=$(find "${CACHE_FILE}" -mmin +60 2>/dev/null | wc -l | tr -d ' ')
18
- if [ "${STALE}" = "0" ]; then
19
- # Cache is fresh — return cached result
20
- cat "${CACHE_FILE}"
21
- exit 0
22
- fi
23
- fi
24
-
25
- # Check that gh CLI is installed
26
- if ! command -v gh >/dev/null 2>&1; then
27
- RESULT="CHECK_FAILED gh_not_installed"
28
- printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
29
- exit 0
30
- fi
31
-
32
- # Query latest release from GitHub
33
- RELEASE_OUTPUT=$(gh release list -R "${REPO}" --limit 1 2>&1)
34
- GH_EXIT=$?
35
-
36
- if [ ${GH_EXIT} -ne 0 ]; then
37
- # Distinguish between network and repo errors
38
- if printf '%s' "${RELEASE_OUTPUT}" | grep -qi "could not resolve\|network\|timeout\|no such host"; then
39
- RESULT="CHECK_FAILED no_internet"
40
- elif printf '%s' "${RELEASE_OUTPUT}" | grep -qi "not found\|404\|Could not find"; then
41
- RESULT="CHECK_FAILED repo_not_found"
42
- else
43
- REASON=$(printf '%s' "${RELEASE_OUTPUT}" | tr '\n' ' ' | cut -c1-80)
44
- RESULT="CHECK_FAILED ${REASON}"
45
- fi
46
- printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
47
- exit 0
48
- fi
49
-
50
- # Parse latest release tag (first column of gh release list output)
51
- LATEST_TAG=$(printf '%s' "${RELEASE_OUTPUT}" | awk 'NR==1{print $1}')
52
-
53
- if [ -z "${LATEST_TAG}" ]; then
54
- RESULT="CHECK_FAILED no_releases_found"
55
- printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
56
- exit 0
57
- fi
58
-
59
- # Read current installed version
60
- if [ -f "${VERSION_FILE}" ]; then
61
- CURRENT_VERSION=$(tr -d '[:space:]' < "${VERSION_FILE}")
62
- else
63
- CURRENT_VERSION="unknown"
64
- fi
65
-
66
- # Compare versions
67
- if [ "${CURRENT_VERSION}" = "${LATEST_TAG}" ]; then
68
- RESULT="UP_TO_DATE"
69
- else
70
- CHANGELOG_URL="https://github.com/${REPO}/releases/tag/${LATEST_TAG}"
71
- RESULT="UPGRADE_AVAILABLE ${LATEST_TAG} ${CHANGELOG_URL}"
72
- fi
73
-
74
- # Write to cache and output
75
- printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
76
- exit 0
1
+ #!/usr/bin/env bash
2
+ # check-version.sh — Check for feed-the-machine updates via GitHub Releases
3
+ # Outputs: UP_TO_DATE | UPGRADE_AVAILABLE <version> <changelog_url> | CHECK_FAILED <reason>
4
+
5
+ set -uo pipefail
6
+
7
+ CACHE_DIR="${HOME}/.cache/ftm-brain"
8
+ CACHE_FILE="${CACHE_DIR}/version-check"
9
+ VERSION_FILE="${HOME}/.claude/skills/ftm-version.txt"
10
+ REPO="kkudumu/ftm-brain"
11
+
12
+ # Ensure cache directory exists
13
+ mkdir -p "${CACHE_DIR}"
14
+
15
+ # Check if cache is fresh (less than 60 minutes old)
16
+ if [ -f "${CACHE_FILE}" ]; then
17
+ STALE=$(find "${CACHE_FILE}" -mmin +60 2>/dev/null | wc -l | tr -d ' ')
18
+ if [ "${STALE}" = "0" ]; then
19
+ # Cache is fresh — return cached result
20
+ cat "${CACHE_FILE}"
21
+ exit 0
22
+ fi
23
+ fi
24
+
25
+ # Check that gh CLI is installed
26
+ if ! command -v gh >/dev/null 2>&1; then
27
+ RESULT="CHECK_FAILED gh_not_installed"
28
+ printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
29
+ exit 0
30
+ fi
31
+
32
+ # Query latest release from GitHub
33
+ RELEASE_OUTPUT=$(gh release list -R "${REPO}" --limit 1 2>&1)
34
+ GH_EXIT=$?
35
+
36
+ if [ ${GH_EXIT} -ne 0 ]; then
37
+ # Distinguish between network and repo errors
38
+ if printf '%s' "${RELEASE_OUTPUT}" | grep -qi "could not resolve\|network\|timeout\|no such host"; then
39
+ RESULT="CHECK_FAILED no_internet"
40
+ elif printf '%s' "${RELEASE_OUTPUT}" | grep -qi "not found\|404\|Could not find"; then
41
+ RESULT="CHECK_FAILED repo_not_found"
42
+ else
43
+ REASON=$(printf '%s' "${RELEASE_OUTPUT}" | tr '\n' ' ' | cut -c1-80)
44
+ RESULT="CHECK_FAILED ${REASON}"
45
+ fi
46
+ printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
47
+ exit 0
48
+ fi
49
+
50
+ # Parse latest release tag (first column of gh release list output)
51
+ LATEST_TAG=$(printf '%s' "${RELEASE_OUTPUT}" | awk 'NR==1{print $1}')
52
+
53
+ if [ -z "${LATEST_TAG}" ]; then
54
+ RESULT="CHECK_FAILED no_releases_found"
55
+ printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
56
+ exit 0
57
+ fi
58
+
59
+ # Read current installed version
60
+ if [ -f "${VERSION_FILE}" ]; then
61
+ CURRENT_VERSION=$(tr -d '[:space:]' < "${VERSION_FILE}")
62
+ else
63
+ CURRENT_VERSION="unknown"
64
+ fi
65
+
66
+ # Compare versions
67
+ if [ "${CURRENT_VERSION}" = "${LATEST_TAG}" ]; then
68
+ RESULT="UP_TO_DATE"
69
+ else
70
+ CHANGELOG_URL="https://github.com/${REPO}/releases/tag/${LATEST_TAG}"
71
+ RESULT="UPGRADE_AVAILABLE ${LATEST_TAG} ${CHANGELOG_URL}"
72
+ fi
73
+
74
+ # Write to cache and output
75
+ printf '%s\n' "${RESULT}" | tee "${CACHE_FILE}"
76
+ exit 0
@@ -1,143 +1,143 @@
1
- #!/usr/bin/env bash
2
- # upgrade.sh — Download and install latest feed-the-machine release
3
- # Usage: upgrade.sh [--version <tag>]
4
-
5
- set -uo pipefail
6
-
7
- REPO="kkudumu/ftm-brain"
8
- SKILLS_DIR="${HOME}/.claude/skills"
9
- VERSION_FILE="${SKILLS_DIR}/ftm-version.txt"
10
- DOWNLOAD_DIR="/tmp/ftm-upgrade"
11
- CACHE_FILE="${HOME}/.cache/ftm-brain/version-check"
12
-
13
- # ── Helpers ──────────────────────────────────────────────────────────────────
14
-
15
- log() { printf '[ftm-upgrade] %s\n' "$*"; }
16
- die() { printf '[ftm-upgrade] ERROR: %s\n' "$*" >&2; exit 1; }
17
-
18
- # ── Preflight checks ─────────────────────────────────────────────────────────
19
-
20
- if ! command -v gh >/dev/null 2>&1; then
21
- die "GitHub CLI (gh) is not installed. Install it with: brew install gh"
22
- fi
23
-
24
- if ! command -v tar >/dev/null 2>&1; then
25
- die "tar is required but not found."
26
- fi
27
-
28
- # ── Determine target version ─────────────────────────────────────────────────
29
-
30
- TARGET_VERSION=""
31
- while [ $# -gt 0 ]; do
32
- case "$1" in
33
- --version) TARGET_VERSION="$2"; shift 2 ;;
34
- *) die "Unknown argument: $1" ;;
35
- esac
36
- done
37
-
38
- if [ -z "${TARGET_VERSION}" ]; then
39
- log "Fetching latest release tag..."
40
- TARGET_VERSION=$(gh release list -R "${REPO}" --limit 1 2>&1 | awk 'NR==1{print $1}')
41
- if [ -z "${TARGET_VERSION}" ]; then
42
- die "Could not determine latest release. Check GitHub access and repository name."
43
- fi
44
- fi
45
-
46
- log "Target version: ${TARGET_VERSION}"
47
-
48
- # ── Read current version ─────────────────────────────────────────────────────
49
-
50
- if [ -f "${VERSION_FILE}" ]; then
51
- CURRENT_VERSION=$(tr -d '[:space:]' < "${VERSION_FILE}")
52
- else
53
- CURRENT_VERSION="(not installed)"
54
- fi
55
-
56
- log "Current version: ${CURRENT_VERSION}"
57
-
58
- if [ "${CURRENT_VERSION}" = "${TARGET_VERSION}" ]; then
59
- log "Already on the latest version (${TARGET_VERSION}). Nothing to do."
60
- exit 0
61
- fi
62
-
63
- # ── Download ──────────────────────────────────────────────────────────────────
64
-
65
- rm -rf "${DOWNLOAD_DIR}"
66
- mkdir -p "${DOWNLOAD_DIR}"
67
-
68
- log "Downloading release archive for ${TARGET_VERSION}..."
69
-
70
- gh release download "${TARGET_VERSION}" \
71
- -R "${REPO}" \
72
- --archive tar.gz \
73
- -D "${DOWNLOAD_DIR}" 2>&1 || die "Download failed. Check your internet connection and repository access."
74
-
75
- # Find the downloaded archive
76
- ARCHIVE=$(find "${DOWNLOAD_DIR}" -maxdepth 1 -name '*.tar.gz' | head -1)
77
- if [ -z "${ARCHIVE}" ]; then
78
- die "No archive found in ${DOWNLOAD_DIR} after download."
79
- fi
80
-
81
- log "Downloaded: ${ARCHIVE}"
82
-
83
- # ── Extract ───────────────────────────────────────────────────────────────────
84
-
85
- EXTRACT_DIR="${DOWNLOAD_DIR}/extracted"
86
- mkdir -p "${EXTRACT_DIR}"
87
-
88
- log "Extracting archive..."
89
- tar -xzf "${ARCHIVE}" -C "${EXTRACT_DIR}" 2>&1 || die "Extraction failed. Archive may be corrupt."
90
-
91
- # GitHub archives typically extract into a directory named <repo>-<tag>/
92
- REPO_DIR=$(find "${EXTRACT_DIR}" -maxdepth 1 -mindepth 1 -type d | head -1)
93
- if [ -z "${REPO_DIR}" ]; then
94
- die "Could not find extracted repository directory."
95
- fi
96
-
97
- log "Extracted to: ${REPO_DIR}"
98
-
99
- # ── Copy skill files ──────────────────────────────────────────────────────────
100
-
101
- # Look for a skills/ subdirectory in the archive; fall back to root
102
- SOURCE_SKILLS=""
103
- if [ -d "${REPO_DIR}/skills" ]; then
104
- SOURCE_SKILLS="${REPO_DIR}/skills"
105
- elif [ -d "${REPO_DIR}" ]; then
106
- # The repo root might itself contain SKILL.md files and .yml files
107
- SOURCE_SKILLS="${REPO_DIR}"
108
- fi
109
-
110
- if [ -z "${SOURCE_SKILLS}" ]; then
111
- die "No skills directory found in release archive."
112
- fi
113
-
114
- log "Copying skill files from ${SOURCE_SKILLS} to ${SKILLS_DIR}..."
115
-
116
- # Use rsync if available for cleaner copy, else cp
117
- if command -v rsync >/dev/null 2>&1; then
118
- rsync -av --exclude='.git' "${SOURCE_SKILLS}/" "${SKILLS_DIR}/" 2>&1
119
- else
120
- cp -R "${SOURCE_SKILLS}/." "${SKILLS_DIR}/" 2>&1
121
- fi
122
-
123
- # ── Update version file ───────────────────────────────────────────────────────
124
-
125
- printf '%s\n' "${TARGET_VERSION}" > "${VERSION_FILE}"
126
-
127
- # Invalidate version cache so next check-version.sh run is fresh
128
- rm -f "${CACHE_FILE}"
129
-
130
- # ── Summary ───────────────────────────────────────────────────────────────────
131
-
132
- log ""
133
- log "Upgrade complete."
134
- log " ${CURRENT_VERSION} → ${TARGET_VERSION}"
135
- log " Changelog: https://github.com/${REPO}/releases/tag/${TARGET_VERSION}"
136
- log ""
137
- log "Installed files updated in: ${SKILLS_DIR}"
138
-
139
- # ── Cleanup ───────────────────────────────────────────────────────────────────
140
-
141
- rm -rf "${DOWNLOAD_DIR}"
142
-
143
- exit 0
1
+ #!/usr/bin/env bash
2
+ # upgrade.sh — Download and install latest feed-the-machine release
3
+ # Usage: upgrade.sh [--version <tag>]
4
+
5
+ set -uo pipefail
6
+
7
+ REPO="kkudumu/ftm-brain"
8
+ SKILLS_DIR="${HOME}/.claude/skills"
9
+ VERSION_FILE="${SKILLS_DIR}/ftm-version.txt"
10
+ DOWNLOAD_DIR="/tmp/ftm-upgrade"
11
+ CACHE_FILE="${HOME}/.cache/ftm-brain/version-check"
12
+
13
+ # ── Helpers ──────────────────────────────────────────────────────────────────
14
+
15
+ log() { printf '[ftm-upgrade] %s\n' "$*"; }
16
+ die() { printf '[ftm-upgrade] ERROR: %s\n' "$*" >&2; exit 1; }
17
+
18
+ # ── Preflight checks ─────────────────────────────────────────────────────────
19
+
20
+ if ! command -v gh >/dev/null 2>&1; then
21
+ die "GitHub CLI (gh) is not installed. Install it with: brew install gh"
22
+ fi
23
+
24
+ if ! command -v tar >/dev/null 2>&1; then
25
+ die "tar is required but not found."
26
+ fi
27
+
28
+ # ── Determine target version ─────────────────────────────────────────────────
29
+
30
+ TARGET_VERSION=""
31
+ while [ $# -gt 0 ]; do
32
+ case "$1" in
33
+ --version) TARGET_VERSION="$2"; shift 2 ;;
34
+ *) die "Unknown argument: $1" ;;
35
+ esac
36
+ done
37
+
38
+ if [ -z "${TARGET_VERSION}" ]; then
39
+ log "Fetching latest release tag..."
40
+ TARGET_VERSION=$(gh release list -R "${REPO}" --limit 1 2>&1 | awk 'NR==1{print $1}')
41
+ if [ -z "${TARGET_VERSION}" ]; then
42
+ die "Could not determine latest release. Check GitHub access and repository name."
43
+ fi
44
+ fi
45
+
46
+ log "Target version: ${TARGET_VERSION}"
47
+
48
+ # ── Read current version ─────────────────────────────────────────────────────
49
+
50
+ if [ -f "${VERSION_FILE}" ]; then
51
+ CURRENT_VERSION=$(tr -d '[:space:]' < "${VERSION_FILE}")
52
+ else
53
+ CURRENT_VERSION="(not installed)"
54
+ fi
55
+
56
+ log "Current version: ${CURRENT_VERSION}"
57
+
58
+ if [ "${CURRENT_VERSION}" = "${TARGET_VERSION}" ]; then
59
+ log "Already on the latest version (${TARGET_VERSION}). Nothing to do."
60
+ exit 0
61
+ fi
62
+
63
+ # ── Download ──────────────────────────────────────────────────────────────────
64
+
65
+ rm -rf "${DOWNLOAD_DIR}"
66
+ mkdir -p "${DOWNLOAD_DIR}"
67
+
68
+ log "Downloading release archive for ${TARGET_VERSION}..."
69
+
70
+ gh release download "${TARGET_VERSION}" \
71
+ -R "${REPO}" \
72
+ --archive tar.gz \
73
+ -D "${DOWNLOAD_DIR}" 2>&1 || die "Download failed. Check your internet connection and repository access."
74
+
75
+ # Find the downloaded archive
76
+ ARCHIVE=$(find "${DOWNLOAD_DIR}" -maxdepth 1 -name '*.tar.gz' | head -1)
77
+ if [ -z "${ARCHIVE}" ]; then
78
+ die "No archive found in ${DOWNLOAD_DIR} after download."
79
+ fi
80
+
81
+ log "Downloaded: ${ARCHIVE}"
82
+
83
+ # ── Extract ───────────────────────────────────────────────────────────────────
84
+
85
+ EXTRACT_DIR="${DOWNLOAD_DIR}/extracted"
86
+ mkdir -p "${EXTRACT_DIR}"
87
+
88
+ log "Extracting archive..."
89
+ tar -xzf "${ARCHIVE}" -C "${EXTRACT_DIR}" 2>&1 || die "Extraction failed. Archive may be corrupt."
90
+
91
+ # GitHub archives typically extract into a directory named <repo>-<tag>/
92
+ REPO_DIR=$(find "${EXTRACT_DIR}" -maxdepth 1 -mindepth 1 -type d | head -1)
93
+ if [ -z "${REPO_DIR}" ]; then
94
+ die "Could not find extracted repository directory."
95
+ fi
96
+
97
+ log "Extracted to: ${REPO_DIR}"
98
+
99
+ # ── Copy skill files ──────────────────────────────────────────────────────────
100
+
101
+ # Look for a skills/ subdirectory in the archive; fall back to root
102
+ SOURCE_SKILLS=""
103
+ if [ -d "${REPO_DIR}/skills" ]; then
104
+ SOURCE_SKILLS="${REPO_DIR}/skills"
105
+ elif [ -d "${REPO_DIR}" ]; then
106
+ # The repo root might itself contain SKILL.md files and .yml files
107
+ SOURCE_SKILLS="${REPO_DIR}"
108
+ fi
109
+
110
+ if [ -z "${SOURCE_SKILLS}" ]; then
111
+ die "No skills directory found in release archive."
112
+ fi
113
+
114
+ log "Copying skill files from ${SOURCE_SKILLS} to ${SKILLS_DIR}..."
115
+
116
+ # Use rsync if available for cleaner copy, else cp
117
+ if command -v rsync >/dev/null 2>&1; then
118
+ rsync -av --exclude='.git' "${SOURCE_SKILLS}/" "${SKILLS_DIR}/" 2>&1
119
+ else
120
+ cp -R "${SOURCE_SKILLS}/." "${SKILLS_DIR}/" 2>&1
121
+ fi
122
+
123
+ # ── Update version file ───────────────────────────────────────────────────────
124
+
125
+ printf '%s\n' "${TARGET_VERSION}" > "${VERSION_FILE}"
126
+
127
+ # Invalidate version cache so next check-version.sh run is fresh
128
+ rm -f "${CACHE_FILE}"
129
+
130
+ # ── Summary ───────────────────────────────────────────────────────────────────
131
+
132
+ log ""
133
+ log "Upgrade complete."
134
+ log " ${CURRENT_VERSION} → ${TARGET_VERSION}"
135
+ log " Changelog: https://github.com/${REPO}/releases/tag/${TARGET_VERSION}"
136
+ log ""
137
+ log "Installed files updated in: ${SKILLS_DIR}"
138
+
139
+ # ── Cleanup ───────────────────────────────────────────────────────────────────
140
+
141
+ rm -rf "${DOWNLOAD_DIR}"
142
+
143
+ exit 0
package/ftm-upgrade.yml CHANGED
@@ -1,2 +1,2 @@
1
- name: ftm-upgrade
2
- description: Self-upgrade mechanism for ftm skills ecosystem. Checks GitHub Releases for new versions, caches results for 60min, shows changelog, and copies updated files. Use when user says "upgrade", "update skills", "new version", "check for updates", "ftm upgrade".
1
+ name: ftm-upgrade
2
+ description: Self-upgrade mechanism for ftm skills ecosystem. Checks GitHub Releases for new versions, caches results for 60min, shows changelog, and copies updated files. Use when user says "upgrade", "update skills", "new version", "check for updates", "ftm upgrade".
package/ftm-verify.yml CHANGED
@@ -1,2 +1,2 @@
1
- name: ftm-verify
2
- description: Comprehensive post-execution verification and auto-remediation engine using dual-model adversarial analysis. Replaces ftm-retro. After ftm-executor completes a plan, this skill runs two independent verification passes in parallel — Codex (OpenAI) and Gemini (Google) — each reading the entire codebase to check plan fulfillment, documentation fidelity, build health, test quality, and wiring integrity. Falls back to Claude subagents if either CLI is unavailable. Reconciles findings from both models, auto-remediates with parallel fix agents, and reports what was found, disagreed on, and fixed. Use when user says "verify", "is the plan done", "check everything", "verify plan", "ftm-verify", "did we miss anything", "is it complete", "validate the build", "check the plan", "verify execution", "post-execution check", or after any ftm-executor run completes. Also triggers on "retro", "retrospective", "how did that go", "execution review" since this skill supersedes ftm-retro. Even if the user just says "are we good?" after a plan execution — this is the skill.
1
+ name: ftm-verify
2
+ description: Comprehensive post-execution verification and auto-remediation engine using dual-model adversarial analysis. Replaces ftm-retro. After ftm-executor completes a plan, this skill runs two independent verification passes in parallel — Codex (OpenAI) and Gemini (Google) — each reading the entire codebase to check plan fulfillment, documentation fidelity, build health, test quality, and wiring integrity. Falls back to Claude subagents if either CLI is unavailable. Reconciles findings from both models, auto-remediates with parallel fix agents, and reports what was found, disagreed on, and fixed. Use when user says "verify", "is the plan done", "check everything", "verify plan", "ftm-verify", "did we miss anything", "is it complete", "validate the build", "check the plan", "verify execution", "post-execution check", or after any ftm-executor run completes. Also triggers on "retro", "retrospective", "how did that go", "execution review" since this skill supersedes ftm-retro. Even if the user just says "are we good?" after a plan execution — this is the skill.
package/ftm.yml CHANGED
@@ -1,2 +1,2 @@
1
- name: ftm
2
- description: Universal entry point for all ftm skills. Routes freeform text to the right ftm skill automatically. Use when user says "/ftm" followed by anything. ftm-mind is the default cognitive entry point for all unclassified input (OODA reasoning). Explicit prefixes route directly: brainstorm, execute, debug, audit, council, intent, diagram, codex-gate, pause, resume, browse, upgrade, retro, config, mind. Also use when user is unsure which ftm skill they need.
1
+ name: ftm
2
+ description: Universal entry point for all ftm skills. Routes freeform text to the right ftm skill automatically. Use when user says "/ftm" followed by anything. ftm-mind is the default cognitive entry point for all unclassified input (OODA reasoning). Explicit prefixes route directly: brainstorm, execute, debug, audit, council, intent, diagram, codex-gate, pause, resume, browse, upgrade, retro, config, mind. Also use when user is unsure which ftm skill they need.
@@ -0,0 +1,137 @@
1
+ #!/bin/bash
2
+ # Hook: Auto-log progress + heartbeat for ftm
3
+ # Triggers: UserPromptSubmit while an ftm session is active
4
+ #
5
+ # 1. Auto-log: reminds Claude to log progress when user reports completing something
6
+ # 2. Task inbox: surfaces unreviewed Slack/email tasks every 10 min
7
+ # 3. Heartbeat: every 30 min, scans task state for urgent items to surface
8
+ #
9
+ # Heartbeat inspired by OpenClaw's HEARTBEAT.md pattern (heartbeat.ts):
10
+ # Periodically checks task state and prompts Claude to surface time-sensitive
11
+ # items without the user asking.
12
+ #
13
+ # FILES:
14
+ # ~/.claude/ftm-state/blackboard/context.json - session gate (active_task check)
15
+ # ~/.claude/ftm-state/.last-heartbeat - timestamp of last heartbeat
16
+ # ~/.claude/ftm-state/HEARTBEAT.md - user-maintained alert/task config
17
+
18
+ FTM_STATE="$HOME/.claude/ftm-state"
19
+ CONTEXT_JSON="$FTM_STATE/blackboard/context.json"
20
+
21
+ # Check if an ftm session is active by reading context.json
22
+ FTM_ACTIVE=$(python3 -c "
23
+ import json, sys
24
+ try:
25
+ with open('$CONTEXT_JSON') as f:
26
+ d = json.load(f)
27
+ task = d.get('current_task', {})
28
+ status = task.get('status', '')
29
+ print('1' if status not in ('', 'completed', 'none') else '0')
30
+ except Exception:
31
+ print('0')
32
+ " 2>/dev/null)
33
+
34
+ if [ "$FTM_ACTIVE" != "1" ]; then
35
+ exit 0 # Not in active ftm session, skip
36
+ fi
37
+
38
+ # Read payload from stdin (JSON) — extract prompt for action pattern matching
39
+ STDIN_DATA=$(cat)
40
+ USER_MESSAGE=$(echo "$STDIN_DATA" | python3 -c "
41
+ import sys, json
42
+ try:
43
+ d = json.load(sys.stdin)
44
+ print(d.get('prompt', ''))
45
+ except:
46
+ print('')
47
+ " 2>/dev/null)
48
+ # Fallback: treat stdin as raw message if JSON parse failed
49
+ if [ -z "$USER_MESSAGE" ]; then
50
+ USER_MESSAGE="$STDIN_DATA"
51
+ fi
52
+
53
+ # Action indicators (what users say when they've done something)
54
+ ACTION_PATTERNS=(
55
+ "^[Ii] (did|completed?|finished|fixed|sent|responded|closed|created|updated|deployed|merged|pushed|committed|tested|reviewed)"
56
+ "^[Jj]ust (did|completed?|finished|fixed|sent|responded|closed|created|updated|deployed|merged|pushed|committed|tested|reviewed)"
57
+ "^[Dd]one"
58
+ "^[Ff]inished"
59
+ "^[Cc]ompleted?"
60
+ "^[Ss]ent (email|message|response)"
61
+ "^[Rr]esponded to"
62
+ "^[Mm]erged"
63
+ "^[Pp]ushed to"
64
+ "^[Cc]ommitted"
65
+ "^[Dd]eployed"
66
+ "^[Ff]ixed"
67
+ "^[Cc]losed (ticket|issue|task)"
68
+ "[Tt]ask.*complete"
69
+ "[Tt]icket.*closed"
70
+ )
71
+
72
+ # Check if message matches any action pattern
73
+ SHOULD_LOG=false
74
+ for pattern in "${ACTION_PATTERNS[@]}"; do
75
+ if echo "$USER_MESSAGE" | grep -qE "$pattern"; then
76
+ SHOULD_LOG=true
77
+ break
78
+ fi
79
+ done
80
+
81
+ # Also check for follow-up questions after taking action
82
+ if echo "$USER_MESSAGE" | grep -qE "(I|i) .* (what|should|next|now)\?"; then
83
+ SHOULD_LOG=true
84
+ fi
85
+
86
+ # If action detected, output logging reminder for Claude to see
87
+ if [ "$SHOULD_LOG" = true ]; then
88
+ echo ""
89
+ echo "[Auto-log] Detected progress update. Please log this to the ftm daily log."
90
+ echo ""
91
+ fi
92
+
93
+ # --- Dashboard sync: surface task-state changes made outside the chat ---
94
+ CLAUDE_SYNC_FILE="$FTM_STATE/blackboard/.runtime/claude-sync-events.txt"
95
+ if [ -s "$CLAUDE_SYNC_FILE" ]; then
96
+ echo ""
97
+ echo "[Dashboard sync] Recent dashboard updates were written to ftm-state:"
98
+ head -20 "$CLAUDE_SYNC_FILE"
99
+ echo "Please reload task state from ftm-state and treat those updates as authoritative."
100
+ echo ""
101
+ : > "$CLAUDE_SYNC_FILE"
102
+ fi
103
+
104
+ # --- Heartbeat: periodic task/urgency check ---
105
+ # Fires every 30 minutes. Prompts Claude to scan for time-sensitive items.
106
+ HEARTBEAT_INTERVAL=1800 # 30 minutes in seconds
107
+ LAST_HEARTBEAT_FILE="$FTM_STATE/.last-heartbeat"
108
+ HEARTBEAT_MD="$FTM_STATE/HEARTBEAT.md"
109
+
110
+ SHOULD_HEARTBEAT=false
111
+ if [ -f "$LAST_HEARTBEAT_FILE" ]; then
112
+ LAST_BEAT=$(cat "$LAST_HEARTBEAT_FILE" 2>/dev/null || echo 0)
113
+ NOW=$(date +%s)
114
+ ELAPSED=$(( NOW - LAST_BEAT ))
115
+ if [ "$ELAPSED" -ge "$HEARTBEAT_INTERVAL" ]; then
116
+ SHOULD_HEARTBEAT=true
117
+ fi
118
+ else
119
+ # First message of session — no heartbeat on first message, just record time
120
+ echo "$(date +%s)" > "$LAST_HEARTBEAT_FILE"
121
+ fi
122
+
123
+ if [ "$SHOULD_HEARTBEAT" = true ]; then
124
+ echo "$(date +%s)" > "$LAST_HEARTBEAT_FILE"
125
+ echo ""
126
+ echo "[HEARTBEAT — $(date '+%H:%M') check-in]: 30 minutes have passed. Briefly scan for anything time-sensitive:"
127
+ echo "- Check ftm-state/blackboard/context.json for deadlines or blockers that need attention."
128
+ if [ -f "$HEARTBEAT_MD" ]; then
129
+ HB_CONTENT=$(cat "$HEARTBEAT_MD" 2>/dev/null)
130
+ HB_ACTIONABLE=$(echo "$HB_CONTENT" | grep -v "^#" | grep -v "^[[:space:]]*$" | head -3)
131
+ if [ -n "$HB_ACTIONABLE" ]; then
132
+ echo "- HEARTBEAT.md has tasks configured — read it and follow any instructions."
133
+ fi
134
+ fi
135
+ echo "If nothing urgent, proceed normally. If something needs attention, surface it briefly."
136
+ echo ""
137
+ fi