feed-the-machine 1.0.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/LICENSE +21 -0
- package/README.md +268 -0
- package/bin/generate-manifest.mjs +210 -0
- package/bin/install.mjs +114 -0
- package/ftm/SKILL.md +88 -0
- package/ftm-audit/SKILL.md +146 -0
- package/ftm-audit/references/protocols/PROJECT-PATTERNS.md +91 -0
- package/ftm-audit/references/protocols/RUNTIME-WIRING.md +66 -0
- package/ftm-audit/references/protocols/WIRING-CONTRACTS.md +135 -0
- package/ftm-audit/references/strategies/AUTO-FIX-STRATEGIES.md +69 -0
- package/ftm-audit/references/templates/REPORT-FORMAT.md +96 -0
- package/ftm-audit/scripts/run-knip.sh +23 -0
- package/ftm-audit.yml +2 -0
- package/ftm-brainstorm/SKILL.md +379 -0
- package/ftm-brainstorm/evals/evals.json +100 -0
- package/ftm-brainstorm/evals/promptfoo.yaml +109 -0
- package/ftm-brainstorm/references/agent-prompts.md +224 -0
- package/ftm-brainstorm/references/plan-template.md +121 -0
- package/ftm-brainstorm.yml +2 -0
- package/ftm-browse/SKILL.md +415 -0
- package/ftm-browse/daemon/browser-manager.ts +206 -0
- package/ftm-browse/daemon/bun.lock +30 -0
- package/ftm-browse/daemon/cli.ts +347 -0
- package/ftm-browse/daemon/commands.ts +410 -0
- package/ftm-browse/daemon/main.ts +357 -0
- package/ftm-browse/daemon/package.json +17 -0
- package/ftm-browse/daemon/server.ts +189 -0
- package/ftm-browse/daemon/snapshot.ts +519 -0
- package/ftm-browse/daemon/tsconfig.json +22 -0
- package/ftm-browse.yml +4 -0
- package/ftm-codex-gate/SKILL.md +302 -0
- package/ftm-codex-gate.yml +2 -0
- package/ftm-config/SKILL.md +310 -0
- package/ftm-config.default.yml +80 -0
- package/ftm-config.yml +2 -0
- package/ftm-council/SKILL.md +132 -0
- package/ftm-council/references/prompts/CLAUDE-INVESTIGATION.md +60 -0
- package/ftm-council/references/prompts/CODEX-INVESTIGATION.md +58 -0
- package/ftm-council/references/prompts/GEMINI-INVESTIGATION.md +58 -0
- package/ftm-council/references/prompts/REBUTTAL-TEMPLATE.md +57 -0
- package/ftm-council/references/protocols/PREREQUISITES.md +47 -0
- package/ftm-council/references/protocols/STEP-0-FRAMING.md +46 -0
- package/ftm-council.yml +2 -0
- package/ftm-dashboard.yml +4 -0
- package/ftm-debug/SKILL.md +146 -0
- package/ftm-debug/references/phases/PHASE-0-INTAKE.md +58 -0
- package/ftm-debug/references/phases/PHASE-1-TRIAGE.md +46 -0
- package/ftm-debug/references/phases/PHASE-2-WAR-ROOM-AGENTS.md +279 -0
- package/ftm-debug/references/phases/PHASE-3-TO-6-EXECUTION.md +436 -0
- package/ftm-debug/references/protocols/BLACKBOARD.md +86 -0
- package/ftm-debug/references/protocols/EDGE-CASES.md +103 -0
- package/ftm-debug.yml +2 -0
- package/ftm-diagram/SKILL.md +233 -0
- package/ftm-diagram.yml +2 -0
- package/ftm-executor/SKILL.md +657 -0
- package/ftm-executor/references/STYLE-TEMPLATE.md +73 -0
- package/ftm-executor/references/phases/PHASE-0-VERIFICATION.md +62 -0
- package/ftm-executor/references/phases/PHASE-2-AGENT-ASSEMBLY.md +34 -0
- package/ftm-executor/references/phases/PHASE-3-WORKTREES.md +38 -0
- package/ftm-executor/references/phases/PHASE-4-5-AUDIT.md +72 -0
- package/ftm-executor/references/phases/PHASE-4-DISPATCH.md +66 -0
- package/ftm-executor/references/phases/PHASE-5-5-CODEX-GATE.md +73 -0
- package/ftm-executor/references/protocols/DOCUMENTATION-BOOTSTRAP.md +36 -0
- package/ftm-executor/references/protocols/MODEL-PROFILE.md +44 -0
- package/ftm-executor/references/protocols/PROGRESS-TRACKING.md +66 -0
- package/ftm-executor/runtime/ftm-runtime.mjs +252 -0
- package/ftm-executor/runtime/package.json +8 -0
- package/ftm-executor.yml +2 -0
- package/ftm-git/SKILL.md +195 -0
- package/ftm-git/evals/evals.json +26 -0
- package/ftm-git/evals/promptfoo.yaml +75 -0
- package/ftm-git/hooks/post-commit-experience.sh +92 -0
- package/ftm-git/references/patterns/SECRET-PATTERNS.md +104 -0
- package/ftm-git/references/protocols/REMEDIATION.md +139 -0
- package/ftm-git/scripts/pre-commit-secrets.sh +110 -0
- package/ftm-git.yml +2 -0
- package/ftm-intent/SKILL.md +198 -0
- package/ftm-intent.yml +2 -0
- package/ftm-map.yml +2 -0
- package/ftm-mind/SKILL.md +986 -0
- package/ftm-mind/evals/promptfoo.yaml +142 -0
- package/ftm-mind/references/blackboard-schema.md +328 -0
- package/ftm-mind/references/complexity-guide.md +110 -0
- package/ftm-mind/references/event-registry.md +299 -0
- package/ftm-mind/references/mcp-inventory.md +296 -0
- package/ftm-mind/references/protocols/COMPLEXITY-SIZING.md +72 -0
- package/ftm-mind/references/protocols/MCP-HEURISTICS.md +32 -0
- package/ftm-mind/references/protocols/PLAN-APPROVAL.md +80 -0
- package/ftm-mind/references/reflexion-protocol.md +249 -0
- package/ftm-mind/references/routing/SCENARIOS.md +22 -0
- package/ftm-mind/references/routing-scenarios.md +35 -0
- package/ftm-mind.yml +2 -0
- package/ftm-pause/SKILL.md +133 -0
- package/ftm-pause/references/protocols/SKILL-RESTORE-PROTOCOLS.md +186 -0
- package/ftm-pause/references/protocols/VALIDATION.md +80 -0
- package/ftm-pause.yml +2 -0
- package/ftm-researcher.yml +2 -0
- package/ftm-resume/SKILL.md +166 -0
- package/ftm-resume/references/protocols/VALIDATION.md +172 -0
- package/ftm-resume.yml +2 -0
- package/ftm-retro/SKILL.md +189 -0
- package/ftm-retro/references/protocols/SCORING-RUBRICS.md +89 -0
- package/ftm-retro/references/templates/REPORT-FORMAT.md +109 -0
- package/ftm-retro.yml +2 -0
- package/ftm-routine.yml +4 -0
- package/ftm-state/blackboard/context.json +23 -0
- package/ftm-state/blackboard/experiences/index.json +9 -0
- package/ftm-state/blackboard/patterns.json +6 -0
- package/ftm-state/schemas/context.schema.json +130 -0
- package/ftm-state/schemas/experience-index.schema.json +77 -0
- package/ftm-state/schemas/experience.schema.json +78 -0
- package/ftm-state/schemas/patterns.schema.json +44 -0
- package/ftm-upgrade/SKILL.md +153 -0
- package/ftm-upgrade/scripts/check-version.sh +76 -0
- package/ftm-upgrade/scripts/upgrade.sh +143 -0
- package/ftm-upgrade.yml +2 -0
- package/ftm.yml +2 -0
- package/install.sh +102 -0
- package/package.json +74 -0
- package/uninstall.sh +25 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kkudumu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Feed The Machine
|
|
2
|
+
|
|
3
|
+
Models get smarter every quarter. Your workflow shouldn't have to start over every time.
|
|
4
|
+
|
|
5
|
+
FTM is a cognitive architecture for Claude Code — not a prompt library, not a wrapper, not scaffolding that dies on the next model drop. It's a persistent intelligence layer that learns how *you* work and gets better every time you use it. The OODA (Observe, Orient, Decide, Act) reasoning loop, the blackboard memory, the multi-model deliberation, the event mesh — these are design patterns that become *more* valuable as models improve, not less.
|
|
6
|
+
|
|
7
|
+
Drop in anything. A support ticket, a feature spec, a bug report, a half-formed idea, a meeting transcript, a "figure this out." The machine reads everything, proposes a plan, waits for your approval, then executes end-to-end. Every successful execution becomes a playbook. Every playbook makes the next similar task faster.
|
|
8
|
+
|
|
9
|
+
The machine hungers. You feed it. It takes care of you.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Plain English
|
|
14
|
+
|
|
15
|
+
You know how every time you start a new chat with an AI, it has no idea who you are, what you're working on, or what you tried last time? You end up repeating yourself constantly. And when you ask it to do something complex, you have to hold its hand through every single step.
|
|
16
|
+
|
|
17
|
+
FTM fixes that.
|
|
18
|
+
|
|
19
|
+
It's a brain upgrade for Claude Code (Anthropic's AI coding tool). You install it once, and from that point on:
|
|
20
|
+
|
|
21
|
+
- **It remembers.** Not just within one conversation — across all of them. It builds a memory of your projects, your preferences, what worked before, and what didn't. The more you use it, the less you have to explain.
|
|
22
|
+
|
|
23
|
+
- **It plans before it acts.** You throw a task at it — could be a bug, a feature request, a vague idea, whatever — and instead of immediately doing something dumb, it reads your context, makes a plan, and shows you the plan first. You approve it, tweak it, or tell it to rethink. Then it goes.
|
|
24
|
+
|
|
25
|
+
- **It does the whole thing, not just one step.** Most AI tools help you write a function or answer a question. FTM coordinates entire workflows — it can read a support ticket, look up the customer's history, draft a response, update the ticket, and notify your team. All from one input.
|
|
26
|
+
|
|
27
|
+
- **It gets a second opinion.** For hard decisions, it doesn't just trust one AI. It asks Claude, GPT, and Gemini independently, then picks the answer where at least two agree. Like calling three contractors instead of trusting the first quote.
|
|
28
|
+
|
|
29
|
+
- **It gets better over time.** Every task it completes becomes a playbook. See the same type of bug three times? It already knows the pattern. Similar support ticket? It remembers what worked last time. It's not just a tool — it's a tool that sharpens itself.
|
|
30
|
+
|
|
31
|
+
Think of it like this: regular AI is a blank whiteboard every time you walk into the room. FTM is an assistant who was in yesterday's meeting, read the doc you shared last week, and already has a draft ready when you walk in.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Why This Exists
|
|
36
|
+
|
|
37
|
+
Most AI tooling is disposable by design. You write prompts, the model gets better, your prompts become unnecessary. That's the scaffolding thesis — and it's true for most of what people are building.
|
|
38
|
+
|
|
39
|
+
FTM is built on the opposite bet: **the orchestration layer survives model drops.** Three things in this system are structurally hard for any single model provider to absorb:
|
|
40
|
+
|
|
41
|
+
**Persistent memory that compounds.** Claude's native memory is conversation-scoped. FTM's blackboard is a three-tier knowledge store — context, experiences, patterns — that persists across every session. By your twentieth task, it knows your stack, your team's conventions, the quirks of your external services, and what kinds of plans you tend to push back on. It's not remembering facts. It's building judgment.
|
|
42
|
+
|
|
43
|
+
**Multi-model deliberation.** FTM's council sends hard decisions to Claude, Codex, and Gemini as equal peers, then loops through rounds of debate until 2-of-3 agree. No model provider will ever natively ship "ask our competitors for a second opinion." That's permanently outside their incentive structure.
|
|
44
|
+
|
|
45
|
+
**Event-driven skill composition.** 18 typed events wire skills together automatically — a commit triggers documentation updates and architecture diagrams, a completed task triggers micro-reflection, a wave boundary triggers adversarial validation. This is workflow orchestration that sits above any single model's capability. It's closer to what Temporal does than what a model improvement would replace.
|
|
46
|
+
|
|
47
|
+
The ideas are portable. The architecture is model-agnostic. The skills format is just the current packaging.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## The Loop
|
|
52
|
+
|
|
53
|
+
Every task, every time:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
FEED --> PLAN --> APPROVE --> EXECUTE --> LEARN
|
|
57
|
+
^ |
|
|
58
|
+
+------------- (next task) --------------+
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**FEED** — Paste anything. A ticket URL. A spec doc. An error stack trace. A Slack thread. Plain English. The machine reads it all.
|
|
62
|
+
|
|
63
|
+
**PLAN** — ftm-mind runs the OODA loop (Observe what you gave it, Orient using blackboard memory, Decide on an approach, Act by assembling the right skills) and proposes a concrete plan with numbered steps.
|
|
64
|
+
|
|
65
|
+
**APPROVE** — You review the plan. Modify it, ask questions, or just say "go."
|
|
66
|
+
|
|
67
|
+
**EXECUTE** — Parallel agent teams work through the plan. Each wave completes, validates, and checks in before the next begins. Browser automation, git ops, test runs, API calls — all coordinated.
|
|
68
|
+
|
|
69
|
+
**LEARN** — Every outcome writes back to the blackboard: what worked, what failed, what pattern to remember. Next time you bring a similar task, the machine already knows the shape of it.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Architecture
|
|
74
|
+
|
|
75
|
+
```mermaid
|
|
76
|
+
graph TD
|
|
77
|
+
User["User Input\n(ticket / spec / idea / error)"] --> Mind
|
|
78
|
+
|
|
79
|
+
subgraph Core["FTM Core"]
|
|
80
|
+
Mind["ftm-mind\n(OODA Cognitive Loop)"]
|
|
81
|
+
BB["Blackboard\ncontext.json\nexperiences/\npatterns.json"]
|
|
82
|
+
Mesh["Event Mesh\n18 typed events"]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
Mind <-->|read / write| BB
|
|
86
|
+
Mind -->|route| Mesh
|
|
87
|
+
|
|
88
|
+
subgraph Skills["Skill Layer"]
|
|
89
|
+
Storm["ftm-brainstorm\nSocratic ideation\n+ parallel research"]
|
|
90
|
+
Debug["ftm-debug\nMulti-vector\ndebugging war room"]
|
|
91
|
+
Exec["ftm-executor\nAutonomous plan\nexecution"]
|
|
92
|
+
Council["ftm-council\nClaude + Codex + Gemini\n2-of-3 consensus"]
|
|
93
|
+
Browse["ftm-browse\nHeadless browser\n+ accessibility inspection"]
|
|
94
|
+
Git["ftm-git\nSecret scanning\n+ credential gate"]
|
|
95
|
+
Audit["ftm-audit\nKnip + adversarial\nLLM wiring check"]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
Mesh --> Storm
|
|
99
|
+
Mesh --> Debug
|
|
100
|
+
Mesh --> Exec
|
|
101
|
+
Mesh --> Council
|
|
102
|
+
Mesh --> Browse
|
|
103
|
+
Mesh --> Git
|
|
104
|
+
Mesh --> Audit
|
|
105
|
+
|
|
106
|
+
subgraph Integrations["External Integrations (via MCP)"]
|
|
107
|
+
Jira["Jira"]
|
|
108
|
+
FS["Freshservice"]
|
|
109
|
+
Slack["Slack"]
|
|
110
|
+
Gmail["Gmail"]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
Browse --> Jira
|
|
114
|
+
Browse --> FS
|
|
115
|
+
Mind --> Slack
|
|
116
|
+
Mind --> Gmail
|
|
117
|
+
|
|
118
|
+
Exec -->|code_committed| Intent["ftm-intent\nINTENT.md layer"]
|
|
119
|
+
Exec -->|code_committed| Diagram["ftm-diagram\nARCHITECTURE.mmd"]
|
|
120
|
+
Exec -->|task_completed| Retro["ftm-retro\nmicro-reflection"]
|
|
121
|
+
Exec -->|wave boundary| Gate["ftm-codex-gate\nadversarial validation"]
|
|
122
|
+
Gate --> Exec
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## First 5 Minutes
|
|
128
|
+
|
|
129
|
+
Install:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx feed-the-machine@latest
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Symlinks all 16+ skills into `~/.claude/skills/` where Claude Code discovers them automatically. That's it.
|
|
136
|
+
|
|
137
|
+
**Three things to try right now:**
|
|
138
|
+
|
|
139
|
+
**1. Feed it a task:**
|
|
140
|
+
```
|
|
141
|
+
/ftm
|
|
142
|
+
```
|
|
143
|
+
Paste anything — a Jira ticket, a Freshservice request, a Slack message, or just describe what you need done. FTM reads it, pulls relevant context from your blackboard, proposes a plan, and waits for your go.
|
|
144
|
+
|
|
145
|
+
**2. Think something through:**
|
|
146
|
+
```
|
|
147
|
+
/ftm-brainstorm
|
|
148
|
+
```
|
|
149
|
+
Describe something you're trying to figure out. It runs parallel web and GitHub research agents, challenges your assumptions Socratically, and surfaces options you hadn't considered.
|
|
150
|
+
|
|
151
|
+
**3. Kill a bug:**
|
|
152
|
+
```
|
|
153
|
+
/ftm-debug
|
|
154
|
+
```
|
|
155
|
+
Paste an error message, stack trace, or just describe unexpected behavior. It opens a multi-vector war room — static analysis, runtime hypothesis testing, dependency auditing — running in parallel.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Before / After
|
|
160
|
+
|
|
161
|
+
### Triaging a support ticket
|
|
162
|
+
|
|
163
|
+
**Without FTM** — Open the ticket. Read it. Check Slack for context. Look up the customer's history. Figure out who should handle it. Draft a response. Copy-paste between four tabs. 30 minutes of context-gathering before any real work starts.
|
|
164
|
+
|
|
165
|
+
**With FTM** — Paste the ticket URL. FTM reads the ticket, pulls the Slack thread, checks your blackboard for similar past issues, proposes a triage plan (categorize, assign, draft response, update ticket), and waits. You say "go." Done in 3 minutes.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### Building a feature from a spec
|
|
170
|
+
|
|
171
|
+
**Without FTM** — You open five files, context-switch between the spec and the codebase, write the route, realize the middleware pattern is different from what you remembered, check another file, write tests separately, forget to update the docs, ship it and wonder why the audit is failing.
|
|
172
|
+
|
|
173
|
+
**With FTM** — You paste the spec. FTM reads the existing patterns in your codebase (blackboard knows your stack), proposes a plan: route, handler, validation, tests, INTENT update, audit check. Parallel agents handle the implementation waves. ftm-codex-gate validates at each boundary. Documentation updates automatically on commit. The whole thing is coherent from the start.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
### Configuring an admin console
|
|
178
|
+
|
|
179
|
+
**Without FTM** — 45 minutes. Find the vendor docs. Navigate the admin panel manually. Cross-reference settings. Copy-paste values without fat-fingering them. Update the ticket. Hope you didn't miss a field.
|
|
180
|
+
|
|
181
|
+
**With FTM** — 5 minutes. Paste the ticket. FTM reads the config docs, opens a headless browser, navigates the admin panel, fills fields from the ticket spec, screenshots the result for verification, and drafts the ticket update. You review and approve each step.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Skill Inventory
|
|
186
|
+
|
|
187
|
+
| Skill | What It Does |
|
|
188
|
+
|-------|-------------|
|
|
189
|
+
| **ftm-mind** | Observe-Orient-Decide-Act cognitive loop — the universal entry point; reads context, sizes tasks, routes everything |
|
|
190
|
+
| **ftm-executor** | Autonomous plan execution with dynamically assembled agent teams and wave-by-wave progress |
|
|
191
|
+
| **ftm-debug** | Multi-vector debugging war room — parallel hypothesis testing, static + runtime + dependency analysis |
|
|
192
|
+
| **ftm-brainstorm** | Socratic ideation with parallel web and GitHub research agents; challenges assumptions, surfaces options |
|
|
193
|
+
| **ftm-audit** | Wiring verification — knip static analysis plus adversarial LLM audit of skill connections |
|
|
194
|
+
| **ftm-council** | Multi-model deliberation — Claude, Codex, and Gemini debate to 2-of-3 consensus on hard decisions |
|
|
195
|
+
| **ftm-codex-gate** | Adversarial Codex validation at executor wave boundaries before proceeding |
|
|
196
|
+
| **ftm-retro** | Post-execution retrospectives and continuous micro-reflections after every task |
|
|
197
|
+
| **ftm-intent** | INTENT.md documentation layer — function-level contracts, auto-updated on every commit |
|
|
198
|
+
| **ftm-diagram** | ARCHITECTURE.mmd mermaid diagrams — auto-regenerated after commits |
|
|
199
|
+
| **ftm-browse** | Headless browser — screenshots, accessibility tree inspection, form automation, visual verification |
|
|
200
|
+
| **ftm-git** | Secret scanning and credential safety gate for all git operations |
|
|
201
|
+
| **ftm-pause** | Save current session state to the blackboard mid-task |
|
|
202
|
+
| **ftm-resume** | Restore a paused session and continue exactly where you left off |
|
|
203
|
+
| **ftm-upgrade** | Self-upgrade from GitHub releases |
|
|
204
|
+
| **ftm-config** | Configure model profiles and execution preferences |
|
|
205
|
+
| **ftm** | Bare invocation — equivalent to `/ftm-mind` with plain-language input |
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## How It Learns
|
|
210
|
+
|
|
211
|
+
The blackboard is a three-tier knowledge store that persists across every session:
|
|
212
|
+
|
|
213
|
+
| Tier | What's Stored | When It's Read |
|
|
214
|
+
|------|--------------|----------------|
|
|
215
|
+
| `context.json` | Current task, recent decisions, your stated preferences | Every single request |
|
|
216
|
+
| `experiences/*.json` | Per-task learnings — one file per completed task, tagged by type | Orient phase, filtered by similarity to current task |
|
|
217
|
+
| `patterns.json` | Insights promoted after 3+ confirming experiences — durable heuristics | Orient phase, matched to the current situation |
|
|
218
|
+
|
|
219
|
+
Cold start is fine. The blackboard bootstraps aggressively in the first ten interactions and reaches useful density fast. By session twenty, FTM knows your stack, your team's conventions, the quirks of your external services, and what kinds of plans you tend to push back on.
|
|
220
|
+
|
|
221
|
+
Every skill writes back. ftm-executor writes task outcomes. ftm-debug writes what the root cause turned out to be. ftm-retro promotes patterns when it sees the same learning three times. The machine gets better with every task you feed it.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Install & Config
|
|
226
|
+
|
|
227
|
+
**Quick start:** See [docs/QUICKSTART.md](docs/QUICKSTART.md)
|
|
228
|
+
|
|
229
|
+
**Configuration reference:** See [docs/CONFIGURATION.md](docs/CONFIGURATION.md)
|
|
230
|
+
|
|
231
|
+
**Development install:**
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
git clone https://github.com/kkudumu/feed-the-machine.git ~/feed-the-machine
|
|
235
|
+
cd ~/feed-the-machine
|
|
236
|
+
./install.sh
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Pull updates anytime: `git pull && ./install.sh`
|
|
240
|
+
|
|
241
|
+
Remove: `./uninstall.sh` (removes symlinks only, keeps your blackboard data)
|
|
242
|
+
|
|
243
|
+
**Model profiles** — edit `~/.claude/ftm-config.yml`:
|
|
244
|
+
|
|
245
|
+
```yaml
|
|
246
|
+
profile: balanced # quality | balanced | budget
|
|
247
|
+
|
|
248
|
+
profiles:
|
|
249
|
+
balanced:
|
|
250
|
+
planning: opus # brainstorm, research
|
|
251
|
+
execution: sonnet # agent task implementation
|
|
252
|
+
review: sonnet # audit, debug review
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Optional dependencies** for the full stack:
|
|
256
|
+
|
|
257
|
+
- [Codex CLI](https://github.com/openai/codex) — required for `ftm-council` and `ftm-codex-gate`
|
|
258
|
+
- [Gemini CLI](https://github.com/google/gemini-cli) — required for `ftm-council`
|
|
259
|
+
- Playwright MCP server (`npx @playwright/mcp@latest`) — required for `ftm-browse`
|
|
260
|
+
*(MCP = Model Context Protocol — the standard way AI tools connect to external services)*
|
|
261
|
+
|
|
262
|
+
All other skills run on Claude Code alone.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## License
|
|
267
|
+
|
|
268
|
+
MIT
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* generate-manifest.mjs
|
|
4
|
+
*
|
|
5
|
+
* Scans all ftm skill SKILL.md files and produces ftm-manifest.json
|
|
6
|
+
* at the project root with structured metadata for each skill.
|
|
7
|
+
*
|
|
8
|
+
* Usage: node bin/generate-manifest.mjs
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { fileURLToPath } from 'url';
|
|
14
|
+
import matter from 'gray-matter';
|
|
15
|
+
|
|
16
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Discovery — collect all SKILL.md paths
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Returns an array of { skillFile, skillDir, triggerFile } objects.
|
|
25
|
+
* Handles both ftm-X/SKILL.md pattern and the special ftm/SKILL.md root skill.
|
|
26
|
+
*/
|
|
27
|
+
function discoverSkillFiles() {
|
|
28
|
+
const entries = fs.readdirSync(ROOT, { withFileTypes: true });
|
|
29
|
+
const skills = [];
|
|
30
|
+
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
if (!entry.isDirectory()) continue;
|
|
33
|
+
|
|
34
|
+
const dirName = entry.name;
|
|
35
|
+
|
|
36
|
+
// Root ftm skill
|
|
37
|
+
if (dirName === 'ftm') {
|
|
38
|
+
const skillFile = path.join(ROOT, 'ftm', 'SKILL.md');
|
|
39
|
+
if (fs.existsSync(skillFile)) {
|
|
40
|
+
skills.push({
|
|
41
|
+
skillFile,
|
|
42
|
+
skillDir: 'ftm/',
|
|
43
|
+
triggerFile: 'ftm.yml',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ftm-* skill directories
|
|
50
|
+
if (dirName.startsWith('ftm-')) {
|
|
51
|
+
const skillFile = path.join(ROOT, dirName, 'SKILL.md');
|
|
52
|
+
if (fs.existsSync(skillFile)) {
|
|
53
|
+
skills.push({
|
|
54
|
+
skillFile,
|
|
55
|
+
skillDir: `${dirName}/`,
|
|
56
|
+
triggerFile: `${dirName}.yml`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return skills;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Parsing helpers
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Splits markdown content into a map of { sectionHeading -> lines[] }.
|
|
71
|
+
* Tracks both ## and ### headings.
|
|
72
|
+
*/
|
|
73
|
+
function parseSections(content) {
|
|
74
|
+
const lines = content.split('\n');
|
|
75
|
+
const sections = {};
|
|
76
|
+
let currentHeading = null;
|
|
77
|
+
|
|
78
|
+
for (const line of lines) {
|
|
79
|
+
const h2Match = line.match(/^##\s+(.+)/);
|
|
80
|
+
const h3Match = line.match(/^###\s+(.+)/);
|
|
81
|
+
|
|
82
|
+
if (h2Match) {
|
|
83
|
+
currentHeading = h2Match[1].trim();
|
|
84
|
+
sections[currentHeading] = [];
|
|
85
|
+
} else if (h3Match) {
|
|
86
|
+
currentHeading = h3Match[1].trim();
|
|
87
|
+
sections[currentHeading] = [];
|
|
88
|
+
} else if (currentHeading !== null) {
|
|
89
|
+
sections[currentHeading].push(line);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return sections;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Extracts event names from lines under an Emits or Listens To section.
|
|
98
|
+
* Format: - `event_name` — description
|
|
99
|
+
*/
|
|
100
|
+
function extractEventNames(lines) {
|
|
101
|
+
const events = [];
|
|
102
|
+
const eventRegex = /^-\s*`([^`]+)`/;
|
|
103
|
+
|
|
104
|
+
for (const line of lines) {
|
|
105
|
+
const match = line.match(eventRegex);
|
|
106
|
+
if (match) {
|
|
107
|
+
events.push(match[1]);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return events;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Extracts ~/.claude/ftm-state/... paths from blackboard section lines.
|
|
116
|
+
*/
|
|
117
|
+
function extractBlackboardPaths(lines) {
|
|
118
|
+
const paths = [];
|
|
119
|
+
// Match backtick-quoted paths containing ftm-state
|
|
120
|
+
const pathRegex = /`(~\/.claude\/ftm-state\/[^`]+)`/g;
|
|
121
|
+
|
|
122
|
+
for (const line of lines) {
|
|
123
|
+
let match;
|
|
124
|
+
while ((match = pathRegex.exec(line)) !== null) {
|
|
125
|
+
if (!paths.includes(match[1])) {
|
|
126
|
+
paths.push(match[1]);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return paths;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Per-skill metadata extraction
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
|
|
138
|
+
function processSkill({ skillFile, skillDir, triggerFile }) {
|
|
139
|
+
const raw = fs.readFileSync(skillFile, 'utf8');
|
|
140
|
+
const stat = fs.statSync(skillFile);
|
|
141
|
+
const parsed = matter(raw);
|
|
142
|
+
|
|
143
|
+
const { name, description } = parsed.data;
|
|
144
|
+
const sections = parseSections(parsed.content);
|
|
145
|
+
|
|
146
|
+
// Events
|
|
147
|
+
const eventsEmits = extractEventNames(sections['Emits'] || []);
|
|
148
|
+
const eventsListens = extractEventNames(sections['Listens To'] || []);
|
|
149
|
+
|
|
150
|
+
// Blackboard paths
|
|
151
|
+
const blackboardReads = extractBlackboardPaths(sections['Blackboard Read'] || []);
|
|
152
|
+
const blackboardWrites = extractBlackboardPaths(sections['Blackboard Write'] || []);
|
|
153
|
+
|
|
154
|
+
// References directory
|
|
155
|
+
const referencesDir = path.join(ROOT, skillDir, 'references');
|
|
156
|
+
let references = [];
|
|
157
|
+
if (fs.existsSync(referencesDir)) {
|
|
158
|
+
try {
|
|
159
|
+
references = fs.readdirSync(referencesDir).filter(f => {
|
|
160
|
+
const fullPath = path.join(referencesDir, f);
|
|
161
|
+
return fs.statSync(fullPath).isFile();
|
|
162
|
+
});
|
|
163
|
+
} catch {
|
|
164
|
+
references = [];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Evals directory
|
|
169
|
+
const evalsDir = path.join(ROOT, skillDir, 'evals');
|
|
170
|
+
const hasEvals = fs.existsSync(evalsDir) && fs.statSync(evalsDir).isDirectory();
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
name: name || path.basename(skillDir, '/'),
|
|
174
|
+
description: description || '',
|
|
175
|
+
trigger_file: triggerFile,
|
|
176
|
+
skill_directory: skillDir,
|
|
177
|
+
events_emits: eventsEmits,
|
|
178
|
+
events_listens: eventsListens,
|
|
179
|
+
blackboard_reads: blackboardReads,
|
|
180
|
+
blackboard_writes: blackboardWrites,
|
|
181
|
+
references,
|
|
182
|
+
has_evals: hasEvals,
|
|
183
|
+
size_bytes: stat.size,
|
|
184
|
+
enabled: true,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
// Main
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
|
|
192
|
+
function main() {
|
|
193
|
+
const skillEntries = discoverSkillFiles();
|
|
194
|
+
const skills = skillEntries.map(processSkill);
|
|
195
|
+
|
|
196
|
+
// Sort alphabetically by name
|
|
197
|
+
skills.sort((a, b) => a.name.localeCompare(b.name));
|
|
198
|
+
|
|
199
|
+
const manifest = {
|
|
200
|
+
generated_at: new Date().toISOString(),
|
|
201
|
+
skills,
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const outputPath = path.join(ROOT, 'ftm-manifest.json');
|
|
205
|
+
fs.writeFileSync(outputPath, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
|
206
|
+
|
|
207
|
+
process.stderr.write(`Generated manifest for ${skills.length} skills\n`);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
main();
|
package/bin/install.mjs
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* npx ftm-skills — installs ftm skills into ~/.claude/skills/
|
|
5
|
+
*
|
|
6
|
+
* Works by finding the npm package root (where the skill files live)
|
|
7
|
+
* and symlinking them into the Claude Code skills directory.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync, mkdirSync, readdirSync, lstatSync, readFileSync, writeFileSync, copyFileSync, symlinkSync, unlinkSync } from "fs";
|
|
11
|
+
import { join, basename, dirname } from "path";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
import { fileURLToPath } from "url";
|
|
14
|
+
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = dirname(__filename);
|
|
17
|
+
const REPO_DIR = dirname(__dirname); // package root (one level up from bin/)
|
|
18
|
+
const HOME = homedir();
|
|
19
|
+
const SKILLS_DIR = join(HOME, ".claude", "skills");
|
|
20
|
+
const STATE_DIR = join(HOME, ".claude", "ftm-state");
|
|
21
|
+
const CONFIG_DIR = join(HOME, ".claude");
|
|
22
|
+
|
|
23
|
+
function log(msg) {
|
|
24
|
+
console.log(` ${msg}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function ensureDir(dir) {
|
|
28
|
+
if (!existsSync(dir)) {
|
|
29
|
+
mkdirSync(dir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function safeSymlink(src, dest) {
|
|
34
|
+
const name = basename(dest);
|
|
35
|
+
try {
|
|
36
|
+
if (lstatSync(dest).isSymbolicLink()) {
|
|
37
|
+
unlinkSync(dest);
|
|
38
|
+
} else if (existsSync(dest)) {
|
|
39
|
+
log(`SKIP ${name} (real file/dir exists — back it up first)`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
// dest doesn't exist, that's fine
|
|
44
|
+
}
|
|
45
|
+
symlinkSync(src, dest);
|
|
46
|
+
log(`LINK ${name}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function main() {
|
|
50
|
+
console.log(`Installing ftm skills from: ${REPO_DIR}`);
|
|
51
|
+
console.log(`Linking into: ${SKILLS_DIR}`);
|
|
52
|
+
console.log("");
|
|
53
|
+
|
|
54
|
+
ensureDir(SKILLS_DIR);
|
|
55
|
+
|
|
56
|
+
// Link all ftm*.yml files
|
|
57
|
+
const ymlFiles = readdirSync(REPO_DIR).filter(
|
|
58
|
+
(f) => f.startsWith("ftm") && f.endsWith(".yml") && !f.includes("config.default")
|
|
59
|
+
);
|
|
60
|
+
for (const yml of ymlFiles) {
|
|
61
|
+
safeSymlink(join(REPO_DIR, yml), join(SKILLS_DIR, yml));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Link all ftm* directories (skills with SKILL.md)
|
|
65
|
+
const dirs = readdirSync(REPO_DIR).filter((f) => {
|
|
66
|
+
if (!f.startsWith("ftm")) return false;
|
|
67
|
+
if (f === "ftm-state") return false;
|
|
68
|
+
const fullPath = join(REPO_DIR, f);
|
|
69
|
+
try {
|
|
70
|
+
return lstatSync(fullPath).isDirectory();
|
|
71
|
+
} catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
for (const dir of dirs) {
|
|
76
|
+
safeSymlink(join(REPO_DIR, dir), join(SKILLS_DIR, dir));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Set up blackboard state (copy templates, don't overwrite existing data)
|
|
80
|
+
const bbDir = join(REPO_DIR, "ftm-state", "blackboard");
|
|
81
|
+
if (existsSync(bbDir)) {
|
|
82
|
+
ensureDir(join(STATE_DIR, "blackboard", "experiences"));
|
|
83
|
+
|
|
84
|
+
const jsonFiles = readdirSync(bbDir).filter((f) => f.endsWith(".json"));
|
|
85
|
+
for (const f of jsonFiles) {
|
|
86
|
+
const target = join(STATE_DIR, "blackboard", f);
|
|
87
|
+
if (!existsSync(target)) {
|
|
88
|
+
copyFileSync(join(bbDir, f), target);
|
|
89
|
+
log(`INIT ${f} (blackboard template)`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const idxSrc = join(bbDir, "experiences", "index.json");
|
|
94
|
+
const idxDest = join(STATE_DIR, "blackboard", "experiences", "index.json");
|
|
95
|
+
if (existsSync(idxSrc) && !existsSync(idxDest)) {
|
|
96
|
+
copyFileSync(idxSrc, idxDest);
|
|
97
|
+
log("INIT experiences/index.json (blackboard template)");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Copy default config if none exists
|
|
102
|
+
const configSrc = join(REPO_DIR, "ftm-config.default.yml");
|
|
103
|
+
const configDest = join(CONFIG_DIR, "ftm-config.yml");
|
|
104
|
+
if (existsSync(configSrc) && !existsSync(configDest)) {
|
|
105
|
+
copyFileSync(configSrc, configDest);
|
|
106
|
+
log("INIT ftm-config.yml (from default template)");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
console.log("");
|
|
110
|
+
console.log(`Done. ${ymlFiles.length} skills linked.`);
|
|
111
|
+
console.log("Try: /ftm help");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
main();
|