@forwardimpact/outpost 3.8.1 → 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/config/scheduler.json +12 -6
- package/package.json +1 -1
- package/src/agent-runner.js +27 -0
- package/src/kb-manager.js +54 -1
- package/src/outpost.js +12 -5
- package/src/privilege.js +45 -0
- 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/config/scheduler.json
CHANGED
|
@@ -1,32 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"agents": {
|
|
3
3
|
"postman": {
|
|
4
|
-
"kb": "
|
|
4
|
+
"kb": "~/.local/share/fit/outpost/Team",
|
|
5
|
+
"privilege": "full",
|
|
5
6
|
"schedule": { "type": "cron", "expression": "*/15 8-18 * * 1-5" },
|
|
6
7
|
"enabled": true
|
|
7
8
|
},
|
|
8
9
|
"concierge": {
|
|
9
|
-
"kb": "
|
|
10
|
+
"kb": "~/.local/share/fit/outpost/Team",
|
|
11
|
+
"privilege": "full",
|
|
10
12
|
"schedule": { "type": "cron", "expression": "*/30 8-18 * * 1-5" },
|
|
11
13
|
"enabled": true
|
|
12
14
|
},
|
|
13
15
|
"librarian": {
|
|
14
|
-
"kb": "
|
|
16
|
+
"kb": "~/.local/share/fit/outpost/Team",
|
|
17
|
+
"privilege": "restricted",
|
|
15
18
|
"schedule": { "type": "cron", "expression": "0 9,12,15,18 * * 1-5" },
|
|
16
19
|
"enabled": true
|
|
17
20
|
},
|
|
18
21
|
"chief-of-staff": {
|
|
19
|
-
"kb": "
|
|
22
|
+
"kb": "~/.local/share/fit/outpost/Team",
|
|
23
|
+
"privilege": "restricted",
|
|
20
24
|
"schedule": { "type": "cron", "expression": "0 7,18 * * 1-5" },
|
|
21
25
|
"enabled": true
|
|
22
26
|
},
|
|
23
27
|
"recruiter": {
|
|
24
|
-
"kb": "
|
|
28
|
+
"kb": "~/.local/share/fit/outpost/Team",
|
|
29
|
+
"privilege": "restricted",
|
|
25
30
|
"schedule": { "type": "cron", "expression": "0 8,12,17 * * 1-5" },
|
|
26
31
|
"enabled": true
|
|
27
32
|
},
|
|
28
33
|
"head-hunter": {
|
|
29
|
-
"kb": "
|
|
34
|
+
"kb": "~/.local/share/fit/outpost/Team",
|
|
35
|
+
"privilege": "restricted",
|
|
30
36
|
"schedule": { "type": "cron", "expression": "0 9 * * 1-5" },
|
|
31
37
|
"enabled": true
|
|
32
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/agent-runner.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
loadManifest,
|
|
12
12
|
draftSkills,
|
|
13
13
|
} from "./posture.js";
|
|
14
|
+
import { resolvePrivilege, disclaimFor } from "./privilege.js";
|
|
14
15
|
import { buildSpawnEnv } from "./spawn-env.js";
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -176,6 +177,24 @@ export class AgentRunner {
|
|
|
176
177
|
* @param {Record<string, string>} [configEnv] - Extra env vars from config
|
|
177
178
|
*/
|
|
178
179
|
async wake(agentName, agent, state, configEnv) {
|
|
180
|
+
// Resolve the mandatory privilege level before any work. A missing or
|
|
181
|
+
// invalid level is fail-closed: log and skip the wake — no agent process is
|
|
182
|
+
// spawned with a guessed privilege. The level lives in the user-only trust
|
|
183
|
+
// root, so a spawned agent cannot raise its own.
|
|
184
|
+
let level;
|
|
185
|
+
try {
|
|
186
|
+
level = resolvePrivilege(agent);
|
|
187
|
+
} catch (err) {
|
|
188
|
+
this.#log(
|
|
189
|
+
JSON.stringify({
|
|
190
|
+
event: "outpost.privilege.rejected",
|
|
191
|
+
agent: agentName,
|
|
192
|
+
error: err.message,
|
|
193
|
+
}),
|
|
194
|
+
);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
179
198
|
if (!agent.kb) {
|
|
180
199
|
this.#log(`Agent ${agentName}: no "kb" specified, skipping.`);
|
|
181
200
|
return;
|
|
@@ -191,6 +210,13 @@ export class AgentRunner {
|
|
|
191
210
|
const claude = await this.#findClaude();
|
|
192
211
|
|
|
193
212
|
this.#log(`Waking agent: ${agentName} (kb: ${agent.kb})`);
|
|
213
|
+
this.#log(
|
|
214
|
+
JSON.stringify({
|
|
215
|
+
event: "outpost.privilege.resolved",
|
|
216
|
+
agent: agentName,
|
|
217
|
+
level,
|
|
218
|
+
}),
|
|
219
|
+
);
|
|
194
220
|
|
|
195
221
|
const as = (state.agents[agentName] ||= {});
|
|
196
222
|
as.status = "active";
|
|
@@ -226,6 +252,7 @@ export class AgentRunner {
|
|
|
226
252
|
env,
|
|
227
253
|
kbPath,
|
|
228
254
|
this.#runtime,
|
|
255
|
+
disclaimFor(level),
|
|
229
256
|
);
|
|
230
257
|
this.#activeChildren.add(pid);
|
|
231
258
|
|
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
|
|
|
@@ -23,6 +23,33 @@ export class KBManager {
|
|
|
23
23
|
this.#logger = createLogger("outpost", runtime);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a knowledge-base name to its path under the XDG data home,
|
|
28
|
+
* `~/.local/share/fit/outpost/<name>`. The argument is a single path segment,
|
|
29
|
+
* never an arbitrary filesystem path, so a provisioned KB always lands outside
|
|
30
|
+
* TCC-protected folders. The name is validated — not sanitised — against the
|
|
31
|
+
* same rule as `agent-path.js`: a name carrying `/`, `\`, `..`, NUL, or a
|
|
32
|
+
* leading `~` could steer the KB back inside `~/Documents`, reopening the TCC
|
|
33
|
+
* hole, so it is rejected rather than rewritten.
|
|
34
|
+
* @param {string} name - The KB name (e.g. `Team`, `personal`).
|
|
35
|
+
* @returns {string} Absolute path under the data home.
|
|
36
|
+
* @throws {Error} when `name` is empty, non-string, or an unsafe segment.
|
|
37
|
+
*/
|
|
38
|
+
static kbPathForName(name) {
|
|
39
|
+
if (
|
|
40
|
+
typeof name !== "string" ||
|
|
41
|
+
name.length === 0 ||
|
|
42
|
+
name.includes("/") ||
|
|
43
|
+
name.includes("\\") ||
|
|
44
|
+
name.includes("..") ||
|
|
45
|
+
name.includes("\0") ||
|
|
46
|
+
name.startsWith("~")
|
|
47
|
+
) {
|
|
48
|
+
throw new Error(`unsafe KB name: ${JSON.stringify(name)}`);
|
|
49
|
+
}
|
|
50
|
+
return join(homedir(), ".local/share/fit/outpost", name);
|
|
51
|
+
}
|
|
52
|
+
|
|
26
53
|
/**
|
|
27
54
|
* Test whether a path exists, via the async fs surface.
|
|
28
55
|
* @param {string} p
|
|
@@ -187,6 +214,7 @@ export class KBManager {
|
|
|
187
214
|
await this.#ensureDir(join(dest, d));
|
|
188
215
|
|
|
189
216
|
await this.copyBundledFiles(templateDir, dest);
|
|
217
|
+
await this.#linkIntoDocuments(dest);
|
|
190
218
|
|
|
191
219
|
this.#logger.info(
|
|
192
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`,
|
|
@@ -194,6 +222,31 @@ export class KBManager {
|
|
|
194
222
|
return { ok: true, value: { dest } };
|
|
195
223
|
}
|
|
196
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
|
+
|
|
197
250
|
/**
|
|
198
251
|
* Update an existing knowledge base with the latest bundled files.
|
|
199
252
|
* @param {string} targetPath
|
package/src/outpost.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// fit-outpost Wake due agents once and exit
|
|
5
5
|
// fit-outpost daemon Run continuously (poll every 60s)
|
|
6
6
|
// fit-outpost wake <agent> Wake a specific agent immediately
|
|
7
|
-
// fit-outpost init
|
|
7
|
+
// fit-outpost init [name] Initialize a knowledge base by name (default: Team)
|
|
8
8
|
// fit-outpost update [path] Update KB with latest CLAUDE.md, agents and skills (defaults to current directory)
|
|
9
9
|
// fit-outpost stop Gracefully stop daemon and all running agents
|
|
10
10
|
// fit-outpost validate Validate agent definitions exist
|
|
@@ -58,7 +58,7 @@ function buildDefinition(version) {
|
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
name: "init",
|
|
61
|
-
args: "
|
|
61
|
+
args: "[name]",
|
|
62
62
|
description: "Initialize a new knowledge base",
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -433,13 +433,20 @@ export async function run(runtime, version) {
|
|
|
433
433
|
return 1;
|
|
434
434
|
},
|
|
435
435
|
init: async () => {
|
|
436
|
-
|
|
437
|
-
|
|
436
|
+
// `init [name]` provisions a KB by name under the data home (default
|
|
437
|
+
// `Team`), never an arbitrary path — so the substrate cannot be
|
|
438
|
+
// steered back into a TCC-protected folder. An unsafe name is refused.
|
|
439
|
+
const name = args[0] ?? "Team";
|
|
440
|
+
let target;
|
|
441
|
+
try {
|
|
442
|
+
target = KBManager.kbPathForName(name);
|
|
443
|
+
} catch {
|
|
444
|
+
cli.usageError(`invalid KB name "${name}"`);
|
|
438
445
|
return 2;
|
|
439
446
|
}
|
|
440
447
|
const tpl = await requireTemplateDir();
|
|
441
448
|
if (tpl === null) return 1;
|
|
442
|
-
const result = await kbManager.init(
|
|
449
|
+
const result = await kbManager.init(target, tpl);
|
|
443
450
|
if (!result.ok) {
|
|
444
451
|
proc.stderr.write(result.error + "\n");
|
|
445
452
|
return result.code;
|
package/src/privilege.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privilege — resolve an agent's least-privilege execution level and map it to
|
|
3
|
+
* the hop-2 spawn disclaim flag.
|
|
4
|
+
*
|
|
5
|
+
* The level governs the macOS reach the daemon grants a woken agent. `full`
|
|
6
|
+
* keeps today's single-grant model (the child inherits `fit-outpost.app` as its
|
|
7
|
+
* responsible process, so Full Disk Access and Automation flow to it); a
|
|
8
|
+
* `restricted` agent is held responsible for itself, so those grants are not
|
|
9
|
+
* extended and it can reach only non-TCC-protected substrate.
|
|
10
|
+
*
|
|
11
|
+
* The level is mandatory and lives in the same user-only trust root as the
|
|
12
|
+
* spawn-env allow-set and the state roots, so an agent cannot raise its own
|
|
13
|
+
* level. Patterned on `posture.js` but with no `effective*` coercion and no
|
|
14
|
+
* default — a missing or unrecognised value throws.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** The two privilege levels, in declaration order. */
|
|
18
|
+
export const PRIVILEGE_LEVELS = ["full", "restricted"];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Resolve an agent's declared privilege level. The level is mandatory: a
|
|
22
|
+
* missing or unrecognised value throws — there is no default.
|
|
23
|
+
* @param {{ privilege?: string }} agent - One agent's config.
|
|
24
|
+
* @returns {"full"|"restricted"} The declared level.
|
|
25
|
+
* @throws {Error} when `agent.privilege` is not one of {@link PRIVILEGE_LEVELS}.
|
|
26
|
+
*/
|
|
27
|
+
export function resolvePrivilege(agent) {
|
|
28
|
+
const level = agent?.privilege;
|
|
29
|
+
if (!PRIVILEGE_LEVELS.includes(level)) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`invalid privilege "${level}"; expected one of ${PRIVILEGE_LEVELS.join(", ")}`,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return level;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Map a level to the hop-2 disclaim flag: `restricted` self-disclaims (`1`),
|
|
39
|
+
* `full` keeps the inherited responsible process (`0`).
|
|
40
|
+
* @param {"full"|"restricted"} level
|
|
41
|
+
* @returns {0|1}
|
|
42
|
+
*/
|
|
43
|
+
export function disclaimFor(level) {
|
|
44
|
+
return level === "restricted" ? 1 : 0;
|
|
45
|
+
}
|
|
@@ -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
|