@oxygen-agent/cli 1.888.6 → 1.894.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/command-manifest.js +11 -1
- package/dist/index.js +276 -16
- package/node_modules/@oxygen/shared/dist/billing.d.ts +3 -3
- package/node_modules/@oxygen/shared/dist/billing.js +2 -2
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +3 -3
- package/node_modules/@oxygen/shared/dist/feature-gates.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/feature-gates.js +6 -0
- package/node_modules/@oxygen/shared/dist/index.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/index.js +1 -0
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +255 -0
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.js +238 -0
- package/node_modules/@oxygen/shared/dist/knowledge-constants.d.ts +3 -0
- package/node_modules/@oxygen/shared/dist/knowledge-constants.js +19 -0
- package/node_modules/@oxygen/shared/dist/knowledge-seed-content.d.ts +23 -6
- package/node_modules/@oxygen/shared/dist/knowledge-seed-content.js +438 -29
- package/node_modules/@oxygen/shared/dist/sending-seats.d.ts +31 -8
- package/node_modules/@oxygen/shared/dist/sending-seats.js +19 -15
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Knowledge Graph starter pack (the Karpathy LLM-wiki scaffold). A fresh workspace
|
|
2
|
-
// self-seeds this page set
|
|
3
|
-
// arrives alive: two active nav pages ([[start-here]] + the
|
|
4
|
-
// and
|
|
5
|
-
// grounding any AI copy until a human fills them.
|
|
2
|
+
// self-seeds this page set at tenant provisioning / first onboarding / `oxygen knowledge
|
|
3
|
+
// seed`, so the wiki arrives alive: two active nav pages ([[start-here]] + the
|
|
4
|
+
// [[conventions]] schema page) and nineteen draft stub hubs that show the shape of a
|
|
5
|
+
// healthy second brain without grounding any AI copy until a human fills them.
|
|
6
6
|
//
|
|
7
7
|
// The seeder (tenant-db `ensureKnowledgeScaffold`) is purely additive and version-gated:
|
|
8
8
|
// it creates a page only when its slug is free (never overwriting a user's edits) and
|
|
@@ -10,9 +10,33 @@
|
|
|
10
10
|
// and add pages with a higher `minScaffoldVersion` to ship a new wave; existing pages are
|
|
11
11
|
// never rewritten by the scaffold. Bodies are the single source of truth for the starter
|
|
12
12
|
// content — keep them dense and wikilinked.
|
|
13
|
+
//
|
|
14
|
+
// BINDING RULE — a scaffold wave adds ZERO active pages. Every content page ships
|
|
15
|
+
// `status: "draft"` with `seed` in its tags; only the two nav pages are active, and they
|
|
16
|
+
// are written full rather than as stubs. `retrieveWorkspaceKnowledge` selects on
|
|
17
|
+
// `status = 'active'` with MIN_BODY_CHARS = 80, so an ACTIVE stub is grounding material:
|
|
18
|
+
// "Stub — fill me. ## Firmographics —" would be injected verbatim into a customer's cold
|
|
19
|
+
// email as company knowledge. Promoting a stub to active is the user's act, never the
|
|
20
|
+
// scaffold's.
|
|
21
|
+
//
|
|
22
|
+
// NEVER SEED `outreach-learnings`, `won-lost-learnings`, or `meeting-learnings`. tenant-db
|
|
23
|
+
// `ensureLearningsPage` get-or-creates them as `active` on the first reply, deal, or
|
|
24
|
+
// meeting and returns an existing row UNTOUCHED — seeding them as draft stubs would pin
|
|
25
|
+
// them draft forever and silently break the learning loop's read half. They stay dashed
|
|
26
|
+
// unresolved links in [[campaign-learnings]] until the loop creates them for real.
|
|
13
27
|
/** Monotonic scaffold cursor stored in knowledge_state.scaffold_version. Bump to ship a
|
|
14
|
-
* new wave of starter pages (tag them with a higher minScaffoldVersion).
|
|
15
|
-
|
|
28
|
+
* new wave of starter pages (tag them with a higher minScaffoldVersion).
|
|
29
|
+
* v1: the 9-page core. v2: twelve GTM stubs (voice/brand/messaging/objections, three
|
|
30
|
+
* motion playbooks + qualification, and the personas/customers/research/metrics hubs). */
|
|
31
|
+
// KNOWN LIMITATION of a create-only seeder, accepted deliberately: on a workspace
|
|
32
|
+
// UPGRADED from an earlier wave, the new pages get no inbound links, because the hub that
|
|
33
|
+
// would link them (start-here) already exists and the scaffold never rewrites an existing
|
|
34
|
+
// page. Those pages are reachable through `knowledge index`, search and the graph, and
|
|
35
|
+
// `knowledge lint` excludes unfilled stubs from `orphans` so they are not reported as
|
|
36
|
+
// unfixable noise. Do NOT "fix" this by having the seeder patch existing bodies —
|
|
37
|
+
// never-overwrite is the entire safety property of this mechanism, and trading it for a
|
|
38
|
+
// tidier link graph on upgraded workspaces is a bad trade.
|
|
39
|
+
export const KNOWLEDGE_SCAFFOLD_VERSION = 2;
|
|
16
40
|
const START_HERE_BODY = `# Start here
|
|
17
41
|
|
|
18
42
|
This is the workspace's knowledge wiki — one shared, compounding second brain for every human and every AI agent here. It replaces scattered Notion docs, chat history, and one-off prompts.
|
|
@@ -24,13 +48,11 @@ This is the workspace's knowledge wiki — one shared, compounding second brain
|
|
|
24
48
|
- **Trust travels.** Every claim cites its source. Canonical live copy (voice / brand / [[positioning]]) is human-approved; everything else auto-writes as revertible revisions. See [[conventions]].
|
|
25
49
|
|
|
26
50
|
## Hubs
|
|
27
|
-
- [[icp]]
|
|
28
|
-
- [[positioning]]
|
|
29
|
-
- [[offers]]
|
|
30
|
-
- [[
|
|
31
|
-
- [[
|
|
32
|
-
- [[campaign-learnings]] — what outreach and meetings taught us
|
|
33
|
-
- [[decisions]] — standing GTM decisions and what would reverse them
|
|
51
|
+
- **Who we sell to** — [[icp]] accounts · [[personas]] buyers · [[customers]] who bought and why
|
|
52
|
+
- **What we say** — [[positioning]] vs. alternatives · [[voice]] how we sound · [[brand]] the promise and the provable claims · [[messaging]] hooks by persona · [[objections]] pushback and our answers
|
|
53
|
+
- **What we sell** — [[offers]] packages and prices · [[competitors]] teardowns
|
|
54
|
+
- **How we run it** — [[playbooks]] one page per motion · [[qualification]] the fit gate
|
|
55
|
+
- **What we learned** — [[campaign-learnings]] outcomes · [[metrics]] the numbers and their definitions · [[research]] dated investigations · [[decisions]] standing calls and what reverses them
|
|
34
56
|
|
|
35
57
|
## Seeing the shape
|
|
36
58
|
\`oxygen knowledge graph\` (or the web graph) shows hubs, orphans, and dashed unresolved links — the gaps worth filling next. \`oxygen knowledge lint\` is the health report.
|
|
@@ -62,10 +84,10 @@ Index-first → open only relevant pages → answer citing slugs → file durabl
|
|
|
62
84
|
| \`schema\` | describes the wiki itself (this page) |
|
|
63
85
|
|
|
64
86
|
## Slugs
|
|
65
|
-
Flat kebab: lowercase alphanumerics + dashes, no slashes, ≤120 chars. **Immutable once created** — choose the durable name (\`competitor-clay\`, not \`clay-notes-july\`). No folders; types, tags, and
|
|
87
|
+
Flat kebab: lowercase alphanumerics + dashes, no slashes, ≤120 chars. **Immutable once created** — choose the durable name (\`competitor-clay\`, not \`clay-notes-july\`). No folders; types, tags, and wikilinks organize. Reserved (never create): \`index\`, \`log\`, \`schema\`, \`company-profile\`, \`readme\`.
|
|
66
88
|
|
|
67
89
|
## Wikilinks
|
|
68
|
-
\`
|
|
90
|
+
Wrap a slug in double square brackets to link it. Three forms all resolve to the same page — bare (\`slug\`), aliased (\`slug|display text\`), and heading-anchored (\`slug#heading\`) — because the alias and the heading are stripped before lookup. **Linking to a page that doesn't exist yet is good** — the dashed node is a visible to-do. Every page should link out (avoid dead-ends) and be linked to (avoid orphans).
|
|
69
91
|
|
|
70
92
|
## New page vs. edit
|
|
71
93
|
New page when it's a distinct entity/concept you'd link to from elsewhere. Edit in place when it's an attribute or update of an existing page. Search first (\`oxygen knowledge search\`) — near-duplicate slugs rot the graph.
|
|
@@ -87,14 +109,14 @@ Prune agent-derived claims once a human verifies the same fact. A contested clai
|
|
|
87
109
|
Record standing calls in [[decisions]] using the template there. Every decision needs a rationale AND a \`## Reversal condition\` — the observable evidence that would flip it — so agents can flag when new data contradicts a standing decision.
|
|
88
110
|
|
|
89
111
|
## Stub-fill contract
|
|
90
|
-
Seeded stubs (tag \`seed\`, still at revision 1, \`status: draft\`) are scaffolding. Replace the body with real cited content, keep the
|
|
112
|
+
Seeded stubs (tag \`seed\`, still at revision 1, \`status: draft\`) are scaffolding. Replace the body with real cited content, keep the wikilinks, set \`status: active\`. **No approval needed.** Until filled they stay draft and never ground AI copy. \`oxygen knowledge lint\` lists unfilled stubs.
|
|
91
113
|
|
|
92
114
|
## Lint discipline
|
|
93
|
-
Run \`oxygen knowledge lint\` regularly
|
|
115
|
+
Run \`oxygen knowledge lint\` regularly — it is the health report, and it names its own categories, so read its output rather than a list here. Three worth knowing by name: **contradictions** (a page tagged \`disputed\` is silently excluded from every AI answer; \`disputed\` + \`verified\` together is a trust conflict; two active pages of the same live-copy type compete inside one prompt), **unfilled stubs** (ranked by how many pages already link to them — fill those first), and **stale** (untouched for 90 days, or *superseded*: sources filed onto the page after its last edit, which on a learnings page means \`oxygen knowledge synthesize\` is overdue, not that anything broke). \`oxygen knowledge lint relink\` rebuilds edges after bulk edits.
|
|
94
116
|
`;
|
|
95
117
|
const ICP_BODY = `# ICP — ideal customer profile
|
|
96
118
|
|
|
97
|
-
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the
|
|
119
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
98
120
|
|
|
99
121
|
## Firmographics
|
|
100
122
|
- Company type / size / stage:
|
|
@@ -108,7 +130,7 @@ const ICP_BODY = `# ICP — ideal customer profile
|
|
|
108
130
|
- Who we should NOT pursue and why:
|
|
109
131
|
|
|
110
132
|
## Buyer personas
|
|
111
|
-
-
|
|
133
|
+
- The buyers inside a fit account live in [[personas]] — one \`persona\` page each (economic buyer, champion, user).
|
|
112
134
|
|
|
113
135
|
## Basis
|
|
114
136
|
- Cite the deals, calls, or market data this is drawn from. Contradicting evidence should route through [[campaign-learnings]] and update [[positioning]].
|
|
@@ -134,7 +156,7 @@ const POSITIONING_BODY = `# Positioning
|
|
|
134
156
|
`;
|
|
135
157
|
const OFFERS_BODY = `# Offers
|
|
136
158
|
|
|
137
|
-
> **Stub — fill me.** Seeded scaffolding — fill, keep
|
|
159
|
+
> **Stub — fill me.** Seeded scaffolding — fill, keep the wikilinks, set \`status: active\`. See [[conventions]].
|
|
138
160
|
|
|
139
161
|
## Offers
|
|
140
162
|
For each: name, who it's for ([[icp]]), price/packaging, the outcome it delivers, and qualifying criteria.
|
|
@@ -147,11 +169,10 @@ Tie each offer to the value in [[positioning]] and the motions in [[playbooks]].
|
|
|
147
169
|
`;
|
|
148
170
|
const COMPETITORS_BODY = `# Competitors (map of content)
|
|
149
171
|
|
|
150
|
-
> **Stub — fill me.** This is a hub. Create one \`competitor\` page per rival
|
|
172
|
+
> **Stub — fill me.** This is a hub. Create one \`competitor\` page per rival — durable slugs like \`competitor-clay\`, \`competitor-apollo\` — wikilink each one here, then fill this overview. See [[conventions]].
|
|
151
173
|
|
|
152
174
|
## Landscape
|
|
153
|
-
- One line per competitor
|
|
154
|
-
- [[competitor-example]] — replace with real teardowns.
|
|
175
|
+
- One line per competitor, wikilinked to its own teardown page. Replace this line with the real ones.
|
|
155
176
|
|
|
156
177
|
## Our stance
|
|
157
178
|
- Where we consistently win / lose (draw from [[positioning]] and [[campaign-learnings]]).
|
|
@@ -162,6 +183,7 @@ const PLAYBOOKS_BODY = `# Playbooks (map of content)
|
|
|
162
183
|
|
|
163
184
|
## Motions
|
|
164
185
|
- [[playbook-outbound]] — cold outbound
|
|
186
|
+
- [[playbook-inbound]] — inbound, referrals, and self-serve signups
|
|
165
187
|
- [[playbook-nurture]] — nurture / re-engagement
|
|
166
188
|
- (add: demo, onboarding, expansion)
|
|
167
189
|
|
|
@@ -178,6 +200,8 @@ Learning-worthy outcomes auto-file as **immutable sources** (facts, no approval)
|
|
|
178
200
|
- completed meetings + notes → [[meeting-learnings]]
|
|
179
201
|
- A/B auto-winners and human edits to AI drafts → the relevant learnings page
|
|
180
202
|
|
|
203
|
+
Those three pages do not exist yet — the first reply, closed deal, or completed meeting creates each one automatically, which is why they show as dashed unresolved links until then.
|
|
204
|
+
|
|
181
205
|
## Distill
|
|
182
206
|
\`oxygen knowledge synthesize\` (and the opt-in scheduled agent) turns accumulated sources into learnings-page revisions — with citations and a "what would change our mind" line per recommendation. Retrieval then grounds the NEXT campaign's drafts on them.
|
|
183
207
|
|
|
@@ -201,11 +225,258 @@ The observable evidence that would flip this decision.
|
|
|
201
225
|
|
|
202
226
|
Every decision MUST have a \`## Reversal condition\` — \`oxygen knowledge lint\` flags decision pages that lack one. Record the call in the log too: \`oxygen knowledge log append --event decision --slug <page> --summary "<what/why>"\`.
|
|
203
227
|
`;
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
// Scaffold v2 — twelve GTM stubs. All draft + `seed`-tagged (see the binding rule
|
|
230
|
+
// at the top of this file). Every body opens with the same stub contract line and
|
|
231
|
+
// links out to at least one other page, so the wave adds no dead-ends.
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
const VOICE_BODY = `# Voice
|
|
234
|
+
|
|
235
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
236
|
+
|
|
237
|
+
## Register
|
|
238
|
+
- Speaker (founder / team / product) and audience:
|
|
239
|
+
- Contractions, humour, emoji — allowed or never:
|
|
240
|
+
- One idea per sentence. Hard word cap:
|
|
241
|
+
|
|
242
|
+
## Words
|
|
243
|
+
| Use | Avoid |
|
|
244
|
+
|---|---|
|
|
245
|
+
| (our word for the problem) | (the jargon it replaces) |
|
|
246
|
+
|
|
247
|
+
Banned hedges: just, hope this finds you well, wanted to reach out, circling back, solution, leverage.
|
|
248
|
+
|
|
249
|
+
## Worked examples
|
|
250
|
+
- **We would send:** one real sentence of ours
|
|
251
|
+
- **We would not send:** the same idea, wrong — and why it fails
|
|
252
|
+
|
|
253
|
+
## Canonical
|
|
254
|
+
Not pinned. Pinning it (\`oxygen knowledge page pin voice --approved\`) is a human-approved act — canonical voice grounds live copy. Claims are [[brand]]; what we do is [[positioning]].
|
|
255
|
+
`;
|
|
256
|
+
const BRAND_BODY = `# Brand
|
|
257
|
+
|
|
258
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
259
|
+
|
|
260
|
+
## The promise (one line)
|
|
261
|
+
What a buyer gets from us and cannot get from the alternative named in [[positioning]]:
|
|
262
|
+
|
|
263
|
+
## Claims
|
|
264
|
+
| We can substantiate | Proof (number, customer, doc) |
|
|
265
|
+
|---|---|
|
|
266
|
+
| 1 | |
|
|
267
|
+
| 2 | |
|
|
268
|
+
| 3 | |
|
|
269
|
+
|
|
270
|
+
Cannot substantiate yet — never write these until the proof is real: 1. 2. 3.
|
|
271
|
+
|
|
272
|
+
## The ask (CTA ladder)
|
|
273
|
+
Smallest commitment first: reply → short call → pilot → paid. Never skip a rung on a first touch. Per-persona wording is [[messaging]]; what is actually sold is [[offers]].
|
|
274
|
+
|
|
275
|
+
## Naming
|
|
276
|
+
Exact spelling and capitalisation of the company, the product, and each feature; one word or two; what we never call ourselves or the category. How it all sounds is [[voice]].
|
|
277
|
+
`;
|
|
278
|
+
const MESSAGING_BODY = `# Messaging playbook
|
|
279
|
+
|
|
280
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
281
|
+
|
|
282
|
+
Once active this page grounds outbound and reply drafts — every line here becomes copy a prospect reads.
|
|
283
|
+
|
|
284
|
+
## Hooks by persona
|
|
285
|
+
| Persona | Trigger (why now) | Opening line, in their words |
|
|
286
|
+
|---|---|---|
|
|
287
|
+
| (one row per page in [[personas]]) | | |
|
|
288
|
+
|
|
289
|
+
## Proof points — numbers only
|
|
290
|
+
| Claim | Number | Source |
|
|
291
|
+
|---|---|---|
|
|
292
|
+
|
|
293
|
+
No number, no claim. Pull them from closed deals and [[campaign-learnings]].
|
|
294
|
+
|
|
295
|
+
## CTA ladder (soft to hard)
|
|
296
|
+
One-word reply → send the teardown → fifteen minutes → pilot.
|
|
297
|
+
|
|
298
|
+
## What we never say
|
|
299
|
+
The banned hedges in [[voice]]; anything absent from the proof table in [[brand]]; a competitor smear — counter with [[positioning]].
|
|
300
|
+
`;
|
|
301
|
+
const OBJECTIONS_BODY = `# Objections
|
|
302
|
+
|
|
303
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
304
|
+
|
|
305
|
+
## Handling
|
|
306
|
+
| Objection | Really asking | Our answer | Proof | Walk when |
|
|
307
|
+
|---|---|---|---|---|
|
|
308
|
+
| Too expensive | Is the outcome worth it? | | | |
|
|
309
|
+
| We use (rival) | What breaks if we switch? | see [[competitors]] | | |
|
|
310
|
+
| Not now | Is there a trigger? | | | no trigger named twice |
|
|
311
|
+
| Must ask someone | Who decides? | | | buyer absent twice |
|
|
312
|
+
|
|
313
|
+
## Rules
|
|
314
|
+
One rebuttal, then a question — never two. Answer price with the outcome in [[offers]], not a discount. Never claim more about a rival than [[competitors]] proves.
|
|
315
|
+
|
|
316
|
+
## When to walk
|
|
317
|
+
The hard-no list is [[icp]], the fit gate [[qualification]] — a stall matching one is a no, not a nurture. Feed the pattern to [[positioning]].
|
|
318
|
+
`;
|
|
319
|
+
const PLAYBOOK_OUTBOUND_BODY = `# Outbound playbook
|
|
320
|
+
|
|
321
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
322
|
+
|
|
323
|
+
## Target and list
|
|
324
|
+
- Slice of [[icp]] this motion works (narrower than all of it):
|
|
325
|
+
- List source, and the filter that decides who is in:
|
|
326
|
+
- Offer we lead with, from [[offers]]:
|
|
327
|
+
|
|
328
|
+
## Cadence
|
|
329
|
+
| Step | Day | Channel | Angle from [[messaging]] |
|
|
330
|
+
|---|---|---|---|
|
|
331
|
+
| 1 | 0 | | |
|
|
332
|
+
| 2 | | | |
|
|
333
|
+
|
|
334
|
+
Daily volume per sender:
|
|
335
|
+
|
|
336
|
+
## Never enroll
|
|
337
|
+
Customers, open opportunities, anyone touched in the last N days, opt-outs, competitors.
|
|
338
|
+
|
|
339
|
+
## Is it working
|
|
340
|
+
Reply rate, positive-reply rate, meetings per 1,000 sent — set a target for each. Outcomes land in [[campaign-learnings]].
|
|
341
|
+
|
|
342
|
+
## Exits
|
|
343
|
+
Positive reply → [[qualification]]. Silent at the last step → [[playbook-nurture]]. Hard no → suppress.
|
|
344
|
+
`;
|
|
345
|
+
const PLAYBOOK_NURTURE_BODY = `# Nurture playbook
|
|
346
|
+
|
|
347
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
348
|
+
|
|
349
|
+
## Who enters the not-now pile
|
|
350
|
+
- Not-now replies, stalled deals, no-shows, churned accounts, and still-fit [[icp]] leads who finished [[playbook-outbound]] silent.
|
|
351
|
+
- Who never enters: a hard no, an opt-out, anyone out of ICP.
|
|
352
|
+
|
|
353
|
+
## Cadence
|
|
354
|
+
| Touch | Timing | What we send |
|
|
355
|
+
|---|---|---|
|
|
356
|
+
| 1 | | |
|
|
357
|
+
| 2 | | |
|
|
358
|
+
|
|
359
|
+
One touch per N weeks, no sequence pressure. Angles come from [[messaging]]; anything quoting an [[offers]] price must still be true when it lands.
|
|
360
|
+
|
|
361
|
+
## Exit
|
|
362
|
+
A reply or a live trigger → [[qualification]]. Two full cycles with zero engagement → drop them, and log why in [[campaign-learnings]].
|
|
363
|
+
`;
|
|
364
|
+
const PLAYBOOK_INBOUND_BODY = `# Inbound playbook
|
|
365
|
+
|
|
366
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
367
|
+
|
|
368
|
+
## Sources
|
|
369
|
+
| Source | Where it lands | Owner |
|
|
370
|
+
|---|---|---|
|
|
371
|
+
| Content / SEO | | |
|
|
372
|
+
| LinkedIn engagement | | |
|
|
373
|
+
| Product signups | | |
|
|
374
|
+
| Referrals | | |
|
|
375
|
+
|
|
376
|
+
## Response SLA
|
|
377
|
+
Business hours, and off hours. Speed is the whole edge here — name the slowest reply we accept, then hold it.
|
|
378
|
+
|
|
379
|
+
## First touch
|
|
380
|
+
- Match the person to a page in [[personas]] and answer in their language ([[messaging]]). Never a generic template.
|
|
381
|
+
- The one question worth asking first:
|
|
382
|
+
|
|
383
|
+
## Routing
|
|
384
|
+
Run [[qualification]] before booking anything. Self-serve signups go to their own path. Anyone outside [[icp]] gets the honest no, fast.
|
|
385
|
+
`;
|
|
386
|
+
const QUALIFICATION_BODY = `# Qualification
|
|
387
|
+
|
|
388
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
389
|
+
|
|
390
|
+
## Five discovery questions
|
|
391
|
+
Each one surfaces a pain, its cost, or the buying process — never a feature preference.
|
|
392
|
+
1.
|
|
393
|
+
2.
|
|
394
|
+
3.
|
|
395
|
+
4.
|
|
396
|
+
5.
|
|
397
|
+
|
|
398
|
+
## Must be true to advance
|
|
399
|
+
- A named pain one of our [[offers]] actually removes:
|
|
400
|
+
- Someone in the room who can spend:
|
|
401
|
+
- A date they want it working by:
|
|
402
|
+
|
|
403
|
+
## Disqualifiers
|
|
404
|
+
The hard-no list is [[icp]] — do not copy it here. Add only what shows up on a call and ICP cannot see: no budget owner, no timeline, or a blocker we cannot move (see [[objections]]).
|
|
405
|
+
|
|
406
|
+
## What counts as a next step
|
|
407
|
+
A booked meeting with a named person and a date on it. Not "send me info", not "circle back in Q3".
|
|
408
|
+
`;
|
|
409
|
+
const PERSONAS_BODY = `# Personas (map of content)
|
|
410
|
+
|
|
411
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
412
|
+
|
|
413
|
+
## Roster
|
|
414
|
+
| Persona | Job to be done | Pain that costs them money | Trigger to buy now | Where they spend time |
|
|
415
|
+
|---|---|---|---|---|
|
|
416
|
+
| | | | | |
|
|
417
|
+
|
|
418
|
+
Create one page per buyer as type \`persona\` — slugs like \`persona-vp-sales\`, \`persona-founder\` — and link it in the first column. Cover the economic buyer, the champion, and whoever blocks the deal.
|
|
419
|
+
|
|
420
|
+
## Rules
|
|
421
|
+
- Split a persona only when the pain or the trigger differs. Same pain, different title is one persona.
|
|
422
|
+
- Quote their words verbatim; those quotes become the hooks in [[messaging]].
|
|
423
|
+
- What they push back on belongs in [[objections]], not here.
|
|
424
|
+
|
|
425
|
+
Personas sit inside the account-level fit defined in [[icp]].
|
|
426
|
+
`;
|
|
427
|
+
const CUSTOMERS_BODY = `# Customers (map of content)
|
|
428
|
+
|
|
429
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
430
|
+
|
|
431
|
+
## Roster
|
|
432
|
+
| Customer | Offer bought | Why they bought | Outcome number | Referenceable? |
|
|
433
|
+
|---|---|---|---|---|
|
|
434
|
+
| | | | | |
|
|
435
|
+
|
|
436
|
+
Create one page per customer as type \`entity\`, slugged with the company name, and wikilink it in the first column. Keep it to the deal story: what broke before, what they compared us to, what changed after.
|
|
437
|
+
|
|
438
|
+
## Scope
|
|
439
|
+
Live account state — plan, seats, renewal, open tickets — is cheaper to re-fetch than to mirror, so it stays out (the density bar in [[conventions]]). This page holds only the durable narrative no query can rebuild.
|
|
440
|
+
|
|
441
|
+
Patterns here sharpen [[icp]], prove [[offers]], and supply the proof lines in [[messaging]].
|
|
442
|
+
`;
|
|
443
|
+
const RESEARCH_BODY = `# Research (map of content)
|
|
444
|
+
|
|
445
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
446
|
+
|
|
447
|
+
## What lands here
|
|
448
|
+
Dated investigations as type \`research_note\`, slugged \`research-2026-03-pricing\`. Link each below, newest first. Agent-derived notes land here too, tagged \`agent-derived\` until verified.
|
|
449
|
+
|
|
450
|
+
Hub vs. note: a hub like [[icp]] or [[competitors]] holds the standing answer and is rewritten. A note is dated evidence, never rewritten — when it moves that answer, edit the hub and cite the note.
|
|
451
|
+
|
|
452
|
+
## Note template
|
|
453
|
+
- **Question** — the one thing this note answers
|
|
454
|
+
- **Method** — what was searched, asked, or measured, over how many
|
|
455
|
+
- **Findings** — each with the URL or call it came from
|
|
456
|
+
- **What would change our mind** — evidence that would invalidate it
|
|
457
|
+
`;
|
|
458
|
+
const METRICS_BODY = `# Metrics
|
|
459
|
+
|
|
460
|
+
> **Stub — fill me.** Seeded scaffolding. Replace with real, cited content, keep the wikilinks, then set \`status: active\`. No approval needed. Draft stubs do not ground AI copy. How-to: [[conventions]].
|
|
461
|
+
|
|
462
|
+
## The five numbers we steer by
|
|
463
|
+
| Metric | How we define it exactly | Current target | Where the live number lives |
|
|
464
|
+
|---|---|---|---|
|
|
465
|
+
| | | | |
|
|
466
|
+
|
|
467
|
+
Five, not fifteen. A number that would not change a decision this quarter is not one of them.
|
|
468
|
+
|
|
469
|
+
## Do not paste live values here
|
|
470
|
+
This page holds definitions and targets — argued over once, then reused. The values live in Dashboards, which are always current; a pasted number is stale the next day, and the density bar in [[conventions]] rules out mirroring anything cheaper to re-fetch.
|
|
471
|
+
|
|
472
|
+
Moving a target is a call: record it in [[decisions]] with its reversal condition. Why it moved is evidence: that goes to [[campaign-learnings]].
|
|
473
|
+
`;
|
|
204
474
|
/**
|
|
205
|
-
* The
|
|
206
|
-
* page), then
|
|
207
|
-
*
|
|
208
|
-
*
|
|
475
|
+
* The 21-page starter pack. Two active nav pages first (start-here + the conventions
|
|
476
|
+
* schema page), then nineteen draft stub hubs (tag `seed`) — seven from wave 1 and
|
|
477
|
+
* twelve from wave 2. `positioning` seeds as a NON-canonical draft so it writes freely;
|
|
478
|
+
* pinning canonical positioning stays a separate human-approved act. Wave 2 adds ZERO
|
|
479
|
+
* active pages, per the binding rule at the top of this file.
|
|
209
480
|
*/
|
|
210
481
|
export const KNOWLEDGE_SEED_PAGES = [
|
|
211
482
|
{
|
|
@@ -237,6 +508,7 @@ export const KNOWLEDGE_SEED_PAGES = [
|
|
|
237
508
|
summary: "Stub: the ideal customer profile — firmographics, triggers, and disqualifiers that define who we sell to. Fill with cited content and set active.",
|
|
238
509
|
body: ICP_BODY,
|
|
239
510
|
minScaffoldVersion: 1,
|
|
511
|
+
researchable: true,
|
|
240
512
|
},
|
|
241
513
|
{
|
|
242
514
|
slug: "positioning",
|
|
@@ -247,6 +519,7 @@ export const KNOWLEDGE_SEED_PAGES = [
|
|
|
247
519
|
summary: "Stub (non-canonical): how we describe ourselves against alternatives — for whom, the core value, and proof. Pinning the canonical positioning is a separate human-approved act.",
|
|
248
520
|
body: POSITIONING_BODY,
|
|
249
521
|
minScaffoldVersion: 1,
|
|
522
|
+
researchable: true,
|
|
250
523
|
},
|
|
251
524
|
{
|
|
252
525
|
slug: "offers",
|
|
@@ -257,6 +530,7 @@ export const KNOWLEDGE_SEED_PAGES = [
|
|
|
257
530
|
summary: "Stub: what we sell — packages, pricing, and the qualifying criteria per offer. Fill with cited content and set active.",
|
|
258
531
|
body: OFFERS_BODY,
|
|
259
532
|
minScaffoldVersion: 1,
|
|
533
|
+
researchable: true,
|
|
260
534
|
},
|
|
261
535
|
{
|
|
262
536
|
slug: "competitors",
|
|
@@ -264,9 +538,10 @@ export const KNOWLEDGE_SEED_PAGES = [
|
|
|
264
538
|
title: "Competitors (map of content)",
|
|
265
539
|
status: "draft",
|
|
266
540
|
tags: ["seed", "moc", "competitors"],
|
|
267
|
-
summary: "Stub map-of-content: index of competitor teardown pages. Create one
|
|
541
|
+
summary: "Stub map-of-content: index of competitor teardown pages. Create one competitor-<name> page each; this hub links them and summarizes our overall competitive stance.",
|
|
268
542
|
body: COMPETITORS_BODY,
|
|
269
543
|
minScaffoldVersion: 1,
|
|
544
|
+
researchable: true,
|
|
270
545
|
},
|
|
271
546
|
{
|
|
272
547
|
slug: "playbooks",
|
|
@@ -274,7 +549,7 @@ export const KNOWLEDGE_SEED_PAGES = [
|
|
|
274
549
|
title: "Playbooks (map of content)",
|
|
275
550
|
status: "draft",
|
|
276
551
|
tags: ["seed", "moc", "playbooks"],
|
|
277
|
-
summary: "Stub map-of-content: index of how-we-run-it playbooks (outbound, nurture, demo, expansion). Create one playbook page per motion and link it here.",
|
|
552
|
+
summary: "Stub map-of-content: index of how-we-run-it playbooks (outbound, inbound, nurture, demo, expansion). Create one playbook page per motion and link it here.",
|
|
278
553
|
body: PLAYBOOKS_BODY,
|
|
279
554
|
minScaffoldVersion: 1,
|
|
280
555
|
},
|
|
@@ -298,4 +573,138 @@ export const KNOWLEDGE_SEED_PAGES = [
|
|
|
298
573
|
body: DECISIONS_BODY,
|
|
299
574
|
minScaffoldVersion: 1,
|
|
300
575
|
},
|
|
576
|
+
{
|
|
577
|
+
slug: "voice",
|
|
578
|
+
type: "voice",
|
|
579
|
+
title: "Voice",
|
|
580
|
+
status: "draft",
|
|
581
|
+
tags: ["seed", "voice", "copy"],
|
|
582
|
+
summary: "Stub (non-canonical): how the workspace sounds — register and audience, the one-idea-per-sentence rule, words to use and avoid, banned hedges, and a would-send / would-not-send example pair. Fill it and set active; pinning the canonical voice is a separate human-approved act.",
|
|
583
|
+
body: VOICE_BODY,
|
|
584
|
+
minScaffoldVersion: 2,
|
|
585
|
+
researchable: true,
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
slug: "brand",
|
|
589
|
+
type: "brand",
|
|
590
|
+
title: "Brand",
|
|
591
|
+
status: "draft",
|
|
592
|
+
tags: ["seed", "brand", "copy"],
|
|
593
|
+
summary: "Stub (non-canonical): the promise in one line, the three claims we can substantiate with proof and the ones we cannot, the CTA ladder from reply to paid, and naming rules. Fill it and set active; pinning canonical brand copy stays human-approved.",
|
|
594
|
+
body: BRAND_BODY,
|
|
595
|
+
minScaffoldVersion: 2,
|
|
596
|
+
researchable: true,
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
slug: "messaging",
|
|
600
|
+
type: "message_playbook",
|
|
601
|
+
title: "Messaging playbook",
|
|
602
|
+
status: "draft",
|
|
603
|
+
tags: ["seed", "messaging", "copy"],
|
|
604
|
+
summary: "Stub: the message playbook — hooks and triggers per persona, proof points that must carry a number, the soft-to-hard CTA ladder, and what we never say. Once filled and set active it grounds outbound and reply drafts, so every claim needs its number and source.",
|
|
605
|
+
body: MESSAGING_BODY,
|
|
606
|
+
minScaffoldVersion: 2,
|
|
607
|
+
researchable: true,
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
slug: "objections",
|
|
611
|
+
type: "message_playbook",
|
|
612
|
+
title: "Objections",
|
|
613
|
+
status: "draft",
|
|
614
|
+
tags: ["seed", "objections", "sales"],
|
|
615
|
+
summary: "Stub: objection handling — a table of the objection, what the buyer is really asking, our answer, the proof behind it, and the point where we walk. Fill it and set active; it then grounds call prep and reply drafts.",
|
|
616
|
+
body: OBJECTIONS_BODY,
|
|
617
|
+
minScaffoldVersion: 2,
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
slug: "playbook-outbound",
|
|
621
|
+
type: "playbook",
|
|
622
|
+
title: "Outbound playbook",
|
|
623
|
+
status: "draft",
|
|
624
|
+
tags: ["seed", "playbook", "outbound"],
|
|
625
|
+
summary: "Stub: the cold outbound motion — which slice of the ICP it works, where the list comes from, channel/cadence and daily volume per sender, the never-enroll suppression list, the three numbers that say it is working, and where a reply exits to. Fill with real cadence and targets, then set active.",
|
|
626
|
+
body: PLAYBOOK_OUTBOUND_BODY,
|
|
627
|
+
minScaffoldVersion: 2,
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
slug: "playbook-inbound",
|
|
631
|
+
type: "playbook",
|
|
632
|
+
title: "Inbound playbook",
|
|
633
|
+
status: "draft",
|
|
634
|
+
tags: ["seed", "playbook", "inbound"],
|
|
635
|
+
summary: "Stub: the inbound motion — the sources (content/SEO, LinkedIn engagement, product signups, referrals) and where each lands, the response SLA in and out of business hours, a persona-matched first touch, and how a lead is routed, self-served, or refused. Fill and set active.",
|
|
636
|
+
body: PLAYBOOK_INBOUND_BODY,
|
|
637
|
+
minScaffoldVersion: 2,
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
slug: "playbook-nurture",
|
|
641
|
+
type: "playbook",
|
|
642
|
+
title: "Nurture playbook",
|
|
643
|
+
status: "draft",
|
|
644
|
+
tags: ["seed", "playbook", "nurture"],
|
|
645
|
+
summary: "Stub: the not-now motion — who enters the pile (not-now replies, stalled deals, no-shows, churned accounts, silent outbound finishers), who never does, the low-pressure touch cadence and what each touch sends, and the exit back to qualification or out. Fill and set active.",
|
|
646
|
+
body: PLAYBOOK_NURTURE_BODY,
|
|
647
|
+
minScaffoldVersion: 2,
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
slug: "qualification",
|
|
651
|
+
type: "playbook",
|
|
652
|
+
title: "Qualification",
|
|
653
|
+
status: "draft",
|
|
654
|
+
tags: ["seed", "sales", "qualification"],
|
|
655
|
+
summary: "Stub: the discovery and fit gate — five discovery questions, the must-be-true criteria to advance, sales-stage disqualifiers only (the hard-no list stays in the ICP page and is never copied here), and what actually counts as a next step. Fill and set active.",
|
|
656
|
+
body: QUALIFICATION_BODY,
|
|
657
|
+
minScaffoldVersion: 2,
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
slug: "personas",
|
|
661
|
+
type: "topic",
|
|
662
|
+
title: "Personas (map of content)",
|
|
663
|
+
status: "draft",
|
|
664
|
+
tags: ["seed", "moc", "personas"],
|
|
665
|
+
summary: "Stub map-of-content: the buyer roster — one row per persona covering job to be done, the pain that costs them money, the buy-now trigger, and where they spend time. Create one persona-typed page per buyer (persona-vp-sales, persona-founder) and link it here. This is the hub the ICP and start-here pages point at.",
|
|
666
|
+
body: PERSONAS_BODY,
|
|
667
|
+
minScaffoldVersion: 2,
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
slug: "customers",
|
|
671
|
+
type: "topic",
|
|
672
|
+
title: "Customers (map of content)",
|
|
673
|
+
status: "draft",
|
|
674
|
+
tags: ["seed", "moc", "customers"],
|
|
675
|
+
summary: "Stub map-of-content: the customer roster — offer bought, why they bought in their own words, the outcome number, and whether they are referenceable. Create one entity-typed page per customer and link it here; live account state (plan, seats, renewal, tickets) stays out, per the density bar.",
|
|
676
|
+
body: CUSTOMERS_BODY,
|
|
677
|
+
minScaffoldVersion: 2,
|
|
678
|
+
researchable: true,
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
slug: "research",
|
|
682
|
+
type: "topic",
|
|
683
|
+
title: "Research (map of content)",
|
|
684
|
+
status: "draft",
|
|
685
|
+
tags: ["seed", "moc", "research"],
|
|
686
|
+
summary: "Stub map-of-content for dated research_note pages: what belongs in a note versus a standing-answer hub, the note template (question, method, findings with URLs, what would change our mind), and the rule that agent-derived notes land here tagged agent-derived until a human verifies them.",
|
|
687
|
+
body: RESEARCH_BODY,
|
|
688
|
+
minScaffoldVersion: 2,
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
slug: "metrics",
|
|
692
|
+
type: "topic",
|
|
693
|
+
title: "Metrics",
|
|
694
|
+
status: "draft",
|
|
695
|
+
tags: ["seed", "moc", "metrics"],
|
|
696
|
+
summary: "Stub: the five numbers we steer by — metric, exact definition, current target, and where the live number actually lives. Definitions and targets only; live values belong in Dashboards, per the density bar in conventions. Moving a target is a decision; why it moved is a campaign learning.",
|
|
697
|
+
body: METRICS_BODY,
|
|
698
|
+
minScaffoldVersion: 2,
|
|
699
|
+
},
|
|
301
700
|
];
|
|
701
|
+
/**
|
|
702
|
+
* Seed slugs a domain-grounded research pass could genuinely draft from the company's
|
|
703
|
+
* PUBLIC web presence — what they sell, who they say they sell to, how they sound, who
|
|
704
|
+
* bought. Derived from the manifest's `researchable` flag (never a second hand-kept list),
|
|
705
|
+
* and consumed by `oxygen knowledge lint`'s researchable check, which reports the ones
|
|
706
|
+
* still sitting unfilled at revision 1 on a workspace that has a company domain.
|
|
707
|
+
*/
|
|
708
|
+
export const KNOWLEDGE_RESEARCHABLE_SEED_SLUGS = KNOWLEDGE_SEED_PAGES
|
|
709
|
+
.filter((page) => page.researchable === true)
|
|
710
|
+
.map((page) => page.slug);
|
|
@@ -96,12 +96,35 @@ export declare const SENDING_SEAT_GATE_ENABLED_ENV_VAR = "OXYGEN_SENDING_SEAT_GA
|
|
|
96
96
|
/**
|
|
97
97
|
* Which seat kind a connect request consumes, by CLI path prefix.
|
|
98
98
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* customers who already
|
|
103
|
-
*
|
|
104
|
-
*
|
|
99
|
+
* ALL FOUR CHANNELS are mapped. Mailboxes were held back while grandfathering
|
|
100
|
+
* was backfill-only, because the backfill runs in the control plane and mailboxes
|
|
101
|
+
* live in each tenant's own database — gating them then would have refused
|
|
102
|
+
* customers who already had mailboxes attached. They are safe to include now
|
|
103
|
+
* that the gate grandfathers an organization's existing senders on FIRST CONTACT
|
|
104
|
+
* (see ensureLegacyEntitlementOnFirstContact), which needs no cross-tenant sweep
|
|
105
|
+
* and cannot miss a tenant.
|
|
105
106
|
*/
|
|
106
|
-
export
|
|
107
|
-
|
|
107
|
+
export type SeatConnectRoute = {
|
|
108
|
+
readonly path: string;
|
|
109
|
+
readonly seatKey: SendingSeatKey;
|
|
110
|
+
/**
|
|
111
|
+
* `prefix` also matches sub-paths, for flows that continue under the same
|
|
112
|
+
* route (an OAuth callback). `exact` matches only the route itself.
|
|
113
|
+
*
|
|
114
|
+
* The distinction is load-bearing. `/api/cli/voice/numbers` buys a number, but
|
|
115
|
+
* `/api/cli/voice/numbers/<id>` and `/<id>/tags` manage an EXISTING one — and
|
|
116
|
+
* gating those would refuse a customer at capacity from RELEASING a number,
|
|
117
|
+
* which is the one action that frees capacity. Prefix-matching everything was
|
|
118
|
+
* the first version of this and it had exactly that bug.
|
|
119
|
+
*/
|
|
120
|
+
readonly match: "exact" | "prefix";
|
|
121
|
+
};
|
|
122
|
+
export declare const SEAT_CONNECT_ROUTES: readonly SeatConnectRoute[];
|
|
123
|
+
/**
|
|
124
|
+
* Which seat a request consumes, or null.
|
|
125
|
+
*
|
|
126
|
+
* METHOD MATTERS: only a request that CREATES a sender consumes capacity.
|
|
127
|
+
* `GET /api/cli/voice/numbers` lists what you already own and must never be
|
|
128
|
+
* refused for want of a seat.
|
|
129
|
+
*/
|
|
130
|
+
export declare function seatKindForConnect(pathname: string, method: string): SendingSeatKey | null;
|