fdeops 3.15.0 → 3.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -31
- package/adapters/LOCAL-LLM.md +1 -1
- package/adapters/README.md +1 -1
- package/bin/check.js +33 -26
- package/mcp/fdeops-ingest/package.json +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
package/README.md
CHANGED
|
@@ -17,9 +17,9 @@ Skills encode the workflows, quality gates, and judgment Forward Deployed Engine
|
|
|
17
17
|
|
|
18
18
|
## Commands
|
|
19
19
|
|
|
20
|
-
6 slash commands that map to the engagement. Each one
|
|
20
|
+
6 slash commands that map to the engagement. Each one activates `@fde`.
|
|
21
21
|
|
|
22
|
-
| What you're doing | Command |
|
|
22
|
+
| What you're doing | Command | Key principle |
|
|
23
23
|
|-------------------|---------|-----------|
|
|
24
24
|
| Land the embed | `/brief` | Brief and trust before code |
|
|
25
25
|
| Find the real problem | `/discover` | Brief is a hypothesis |
|
|
@@ -30,7 +30,7 @@ Skills encode the workflows, quality gates, and judgment Forward Deployed Engine
|
|
|
30
30
|
|
|
31
31
|
Also: `/debrief` (after a meeting) · `/prep` (walk-in) · `/quiet` (sponsor silent) · `/agreed` (scope dispute) · `/status` (Friday readout).
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Skills also activate automatically based on what you're doing — naming a client, debriefing a meeting, or asking what was agreed triggers `@fde`. Ordinary TypeScript, unit tests, and git commits stay in the host agent.
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
@@ -92,13 +92,13 @@ Requires Node.js >= 18. Override: `FDEOPS_ENGAGEMENT` — [docs/install.md](docs
|
|
|
92
92
|
|
|
93
93
|
---
|
|
94
94
|
|
|
95
|
-
## All 31
|
|
95
|
+
## All 31 Skills
|
|
96
96
|
|
|
97
|
-
The commands above are the entry points.
|
|
97
|
+
The commands above are the entry points. Under the hood, `@fde` activates these 31 skills — each a structured workflow with steps, an artifact, and a checkpoint. You never pick one by name. Full detail: [docs/skills-reference.md](docs/skills-reference.md).
|
|
98
98
|
|
|
99
|
-
### Land
|
|
99
|
+
### Land - Brief and trust
|
|
100
100
|
|
|
101
|
-
|
|
|
101
|
+
| Skill | What It Does | Use When |
|
|
102
102
|
|--------|--------------|----------|
|
|
103
103
|
| [land](skills/fde/references/land.md) | Interrogate the brief, map stakeholders, define success | New client, first meeting, just got the brief |
|
|
104
104
|
| [audit](skills/fde/references/audit.md) | Verify claims, find the load-bearing wall | Taking over, previous consultant left |
|
|
@@ -106,27 +106,27 @@ The commands above are the entry points. One `@fde` skill routes to these 31 met
|
|
|
106
106
|
| [trust-engineering](skills/fde/references/trust-engineering.md) | Observer → trusted; navigate AI policy | Need access or credibility |
|
|
107
107
|
| [scope-defense](skills/fde/references/scope-defense.md) | Scope receipts; the accumulation conversation | "Also can you…", timeline unchanged |
|
|
108
108
|
|
|
109
|
-
### Discover
|
|
109
|
+
### Discover - Find the real problem
|
|
110
110
|
|
|
111
|
-
|
|
|
111
|
+
| Skill | What It Does | Use When |
|
|
112
112
|
|--------|--------------|----------|
|
|
113
113
|
| [discover](skills/fde/references/discover.md) | Repo + workaround + the real problem | Brief feels wrong, shadow processes |
|
|
114
114
|
| [assumption-audit](skills/fde/references/assumption-audit.md) | Untested assumptions by blast radius | Brief feels too neat |
|
|
115
115
|
| [use-case-scoring](skills/fde/references/use-case-scoring.md) | Value × urgency × alignment / complexity | Everything is P0 |
|
|
116
116
|
| [sketch](skills/fde/references/sketch.md) | Kill the killer assumption in a day | Need to de-risk a direction |
|
|
117
117
|
|
|
118
|
-
### Plan
|
|
118
|
+
### Plan - Sequence the work
|
|
119
119
|
|
|
120
|
-
|
|
|
120
|
+
| Skill | What It Does | Use When |
|
|
121
121
|
|--------|--------------|----------|
|
|
122
122
|
| [plan](skills/fde/references/plan.md) | Backwards from done, PR-sized | What order, what is done |
|
|
123
123
|
| [business-case](skills/fde/references/business-case.md) | Cost of nothing → investment → return | Defend budget or timeline |
|
|
124
124
|
| [options-analysis](skills/fde/references/options-analysis.md) | Three genuine options | "What should we do?" |
|
|
125
125
|
| [initiative-triage](skills/fde/references/initiative-triage.md) | Pick three from twenty urgents | Everything is urgent |
|
|
126
126
|
|
|
127
|
-
### Ship
|
|
127
|
+
### Ship - Go live
|
|
128
128
|
|
|
129
|
-
|
|
|
129
|
+
| Skill | What It Does | Use When |
|
|
130
130
|
|--------|--------------|----------|
|
|
131
131
|
| [incremental-build](skills/fde/references/incremental-build.md) | Vertical slices, visible every 2–3 days | Large feature on their codebase |
|
|
132
132
|
| [blast-radius](skills/fde/references/blast-radius.md) | Impact from contained → irreversible | Touching shared infrastructure |
|
|
@@ -135,9 +135,9 @@ The commands above are the entry points. One `@fde` skill routes to these 31 met
|
|
|
135
135
|
| [review](skills/fde/references/review.md) | Did we only build what we agreed | Before merge, scope creep |
|
|
136
136
|
| [rollback-drill](skills/fde/references/rollback-drill.md) | Test the escape route before 2am | "We can always revert" |
|
|
137
137
|
|
|
138
|
-
### Prove
|
|
138
|
+
### Prove - What they got
|
|
139
139
|
|
|
140
|
-
|
|
|
140
|
+
| Skill | What It Does | Use When |
|
|
141
141
|
|--------|--------------|----------|
|
|
142
142
|
| [status](skills/fde/references/status.md) | Promised → measured → accepted | Friday, sponsor update |
|
|
143
143
|
| [demo-prep](skills/fde/references/demo-prep.md) | One number, five hard questions | Demo or exec walkthrough |
|
|
@@ -147,9 +147,9 @@ The commands above are the entry points. One `@fde` skill routes to these 31 met
|
|
|
147
147
|
| [ingest](skills/fde/references/ingest.md) | Pull text you confirm | Transcript, Notion, Slack |
|
|
148
148
|
| [ingest-connect](skills/fde/references/ingest-connect.md) | Wire a source MCP | Connect Granola |
|
|
149
149
|
|
|
150
|
-
### Close
|
|
150
|
+
### Close - They run it
|
|
151
151
|
|
|
152
|
-
|
|
|
152
|
+
| Skill | What It Does | Use When |
|
|
153
153
|
|--------|--------------|----------|
|
|
154
154
|
| [close](skills/fde/references/close.md) | Handoff that survives you | Wrapping up |
|
|
155
155
|
| [handoff-engineering](skills/fde/references/handoff-engineering.md) | Runbook, confidence scoring | They must operate without you |
|
|
@@ -163,9 +163,9 @@ Optional pull: you add the source MCP; we **pull** on request. [mcp/recipes/](mc
|
|
|
163
163
|
|
|
164
164
|
---
|
|
165
165
|
|
|
166
|
-
## How
|
|
166
|
+
## How Skills Work
|
|
167
167
|
|
|
168
|
-
Every
|
|
168
|
+
Every skill follows a consistent anatomy:
|
|
169
169
|
|
|
170
170
|
```
|
|
171
171
|
┌─────────────────────────────────────────────┐
|
|
@@ -181,19 +181,17 @@ Every method follows the same anatomy:
|
|
|
181
181
|
└─────────────────────────────────────────────┘
|
|
182
182
|
│
|
|
183
183
|
▼
|
|
184
|
-
references/<
|
|
184
|
+
references/<skill>.md fde CLI (local)
|
|
185
185
|
one file, then stop dating, gates, redaction
|
|
186
186
|
```
|
|
187
187
|
|
|
188
|
-
- **Process, not prose.**
|
|
188
|
+
- **Process, not prose.** Skills are workflows with an artifact and a checkpoint, not tip sheets.
|
|
189
189
|
- **You confirm.** Nothing is written until you say so.
|
|
190
|
-
- **Progressive disclosure.** `SKILL.md` is the entry point. One `references/*.md` loads when routed.
|
|
191
|
-
- **Local CLI.** Writes,
|
|
190
|
+
- **Progressive disclosure.** The `SKILL.md` is the entry point. One `references/*.md` loads when routed.
|
|
191
|
+
- **Local CLI.** Writes, status, dated agreements. Zero model tokens. The AI coding agent runs it.
|
|
192
192
|
|
|
193
193
|
The record lives at `~/fde-engagements/<client>/.fde/` — not inside any vendor. Change hosts, install `@fde` on the new one, bind if needed, keep talking.
|
|
194
194
|
|
|
195
|
-
**Words used here, once:** *engagement* - one client's body of work, one folder. *Fieldbook* - that folder (`.fde/`), the record itself. *Brief vs reality* - what they said the problem was, and what it turned out to be. *Terrain* - their systems and org as you actually found them. *Trust signal* - green / amber / red on one relationship. *Receipts* - the dated line proving something was agreed. *Vault* - the Obsidian copy `fde vault` generates to read it all in one window.
|
|
196
|
-
|
|
197
195
|
---
|
|
198
196
|
|
|
199
197
|
## Project Structure
|
|
@@ -202,18 +200,23 @@ The record lives at `~/fde-engagements/<client>/.fde/` — not inside any vendor
|
|
|
202
200
|
fdeops/
|
|
203
201
|
├── skills/fde/ # the one skill
|
|
204
202
|
│ ├── SKILL.md # router
|
|
205
|
-
│ └── references/ # 31
|
|
203
|
+
│ └── references/ # 31 skills + overlays
|
|
206
204
|
├── .claude/commands/ # slash commands (each loads @fde)
|
|
207
|
-
├──
|
|
205
|
+
├── .claude-plugin/ # Claude Code marketplace
|
|
206
|
+
├── bin/ # local CLI — git + files, no network
|
|
208
207
|
├── hooks/ # session-start / session-stop / pre-compact
|
|
209
208
|
├── adapters/ # Cursor, Gemini, Copilot, Codex pointers
|
|
210
209
|
├── templates/.fde/ # memory files created on bind
|
|
211
|
-
|
|
210
|
+
├── examples/ # fictional walkthroughs
|
|
211
|
+
├── mcp/ # optional ingest + source recipes
|
|
212
|
+
├── evals/ # routing checks + CLI attack notes
|
|
213
|
+
├── media/ # recorded session (docs/USAGE.md)
|
|
214
|
+
└── docs/ # usage, schema, install, methodology
|
|
212
215
|
```
|
|
213
216
|
|
|
214
217
|
---
|
|
215
218
|
|
|
216
|
-
## Why
|
|
219
|
+
## Why FDEOps?
|
|
217
220
|
|
|
218
221
|
### 1. The brief is wrong
|
|
219
222
|
|
|
@@ -273,7 +276,7 @@ Local only — `git` + files, no network, no telemetry. Plain markdown. The mode
|
|
|
273
276
|
## Principles
|
|
274
277
|
|
|
275
278
|
- **The artifact is the memory** — producing the work and recording it are one action
|
|
276
|
-
- **
|
|
279
|
+
- **Skills, not autonomy** — the kit says what to check; judgment stays yours
|
|
277
280
|
- **Brief is a hypothesis** — discover before building the wrong thing
|
|
278
281
|
- **Evidence on every claim** — these files get defended in the room
|
|
279
282
|
- **One customer, one folder** — context never bleeds
|
|
@@ -284,7 +287,7 @@ Local only — `git` + files, no network, no telemetry. Plain markdown. The mode
|
|
|
284
287
|
|
|
285
288
|
**[Subash Natarajan](https://www.linkedin.com/in/subashn/)**. [Issues](https://github.com/suboss87/fdeops/issues) · [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
286
289
|
|
|
287
|
-
|
|
290
|
+
Skills should be **specific** (actionable steps), **verifiable** (an artifact in `.fde/`), and **minimal**. The `fde` CLI stays local-only.
|
|
288
291
|
|
|
289
292
|
## License
|
|
290
293
|
|
package/adapters/LOCAL-LLM.md
CHANGED
|
@@ -62,7 +62,7 @@ The model reads SKILL.md, routes to the right skill, and produces artifacts in y
|
|
|
62
62
|
|
|
63
63
|
## Model size recommendations
|
|
64
64
|
|
|
65
|
-
The methodology is detailed (31
|
|
65
|
+
The methodology is detailed (31 skills, routing logic, evidence format, memory contract). Larger models handle it better:
|
|
66
66
|
|
|
67
67
|
| Model class | Experience |
|
|
68
68
|
|-------------|-----------|
|
package/adapters/README.md
CHANGED
|
@@ -31,4 +31,4 @@ Defaults to the current directory if no path is given. Existing files are never
|
|
|
31
31
|
|
|
32
32
|
## The principle
|
|
33
33
|
|
|
34
|
-
The adapter only tells the tool **where the brain is and how to behave**. All
|
|
34
|
+
The adapter only tells the tool **where the brain is and how to behave**. All 31 skills, the overlays, and the memory contract live once in `skills/fde/SKILL.md`. Update the brain, every platform gets it. That's why fdeops feels native in whatever the FDE already uses, without five things to keep in sync.
|
package/bin/check.js
CHANGED
|
@@ -182,24 +182,22 @@ ok(`router dispatch (${mentioned.length} reference targets verified) + memory co
|
|
|
182
182
|
// the agent can never reach, advertised anyway.
|
|
183
183
|
const unrouted = [...documented].filter(name => !routed.has(name))
|
|
184
184
|
if (unrouted.length) {
|
|
185
|
-
fail(`docs/skills-reference.md documents
|
|
185
|
+
fail(`docs/skills-reference.md documents skill(s) SKILL.md never routes to: ${unrouted.join(', ')}`)
|
|
186
186
|
}
|
|
187
187
|
for (const rel of ['docs/skills.md', 'docs/skills-reference.md']) {
|
|
188
188
|
const body = read(rel)
|
|
189
189
|
// `-` is a word boundary, so \bingest\b matches inside `ingest-connect`:
|
|
190
190
|
// a method could disappear from the docs behind a hyphenated sibling.
|
|
191
191
|
const absent = [...documented].filter(name => !new RegExp(`(?<![\\w-])${name}(?![\\w-])`).test(body))
|
|
192
|
-
if (absent.length) fail(`${rel} does not list
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const claims = [...body.matchAll(/(\d+)\s+methods/g)].map(m => Number(m[1]))
|
|
196
|
-
if (!claims.length) fail(`${rel} must state how many methods it documents`)
|
|
192
|
+
if (absent.length) fail(`${rel} does not list skill(s): ${absent.join(', ')}`)
|
|
193
|
+
const claims = [...body.matchAll(/(\d+)\s+skills/g)].map(m => Number(m[1]))
|
|
194
|
+
if (!claims.length) fail(`${rel} must state how many skills it documents`)
|
|
197
195
|
const wrong = [...new Set(claims.filter(n => n !== documented.size))]
|
|
198
196
|
if (wrong.length) {
|
|
199
|
-
fail(`${rel} claims ${wrong.join('/')}
|
|
197
|
+
fail(`${rel} claims ${wrong.join('/')} skills; ${documented.size} are documented`)
|
|
200
198
|
}
|
|
201
199
|
}
|
|
202
|
-
ok(`public
|
|
200
|
+
ok(`public skill count is verifiable (${documented.size} documented, ${routed.size} routed)`)
|
|
203
201
|
|
|
204
202
|
const refDir = path.join(root, 'skills', 'fde', 'references')
|
|
205
203
|
const extra = fs.readdirSync(refDir).filter(f => f.endsWith('.md') && !mentioned.includes(f))
|
|
@@ -250,7 +248,7 @@ if (brokenLinks.length) fail(`README links to missing paths: ${brokenLinks.join(
|
|
|
250
248
|
else ok('README links all resolve')
|
|
251
249
|
|
|
252
250
|
for (const section of [
|
|
253
|
-
'How
|
|
251
|
+
'How Skills Work',
|
|
254
252
|
'Quick Start',
|
|
255
253
|
'Engagement memory',
|
|
256
254
|
'Who this is for',
|
|
@@ -282,9 +280,8 @@ if (!readme.includes('fde-engagements') || !/fdeops.*init.*engagement/i.test(rea
|
|
|
282
280
|
fail('README must document fde-engagements + init flow')
|
|
283
281
|
} else ok('README engagement path')
|
|
284
282
|
|
|
285
|
-
// The
|
|
286
|
-
//
|
|
287
|
-
// a field user wants.
|
|
283
|
+
// The advertised command must name the one skill a field user wants.
|
|
284
|
+
// Contributor CLI attack notes live in evals/testing-fieldbook.md, not as a skill.
|
|
288
285
|
for (const m of readme.match(/^.*npx skills add .*$/gm) || []) {
|
|
289
286
|
if (!m.includes('--skill fde')) {
|
|
290
287
|
fail(`README skills-add command must pin --skill fde: ${m.trim()}`)
|
|
@@ -310,19 +307,7 @@ if (!read('skills/fde/SKILL.md').includes('npx --yes fdeops')) {
|
|
|
310
307
|
fail(`SKILL.md description needs several "Use when …" triggers so it fires on intent (found ${triggers.length})`)
|
|
311
308
|
} else if (/Use when the human says @fde or/.test(desc)) {
|
|
312
309
|
fail('SKILL.md description must not gate on @fde - name the client-work intents first')
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Six invented words (fieldbook, terrain, reality, trust signal, receipts,
|
|
317
|
-
// vault) carry the method. They were never defined in one place, so a stranger
|
|
318
|
-
// met them scattered through the docs and guessed.
|
|
319
|
-
{
|
|
320
|
-
const gloss = /Words used here[\s\S]{0,1200}/.exec(readme)
|
|
321
|
-
const missing = ['fieldbook', 'reality', 'terrain', 'trust signal', 'receipts', 'vault']
|
|
322
|
-
.filter(w => !gloss || !new RegExp(w, 'i').test(gloss[0]))
|
|
323
|
-
if (!gloss) fail('README must define its invented words once (a "Words used here" line)')
|
|
324
|
-
else if (missing.length) fail(`README glossary is missing: ${missing.join(', ')}`)
|
|
325
|
-
else ok('README defines its own vocabulary')
|
|
310
|
+
} else ok('SKILL.md description triggers on intent')
|
|
326
311
|
}
|
|
327
312
|
|
|
328
313
|
if (!fs.existsSync(path.join(root, 'docs', 'USAGE.md'))) {
|
|
@@ -629,12 +614,34 @@ for (const manifest of ['plugin.json', 'mcp.json']) {
|
|
|
629
614
|
else ok(`${manifest} published to npm`)
|
|
630
615
|
}
|
|
631
616
|
|
|
617
|
+
const skillDirs = []
|
|
632
618
|
for (const entry of fs.readdirSync(path.join(root, 'skills'))) {
|
|
633
619
|
const dir = path.join(root, 'skills', entry)
|
|
634
620
|
if (!fs.statSync(dir).isDirectory()) continue
|
|
635
621
|
if (!fs.existsSync(path.join(dir, 'SKILL.md'))) fail(`skills/${entry}/ has no SKILL.md - clients skip it`)
|
|
636
|
-
else
|
|
622
|
+
else {
|
|
623
|
+
skillDirs.push(entry)
|
|
624
|
+
ok(`skill ${entry} discoverable`)
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
if (skillDirs.length !== 1 || skillDirs[0] !== 'fde') {
|
|
628
|
+
fail(`public tree ships one skill (skills/fde); found: ${skillDirs.join(', ') || '(none)'}`)
|
|
629
|
+
} else ok('one public skill')
|
|
630
|
+
|
|
631
|
+
function findSkillMd(dir, acc = []) {
|
|
632
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
633
|
+
if (e.name === '.git' || e.name === 'node_modules' || e.name === '.agents') continue
|
|
634
|
+
const p = path.join(dir, e.name)
|
|
635
|
+
if (e.isDirectory()) findSkillMd(p, acc)
|
|
636
|
+
else if (e.name === 'SKILL.md') acc.push(path.relative(root, p))
|
|
637
|
+
}
|
|
638
|
+
return acc
|
|
637
639
|
}
|
|
640
|
+
const skillFiles = findSkillMd(root)
|
|
641
|
+
const allowedSkill = path.join('skills', 'fde', 'SKILL.md')
|
|
642
|
+
if (skillFiles.length !== 1 || skillFiles[0] !== allowedSkill) {
|
|
643
|
+
fail(`only ${allowedSkill} may exist; found: ${skillFiles.join(', ') || '(none)'}`)
|
|
644
|
+
} else ok('one SKILL.md')
|
|
638
645
|
|
|
639
646
|
if (!fs.existsSync(path.join(root, '.github', 'ISSUE_TEMPLATE', 'bug_report.yml'))) {
|
|
640
647
|
fail('GitHub issue template missing')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fdeops",
|
|
3
|
-
"version": "3.15.
|
|
3
|
+
"version": "3.15.1",
|
|
4
4
|
"description": "Forward deployed engineering skills for AI coding agents. Your agent forgets the client every morning - the sponsor, the promise, who signed off. FDEOps keeps that as dated markdown on your laptop: one @fde skill, a deterministic local CLI, and hooks that make it automatic. Claude Code plugin and any agent that loads skills.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fdeops": "bin/install.js",
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "fdeops",
|
|
4
|
-
"version": "3.15.
|
|
4
|
+
"version": "3.15.1",
|
|
5
5
|
"description": "Forward deployed engineering skills for AI coding agents: per-client memory in local .fde/ files, one @fde skill. Local-only, no network.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Subash Natarajan",
|