@forwardimpact/outpost 3.9.0 → 3.10.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/package.json +1 -1
- package/src/kb-manager.js +27 -1
- package/templates/.claude/agents/chief-of-staff.md +9 -7
- package/templates/.claude/agents/concierge.md +6 -4
- package/templates/.claude/agents/head-hunter.md +6 -4
- package/templates/.claude/agents/librarian.md +14 -10
- package/templates/.claude/agents/postman.md +6 -4
- package/templates/.claude/agents/recruiter.md +8 -5
- package/templates/.claude/skills/anarlog-follow/references/coaching.md +3 -3
- package/templates/.claude/skills/anarlog-trim/SKILL.md +9 -3
- package/templates/.claude/skills/candidate-report/SKILL.md +4 -3
- package/templates/.claude/skills/changelog/SKILL.md +10 -10
- package/templates/.claude/skills/deck-create/SKILL.md +23 -22
- package/templates/.claude/skills/deck-review/SKILL.md +29 -25
- package/templates/.claude/skills/doc-create/SKILL.md +17 -16
- package/templates/.claude/skills/extract-entities/SKILL.md +4 -2
- package/templates/.claude/skills/meeting-prep/SKILL.md +2 -1
- package/templates/.claude/skills/organize-files/SKILL.md +9 -5
- package/templates/.claude/skills/person-identify/SKILL.md +2 -2
- package/templates/.claude/skills/person-lookup/SKILL.md +3 -3
- package/templates/.claude/skills/req-forget/references/report-template.md +1 -1
- package/templates/.claude/skills/req-scan/references/fallbacks.md +3 -3
- package/templates/.claude/skills/req-scan/references/sources.md +5 -5
- package/templates/.claude/skills/req-track/SKILL.md +2 -2
- package/templates/.claude/skills/req-workday/references/status-mapping.md +1 -1
- package/templates/.claude/skills/sync-apple-calendar/SKILL.md +6 -2
- package/templates/.claude/skills/sync-apple-mail/SKILL.md +3 -1
- package/templates/.claude/skills/sync-apple-mail/references/SCHEMA.md +1 -1
- package/templates/.claude/skills/sync-teams/SKILL.md +13 -1
- package/templates/.claude/skills/sync-teams/scripts/idb-reader.mjs +67 -34
- package/templates/.claude/skills/upstream-instructions/SKILL.md +2 -1
- package/templates/CLAUDE.md +27 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/outpost",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "Personal operations center — context from email, calendar, and knowledge assembled so preparation is continuous, not a morning scramble.",
|
|
5
5
|
"homepage": "https://www.forwardimpact.team",
|
|
6
6
|
"repository": {
|
package/src/kb-manager.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* KBManager — knowledge base init/update operations.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { join, dirname, resolve } from "node:path";
|
|
5
|
+
import { join, dirname, resolve, basename } from "node:path";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
8
8
|
|
|
@@ -214,6 +214,7 @@ export class KBManager {
|
|
|
214
214
|
await this.#ensureDir(join(dest, d));
|
|
215
215
|
|
|
216
216
|
await this.copyBundledFiles(templateDir, dest);
|
|
217
|
+
await this.#linkIntoDocuments(dest);
|
|
217
218
|
|
|
218
219
|
this.#logger.info(
|
|
219
220
|
`Knowledge base initialized at ${dest}\n\nNext steps:\n 1. cd ${dest} && npx apm install\n 2. claude\n 3. Run the person-identify skill to populate your identity`,
|
|
@@ -221,6 +222,31 @@ export class KBManager {
|
|
|
221
222
|
return { ok: true, value: { dest } };
|
|
222
223
|
}
|
|
223
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Create a navigation symlink at `~/Documents/<name>` pointing to the KB.
|
|
227
|
+
* The KB data itself stays under the XDG data home, outside TCC-protected
|
|
228
|
+
* folders — this is only a convenience pointer so the KB is easy to find and
|
|
229
|
+
* open from Finder. Best-effort: a pre-existing entry is left untouched, and
|
|
230
|
+
* any failure (e.g. macOS denying write access to `~/Documents`) is logged,
|
|
231
|
+
* never fatal, because the KB is already provisioned at `dest`.
|
|
232
|
+
* @param {string} dest - Absolute path to the provisioned KB.
|
|
233
|
+
* @returns {Promise<void>}
|
|
234
|
+
*/
|
|
235
|
+
async #linkIntoDocuments(dest) {
|
|
236
|
+
const link = join(homedir(), "Documents", basename(dest));
|
|
237
|
+
if (await this.#exists(link)) {
|
|
238
|
+
this.#logger.info(` Skipped ${link}: already exists`);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
await this.#ensureDir(dirname(link));
|
|
243
|
+
await this.#fs.symlink(dest, link, "dir");
|
|
244
|
+
this.#logger.info(` Linked ${link} -> ${dest}`);
|
|
245
|
+
} catch (err) {
|
|
246
|
+
this.#logger.info(` Could not link into ~/Documents: ${err.message}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
224
250
|
/**
|
|
225
251
|
* Update an existing knowledge base with the latest bundled files.
|
|
226
252
|
* @param {string} targetPath
|
|
@@ -14,16 +14,18 @@ single briefing.
|
|
|
14
14
|
|
|
15
15
|
## Priorities
|
|
16
16
|
|
|
17
|
-
`Knowledge/Priorities/` is the backbone of every briefing. Read it
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
`Knowledge/Priorities/` is the backbone of every briefing. Read it and
|
|
18
|
+
`Knowledge/Conditions/` (the live constraints that shape how priorities are
|
|
19
|
+
pursued — see Operating Context in CLAUDE.md) each wake (both are also listed
|
|
20
|
+
under Inputs) and frame the whole briefing around what advances or threatens the
|
|
21
|
+
user's priorities.
|
|
20
22
|
|
|
21
23
|
- **Always consider them.** Tie the schedule, the top actions, and the pipeline
|
|
22
24
|
back to the priority each one serves.
|
|
23
25
|
- **Always escalate risks.** Consolidate every `## Priority Watch` flag from the
|
|
24
26
|
sibling triage files — plus anything you find in your own reads — into a
|
|
25
|
-
`## Priority Watch` section in the briefing, each item naming the priority,
|
|
26
|
-
evidence, and the risk. A signal that could contradict, block, or slow a
|
|
27
|
+
`## Priority Watch` section in the briefing, each item naming the priority,
|
|
28
|
+
the evidence, and the risk. A signal that could contradict, block, or slow a
|
|
27
29
|
priority is the most important thing the briefing surfaces.
|
|
28
30
|
|
|
29
31
|
## Inputs
|
|
@@ -37,7 +39,7 @@ authoritative current-state summaries:
|
|
|
37
39
|
- `~/.cache/fit/outpost/state/recruiter_triage.md`
|
|
38
40
|
- `~/.cache/fit/outpost/state/head_hunter_triage.md`
|
|
39
41
|
|
|
40
|
-
Plus directly: `Knowledge/Priorities/`, `Drafts/`,
|
|
42
|
+
Plus directly: `Knowledge/Priorities/`, `Knowledge/Conditions/`, `Drafts/`,
|
|
41
43
|
`~/.cache/fit/outpost/apple_calendar/`, and unchecked `- [ ]` items in
|
|
42
44
|
`Knowledge/`.
|
|
43
45
|
|
|
@@ -64,7 +66,7 @@ and "Still Outstanding".
|
|
|
64
66
|
|
|
65
67
|
## Output
|
|
66
68
|
|
|
67
|
-
```
|
|
69
|
+
```text
|
|
68
70
|
Decision: {morning/evening} briefing — {key insight about today}
|
|
69
71
|
Action: Created Briefings/{YYYY-MM-DD}-{morning|evening}.md
|
|
70
72
|
```
|
|
@@ -18,11 +18,13 @@ recordings.
|
|
|
18
18
|
|
|
19
19
|
## Priorities
|
|
20
20
|
|
|
21
|
-
At the start of every wake, before acting, read `Knowledge/Priorities
|
|
22
|
-
|
|
21
|
+
At the start of every wake, before acting, read `Knowledge/Priorities/` and
|
|
22
|
+
`Knowledge/Conditions/` (which constrains them — see Operating Context in
|
|
23
|
+
CLAUDE.md). The user's priorities are the lens for all your work this wake.
|
|
23
24
|
|
|
24
25
|
- **Always consider them.** Weigh each action against whether it advances a
|
|
25
|
-
priority, and favour work that does.
|
|
26
|
+
priority, and favour work that does. Let the active conditions shape how you
|
|
27
|
+
act on it.
|
|
26
28
|
- **Always flag risks.** When you encounter a chat, email, transcript, or any
|
|
27
29
|
other signal that could **contradict, block, or slow** a priority, record it
|
|
28
30
|
under a `## Priority Watch` heading in your triage report — name the priority,
|
|
@@ -53,7 +55,7 @@ over **anarlog-process** (catch-up work).
|
|
|
53
55
|
|
|
54
56
|
After acting, emit exactly:
|
|
55
57
|
|
|
56
|
-
```
|
|
58
|
+
```text
|
|
57
59
|
Decision: {what you observed and why you chose this action}
|
|
58
60
|
Action: {what you did, e.g. "meeting-prep for 2pm with Sarah Chen"}
|
|
59
61
|
Priority Watch: {priority at risk + one-line why, or "none"}
|
|
@@ -21,11 +21,13 @@ benchmark promising matches, and write prospect notes for the user to review.
|
|
|
21
21
|
|
|
22
22
|
## Priorities
|
|
23
23
|
|
|
24
|
-
At the start of every wake, before acting, read `Knowledge/Priorities
|
|
25
|
-
|
|
24
|
+
At the start of every wake, before acting, read `Knowledge/Priorities/` and
|
|
25
|
+
`Knowledge/Conditions/` (which constrains them — see Operating Context in
|
|
26
|
+
CLAUDE.md). The user's priorities are the lens for all your work this wake.
|
|
26
27
|
|
|
27
28
|
- **Always consider them.** Weigh each action against whether it advances a
|
|
28
|
-
priority, and favour work that does.
|
|
29
|
+
priority, and favour work that does. Let the active conditions shape how you
|
|
30
|
+
act on it.
|
|
29
31
|
- **Always flag risks.** When you encounter a chat, email, transcript, or any
|
|
30
32
|
other signal that could **contradict, block, or slow** a priority, record it
|
|
31
33
|
under a `## Priority Watch` heading in your triage report — name the priority,
|
|
@@ -63,7 +65,7 @@ wake — the chief-of-staff reads it.
|
|
|
63
65
|
|
|
64
66
|
## Output
|
|
65
67
|
|
|
66
|
-
```
|
|
68
|
+
```text
|
|
67
69
|
Decision: {source chosen and why}
|
|
68
70
|
Action: {what was scanned, e.g. "scanned HN Who Wants to Be Hired March 2026, 47 posts"}
|
|
69
71
|
Prospects: {N} new ({strong} strong, {moderate} moderate), {total} total
|
|
@@ -16,11 +16,13 @@ you process new data into the knowledge graph and keep everything organized.
|
|
|
16
16
|
|
|
17
17
|
## Priorities
|
|
18
18
|
|
|
19
|
-
At the start of every wake, before acting, read `Knowledge/Priorities
|
|
20
|
-
|
|
19
|
+
At the start of every wake, before acting, read `Knowledge/Priorities/` and
|
|
20
|
+
`Knowledge/Conditions/` (which constrains them — see Operating Context in
|
|
21
|
+
CLAUDE.md). The user's priorities are the lens for all your work this wake.
|
|
21
22
|
|
|
22
23
|
- **Always consider them.** Weigh each action against whether it advances a
|
|
23
|
-
priority, and favour work that does.
|
|
24
|
+
priority, and favour work that does. Let the active conditions shape how you
|
|
25
|
+
act on it.
|
|
24
26
|
- **Always flag risks.** When you encounter a chat, email, transcript, or any
|
|
25
27
|
other signal that could **contradict, block, or slow** a priority, record it
|
|
26
28
|
under a `## Priority Watch` heading in your triage report — name the priority,
|
|
@@ -31,18 +33,20 @@ user's priorities are the lens for all your work this wake.
|
|
|
31
33
|
|
|
32
34
|
Assess what needs processing:
|
|
33
35
|
|
|
34
|
-
1.
|
|
36
|
+
1. Check for unprocessed synced files (mail and calendar data):
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
```text
|
|
39
|
+
node .claude/skills/extract-entities/scripts/state.mjs check
|
|
40
|
+
```
|
|
37
41
|
|
|
38
|
-
2.
|
|
42
|
+
2. Count existing knowledge graph entities:
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
ls Knowledge/People/ Knowledge/Organizations/ Knowledge/Projects/
|
|
45
|
+
Knowledge/Topics/ Knowledge/Priorities/ 2>/dev/null | wc -l
|
|
42
46
|
|
|
43
47
|
Write triage results to `~/.cache/fit/outpost/state/librarian_triage.md`:
|
|
44
48
|
|
|
45
|
-
```
|
|
49
|
+
```text
|
|
46
50
|
# Knowledge Triage — {YYYY-MM-DD HH:MM}
|
|
47
51
|
## Pending Processing
|
|
48
52
|
- {count} unprocessed synced files
|
|
@@ -64,7 +68,7 @@ Choose the most valuable action:
|
|
|
64
68
|
|
|
65
69
|
After acting, output exactly:
|
|
66
70
|
|
|
67
|
-
```
|
|
71
|
+
```text
|
|
68
72
|
Decision: {what you observed and why you chose this action}
|
|
69
73
|
Action: {what you did, e.g. "extract-entities on 7 files"}
|
|
70
74
|
Priority Watch: {priority at risk + one-line why, or "none"}
|
|
@@ -17,11 +17,13 @@ and Teams, triage what's new, take the most valuable action.
|
|
|
17
17
|
|
|
18
18
|
## Priorities
|
|
19
19
|
|
|
20
|
-
At the start of every wake, before acting, read `Knowledge/Priorities
|
|
21
|
-
|
|
20
|
+
At the start of every wake, before acting, read `Knowledge/Priorities/` and
|
|
21
|
+
`Knowledge/Conditions/` (which constrains them — see Operating Context in
|
|
22
|
+
CLAUDE.md). The user's priorities are the lens for all your work this wake.
|
|
22
23
|
|
|
23
24
|
- **Always consider them.** Weigh each action against whether it advances a
|
|
24
|
-
priority, and favour work that does.
|
|
25
|
+
priority, and favour work that does. Let the active conditions shape how you
|
|
26
|
+
act on it.
|
|
25
27
|
- **Always flag risks.** When you encounter a chat, email, transcript, or any
|
|
26
28
|
other signal that could **contradict, block, or slow** a priority, record it
|
|
27
29
|
under a `## Priority Watch` heading in your triage report — name the priority,
|
|
@@ -54,7 +56,7 @@ email only.
|
|
|
54
56
|
|
|
55
57
|
After acting, emit exactly:
|
|
56
58
|
|
|
57
|
-
```
|
|
59
|
+
```text
|
|
58
60
|
Decision: {what you observed and why you chose this action}
|
|
59
61
|
Action: {what you did, e.g. "draft-emails for thread 123"}
|
|
60
62
|
Priority Watch: {priority at risk + one-line why, or "none"}
|
|
@@ -22,11 +22,13 @@ assessment and recommendation references the standard.
|
|
|
22
22
|
|
|
23
23
|
## Priorities
|
|
24
24
|
|
|
25
|
-
At the start of every wake, before acting, read `Knowledge/Priorities
|
|
26
|
-
|
|
25
|
+
At the start of every wake, before acting, read `Knowledge/Priorities/` and
|
|
26
|
+
`Knowledge/Conditions/` (which constrains them — see Operating Context in
|
|
27
|
+
CLAUDE.md). The user's priorities are the lens for all your work this wake.
|
|
27
28
|
|
|
28
29
|
- **Always consider them.** Weigh each action against whether it advances a
|
|
29
|
-
priority, and favour work that does.
|
|
30
|
+
priority, and favour work that does. Let the active conditions shape how you
|
|
31
|
+
act on it.
|
|
30
32
|
- **Always flag risks.** When you encounter a chat, email, transcript, or any
|
|
31
33
|
other signal that could **contradict, block, or slow** a priority, record it
|
|
32
34
|
under a `## Priority Watch` heading in your triage report — name the priority,
|
|
@@ -60,11 +62,12 @@ screen > sync. Stage 3 **never** triggers automatically — only on user request
|
|
|
60
62
|
|
|
61
63
|
Triage state goes to `~/.cache/fit/outpost/state/recruiter_triage.md` every wake
|
|
62
64
|
(the chief-of-staff reads it): needs-action by stage, recently processed
|
|
63
|
-
candidates, pipeline totals by stage/track, aggregate diversity, retention
|
|
65
|
+
candidates, pipeline totals by stage/track, aggregate diversity, retention
|
|
66
|
+
flags.
|
|
64
67
|
|
|
65
68
|
## Output
|
|
66
69
|
|
|
67
|
-
```
|
|
70
|
+
```text
|
|
68
71
|
Decision: {observation and chosen action}
|
|
69
72
|
Action: {e.g. "req-screen for John Smith against J060 forward-deployed"}
|
|
70
73
|
Stage: {1 | 2 | sync | erasure}
|
|
@@ -6,7 +6,7 @@ Reference for `anarlog-follow` Phases 2 and 3.
|
|
|
6
6
|
|
|
7
7
|
### For interviews
|
|
8
8
|
|
|
9
|
-
```
|
|
9
|
+
```text
|
|
10
10
|
Following: {Title}
|
|
11
11
|
Type: {Interview type}
|
|
12
12
|
Candidate: {Name} — {current role} at {employer}
|
|
@@ -27,7 +27,7 @@ Watching for: {specific signals at this interview stage}
|
|
|
27
27
|
|
|
28
28
|
### For general meetings
|
|
29
29
|
|
|
30
|
-
```
|
|
30
|
+
```text
|
|
31
31
|
Following: {Title}
|
|
32
32
|
Attendees: {names with roles}
|
|
33
33
|
|
|
@@ -66,7 +66,7 @@ Suggested topics:
|
|
|
66
66
|
|
|
67
67
|
Output **only when actionable**. Each nudge: 1–3 lines max.
|
|
68
68
|
|
|
69
|
-
```
|
|
69
|
+
```text
|
|
70
70
|
Probe deeper: {Name} mentioned {topic} — ask for a specific example
|
|
71
71
|
Gap: screening flagged {skill} as uncertain. Try: "{question}"
|
|
72
72
|
Confirmed: {Name} demonstrated {skill} at {level} — "{brief quote}"
|
|
@@ -46,9 +46,11 @@ Run this skill:
|
|
|
46
46
|
### Step 0 — Validate the session
|
|
47
47
|
|
|
48
48
|
1. Confirm the session directory exists:
|
|
49
|
-
|
|
49
|
+
|
|
50
|
+
```text
|
|
50
51
|
~/Library/Application Support/anarlog/sessions/{uuid}/
|
|
51
52
|
```
|
|
53
|
+
|
|
52
54
|
2. Confirm `transcript.json` exists and has at least one transcript with words.
|
|
53
55
|
3. Read `_meta.json` to get the session title for context.
|
|
54
56
|
|
|
@@ -132,7 +134,8 @@ json.dump(data, open(path, 'w'), indent=2)
|
|
|
132
134
|
```
|
|
133
135
|
|
|
134
136
|
4. Print a summary:
|
|
135
|
-
|
|
137
|
+
|
|
138
|
+
```text
|
|
136
139
|
Trimmed: {title}
|
|
137
140
|
Before: {original_words} words, {original_duration}
|
|
138
141
|
After: {new_words} words, {new_duration}
|
|
@@ -147,11 +150,14 @@ people who did not consent to being recorded. The full audio file must be
|
|
|
147
150
|
deleted to respect participant privacy.
|
|
148
151
|
|
|
149
152
|
1. Delete the audio file:
|
|
153
|
+
|
|
150
154
|
```bash
|
|
151
155
|
rm "~/Library/Application Support/anarlog/sessions/{uuid}/audio.mp3"
|
|
152
156
|
```
|
|
157
|
+
|
|
153
158
|
2. Confirm deletion and inform the user:
|
|
154
|
-
|
|
159
|
+
|
|
160
|
+
```text
|
|
155
161
|
Audio deleted: audio.mp3 removed (recording contained unconsented content beyond the meeting)
|
|
156
162
|
```
|
|
157
163
|
|
|
@@ -50,7 +50,8 @@ before deciding whether to invest interview time.
|
|
|
50
50
|
- [ ] Verdict class matches the overall assessment.
|
|
51
51
|
- [ ] Report fits on a single A4 page (browser print preview).
|
|
52
52
|
- [ ] CSS is inlined in the `<style>` block.
|
|
53
|
-
- [ ] Footer shows the author name and role from
|
|
53
|
+
- [ ] Footer shows the author name and role from
|
|
54
|
+
`~/.cache/fit/outpost/state/identity.md`.
|
|
54
55
|
- [ ] Written as if the candidate will read it; no special-category data.
|
|
55
56
|
|
|
56
57
|
</do_confirm_checklist>
|
|
@@ -61,7 +62,7 @@ before deciding whether to invest interview time.
|
|
|
61
62
|
|
|
62
63
|
Read whatever exists for the candidate:
|
|
63
64
|
|
|
64
|
-
```
|
|
65
|
+
```text
|
|
65
66
|
Knowledge/Candidates/{Name}/brief.md # required
|
|
66
67
|
Knowledge/Candidates/{Name}/screening.md # if produced by req-screen
|
|
67
68
|
Knowledge/Candidates/{Name}/interview-*.md # if produced by req-assess
|
|
@@ -118,7 +119,7 @@ preview overflows, cut content.
|
|
|
118
119
|
|
|
119
120
|
Save the completed HTML to:
|
|
120
121
|
|
|
121
|
-
```
|
|
122
|
+
```text
|
|
122
123
|
Drafts/{Recipient}-{CandidateSurname}-Report.html
|
|
123
124
|
```
|
|
124
125
|
|
|
@@ -11,8 +11,8 @@ teammates syncing the same filesystem can see what changed and why.
|
|
|
11
11
|
|
|
12
12
|
This tracks **graph content** — notes under `Knowledge/People/`,
|
|
13
13
|
`Organizations/`, `Projects/`, `Topics/`, `Candidates/`, `Priorities/`, and the
|
|
14
|
-
other subdirectories. It does **not** track changes to instructions
|
|
15
|
-
agents, skills) — that is the `upstream-instructions` skill's job.
|
|
14
|
+
other subdirectories. It does **not** track changes to instructions
|
|
15
|
+
(`CLAUDE.md`, agents, skills) — that is the `upstream-instructions` skill's job.
|
|
16
16
|
|
|
17
17
|
## Trigger
|
|
18
18
|
|
|
@@ -40,16 +40,16 @@ agents, skills) — that is the `upstream-instructions` skill's job.
|
|
|
40
40
|
|
|
41
41
|
## Ethics
|
|
42
42
|
|
|
43
|
-
`Knowledge/` is shared with the team. Every entry obeys the KB's integrity
|
|
44
|
-
objective and factual, work-relevant, no personal judgments. Assume the
|
|
45
|
-
note is about will read its changelog entry. Describe
|
|
46
|
-
graph**, not opinions about the people in it.
|
|
43
|
+
`Knowledge/` is shared with the team. Every entry obeys the KB's integrity
|
|
44
|
+
rules: objective and factual, work-relevant, no personal judgments. Assume the
|
|
45
|
+
person a note is about will read its changelog entry. Describe
|
|
46
|
+
**what changed in the graph**, not opinions about the people in it.
|
|
47
47
|
|
|
48
48
|
<do_confirm_checklist goal="Verify the changelog is accurate and shareable">
|
|
49
49
|
|
|
50
50
|
- [ ] Exactly one `Knowledge/CHANGELOG.md`; no stray per-folder changelogs.
|
|
51
|
-
- [ ] Every entry names its **Scope** — the specific note(s) or folder(s)
|
|
52
|
-
by full path.
|
|
51
|
+
- [ ] Every entry names its **Scope** — the specific note(s) or folder(s)
|
|
52
|
+
touched, by full path.
|
|
53
53
|
- [ ] Each entry has **Who** (author, from identity), **What**, and **Why**.
|
|
54
54
|
- [ ] Descriptions are specific enough to be useful (not "updated some notes").
|
|
55
55
|
- [ ] Dates are the date the change was actually made, not guessed.
|
|
@@ -104,8 +104,8 @@ Scope lists every note touched.
|
|
|
104
104
|
|
|
105
105
|
### 4. Write the changelog
|
|
106
106
|
|
|
107
|
-
Create or update `Knowledge/CHANGELOG.md` (newest first). Group entries under
|
|
108
|
-
heading per day; one bullet per logical change:
|
|
107
|
+
Create or update `Knowledge/CHANGELOG.md` (newest first). Group entries under
|
|
108
|
+
one heading per day; one bullet per logical change:
|
|
109
109
|
|
|
110
110
|
```markdown
|
|
111
111
|
# Knowledge Changelog
|
|
@@ -32,18 +32,18 @@ Run when the user asks to create a presentation, slide deck, or pitch deck.
|
|
|
32
32
|
|
|
33
33
|
## Workflow
|
|
34
34
|
|
|
35
|
-
1.
|
|
36
|
-
|
|
37
|
-
2.
|
|
38
|
-
|
|
39
|
-
3.
|
|
40
|
-
|
|
41
|
-
4.
|
|
42
|
-
5.
|
|
35
|
+
1. Check `Knowledge/` for relevant context about the company, product, team,
|
|
36
|
+
etc.
|
|
37
|
+
2. Ensure Playwright is installed:
|
|
38
|
+
`bun install playwright && bunx playwright install chromium`
|
|
39
|
+
3. Create an HTML file at `/tmp/outpost-presentation.html` with slides
|
|
40
|
+
(1280x720px each)
|
|
41
|
+
4. Include the required CSS from [references/slide.css](references/slide.css)
|
|
42
|
+
5. Run the conversion script:
|
|
43
43
|
|
|
44
44
|
node scripts/convert-to-pdf.mjs
|
|
45
45
|
|
|
46
|
-
6.
|
|
46
|
+
6. Tell the user: "Your presentation is ready at ~/Desktop/presentation.pdf"
|
|
47
47
|
|
|
48
48
|
**Do NOT show HTML code to the user. Just create the PDF and deliver it.**
|
|
49
49
|
|
|
@@ -82,28 +82,29 @@ selecting/copying text on a slide, and typing into overlay tools (e.g. the
|
|
|
82
82
|
2. **No click-to-advance.** Do NOT add click regions on the slide/stage that
|
|
83
83
|
navigate (e.g. "click left/right third"). They fire on the mouse-up that ends
|
|
84
84
|
a text-selection drag and jump the slide unexpectedly.
|
|
85
|
-
3. **No spacebar, PageUp/PageDown, or other global key bindings.** Space
|
|
86
|
-
with typing in overlay inputs; the rest are redundant and
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
3. **No spacebar, PageUp/PageDown, or other global key bindings.** Space
|
|
86
|
+
conflicts with typing in overlay inputs; the rest are redundant and
|
|
87
|
+
surprising.
|
|
88
|
+
4. **A progress indicator may be clickable**, but it must live in the
|
|
89
|
+
footer/chrome and never overlap slide content.
|
|
89
90
|
5. **Expose `window.deckGoto(index)`** (0-based) right after the slide-show
|
|
90
|
-
function, so review/overlay tools can jump to a slide without simulating
|
|
91
|
-
or keys:
|
|
91
|
+
function, so review/overlay tools can jump to a slide without simulating
|
|
92
|
+
clicks or keys:
|
|
92
93
|
|
|
93
94
|
function go(n) { /* ...show slide n... */ }
|
|
94
95
|
window.deckGoto = go;
|
|
95
96
|
|
|
96
|
-
6. **Keep the hint honest** — the on-screen nav hint should read
|
|
97
|
-
(don't advertise click/space).
|
|
97
|
+
6. **Keep the hint honest** — the on-screen nav hint should read
|
|
98
|
+
`← → to navigate` (don't advertise click/space).
|
|
98
99
|
7. **Use stable structural hooks.** Make each slide one element with class
|
|
99
100
|
`.slide`, and put the slide-number label (if any) in a `.slide-num` element.
|
|
100
101
|
The review overlay defaults to these selectors to detect and index slides.
|
|
101
102
|
|
|
102
|
-
These rules keep decks compatible with the **`deck-review`** skill, which
|
|
103
|
-
the `slide-annotator.js` review overlay (highlight text on a slide →
|
|
104
|
-
of feedback that an agent acts on). After producing an interactive
|
|
105
|
-
can offer to run `deck-review` to make it reviewable; see that
|
|
106
|
-
install steps and the sidecar JSON schema.
|
|
103
|
+
These rules keep decks compatible with the **`deck-review`** skill, which
|
|
104
|
+
installs the `slide-annotator.js` review overlay (highlight text on a slide →
|
|
105
|
+
sidecar JSON of feedback that an agent acts on). After producing an interactive
|
|
106
|
+
HTML deck, you can offer to run `deck-review` to make it reviewable; see that
|
|
107
|
+
skill for the install steps and the sidecar JSON schema.
|
|
107
108
|
|
|
108
109
|
## Constraints
|
|
109
110
|
|
|
@@ -8,9 +8,10 @@ compatibility: Standalone HTML deck opened in a Chromium-based browser (Chrome/E
|
|
|
8
8
|
|
|
9
9
|
Install the self-contained `slide-annotator.js` overlay onto an HTML deck so the
|
|
10
10
|
user can **highlight text on a slide and save the feedback as a sidecar JSON**.
|
|
11
|
-
Each annotation carries a robust anchor (exact text + surrounding context +
|
|
12
|
-
and, once the folder is connected, the resolved
|
|
13
|
-
lines** — so an agent can locate and edit the
|
|
11
|
+
Each annotation carries a robust anchor (exact text + surrounding context +
|
|
12
|
+
slide) and, once the folder is connected, the resolved
|
|
13
|
+
**source line, column and context lines** — so an agent can locate and edit the
|
|
14
|
+
exact text in small iterations.
|
|
14
15
|
|
|
15
16
|
This is the companion to **`deck-create`**: decks produced by `deck-create`
|
|
16
17
|
already follow the navigation/structure standards this overlay needs, and this
|
|
@@ -19,8 +20,8 @@ overlay is designed to drop onto them with one script tag.
|
|
|
19
20
|
## Trigger
|
|
20
21
|
|
|
21
22
|
Run when the user asks to add review / annotation / highlight / comment / markup
|
|
22
|
-
capability to a deck, "make this deck reviewable", or to set up a feedback loop
|
|
23
|
-
slides.
|
|
23
|
+
capability to a deck, "make this deck reviewable", or to set up a feedback loop
|
|
24
|
+
on slides.
|
|
24
25
|
|
|
25
26
|
## Inputs
|
|
26
27
|
|
|
@@ -46,10 +47,10 @@ slides.
|
|
|
46
47
|
- **Slide selector** — each slide is one element with a stable class
|
|
47
48
|
(default `.slide`). If the deck uses a different class, note it for step 4.
|
|
48
49
|
- **Navigation hook** — the deck exposes `window.deckGoto(index)` (0-based).
|
|
49
|
-
If it has a slideshow function (e.g. `go(n)`) but no hook, add one line
|
|
50
|
-
after it: `window.deckGoto = go;`. Without it the overlay still works
|
|
51
|
-
panel's *Go* button falls back to `scrollIntoView`), but it can't jump
|
|
52
|
-
hidden slide precisely.
|
|
50
|
+
If it has a slideshow function (e.g. `go(n)`) but no hook, add one line
|
|
51
|
+
right after it: `window.deckGoto = go;`. Without it the overlay still works
|
|
52
|
+
(the panel's *Go* button falls back to `scrollIntoView`), but it can't jump
|
|
53
|
+
to a hidden slide precisely.
|
|
53
54
|
- Optionally a slide-number label element (default `.slide-num`) for nicer
|
|
54
55
|
labels in the panel — purely cosmetic.
|
|
55
56
|
|
|
@@ -57,8 +58,8 @@ slides.
|
|
|
57
58
|
**same directory as the deck**. Resolve `~` to `$HOME`; pass the Write/copy a
|
|
58
59
|
full path.
|
|
59
60
|
|
|
60
|
-
4. **Inject the script tag** immediately before `</body>` (idempotent — skip if
|
|
61
|
-
`slide-annotator` script tag is already present):
|
|
61
|
+
4. **Inject the script tag** immediately before `</body>` (idempotent — skip if
|
|
62
|
+
a `slide-annotator` script tag is already present):
|
|
62
63
|
|
|
63
64
|
```html
|
|
64
65
|
<!-- Review overlay: highlight text on a slide → sidecar JSON. Self-contained, optional. -->
|
|
@@ -86,21 +87,23 @@ follow:
|
|
|
86
87
|
| Navigation hook | `window.deckGoto(index)` (0-based) | panel "Go" jumps to the right slide |
|
|
87
88
|
| Arrow-keys-only navigation, **no** click-to-advance / spacebar | — | text selection + typing in the overlay must not move slides |
|
|
88
89
|
|
|
89
|
-
If a deck violates the last row (has click-to-advance), the overlay's click
|
|
90
|
-
only suppresses the click that ends a text-selection drag, so it degrades
|
|
90
|
+
If a deck violates the last row (has click-to-advance), the overlay's click
|
|
91
|
+
guard only suppresses the click that ends a text-selection drag, so it degrades
|
|
91
92
|
gracefully — but the correct fix is to make the deck arrow-keys-only per
|
|
92
93
|
`deck-create`'s *Navigation & Event Standards*.
|
|
93
94
|
|
|
94
95
|
## Using the overlay (tell the user)
|
|
95
96
|
|
|
96
97
|
1. Open the deck in Chrome and click **✎ Review** (bottom-left).
|
|
97
|
-
2. **Select text** on a slide → a popover lets you add an optional note →
|
|
98
|
-
The highlight appears and **autosaves to `localStorage`**
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
2. **Select text** on a slide → a popover lets you add an optional note →
|
|
99
|
+
**Add**. The highlight appears and **autosaves to `localStorage`**
|
|
100
|
+
immediately.
|
|
101
|
+
3. Click **Connect folder** once and pick the deck's folder. From then on
|
|
102
|
+
**Save** writes a real `‹deck›.annotations.json` next to the deck, and the
|
|
103
|
+
tool reads the deck's own source to fill in
|
|
104
|
+
**source line / column / context** for each highlight. (If the browser blocks
|
|
105
|
+
folder access on `file://`, **Save** downloads the JSON instead — move it
|
|
106
|
+
next to the deck.)
|
|
104
107
|
4. Navigation while reviewing is the deck's normal **← / →** (the overlay's own
|
|
105
108
|
keystrokes never leak to the deck).
|
|
106
109
|
|
|
@@ -143,14 +146,15 @@ When the user says "work the annotations":
|
|
|
143
146
|
|
|
144
147
|
## Removing the overlay (for final delivery)
|
|
145
148
|
|
|
146
|
-
To hand off a clean presentation, delete the injected
|
|
147
|
-
line and the `slide-annotator.js` file.
|
|
148
|
-
the deck is harmless.
|
|
149
|
+
To hand off a clean presentation, delete the injected
|
|
150
|
+
`<script src="slide-annotator.js" …>` line and the `slide-annotator.js` file.
|
|
151
|
+
Leaving the `window.deckGoto = go;` line in the deck is harmless.
|
|
149
152
|
|
|
150
153
|
## Constraints
|
|
151
154
|
|
|
152
155
|
- Keep `slide-annotator.js` **dependency-free and host-agnostic** — it must work
|
|
153
156
|
on any static HTML page, not just `deck-create` output.
|
|
154
|
-
- Edit the tool **here** (`assets/slide-annotator.js`) as the source of truth,
|
|
155
|
-
re-install onto decks. Don't fork per-deck copies with divergent
|
|
157
|
+
- Edit the tool **here** (`assets/slide-annotator.js`) as the source of truth,
|
|
158
|
+
then re-install onto decks. Don't fork per-deck copies with divergent
|
|
159
|
+
behavior.
|
|
156
160
|
- Never auto-send or upload annotations anywhere — the sidecar JSON stays local.
|
|
@@ -34,22 +34,23 @@ submission, brief, or any multi-page PDF that is not a slide deck.
|
|
|
34
34
|
|
|
35
35
|
## Workflow
|
|
36
36
|
|
|
37
|
-
1.
|
|
38
|
-
|
|
39
|
-
2.
|
|
40
|
-
|
|
41
|
-
3.
|
|
42
|
-
|
|
43
|
-
4.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
37
|
+
1. Check `Knowledge/` for relevant context about the company, product, team,
|
|
38
|
+
projects, or people mentioned.
|
|
39
|
+
2. Ensure Playwright is installed:
|
|
40
|
+
`bun install playwright && bunx playwright install chromium`
|
|
41
|
+
3. Create a self-contained HTML file with all CSS inlined. The HTML must handle
|
|
42
|
+
its own page layout — see **HTML Document Rules** below.
|
|
43
|
+
4. Run the conversion script:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
node .claude/skills/doc-create/scripts/convert-to-pdf.mjs <input.html> [output.pdf]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
If output is omitted, the PDF is written alongside the HTML file with the
|
|
50
|
+
same name.
|
|
51
|
+
5. Read the PDF back to visually verify it renders correctly. Check each page
|
|
52
|
+
for overflow, clipped content, and correct page breaks. Fix and re-render if
|
|
53
|
+
needed.
|
|
53
54
|
|
|
54
55
|
**Do NOT show HTML code to the user. Just create the PDF and deliver it.**
|
|
55
56
|
|
|
@@ -76,7 +76,8 @@ writes.
|
|
|
76
76
|
### 0. Load context and pick the batch
|
|
77
77
|
|
|
78
78
|
Read the user's identity from `~/.cache/fit/outpost/state/identity.md` (run the
|
|
79
|
-
`person-identify` skill first if it is missing or stale). Find new/changed
|
|
79
|
+
`person-identify` skill first if it is missing or stale). Find new/changed
|
|
80
|
+
files:
|
|
80
81
|
|
|
81
82
|
```bash
|
|
82
83
|
node scripts/state.mjs check
|
|
@@ -151,7 +152,8 @@ filler or meta-commentary.
|
|
|
151
152
|
domain-lead inference):
|
|
152
153
|
[references/recruitment.md](references/recruitment.md).
|
|
153
154
|
- **Priority links** (Step 7c): rules in
|
|
154
|
-
[references/links.md](references/links.md#priorities-step-7c).
|
|
155
|
+
[references/links.md](references/links.md#priorities-step-7c).
|
|
156
|
+
**Never auto-create.**
|
|
155
157
|
- **Conditions** (cross-cutting states affecting ≥ 3 entities):
|
|
156
158
|
[references/conditions.md](references/conditions.md).
|
|
157
159
|
|
|
@@ -25,7 +25,8 @@ meetings.
|
|
|
25
25
|
- `Knowledge/People/*.md` — attendee context
|
|
26
26
|
- `Knowledge/Organizations/*.md` — company context
|
|
27
27
|
- `Knowledge/Projects/*.md` — project context
|
|
28
|
-
- `Knowledge/Priorities/*.md` — active priorities and strategic context for
|
|
28
|
+
- `Knowledge/Priorities/*.md` — active priorities and strategic context for
|
|
29
|
+
framing
|
|
29
30
|
- `Knowledge/Candidates/*/brief.md` — candidate context (for interview meetings)
|
|
30
31
|
- `Knowledge/Roles/*.md` — role/requisition context (for interview meetings)
|
|
31
32
|
|
|
@@ -61,7 +61,9 @@ Run when the user asks to find, organize, clean up, or tidy files on their Mac.
|
|
|
61
61
|
|
|
62
62
|
Get an overview of both directories:
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
```text
|
|
65
|
+
node scripts/summarize.mjs
|
|
66
|
+
```
|
|
65
67
|
|
|
66
68
|
## Finding Files
|
|
67
69
|
|
|
@@ -79,8 +81,10 @@ find ~/Desktop -maxdepth 1 \( -name "Screenshot*" -o -name "Screen Shot*" \)
|
|
|
79
81
|
Organize a directory into type-based subdirectories (Documents, Images,
|
|
80
82
|
Archives, Installers, Screenshots):
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
```text
|
|
85
|
+
node scripts/organize-by-type.mjs ~/Downloads
|
|
86
|
+
node scripts/organize-by-type.mjs ~/Desktop
|
|
87
|
+
```
|
|
84
88
|
|
|
85
89
|
The script creates subdirectories and moves matching files. It does NOT delete
|
|
86
90
|
anything.
|
|
@@ -106,7 +110,7 @@ After organizing, collect the paths of document files and invoke the
|
|
|
106
110
|
|
|
107
111
|
**Plan:**
|
|
108
112
|
|
|
109
|
-
```
|
|
113
|
+
```text
|
|
110
114
|
Organization Plan: Desktop & Downloads Cleanup
|
|
111
115
|
|
|
112
116
|
Found 47 files to organize:
|
|
@@ -123,7 +127,7 @@ Should I proceed?
|
|
|
123
127
|
|
|
124
128
|
**Results:**
|
|
125
129
|
|
|
126
|
-
```
|
|
130
|
+
```text
|
|
127
131
|
Organization Complete
|
|
128
132
|
|
|
129
133
|
Moved 47 files:
|
|
@@ -98,7 +98,7 @@ Key attributes returned (names per Active Directory schema):
|
|
|
98
98
|
|
|
99
99
|
- To look up **someone else**, use the sibling `person-lookup` skill — it takes
|
|
100
100
|
free-text input (email or name), searches the Global Catalog forest-wide
|
|
101
|
-
(`ldap://$dc:3268 -b ''`), handles multiple matches, and does **not** touch
|
|
102
|
-
identity cache.
|
|
101
|
+
(`ldap://$dc:3268 -b ''`), handles multiple matches, and does **not** touch
|
|
102
|
+
the identity cache.
|
|
103
103
|
- Not Active Directory? The same `ldapsearch -Y GSSAPI` shape works against any
|
|
104
104
|
Kerberos-backed LDAP directory; only the attribute names differ.
|
|
@@ -86,9 +86,9 @@ The argument is free text: an email, a full name, or just a surname.
|
|
|
86
86
|
since the OU convention is organization-specific. Narrow with an email for an
|
|
87
87
|
exact hit.
|
|
88
88
|
- **Silent partial results.** Under load the directory occasionally returns an
|
|
89
|
-
entry's DN with no attributes (exit 0, no error). Every attribute fetch
|
|
90
|
-
with backoff, so a throttled response never masquerades as a person
|
|
91
|
-
blank title or email.
|
|
89
|
+
entry's DN with no attributes (exit 0, no error). Every attribute fetch
|
|
90
|
+
retries with backoff, so a throttled response never masquerades as a person
|
|
91
|
+
with a blank title or email.
|
|
92
92
|
- **No cache.** This skill prints and exits. It never touches
|
|
93
93
|
`~/.cache/fit/outpost/state/identity.md` — that file is owned solely by
|
|
94
94
|
`person-identify`.
|
|
@@ -18,7 +18,7 @@ limits.
|
|
|
18
18
|
|
|
19
19
|
Search by skill + availability:
|
|
20
20
|
|
|
21
|
-
```
|
|
21
|
+
```text
|
|
22
22
|
WebFetch URL: https://api.github.com/search/users?q=%22data+engineering%22+%22open+to+work%22&per_page=30&sort=joined&order=desc
|
|
23
23
|
WebFetch URL: https://api.github.com/search/users?q=%22full+stack%22+%22available+for+hire%22&per_page=30&sort=joined&order=desc
|
|
24
24
|
WebFetch URL: https://api.github.com/search/users?q=%22devops%22+%22looking+for%22&per_page=30&sort=joined&order=desc
|
|
@@ -26,7 +26,7 @@ WebFetch URL: https://api.github.com/search/users?q=%22devops%22+%22looking+for%
|
|
|
26
26
|
|
|
27
27
|
Search repos with README signals:
|
|
28
28
|
|
|
29
|
-
```
|
|
29
|
+
```text
|
|
30
30
|
WebFetch URL: https://api.github.com/search/repositories?q=%22hire+me%22+in:readme&sort=updated&order=desc&per_page=10
|
|
31
31
|
```
|
|
32
32
|
|
|
@@ -38,7 +38,7 @@ Manchester, Edinburgh.
|
|
|
38
38
|
Try broader tags: `jobsearch`, `career`, `remotework`, `job`, `hiring`. Or pull
|
|
39
39
|
from a tag and filter by title/description:
|
|
40
40
|
|
|
41
|
-
```
|
|
41
|
+
```text
|
|
42
42
|
WebFetch URL: https://dev.to/api/articles?tag=career&per_page=25
|
|
43
43
|
```
|
|
44
44
|
|
|
@@ -6,14 +6,14 @@ Reference for `req-scan` Step 2 (fetch & scan). One source per wake cycle.
|
|
|
6
6
|
|
|
7
7
|
Monthly thread, posted on the 1st.
|
|
8
8
|
|
|
9
|
-
```
|
|
9
|
+
```text
|
|
10
10
|
WebFetch URL: https://hn.algolia.com/api/v1/search?query=%22Who+wants+to+be+hired%22&tags=ask_hn&hitsPerPage=5
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
The first hit whose title matches "Who wants to be hired?" with `created_at` in
|
|
14
14
|
the current or previous month is the target thread.
|
|
15
15
|
|
|
16
|
-
```
|
|
16
|
+
```text
|
|
17
17
|
WebFetch URL: https://hn.algolia.com/api/v1/items/{objectID}
|
|
18
18
|
```
|
|
19
19
|
|
|
@@ -34,7 +34,7 @@ WebFetch URL: https://hn.algolia.com/api/v1/items/{objectID}
|
|
|
34
34
|
|
|
35
35
|
Search by location (rotate one query per wake):
|
|
36
36
|
|
|
37
|
-
```
|
|
37
|
+
```text
|
|
38
38
|
WebFetch URL: https://api.github.com/search/users?q=%22open+to+work%22+location:UK&per_page=30&sort=joined&order=desc
|
|
39
39
|
WebFetch URL: https://api.github.com/search/users?q=%22open+to+work%22+location:Europe&per_page=30&sort=joined&order=desc
|
|
40
40
|
WebFetch URL: https://api.github.com/search/users?q=%22looking+for+work%22+location:remote&per_page=30&sort=joined&order=desc
|
|
@@ -47,7 +47,7 @@ Alternate bio phrases to rotate across wakes: `"available for hire"`,
|
|
|
47
47
|
|
|
48
48
|
Fetch each promising candidate's full profile:
|
|
49
49
|
|
|
50
|
-
```
|
|
50
|
+
```text
|
|
51
51
|
WebFetch URL: https://api.github.com/users/{login}
|
|
52
52
|
```
|
|
53
53
|
|
|
@@ -60,7 +60,7 @@ profiles per wake (1 search + 5 profile fetches = 6 requests).
|
|
|
60
60
|
|
|
61
61
|
## 3. dev.to
|
|
62
62
|
|
|
63
|
-
```
|
|
63
|
+
```text
|
|
64
64
|
WebFetch URL: https://dev.to/api/articles?tag=opentowork&per_page=25
|
|
65
65
|
WebFetch URL: https://dev.to/api/articles?tag=lookingforwork&per_page=25
|
|
66
66
|
```
|
|
@@ -71,8 +71,8 @@ Process **10 files per run**.
|
|
|
71
71
|
### 1. Load context and pick the batch
|
|
72
72
|
|
|
73
73
|
Read the user's name, email, and domain from
|
|
74
|
-
`~/.cache/fit/outpost/state/identity.md` (run the `person-identify` skill first
|
|
75
|
-
it is missing or stale). List new or changed source files:
|
|
74
|
+
`~/.cache/fit/outpost/state/identity.md` (run the `person-identify` skill first
|
|
75
|
+
if it is missing or stale). List new or changed source files:
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
78
|
node .claude/skills/extract-entities/scripts/state.mjs check
|
|
@@ -30,7 +30,7 @@ Empty or unrecognized step → default to `new`.
|
|
|
30
30
|
The raw `step` value is always preserved in the parser's JSON output and must be
|
|
31
31
|
stored in the candidate brief's `## Pipeline` section, e.g.
|
|
32
32
|
|
|
33
|
-
```
|
|
33
|
+
```text
|
|
34
34
|
- **2026-02-10**: Applied via LinkedIn — Step: Manager Request to Move Forward (HS)
|
|
35
35
|
```
|
|
36
36
|
|
|
@@ -41,7 +41,9 @@ Run the sync as a single Node.js script with embedded SQLite. This avoids N+1
|
|
|
41
41
|
process invocations (one per event for attendees) and handles all data
|
|
42
42
|
transformation in one pass:
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
```text
|
|
45
|
+
node scripts/sync.mjs [--days N]
|
|
46
|
+
```
|
|
45
47
|
|
|
46
48
|
- `--days N` — how many days back to sync (default: 30)
|
|
47
49
|
|
|
@@ -101,7 +103,9 @@ Each `{event_id}.json` file:
|
|
|
101
103
|
After syncing, use the query script to filter events by date or time window.
|
|
102
104
|
**Agents should use this script instead of writing bespoke calendar parsers.**
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
```text
|
|
107
|
+
node scripts/query.mjs [options]
|
|
108
|
+
```
|
|
105
109
|
|
|
106
110
|
### Time filters (combinable)
|
|
107
111
|
|
|
@@ -48,7 +48,9 @@ their email.
|
|
|
48
48
|
Run the sync as a single Node.js script with embedded SQLite. This avoids N+1
|
|
49
49
|
process invocations and handles all data transformation in one pass:
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
```text
|
|
52
|
+
node scripts/sync.mjs [--days N]
|
|
53
|
+
```
|
|
52
54
|
|
|
53
55
|
- `--days N` — how many days back to look on first sync (default: 30)
|
|
54
56
|
|
|
@@ -48,7 +48,9 @@ their Teams chats.
|
|
|
48
48
|
|
|
49
49
|
Run the sync as a single Node.js script:
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
```text
|
|
52
|
+
node scripts/sync.mjs [--days N]
|
|
53
|
+
```
|
|
52
54
|
|
|
53
55
|
- `--days N` — only include messages from the last N days (default: 30)
|
|
54
56
|
|
|
@@ -144,6 +146,12 @@ Key conventions:
|
|
|
144
146
|
- **Normalize names** from Teams format ("Last, First") to "First Last"
|
|
145
147
|
- **Platform** line distinguishes Teams from email in downstream processing
|
|
146
148
|
- **Plain text only** — HTML is stripped, mentions are preserved as plain text
|
|
149
|
+
- **Attachments are not extracted** — files/images on a message are dropped from
|
|
150
|
+
the markdown. They are hosted on SharePoint/OneDrive, not in the local cache.
|
|
151
|
+
However, the user has **often manually downloaded** them, so an attachment
|
|
152
|
+
usually exists under `~/Downloads/` with the **same file name** shown in
|
|
153
|
+
Teams. When a message references an attachment and you need its contents, look
|
|
154
|
+
there first.
|
|
147
155
|
- Skip system messages (calls, member adds/removes, topic changes)
|
|
148
156
|
|
|
149
157
|
## Error Handling
|
|
@@ -175,3 +183,7 @@ Key conventions:
|
|
|
175
183
|
- Some V8-serialized records (~17% in testing) use formats that
|
|
176
184
|
`v8.deserialize()` cannot decode. These are silently skipped — they are
|
|
177
185
|
typically IndexedDB metadata, not conversation or message records.
|
|
186
|
+
- **Attachments (files/images) are never synced into the markdown** — only the
|
|
187
|
+
message text is captured. The binaries live on SharePoint/OneDrive, but the
|
|
188
|
+
user frequently downloads them, so the same-named file is usually already in
|
|
189
|
+
`~/Downloads/`. Check there before trying to fetch from SharePoint.
|
|
@@ -31,56 +31,89 @@ function readIdbVarint(buf, offset) {
|
|
|
31
31
|
return { value: result, bytesRead: pos - offset };
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Highest V8 serialization wire-format version Node's bundled v8.deserialize
|
|
35
|
+
// accepts. Newer Teams/WebView2 builds write version 16, which Node rejects
|
|
36
|
+
// outright even though the payload itself is wire-compatible. We patch the
|
|
37
|
+
// version byte down to this value before deserializing. Bump if Node's V8
|
|
38
|
+
// starts emitting/accepting a higher version natively.
|
|
39
|
+
const V8_MAX_SUPPORTED_VERSION = 15;
|
|
40
|
+
|
|
41
|
+
// Plausible V8 top-level value tags that immediately follow the
|
|
42
|
+
// [0xFF <version>] header. Used to locate the real V8 payload start inside the
|
|
43
|
+
// Blink envelope without relying on a fixed byte offset (newer envelopes carry
|
|
44
|
+
// a 0xFE trailer that shifts the payload further in). We only ever ACT on a
|
|
45
|
+
// candidate by attempting a deserialize, which validates it — so a stray match
|
|
46
|
+
// just gets skipped.
|
|
47
|
+
const V8_TOP_LEVEL_TAGS = new Set([
|
|
48
|
+
0x6f, // 'o' begin JS object
|
|
49
|
+
0x22, // '"' one-byte string
|
|
50
|
+
0x63, // 'c' two-byte string
|
|
51
|
+
0x44, // 'D' utf8 string
|
|
52
|
+
0x49, // 'I' int32
|
|
53
|
+
0x55, // 'U' uint32
|
|
54
|
+
0x4e, // 'N' number (double)
|
|
55
|
+
0x6c, // 'l' bigint
|
|
56
|
+
0x7b, // '{' begin map
|
|
57
|
+
0x41, // 'A' begin dense array
|
|
58
|
+
0x61, // 'a' begin sparse array
|
|
59
|
+
0x5f, // '_' undefined
|
|
60
|
+
0x54, // 'T' true
|
|
61
|
+
0x46, // 'F' false
|
|
62
|
+
0x30, // '0' null
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
// Only the Blink envelope precedes the V8 payload, and it is always small.
|
|
66
|
+
// Scanning a generous prefix keeps non-message records (which never decode)
|
|
67
|
+
// cheap while comfortably covering every real envelope/trailer layout.
|
|
68
|
+
const V8_START_SCAN_LIMIT = 256;
|
|
69
|
+
|
|
34
70
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
71
|
+
* Deserialize the V8 payload starting at `off`. Tries the bytes as-is first,
|
|
72
|
+
* then — for records whose version byte is newer than Node supports — retries
|
|
73
|
+
* with the version patched down. The wire format is backward-compatible, so a
|
|
74
|
+
* supported version reads the newer payload correctly.
|
|
38
75
|
*/
|
|
39
|
-
function
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
76
|
+
function deserializeAt(rawValue, off) {
|
|
77
|
+
try {
|
|
78
|
+
return v8.deserialize(rawValue.subarray(off));
|
|
79
|
+
} catch {
|
|
80
|
+
// fall through to version patching
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const version = rawValue[off + 1];
|
|
84
|
+
if (version > V8_MAX_SUPPORTED_VERSION) {
|
|
85
|
+
const patched = Buffer.from(rawValue.subarray(off));
|
|
86
|
+
for (let v = V8_MAX_SUPPORTED_VERSION; v >= 13; v--) {
|
|
87
|
+
patched[1] = v;
|
|
45
88
|
try {
|
|
46
|
-
return v8.deserialize(
|
|
89
|
+
return v8.deserialize(patched);
|
|
47
90
|
} catch {
|
|
48
|
-
//
|
|
91
|
+
// try the next-lower version
|
|
49
92
|
}
|
|
50
93
|
}
|
|
51
94
|
}
|
|
52
95
|
return null;
|
|
53
96
|
}
|
|
54
97
|
|
|
55
|
-
/**
|
|
56
|
-
* Fallback: try deserializing from every 0xFF position within `limit` bytes.
|
|
57
|
-
*/
|
|
58
|
-
function deserializeFromAnyMarker(rawValue, limit) {
|
|
59
|
-
for (let i = 0; i < limit; i++) {
|
|
60
|
-
if (rawValue[i] !== 0xff) continue;
|
|
61
|
-
try {
|
|
62
|
-
return v8.deserialize(rawValue.subarray(i));
|
|
63
|
-
} catch {
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
98
|
/**
|
|
71
99
|
* Try to deserialize a Chromium IndexedDB value.
|
|
72
|
-
*
|
|
73
|
-
*
|
|
100
|
+
*
|
|
101
|
+
* Values have a Blink envelope (and, in newer WebView2 builds, a 0xFE trailer)
|
|
102
|
+
* before the V8 payload. Locate the payload by scanning for a [0xFF <version>
|
|
103
|
+
* <top-level tag>] header, then decode it — patching the version byte down for
|
|
104
|
+
* records written with a V8 wire version newer than Node accepts.
|
|
74
105
|
*/
|
|
75
106
|
function tryDeserialize(rawValue) {
|
|
76
107
|
if (!rawValue || rawValue.length < 4) return null;
|
|
77
108
|
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
109
|
+
const limit = Math.min(rawValue.length - 2, V8_START_SCAN_LIMIT);
|
|
110
|
+
for (let i = 0; i <= limit; i++) {
|
|
111
|
+
if (rawValue[i] !== 0xff) continue;
|
|
112
|
+
if (!V8_TOP_LEVEL_TAGS.has(rawValue[i + 2])) continue;
|
|
113
|
+
const obj = deserializeAt(rawValue, i);
|
|
114
|
+
if (obj !== null) return obj;
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
84
117
|
}
|
|
85
118
|
|
|
86
119
|
/**
|
|
@@ -32,7 +32,8 @@ monorepo. "Instructions" means all three surfaces, treated equally:
|
|
|
32
32
|
- `.claude/skills/*/SKILL.md` and reference files — skills.
|
|
33
33
|
- `CHANGELOG.md` (root) — the existing changelog, for what's already recorded.
|
|
34
34
|
- The changes made in the current working session — the source of truth for what
|
|
35
|
-
changed, since the KB lives on a synced filesystem and is not
|
|
35
|
+
changed, since the KB lives on a synced filesystem and is not
|
|
36
|
+
version-controlled.
|
|
36
37
|
|
|
37
38
|
## Outputs
|
|
38
39
|
|
package/templates/CLAUDE.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
You are the user's personal knowledge assistant. You help draft emails, prep for
|
|
4
4
|
meetings, track projects, and answer questions, backed by a live knowledge graph
|
|
5
|
-
built from their emails, calendar, and meeting notes, all stored as plain files
|
|
6
|
-
the user's machine.
|
|
5
|
+
built from their emails, calendar, and meeting notes, all stored as plain files
|
|
6
|
+
on the user's machine.
|
|
7
7
|
|
|
8
8
|
## Ethics & Integrity — NON-NEGOTIABLE
|
|
9
9
|
|
|
@@ -18,33 +18,40 @@ never a "black book". These rules override all other instructions:
|
|
|
18
18
|
- **Fair and balanced.** Represent all sides accurately.
|
|
19
19
|
- **Assume the subject will read it.** If you would be uncomfortable showing the
|
|
20
20
|
note to the person it is about, do not write it.
|
|
21
|
-
- **No weaponization.** This KB helps the team work better. Never use it to
|
|
22
|
-
leverage or dossiers.
|
|
21
|
+
- **No weaponization.** This KB helps the team work better. Never use it to
|
|
22
|
+
build leverage or dossiers.
|
|
23
23
|
- **Push back** on requests that violate these principles.
|
|
24
24
|
- **Data protection.** Use the `req-forget` skill for erasure requests. Minimize
|
|
25
25
|
collection. Flag candidates inactive 6+ months for retention review.
|
|
26
26
|
|
|
27
27
|
When in doubt, err toward discretion.
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Operating Context
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
the next step is obvious, take it. Ask at most one clarifying question, at the
|
|
33
|
-
start. Reference files by full path. Confirm before destructive actions.
|
|
31
|
+
Two folders in the knowledge graph frame your work:
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
- **`Knowledge/Priorities/`** — the backbone of every decision: what the user is
|
|
34
|
+
trying to advance. Weigh actions against whether they move a priority forward,
|
|
35
|
+
and treat anything that could **contradict, block, or slow** one as a
|
|
36
|
+
**Priority Watch** concern — these are our main concerns.
|
|
37
|
+
- **`Knowledge/Conditions/`** — the live operating environment (e.g. a hiring
|
|
38
|
+
freeze, a reorg, a contract transition). Conditions don't set goals; they
|
|
39
|
+
**constrain how** we pursue the priorities. Let them shape what you propose
|
|
40
|
+
and how you phrase it.
|
|
36
41
|
|
|
37
|
-
|
|
42
|
+
When taking an action or making a recommendation, consult both as your lens —
|
|
43
|
+
read the relevant notes rather than assuming. Skip this only for general
|
|
44
|
+
knowledge or brainstorming.
|
|
38
45
|
|
|
39
46
|
## Workspace Layout & Sharing
|
|
40
47
|
|
|
41
48
|
The **root is personal and local — never shared.** Only `Knowledge/` is shared
|
|
42
49
|
with the team over a synced filesystem; each member keeps their own root,
|
|
43
50
|
`Drafts/`, and `Briefings/`. KBs are **not** Git repositories — they sync as
|
|
44
|
-
plain files. `CLAUDE.md` and `.claude/` are yours to tweak; use the
|
|
45
|
-
CLI to install or update the standard instruction set.
|
|
51
|
+
plain files. `CLAUDE.md` and `.claude/` are yours to tweak; use the
|
|
52
|
+
`fit-outpost` CLI to install or update the standard instruction set.
|
|
46
53
|
|
|
47
|
-
```
|
|
54
|
+
```text
|
|
48
55
|
./ # Personal root — never shared
|
|
49
56
|
├── CLAUDE.md # This file
|
|
50
57
|
├── .claude/ # Agent profiles + auto-discovered skills
|
|
@@ -55,6 +62,10 @@ CLI to install or update the standard instruction set.
|
|
|
55
62
|
└── .mcp.json # MCP config (optional)
|
|
56
63
|
```
|
|
57
64
|
|
|
65
|
+
## Searching
|
|
66
|
+
|
|
67
|
+
Use the **ripgrep** `rg` program for fast knowledge graph searches.
|
|
68
|
+
|
|
58
69
|
## Agents
|
|
59
70
|
|
|
60
71
|
Agents in `.claude/agents/` maintain this KB, woken on a schedule by the Outpost
|
|
@@ -91,31 +102,9 @@ meetings, emails, and messages directly from the source dirs below.
|
|
|
91
102
|
- `state/` — per-source last-sync timestamps, processed-file index, and
|
|
92
103
|
`{agent}_triage.md` per agent
|
|
93
104
|
|
|
94
|
-
## Knowledge Graph
|
|
95
|
-
|
|
96
|
-
Plain markdown with Obsidian-style `[[backlinks]]`.
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
rg "Sarah Chen" Knowledge/ # Search by name
|
|
100
|
-
cat "Knowledge/People/Sarah Chen.md" # Read a note
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
**Always search broadly first.** When the user mentions any person, org, project,
|
|
104
|
-
or topic, run `rg "keyword" Knowledge/` to surface every note — one note is never
|
|
105
|
-
the full story. Skip it only for general knowledge and brainstorming.
|
|
106
|
-
|
|
107
|
-
## Skills
|
|
108
|
-
|
|
109
|
-
Skills auto-discover from `.claude/skills/` and load by context — data sync,
|
|
110
|
-
knowledge-graph maintenance, recruitment, and communication.
|
|
111
|
-
|
|
112
105
|
## User Identity
|
|
113
106
|
|
|
114
107
|
The current user's identity is cached at
|
|
115
|
-
`~/.cache/fit/outpost/state/identity.md` — read it directly. If missing or
|
|
116
|
-
run the `person-identify` skill to refresh it from the corporate
|
|
117
|
-
|
|
118
|
-
## Working Outside This Directory
|
|
119
|
-
|
|
120
|
-
You have full filesystem access (macOS). For tasks outside this KB, use shell
|
|
121
|
-
commands directly.
|
|
108
|
+
`~/.cache/fit/outpost/state/identity.md` — read it directly. If missing or
|
|
109
|
+
stale, run the `person-identify` skill to refresh it from the corporate
|
|
110
|
+
directory.
|