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.
- package/bin/generate-manifest.mjs +253 -0
- package/bin/install.mjs +134 -4
- package/docs/HOOKS.md +243 -0
- package/docs/INBOX.md +233 -0
- package/ftm/SKILL.md +34 -0
- package/ftm-audit/SKILL.md +69 -0
- package/ftm-brainstorm/SKILL.md +51 -0
- package/ftm-browse/SKILL.md +39 -0
- package/ftm-capture/SKILL.md +370 -0
- package/ftm-capture.yml +4 -0
- package/ftm-codex-gate/SKILL.md +59 -0
- package/ftm-config/SKILL.md +35 -0
- package/ftm-council/SKILL.md +56 -0
- package/ftm-dashboard/SKILL.md +163 -0
- package/ftm-debug/SKILL.md +84 -0
- package/ftm-diagram/SKILL.md +44 -0
- package/ftm-executor/SKILL.md +97 -0
- package/ftm-git/SKILL.md +60 -0
- package/ftm-inbox/backend/__init__.py +0 -0
- package/ftm-inbox/backend/__pycache__/main.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/adapters/__init__.py +0 -0
- package/ftm-inbox/backend/adapters/_retry.py +64 -0
- package/ftm-inbox/backend/adapters/base.py +230 -0
- package/ftm-inbox/backend/adapters/freshservice.py +104 -0
- package/ftm-inbox/backend/adapters/gmail.py +125 -0
- package/ftm-inbox/backend/adapters/jira.py +136 -0
- package/ftm-inbox/backend/adapters/registry.py +192 -0
- package/ftm-inbox/backend/adapters/slack.py +110 -0
- package/ftm-inbox/backend/db/__init__.py +0 -0
- package/ftm-inbox/backend/db/connection.py +54 -0
- package/ftm-inbox/backend/db/schema.py +78 -0
- package/ftm-inbox/backend/executor/__init__.py +7 -0
- package/ftm-inbox/backend/executor/engine.py +149 -0
- package/ftm-inbox/backend/executor/step_runner.py +98 -0
- package/ftm-inbox/backend/main.py +103 -0
- package/ftm-inbox/backend/models/__init__.py +1 -0
- package/ftm-inbox/backend/models/unified_task.py +36 -0
- package/ftm-inbox/backend/planner/__init__.py +6 -0
- package/ftm-inbox/backend/planner/__pycache__/__init__.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/planner/__pycache__/generator.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/planner/__pycache__/schema.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/planner/generator.py +127 -0
- package/ftm-inbox/backend/planner/schema.py +34 -0
- package/ftm-inbox/backend/requirements.txt +5 -0
- package/ftm-inbox/backend/routes/__init__.py +0 -0
- package/ftm-inbox/backend/routes/__pycache__/plan.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/routes/execute.py +186 -0
- package/ftm-inbox/backend/routes/health.py +52 -0
- package/ftm-inbox/backend/routes/inbox.py +68 -0
- package/ftm-inbox/backend/routes/plan.py +271 -0
- package/ftm-inbox/bin/launchagent.mjs +91 -0
- package/ftm-inbox/bin/setup.mjs +188 -0
- package/ftm-inbox/bin/start.sh +10 -0
- package/ftm-inbox/bin/status.sh +17 -0
- package/ftm-inbox/bin/stop.sh +8 -0
- package/ftm-inbox/config.example.yml +55 -0
- package/ftm-inbox/package-lock.json +2898 -0
- package/ftm-inbox/package.json +26 -0
- package/ftm-inbox/postcss.config.js +6 -0
- package/ftm-inbox/src/app.css +199 -0
- package/ftm-inbox/src/app.html +18 -0
- package/ftm-inbox/src/lib/api.ts +166 -0
- package/ftm-inbox/src/lib/components/ExecutionLog.svelte +81 -0
- package/ftm-inbox/src/lib/components/InboxFeed.svelte +143 -0
- package/ftm-inbox/src/lib/components/PlanStep.svelte +271 -0
- package/ftm-inbox/src/lib/components/PlanView.svelte +206 -0
- package/ftm-inbox/src/lib/components/StreamPanel.svelte +99 -0
- package/ftm-inbox/src/lib/components/TaskCard.svelte +190 -0
- package/ftm-inbox/src/lib/components/ui/EmptyState.svelte +63 -0
- package/ftm-inbox/src/lib/components/ui/KawaiiCard.svelte +86 -0
- package/ftm-inbox/src/lib/components/ui/PillButton.svelte +106 -0
- package/ftm-inbox/src/lib/components/ui/StatusBadge.svelte +67 -0
- package/ftm-inbox/src/lib/components/ui/StreamDrawer.svelte +149 -0
- package/ftm-inbox/src/lib/components/ui/ThemeToggle.svelte +80 -0
- package/ftm-inbox/src/lib/theme.ts +47 -0
- package/ftm-inbox/src/routes/+layout.svelte +76 -0
- package/ftm-inbox/src/routes/+page.svelte +401 -0
- package/ftm-inbox/static/favicon.png +0 -0
- package/ftm-inbox/svelte.config.js +12 -0
- package/ftm-inbox/tailwind.config.ts +63 -0
- package/ftm-inbox/tsconfig.json +13 -0
- package/ftm-inbox/vite.config.ts +6 -0
- package/ftm-intent/SKILL.md +44 -0
- package/ftm-manifest.json +3794 -0
- package/ftm-map/SKILL.md +259 -0
- package/ftm-map/scripts/db.py +391 -0
- package/ftm-map/scripts/index.py +341 -0
- package/ftm-map/scripts/parser.py +455 -0
- package/ftm-map/scripts/queries/.gitkeep +0 -0
- package/ftm-map/scripts/queries/javascript-tags.scm +23 -0
- package/ftm-map/scripts/queries/python-tags.scm +17 -0
- package/ftm-map/scripts/queries/typescript-tags.scm +29 -0
- package/ftm-map/scripts/query.py +149 -0
- package/ftm-map/scripts/requirements.txt +2 -0
- package/ftm-map/scripts/setup-hooks.sh +27 -0
- package/ftm-map/scripts/setup.sh +45 -0
- package/ftm-map/scripts/test_db.py +124 -0
- package/ftm-map/scripts/test_parser.py +106 -0
- package/ftm-map/scripts/test_query.py +66 -0
- package/ftm-map/scripts/tests/fixtures/__init__.py +0 -0
- package/ftm-map/scripts/tests/fixtures/sample_project/api.ts +16 -0
- package/ftm-map/scripts/tests/fixtures/sample_project/auth.py +15 -0
- package/ftm-map/scripts/tests/fixtures/sample_project/utils.js +16 -0
- package/ftm-map/scripts/views.py +545 -0
- package/ftm-mind/SKILL.md +173 -66
- package/ftm-pause/SKILL.md +43 -0
- package/ftm-researcher/SKILL.md +275 -0
- package/ftm-researcher/evals/agent-diversity.yaml +17 -0
- package/ftm-researcher/evals/synthesis-quality.yaml +12 -0
- package/ftm-researcher/evals/trigger-accuracy.yaml +39 -0
- package/ftm-researcher/references/adaptive-search.md +116 -0
- package/ftm-researcher/references/agent-prompts.md +193 -0
- package/ftm-researcher/references/council-integration.md +193 -0
- package/ftm-researcher/references/output-format.md +203 -0
- package/ftm-researcher/references/synthesis-pipeline.md +165 -0
- package/ftm-researcher/scripts/score_credibility.py +234 -0
- package/ftm-researcher/scripts/validate_research.py +92 -0
- package/ftm-resume/SKILL.md +47 -0
- package/ftm-retro/SKILL.md +54 -0
- package/ftm-routine/SKILL.md +170 -0
- package/ftm-state/blackboard/capabilities.json +5 -0
- package/ftm-state/blackboard/capabilities.schema.json +27 -0
- package/ftm-upgrade/SKILL.md +41 -0
- package/ftm-upgrade/scripts/check-version.sh +1 -1
- package/ftm-upgrade/scripts/upgrade.sh +1 -1
- package/hooks/ftm-blackboard-enforcer.sh +94 -0
- package/hooks/ftm-discovery-reminder.sh +90 -0
- package/hooks/ftm-drafts-gate.sh +61 -0
- package/hooks/ftm-event-logger.mjs +107 -0
- package/hooks/ftm-map-autodetect.sh +79 -0
- package/hooks/ftm-pending-sync-check.sh +22 -0
- package/hooks/ftm-plan-gate.sh +96 -0
- package/hooks/ftm-post-commit-trigger.sh +57 -0
- package/hooks/settings-template.json +81 -0
- package/install.sh +140 -11
- package/package.json +12 -2
package/ftm-resume/SKILL.md
CHANGED
|
@@ -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
|
package/ftm-retro/SKILL.md
CHANGED
|
@@ -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,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
|
+
}
|
package/ftm-upgrade/SKILL.md
CHANGED
|
@@ -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
|
|
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
|
|
@@ -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
|