@forwardimpact/outpost 3.3.4 → 3.5.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/LICENSE +21 -201
- package/config/skill-postures.json +28 -0
- package/package.json +2 -4
- package/src/agent-path.js +42 -0
- package/src/agent-runner.js +60 -17
- package/src/kb-manager.js +5 -7
- package/src/outpost.js +43 -1
- package/src/posture.js +77 -0
- package/src/socket-server.js +15 -6
- package/src/spawn-env.js +62 -0
- package/src/state-manager.js +17 -2
- package/templates/.claude/agents/chief-of-staff.md +24 -9
- package/templates/.claude/agents/concierge.md +14 -0
- package/templates/.claude/agents/head-hunter.md +14 -0
- package/templates/.claude/agents/librarian.md +19 -7
- package/templates/.claude/agents/postman.md +14 -0
- package/templates/.claude/agents/recruiter.md +21 -12
- package/templates/.claude/settings.json +4 -0
- package/templates/.claude/skills/anarlog-follow/SKILL.md +7 -7
- package/templates/.claude/skills/anarlog-process/SKILL.md +15 -16
- package/templates/.claude/skills/anarlog-process/references/extraction.md +5 -5
- package/templates/.claude/skills/candidate-report/SKILL.md +9 -9
- package/templates/.claude/skills/deck-create/SKILL.md +2 -2
- package/templates/.claude/skills/deck-summarize/SKILL.md +2 -2
- package/templates/.claude/skills/deck-summarize/references/brief-template.md +1 -1
- package/templates/.claude/skills/doc-collab/SKILL.md +8 -8
- package/templates/.claude/skills/doc-create/SKILL.md +3 -3
- package/templates/.claude/skills/draft-emails/SKILL.md +19 -19
- package/templates/.claude/skills/draft-emails/references/template.md +1 -1
- package/templates/.claude/skills/draft-emails/scripts/scan-emails.mjs +4 -4
- package/templates/.claude/skills/draft-emails/scripts/send-email.mjs +2 -2
- package/templates/.claude/skills/extract-entities/SKILL.md +16 -17
- package/templates/.claude/skills/extract-entities/references/TEMPLATES.md +2 -2
- package/templates/.claude/skills/extract-entities/references/conditions.md +4 -4
- package/templates/.claude/skills/extract-entities/references/links.md +3 -18
- package/templates/.claude/skills/extract-entities/references/recruitment.md +8 -8
- package/templates/.claude/skills/extract-entities/references/resolution.md +3 -5
- package/templates/.claude/skills/extract-entities/references/sources.md +1 -1
- package/templates/.claude/skills/extract-entities/references/templates-conditions.md +2 -2
- package/templates/.claude/skills/extract-entities/references/templates-priorities.md +32 -0
- package/templates/.claude/skills/extract-entities/references/templates-projects-topics.md +2 -2
- package/templates/.claude/skills/meeting-prep/SKILL.md +18 -19
- package/templates/.claude/skills/req-assess/SKILL.md +11 -11
- package/templates/.claude/skills/req-assess/references/interview-template.md +1 -1
- package/templates/.claude/skills/req-assess/references/panel-template.md +1 -1
- package/templates/.claude/skills/req-decide/SKILL.md +17 -17
- package/templates/.claude/skills/req-decide/references/template.md +1 -1
- package/templates/.claude/skills/req-forget/SKILL.md +8 -8
- package/templates/.claude/skills/req-forget/references/classify.md +4 -4
- package/templates/.claude/skills/req-forget/references/locations.md +10 -10
- package/templates/.claude/skills/req-forget/references/report-template.md +8 -8
- package/templates/.claude/skills/req-scan/SKILL.md +3 -3
- package/templates/.claude/skills/req-scan/references/template.md +1 -1
- package/templates/.claude/skills/req-screen/SKILL.md +9 -9
- package/templates/.claude/skills/req-screen/references/template.md +1 -1
- package/templates/.claude/skills/req-track/SKILL.md +17 -17
- package/templates/.claude/skills/req-track/references/fields.md +8 -8
- package/templates/.claude/skills/req-track/references/signals.md +2 -2
- package/templates/.claude/skills/req-track/references/templates.md +1 -1
- package/templates/.claude/skills/req-workday/SKILL.md +12 -12
- package/templates/.claude/skills/req-workday/references/templates.md +3 -3
- package/templates/.claude/skills/send-chat/SKILL.md +4 -4
- package/templates/.claude/skills/upstream-instructions/SKILL.md +154 -0
- package/templates/.claude/skills/upstream-instructions/references/examples.md +97 -0
- package/templates/CLAUDE.md +47 -53
- package/templates/.claude/skills/extract-entities/references/templates-goals-priorities.md +0 -63
- package/templates/.claude/skills/upstream-skill/SKILL.md +0 -130
- package/templates/.claude/skills/upstream-skill/references/examples.md +0 -80
- package/templates/knowledge/Briefings/.gitkeep +0 -0
package/src/socket-server.js
CHANGED
|
@@ -8,6 +8,7 @@ import { createLogger } from "@forwardimpact/libtelemetry";
|
|
|
8
8
|
import { join, resolve } from "node:path";
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { computeNextWakeAt, nowFromClock } from "./scheduler.js";
|
|
11
|
+
import { agentNameToStatePrefix, UnsafeAgentNameError } from "./agent-path.js";
|
|
11
12
|
|
|
12
13
|
/** Unix-socket IPC server that handles status queries, wake requests, and shutdown commands. */
|
|
13
14
|
export class SocketServer {
|
|
@@ -131,7 +132,19 @@ export class SocketServer {
|
|
|
131
132
|
#resolveBriefingFile(agentName, agentConfig) {
|
|
132
133
|
const stateDir = join(this.#cacheDir, "state");
|
|
133
134
|
if (this.#fsSync.existsSync(stateDir)) {
|
|
134
|
-
|
|
135
|
+
let prefix;
|
|
136
|
+
try {
|
|
137
|
+
prefix = agentNameToStatePrefix(agentName) + "_";
|
|
138
|
+
} catch (err) {
|
|
139
|
+
if (!(err instanceof UnsafeAgentNameError)) throw err;
|
|
140
|
+
this.#log(
|
|
141
|
+
JSON.stringify({
|
|
142
|
+
event: "outpost.state_path.rejected",
|
|
143
|
+
agent: agentName,
|
|
144
|
+
}),
|
|
145
|
+
);
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
135
148
|
const found = this.#latestFileByMtime(
|
|
136
149
|
stateDir,
|
|
137
150
|
(f) => f.startsWith(prefix) && f.endsWith(".md"),
|
|
@@ -140,11 +153,7 @@ export class SocketServer {
|
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
if (agentConfig.kb) {
|
|
143
|
-
const dir = join(
|
|
144
|
-
this.#expandPath(agentConfig.kb),
|
|
145
|
-
"knowledge",
|
|
146
|
-
"Briefings",
|
|
147
|
-
);
|
|
156
|
+
const dir = join(this.#expandPath(agentConfig.kb), "Briefings");
|
|
148
157
|
if (this.#fsSync.existsSync(dir)) {
|
|
149
158
|
const files = this.#fsSync
|
|
150
159
|
.readdirSync(dir)
|
package/src/spawn-env.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spawn-env — env allow-set and the pure spawn-environment filter.
|
|
3
|
+
*
|
|
4
|
+
* The daemon-mediated wake paths forward `config.env` from
|
|
5
|
+
* `~/.fit/outpost/scheduler.json` into spawned `claude` processes. This module
|
|
6
|
+
* is the single trust contract that decides which keys are honored.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Build a Set whose mutators are neutralised. `Object.freeze` alone does not
|
|
14
|
+
* stop `Set.prototype.add`/`delete`/`clear` from mutating internal state, so
|
|
15
|
+
* the allow-set is only a durable trust contract if the mutators themselves
|
|
16
|
+
* throw.
|
|
17
|
+
* @param {string[]} keys
|
|
18
|
+
* @returns {ReadonlySet<string>}
|
|
19
|
+
*/
|
|
20
|
+
function frozenSet(keys) {
|
|
21
|
+
const set = new Set(keys);
|
|
22
|
+
for (const m of ["add", "delete", "clear"]) {
|
|
23
|
+
Object.defineProperty(set, m, {
|
|
24
|
+
value: () => {
|
|
25
|
+
throw new TypeError(`AGENT_ENV_ALLOWSET is immutable: ${m}() denied`);
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return Object.freeze(set);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Env keys the daemon honors for spawned agents. Add new keys here under
|
|
34
|
+
* code review. This single point is the env trust contract.
|
|
35
|
+
* @type {ReadonlySet<string>}
|
|
36
|
+
*/
|
|
37
|
+
export const AGENT_ENV_ALLOWSET = frozenSet(["ANTHROPIC_API_KEY"]);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Build the spawn environment from a base env plus allow-set members of
|
|
41
|
+
* `configEnv`. Keys outside the allow-set are dropped and returned in
|
|
42
|
+
* `rejections`. Tilde-prefixed values are home-expanded. Pure; the caller logs.
|
|
43
|
+
* @param {Record<string,string>=} configEnv
|
|
44
|
+
* @param {NodeJS.ProcessEnv} baseEnv
|
|
45
|
+
* @returns {{ env: Record<string,string>, rejections: string[] }}
|
|
46
|
+
*/
|
|
47
|
+
export function buildSpawnEnv(configEnv, baseEnv) {
|
|
48
|
+
const env = { ...baseEnv };
|
|
49
|
+
const rejections = [];
|
|
50
|
+
if (configEnv) {
|
|
51
|
+
const home = homedir();
|
|
52
|
+
for (const [key, value] of Object.entries(configEnv)) {
|
|
53
|
+
if (!AGENT_ENV_ALLOWSET.has(key)) {
|
|
54
|
+
rejections.push(key);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const v = String(value);
|
|
58
|
+
env[key] = v.startsWith("~/") ? join(home, v.slice(2)) : v;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { env, rejections };
|
|
62
|
+
}
|
package/src/state-manager.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
import { isoTimestamp } from "@forwardimpact/libutil";
|
|
7
|
+
import { agentNameToStatePrefix, UnsafeAgentNameError } from "./agent-path.js";
|
|
7
8
|
|
|
8
9
|
/** Persist and query agent scheduler state from a JSON file on disk. */
|
|
9
10
|
export class StateManager {
|
|
@@ -92,9 +93,10 @@ export class StateManager {
|
|
|
92
93
|
* @param {string} stdout
|
|
93
94
|
* @param {string} agentName
|
|
94
95
|
* @param {string} cacheDir - Cache directory for state files
|
|
96
|
+
* @param {Function} [logFn] - Optional logger for rejection records
|
|
95
97
|
* @returns {Promise<void>}
|
|
96
98
|
*/
|
|
97
|
-
async updateAgentState(agentState, stdout, agentName, cacheDir) {
|
|
99
|
+
async updateAgentState(agentState, stdout, agentName, cacheDir, logFn) {
|
|
98
100
|
const lines = stdout.split("\n");
|
|
99
101
|
const decisionLine = lines.find((l) => l.startsWith("Decision:"));
|
|
100
102
|
const actionLine = lines.find((l) => l.startsWith("Action:"));
|
|
@@ -113,8 +115,21 @@ export class StateManager {
|
|
|
113
115
|
|
|
114
116
|
// Save output as briefing fallback
|
|
115
117
|
const stateDir = join(cacheDir, "state");
|
|
118
|
+
let prefix;
|
|
119
|
+
try {
|
|
120
|
+
prefix = agentNameToStatePrefix(agentName);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
if (!(err instanceof UnsafeAgentNameError)) throw err;
|
|
123
|
+
if (logFn)
|
|
124
|
+
logFn(
|
|
125
|
+
JSON.stringify({
|
|
126
|
+
event: "outpost.state_path.rejected",
|
|
127
|
+
agent: agentName,
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
116
132
|
await this.#fs.mkdir(stateDir, { recursive: true });
|
|
117
|
-
const prefix = agentName.replace(/-/g, "_");
|
|
118
133
|
await this.#fs.writeFile(
|
|
119
134
|
join(stateDir, `${prefix}_last_output.md`),
|
|
120
135
|
stdout,
|
|
@@ -12,6 +12,20 @@ You are the chief of staff — the user's executive assistant. Each wake:
|
|
|
12
12
|
synthesize what matters across email, calendar, and the knowledge graph into a
|
|
13
13
|
single briefing.
|
|
14
14
|
|
|
15
|
+
## Priorities
|
|
16
|
+
|
|
17
|
+
`Knowledge/Priorities/` is the backbone of every briefing. Read it each wake (it
|
|
18
|
+
is also listed under Inputs) and frame the whole briefing around what advances or
|
|
19
|
+
threatens the user's priorities.
|
|
20
|
+
|
|
21
|
+
- **Always consider them.** Tie the schedule, the top actions, and the pipeline
|
|
22
|
+
back to the priority each one serves.
|
|
23
|
+
- **Always escalate risks.** Consolidate every `## Priority Watch` flag from the
|
|
24
|
+
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, the
|
|
26
|
+
evidence, and the risk. A signal that could contradict, block, or slow a
|
|
27
|
+
priority is the most important thing the briefing surfaces.
|
|
28
|
+
|
|
15
29
|
## Inputs
|
|
16
30
|
|
|
17
31
|
Read all five sibling agents' triage files before writing — these are the
|
|
@@ -23,22 +37,23 @@ authoritative current-state summaries:
|
|
|
23
37
|
- `~/.cache/fit/outpost/state/recruiter_triage.md`
|
|
24
38
|
- `~/.cache/fit/outpost/state/head_hunter_triage.md`
|
|
25
39
|
|
|
26
|
-
Plus directly: `
|
|
40
|
+
Plus directly: `Knowledge/Priorities/`, `Drafts/`,
|
|
27
41
|
`~/.cache/fit/outpost/apple_calendar/`, and unchecked `- [ ]` items in
|
|
28
|
-
`
|
|
42
|
+
`Knowledge/`.
|
|
29
43
|
|
|
30
44
|
## Routing
|
|
31
45
|
|
|
32
46
|
| Trigger | Output |
|
|
33
47
|
| -------------- | -------------------------------------------------- |
|
|
34
|
-
| Before noon | `
|
|
35
|
-
| Noon or later | `
|
|
48
|
+
| Before noon | `Briefings/{YYYY-MM-DD}-morning.md` |
|
|
49
|
+
| Noon or later | `Briefings/{YYYY-MM-DD}-evening.md` |
|
|
36
50
|
|
|
37
51
|
A briefing covers: today's schedule with prep status, top three priority actions
|
|
38
|
-
linked to `[[Priorities/...]]`,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
52
|
+
linked to `[[Priorities/...]]`, priority progress, a **Priority Watch** section
|
|
53
|
+
consolidating priority risks flagged by the agents, inbox snapshot (urgent /
|
|
54
|
+
awaiting reply), open commitments, recruitment pipeline summary, and a heads-up
|
|
55
|
+
section. Evening briefings replace "Priority Actions" with "What Happened Today"
|
|
56
|
+
and "Still Outstanding".
|
|
42
57
|
|
|
43
58
|
## Scope
|
|
44
59
|
|
|
@@ -51,5 +66,5 @@ Evening briefings replace "Priority Actions" with "What Happened Today" and
|
|
|
51
66
|
|
|
52
67
|
```
|
|
53
68
|
Decision: {morning/evening} briefing — {key insight about today}
|
|
54
|
-
Action: Created
|
|
69
|
+
Action: Created Briefings/{YYYY-MM-DD}-{morning|evening}.md
|
|
55
70
|
```
|
|
@@ -16,6 +16,19 @@ You are the concierge — the user's scheduling assistant. Each wake: keep the
|
|
|
16
16
|
calendar current, prepare for upcoming meetings, and process completed meeting
|
|
17
17
|
recordings.
|
|
18
18
|
|
|
19
|
+
## Priorities
|
|
20
|
+
|
|
21
|
+
At the start of every wake, before acting, read `Knowledge/Priorities/`. The
|
|
22
|
+
user's priorities are the lens for all your work this wake.
|
|
23
|
+
|
|
24
|
+
- **Always consider them.** Weigh each action against whether it advances a
|
|
25
|
+
priority, and favour work that does.
|
|
26
|
+
- **Always flag risks.** When you encounter a chat, email, transcript, or any
|
|
27
|
+
other signal that could **contradict, block, or slow** a priority, record it
|
|
28
|
+
under a `## Priority Watch` heading in your triage report — name the priority,
|
|
29
|
+
quote the evidence, and state the risk — and echo it in the `Priority Watch`
|
|
30
|
+
line of your output. Never let such a signal pass silently.
|
|
31
|
+
|
|
19
32
|
## Routing
|
|
20
33
|
|
|
21
34
|
| Trigger | Skill |
|
|
@@ -43,4 +56,5 @@ After acting, emit exactly:
|
|
|
43
56
|
```
|
|
44
57
|
Decision: {what you observed and why you chose this action}
|
|
45
58
|
Action: {what you did, e.g. "meeting-prep for 2pm with Sarah Chen"}
|
|
59
|
+
Priority Watch: {priority at risk + one-line why, or "none"}
|
|
46
60
|
```
|
|
@@ -19,6 +19,19 @@ benchmark promising matches, and write prospect notes for the user to review.
|
|
|
19
19
|
|
|
20
20
|
**You never contact candidates.** Outreach is the user's call.
|
|
21
21
|
|
|
22
|
+
## Priorities
|
|
23
|
+
|
|
24
|
+
At the start of every wake, before acting, read `Knowledge/Priorities/`. The
|
|
25
|
+
user's priorities are the lens for all your work this wake.
|
|
26
|
+
|
|
27
|
+
- **Always consider them.** Weigh each action against whether it advances a
|
|
28
|
+
priority, and favour work that does.
|
|
29
|
+
- **Always flag risks.** When you encounter a chat, email, transcript, or any
|
|
30
|
+
other signal that could **contradict, block, or slow** a priority, record it
|
|
31
|
+
under a `## Priority Watch` heading in your triage report — name the priority,
|
|
32
|
+
quote the evidence, and state the risk — and echo it in the `Priority Watch`
|
|
33
|
+
line of your output. Never let such a signal pass silently.
|
|
34
|
+
|
|
22
35
|
## Routing
|
|
23
36
|
|
|
24
37
|
| Trigger | Skill |
|
|
@@ -54,4 +67,5 @@ wake — the chief-of-staff reads it.
|
|
|
54
67
|
Decision: {source chosen and why}
|
|
55
68
|
Action: {what was scanned, e.g. "scanned HN Who Wants to Be Hired March 2026, 47 posts"}
|
|
56
69
|
Prospects: {N} new ({strong} strong, {moderate} moderate), {total} total
|
|
70
|
+
Priority Watch: {priority at risk + one-line why, or "none"}
|
|
57
71
|
```
|
|
@@ -14,6 +14,19 @@ skills:
|
|
|
14
14
|
You are the librarian — the user's knowledge curator. Each time you are woken,
|
|
15
15
|
you process new data into the knowledge graph and keep everything organized.
|
|
16
16
|
|
|
17
|
+
## Priorities
|
|
18
|
+
|
|
19
|
+
At the start of every wake, before acting, read `Knowledge/Priorities/`. The
|
|
20
|
+
user's priorities are the lens for all your work this wake.
|
|
21
|
+
|
|
22
|
+
- **Always consider them.** Weigh each action against whether it advances a
|
|
23
|
+
priority, and favour work that does.
|
|
24
|
+
- **Always flag risks.** When you encounter a chat, email, transcript, or any
|
|
25
|
+
other signal that could **contradict, block, or slow** a priority, record it
|
|
26
|
+
under a `## Priority Watch` heading in your triage report — name the priority,
|
|
27
|
+
quote the evidence, and state the risk — and echo it in the `Priority Watch`
|
|
28
|
+
line of your output. Never let such a signal pass silently.
|
|
29
|
+
|
|
17
30
|
## 1. Observe
|
|
18
31
|
|
|
19
32
|
Assess what needs processing:
|
|
@@ -24,21 +37,19 @@ Assess what needs processing:
|
|
|
24
37
|
|
|
25
38
|
2. Count existing knowledge graph entities:
|
|
26
39
|
|
|
27
|
-
ls
|
|
28
|
-
|
|
40
|
+
ls Knowledge/People/ Knowledge/Organizations/ Knowledge/Projects/
|
|
41
|
+
Knowledge/Topics/ Knowledge/Priorities/ 2>/dev/null | wc -l
|
|
29
42
|
|
|
30
43
|
Write triage results to `~/.cache/fit/outpost/state/librarian_triage.md`:
|
|
31
44
|
|
|
32
45
|
```
|
|
33
46
|
# Knowledge Triage — {YYYY-MM-DD HH:MM}
|
|
34
|
-
|
|
35
47
|
## Pending Processing
|
|
36
48
|
- {count} unprocessed synced files
|
|
37
|
-
|
|
38
49
|
## Knowledge Graph
|
|
39
|
-
- {count} People / {count}
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
- {count} People / {count} Orgs / {count} Projects / {count} Topics / {count} Priorities
|
|
51
|
+
## Priority Watch
|
|
52
|
+
- {priority risks found while processing, or "none"}
|
|
42
53
|
## Summary
|
|
43
54
|
{unprocessed} files to process, graph has {total} entities
|
|
44
55
|
```
|
|
@@ -56,4 +67,5 @@ After acting, output exactly:
|
|
|
56
67
|
```
|
|
57
68
|
Decision: {what you observed and why you chose this action}
|
|
58
69
|
Action: {what you did, e.g. "extract-entities on 7 files"}
|
|
70
|
+
Priority Watch: {priority at risk + one-line why, or "none"}
|
|
59
71
|
```
|
|
@@ -15,6 +15,19 @@ skills:
|
|
|
15
15
|
You are the postman — the user's communication gatekeeper. Each wake: sync mail
|
|
16
16
|
and Teams, triage what's new, take the most valuable action.
|
|
17
17
|
|
|
18
|
+
## Priorities
|
|
19
|
+
|
|
20
|
+
At the start of every wake, before acting, read `Knowledge/Priorities/`. The
|
|
21
|
+
user's priorities are the lens for all your work this wake.
|
|
22
|
+
|
|
23
|
+
- **Always consider them.** Weigh each action against whether it advances a
|
|
24
|
+
priority, and favour work that does.
|
|
25
|
+
- **Always flag risks.** When you encounter a chat, email, transcript, or any
|
|
26
|
+
other signal that could **contradict, block, or slow** a priority, record it
|
|
27
|
+
under a `## Priority Watch` heading in your triage report — name the priority,
|
|
28
|
+
quote the evidence, and state the risk — and echo it in the `Priority Watch`
|
|
29
|
+
line of your output. Never let such a signal pass silently.
|
|
30
|
+
|
|
18
31
|
## Routing
|
|
19
32
|
|
|
20
33
|
| Trigger | Skill |
|
|
@@ -44,4 +57,5 @@ After acting, emit exactly:
|
|
|
44
57
|
```
|
|
45
58
|
Decision: {what you observed and why you chose this action}
|
|
46
59
|
Action: {what you did, e.g. "draft-emails for thread 123"}
|
|
60
|
+
Priority Watch: {priority at risk + one-line why, or "none"}
|
|
47
61
|
```
|
|
@@ -3,8 +3,7 @@ name: recruiter
|
|
|
3
3
|
description: >
|
|
4
4
|
The user's engineering recruitment specialist. Screens CVs, assesses
|
|
5
5
|
interviews, and produces hiring recommendations grounded in the fit-pathway
|
|
6
|
-
agent-aligned engineering standard.
|
|
7
|
-
Woken on a schedule by the Outpost scheduler.
|
|
6
|
+
agent-aligned engineering standard. Woken on a schedule by the Outpost scheduler.
|
|
8
7
|
model: sonnet
|
|
9
8
|
permissionMode: bypassPermissions
|
|
10
9
|
skills:
|
|
@@ -18,8 +17,21 @@ skills:
|
|
|
18
17
|
---
|
|
19
18
|
|
|
20
19
|
You are the recruiter — the user's engineering recruitment specialist. The
|
|
21
|
-
single source of truth for "good engineering" is the `fit-pathway` CLI
|
|
22
|
-
assessment
|
|
20
|
+
single source of truth for "good engineering" is the `fit-pathway` CLI; every
|
|
21
|
+
assessment and recommendation references the standard.
|
|
22
|
+
|
|
23
|
+
## Priorities
|
|
24
|
+
|
|
25
|
+
At the start of every wake, before acting, read `Knowledge/Priorities/`. The
|
|
26
|
+
user's priorities are the lens for all your work this wake.
|
|
27
|
+
|
|
28
|
+
- **Always consider them.** Weigh each action against whether it advances a
|
|
29
|
+
priority, and favour work that does.
|
|
30
|
+
- **Always flag risks.** When you encounter a chat, email, transcript, or any
|
|
31
|
+
other signal that could **contradict, block, or slow** a priority, record it
|
|
32
|
+
under a `## Priority Watch` heading in your triage report — name the priority,
|
|
33
|
+
quote the evidence, and state the risk — and echo it in the `Priority Watch`
|
|
34
|
+
line of your output. Never let such a signal pass silently.
|
|
23
35
|
|
|
24
36
|
## Routing
|
|
25
37
|
|
|
@@ -40,19 +52,15 @@ screen > sync. Stage 3 **never** triggers automatically — only on user request
|
|
|
40
52
|
Present level estimates with confidence language ("likely J060").
|
|
41
53
|
- **Standard-grounded.** Use `bunx fit-pathway job/skill/progress/interview`
|
|
42
54
|
before claiming fit, gaps, or level.
|
|
43
|
-
- **Data minimization.** Record only role-relevant data
|
|
44
|
-
data. Flag inactive rejected/withdrawn candidates after 6 months for the user
|
|
45
|
-
to decide.
|
|
55
|
+
- **Data minimization.** Record only role-relevant data; no special-category
|
|
56
|
+
data. Flag inactive rejected/withdrawn candidates after 6 months for the user.
|
|
46
57
|
- **Aggregate diversity only.** Track pool-level gender stats; never sort,
|
|
47
58
|
filter, or rank by protected characteristics. Gender recorded only from
|
|
48
59
|
explicit pronouns/titles, never name-inferred.
|
|
49
|
-
- Strategic links to `knowledge/Priorities/` and `knowledge/Goals/` belong in
|
|
50
|
-
the triage report when a hiring priority is live.
|
|
51
60
|
|
|
52
61
|
Triage state goes to `~/.cache/fit/outpost/state/recruiter_triage.md` every wake
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
and any data-retention flags.
|
|
62
|
+
(the chief-of-staff reads it): needs-action by stage, recently processed
|
|
63
|
+
candidates, pipeline totals by stage/track, aggregate diversity, retention flags.
|
|
56
64
|
|
|
57
65
|
## Output
|
|
58
66
|
|
|
@@ -60,4 +68,5 @@ and any data-retention flags.
|
|
|
60
68
|
Decision: {observation and chosen action}
|
|
61
69
|
Action: {e.g. "req-screen for John Smith against J060 forward_deployed"}
|
|
62
70
|
Stage: {1 | 2 | sync | erasure}
|
|
71
|
+
Priority Watch: {priority at risk + one-line why, or "none"}
|
|
63
72
|
```
|
|
@@ -62,6 +62,10 @@
|
|
|
62
62
|
"Bash(killall *)",
|
|
63
63
|
"Bash(launchctl *)",
|
|
64
64
|
"Bash(brew *)",
|
|
65
|
+
"Edit(~/.fit/outpost/**)",
|
|
66
|
+
"Edit(~/.cache/fit/outpost/state/**)",
|
|
67
|
+
"Bash(sed * ~/.fit/outpost/**)",
|
|
68
|
+
"Bash(sed * ~/.cache/fit/outpost/state/**)",
|
|
65
69
|
"Edit(~/Library/**)",
|
|
66
70
|
"Read(~/Pictures/**)",
|
|
67
71
|
"Read(~/Music/**)",
|
|
@@ -31,8 +31,8 @@ content appears.
|
|
|
31
31
|
## Inputs
|
|
32
32
|
|
|
33
33
|
- Live `transcript.json` (growing during the session).
|
|
34
|
-
- `
|
|
35
|
-
`
|
|
34
|
+
- `Knowledge/People/`, `Knowledge/Candidates/{Name}/{brief,screening,panel}.md`,
|
|
35
|
+
`Knowledge/Roles/`, `Knowledge/Organizations/`, `Knowledge/Projects/`.
|
|
36
36
|
- `~/.cache/fit/outpost/apple_calendar/*.json` for context.
|
|
37
37
|
|
|
38
38
|
## Outputs
|
|
@@ -91,8 +91,8 @@ Phase 2 context loading and Phase 3 dimensions.
|
|
|
91
91
|
Extract names from title and participant list. For each:
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
|
-
rg -l "{name}"
|
|
95
|
-
rg -l "{name}"
|
|
94
|
+
rg -l "{name}" Knowledge/People/
|
|
95
|
+
rg -l "{name}" Knowledge/Candidates/
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
Read matching notes for role, organization, history, open items, prior
|
|
@@ -100,8 +100,8 @@ interactions.
|
|
|
100
100
|
|
|
101
101
|
#### 5. Load type-specific context
|
|
102
102
|
|
|
103
|
-
**Interviews:** read `
|
|
104
|
-
look up the `Req` field's matching `
|
|
103
|
+
**Interviews:** read `Knowledge/Candidates/{Name}/{brief,screening,panel}.md`,
|
|
104
|
+
look up the `Req` field's matching `Knowledge/Roles/*.md`, and load standard
|
|
105
105
|
expectations:
|
|
106
106
|
|
|
107
107
|
```bash
|
|
@@ -109,7 +109,7 @@ bunx fit-pathway job {discipline} {level} --track={track}
|
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
**General meetings:** read attendee People notes plus referenced
|
|
112
|
-
Project/Organization notes. Check open tasks: `rg "{name}"
|
|
112
|
+
Project/Organization notes. Check open tasks: `rg "{name}" Knowledge/Tasks/`.
|
|
113
113
|
|
|
114
114
|
#### 6. Build the coaching brief
|
|
115
115
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: anarlog-process
|
|
3
|
-
description: Process Anarlog meeting sessions (memos, summaries, transcripts) into the knowledge graph. Extracts people, organizations, projects, and topics from AI-generated meeting summaries and user notes, creating or updating Obsidian-compatible notes in
|
|
3
|
+
description: Process Anarlog meeting sessions (memos, summaries, transcripts) into the knowledge graph. Extracts people, organizations, projects, and topics from AI-generated meeting summaries and user notes, creating or updating Obsidian-compatible notes in Knowledge/. Use when the user asks to process meeting notes or after Anarlog sessions.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Process Anarlog
|
|
7
7
|
|
|
8
8
|
Process meeting sessions from Anarlog (a local AI meeting-notes app) into the
|
|
9
9
|
knowledge graph. Anarlog records meetings, transcribes them, and generates AI
|
|
10
|
-
summaries; this skill reads that output and feeds it into `
|
|
10
|
+
summaries; this skill reads that output and feeds it into `Knowledge/` — the
|
|
11
11
|
same way `extract-entities` processes emails and calendar events.
|
|
12
12
|
|
|
13
13
|
## Trigger
|
|
@@ -35,9 +35,9 @@ same way `extract-entities` processes emails and calendar events.
|
|
|
35
35
|
|
|
36
36
|
## Outputs
|
|
37
37
|
|
|
38
|
-
- `
|
|
39
|
-
`
|
|
40
|
-
- `
|
|
38
|
+
- `Knowledge/People/`, `Knowledge/Organizations/`, `Knowledge/Projects/`,
|
|
39
|
+
`Knowledge/Topics/` — created or updated.
|
|
40
|
+
- `Knowledge/Priorities/` — **updated only**, never
|
|
41
41
|
auto-created.
|
|
42
42
|
- `~/.cache/fit/outpost/state/graph_processed` — updated.
|
|
43
43
|
|
|
@@ -47,12 +47,12 @@ same way `extract-entities` processes emails and calendar events.
|
|
|
47
47
|
- [ ] Both `_memo.md` and `_summary.md` read (when present); transcript
|
|
48
48
|
consulted only for disambiguation.
|
|
49
49
|
- [ ] "Would I prep?" test applied to each person; self excluded.
|
|
50
|
-
- [ ] Interview sessions wrote to `
|
|
51
|
-
`
|
|
50
|
+
- [ ] Interview sessions wrote to `Knowledge/Candidates/`, not
|
|
51
|
+
`Knowledge/People/`.
|
|
52
52
|
- [ ] All links use absolute paths `[[Folder/Name]]`.
|
|
53
53
|
- [ ] Activity entries describe relationship, not communication method.
|
|
54
|
-
- [ ] No new `
|
|
55
|
-
referenced
|
|
54
|
+
- [ ] No new `Priorities/` auto-created (user-set only); any
|
|
55
|
+
referenced priority had its progress updated.
|
|
56
56
|
- [ ] `graph_processed` updated for every processed file (memo + summary).
|
|
57
57
|
|
|
58
58
|
</do_confirm_checklist>
|
|
@@ -83,9 +83,9 @@ metadata fallback).
|
|
|
83
83
|
### 1. Build the knowledge index
|
|
84
84
|
|
|
85
85
|
```bash
|
|
86
|
-
ls
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
ls Knowledge/People/ Knowledge/Organizations/ Knowledge/Projects/ \
|
|
87
|
+
Knowledge/Topics/ Knowledge/Priorities/ \
|
|
88
|
+
Knowledge/Conditions/ 2>/dev/null
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
Read each note's header to build a mental index of known entities (same approach
|
|
@@ -104,7 +104,7 @@ Anarlog sessions are **meetings** and follow the meeting rules from
|
|
|
104
104
|
`extract-entities`:
|
|
105
105
|
|
|
106
106
|
- **Can create** People, Organization, Project, and Topic notes.
|
|
107
|
-
- **Can update** existing notes — including
|
|
107
|
+
- **Can update** existing notes — including Priorities, which are
|
|
108
108
|
user-set and never auto-created.
|
|
109
109
|
- **Can detect** state changes.
|
|
110
110
|
|
|
@@ -123,7 +123,7 @@ interview-note rules, and linking rules — live in
|
|
|
123
123
|
For **new** entities, use the templates in
|
|
124
124
|
`.claude/skills/extract-entities/references/TEMPLATES.md`. For interview
|
|
125
125
|
sessions, use the candidate brief template from `req-track` (under
|
|
126
|
-
`
|
|
126
|
+
`Knowledge/Candidates/`).
|
|
127
127
|
|
|
128
128
|
For **existing** entities, apply targeted edits — never rewrite the file:
|
|
129
129
|
|
|
@@ -133,8 +133,7 @@ For **existing** entities, apply targeted edits — never rewrite the file:
|
|
|
133
133
|
- Update open items (mark completed, add new).
|
|
134
134
|
- Apply state changes.
|
|
135
135
|
|
|
136
|
-
Verify bidirectional links per `extract-entities` Step 10 (
|
|
137
|
-
↔ Priority, Project ↔ Priority).
|
|
136
|
+
Verify bidirectional links per `extract-entities` Step 10 (Project ↔ Priority).
|
|
138
137
|
|
|
139
138
|
### 6. Update graph state
|
|
140
139
|
|
|
@@ -39,8 +39,8 @@ Never create or update a note for the user — match against name, email, or
|
|
|
39
39
|
## Interview sessions (special case)
|
|
40
40
|
|
|
41
41
|
If the title or memo indicates "interview with {Name}", the interviewee is a
|
|
42
|
-
**candidate** — create or update their note in `
|
|
43
|
-
the candidate brief template from `req-track`), **not** in `
|
|
42
|
+
**candidate** — create or update their note in `Knowledge/Candidates/` (using
|
|
43
|
+
the candidate brief template from `req-track`), **not** in `Knowledge/People/`.
|
|
44
44
|
|
|
45
45
|
## Content signals
|
|
46
46
|
|
|
@@ -77,8 +77,8 @@ strengths and concerns, any interview scoring or decisions.
|
|
|
77
77
|
## Linking rules
|
|
78
78
|
|
|
79
79
|
Use absolute paths everywhere: `[[People/Name]]`, `[[Organizations/Name]]`,
|
|
80
|
-
`[[Projects/Name]]`, `[[
|
|
80
|
+
`[[Projects/Name]]`, `[[Priorities/Priority Name]]`.
|
|
81
81
|
|
|
82
|
-
When meeting content references an existing
|
|
82
|
+
When meeting content references an existing Priority, follow the linking
|
|
83
83
|
rules in `extract-entities` Step 7c — update progress and add backlinks, but
|
|
84
|
-
**never** auto-create
|
|
84
|
+
**never** auto-create Priority notes.
|
|
@@ -25,11 +25,11 @@ before deciding whether to invest interview time.
|
|
|
25
25
|
- `@forwardimpact/pathway` CLI installed (`bunx fit-pathway --help`).
|
|
26
26
|
- Playwright for PDF output
|
|
27
27
|
(`bun install playwright && bunx playwright install chromium`).
|
|
28
|
-
- Candidate has a `brief.md` in `
|
|
28
|
+
- Candidate has a `brief.md` in `Knowledge/Candidates/{Name}/`.
|
|
29
29
|
|
|
30
30
|
## Inputs
|
|
31
31
|
|
|
32
|
-
- **Candidate name** — locates `
|
|
32
|
+
- **Candidate name** — locates `Knowledge/Candidates/{Name}/brief.md`.
|
|
33
33
|
- **Target role** — discipline, level, track (e.g.
|
|
34
34
|
`software_engineering J070 forward_deployed`). If not given, infer from the
|
|
35
35
|
candidate's `Req` field → Role file. Ask the user if it can't be inferred.
|
|
@@ -38,7 +38,7 @@ before deciding whether to invest interview time.
|
|
|
38
38
|
|
|
39
39
|
## Outputs
|
|
40
40
|
|
|
41
|
-
- `
|
|
41
|
+
- `Drafts/{Recipient}-{CandidateSurname}-Report.html` — the A4 one-pager.
|
|
42
42
|
- Optional PDF via `scripts/render-pdf.mjs`.
|
|
43
43
|
|
|
44
44
|
<do_confirm_checklist goal="Verify the report before delivering it">
|
|
@@ -62,16 +62,16 @@ before deciding whether to invest interview time.
|
|
|
62
62
|
Read whatever exists for the candidate:
|
|
63
63
|
|
|
64
64
|
```
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
Knowledge/Candidates/{Name}/brief.md # required
|
|
66
|
+
Knowledge/Candidates/{Name}/screening.md # if produced by req-screen
|
|
67
|
+
Knowledge/Candidates/{Name}/interview-*.md # if produced by req-assess
|
|
68
|
+
Knowledge/Candidates/{Name}/CV.pdf|CV.md # raw CV if needed
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
If `screening.md` exists, treat its skill and behaviour ratings as the primary
|
|
72
72
|
source — they're already standard-calibrated. Otherwise map manually in Step 3.
|
|
73
73
|
|
|
74
|
-
Search the graph for surrounding context: `rg "{Candidate Name}"
|
|
74
|
+
Search the graph for surrounding context: `rg "{Candidate Name}" Knowledge/`.
|
|
75
75
|
|
|
76
76
|
### 2. Load the standard benchmark
|
|
77
77
|
|
|
@@ -119,7 +119,7 @@ preview overflows, cut content.
|
|
|
119
119
|
Save the completed HTML to:
|
|
120
120
|
|
|
121
121
|
```
|
|
122
|
-
|
|
122
|
+
Drafts/{Recipient}-{CandidateSurname}-Report.html
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
`{Recipient}` is the first name of the person the report is for.
|
|
@@ -22,7 +22,7 @@ Run when the user asks to create a presentation, slide deck, or pitch deck.
|
|
|
22
22
|
## Inputs
|
|
23
23
|
|
|
24
24
|
- User's description of the presentation
|
|
25
|
-
- `
|
|
25
|
+
- `Knowledge/` — optional context about company, product, team, projects
|
|
26
26
|
|
|
27
27
|
## Outputs
|
|
28
28
|
|
|
@@ -32,7 +32,7 @@ Run when the user asks to create a presentation, slide deck, or pitch deck.
|
|
|
32
32
|
|
|
33
33
|
## Workflow
|
|
34
34
|
|
|
35
|
-
1. Check `
|
|
35
|
+
1. Check `Knowledge/` for relevant context about the company, product, team,
|
|
36
36
|
etc.
|
|
37
37
|
2. Ensure Playwright is installed:
|
|
38
38
|
`bun install playwright && bunx playwright install chromium`
|
|
@@ -30,7 +30,7 @@ from a slide deck; or understand what a project deck is actually asking for.
|
|
|
30
30
|
## Outputs
|
|
31
31
|
|
|
32
32
|
- One markdown file per deck (or one combined file for related decks) written to
|
|
33
|
-
`
|
|
33
|
+
`Knowledge/Projects/{Project Name} - Engineering Brief.md`.
|
|
34
34
|
|
|
35
35
|
<do_confirm_checklist goal="Verify the brief is engineer-actionable before
|
|
36
36
|
delivering">
|
|
@@ -125,7 +125,7 @@ mismatches.
|
|
|
125
125
|
|
|
126
126
|
Use the structure in
|
|
127
127
|
[references/brief-template.md](references/brief-template.md). Save to
|
|
128
|
-
`
|
|
128
|
+
`Knowledge/Projects/{Project Name} - Engineering Brief.md`. For multiple related
|
|
129
129
|
decks, write one combined brief with shared dependencies.
|
|
130
130
|
|
|
131
131
|
### 9. Save and report
|