@forwardimpact/outpost 3.12.1 → 3.13.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.
Files changed (85) hide show
  1. package/package.json +3 -2
  2. package/src/kb-manager.js +58 -5
  3. package/src/kb-validator.js +762 -0
  4. package/src/outpost.js +73 -8
  5. package/templates/.claude/agents/chief-of-staff.md +14 -6
  6. package/templates/.claude/agents/concierge.md +9 -2
  7. package/templates/.claude/agents/head-hunter.md +9 -2
  8. package/templates/.claude/agents/librarian.md +11 -4
  9. package/templates/.claude/agents/postman.md +9 -2
  10. package/templates/.claude/agents/recruiter.md +9 -2
  11. package/templates/.claude/skills/anarlog-follow/SKILL.md +53 -29
  12. package/templates/.claude/skills/anarlog-follow/references/sessions.md +52 -0
  13. package/templates/.claude/skills/anarlog-process/SKILL.md +88 -45
  14. package/templates/.claude/skills/anarlog-process/references/extraction.md +19 -11
  15. package/templates/.claude/skills/anarlog-process/references/sessions.md +92 -58
  16. package/templates/.claude/skills/anarlog-process/scripts/scan.mjs +404 -163
  17. package/templates/.claude/skills/candidate-report/SKILL.md +12 -9
  18. package/templates/.claude/skills/changelog/SKILL.md +106 -56
  19. package/templates/.claude/skills/deck-create/SKILL.md +60 -2
  20. package/templates/.claude/skills/deck-review/SKILL.md +4 -1
  21. package/templates/.claude/skills/deck-summarize/SKILL.md +6 -2
  22. package/templates/.claude/skills/deck-summarize/references/brief-template.md +1 -1
  23. package/templates/.claude/skills/doc-collab/SKILL.md +16 -11
  24. package/templates/.claude/skills/doc-create/SKILL.md +6 -3
  25. package/templates/.claude/skills/draft-emails/SKILL.md +31 -25
  26. package/templates/.claude/skills/draft-emails/references/template.md +1 -1
  27. package/templates/.claude/skills/draft-emails/scripts/scan-emails.mjs +14 -8
  28. package/templates/.claude/skills/draft-emails/scripts/send-email.mjs +9 -3
  29. package/templates/.claude/skills/extract-entities/SKILL.md +17 -16
  30. package/templates/.claude/skills/extract-entities/references/TEMPLATES.md +2 -1
  31. package/templates/.claude/skills/extract-entities/references/conditions.md +6 -5
  32. package/templates/.claude/skills/extract-entities/references/links.md +34 -10
  33. package/templates/.claude/skills/extract-entities/references/recruitment.md +15 -10
  34. package/templates/.claude/skills/extract-entities/references/resolution.md +1 -1
  35. package/templates/.claude/skills/extract-entities/references/sources.md +1 -1
  36. package/templates/.claude/skills/extract-entities/references/templates-conditions.md +10 -4
  37. package/templates/.claude/skills/extract-entities/references/templates-people-orgs.md +29 -10
  38. package/templates/.claude/skills/extract-entities/references/templates-priorities.md +8 -2
  39. package/templates/.claude/skills/extract-entities/references/templates-projects-topics.md +19 -7
  40. package/templates/.claude/skills/meeting-prep/SKILL.md +23 -18
  41. package/templates/.claude/skills/organize-files/SKILL.md +3 -0
  42. package/templates/.claude/skills/person-identify/SKILL.md +58 -10
  43. package/templates/.claude/skills/person-identify/scripts/identify.sh +110 -11
  44. package/templates/.claude/skills/person-lookup/SKILL.md +8 -3
  45. package/templates/.claude/skills/person-lookup/scripts/lookup.sh +27 -1
  46. package/templates/.claude/skills/req-assess/SKILL.md +19 -11
  47. package/templates/.claude/skills/req-assess/references/interview-template.md +6 -1
  48. package/templates/.claude/skills/req-assess/references/panel-template.md +5 -1
  49. package/templates/.claude/skills/req-bundle/SKILL.md +164 -0
  50. package/templates/.claude/skills/req-bundle/references/matching.md +70 -0
  51. package/templates/.claude/skills/req-bundle/references/pdf-structure.md +74 -0
  52. package/templates/.claude/skills/req-bundle/scripts/split-bundle.mjs +377 -0
  53. package/templates/.claude/skills/req-decide/SKILL.md +26 -18
  54. package/templates/.claude/skills/req-decide/references/template.md +2 -2
  55. package/templates/.claude/skills/req-forget/SKILL.md +39 -22
  56. package/templates/.claude/skills/req-forget/references/classify.md +12 -10
  57. package/templates/.claude/skills/req-forget/references/locations.md +27 -22
  58. package/templates/.claude/skills/req-forget/references/report-template.md +23 -15
  59. package/templates/.claude/skills/req-scan/SKILL.md +6 -3
  60. package/templates/.claude/skills/req-scan/references/template.md +11 -1
  61. package/templates/.claude/skills/req-screen/SKILL.md +78 -34
  62. package/templates/.claude/skills/req-screen/references/rubric.md +38 -42
  63. package/templates/.claude/skills/req-screen/references/scoring.md +79 -0
  64. package/templates/.claude/skills/req-screen/references/template.md +26 -14
  65. package/templates/.claude/skills/req-track/SKILL.md +44 -44
  66. package/templates/.claude/skills/req-track/references/fields.md +18 -15
  67. package/templates/.claude/skills/req-track/references/overlays.md +42 -0
  68. package/templates/.claude/skills/req-track/references/signals.md +2 -2
  69. package/templates/.claude/skills/req-track/references/templates.md +28 -27
  70. package/templates/.claude/skills/req-workday/SKILL.md +49 -20
  71. package/templates/.claude/skills/req-workday/references/brief.md +81 -0
  72. package/templates/.claude/skills/req-workday/references/templates.md +6 -73
  73. package/templates/.claude/skills/req-workday/references/xlsx-format.md +19 -0
  74. package/templates/.claude/skills/req-workday/scripts/parse-workday.mjs +96 -20
  75. package/templates/.claude/skills/send-chat/SKILL.md +11 -11
  76. package/templates/.claude/skills/sync-apple-calendar/SKILL.md +3 -0
  77. package/templates/.claude/skills/sync-apple-mail/SKILL.md +3 -0
  78. package/templates/.claude/skills/sync-teams/SKILL.md +3 -0
  79. package/templates/.claude/skills/upstream-instructions/SKILL.md +8 -5
  80. package/templates/.claude/skills/upstream-instructions/references/examples.md +3 -3
  81. package/templates/CLAUDE.md +96 -87
  82. package/templates/MIGRATION.md +359 -0
  83. package/templates/registry.yaml +25 -0
  84. package/templates/.claude/skills/anarlog-follow/scripts/follow.mjs +0 -243
  85. package/templates/.claude/skills/anarlog-trim/SKILL.md +0 -186
@@ -54,20 +54,56 @@ try {
54
54
  const filePath = process.argv[2];
55
55
  const summaryMode = process.argv.includes("--summary");
56
56
 
57
+ /**
58
+ * Read a workbook. Tolerate Workday's ZIP container.
59
+ *
60
+ * Workday exports .xlsx via Apache POI's streaming writer. That writer sets
61
+ * the ZIP "data descriptor" flag (bit 0x08) on every entry, so the sizes live
62
+ * in a trailer after each entry, not in the local header. read-excel-file's
63
+ * streaming unzipper trusts the (zeroed) local-header sizes, loses alignment,
64
+ * and throws `invalid signature: 0x…`. fflate reads the authoritative ZIP
65
+ * central directory, so on failure we re-pack into a clean container (sizes
66
+ * in the local headers, no data descriptors) and retry. Files that already
67
+ * parse take the original path unchanged.
68
+ */
69
+ async function readWorkbook(path) {
70
+ try {
71
+ return await readXlsxFile(path);
72
+ } catch (err) {
73
+ let fflate;
74
+ try {
75
+ fflate = await import("fflate");
76
+ } catch {
77
+ throw err; // fflate unavailable — surface the original parse error
78
+ }
79
+ const { readFileSync } = await import("node:fs");
80
+ const raw = readFileSync(path);
81
+ const normalized = Buffer.from(
82
+ fflate.zipSync(fflate.unzipSync(new Uint8Array(raw))),
83
+ );
84
+ return await readXlsxFile(normalized);
85
+ }
86
+ }
87
+
88
+ // read-excel-file v9 returns the whole workbook as [{ sheet, data }] —
89
+ // read it once and index sheets from that.
90
+ const workbook = await readWorkbook(filePath);
91
+ const sheetNames = workbook.map((s) => s.sheet);
92
+
57
93
  /** Read a sheet by number (1-indexed) or name. Rows are arrays of strings. */
58
- async function readSheet(file, sheet) {
59
- const rows = await readXlsxFile(file, { sheet });
94
+ function readSheet(_file, sheet) {
95
+ const entry =
96
+ typeof sheet === "number"
97
+ ? workbook[sheet - 1]
98
+ : workbook.find((s) => s.sheet === sheet);
99
+ const rows = entry ? entry.data : [];
60
100
  // Normalise null cells to empty strings to match previous behaviour
61
101
  return rows.map((row) => row.map((cell) => (cell == null ? "" : cell)));
62
102
  }
63
103
 
64
- // Get sheet names to find the candidates sheet
65
- const sheets = await readXlsxFile(filePath, { getSheets: true });
66
- const sheetNames = sheets.map((s) => s.name);
67
-
68
104
  // --- Sheet 1: Requisition metadata ---
69
105
 
70
- const sheet1Rows = await readSheet(filePath, 1);
106
+ const sheet1Rows = readSheet(filePath, 1);
71
107
 
72
108
  /** Extract the requisition ID and title from the header row. */
73
109
  function parseReqHeader(headerText) {
@@ -120,7 +156,7 @@ const requisition = {
120
156
  const candSheetName =
121
157
  sheetNames.find((n) => n.toLowerCase() === "candidates") ||
122
158
  sheetNames[Math.min(2, sheetNames.length - 1)];
123
- const candRows = await readSheet(filePath, candSheetName);
159
+ const candRows = readSheet(filePath, candSheetName);
124
160
 
125
161
  // Find the header row dynamically. Look for a row that contains "Stage".
126
162
  // Old format: row 3 (index 2). New format: row 8 (index 7).
@@ -194,24 +230,64 @@ function col(row, field) {
194
230
  return row[idx] ?? "";
195
231
  }
196
232
 
233
+ // Any character outside the Latin script blocks (Basic Latin + Latin-1
234
+ // Supplement + Latin Extended-A/B + Latin Extended Additional). Accented Latin
235
+ // (é, ñ, ø, ç, Vietnamese, …) stays; Greek, Cyrillic, CJK, Arabic, Hebrew,
236
+ // etc. count as native-alphabet text to drop.
237
+ const NON_LATIN = /[^\u0020-\u024F\u1E00-\u1EFF]/;
238
+ const HAS_LATIN_LETTER = /[A-Za-z\u00C0-\u024F\u1E00-\u1EFF]/;
239
+
197
240
  /**
198
- * Clean a candidate name. Strip annotations like (Prior Worker), (Internal),
199
- * etc. Returns { cleanName, internalExternal }.
241
+ * Clean a candidate name into the canonical Latin name.
242
+ *
243
+ * Workday encodes several things in the name cell as parentheticals:
244
+ * - Employment annotations: `(Internal)`, `(Prior Worker)`, `(External)`.
245
+ * - A native-alphabet transliteration of the name, e.g.
246
+ * `Nikos Papadopoulos (ΝΙΚΟΣ ΠΑΠΑΔΟΠΟΥΛΟΣ)` or `Wei Zhang (张伟)`.
247
+ * A name may carry both, in either paren style. Normalise on the Latin name:
248
+ * strip every trailing parenthetical (classify employment ones into
249
+ * `internalExternal`, discard native-alphabet ones), then drop any residual
250
+ * non-Latin-script tokens. Returns { cleanName, internalExternal }.
200
251
  */
252
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: annotation peel loop classifies employment vs transliteration cases
201
253
  function parseName(raw) {
202
- const name = String(raw).trim();
254
+ // Normalise full-width parens () to ASCII so both styles strip uniformly.
255
+ let name = String(raw).replace(/(/g, "(").replace(/)/g, ")").trim();
203
256
  if (!name) return { cleanName: "", internalExternal: "" };
204
257
 
205
- const match = name.match(/^(.+?)\s*\(([^)]+)\)\s*$/);
206
- if (match) {
207
- const annotation = match[2].trim();
208
- let ie;
209
- if (/prior\s*worker/i.test(annotation)) ie = "External (Prior Worker)";
210
- else if (/internal/i.test(annotation)) ie = "Internal";
211
- else ie = annotation;
212
- return { cleanName: match[1].trim(), internalExternal: ie };
258
+ let internalExternal = "";
259
+ // Repeatedly peel a trailing parenthetical group (allowing one level of
260
+ // nesting so `(External (Prior Worker))` is captured whole).
261
+ const trailing = /\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)\s*$/;
262
+ let m;
263
+ while ((m = name.match(trailing)) !== null) {
264
+ const annotation = m[1].trim();
265
+ if (/prior\s*worker/i.test(annotation)) {
266
+ if (!internalExternal) internalExternal = "External (Prior Worker)";
267
+ } else if (/internal/i.test(annotation)) {
268
+ if (!internalExternal) internalExternal = "Internal";
269
+ } else if (/external/i.test(annotation)) {
270
+ if (!internalExternal) internalExternal = "External";
271
+ } else if (NON_LATIN.test(annotation)) {
272
+ // Native-alphabet transliteration of the name — drop, no IE signal.
273
+ } else if (!internalExternal && annotation) {
274
+ // Unknown Latin annotation — preserve prior behaviour (first one wins).
275
+ internalExternal = annotation;
276
+ }
277
+ name = name.slice(0, name.length - m[0].length).trim();
213
278
  }
214
- return { cleanName: name, internalExternal: "" };
279
+
280
+ // Drop any residual whole-word tokens that are purely non-Latin script
281
+ // (e.g. a native name appended without parentheses). Keep Latin tokens
282
+ // and pure punctuation/digits.
283
+ name = name
284
+ .split(/\s+/)
285
+ .filter((tok) => HAS_LATIN_LETTER.test(tok) || !NON_LATIN.test(tok))
286
+ .join(" ")
287
+ .replace(/\s{2,}/g, " ")
288
+ .trim();
289
+
290
+ return { cleanName: name, internalExternal };
215
291
  }
216
292
 
217
293
  /** Detect source-based internal/external when the name annotation is absent. */
@@ -8,6 +8,9 @@ compatibility:
8
8
 
9
9
  # Send Chat
10
10
 
11
+ Write tier: `0-Draft` (sending is an export)
12
+ Frontmatter: none
13
+
11
14
  Send chat messages to people with browser automation against a web-based chat
12
15
  platform (Microsoft Teams, Slack, or similar). This skill resolves recipients by
13
16
  name from the knowledge graph. The user can say "message Sarah about the
@@ -36,7 +39,7 @@ base.**
36
39
  When the user mentions ANY person:
37
40
 
38
41
  1. **STOP** — Do not open the chat platform yet
39
- 2. **SEARCH** — Look them up: `rg -l "{name}" Knowledge/People/`
42
+ 2. **SEARCH** — Look them up: `rg -l "{name}" 3-Team/People/`
40
43
  3. **READ** — Read their note to understand context, role, recent interactions
41
44
  4. **UNDERSTAND** — Know who they are and what you work on together
42
45
  5. **THEN PROCEED** — Only now compose the message and use browser automation
@@ -54,10 +57,10 @@ reference to a full name with the knowledge graph:
54
57
 
55
58
  ```bash
56
59
  # Find person by partial name
57
- rg -l -i "{name}" Knowledge/People/
60
+ rg -l -i "{name}" 3-Team/People/
58
61
 
59
62
  # If ambiguous, read candidates to disambiguate
60
- cat "Knowledge/People/{Candidate}.md"
63
+ cat "3-Team/People/{Candidate}.md"
61
64
  ```
62
65
 
63
66
  **If ambiguous** (multiple matches), ask the user which person they mean. List
@@ -74,7 +77,7 @@ can review and edit the exact message before you send it.
74
77
  ### Draft Workflow
75
78
 
76
79
  1. **Compose the message** based on context and user intent.
77
- 2. **Write it to a draft file** at `Drafts/chat-{recipient-slug}-{date}.md`
80
+ 2. **Write it to a draft file** at `0-Draft/chat-{recipient-slug}-{date}.md`
78
81
  - `{recipient-slug}` = lowercase, hyphenated full name (e.g. `sarah-chen`)
79
82
  - `{date}` = ISO date (e.g. `2026-02-19`)
80
83
  3. **Show the user the draft** — display the file path and contents.
@@ -139,14 +142,11 @@ same organization.
139
142
  4. Press Enter or click Send
140
143
  5. Take a screenshot to confirm the message was sent
141
144
 
142
- ### Step 4: Update Knowledge Graph (Optional)
143
-
144
- If the message is substantive (not just "hey" or "thanks"), note the interaction
145
- on the person's knowledge note:
145
+ ### Step 4: Keep the Draft as the Record
146
146
 
147
- ```markdown
148
- - {YYYY-MM-DD}: Messaged on {Platform} re: {topic}
149
- ```
147
+ Do not write the interaction to the person's note. This skill writes only to
148
+ `0-Draft/`. The chat sync (`sync-teams`) and `extract-entities` record the
149
+ interaction when the messages sync.
150
150
 
151
151
  ## Error Handling
152
152
 
@@ -6,6 +6,9 @@ compatibility: Requires macOS with Apple Calendar configured and Full Disk Acces
6
6
 
7
7
  # Sync Apple Calendar
8
8
 
9
+ Write tier: none (cache only)
10
+ Frontmatter: none
11
+
9
12
  Sync calendar events from the macOS Calendar app's local SQLite database into
10
13
  `~/.cache/fit/outpost/apple_calendar/` as JSON files. This is an automated skill
11
14
  in the data pipeline. It ingests raw calendar data that other skills (like
@@ -6,6 +6,9 @@ compatibility: Requires macOS with Apple Mail configured and Full Disk Access gr
6
6
 
7
7
  # Sync Apple Mail
8
8
 
9
+ Write tier: none (cache only)
10
+ Frontmatter: none
11
+
9
12
  Sync email threads from the macOS Mail app's local SQLite database into
10
13
  `~/.cache/fit/outpost/apple_mail/` as markdown files. This is an automated skill
11
14
  in the data pipeline. It ingests raw email data that other skills (like
@@ -6,6 +6,9 @@ compatibility: Requires macOS with Microsoft Teams desktop app (com.microsoft.te
6
6
 
7
7
  # Sync Teams
8
8
 
9
+ Write tier: none (cache only)
10
+ Frontmatter: none
11
+
9
12
  Sync recent Microsoft Teams chat messages into
10
13
  `~/.cache/fit/outpost/teams_chat/` as markdown files. This is an automated skill
11
14
  in the data pipeline. It ingests chat data that other skills (like
@@ -5,6 +5,9 @@ description: Track changes to this installation's instruction files: the root CL
5
5
 
6
6
  # Upstream Instructions
7
7
 
8
+ Write tier: none (the root CHANGELOG.md is a personal surface)
9
+ Frontmatter: none
10
+
8
11
  Track changes to this installation's **instructions**. Record them in one root
9
12
  `CHANGELOG.md` so you can contribute improvements back to the upstream monorepo.
10
13
  "Instructions" means all three surfaces, and they carry equal weight:
@@ -32,7 +35,7 @@ Track changes to this installation's **instructions**. Record them in one root
32
35
  - `.claude/skills/*/SKILL.md` and reference files — skills.
33
36
  - `CHANGELOG.md` (root) — the existing changelog, for what's already recorded.
34
37
  - The changes you made in the current working session — the source of truth for
35
- what changed. The KB lives on a synced filesystem. It has no version control.
38
+ what changed. The KB may sync without version control; do not rely on it.
36
39
 
37
40
  ## Outputs
38
41
 
@@ -64,8 +67,8 @@ head -20 CHANGELOG.md 2>/dev/null # newest date already recorded, if any
64
67
 
65
68
  ### 2. Identify changed instructions
66
69
 
67
- Knowledge bases live on a synced filesystem. They do not live in Git, so there
68
- is no commit history to diff. Identify what changed from the work you did **this
70
+ A knowledge base may sync over a mount with no version control, so never rely
71
+ on commit history. Identify what changed from the work you did **this
69
72
  session**. Recall every edit, addition, removal, and rename you made to
70
73
  `CLAUDE.md`, `.claude/agents/`, and `.claude/skills/` during the current
71
74
  conversation. List them per surface.
@@ -102,8 +105,8 @@ Every entry must answer:
102
105
  2. **Why?** — the problem encountered or improvement discovered in use.
103
106
  3. **Details** — a summary of the actual change (not a full diff).
104
107
 
105
- Good: "Agents now read `Knowledge/Priorities/` at the start of every wake and
106
- flag anything that threatens a priority. Drafts and triage ignored strategic
108
+ Good: "Agents now read `Priorities/` in every tier at the start of every wake
109
+ and flag anything that threatens a priority. Drafts and triage ignored strategic
107
110
  context."
108
111
 
109
112
  Bad: "Updated the agents" / "Fixed stuff" / "Changed line 42".
@@ -20,7 +20,7 @@ strategic layer.
20
20
  Priorities, removing the Project↔Goal↔Priority coupling that earned nothing.
21
21
 
22
22
  **Details:**
23
- - Deleted `Knowledge/Goals/`; repointed live backlinks to `Priorities/C - Onboarding`.
23
+ - Deleted `3-Team/Goals/`; repointed live backlinks to `3-Team/Priorities/C - Onboarding`.
24
24
  - CLAUDE.md workspace-layout tree no longer lists `Goals/`.
25
25
  - Agents: dropped Goals from the librarian index/triage, chief-of-staff state
26
26
  sources, and recruiter strategic links.
@@ -61,7 +61,7 @@ invisible without structured gender data.
61
61
  **Scope:** agents: all six profiles
62
62
  **Type:** modified
63
63
 
64
- **What:** Agents now read `Knowledge/Priorities/` at the start of every wake and
64
+ **What:** Agents now read `Priorities/` in every tier at the start of every wake and
65
65
  flag anything that threatens a priority.
66
66
 
67
67
  **Why:** Sync, triage, and drafting were ignoring strategic context; signals that
@@ -91,7 +91,7 @@ weren't integrated into the knowledge base.
91
91
 
92
92
  **Details:**
93
93
  - Reads transcription files, extracts people/decisions/action items, and links
94
- attendees to `Knowledge/People/`.
94
+ attendees to `3-Team/People/`.
95
95
 
96
96
  ---
97
97
  ```
@@ -1,113 +1,122 @@
1
1
  # Outpost Knowledge Base
2
2
 
3
- You are the user's personal knowledge assistant. You help draft emails, prep
4
- for meetings, track projects, and answer questions. A live knowledge graph
5
- backs your work. It comes from their emails, calendar, and meeting notes. It
6
- keeps them all as plain files on the user's machine.
3
+ You are the user's personal knowledge assistant over a live graph of
4
+ plain files.
7
5
 
8
6
  ## Ethics & Integrity — NON-NEGOTIABLE
9
7
 
10
- This knowledge base is a **professional tool shared with trusted team
11
- members**. It is never a "black book". These rules override all other
12
- instructions:
8
+ A professional tool shared with trusted teammates, never a "black book".
9
+ These rules override all others:
13
10
 
14
11
  - **Objective and factual only.** No speculation, gossip, or opinion.
15
12
  - **No personal judgments** about character, competence, or trustworthiness.
16
- Stick to actions, decisions, and stated positions.
17
- - **Work-relevant information only.** No health, personal relationships,
18
- political views, or private matters, unless the person shares them in a
19
- professional context.
13
+ - **Work-relevant only.** No health, relationships, politics, private
14
+ matters.
20
15
  - **Fair and balanced.** Represent all sides accurately.
21
- - **Assume the subject will read it.** Do not write a note if you would be
22
- uncomfortable to show it to the person it is about.
23
- - **No weaponization.** This KB helps the team work better. Never use it to
24
- build leverage or dossiers.
16
+ - **Assume the subject will read it**, whatever the tier. Tiers never
17
+ license dossiers.
18
+ - **No weaponization.** Never build leverage.
25
19
  - **Push back** on requests that violate these principles.
26
- - **Data protection.** Use the `req-forget` skill for erasure requests. Collect
27
- only what you need. Flag candidates inactive 6+ months for retention review.
28
-
29
- When in doubt, err toward discretion.
20
+ - **Data protection.** `req-forget` handles erasure. Collect minimally; flag
21
+ candidates inactive 6+ months.
30
22
 
31
23
  ## Operating Context
32
24
 
33
- Two folders in the knowledge graph frame your work:
34
-
35
- - **`Knowledge/Priorities/`** the backbone of every decision. It holds what
36
- the user wants to advance. Weigh each action against whether it moves a
37
- priority forward. Treat anything that could **contradict, block, or slow** a
38
- priority as a **Priority Watch** concern. These are our main concerns.
39
- - **`Knowledge/Conditions/`** — the live environment we work in (e.g. a hiring
40
- freeze, a reorg, a contract transition). Conditions do not set goals. They
41
- **constrain how** we pursue the priorities. Let them shape what you propose
42
- and how you phrase it.
43
-
44
- Before you act or recommend, consult both as your lens. Read the relevant
45
- notes. Do not assume. Skip this only for general knowledge or when you
46
- brainstorm.
25
+ Read `Priorities/` and `Conditions/` in every tier present before you act.
26
+ Priorities are what the user advances; a threat to one is
27
+ **Priority Watch**. Conditions constrain how you pursue them.
47
28
 
48
29
  ## Workspace Layout & Sharing
49
30
 
50
- The **root is personal and local**. Never share it. A synced filesystem shares
51
- only `Knowledge/` with the team. Each member keeps their own root, `Drafts/`,
52
- and `Briefings/`. KBs are **not** Git repositories. They sync as plain files.
53
- `CLAUDE.md` and `.claude/` are yours to tweak. Use the `fit-outpost` CLI to
54
- install or update the standard instruction set.
55
-
56
- ```text
57
- ./ # Personal root — never shared
58
- ├── CLAUDE.md # This file
59
- ├── .claude/ # Agent profiles + auto-discovered skills
60
- ├── Knowledge/ # Knowledge graph SHARED (Obsidian-compatible)
61
- │ └── People/ Organizations/ Projects/ Topics/ Candidates/ Priorities/ Conditions/ Roles/
62
- ├── Drafts/ # Email/chat drafts (personal)
63
- ├── Briefings/ # Daily briefings (personal)
64
- └── .mcp.json # MCP config (optional)
65
- ```
66
-
67
- ## Search
68
-
69
- Use the **ripgrep** `rg` program for fast knowledge graph searches.
31
+ The KB root is the Obsidian vault. Tier directories (one digit, one dash) are
32
+ the graph and the share units; a lower rank is a narrower audience. Every other
33
+ root entry is personal, never shared (instruction files, `Briefings/`,
34
+ `registry.yaml`, `validation-baseline.json`); personal folders never match the
35
+ rank grammar.
36
+
37
+ - `0-Draft/` — owner only, never shared: drafts, agent reports, permanent
38
+ owner-only notes.
39
+ - `1-Management/` — senior managers. User-placed; fellow-manager notes go
40
+ to tier 0.
41
+ - `2-Confidential/` hiring managers. Candidates, Prospects, Roles,
42
+ Erasure.
43
+ - `3-Team/` the team. People, Teams, Organizations, Projects, Topics,
44
+ Priorities, Conditions, Tasks.
45
+ - `4-Public/` — anyone. User-placed after rights and verification checks.
46
+
47
+ Rename, add, or remove tiers; entity subdirectories appear on demand.
48
+
49
+ Sharing is cumulative: a tier-N member receives every wider tier, from
50
+ tier 1 up, over any syncing mount (OneDrive, Git). A shared tier is often a
51
+ symlink into a synced folder; the rank comes from the link's name. Keep
52
+ the vault root outside every cloud-synced folder.
53
+ `npx fit-outpost validate <root>` checks any vault or suffix.
54
+
55
+ ## Placement and Links
56
+
57
+ - Link only to your own tier or a wider one, never narrower or personal.
58
+ - Shared-tier links are tier-prefixed and vault-absolute
59
+ (`[[3-Team/People/Sarah Chen]]`); bare basenames only in tier 0 or one
60
+ entity folder.
61
+ - Place each note in the widest tier that excludes everyone who must not
62
+ read it; otherwise tier 0.
63
+ - Promote: a human moves a note into its tier. Export: a skill
64
+ sends a copy over mail or chat; the note keeps its tier. Named recipients
65
+ and panels are exports.
66
+ - Overlay: a narrower facet in a narrower tier, declared by a one-way
67
+ quoted `canonical` link to the wide note. Forms: facet, timeline split
68
+ (same date keys), inverse stub (linked down to).
69
+ - Link inversion: the wide note's narrow link moves, with its one-line
70
+ context, into the narrow note; no tombstone.
71
+ - Route each dated entry to the note in its own tier.
72
+ - Aggregates over narrower sources go to `0-Draft/`; no agent writes
73
+ tier 1.
74
+ - `no-redistribute` overrides tier; marked or third-party content never
75
+ enters tier 4.
76
+ - Assessment prose about a named subject lives only in that subject's
77
+ record.
78
+
79
+ ## Note Metadata
80
+
81
+ Stamp YAML frontmatter on every note. Humans edit `registry.yaml`; agents
82
+ select from it.
83
+
84
+ - Core on every shared note: `type`, `created`, `updated` (ISO dates).
85
+ - Conditional: `aliases` (person, candidate, organization), `status`
86
+ (candidate, prospect), `canonical` (overlays), `verified` (tier 4).
87
+ - Flat block at line 1, snake_case, canonical key order; property links
88
+ double-quoted, tier-prefixed.
89
+ - No tier, rank, or audience key; the path is the sole tier authority.
90
+ - Tags: the closed `topic/` registry taxonomy, frontmatter `tags` only;
91
+ each tag carries its widest tier.
92
+ - Coherence: Bases on `type`/`status`, aliases in the switcher, path-keyed
93
+ graph groups; absolute-link, same-folder vault settings.
70
94
 
71
95
  ## Agents
72
96
 
73
- Agents in `.claude/agents/` maintain this KB. The Outpost scheduler wakes them
74
- on a schedule. On each wake, observe the state. Decide the most valuable action.
75
- Execute it.
76
-
77
- Each agent's own profile under `.claude/agents/` declares its skills.
97
+ The scheduler wakes the `.claude/agents/` agents: observe, decide,
98
+ execute. Profiles declare skills, read scope, write tier.
78
99
 
79
- | Agent | Domain | Schedule |
80
- | ------------------ | ------------------------------- | --------------- |
81
- | **postman** | Communication triage and drafts | Every 5 min |
82
- | **concierge** | Meeting prep and transcripts | Every 10 min |
83
- | **librarian** | Knowledge graph maintenance | Every 15 min |
84
- | **recruiter** | Engineering recruitment | Every 30 min |
85
- | **head-hunter** | Passive talent scouting | Every 60 min |
86
- | **chief-of-staff** | Daily briefings and priorities | 7am, Mon 7:30am |
87
-
88
- Each agent writes `~/.cache/fit/outpost/state/{agent}_triage.md` per wake. The
89
- **chief-of-staff** reads all of them to write daily briefings in `Briefings/`.
100
+ - **postman** (5 min) — communication triage and drafts
101
+ - **concierge** (10 min) meeting prep and transcripts
102
+ - **librarian** (15 min) knowledge graph maintenance
103
+ - **recruiter** (30 min) engineering recruitment
104
+ - **head-hunter** (60 min) passive talent scouting
105
+ - **chief-of-staff** (daily 7am) briefings in `Briefings/`
90
106
 
91
107
  ## Cache Directory (`~/.cache/fit/outpost/`)
92
108
 
93
- Synced data and runtime state live outside the KB. Only notes, drafts, and
94
- briefings live inside it.
95
-
96
- **Resolve `~` before you pass a path to a tool.** Shell commands expand `~`.
97
- The Write and Edit tools do not. A literal `~/...` creates a stray `.cache/`
98
- inside the KB. Read `$HOME` at runtime and pass the full `$HOME/...` path. Read
99
- meetings, emails, and messages directly from the source dirs below.
109
+ Synced data and runtime state live outside the KB. Resolve `~` to `$HOME`
110
+ for Write and Edit; search with `rg`.
100
111
 
101
- - `apple_mail/` — Mail threads as `.md` (plus `attachments/`)
102
- - `apple_calendar/` — Calendar events as `.json`
103
- - `teams_chat/` — Teams 1:1 chats as `.md`
104
- - `head-hunter/` — head-hunter agent memory
105
- - `state/` — per-source last-sync timestamps, processed-file index, and
106
- `{agent}_triage.md` per agent
112
+ - `apple_mail/`, `apple_calendar/`, `teams_chat/` — synced sources
113
+ - `head-hunter/` — agent memory
114
+ - `drafts/` — the draft-status ledgers (`handled`, `ignored`)
115
+ - `state/` — daemon-owned sync state and triage files
107
116
 
108
- ## User Identity
117
+ ## User Identity & Team
109
118
 
110
- The current user's identity lives at
111
- `~/.cache/fit/outpost/state/identity.md`. Read it directly. If the file is
112
- missing or stale, run the `person-identify` skill to refresh it from the
113
- corporate directory.
119
+ Read `~/.cache/fit/outpost/state/identity.md`; refresh with
120
+ `person-identify`. Manager plus Direct reports define "our team";
121
+ `Direct reports: none` means an individual contributor. Resolve peers with
122
+ `person-lookup` on the Manager. Never guess.