fdeops 3.9.20 → 3.10.2
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 +106 -87
- package/adapters/LOCAL-LLM.md +1 -1
- package/adapters/README.md +1 -1
- package/bin/check.js +211 -4
- package/bin/fde.js +379 -26
- package/bin/install.js +223 -20
- package/bin/lib/memory.js +2 -2
- package/bin/lib/render.js +2 -0
- package/mcp/README.md +2 -4
- package/mcp/fdeops-ingest/README.md +7 -3
- package/mcp/fdeops-ingest/package.json +1 -1
- package/mcp/fdeops-ingest/server.js +59 -28
- package/mcp/recipes/README.md +9 -8
- package/mcp/recipes/file.md +7 -7
- package/mcp/recipes/granola.md +16 -20
- package/mcp/recipes/notion.md +16 -18
- package/mcp/recipes/slack.md +61 -0
- package/mcp.json +10 -0
- package/package.json +4 -2
- package/plugin.json +21 -0
- package/skills/fde/SKILL.md +4 -4
- package/skills/fde/references/assumption-audit.md +10 -0
- package/skills/fde/references/build.md +13 -1
- package/skills/fde/references/business-case.md +10 -0
- package/skills/fde/references/close.md +11 -1
- package/skills/fde/references/discover.md +10 -0
- package/skills/fde/references/ingest-connect.md +16 -18
- package/skills/fde/references/ingest.md +5 -4
- package/skills/fde/references/land.md +20 -0
- package/skills/fde/references/options-analysis.md +10 -0
- package/skills/fde/references/plan.md +10 -0
- package/skills/fde/references/scope-defense.md +10 -0
- package/skills/fde/references/ship.md +10 -0
- package/skills/fde/references/stakeholder-radar.md +21 -0
- package/skills/fde/references/status.md +12 -2
- package/templates/.fde/delivery.md +3 -3
package/mcp/recipes/granola.md
CHANGED
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
**Use when:** meeting notes live in Granola (or a similar notes MCP). FDEOps does not ship a Granola server — you add whichever MCP/export path you trust.
|
|
4
4
|
|
|
5
|
+
Daily path if the notes are already in chat or on disk: paste to `@fde debrief` or [file.md](./file.md). This recipe is only for **pull**.
|
|
6
|
+
|
|
5
7
|
## Setup (once)
|
|
6
8
|
|
|
7
|
-
1.
|
|
8
|
-
2.
|
|
9
|
-
3.
|
|
10
|
-
|
|
9
|
+
1. Enable a **Granola (or notes) MCP** in Cursor/Claude per that product’s docs.
|
|
10
|
+
2. Reload MCP / restart the host.
|
|
11
|
+
3. Test: `@fde what can you pull?` — notes-source tools should appear.
|
|
12
|
+
|
|
13
|
+
The sink is **`fde ingest` in this bound workspace.** You do not need `fdeops-ingest` MCP for daily pull.
|
|
11
14
|
|
|
12
15
|
### Example mcp.json shape (illustrative)
|
|
13
16
|
|
|
14
|
-
Replace
|
|
17
|
+
Replace command/args with whatever the real Granola MCP documents. FDEOps only needs *some* tool that returns transcript text.
|
|
15
18
|
|
|
16
19
|
```json
|
|
17
20
|
{
|
|
@@ -22,19 +25,12 @@ Replace `granola-mcp` command/args with whatever the real server documents. FDEO
|
|
|
22
25
|
"env": {
|
|
23
26
|
"GRANOLA_API_KEY": "from-your-secrets"
|
|
24
27
|
}
|
|
25
|
-
},
|
|
26
|
-
"fdeops-ingest": {
|
|
27
|
-
"command": "node",
|
|
28
|
-
"args": ["/absolute/path/to/fdeops/mcp/fdeops-ingest/server.js"],
|
|
29
|
-
"env": {
|
|
30
|
-
"FDEOPS_ENGAGEMENT": "/Users/you/fde-engagements/acme/.fde"
|
|
31
|
-
}
|
|
32
28
|
}
|
|
33
29
|
}
|
|
34
30
|
}
|
|
35
31
|
```
|
|
36
32
|
|
|
37
|
-
**No Granola MCP available?** Export transcript to a file →
|
|
33
|
+
**No Granola MCP available?** Export transcript to a file → [file.md](./file.md).
|
|
38
34
|
|
|
39
35
|
## Pull phrase
|
|
40
36
|
|
|
@@ -44,15 +40,15 @@ Replace `granola-mcp` command/args with whatever the real server documents. FDEO
|
|
|
44
40
|
|
|
45
41
|
## Agent steps
|
|
46
42
|
|
|
47
|
-
1. Capability check —
|
|
48
|
-
2. Fetch transcript
|
|
49
|
-
3. `
|
|
50
|
-
4.
|
|
43
|
+
1. Capability check — notes-source tools present?
|
|
44
|
+
2. Fetch transcript text (ask which meeting if ambiguous).
|
|
45
|
+
3. `fde ingest stage --source granola --title "<short>"` then propose → confirm → apply.
|
|
46
|
+
4. Extract decisions/risks/next — do not dump the raw transcript into `.fde/`.
|
|
51
47
|
|
|
52
48
|
## Common fails
|
|
53
49
|
|
|
54
50
|
| Symptom | Fix |
|
|
55
51
|
|---------|-----|
|
|
56
|
-
|
|
|
57
|
-
| Wrong
|
|
58
|
-
|
|
|
52
|
+
| No Granola tools | Source MCP not loaded — they save + reload |
|
|
53
|
+
| Wrong meeting | One clarifying question, then fetch |
|
|
54
|
+
| Wrong engagement | `fde resume` in this workspace before staging |
|
package/mcp/recipes/notion.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# Recipe: Notion docs / meeting notes
|
|
2
2
|
|
|
3
|
-
**Use when:** useful engagement notes live in Notion. FDEOps does not ship a Notion server — use a Notion MCP (or export markdown).
|
|
3
|
+
**Use when:** useful engagement notes live in Notion. FDEOps does not ship a Notion server — use a Notion MCP (or export markdown). We do not write back to Notion.
|
|
4
4
|
|
|
5
5
|
## Setup (once)
|
|
6
6
|
|
|
7
|
-
1. Enable a **Notion MCP** (official or community) with a token that can read the pages you need.
|
|
8
|
-
2.
|
|
9
|
-
3.
|
|
10
|
-
|
|
7
|
+
1. Enable a **Notion MCP** (official or community) with a token that can **read** the pages you need.
|
|
8
|
+
2. Reload MCP / restart host.
|
|
9
|
+
3. Test: `@fde what can you pull?`
|
|
10
|
+
|
|
11
|
+
The sink is **`fde ingest` in this bound workspace.** `fdeops-ingest` MCP is optional.
|
|
11
12
|
|
|
12
13
|
### Example mcp.json shape (illustrative)
|
|
13
14
|
|
|
@@ -20,13 +21,6 @@
|
|
|
20
21
|
"env": {
|
|
21
22
|
"NOTION_TOKEN": "from-your-secrets"
|
|
22
23
|
}
|
|
23
|
-
},
|
|
24
|
-
"fdeops-ingest": {
|
|
25
|
-
"command": "node",
|
|
26
|
-
"args": ["/absolute/path/to/fdeops/mcp/fdeops-ingest/server.js"],
|
|
27
|
-
"env": {
|
|
28
|
-
"FDEOPS_ENGAGEMENT": "/Users/you/fde-engagements/acme/.fde"
|
|
29
|
-
}
|
|
30
24
|
}
|
|
31
25
|
}
|
|
32
26
|
}
|
|
@@ -42,15 +36,19 @@
|
|
|
42
36
|
|
|
43
37
|
## Agent steps
|
|
44
38
|
|
|
45
|
-
1. Capability check — Notion tools present?
|
|
46
|
-
2. Fetch page/block text
|
|
47
|
-
3.
|
|
48
|
-
|
|
39
|
+
1. Capability check — Notion read tools present?
|
|
40
|
+
2. Fetch page/block text (ask which page if ambiguous).
|
|
41
|
+
3. `fde ingest stage --source notion --title "<short>"` → propose → confirm → apply.
|
|
42
|
+
|
|
43
|
+
## Never
|
|
44
|
+
|
|
45
|
+
- Create or edit Notion pages from FDEOps.
|
|
46
|
+
- Ambient-sync a database.
|
|
49
47
|
|
|
50
48
|
## Common fails
|
|
51
49
|
|
|
52
50
|
| Symptom | Fix |
|
|
53
51
|
|---------|-----|
|
|
54
52
|
| 401 / forbidden | Token lacks access to that workspace/page |
|
|
55
|
-
| Huge page dump | Stage full text in `.inbox/`;
|
|
56
|
-
| Wrong engagement | Bind
|
|
53
|
+
| Huge page dump | Stage full text in `.inbox/`; apply only short dated facts |
|
|
54
|
+
| Wrong engagement | Bind this workspace before staging |
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Recipe: Slack (pull only)
|
|
2
|
+
|
|
3
|
+
**Use when:** useful context lives in a Slack thread or channel. FDEOps does **not** ship a Slack server, does **not** post messages, and does **not** sync channels.
|
|
4
|
+
|
|
5
|
+
You add whatever Slack MCP your host already supports. We only accept **text you pulled**, then the same confirm loop as a debrief.
|
|
6
|
+
|
|
7
|
+
## Setup (once)
|
|
8
|
+
|
|
9
|
+
1. Enable a **Slack MCP** (official or community) with read access to the threads you need.
|
|
10
|
+
2. Reload MCP / restart the host.
|
|
11
|
+
3. Test: `@fde what can you pull?` — Slack fetch tools should appear. The FDEOps **CLI** (`fde ingest`) is the sink if this workspace is bound; you do not need `fdeops-ingest` MCP for daily use.
|
|
12
|
+
|
|
13
|
+
### Example mcp.json shape (illustrative)
|
|
14
|
+
|
|
15
|
+
Replace the Slack server with whatever that MCP actually documents. Do not invent a package name.
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"slack": {
|
|
21
|
+
"command": "npx",
|
|
22
|
+
"args": ["-y", "YOUR-SLACK-MCP-PACKAGE"],
|
|
23
|
+
"env": {
|
|
24
|
+
"SLACK_BOT_TOKEN": "from-your-secrets"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Optional sink MCP (only if you are not running `fde ingest` from this workspace): see [../fdeops-ingest/README.md](../fdeops-ingest/README.md). Pass `engagement` as the path to this client's `.fde/` (from `fde resume --bind`).
|
|
32
|
+
|
|
33
|
+
**No Slack MCP?** Copy the thread to a file or paste into chat → [file.md](./file.md) or `@fde debrief`.
|
|
34
|
+
|
|
35
|
+
## Pull phrase
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
@fde pull yesterday's #acme-launch thread into the fieldbook
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Agent steps
|
|
42
|
+
|
|
43
|
+
1. Capability check — Slack **read** tools present? If not → this recipe, then stop.
|
|
44
|
+
2. Fetch the thread/channel as **text** (ask which channel/thread if ambiguous).
|
|
45
|
+
3. `fde ingest stage --source slack --title "<short>"` (CLI in this bound workspace).
|
|
46
|
+
4. Propose → FDE confirms → apply. Extract decisions/risks/asks — do not dump the thread into `.fde/`.
|
|
47
|
+
|
|
48
|
+
## Never
|
|
49
|
+
|
|
50
|
+
- Post, reply, or react in Slack from FDEOps.
|
|
51
|
+
- Background-sync a channel.
|
|
52
|
+
- Auto-apply.
|
|
53
|
+
|
|
54
|
+
## Common fails
|
|
55
|
+
|
|
56
|
+
| Symptom | Fix |
|
|
57
|
+
|---------|-----|
|
|
58
|
+
| No Slack tools | Source MCP not loaded — they save + reload; we cannot silent-install |
|
|
59
|
+
| Missing channel | Token/scopes cannot read that workspace — their Slack admin, not FDEOps |
|
|
60
|
+
| Huge dump | Stage full text in `.inbox/`; apply only short dated facts |
|
|
61
|
+
| Wrong client | Bind this workspace (`fde resume`) before staging |
|
package/mcp.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fdeops",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.2",
|
|
4
4
|
"description": "Field kit for engineers embedded in client work - a real CLI (recon, memory, portfolio), one @fde skill with field judgment on top, and hooks that make it automatic. Claude Code plugin and any agent that loads skills.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fdeops": "bin/install.js",
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
"adapters/",
|
|
21
21
|
"mcp/",
|
|
22
22
|
"CLAUDE.md.template",
|
|
23
|
-
"AGENTS.md"
|
|
23
|
+
"AGENTS.md",
|
|
24
|
+
"plugin.json",
|
|
25
|
+
"mcp.json"
|
|
24
26
|
],
|
|
25
27
|
"keywords": [
|
|
26
28
|
"claude-code",
|
package/plugin.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
|
+
"name": "fdeops",
|
|
4
|
+
"version": "3.10.2",
|
|
5
|
+
"description": "Engagement fieldbook for Forward Deployed Engineers: per-client memory in local .fde/ files, one @fde skill, land to close methodology. Local-only, no network.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Subash Natarajan",
|
|
8
|
+
"url": "https://github.com/suboss87"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://fdeops.io/",
|
|
11
|
+
"repository": "https://github.com/suboss87/FDEOps",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"fde",
|
|
15
|
+
"forward-deployed",
|
|
16
|
+
"engagement-memory",
|
|
17
|
+
"client-work",
|
|
18
|
+
"consulting",
|
|
19
|
+
"brownfield"
|
|
20
|
+
]
|
|
21
|
+
}
|
package/skills/fde/SKILL.md
CHANGED
|
@@ -83,8 +83,8 @@ When NOT to interrogate or challenge: unambiguous one-liners, mechanical ops, FD
|
|
|
83
83
|
| (session entry / where are we) | `fde resume` or use injected TRIAGE; `fde resume --init <name>` only if unbound |
|
|
84
84
|
| Day-1 look at the repo | `fde scan` - then you interpret against the brief |
|
|
85
85
|
| "Debrief these notes" / pastes meeting notes | Prefer `fde debrief --smart <notes>` → **you** (the agent) rewrite `.debrief-propose` with `decision:`/`risk:`/`delivery:`/`contact:`/`next:` prefixes where needed → show FDE → on confirm `fde debrief --apply`. `--smart` is a prefix/keyword gate, not a brain. Fallback: structure prefixed lines yourself, show FDE, then `fde debrief` |
|
|
86
|
-
| "Make sure we're up to date" / "pull relevant info" / "pull from Granola/
|
|
87
|
-
| "Connect a new MCP" / "connect Granola/Notion" / "what can you pull?" | Follow `references/ingest-connect.md`:
|
|
86
|
+
| "Make sure we're up to date" / "pull relevant info" / "pull from Granola/Slack/transcript" | Bind engagement; **capability check** (which *source* MCPs exist — never pretend). If missing → connect flow. Else fetch text → `fde ingest stage` **in this workspace** → propose → rewrite prefixes → show FDE → on confirm `fde ingest apply`. MCP sink is optional; if used, pass `engagement` from `fde resume --bind`. **Never auto-apply. Never push. Never ambient sync.** Detail: `references/ingest.md` |
|
|
87
|
+
| "Connect a new MCP" / "connect Granola/Slack/Notion" / "what can you pull?" | Follow `references/ingest-connect.md`: source MCP only; sink is `fde ingest` here. They save/reload; you cannot silent-install. Paste still works with no MCP. |
|
|
88
88
|
| "Prep me for the meeting with …" / walk-in brief | `fde prep "<short label>"` - present the brief in plain language; do not invent facts missing from `.fde/` |
|
|
89
89
|
| "When did we agree…?" / scope dispute | `fde receipts <term>` - answer with dates; no hit = gap, not proof |
|
|
90
90
|
| "Draft the sponsor update" / how are we doing | `fde status` then follow `references/status.md` for the narrative |
|
|
@@ -271,8 +271,8 @@ Running the engagement and ending it well.
|
|
|
271
271
|
| Weekly update due, "need to send the sponsor something" | status | `references/status.md` |
|
|
272
272
|
| Demo coming up, show-and-tell, exec walkthrough | demo-prep | `references/demo-prep.md` |
|
|
273
273
|
| Just out of a meeting, raw notes, "they said…", "debrief" | debrief | the debrief verb (above) + `references/debrief.md` |
|
|
274
|
-
| Make sure we're up to date, pull what's relevant, fetch from Granola/Gmail/transcript | ingest | `references/ingest.md` (capability check → stage → propose → confirm → apply) |
|
|
275
|
-
| Connect a new MCP / connect Granola or Notion / what can you pull | ingest-connect | `references/ingest-connect.md` (+ `mcp/recipes/`) |
|
|
274
|
+
| Make sure we're up to date, pull what's relevant, fetch from Granola/Slack/Gmail/transcript | ingest | `references/ingest.md` (capability check → stage → propose → confirm → apply) |
|
|
275
|
+
| Connect a new MCP / connect Granola Slack or Notion / what can you pull | ingest-connect | `references/ingest-connect.md` (+ `mcp/recipes/`) |
|
|
276
276
|
| Prep me for a meeting / walk-in brief / "what should I know before I talk to…" | - | run `fde prep "<label>"`, present in plain language |
|
|
277
277
|
| Sponsor's boss needs a summary, board update, justify continued investment | exec-narrative | `references/exec-narrative.md` |
|
|
278
278
|
| Status across all my customers | dashboard | `references/dashboard.md` |
|
|
@@ -72,6 +72,16 @@ Status values: `OPEN` · `TESTING` · `CONFIRMED` · `DISPROVED` · `PARKED`. A
|
|
|
72
72
|
|
|
73
73
|
Tell the FDE: how many assumptions extracted, how many critical, which ones were tested, which changed the direction. If a critical assumption is disproved: recommend the next move (rescope, pivot, or the conversation with the sponsor) before the FDE asks. If any CRITICAL remains OPEN: do not route to plan.
|
|
74
74
|
|
|
75
|
+
## Worked example
|
|
76
|
+
|
|
77
|
+
Acme's brief reads cleanly, which is the signal.
|
|
78
|
+
|
|
79
|
+
Extracted assumptions include one nobody said aloud: *finance would act on an alert*. The whole plan rests on it, and the evidence behind it is a sentence in a kickoff. Blast radius CRITICAL — if false, alerting changes nothing and the engagement delivers a page nobody answers.
|
|
80
|
+
|
|
81
|
+
Validation is a test, not a discussion, and it is cheap: send one real failure notification to the finance channel and watch what happens. It goes first because highest blast radius × cheapest test is the killer test.
|
|
82
|
+
|
|
83
|
+
Result: acked in 40 minutes, by Marco, not finance. Assumption DISPROVED, and the plan changes before six weeks are spent on it — the alert needs a rota with an owner, which is a different piece of work than the one that was funded. `assumptions.md` records the status, the evidence, and the date; the finding is presented to the FDE as a fact base, not as "the brief was wrong".
|
|
84
|
+
|
|
75
85
|
## Principles
|
|
76
86
|
|
|
77
87
|
- Every "just" is an assumption. Every "should" is an assumption.
|
|
@@ -127,12 +127,24 @@ The FDE's job is to make themselves replaceable. Not at handoff - every day. A c
|
|
|
127
127
|
|
|
128
128
|
- **`decisions.md`** - each significant choice: what, alternatives considered, why this one. For non-trivial architecture decisions, present three options to the FDE (safe / pragmatic / aggressive) with costs and a recommendation - three options is a real decision; one option is a request for trust. Integration contracts go here too.
|
|
129
129
|
- **`risks.md`** - new risks discovered while building.
|
|
130
|
-
- **`delivery.md`** - append a **value ledger** row for every ship: Date | Slice | Bucket | Promised | Measured | Evidence | Rollback. Bucket is `cost-save` / `risk-mitigation` / `revenue-uplift`. "Measured" may be `pending` until the pulse exists - never skip the promised column. Narrative under Shipped is optional color; the ledger is the record status and close read.
|
|
130
|
+
- **`delivery.md`** - append a **value ledger** row for every ship: Date | Slice | Bucket | Promised | Measured | Accepted by | Evidence | Rollback. Bucket is `cost-save` / `risk-mitigation` / `revenue-uplift`. "Measured" may be `pending` until the pulse exists - never skip the promised column. Narrative under Shipped is optional color; the ledger is the record status and close read.
|
|
131
|
+
|
|
132
|
+
**Measured is not the same as accepted.** A number the FDE calculated is `claimed` until a named customer-side owner agrees it is real - their finance lead, their ops manager, the person whose budget it moves. Write the name and the date in **Accepted by**; leave it empty and the row reads `claimed`, never "delivered". This is the difference between a benefit that survives the renewal conversation and one the sponsor's CFO deletes in the review.
|
|
131
133
|
|
|
132
134
|
## Checkpoint
|
|
133
135
|
|
|
134
136
|
Before merge: the two-stage review (scope, then safety) has run clean, verification evidence is stated, and the slice is demonstrable. If `trust-profile.md` requires human sign-off on AI-generated code, that sign-off exists.
|
|
135
137
|
|
|
138
|
+
## Worked example
|
|
139
|
+
|
|
140
|
+
Acme task 1: route reconciliation failures to a named on-call.
|
|
141
|
+
|
|
142
|
+
Characterisation first — a test that captures what the job does *today* when it exits non-zero (silently succeeds from the caller's perspective). That test fails after the fix, which is the point: it documents the behaviour being changed rather than trusting the diff.
|
|
143
|
+
|
|
144
|
+
Mid-build, Tom asks to "just also fix the retry logic while you're in there." That is a scope decision, not a request: logged in `decisions.md` with the blast radius (retry touches the settlement path — not in this slice's declared radius) and routed to the plan's Next lane.
|
|
145
|
+
|
|
146
|
+
Ledger row on ship: `Jun 18 | failure routing | risk-mitigation | 4h → 15min detection | pending | — | staging kill test, PR #212 | disable alert route`. **Accepted by** stays empty until Marco confirms from a real incident — until then the number is claimed, and the status update says so.
|
|
147
|
+
|
|
136
148
|
## Principles
|
|
137
149
|
|
|
138
150
|
- Characterisation tests before modification. Every time.
|
|
@@ -69,6 +69,16 @@ The sponsor who sees you've identified where the case could break trusts the cas
|
|
|
69
69
|
|
|
70
70
|
Walk the FDE through: the cost of doing nothing (anchor), the investment, the return, and the one sensitivity that matters most. If the FDE says "the sponsor won't buy the ROI number" - ask what number they would believe and work backwards from there.
|
|
71
71
|
|
|
72
|
+
## Worked example
|
|
73
|
+
|
|
74
|
+
Acme phase 2 needs funding. The case starts with the cost of doing nothing, not the cost of building.
|
|
75
|
+
|
|
76
|
+
Anchor: two silent failures since March, each one day of finance reconciliation by hand plus a late close (`reality.md`, Marco's sheet). That is the number the sponsor already believes because her own team reported it.
|
|
77
|
+
|
|
78
|
+
Driver model the sponsor can trace: incidents/quarter × hours of manual reconciliation × loaded cost, plus the tail risk of a late regulatory close — stated separately, because mixing a certain small number with an uncertain large one is how a case loses credibility.
|
|
79
|
+
|
|
80
|
+
Sensitivity names the two drivers that swing it: incident frequency (2/quarter → 1/quarter and the case halves) and whether the manual re-run continues in parallel (if Marco keeps re-running every morning, the saving is theoretical). The second one is the honest weakness, so it is in the case rather than waiting to be found in the room — with the condition that makes it hold: the morning re-run stops after two clean cycles, agreed with Marco.
|
|
81
|
+
|
|
72
82
|
## Principles
|
|
73
83
|
|
|
74
84
|
- The cost of doing nothing is always the opening move. Anchor before proposing.
|
|
@@ -18,7 +18,7 @@ The engagement doesn't end at ship. It ends when the customer can maintain what
|
|
|
18
18
|
- AI components: did they behave in production? What failure modes did the prototype hide? Is the team equipped to maintain them?
|
|
19
19
|
|
|
20
20
|
**1b. Value + receipts close gate (refuse green close if any fail):**
|
|
21
|
-
- Primary value bucket in `success.md` matches what the sponsor funded; at least one ledger row has **Measured** (not forever-`pending`) with evidence for that bucket — or the retrospective explicitly records “not measured; sponsor accepted pending.”
|
|
21
|
+
- Primary value bucket in `success.md` matches what the sponsor funded; at least one ledger row has **Measured** (not forever-`pending`) with evidence **and a named customer-side owner in Accepted by** for that bucket — or the retrospective explicitly records “not measured; sponsor accepted pending.” A measured-but-unaccepted number closes as `claimed`; say so in the retrospective rather than closing green on arithmetic nobody signed.
|
|
22
22
|
- Audit receipt exists for the final shipped path (exceptions/operating map walked; cite file).
|
|
23
23
|
- Eval receipt: **n/a if no AI**, else final golden/eval result + HITL owner recorded; kill switch / fallback named in `handoff.md`.
|
|
24
24
|
- One line in the retrospective: which bucket moved, by how much, vs baseline.
|
|
@@ -41,6 +41,16 @@ The engagement doesn't end at ship. It ends when the customer can maintain what
|
|
|
41
41
|
|
|
42
42
|
Direct assessment to the FDE: did the engagement achieve `success.md` · 2–3 lessons that matter · is the pattern worth encoding · is the handoff complete or where are the gaps. Also: value bucket + audit receipt green; eval **n/a or green**. Pending Measured without sponsor acceptance = gap, not green close. Honest - a gap named now is cheaper than a callback in six weeks.
|
|
43
43
|
|
|
44
|
+
## Worked example
|
|
45
|
+
|
|
46
|
+
Acme, twelve weeks in, the FDE is rolling off.
|
|
47
|
+
|
|
48
|
+
Retrospective against the receipts: `brief.md` asked for monitoring, `reality.md` proved it was ownership — and the delta is the most useful paragraph in the file, because it is exactly the argument the next engagement will need.
|
|
49
|
+
|
|
50
|
+
The close gate bites in a useful way. The ledger shows detection at 12 minutes measured across two real incidents, but **Accepted by** is empty — Marco confirmed it in Slack, Denise (finance) never did, and Denise is whose escalation started the engagement. So it closes as `claimed` with a one-line retrospective note and a named next step, rather than a green close on a number nobody with budget agreed to.
|
|
51
|
+
|
|
52
|
+
`handoff.md` is written for the person woken at 2am: the three things that break, what the page means, how to re-run manually the way Marco does, and who holds the tribal knowledge (Raj, who built the original job — credited, because he protects it now). `patterns.md` gets *"unowned job" presents as "unmonitored job"* — it has now happened twice.
|
|
53
|
+
|
|
44
54
|
## Principles
|
|
45
55
|
|
|
46
56
|
- Done = the customer operates without you.
|
|
@@ -192,6 +192,16 @@ If discovery revealed the problem is 3× the brief: the FDE tells the customer *
|
|
|
192
192
|
|
|
193
193
|
Stop. Don't form a fourth hypothesis. Three disproven reads means the brief is actively misleading - usually the person who briefed doesn't know, or knows and can't say. Change method: stop analysing the system, ask three people separately "if you had to bet on what's actually wrong here, what would you say?" The thing they all hesitate before saying is the real problem.
|
|
194
194
|
|
|
195
|
+
## Worked example
|
|
196
|
+
|
|
197
|
+
Acme's brief blamed missing monitoring. Discovery goes to the workaround first.
|
|
198
|
+
|
|
199
|
+
`git log` shows the reconciliation module at 47 commits/90d with no tests, all from one author who left in February. Marco (ops lead) turns out to keep a spreadsheet: every morning he re-runs the job manually and eyeballs the totals — a habit nobody mentioned because to him it is just the job. That spreadsheet is the system of record when the job fails, which is the actual finding.
|
|
200
|
+
|
|
201
|
+
`reality.md`: **Confirmed:** the job has no owner, and the manual re-run masks failures for a day (evidence: Marco's sheet, Day 5; two silent failures since March, finance escalation Mar 14). **Stated brief was wrong because:** alerting existed last year and was disabled — adding it again without an owner reproduces the same outcome. `terrain.md` gets the hotspot row and an operating-map row: `job fails silently → Marco notices next morning → re-runs by hand → spreadsheet is truth → LOAD-BEARING (Marco, Day 5)`.
|
|
202
|
+
|
|
203
|
+
Checkpoint to the FDE names the sponsor decision this creates: fund ownership, or fund alerting and accept the same failure in six months.
|
|
204
|
+
|
|
195
205
|
## Principles
|
|
196
206
|
|
|
197
207
|
- The brief is a hypothesis until evidence confirms it.
|
|
@@ -1,36 +1,34 @@
|
|
|
1
1
|
# ingest-connect - wire a source MCP in plain language
|
|
2
2
|
|
|
3
|
-
**Enter when:** the FDE says "I want to connect a new MCP", "connect Granola /
|
|
3
|
+
**Enter when:** the FDE says "I want to connect a new MCP", "connect Granola / Slack / Notion", "how do I pull from …", or a pull request fails because no source tools exist.
|
|
4
4
|
|
|
5
|
-
**Read first:** `references/ingest.md` (sink contract).
|
|
5
|
+
**Read first:** `references/ingest.md` (sink contract). Recipes: `mcp/recipes/` (file, granola, slack, notion).
|
|
6
6
|
|
|
7
7
|
**Who runs setup:** you guide; the **host** (Cursor/Claude) must save MCP config. You cannot silently install servers into the host.
|
|
8
8
|
|
|
9
9
|
## Honest contract
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
11
|
+
- **Daily work does not need a source MCP.** Paste notes → debrief. File on disk → `fde ingest`.
|
|
12
|
+
- **Connect means a source**, not FDEOps. Granola/Slack/Notion credentials stay with that MCP. FDEOps never pushes, never ambient-syncs, never stores their tokens.
|
|
13
|
+
- **Sink is the CLI in this bound workspace** (`fde ingest`). `fdeops-ingest` MCP is optional. If you use it, pass `engagement` as the `.fde/` path from `fde resume --bind` (MCP servers often do not inherit the workspace bind).
|
|
14
|
+
- Never invent that Granola/Slack is available if tools are missing. Never auto-apply to `.fde/`.
|
|
14
15
|
|
|
15
16
|
## Method
|
|
16
17
|
|
|
17
|
-
1. **Ask one question** — which source? (`file` / `granola` / `notion` / other
|
|
18
|
+
1. **Ask one question** — which source? (`file` / `granola` / `slack` / `notion` / other). If "other", ask for the MCP they intend to use. If they just want paste → send them to debrief and stop.
|
|
18
19
|
2. **Capability check (current session)** — list MCP tools you can actually call:
|
|
19
|
-
- Sink
|
|
20
|
-
- Source
|
|
20
|
+
- Sink: `fde ingest` CLI (preferred) and/or `ingest_stage`
|
|
21
|
+
- Source: anything that can **fetch** that system's content (not post)
|
|
21
22
|
- Say clearly: *available now* vs *needs config*.
|
|
22
|
-
3. **Emit config
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
4. **Tell them where to paste** — Cursor: MCP settings / `~/.cursor/mcp.json` (or project MCP). Claude Code: MCP config per their docs. One sentence: save → reload MCP / restart session.
|
|
27
|
-
5. **Verify** — after they confirm reload: re-run capability check. If source tools appear, offer a **test pull** into `.inbox/` only (stage + show list). Stop before apply unless they ask to propose.
|
|
28
|
-
6. **Handoff phrase** — give them the daily line, e.g. `@fde pull today's Acme Granola into the fieldbook`.
|
|
23
|
+
3. **Emit config for the source only** — open `mcp/recipes/<source>.md`. Fill placeholders from *that product's* docs. Tell them to paste secrets into host env — never into `.fde/`.
|
|
24
|
+
4. **Tell them where to paste** — Cursor MCP settings / `mcp.json`. Claude Code: their MCP config. Save → reload MCP / restart session.
|
|
25
|
+
5. **Verify** — after reload: re-run capability check. If source tools appear, offer a **test pull** staged to `.inbox/` only. Stop before apply unless they ask to propose.
|
|
26
|
+
6. **Handoff phrase** — e.g. `@fde pull today's Acme Granola into the fieldbook`.
|
|
29
27
|
|
|
30
|
-
## If they only want
|
|
28
|
+
## If they only want paste / files
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
Do not add MCP. Use debrief or [mcp/recipes/file.md](../../../mcp/recipes/file.md).
|
|
33
31
|
|
|
34
32
|
## Checkpoint
|
|
35
33
|
|
|
36
|
-
Before ending connect: (1)
|
|
34
|
+
Before ending connect: (1) they know paste still works, (2) source reachable or honest gap, (3) they know the pull phrase. Do not write `.fde/` during connect.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Enter when:** the FDE wants to catch the engagement up from external sources — "make sure Acme is up to date," "pull what's relevant," "grab today's Granola and Denise's last email." Raw transcripts and long emails that are too big to paste usefully.
|
|
4
4
|
|
|
5
|
-
**Connect / capability (different entry):** "connect a new MCP", "connect Granola/Notion", "what can you pull?" → `references/ingest-connect.md` first. Recipes: `mcp/recipes/` (file, granola, notion).
|
|
5
|
+
**Connect / capability (different entry):** "connect a new MCP", "connect Granola/Slack/Notion", "what can you pull?" → `references/ingest-connect.md` first. Recipes: `mcp/recipes/` (file, granola, slack, notion).
|
|
6
6
|
|
|
7
7
|
**Read first:** `context.md` (what's already logged, what's stale). Bind the engagement before staging anything.
|
|
8
8
|
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
## Honest contract (read once)
|
|
12
12
|
|
|
13
13
|
- FDEOps owns the **sink only**: stage raw pulls → propose → confirm → apply. Nothing writes `.fde/` unreviewed.
|
|
14
|
-
- **Source MCPs are the FDE's.** Granola,
|
|
14
|
+
- **Source MCPs are the FDE's.** Granola, Slack, Notion, Gmail, custom — whatever they configured in Cursor/Claude. fdeops does not bundle OAuth, connectors, or ambient sync, and **does not push** to those tools.
|
|
15
|
+
- Prefer **`fde ingest` in this bound workspace.** Optional `fdeops-ingest` MCP: pass `engagement` (path to `.fde/` from `fde resume --bind`) because MCP cwd often is not the client workspace.
|
|
15
16
|
- The core `fde` CLI stays local (git + file reads). Source credentials live with that MCP; fdeops never stores them.
|
|
16
17
|
- After apply, raw stays in `.inbox/`; the system of record (`.fde/`) stays thin dated facts.
|
|
17
18
|
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
List what you can actually call **this session**:
|
|
21
22
|
|
|
22
23
|
1. **Sink** — `ingest_stage` / `fde ingest` available?
|
|
23
|
-
2. **Sources** — which fetch tools exist (Granola-shaped, Notion, Drive, file-only)?
|
|
24
|
+
2. **Sources** — which fetch tools exist (Granola-shaped, Slack, Notion, Drive, file-only)?
|
|
24
25
|
3. Tell the FDE in one line: *I can pull from X; Y is not connected.* If they asked to pull Y and it is missing → switch to `ingest-connect.md`. Never pretend a source exists.
|
|
25
26
|
|
|
26
27
|
## Ground loop (you do this work)
|
|
@@ -67,6 +68,6 @@ Before apply, read back the 2–3 most consequential captures in one breath —
|
|
|
67
68
|
|
|
68
69
|
## Principles
|
|
69
70
|
|
|
70
|
-
- Pull on request, not on a schedule. No auto-poll, no vacuum of inbox or Slack.
|
|
71
|
+
- Pull on request, not on a schedule. No auto-poll, no vacuum of inbox or Slack. No posting back.
|
|
71
72
|
- Staging is not memory. Only `--apply` after confirm writes `.fde/`.
|
|
72
73
|
- Large artifact → ingest stage first; pasted short notes → debrief verb directly (`references/debrief.md`).
|
|
@@ -79,6 +79,16 @@ Before the end of day 1, ship one visible thing: a small bug fix, a cleanup the
|
|
|
79
79
|
|
|
80
80
|
**`success.md`** - what done looks like, **primary value bucket** (`cost-save` | `risk-mitigation` | `revenue-uplift`), baseline → target, who actually signs off, what is explicitly out of scope. Agreed with the customer, not assumed.
|
|
81
81
|
|
|
82
|
+
For every target number, run the **gaming check** before it is written down: *how could this metric hit its target without the customer being any better off?* There is always an answer, and the answer is what the org will drift toward under pressure. Write the guard next to the metric:
|
|
83
|
+
|
|
84
|
+
```markdown
|
|
85
|
+
| Metric | Baseline → target | Gamed by | Guard |
|
|
86
|
+
|--------|-------------------|----------|-------|
|
|
87
|
+
| reconciliation alert latency | 4h → 15min | alerting on everything, so nobody reads them | alerts acked by a named owner, ≤2/week |
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
A metric with no gaming check is a metric the FDE will be held to and cannot defend. If the customer resists the guard, that is the real conversation - they are attached to the number, not the outcome.
|
|
91
|
+
|
|
82
92
|
**`stakeholders.md`**:
|
|
83
93
|
```markdown
|
|
84
94
|
| Who | Role | Signal | Notes |
|
|
@@ -105,6 +115,16 @@ One page back to the FDE: success + value bucket + sign-off owner, out-of-scope
|
|
|
105
115
|
|
|
106
116
|
If remote: trust-building takes ~40% longer - push for a short video call before anything asynchronous.
|
|
107
117
|
|
|
118
|
+
## Worked example
|
|
119
|
+
|
|
120
|
+
Kickoff at Acme payments. Priya (VP Eng) sponsors; the brief says "add monitoring to the reconciliation service."
|
|
121
|
+
|
|
122
|
+
Asking what happens the week after a perfect delivery gets: "I stop hearing about it from finance." That is the real success statement — not monitoring. The previous attempt surfaces too: the platform team built alerting last year, it was turned off. Raj, who built it, is still there and was not in the kickoff — the passed-over team, found on day 1 rather than at the first standup.
|
|
123
|
+
|
|
124
|
+
What gets written: `success.md` with bucket `risk-mitigation`, `reconciliation failures reach a named owner within 15 min (baseline: 4h, found by finance)`, gaming check `alerting on everything so nobody reads them` → guard `≤2 alerts/week, acked by name`, sign-off Priya. `brief.md` carries the gap list and the hypothesis: *the job is not unmonitored, it is unowned*. `assumptions.md` seeds `"finance would act on an alert" — CRITICAL — OPEN — (stated, unverified)`. `trust-profile.md` records the sacred thing Priya hesitated before naming.
|
|
125
|
+
|
|
126
|
+
Day-1 deliverable: fix the log line that swallows the job's exit code. Small, visible, in their environment.
|
|
127
|
+
|
|
108
128
|
## Principles
|
|
109
129
|
|
|
110
130
|
- Never start technical work before `success.md` exists.
|
|
@@ -72,6 +72,16 @@ The full option details in the same entry or linked to a section in `reality.md`
|
|
|
72
72
|
|
|
73
73
|
Present the three options and the recommendation. One question to the FDE: "Which option matches what the sponsor can hear right now?" (A risk-averse sponsor after an incident → conservative. A founder pre-fundraise → ambitious.) If unsure: present all three and let the sponsor decide.
|
|
74
74
|
|
|
75
|
+
## Worked example
|
|
76
|
+
|
|
77
|
+
Acme: the reconciliation job needs to survive the FDE leaving. Priya asks "so what should we do?"
|
|
78
|
+
|
|
79
|
+
Three real paths, not a strawman set. **Safe:** keep the job, add the rota and runbook — two weeks, no new failure modes, does nothing about the 47-commits/90d hotspot. **Pragmatic:** extract the settlement-matching step behind a tested interface — six weeks, retires the untested hotspot, needs Raj's time and he currently opposes it. **Aggressive:** rewrite the service — a quarter, fixes everything, and the same team already abandoned this once.
|
|
80
|
+
|
|
81
|
+
Same dimensions on each, so comparison is instant, and every cost carries a source: the six-week figure is churn-based, not felt.
|
|
82
|
+
|
|
83
|
+
Recommendation: pragmatic, conditional — *if* Raj is on the design, otherwise safe, because the aggressive path failed here before for exactly the reason it would fail again. `decisions.md` records the decision, who chose it, and the condition, so week 10's "why aren't we rewriting it" has an answer with a date on it.
|
|
84
|
+
|
|
75
85
|
## Principles
|
|
76
86
|
|
|
77
87
|
- Three options, never one. One option is a request for trust; three is a real decision.
|
|
@@ -131,6 +131,16 @@ Write migration strategy to `decisions.md` under `## Migration`. Each service ge
|
|
|
131
131
|
|
|
132
132
|
Never quietly update tasks. Name the reset: update `reality.md` and `success.md`, one paragraph in `decisions.md` - what changed, why, new sequence. An undocumented reset looks like drift; a documented one looks like the FDE caught something important.
|
|
133
133
|
|
|
134
|
+
## Worked example
|
|
135
|
+
|
|
136
|
+
Acme, after discover: the reconciliation job is unowned, Marco's spreadsheet is the real fallback.
|
|
137
|
+
|
|
138
|
+
**Now** is three tasks, not eight. Task 1 is *failures reach a named human* — delivers a page to a rota, accepts "kill the job mid-run → the on-call is paged within 15 min", touches the job wrapper and the alert config, rollback is re-disable the route, verify by killing it in staging. Value promised: `risk-mitigation — a silent failure becomes a 15-minute one`.
|
|
139
|
+
|
|
140
|
+
The kill list in `decisions.md` is where the plan earns its keep: the rewrite of the reconciliation service that Tom keeps proposing goes there — *deferred, the failure mode is ownership not architecture (Priya accepted, Jun 12)* — along with the finance dashboard finance asked for directly. Both stay visible so the same argument is not re-litigated in week 4 without a receipt.
|
|
141
|
+
|
|
142
|
+
First visible slice goes to Marco, not Priya: he is the one whose morning changes, and his confirmation is what makes the sponsor update true.
|
|
143
|
+
|
|
134
144
|
## Principles
|
|
135
145
|
|
|
136
146
|
- Plan from success backwards, not from today forwards.
|
|
@@ -61,6 +61,16 @@ Evidence-based: point to `decisions.md` scope receipts with dates and requesters
|
|
|
61
61
|
|
|
62
62
|
Weekly check: count the scope receipts since last conversation. Three or more unaddressed → recommend the accumulation conversation to the FDE. Zero → "scope holding, `success.md` current."
|
|
63
63
|
|
|
64
|
+
## Worked example
|
|
65
|
+
|
|
66
|
+
Acme, week 5. Nothing has been formally added, and the slice is a week late.
|
|
67
|
+
|
|
68
|
+
The pattern shows in three receipts, not one argument: a "quick" finance CSV export (Jun 20, half a day, from Denise directly), retry-logic cleanup asked for mid-build (Jun 24, one day, Tom), and a dashboard tile "while you're in there" (Jun 27, half a day). Each was individually reasonable; together they are the slip.
|
|
69
|
+
|
|
70
|
+
Three-bucket response, applied at the moment of the third ask rather than in a retrospective: the CSV export goes to Next with an accepted trade (it displaces the runbook polish), the retry cleanup goes to the kill list in `decisions.md` with the blast-radius reason, and the tile is absorbed because it is genuinely twenty minutes — logged anyway, since an unlogged absorption is the one that gets forgotten in the accumulation conversation.
|
|
71
|
+
|
|
72
|
+
That conversation happens with Priya at three receipts, with the dates on screen: "these are the four asks, here is the two days, here is what moved." Not a complaint — a decision she gets to make, with evidence, before the deadline makes it for her.
|
|
73
|
+
|
|
64
74
|
## Principles
|
|
65
75
|
|
|
66
76
|
- "Let me place it" is the phrase. Not "no," not "sure."
|
|
@@ -186,6 +186,16 @@ Adoption isn't a handoff-stage problem - it starts during build. Software that l
|
|
|
186
186
|
|
|
187
187
|
Before 100%: canary clean, business metric verified, pulse written into `delivery.md`. Also green: value bucket named, audit receipt dated, eval receipt **n/a or pass**, **intent vs diff clean** (no unresolved SPLIT/DROP). Missing any of those → not green. For enterprise-scale: scale-readiness gate passed before broad rollout.
|
|
188
188
|
|
|
189
|
+
## Worked example
|
|
190
|
+
|
|
191
|
+
Acme, shipping the failure-routing slice into a payments environment on a Thursday.
|
|
192
|
+
|
|
193
|
+
Readiness scoring catches two things the diff does not. The audit receipt is missing: the operating map says Marco's manual re-run is the fallback, and nobody has checked whether the new page fires *before* his morning run or after — if after, the alert changes nothing. That gets walked and cited before deploy. Second, the intent-vs-diff read shows the PR also touches the settlement retry that was deferred in build; it comes out.
|
|
194
|
+
|
|
195
|
+
Pre-blast challenge: "what does this break if it fires at 3am and nobody acks?" Answer: nothing breaks, but the rota is not yet agreed — so the deploy waits on a name, not on code. That is a one-day slip that prevents a fake green.
|
|
196
|
+
|
|
197
|
+
After deploy: `delivery.md` ship receipt with the audit cite, the kill test evidence, and the rollback line. Eval receipt: n/a, no AI in this path.
|
|
198
|
+
|
|
189
199
|
## Principles
|
|
190
200
|
|
|
191
201
|
- A deployment without a tested rollback is reckless.
|