fdeops 3.10.0 → 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 +87 -105
- package/bin/check.js +1 -1
- package/mcp/README.md +1 -1
- package/mcp/fdeops-ingest/README.md +4 -2
- package/mcp/fdeops-ingest/package.json +1 -1
- package/mcp/fdeops-ingest/server.js +32 -11
- 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/package.json +1 -1
- package/plugin.json +1 -1
- package/skills/fde/SKILL.md +4 -4
- package/skills/fde/references/ingest-connect.md +16 -18
- package/skills/fde/references/ingest.md +5 -4
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](https://nodejs.org)
|
|
9
9
|
|
|
10
|
-
**Memory + methodology + skills, in one kit.** Skill packs - BMAD, Spec-Kit, [mattpocock/skills](https://github.com/mattpocock/skills) - teach your AI agent how to *build*. None of them remember who the client is, what you promised them, or who agreed it was delivered. FDEOps adds the missing layer: a private fieldbook per engagement (`.fde/`), a field methodology (land → close), and one `@fde` skill that routes it all.
|
|
10
|
+
**Memory + methodology + skills, in one kit.** Skill packs - BMAD, Spec-Kit, [mattpocock/skills](https://github.com/mattpocock/skills) - teach your AI coding agent how to *build*. None of them remember who the client is, what you promised them, or who agreed it was delivered. FDEOps adds the missing layer: a private fieldbook per engagement (`.fde/`), a field methodology (land → close), and one `@fde` skill that routes it all.
|
|
11
11
|
|
|
12
12
|
Built for Forward Deployed Engineers, and anyone embedded in client work: consultants, agency developers, solutions architects, fractional CTOs. Feels like a second brain; behaves like a defensible record (dated, sourced, yours).
|
|
13
13
|
|
|
@@ -19,87 +19,82 @@ Built for Forward Deployed Engineers, and anyone embedded in client work: consul
|
|
|
19
19
|
written as a side effect of the work
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Talk in plain language with `@fde`. The AI coding agent runs the plumbing. You confirm anything that enters the record.
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
26
26
|
## The week
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
`@fde` plus English. No cheat sheet.
|
|
29
29
|
|
|
30
30
|
| When | What you say | What you get |
|
|
31
31
|
|------|--------------|--------------|
|
|
32
|
-
| **Start of week** |
|
|
33
|
-
| **After a meeting** | `@fde` debrief these notes *(paste or attach
|
|
34
|
-
| **
|
|
35
|
-
| **Before a stakeholder meeting** | `@fde` prep me for tomorrow
|
|
36
|
-
| **
|
|
37
|
-
| **End of week** | `@fde` draft the sponsor update from the record | Status grounded in what
|
|
32
|
+
| **Start of week** | `@fde` — or just open Claude Code | Fieldbook on disk either way. **Claude Code** injects trust, phase, next before you type. **Cursor / Codex / others:** say `@fde` or `resume` — nothing auto-loads. |
|
|
33
|
+
| **After a meeting** | `@fde` debrief these notes *(paste or attach)* | Proposed updates. You review, then confirm. |
|
|
34
|
+
| **Optional: pull** | `@fde` connect Granola *(once)* · `@fde` pull today's Acme transcript | You add that source MCP. We **pull** on request — no push, no sync. [mcp/recipes/](mcp/recipes/) |
|
|
35
|
+
| **Before a stakeholder meeting** | `@fde` prep me for tomorrow with the sponsor | Brief from what you already logged. |
|
|
36
|
+
| **Scope dispute** | `@fde` when did we agree to drop that? | Dated answers, or a clear gap. |
|
|
37
|
+
| **End of week** | `@fde` draft the sponsor update from the record | Status grounded in what happened. |
|
|
38
38
|
|
|
39
|
-
Same
|
|
39
|
+
Same folder every time: `~/fde-engagements/<client>/.fde/`.
|
|
40
40
|
|
|
41
41
|
---
|
|
42
42
|
|
|
43
|
-
## See it
|
|
43
|
+
## See it
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
46
|
npx fdeops demo
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Real commands on a fake client: messy notes → you confirm → cold reload → prep → receipts → fieldbook page. Nothing of yours is read. Lives in `~/fde-engagements/.demo/`. Remove with `npx fdeops demo --clean`.
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
One recorded session — kickoff notes, next morning, “when did we agree?” weeks later. CLI output; typing pace is staged. Re-record: [`media/record-session.sh`](media/record-session.sh).
|
|
52
52
|
|
|
53
53
|
<p align="center"><img alt="A real fdeops session: messy kickoff notes routed into dated memory after you confirm, then a cold session that already knows the client, a grounded sponsor-meeting brief, and dated receipts" src="media/session.gif" width="900" /></p>
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
Two things a chat window cannot do: **nothing is written until you confirm**, and `<private>` lands sealed as `(private - redacted)` — never in `resume`, `prep`, `receipts`, or the dashboard.
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
59
59
|
## Quickstart
|
|
60
60
|
|
|
61
|
-
**1. Install.** Claude Code
|
|
61
|
+
**1. Install.** Claude Code: session hooks (context before you type). Everywhere else: the same fieldbook, loaded when you ask.
|
|
62
62
|
|
|
63
63
|
```text
|
|
64
|
-
/plugin marketplace add suboss87/fdeops
|
|
64
|
+
/plugin marketplace add suboss87/fdeops
|
|
65
65
|
/plugin install fdeops@fdeops
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
|
-
npx skills add suboss87/fdeops # Cursor, Codex,
|
|
69
|
+
npx skills add suboss87/fdeops # Cursor, Codex, skills-compatible hosts
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
**2. Bind once**
|
|
72
|
+
**2. Bind once** in the client workspace:
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
|
-
npx fdeops resume --init garvey #
|
|
75
|
+
npx fdeops resume --init garvey # ~/fde-engagements/garvey + bind this checkout
|
|
76
|
+
npx fdeops resume # where we are
|
|
76
77
|
```
|
|
77
78
|
|
|
78
|
-
**
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
npx fdeops resume # prints a short "where we are" for this client
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**3. Work** - talk normally:
|
|
79
|
+
**3. Work**
|
|
85
80
|
|
|
86
81
|
```text
|
|
87
|
-
@fde
|
|
82
|
+
@fde New client. Payments platform. They want it live before the Q3 audit.
|
|
88
83
|
```
|
|
89
84
|
|
|
90
|
-
`@fde` routes and
|
|
85
|
+
`@fde` routes and drafts; you confirm judgment. Workflow: [docs/USAGE.md](docs/USAGE.md).
|
|
91
86
|
|
|
92
|
-
|
|
87
|
+
Working: `npx fdeops resume` prints this client's phase, trust, and next action. Tomorrow that file is still there. Auto-load at session start is Claude Code; elsewhere you invoke `@fde`.
|
|
93
88
|
|
|
94
89
|
<details>
|
|
95
|
-
<summary
|
|
90
|
+
<summary>Other install paths · scan · env</summary>
|
|
96
91
|
|
|
97
|
-
- **
|
|
98
|
-
- **Local LLMs
|
|
99
|
-
- **
|
|
100
|
-
- **
|
|
101
|
-
- **Requires:**
|
|
102
|
-
- **
|
|
92
|
+
- **Adapters:** `npx fdeops adapters .` — [adapters/](adapters/README.md)
|
|
93
|
+
- **Local LLMs:** load `skills/fde/SKILL.md` — [guide](adapters/LOCAL-LLM.md)
|
|
94
|
+
- **Air-gapped:** `git clone https://github.com/suboss87/fdeops.git && cd fdeops && node bin/install.js`
|
|
95
|
+
- **No install:** `npx fdeops demo` · `npx fdeops scan` (heuristic recon, not findings)
|
|
96
|
+
- **Requires:** Node.js >= 18
|
|
97
|
+
- **Override:** `FDEOPS_ENGAGEMENT` — [docs/install.md](docs/install.md)
|
|
103
98
|
|
|
104
99
|
</details>
|
|
105
100
|
|
|
@@ -107,38 +102,26 @@ npx fdeops resume # prints a short "where we are" for this clien
|
|
|
107
102
|
|
|
108
103
|
## How it works
|
|
109
104
|
|
|
110
|
-
- **You** describe the situation with `@fde` (or plain language once the skill is loaded)
|
|
111
|
-
- **
|
|
112
|
-
- **Local CLI**
|
|
113
|
-
- **
|
|
114
|
-
|
|
115
|
-
fdeops complements repo memory: CLAUDE.md holds how the *code* works; the fieldbook holds how the *client engagement* works.
|
|
116
|
-
|
|
117
|
-
### Switch coding agents anytime
|
|
118
|
-
|
|
119
|
-
The fieldbook lives on disk at `~/fde-engagements/<client>/.fde/` - not inside Claude, Cursor, or any other tool. Change AI coding agents and the **same client record** is still there.
|
|
105
|
+
- **You** describe the situation with `@fde` (or plain language once the skill is loaded).
|
|
106
|
+
- **Hooks (Claude Code)** load where you left off and snapshot on the way out. Other hosts: same CLI and files; you call `@fde` / `resume`.
|
|
107
|
+
- **Local CLI** — writes, receipts, status. Zero model tokens. The AI coding agent runs it; you do not live in the CLI. [docs/USAGE.md](docs/USAGE.md)
|
|
108
|
+
- **Pull (optional)** — FDEOps is the sink. Paste is the daily path. A source MCP you add (Granola, Slack, Notion, …) can fetch text; `@fde connect …` walks config. No push, no sync, no tokens in `.fde/`. [mcp/recipes/](mcp/recipes/)
|
|
120
109
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
1. Install `@fde` for that tool (plugin, `npx skills add suboss87/fdeops`, or `npx fdeops adapters .` - see [adapters/](adapters/README.md))
|
|
124
|
-
2. Open a workspace already bound with `npx fdeops resume --init <client>` (or bind once if this checkout is new)
|
|
125
|
-
3. Talk with `@fde` or run `npx fdeops resume`
|
|
126
|
-
|
|
127
|
-
Same fieldbook. **Claude Code** gets the fullest ride (session start/stop hooks). Elsewhere the memory and CLI are the same; context usually loads when you ask `@fde` / `resume`, not automatically. Details: [docs/install.md](docs/install.md).
|
|
110
|
+
`CLAUDE.md` is how the *code* works. The fieldbook is how the *engagement* works. 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.
|
|
128
111
|
|
|
129
112
|
<details>
|
|
130
|
-
<summary
|
|
113
|
+
<summary>Phase verbs (land → close)</summary>
|
|
131
114
|
|
|
132
115
|
| Verb | When |
|
|
133
116
|
|------|------|
|
|
134
|
-
| **land** | First days
|
|
135
|
-
| **discover** | The brief
|
|
136
|
-
| **plan** |
|
|
137
|
-
| **build** |
|
|
138
|
-
| **ship** |
|
|
139
|
-
| **close** |
|
|
117
|
+
| **land** | First days — brief, stakeholders, success |
|
|
118
|
+
| **discover** | The brief is wrong — evidence from the repo |
|
|
119
|
+
| **plan** | Sequence backwards from done, PR-sized |
|
|
120
|
+
| **build** | Blast radius, log what shipped |
|
|
121
|
+
| **ship** | Pre-flight, canary, rollback |
|
|
122
|
+
| **close** | Handoff, retro, receipts that survive you |
|
|
140
123
|
|
|
141
|
-
Overlays
|
|
124
|
+
Overlays (AI, fintech, healthcare, gov) fire on signal. [docs/skills.md](docs/skills.md)
|
|
142
125
|
|
|
143
126
|
</details>
|
|
144
127
|
|
|
@@ -146,43 +129,46 @@ Overlays for regulated domains (AI, fintech, healthcare, government) activate on
|
|
|
146
129
|
|
|
147
130
|
## The field methods
|
|
148
131
|
|
|
149
|
-
You never pick one
|
|
132
|
+
You never pick one. You describe the situation; `@fde` routes. **37 methods**, six domains — each a method (thinking, artifact, checkpoint), not a tip sheet. [docs/skills.md](docs/skills.md) · [docs/skills-reference.md](docs/skills-reference.md)
|
|
133
|
+
|
|
134
|
+
<details>
|
|
135
|
+
<summary>All 37 methods</summary>
|
|
150
136
|
|
|
151
137
|
| Domain | Methods |
|
|
152
138
|
|--------|---------|
|
|
153
|
-
| **1. Embed & Trust**
|
|
154
|
-
| **2. Discover & Diagnose**
|
|
155
|
-
| **3. Plan & Align**
|
|
156
|
-
| **4. Build & Guard**
|
|
157
|
-
| **5. Ship & Verify**
|
|
158
|
-
| **6. Operate & Close**
|
|
139
|
+
| **1. Embed & Trust** | [land](skills/fde/references/land.md) · [audit](skills/fde/references/audit.md) · [stakeholder-radar](skills/fde/references/stakeholder-radar.md) · [trust-engineering](skills/fde/references/trust-engineering.md) · [scope-defense](skills/fde/references/scope-defense.md) |
|
|
140
|
+
| **2. Discover & Diagnose** | [discover](skills/fde/references/discover.md) · [assumption-audit](skills/fde/references/assumption-audit.md) · [use-case-scoring](skills/fde/references/use-case-scoring.md) · [sketch](skills/fde/references/sketch.md) |
|
|
141
|
+
| **3. Plan & Align** | [plan](skills/fde/references/plan.md) · [business-case](skills/fde/references/business-case.md) · [options-analysis](skills/fde/references/options-analysis.md) · [initiative-triage](skills/fde/references/initiative-triage.md) |
|
|
142
|
+
| **4. Build & Guard** | [build](skills/fde/references/build.md) · [incremental-build](skills/fde/references/incremental-build.md) · [test-on-legacy](skills/fde/references/test-on-legacy.md) · [blast-radius](skills/fde/references/blast-radius.md) · [debug](skills/fde/references/debug.md) · [rescue](skills/fde/references/rescue.md) · [security-audit](skills/fde/references/security-audit.md) · [observability](skills/fde/references/observability.md) |
|
|
143
|
+
| **5. Ship & Verify** | [ship](skills/fde/references/ship.md) · [review](skills/fde/references/review.md) · [rollback-drill](skills/fde/references/rollback-drill.md) · [qa-live](skills/fde/references/qa-live.md) |
|
|
144
|
+
| **6. Operate & Close** | [status](skills/fde/references/status.md) · [demo-prep](skills/fde/references/demo-prep.md) · [debrief](skills/fde/references/debrief.md) · [exec-narrative](skills/fde/references/exec-narrative.md) · [dashboard](skills/fde/references/dashboard.md) · [multi-customer-ops](skills/fde/references/multi-customer-ops.md) · [close](skills/fde/references/close.md) · [handoff-engineering](skills/fde/references/handoff-engineering.md) · [pattern-extract](skills/fde/references/pattern-extract.md) · [red-team](skills/fde/references/red-team.md) · [ingest](skills/fde/references/ingest.md) · [ingest-connect](skills/fde/references/ingest-connect.md) |
|
|
159
145
|
|
|
160
|
-
|
|
146
|
+
Overlays: [ai](skills/fde/references/ai.md) · [artifacts](skills/fde/references/artifacts.md) · [fintech](skills/fde/references/fintech.md) · [healthcare](skills/fde/references/healthcare.md) · [gov](skills/fde/references/gov.md)
|
|
161
147
|
|
|
162
|
-
|
|
148
|
+
</details>
|
|
163
149
|
|
|
164
150
|
---
|
|
165
151
|
|
|
166
152
|
## Engagement memory (`.fde/`)
|
|
167
153
|
|
|
168
|
-
|
|
154
|
+
One folder per client. Plain markdown. Grep it, copy it, defend it.
|
|
169
155
|
|
|
170
156
|
| File | Holds |
|
|
171
157
|
|------|-------|
|
|
172
|
-
| `context.md` | Where you are
|
|
173
|
-
| `brief.md` / `success.md` | What they asked
|
|
174
|
-
| `reality.md` / `terrain.md` | The real problem; the
|
|
175
|
-
| `stakeholders.md` |
|
|
158
|
+
| `context.md` | Where you are |
|
|
159
|
+
| `brief.md` / `success.md` | What they asked; what “done” is and who signs |
|
|
160
|
+
| `reality.md` / `terrain.md` | The real problem; the map |
|
|
161
|
+
| `stakeholders.md` | `[signal:green\|amber\|red]` |
|
|
176
162
|
| `trust-profile.md` | Sacred data, AI policy, approval chain |
|
|
177
|
-
| `decisions.md` / `risks.md` / `delivery.md` |
|
|
163
|
+
| `decisions.md` / `risks.md` / `delivery.md` | Dated choices; live risks; what shipped and how it rolls back |
|
|
178
164
|
|
|
179
|
-
|
|
165
|
+
Schema: [docs/schema.md](docs/schema.md).
|
|
180
166
|
|
|
181
167
|
---
|
|
182
168
|
|
|
183
169
|
## Fieldbook UI
|
|
184
170
|
|
|
185
|
-
|
|
171
|
+
Local HTML: trust, phase, next, the record. `@fde` dashboard, or `npx fdeops dashboard` (`--all` for the portfolio).
|
|
186
172
|
|
|
187
173
|
<p align="center"><img width="1336" height="624" alt="fdeops Fieldbook in the browser" src="https://github.com/user-attachments/assets/5683614c-7730-4a3a-860d-185053a377eb" /></p>
|
|
188
174
|
|
|
@@ -190,54 +176,50 @@ Open the system of record in a browser - trust, phase, next action, and the full
|
|
|
190
176
|
|
|
191
177
|
## Who this is for
|
|
192
178
|
|
|
193
|
-
| You are
|
|
194
|
-
|
|
195
|
-
| **Forward Deployed Engineer** | The
|
|
196
|
-
| **Consultant
|
|
197
|
-
| **Solutions architect
|
|
198
|
-
| **Agency
|
|
199
|
-
| **Fractional CTO
|
|
179
|
+
| You are | What this is |
|
|
180
|
+
|---------|----------------|
|
|
181
|
+
| **Forward Deployed Engineer** | The job this was built for — first meeting through handoff |
|
|
182
|
+
| **Consultant / contractor on site** | The engagement stops resetting every morning |
|
|
183
|
+
| **Solutions architect** | Politics and architecture in the same record |
|
|
184
|
+
| **Agency, 3–5 clients** | One `.fde/` each — they stop blurring |
|
|
185
|
+
| **Fractional CTO on client work** | System of record for the embed, and the billable trail |
|
|
200
186
|
|
|
201
187
|
---
|
|
202
188
|
|
|
203
189
|
## Your data stays yours
|
|
204
190
|
|
|
205
|
-
- **Local only.**
|
|
206
|
-
- **Plain markdown.** No database
|
|
207
|
-
- **No new data path.** The
|
|
208
|
-
- **Nothing
|
|
209
|
-
- **Know
|
|
191
|
+
- **Local only.** `git` + files. No network, no telemetry, no account. Air-gapped is fine.
|
|
192
|
+
- **Plain markdown.** No database.
|
|
193
|
+
- **No new data path.** The model sees client code only when you point the AI coding agent at it. `<private>` is redacted from CLI, dashboard, and hooks — do not open raw private blocks with file tools.
|
|
194
|
+
- **Nothing unreviewed.** Draft → you confirm. `fde debrief --dry-run` shows routing first.
|
|
195
|
+
- **Know the sync surface.** `~/fde-engagements` is in `$HOME`. iCloud/Dropbox is an NDA incident waiting. `resume --init` warns. [PRIVACY.md](PRIVACY.md) before the first NDA.
|
|
210
196
|
|
|
211
|
-
|
|
197
|
+
[PRIVACY.md](PRIVACY.md) · [SECURITY.md](SECURITY.md)
|
|
212
198
|
|
|
213
199
|
---
|
|
214
200
|
|
|
215
201
|
## Principles
|
|
216
202
|
|
|
217
|
-
- **The artifact is the memory**
|
|
218
|
-
- **Methods, not autonomy**
|
|
219
|
-
- **Brief is a hypothesis**
|
|
220
|
-
- **Evidence on every claim**
|
|
221
|
-
- **One customer, one folder**
|
|
203
|
+
- **The artifact is the memory** — producing the work and recording it are one action
|
|
204
|
+
- **Methods, not autonomy** — the kit says what to check; judgment stays yours
|
|
205
|
+
- **Brief is a hypothesis** — discover before building the wrong thing
|
|
206
|
+
- **Evidence on every claim** — these files get defended in the room
|
|
207
|
+
- **One customer, one folder** — context never bleeds
|
|
222
208
|
|
|
223
209
|
---
|
|
224
210
|
|
|
225
211
|
## Updating
|
|
226
212
|
|
|
227
|
-
|
|
228
|
-
# Plugin / skills install: re-run the install command from Quickstart
|
|
229
|
-
# From a git clone:
|
|
230
|
-
cd fdeops && git pull && node bin/install.js
|
|
231
|
-
```
|
|
213
|
+
Re-run the Quickstart install, or from a clone: `git pull && node bin/install.js`
|
|
232
214
|
|
|
233
215
|
---
|
|
234
216
|
|
|
235
217
|
## Contributing
|
|
236
218
|
|
|
237
|
-
|
|
219
|
+
**[Subash Natarajan](https://www.linkedin.com/in/subashn/)**. [Issues](https://github.com/suboss87/fdeops/issues) · [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
238
220
|
|
|
239
|
-
Thanks to builders whose craft
|
|
221
|
+
Thanks to builders whose craft sharpened the thinking, among them [Andrej Karpathy](https://karpathy.ai/)'s engineering guidelines and the [agentic engineering workflow](https://github.com/pawel-cell/micky-podcast-agentic-engineering) notes from David Ondrej / Michael Shimeles. FDEOps is handcrafted for field work; resemblance is craft, not a fork.
|
|
240
222
|
|
|
241
|
-
**What we won't build:** SaaS sync
|
|
223
|
+
**What we won't build:** SaaS sync; Slack/Notion/Granola connectors or **push** inside the CLI; CRM as core; hardware capture; generic code-craft packs (TDD/review live elsewhere). You may **pull** via *your* MCP. The `fde` CLI stays local-only.
|
|
242
224
|
|
|
243
|
-
[FDE Methodology](FDE-METHODOLOGY.md)
|
|
225
|
+
[FDE Methodology](FDE-METHODOLOGY.md) · [SECURITY.md](SECURITY.md) · [PRIVACY.md](PRIVACY.md) · [Repo layout](docs/REPO_LAYOUT.md) · [Skills matrix](docs/skills.md) · MIT
|
package/bin/check.js
CHANGED
|
@@ -499,7 +499,7 @@ if (!fs.existsSync(path.join(root, 'mcp', 'fdeops-ingest', 'server.js'))) {
|
|
|
499
499
|
} else if (!fs.existsSync(path.join(root, 'skills', 'fde', 'references', 'ingest-connect.md'))) {
|
|
500
500
|
fail('skills/fde/references/ingest-connect.md missing')
|
|
501
501
|
} else {
|
|
502
|
-
for (const recipe of ['file.md', 'granola.md', 'notion.md']) {
|
|
502
|
+
for (const recipe of ['file.md', 'granola.md', 'slack.md', 'notion.md']) {
|
|
503
503
|
if (!fs.existsSync(path.join(root, 'mcp', 'recipes', recipe))) fail(`mcp/recipes/${recipe} missing`)
|
|
504
504
|
}
|
|
505
505
|
if (!read('README.md').includes('mcp/recipes')) fail('README must point at mcp/recipes for connect clarity')
|
package/mcp/README.md
CHANGED
|
@@ -6,7 +6,7 @@ FDEOps MCP servers follow a **pluggable source model**: core owns the **sink**,
|
|
|
6
6
|
|
|
7
7
|
| Role | Owner | Examples |
|
|
8
8
|
|------|-------|----------|
|
|
9
|
-
| **Source** | FDE configures separately | Granola,
|
|
9
|
+
| **Source** | FDE configures separately | Granola, Slack, Notion, Gmail, file |
|
|
10
10
|
| **Sink** | FDEOps (`fdeops-ingest`) | stage → propose → apply into engagement memory |
|
|
11
11
|
|
|
12
12
|
Source MCPs fetch raw text from SaaS APIs using credentials the FDE manages. The ingest MCP never stores OAuth tokens or calls external services — it only shells out to the local `fde` CLI.
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Thin stdio MCP server for the FDEOps **ingest sink** only: **stage → propose → apply**.
|
|
4
4
|
|
|
5
|
-
This package shells out to the local `fde` CLI. It never calls SaaS APIs. Source MCPs (Granola,
|
|
5
|
+
This package shells out to the local `fde` CLI. It never calls SaaS APIs. Source MCPs (Granola, Slack, Notion, etc.) are **separate** — you add those in your own `mcp.json`.
|
|
6
|
+
|
|
7
|
+
**Prefer the CLI when this workspace is bound:** `fde ingest stage|list|propose|apply`. Use this MCP when the host did not start in a bound workspace — then pass `engagement` (path to `.fde/` from `fde resume --bind`) on every tool call.
|
|
6
8
|
|
|
7
9
|
## Tools
|
|
8
10
|
|
|
@@ -89,4 +91,4 @@ Sources are pluggable and user-configured. This MCP owns the sink only.
|
|
|
89
91
|
|
|
90
92
|
## Zero dependencies
|
|
91
93
|
|
|
92
|
-
Hand-rolled MCP over stdio (
|
|
94
|
+
Hand-rolled MCP over stdio (newline-delimited JSON-RPC). No `@modelcontextprotocol/sdk` required at runtime.
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* fdeops-ingest MCP — thin stdio sink for FDEOps ingest.
|
|
6
6
|
* Shells out to local `fde` CLI only. Never calls SaaS.
|
|
7
|
-
* MCP stdio transport:
|
|
7
|
+
* MCP stdio transport: newline-delimited JSON-RPC 2.0
|
|
8
|
+
* (Content-Length frames are accepted on input).
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
const fs = require('fs')
|
|
@@ -15,11 +16,17 @@ const PROTOCOL_VERSION = '2024-11-05'
|
|
|
15
16
|
const SERVER_NAME = 'fdeops-ingest'
|
|
16
17
|
const SERVER_VERSION = require('./package.json').version
|
|
17
18
|
|
|
19
|
+
const ENGAGEMENT_PROP = {
|
|
20
|
+
type: 'string',
|
|
21
|
+
description:
|
|
22
|
+
'Path to this client\'s .fde/ folder (from `fde resume --bind`). Optional if FDEOPS_ENGAGEMENT is set or the process cwd is already bound.',
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
const TOOLS = [
|
|
19
26
|
{
|
|
20
27
|
name: 'ingest_stage',
|
|
21
28
|
description:
|
|
22
|
-
'Stage raw content into the engagement inbox (.inbox/). Does not write .fde/.',
|
|
29
|
+
'Stage raw content into the engagement inbox (.inbox/). Does not write .fde/. Prefer the fde ingest CLI when the workspace is already bound.',
|
|
23
30
|
inputSchema: {
|
|
24
31
|
type: 'object',
|
|
25
32
|
properties: {
|
|
@@ -29,12 +36,13 @@ const TOOLS = [
|
|
|
29
36
|
},
|
|
30
37
|
source: {
|
|
31
38
|
type: 'string',
|
|
32
|
-
description: 'Provenance label (e.g. granola,
|
|
39
|
+
description: 'Provenance label (e.g. granola, slack, notion, file, manual). Default: manual.',
|
|
33
40
|
},
|
|
34
41
|
title: {
|
|
35
42
|
type: 'string',
|
|
36
43
|
description: 'Optional human-readable title for the staged item.',
|
|
37
44
|
},
|
|
45
|
+
engagement: ENGAGEMENT_PROP,
|
|
38
46
|
},
|
|
39
47
|
required: ['content'],
|
|
40
48
|
},
|
|
@@ -42,7 +50,10 @@ const TOOLS = [
|
|
|
42
50
|
{
|
|
43
51
|
name: 'ingest_list',
|
|
44
52
|
description: 'List staged items in the current engagement inbox.',
|
|
45
|
-
inputSchema: {
|
|
53
|
+
inputSchema: {
|
|
54
|
+
type: 'object',
|
|
55
|
+
properties: { engagement: ENGAGEMENT_PROP },
|
|
56
|
+
},
|
|
46
57
|
},
|
|
47
58
|
{
|
|
48
59
|
name: 'ingest_propose',
|
|
@@ -55,6 +66,7 @@ const TOOLS = [
|
|
|
55
66
|
type: 'string',
|
|
56
67
|
description: 'Staged filename or id from ingest_list.',
|
|
57
68
|
},
|
|
69
|
+
engagement: ENGAGEMENT_PROP,
|
|
58
70
|
},
|
|
59
71
|
required: ['id'],
|
|
60
72
|
},
|
|
@@ -63,7 +75,10 @@ const TOOLS = [
|
|
|
63
75
|
name: 'ingest_apply',
|
|
64
76
|
description:
|
|
65
77
|
'Apply the current debrief proposal into .fde/ memory (requires prior FDE confirm).',
|
|
66
|
-
inputSchema: {
|
|
78
|
+
inputSchema: {
|
|
79
|
+
type: 'object',
|
|
80
|
+
properties: { engagement: ENGAGEMENT_PROP },
|
|
81
|
+
},
|
|
67
82
|
},
|
|
68
83
|
]
|
|
69
84
|
|
|
@@ -128,10 +143,10 @@ function fdeEnv() {
|
|
|
128
143
|
return env
|
|
129
144
|
}
|
|
130
145
|
|
|
131
|
-
function runFde(args, stdin) {
|
|
146
|
+
function runFde(args, stdin, extraEnv) {
|
|
132
147
|
const { cmd, prefix } = resolveFde()
|
|
133
148
|
const result = spawnSync(cmd, [...prefix, ...args], {
|
|
134
|
-
env: fdeEnv(),
|
|
149
|
+
env: { ...fdeEnv(), ...(extraEnv || {}) },
|
|
135
150
|
input: stdin ?? undefined,
|
|
136
151
|
encoding: 'utf8',
|
|
137
152
|
maxBuffer: 16 * 1024 * 1024,
|
|
@@ -144,6 +159,11 @@ function runFde(args, stdin) {
|
|
|
144
159
|
}
|
|
145
160
|
}
|
|
146
161
|
|
|
162
|
+
function engagementEnv(args) {
|
|
163
|
+
const p = args && typeof args.engagement === 'string' ? args.engagement.trim() : ''
|
|
164
|
+
return p ? { FDEOPS_ENGAGEMENT: p } : {}
|
|
165
|
+
}
|
|
166
|
+
|
|
147
167
|
function cliPayload(out) {
|
|
148
168
|
const payload = { stdout: out.stdout, stderr: out.stderr, status: out.status }
|
|
149
169
|
if (out.error) payload.spawnError = out.error
|
|
@@ -163,6 +183,7 @@ function toolError(payload) {
|
|
|
163
183
|
|
|
164
184
|
function handleToolCall(name, args) {
|
|
165
185
|
args = args || {}
|
|
186
|
+
const extraEnv = engagementEnv(args)
|
|
166
187
|
|
|
167
188
|
switch (name) {
|
|
168
189
|
case 'ingest_stage': {
|
|
@@ -172,23 +193,23 @@ function handleToolCall(name, args) {
|
|
|
172
193
|
const source = args.source || 'manual'
|
|
173
194
|
const cliArgs = ['ingest', 'stage', '--source', source]
|
|
174
195
|
if (args.title) cliArgs.push('--title', args.title)
|
|
175
|
-
const out = runFde(cliArgs, args.content)
|
|
196
|
+
const out = runFde(cliArgs, args.content, extraEnv)
|
|
176
197
|
const payload = cliPayload(out)
|
|
177
198
|
return out.status === 0 ? toolResult(payload) : toolError(payload)
|
|
178
199
|
}
|
|
179
200
|
case 'ingest_list': {
|
|
180
|
-
const out = runFde(['ingest', 'list'])
|
|
201
|
+
const out = runFde(['ingest', 'list'], undefined, extraEnv)
|
|
181
202
|
const payload = cliPayload(out)
|
|
182
203
|
return out.status === 0 ? toolResult(payload) : toolError(payload)
|
|
183
204
|
}
|
|
184
205
|
case 'ingest_propose': {
|
|
185
206
|
if (!args.id) return toolError('Missing required argument: id')
|
|
186
|
-
const out = runFde(['ingest', 'propose', String(args.id)])
|
|
207
|
+
const out = runFde(['ingest', 'propose', String(args.id)], undefined, extraEnv)
|
|
187
208
|
const payload = cliPayload(out)
|
|
188
209
|
return out.status === 0 ? toolResult(payload) : toolError(payload)
|
|
189
210
|
}
|
|
190
211
|
case 'ingest_apply': {
|
|
191
|
-
const out = runFde(['ingest', 'apply'])
|
|
212
|
+
const out = runFde(['ingest', 'apply'], undefined, extraEnv)
|
|
192
213
|
const payload = cliPayload(out)
|
|
193
214
|
return out.status === 0 ? toolResult(payload) : toolError(payload)
|
|
194
215
|
}
|
package/mcp/recipes/README.md
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# Ingest source recipes
|
|
2
2
|
|
|
3
|
-
FDEOps does **not** bundle Granola /
|
|
3
|
+
FDEOps does **not** bundle Granola / Slack / Notion OAuth and does **not** push to those tools.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Daily (no MCP):** paste notes to `@fde debrief`, or drop a file ([file.md](./file.md)).
|
|
6
|
+
|
|
7
|
+
**Pull (optional):** you add a **source** MCP. The agent fetches text, then runs `fde ingest` in this bound workspace (stage → propose → you confirm → apply). The `fdeops-ingest` MCP is optional — only if you are not using the CLI from a bound workspace.
|
|
6
8
|
|
|
7
9
|
| Recipe | When |
|
|
8
10
|
|--------|------|
|
|
9
|
-
| [file.md](./file.md) |
|
|
10
|
-
| [granola.md](./granola.md) | Meeting transcripts via a
|
|
11
|
-
| [
|
|
12
|
-
|
|
13
|
-
Also wire the sink once: [fdeops-ingest/README.md](../fdeops-ingest/README.md).
|
|
11
|
+
| [file.md](./file.md) | Transcript / export already on disk, or paste |
|
|
12
|
+
| [granola.md](./granola.md) | Meeting transcripts via a notes MCP (or export) |
|
|
13
|
+
| [slack.md](./slack.md) | Pull a thread/channel as text — never post |
|
|
14
|
+
| [notion.md](./notion.md) | Read a Notion page (or export markdown) |
|
|
14
15
|
|
|
15
|
-
**Natural language:** `@fde I want to connect Granola`
|
|
16
|
+
**Natural language:** `@fde I want to connect Granola` (or Slack / Notion) → `skills/fde/references/ingest-connect.md`.
|
package/mcp/recipes/file.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Recipe: local file / paste (no source MCP)
|
|
2
2
|
|
|
3
|
-
**Use when:** you already have a transcript, `.eml`, or export on disk — or you paste into chat.
|
|
3
|
+
**Use when:** you already have a transcript, `.eml`, or export on disk — or you paste into chat. This is the default FDE path.
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
7
|
-
None
|
|
7
|
+
None. Bound workspace + `fde ingest` (or `@fde debrief` for short notes).
|
|
8
8
|
|
|
9
9
|
## Pull phrase
|
|
10
10
|
|
|
@@ -12,14 +12,14 @@ None beyond the FDEOps sink (`fde` CLI and optionally `fdeops-ingest` MCP).
|
|
|
12
12
|
@fde stage this transcript into the fieldbook and propose updates
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
(or attach / point at a path)
|
|
15
|
+
(or attach / point at a path, or paste and say debrief)
|
|
16
16
|
|
|
17
17
|
## Agent steps
|
|
18
18
|
|
|
19
|
-
1. Bind engagement.
|
|
20
|
-
2. `fde ingest stage --source file --title "<short>" <path
|
|
21
|
-
3.
|
|
19
|
+
1. Bind engagement (`fde resume`).
|
|
20
|
+
2. Short paste → debrief verb. Long file → `fde ingest stage --source file --title "<short>" <path>`.
|
|
21
|
+
3. Propose → rewrite prefixes → show FDE → on confirm apply.
|
|
22
22
|
|
|
23
23
|
## mcp.json
|
|
24
24
|
|
|
25
|
-
Not required
|
|
25
|
+
Not required.
|
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fdeops",
|
|
3
|
-
"version": "3.10.
|
|
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",
|
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.10.
|
|
4
|
+
"version": "3.10.2",
|
|
5
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
6
|
"author": {
|
|
7
7
|
"name": "Subash Natarajan",
|
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` |
|
|
@@ -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`).
|