feed-the-machine 1.0.0 → 1.2.0

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 (136) hide show
  1. package/bin/generate-manifest.mjs +253 -0
  2. package/bin/install.mjs +134 -4
  3. package/docs/HOOKS.md +243 -0
  4. package/docs/INBOX.md +233 -0
  5. package/ftm/SKILL.md +34 -0
  6. package/ftm-audit/SKILL.md +69 -0
  7. package/ftm-brainstorm/SKILL.md +51 -0
  8. package/ftm-browse/SKILL.md +39 -0
  9. package/ftm-capture/SKILL.md +370 -0
  10. package/ftm-capture.yml +4 -0
  11. package/ftm-codex-gate/SKILL.md +59 -0
  12. package/ftm-config/SKILL.md +35 -0
  13. package/ftm-council/SKILL.md +56 -0
  14. package/ftm-dashboard/SKILL.md +163 -0
  15. package/ftm-debug/SKILL.md +84 -0
  16. package/ftm-diagram/SKILL.md +44 -0
  17. package/ftm-executor/SKILL.md +97 -0
  18. package/ftm-git/SKILL.md +60 -0
  19. package/ftm-inbox/backend/__init__.py +0 -0
  20. package/ftm-inbox/backend/__pycache__/main.cpython-314.pyc +0 -0
  21. package/ftm-inbox/backend/adapters/__init__.py +0 -0
  22. package/ftm-inbox/backend/adapters/_retry.py +64 -0
  23. package/ftm-inbox/backend/adapters/base.py +230 -0
  24. package/ftm-inbox/backend/adapters/freshservice.py +104 -0
  25. package/ftm-inbox/backend/adapters/gmail.py +125 -0
  26. package/ftm-inbox/backend/adapters/jira.py +136 -0
  27. package/ftm-inbox/backend/adapters/registry.py +192 -0
  28. package/ftm-inbox/backend/adapters/slack.py +110 -0
  29. package/ftm-inbox/backend/db/__init__.py +0 -0
  30. package/ftm-inbox/backend/db/connection.py +54 -0
  31. package/ftm-inbox/backend/db/schema.py +78 -0
  32. package/ftm-inbox/backend/executor/__init__.py +7 -0
  33. package/ftm-inbox/backend/executor/engine.py +149 -0
  34. package/ftm-inbox/backend/executor/step_runner.py +98 -0
  35. package/ftm-inbox/backend/main.py +103 -0
  36. package/ftm-inbox/backend/models/__init__.py +1 -0
  37. package/ftm-inbox/backend/models/unified_task.py +36 -0
  38. package/ftm-inbox/backend/planner/__init__.py +6 -0
  39. package/ftm-inbox/backend/planner/__pycache__/__init__.cpython-314.pyc +0 -0
  40. package/ftm-inbox/backend/planner/__pycache__/generator.cpython-314.pyc +0 -0
  41. package/ftm-inbox/backend/planner/__pycache__/schema.cpython-314.pyc +0 -0
  42. package/ftm-inbox/backend/planner/generator.py +127 -0
  43. package/ftm-inbox/backend/planner/schema.py +34 -0
  44. package/ftm-inbox/backend/requirements.txt +5 -0
  45. package/ftm-inbox/backend/routes/__init__.py +0 -0
  46. package/ftm-inbox/backend/routes/__pycache__/plan.cpython-314.pyc +0 -0
  47. package/ftm-inbox/backend/routes/execute.py +186 -0
  48. package/ftm-inbox/backend/routes/health.py +52 -0
  49. package/ftm-inbox/backend/routes/inbox.py +68 -0
  50. package/ftm-inbox/backend/routes/plan.py +271 -0
  51. package/ftm-inbox/bin/launchagent.mjs +91 -0
  52. package/ftm-inbox/bin/setup.mjs +188 -0
  53. package/ftm-inbox/bin/start.sh +10 -0
  54. package/ftm-inbox/bin/status.sh +17 -0
  55. package/ftm-inbox/bin/stop.sh +8 -0
  56. package/ftm-inbox/config.example.yml +55 -0
  57. package/ftm-inbox/package-lock.json +2898 -0
  58. package/ftm-inbox/package.json +26 -0
  59. package/ftm-inbox/postcss.config.js +6 -0
  60. package/ftm-inbox/src/app.css +199 -0
  61. package/ftm-inbox/src/app.html +18 -0
  62. package/ftm-inbox/src/lib/api.ts +166 -0
  63. package/ftm-inbox/src/lib/components/ExecutionLog.svelte +81 -0
  64. package/ftm-inbox/src/lib/components/InboxFeed.svelte +143 -0
  65. package/ftm-inbox/src/lib/components/PlanStep.svelte +271 -0
  66. package/ftm-inbox/src/lib/components/PlanView.svelte +206 -0
  67. package/ftm-inbox/src/lib/components/StreamPanel.svelte +99 -0
  68. package/ftm-inbox/src/lib/components/TaskCard.svelte +190 -0
  69. package/ftm-inbox/src/lib/components/ui/EmptyState.svelte +63 -0
  70. package/ftm-inbox/src/lib/components/ui/KawaiiCard.svelte +86 -0
  71. package/ftm-inbox/src/lib/components/ui/PillButton.svelte +106 -0
  72. package/ftm-inbox/src/lib/components/ui/StatusBadge.svelte +67 -0
  73. package/ftm-inbox/src/lib/components/ui/StreamDrawer.svelte +149 -0
  74. package/ftm-inbox/src/lib/components/ui/ThemeToggle.svelte +80 -0
  75. package/ftm-inbox/src/lib/theme.ts +47 -0
  76. package/ftm-inbox/src/routes/+layout.svelte +76 -0
  77. package/ftm-inbox/src/routes/+page.svelte +401 -0
  78. package/ftm-inbox/static/favicon.png +0 -0
  79. package/ftm-inbox/svelte.config.js +12 -0
  80. package/ftm-inbox/tailwind.config.ts +63 -0
  81. package/ftm-inbox/tsconfig.json +13 -0
  82. package/ftm-inbox/vite.config.ts +6 -0
  83. package/ftm-intent/SKILL.md +44 -0
  84. package/ftm-manifest.json +3794 -0
  85. package/ftm-map/SKILL.md +259 -0
  86. package/ftm-map/scripts/db.py +391 -0
  87. package/ftm-map/scripts/index.py +341 -0
  88. package/ftm-map/scripts/parser.py +455 -0
  89. package/ftm-map/scripts/queries/.gitkeep +0 -0
  90. package/ftm-map/scripts/queries/javascript-tags.scm +23 -0
  91. package/ftm-map/scripts/queries/python-tags.scm +17 -0
  92. package/ftm-map/scripts/queries/typescript-tags.scm +29 -0
  93. package/ftm-map/scripts/query.py +149 -0
  94. package/ftm-map/scripts/requirements.txt +2 -0
  95. package/ftm-map/scripts/setup-hooks.sh +27 -0
  96. package/ftm-map/scripts/setup.sh +45 -0
  97. package/ftm-map/scripts/test_db.py +124 -0
  98. package/ftm-map/scripts/test_parser.py +106 -0
  99. package/ftm-map/scripts/test_query.py +66 -0
  100. package/ftm-map/scripts/tests/fixtures/__init__.py +0 -0
  101. package/ftm-map/scripts/tests/fixtures/sample_project/api.ts +16 -0
  102. package/ftm-map/scripts/tests/fixtures/sample_project/auth.py +15 -0
  103. package/ftm-map/scripts/tests/fixtures/sample_project/utils.js +16 -0
  104. package/ftm-map/scripts/views.py +545 -0
  105. package/ftm-mind/SKILL.md +173 -66
  106. package/ftm-pause/SKILL.md +43 -0
  107. package/ftm-researcher/SKILL.md +275 -0
  108. package/ftm-researcher/evals/agent-diversity.yaml +17 -0
  109. package/ftm-researcher/evals/synthesis-quality.yaml +12 -0
  110. package/ftm-researcher/evals/trigger-accuracy.yaml +39 -0
  111. package/ftm-researcher/references/adaptive-search.md +116 -0
  112. package/ftm-researcher/references/agent-prompts.md +193 -0
  113. package/ftm-researcher/references/council-integration.md +193 -0
  114. package/ftm-researcher/references/output-format.md +203 -0
  115. package/ftm-researcher/references/synthesis-pipeline.md +165 -0
  116. package/ftm-researcher/scripts/score_credibility.py +234 -0
  117. package/ftm-researcher/scripts/validate_research.py +92 -0
  118. package/ftm-resume/SKILL.md +47 -0
  119. package/ftm-retro/SKILL.md +54 -0
  120. package/ftm-routine/SKILL.md +170 -0
  121. package/ftm-state/blackboard/capabilities.json +5 -0
  122. package/ftm-state/blackboard/capabilities.schema.json +27 -0
  123. package/ftm-upgrade/SKILL.md +41 -0
  124. package/ftm-upgrade/scripts/check-version.sh +1 -1
  125. package/ftm-upgrade/scripts/upgrade.sh +1 -1
  126. package/hooks/ftm-blackboard-enforcer.sh +94 -0
  127. package/hooks/ftm-discovery-reminder.sh +90 -0
  128. package/hooks/ftm-drafts-gate.sh +61 -0
  129. package/hooks/ftm-event-logger.mjs +107 -0
  130. package/hooks/ftm-map-autodetect.sh +79 -0
  131. package/hooks/ftm-pending-sync-check.sh +22 -0
  132. package/hooks/ftm-plan-gate.sh +96 -0
  133. package/hooks/ftm-post-commit-trigger.sh +57 -0
  134. package/hooks/settings-template.json +81 -0
  135. package/install.sh +140 -11
  136. package/package.json +12 -2
@@ -164,3 +164,50 @@ To save a session for later:
164
164
  2. When you need to stop, use /ftm-pause
165
165
  3. In a new conversation, use /ftm-resume to continue
166
166
  ```
167
+
168
+ ## Requirements
169
+
170
+ - reference: `~/.claude/ftm-state/STATE.md` | required | saved session state file from ftm-pause
171
+ - reference: `../ftm-pause/references/protocols/SKILL-RESTORE-PROTOCOLS.md` | required | per-skill state field restoration instructions
172
+ - reference: `../ftm-pause/references/protocols/VALIDATION.md` | required | validation protocol for state file integrity
173
+ - reference: `~/.claude/ftm-state/archive/` | optional | archived prior state files
174
+ - tool: `git` | optional | checking git state drift since session was paused
175
+
176
+ ## Risk
177
+
178
+ - level: low_write
179
+ - scope: archives STATE.md by moving it to ~/.claude/ftm-state/archive/; invokes the target ftm skill with restored context; does not modify project source files
180
+ - rollback: copy archived STATE.md back from archive if restoration was incorrect
181
+
182
+ ## Approval Gates
183
+
184
+ - trigger: validation finds warnings (git drift, stale state, missing artifacts) | action: present consolidated validation summary and require user acknowledgment before proceeding
185
+ - trigger: validation finds block-level failure | action: stop and report failure; do not invoke target skill
186
+ - trigger: user provides new context along with "yes" | action: capture as post-pause update and inject into skill invocation
187
+ - complexity_routing: micro → auto | small → auto | medium → auto | large → auto | xl → auto
188
+
189
+ ## Fallbacks
190
+
191
+ - condition: STATE.md not found | action: report "No saved ftm session found" with instructions for saving sessions
192
+ - condition: STATE.md frontmatter missing required fields | action: report validation failure with specific missing fields
193
+ - condition: multiple STATE.md files (STATE.md + STATE-*.md) | action: ask user which to resume, list each with skill type and timestamp
194
+ - condition: state is >7 days old | action: flag as potentially stale with warning, require user acknowledgment
195
+
196
+ ## Capabilities
197
+
198
+ - cli: `git` | optional | branch and commit state validation
199
+ - env: none required
200
+
201
+ ## Event Payloads
202
+
203
+ ### session_resumed
204
+ - skill: string — "ftm-resume"
205
+ - resumed_skill: string — the ftm skill that was re-invoked
206
+ - phase: string — phase the session is resuming at
207
+ - state_age_hours: number — how long ago the session was paused
208
+ - post_pause_update: boolean — whether user provided new context
209
+
210
+ ### task_completed
211
+ - skill: string — "ftm-resume"
212
+ - resumed_skill: string — the ftm skill re-invoked
213
+ - state_file_archived: string — path where STATE.md was archived
@@ -187,3 +187,57 @@ After completing, update:
187
187
  2. Write experience file to `~/.claude/ftm-state/blackboard/experiences/YYYY-MM-DD_task-slug.json`
188
188
  3. Update `experiences/index.json` with the new entry
189
189
  4. Emit `task_completed`
190
+
191
+ ## Requirements
192
+
193
+ - reference: `PROGRESS.md` | optional | executor progress log for auto-triggered mode
194
+ - reference: `~/.claude/ftm-retros/` | optional | prior retro files for pattern analysis
195
+ - reference: `references/protocols/SCORING-RUBRICS.md` | required | scoring scale breakpoints and evidence requirements
196
+ - reference: `references/templates/REPORT-FORMAT.md` | required | retro report output template
197
+ - reference: `~/.claude/ftm-state/blackboard/experiences/index.json` | optional | experience inventory for micro-reflection mode
198
+ - reference: `~/.claude/ftm-state/blackboard/patterns.json` | optional | pattern registry for promotion and decay
199
+
200
+ ## Risk
201
+
202
+ - level: low_write
203
+ - scope: writes retro report to ~/.claude/ftm-retros/; writes experience files to blackboard; promotes patterns to patterns.json; does not modify project source files
204
+ - rollback: delete retro report file; remove experience entry from blackboard
205
+
206
+ ## Approval Gates
207
+
208
+ - trigger: pattern promotion triggered (3+ matching experiences) | action: auto-promote to patterns.json without user gate (learning system behavior)
209
+ - complexity_routing: micro → auto | small → auto | medium → auto | large → auto | xl → auto
210
+
211
+ ## Fallbacks
212
+
213
+ - condition: PROGRESS.md not found and manual mode | action: check ~/.claude/ftm-retros/ for most recent .md file; ask user which execution to review if multiple found
214
+ - condition: execution context not provided by ftm-executor | action: reconstruct from PROGRESS.md or ask user for context
215
+ - condition: scoring rubric file missing | action: apply built-in scoring heuristics from skill body
216
+ - condition: experiences/index.json has fewer than 10 entries | action: cold-start mode — record every task, set all confidence to low
217
+
218
+ ## Capabilities
219
+
220
+ - env: none required
221
+
222
+ ## Event Payloads
223
+
224
+ ### experience_recorded
225
+ - skill: string — "ftm-retro"
226
+ - experience_path: string — path to written experience file
227
+ - task_type: string — type of task recorded
228
+ - outcome: string — success | partial | failure
229
+ - confidence: string — low | medium | high
230
+
231
+ ### pattern_discovered
232
+ - skill: string — "ftm-retro"
233
+ - pattern_name: string — name of the promoted pattern
234
+ - category: string — codebase_insights | execution_patterns | user_behavior | recurring_issues
235
+ - occurrence_count: number — number of experiences that triggered promotion
236
+ - confidence: string — low | medium | high
237
+
238
+ ### task_completed
239
+ - skill: string — "ftm-retro"
240
+ - report_path: string — absolute path to saved retro report
241
+ - overall_score: number — total score out of 50
242
+ - top_issue: string — most impactful bottleneck identified
243
+ - patterns_promoted: number — new patterns added to patterns.json
@@ -0,0 +1,170 @@
1
+ ---
2
+ name: ftm-routine
3
+ description: Execute named, recurring multi-step workflows from YAML definitions. Use when user says "routine", "run routine", "ftm-routine", "morning triage", or names a known routine.
4
+ ---
5
+
6
+ # FTM Routine Runner
7
+
8
+ Routines are named, recurring multi-step workflows defined as YAML in `~/.ftm/routines/`. Each routine specifies steps that combine skill invocations, MCP operations, and approval gates.
9
+
10
+ ## Routine Format
11
+
12
+ Routines are stored as YAML files in `~/.ftm/routines/`:
13
+
14
+ ```yaml
15
+ name: morning-triage
16
+ description: Check all inboxes, prioritize, and plan the day
17
+ trigger: manual # only "manual" for v1, future: "schedule", "event"
18
+ tags: [triage, daily, ops]
19
+
20
+ steps:
21
+ - name: Check Jira backlog
22
+ action: mcp
23
+ tool: jira_search
24
+ params:
25
+ jql: "assignee = currentUser() AND status != Done ORDER BY priority DESC"
26
+ approval: none # no approval needed for read operations
27
+
28
+ - name: Check Freshservice tickets
29
+ action: mcp
30
+ tool: get_tickets
31
+ params:
32
+ filter: "agent_id:me AND status:2" # open tickets assigned to me
33
+ approval: none
34
+
35
+ - name: Check Slack mentions
36
+ action: mcp
37
+ tool: slack_get_channel_history
38
+ params:
39
+ channel: "general"
40
+ limit: 20
41
+ approval: none
42
+
43
+ - name: Check email
44
+ action: mcp
45
+ tool: search_emails
46
+ params:
47
+ query: "is:unread"
48
+ max_results: 10
49
+ approval: none
50
+
51
+ - name: Synthesize and prioritize
52
+ action: skill
53
+ skill: ftm-mind
54
+ input: "Based on the above: prioritize today's work. What's urgent? What can wait?"
55
+ approval: review # show synthesis for user review before proceeding
56
+
57
+ - name: Create today's plan
58
+ action: skill
59
+ skill: ftm-mind
60
+ input: "Create a plan for today's top 3 priorities"
61
+ approval: approve # full plan approval before execution
62
+ ```
63
+
64
+ ## Invocation
65
+
66
+ ```
67
+ /ftm-routine morning-triage
68
+ ```
69
+
70
+ Or via ftm-mind when it detects a routine name:
71
+ ```
72
+ /ftm run my morning triage
73
+ ```
74
+
75
+ ## Execution Flow
76
+
77
+ 1. **Load routine** — Read `~/.ftm/routines/[name].yml`
78
+ 2. **Validate** — Check all referenced MCP tools and skills are available
79
+ 3. **Present as plan** — Convert routine steps to the standard plan format:
80
+ ```
81
+ Routine: morning-triage — "Check all inboxes, prioritize, and plan the day"
82
+
83
+ 1. Check Jira backlog (auto)
84
+ 2. Check Freshservice tickets (auto)
85
+ 3. Check Slack mentions (auto)
86
+ 4. Check email (auto)
87
+ 5. Synthesize and prioritize (review)
88
+ 6. Create today's plan (approve)
89
+
90
+ Steps 1-4 run automatically. Step 5 pauses for your review.
91
+ Step 6 requires your approval before execution.
92
+
93
+ Say "go" to start.
94
+ ```
95
+ 4. **Execute** — Run steps in order, respecting approval gates:
96
+ - `approval: none` — execute automatically, show results
97
+ - `approval: review` — execute, show results, wait for "continue" or "stop"
98
+ - `approval: approve` — show plan, wait for "go" before executing
99
+
100
+ ## Step Types
101
+
102
+ | Action | Description | Example |
103
+ |---|---|---|
104
+ | `mcp` | Call an MCP tool directly | `jira_search`, `slack_post_message` |
105
+ | `skill` | Invoke an FTM skill | `ftm-mind`, `ftm-debug`, `ftm-brainstorm` |
106
+ | `bash` | Run a shell command | `npm test`, `git status` |
107
+
108
+ ## Creating Routines
109
+
110
+ Users create routines by:
111
+ 1. Writing YAML directly to `~/.ftm/routines/[name].yml`
112
+ 2. Saving a successful plan as a routine: "save as routine" (future enhancement)
113
+ 3. Asking ftm-mind: "create a routine for my morning triage"
114
+
115
+ ## Listing Routines
116
+
117
+ ```
118
+ /ftm-routine list
119
+ ```
120
+ Shows all routines in `~/.ftm/routines/` with name and description.
121
+
122
+ ## Example Routines
123
+
124
+ ### morning-triage
125
+ Check Jira, Freshservice, Slack, email → synthesize → prioritize → plan
126
+
127
+ ### deploy-checklist
128
+ Run tests → check CI → review changelog → create release tag → monitor
129
+
130
+ ### new-hire-setup
131
+ Create accounts → set permissions → send welcome email → schedule onboarding
132
+
133
+ ### incident-response
134
+ Check Sentry → check logs → notify channel → create Jira ticket → start investigation
135
+
136
+ ## Requirements
137
+
138
+ - reference: `~/.ftm/routines/` | required | YAML routine definitions directory
139
+ - config: `~/.claude/ftm-config.yml` | optional | model preferences for skill-type steps
140
+
141
+ ## Risk
142
+
143
+ - level: medium_write
144
+ - scope: executes MCP tool calls, skill invocations, and bash commands as defined by the routine; external-facing mutations depend entirely on routine definition; approval gates in the routine control which steps require user confirmation
145
+ - rollback: depends on individual routine steps; steps with approval: approve gate let user review before execution; MCP writes (Jira, Slack, email) may not be reversible
146
+
147
+ ## Approval Gates
148
+
149
+ - trigger: routine step with approval: approve | action: show plan for that step and wait for "go" before executing
150
+ - trigger: routine step with approval: review | action: execute step, show results, wait for "continue" or "stop"
151
+ - trigger: routine step with approval: none | action: execute automatically and show results
152
+ - complexity_routing: micro → auto | small → auto | medium → plan_first (show full routine plan first) | large → plan_first | xl → always_ask
153
+
154
+ ## Fallbacks
155
+
156
+ - condition: routine YAML file not found | action: show "Routine not found" with list of available routines from ~/.ftm/routines/
157
+ - condition: MCP tool referenced in routine not available | action: report unavailable tool, ask user whether to skip that step or abort
158
+ - condition: skill referenced in routine not available | action: report unavailable skill, ask user whether to skip or abort
159
+ - condition: bash command in step fails with non-zero exit | action: report failure output, ask user whether to continue or abort
160
+
161
+ ## Capabilities
162
+
163
+ - mcp: various | optional | determined by individual routine definitions
164
+ - cli: various | optional | bash steps in routine definitions
165
+ - env: none required directly
166
+
167
+ ## Event Payloads
168
+
169
+ ### (none)
170
+ ftm-routine does not emit its own events. Events are emitted by the MCPs and skills invoked during routine execution.
@@ -0,0 +1,5 @@
1
+ {
2
+ "discovered_at": null,
3
+ "expires_at": null,
4
+ "capabilities": []
5
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "FTM Capabilities Snapshot",
4
+ "type": "object",
5
+ "required": ["discovered_at", "expires_at", "capabilities"],
6
+ "properties": {
7
+ "discovered_at": { "type": "string", "format": "date-time" },
8
+ "expires_at": { "type": "string", "format": "date-time" },
9
+ "capabilities": {
10
+ "type": "array",
11
+ "items": {
12
+ "type": "object",
13
+ "required": ["name", "type", "verified", "confidence"],
14
+ "properties": {
15
+ "name": { "type": "string" },
16
+ "type": { "type": "string", "enum": ["mcp", "cli", "api", "env", "browser"] },
17
+ "verified": { "type": "boolean" },
18
+ "last_verified_at": { "type": "string", "format": "date-time" },
19
+ "operations_verified": { "type": "array", "items": { "type": "string" } },
20
+ "path": { "type": "string" },
21
+ "version": { "type": "string" },
22
+ "confidence": { "type": "string", "enum": ["verified", "known", "inferred", "unavailable"] }
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
@@ -151,3 +151,44 @@ Map `CHECK_FAILED <reason>` codes to user-facing messages:
151
151
  **Cache location**: `~/.cache/ftm-brain/version-check`
152
152
  **Version file**: `~/.claude/skills/ftm-version.txt`
153
153
  **Repo**: `kkudumu/ftm-brain`
154
+
155
+ ## Requirements
156
+
157
+ - tool: `gh` | required | GitHub CLI for querying releases from kkudumu/ftm-brain
158
+ - reference: `~/.claude/skills/ftm-upgrade/scripts/check-version.sh` | required | version check and cache script
159
+ - reference: `~/.claude/skills/ftm-upgrade/scripts/upgrade.sh` | required | download and install latest release script
160
+ - reference: `~/.claude/skills/ftm-version.txt` | optional | locally installed version number
161
+
162
+ ## Risk
163
+
164
+ - level: high_write
165
+ - scope: downloads and overwrites skill files in ~/.claude/skills/ on upgrade; changes affect all ftm skill behavior going forward; irreversible without restoring previous version from backup or git
166
+ - rollback: restore from ~/.claude/skills/ backup if one was made before upgrade; or reinstall specific version by downloading an older release tarball
167
+
168
+ ## Approval Gates
169
+
170
+ - trigger: UPGRADE_AVAILABLE detected | action: show current and latest version with changelog URL, wait for explicit "yes" confirmation before running upgrade.sh
171
+ - trigger: version check during preamble (passive notice pattern) | action: show one-line notice only, do NOT ask for confirmation or interrupt workflow
172
+ - complexity_routing: micro → auto | small → auto | medium → auto | large → auto | xl → auto
173
+
174
+ ## Fallbacks
175
+
176
+ - condition: gh not installed | action: report "GitHub CLI not installed" with brew install gh instructions
177
+ - condition: no internet connection | action: report "Cannot reach GitHub. Check internet connection."
178
+ - condition: kkudumu/ftm-brain repo not found | action: report repo not found, suggest verifying access
179
+ - condition: no releases found | action: report "No releases found yet. Check back later."
180
+ - condition: upgrade.sh exits non-zero | action: report failure output, suggest running script manually
181
+
182
+ ## Capabilities
183
+
184
+ - cli: `gh` | required | GitHub CLI for release queries and download
185
+ - cli: `bash` | required | for running check-version.sh and upgrade.sh
186
+
187
+ ## Event Payloads
188
+
189
+ ### task_completed
190
+ - skill: string — "ftm-upgrade"
191
+ - action: string — "check" | "upgrade" | "already_up_to_date"
192
+ - current_version: string | null — version before upgrade
193
+ - new_version: string | null — version after upgrade (null if no upgrade)
194
+ - status: string — "success" | "failed" | "up_to_date" | "check_failed"
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # check-version.sh — Check for ftm-skills updates via GitHub Releases
2
+ # check-version.sh — Check for feed-the-machine updates via GitHub Releases
3
3
  # Outputs: UP_TO_DATE | UPGRADE_AVAILABLE <version> <changelog_url> | CHECK_FAILED <reason>
4
4
 
5
5
  set -uo pipefail
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # upgrade.sh — Download and install latest ftm-skills release
2
+ # upgrade.sh — Download and install latest feed-the-machine release
3
3
  # Usage: upgrade.sh [--version <tag>]
4
4
 
5
5
  set -uo pipefail
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env bash
2
+ # ftm-blackboard-enforcer.sh
3
+ # Stop hook that checks if meaningful work was done but no blackboard
4
+ # experience was recorded. If so, blocks the stop and tells Claude
5
+ # to write the experience first.
6
+ #
7
+ # "Meaningful work" = 3+ tool uses detected by the edit counter,
8
+ # or ftm skills were invoked (checked via context.json).
9
+ #
10
+ # Hook: Stop
11
+
12
+ set -euo pipefail
13
+
14
+ INPUT=$(cat)
15
+
16
+ # Prevent infinite loop — if this hook already fired, let Claude stop
17
+ STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
18
+ if [[ "$STOP_HOOK_ACTIVE" == "true" ]]; then
19
+ exit 0
20
+ fi
21
+
22
+ STATE_DIR="$HOME/.claude/ftm-state"
23
+ BB_DIR="$STATE_DIR/blackboard"
24
+ EDIT_COUNTER="$STATE_DIR/.edit-count"
25
+ CONTEXT_FILE="$BB_DIR/context.json"
26
+ EXPERIENCES_DIR="$BB_DIR/experiences"
27
+ EXPERIENCE_INDEX="$EXPERIENCES_DIR/index.json"
28
+
29
+ CURRENT_SESSION="${CLAUDE_SESSION_ID:-unknown}"
30
+
31
+ # Check 1: Were there meaningful edits this session?
32
+ HAD_EDITS=false
33
+ if [[ -f "$EDIT_COUNTER" ]]; then
34
+ STORED=$(cat "$EDIT_COUNTER" 2>/dev/null || echo "0:unknown")
35
+ STORED_SESSION=$(echo "$STORED" | cut -d: -f2)
36
+ STORED_COUNT=$(echo "$STORED" | cut -d: -f1)
37
+ if [[ "$STORED_SESSION" == "$CURRENT_SESSION" && "$STORED_COUNT" -ge 3 ]]; then
38
+ HAD_EDITS=true
39
+ fi
40
+ fi
41
+
42
+ # Check 2: Were ftm skills invoked this session?
43
+ HAD_SKILLS=false
44
+ if [[ -f "$CONTEXT_FILE" ]]; then
45
+ SKILLS_COUNT=$(jq -r '.session_metadata.skills_invoked | length' "$CONTEXT_FILE" 2>/dev/null || echo "0")
46
+ if [[ "$SKILLS_COUNT" -gt 0 ]]; then
47
+ HAD_SKILLS=true
48
+ fi
49
+ fi
50
+
51
+ # If no meaningful work detected, allow stop
52
+ if [[ "$HAD_EDITS" == "false" && "$HAD_SKILLS" == "false" ]]; then
53
+ exit 0
54
+ fi
55
+
56
+ # Check 3: Was an experience recorded today?
57
+ TODAY=$(date +%Y-%m-%d)
58
+ HAS_EXPERIENCE=false
59
+
60
+ if [[ -d "$EXPERIENCES_DIR" ]]; then
61
+ # Check for experience files created today
62
+ TODAY_EXPERIENCE=$(find "$EXPERIENCES_DIR" -name "${TODAY}*" -type f 2>/dev/null | head -1)
63
+ if [[ -n "$TODAY_EXPERIENCE" ]]; then
64
+ HAS_EXPERIENCE=true
65
+ fi
66
+ fi
67
+
68
+ # Also check if context.json was updated this session (recent_decisions not empty)
69
+ if [[ -f "$CONTEXT_FILE" ]]; then
70
+ DECISIONS_COUNT=$(jq -r '.recent_decisions | length' "$CONTEXT_FILE" 2>/dev/null || echo "0")
71
+ LAST_UPDATED=$(jq -r '.session_metadata.last_updated // ""' "$CONTEXT_FILE" 2>/dev/null || echo "")
72
+ if [[ "$DECISIONS_COUNT" -gt 0 && -n "$LAST_UPDATED" ]]; then
73
+ # Check if last_updated is from today
74
+ if [[ "$LAST_UPDATED" == *"$TODAY"* ]]; then
75
+ HAS_EXPERIENCE=true
76
+ fi
77
+ fi
78
+ fi
79
+
80
+ if [[ "$HAS_EXPERIENCE" == "true" ]]; then
81
+ # Blackboard was written, allow stop
82
+ # Clean up session markers
83
+ rm -f "$EDIT_COUNTER" "$STATE_DIR/.plan-presented" 2>/dev/null
84
+ exit 0
85
+ fi
86
+
87
+ # Work was done but no blackboard write — block the stop
88
+ cat <<'JSON'
89
+ {
90
+ "decision": "block",
91
+ "reason": "[ftm-blackboard-enforcer] You did meaningful work this session (3+ edits or ftm skills used) but did not record an experience to the blackboard. Before stopping, you MUST: (1) Update ~/.claude/ftm-state/blackboard/context.json with current_task status and recent_decisions. (2) Write an experience file to ~/.claude/ftm-state/blackboard/experiences/ with task_type, tags, outcome, lessons, files_touched, stakeholders, and decisions_made. (3) Update ~/.claude/ftm-state/blackboard/experiences/index.json with the new entry. This is how ftm learns — skipping it means the next session starts from zero."
92
+ }
93
+ JSON
94
+ exit 0
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env bash
2
+ # ftm-discovery-reminder.sh
3
+ # UserPromptSubmit hook that detects when a user's prompt mentions
4
+ # external systems, migrations, rerouting, or stakeholder coordination.
5
+ # Injects a reminder about the discovery interview before Claude starts working.
6
+ #
7
+ # This is a soft nudge, not a block — it adds additionalContext that
8
+ # reminds Claude about the ftm-mind discovery interview protocol.
9
+ #
10
+ # Hook: UserPromptSubmit
11
+
12
+ set -euo pipefail
13
+
14
+ INPUT=$(cat)
15
+ PROMPT=$(echo "$INPUT" | jq -r '.prompt // ""')
16
+
17
+ # Lowercase the prompt for matching
18
+ PROMPT_LOWER=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]')
19
+
20
+ # Patterns that indicate external system work requiring discovery interview
21
+ EXTERNAL_PATTERNS=(
22
+ "reroute"
23
+ "migrate"
24
+ "migration"
25
+ "move.*to.*board"
26
+ "move.*to.*project"
27
+ "point.*to.*new"
28
+ "update.*integration"
29
+ "change.*endpoint"
30
+ "switch.*from.*to"
31
+ "redirect.*to"
32
+ "jira.*automation"
33
+ "freshservice.*automation"
34
+ "update.*workflow"
35
+ "change.*routing"
36
+ "slack.*message.*to"
37
+ "email.*to"
38
+ "draft.*message"
39
+ "notify.*about"
40
+ "check.*with"
41
+ "coordinate.*with"
42
+ "ask.*about"
43
+ "tell.*about.*change"
44
+ )
45
+
46
+ # Patterns that indicate the user already provided comprehensive context
47
+ # (e.g., pasted a Slack thread, gave detailed instructions)
48
+ CONTEXT_SIGNALS=(
49
+ "here's the slack"
50
+ "here's the thread"
51
+ "here's what they said"
52
+ "per the conversation"
53
+ "just do it"
54
+ "no questions"
55
+ "skip the interview"
56
+ "don't ask"
57
+ )
58
+
59
+ # Check if user already provided enough context
60
+ for signal in "${CONTEXT_SIGNALS[@]}"; do
61
+ if [[ "$PROMPT_LOWER" == *"$signal"* ]]; then
62
+ exit 0 # User explicitly provided context or asked to skip
63
+ fi
64
+ done
65
+
66
+ # Check for external system patterns
67
+ MATCHED=false
68
+ MATCHED_PATTERN=""
69
+ for pattern in "${EXTERNAL_PATTERNS[@]}"; do
70
+ if echo "$PROMPT_LOWER" | grep -qE "$pattern"; then
71
+ MATCHED=true
72
+ MATCHED_PATTERN="$pattern"
73
+ break
74
+ fi
75
+ done
76
+
77
+ if [[ "$MATCHED" == "false" ]]; then
78
+ exit 0 # No external system work detected
79
+ fi
80
+
81
+ # Inject discovery interview reminder
82
+ cat <<JSON
83
+ {
84
+ "hookSpecificOutput": {
85
+ "hookEventName": "UserPromptSubmit",
86
+ "additionalContext": "[ftm-discovery-reminder] This request involves external systems or stakeholder coordination (matched: ${MATCHED_PATTERN}). Before generating a plan or starting work, run the Discovery Interview from ftm-mind section 10. Ask 2-4 focused questions about: (1) who else needs to know, (2) downstream dependencies, (3) anything to leave as-is, (4) timeline/approval constraints. The user's answers should feed into the plan. Skip the interview ONLY if the user already provided comprehensive context in their message or explicitly said to skip it."
87
+ }
88
+ }
89
+ JSON
90
+ exit 0
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bash
2
+ # ftm-drafts-gate.sh
3
+ # PreToolUse hook for Slack/Gmail send tools.
4
+ #
5
+ # Before allowing a message to be sent via Slack or Gmail, checks that
6
+ # a corresponding draft exists in .ftm-drafts/ (project root) or
7
+ # ~/.claude/ftm-drafts/ (global fallback).
8
+ #
9
+ # If no draft exists, blocks the send and tells Claude to save the draft first.
10
+ #
11
+ # Hook: PreToolUse (matcher: mcp__slack__slack_post_message|mcp__slack__slack_reply_to_thread|mcp__gmail__send_email)
12
+
13
+ set -euo pipefail
14
+
15
+ INPUT=$(cat)
16
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // ""')
17
+
18
+ # Only gate send tools (not reads/searches)
19
+ case "$TOOL_NAME" in
20
+ *slack_post_message*|*slack_reply_to_thread*|*send_email*)
21
+ ;;
22
+ *)
23
+ exit 0 # Not a send tool, allow
24
+ ;;
25
+ esac
26
+
27
+ # Check for drafts in project .ftm-drafts/ or global ~/.claude/ftm-drafts/
28
+ CWD=$(echo "$INPUT" | jq -r '.cwd // ""')
29
+ PROJECT_DRAFTS="${CWD}/.ftm-drafts"
30
+ GLOBAL_DRAFTS="$HOME/.claude/ftm-drafts"
31
+
32
+ HAS_RECENT_DRAFT=false
33
+
34
+ # Check both locations for any draft file modified in the last 30 minutes
35
+ for DRAFTS_DIR in "$PROJECT_DRAFTS" "$GLOBAL_DRAFTS"; do
36
+ if [[ -d "$DRAFTS_DIR" ]]; then
37
+ # Find draft files modified in the last 30 minutes
38
+ RECENT=$(find "$DRAFTS_DIR" -name "*.md" -mmin -30 2>/dev/null | head -1)
39
+ if [[ -n "$RECENT" ]]; then
40
+ HAS_RECENT_DRAFT=true
41
+ break
42
+ fi
43
+ fi
44
+ done
45
+
46
+ if [[ "$HAS_RECENT_DRAFT" == "true" ]]; then
47
+ # Draft exists, allow the send (the external-action-guard will still prompt for approval)
48
+ exit 0
49
+ fi
50
+
51
+ # No draft found — block and tell Claude to save one first
52
+ cat <<JSON
53
+ {
54
+ "hookSpecificOutput": {
55
+ "hookEventName": "PreToolUse",
56
+ "permissionDecision": "deny",
57
+ "permissionDecisionReason": "[ftm-drafts-gate] No draft found in .ftm-drafts/ before sending. Save the message to .ftm-drafts/ first (using the draft-before-send protocol from ftm-mind section 3.5), then retry the send. This creates an audit trail and lets the user review before sending."
58
+ }
59
+ }
60
+ JSON
61
+ exit 0