@forwardimpact/outpost 3.3.0 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/package.json +1 -1
  2. package/src/kb-manager.js +1 -6
  3. package/templates/.claude/agents/chief-of-staff.md +0 -3
  4. package/templates/.claude/agents/concierge.md +3 -3
  5. package/templates/.claude/agents/librarian.md +0 -1
  6. package/templates/.claude/settings.json +2 -2
  7. package/templates/.claude/skills/{hyprnote-follow → anarlog-follow}/SKILL.md +12 -12
  8. package/templates/.claude/skills/{hyprnote-follow → anarlog-follow}/references/coaching.md +3 -3
  9. package/templates/.claude/skills/{hyprnote-follow → anarlog-follow}/references/debrief.md +2 -2
  10. package/templates/.claude/skills/{hyprnote-follow → anarlog-follow}/references/meeting-types.md +1 -1
  11. package/templates/.claude/skills/{hyprnote-follow → anarlog-follow}/scripts/follow.mjs +3 -3
  12. package/templates/.claude/skills/{hyprnote-process → anarlog-process}/SKILL.md +20 -16
  13. package/templates/.claude/skills/{hyprnote-process → anarlog-process}/references/extraction.md +2 -2
  14. package/templates/.claude/skills/{hyprnote-process → anarlog-process}/references/sessions.md +5 -5
  15. package/templates/.claude/skills/{hyprnote-process → anarlog-process}/scripts/scan.mjs +5 -8
  16. package/templates/.claude/skills/{hyprnote-trim → anarlog-trim}/SKILL.md +15 -15
  17. package/templates/.claude/skills/candidate-report/SKILL.md +1 -1
  18. package/templates/.claude/skills/candidate-report/references/rubric.md +12 -12
  19. package/templates/.claude/skills/extract-entities/SKILL.md +11 -6
  20. package/templates/.claude/skills/extract-entities/references/TEMPLATES.md +2 -2
  21. package/templates/.claude/skills/extract-entities/references/recruitment.md +2 -1
  22. package/templates/.claude/skills/extract-entities/references/resolution.md +15 -0
  23. package/templates/.claude/skills/extract-entities/references/sources.md +8 -1
  24. package/templates/.claude/skills/extract-entities/references/templates-goals-priorities.md +1 -1
  25. package/templates/.claude/skills/identify-user/SKILL.md +103 -0
  26. package/templates/.claude/skills/identify-user/scripts/identify.sh +89 -0
  27. package/templates/.claude/skills/req-assess/SKILL.md +1 -1
  28. package/templates/.claude/skills/req-track/SKILL.md +7 -4
  29. package/templates/.claude/skills/req-workday/SKILL.md +5 -3
  30. package/templates/.claude/skills/sync-teams/scripts/sync.mjs +4 -3
  31. package/templates/.claude/skills/upstream-skill/references/examples.md +5 -5
  32. package/templates/CLAUDE.md +45 -46
  33. package/templates/.claude/skills/manage-tasks/SKILL.md +0 -152
  34. package/templates/.claude/skills/manage-tasks/references/format.md +0 -73
  35. package/templates/.claude/skills/weekly-update/SKILL.md +0 -141
  36. package/templates/.claude/skills/weekly-update/references/template.md +0 -55
  37. package/templates/USER.md +0 -3
@@ -48,11 +48,26 @@ Apply for entities not resolved to existing notes (meetings only).
48
48
  - Transactional service providers (bank employees, support reps).
49
49
  - One-time administrative contacts.
50
50
  - Large-group attendees you didn't interact with.
51
+ - Calendar-only attendees — people who appear solely on an invite's
52
+ attendee list with no interaction, decision, or discussion attributed to them.
51
53
  - Assistants handling only logistics.
52
54
 
53
55
  People who don't get their own note go in the Organization note's `## Contacts`
54
56
  section instead.
55
57
 
58
+ ## Minimum content bar — no stubs
59
+
60
+ A People note is only worth creating if you can write a substantive `## Summary`
61
+ (who they are, why you know them, what you're working on together) grounded in
62
+ the source. **If you cannot write that Summary from the source, do not create
63
+ the note** — record the contact in the Organization's `## Contacts` section
64
+ instead.
65
+
66
+ Never write a placeholder profile (name + email + generic role + a boilerplate
67
+ "created from…" line and nothing else). An email address and a meeting invite
68
+ are not, on their own, a reason to create a profile. These stubs add noise
69
+ without signal and must not be produced.
70
+
56
71
  ## Role inference
57
72
 
58
73
  When role isn't explicit, infer from context and qualify with the basis:
@@ -19,6 +19,13 @@ Calendar events. Internal-only meetings still enrich Project and Topic notes
19
19
  (decisions, agenda items). Only skip all-day placeholders with no attendees and
20
20
  no description (e.g. "Block", "OOO").
21
21
 
22
+ **Stub guard:** calendar attendance alone never creates a People note — calendar
23
+ events only *enrich* existing notes (see the table below). An attendee who is
24
+ only on the invite list, with no interaction or decision attributed to them, is
25
+ not profiled. If they matter, they go in the Organization's `## Contacts`. Never
26
+ write a placeholder profile; see the
27
+ [minimum content bar](resolution.md#minimum-content-bar--no-stubs).
28
+
22
29
  ## Skip entirely
23
30
 
24
31
  - Newsletters (unsubscribe links, "View in browser", bulk-sender indicators).
@@ -54,7 +61,7 @@ CC'd.
54
61
  ## Self-exclusion
55
62
 
56
63
  Never create or update notes for the user (matches name, email, or @domain from
57
- `USER.md`) or for `@{user.domain}` colleagues.
64
+ `~/.cache/fit/outpost/state/identity.md`) or for `@{user.domain}` colleagues.
58
65
 
59
66
  ## Source-type rules summary
60
67
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Goals and Priorities are **never auto-created** by `extract-entities`. They are
4
4
  set deliberately by the user. These templates are for manual creation only —
5
- `extract-entities` and `hyprnote-process` only **link to** and **update progress
5
+ `extract-entities` and `anarlog-process` only **link to** and **update progress
6
6
  on** existing notes.
7
7
 
8
8
  ## Priorities
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: identify-user
3
+ description: Look up the current user's identity (real name, company, job title, department, email, employee ID, and manager) from the corporate directory via LDAP, authenticated with the existing Kerberos ticket. Use to establish who the knowledge base belongs to, when CLAUDE.md needs the user's identity, or when the user asks "who am I" / for their own directory record.
4
+ ---
5
+
6
+ # Identify User
7
+
8
+ Resolve the current user's identity from the corporate Active Directory over
9
+ LDAP. This is the canonical way to establish **who the knowledge base belongs
10
+ to** — replacing any static identity file. Results reflect the live directory,
11
+ so a job change or reorg is picked up automatically.
12
+
13
+ ## Trigger
14
+
15
+ - CLAUDE.md (or another skill) needs the current user's identity.
16
+ - The user asks "who am I", for their own directory record, or for their
17
+ employee ID, title, department, or manager.
18
+
19
+ ## Prerequisites
20
+
21
+ - A valid **Kerberos ticket** for the user (`klist` shows a principal).
22
+ If absent, get one with `kinit <user>@<REALM>`.
23
+ - Network reachability to a domain controller (on-site or via VPN).
24
+ - `ldapsearch` and `dig` — both ship with macOS; nothing to install.
25
+
26
+ Nothing is hardcoded: the username, realm, base DN, and domain controller are
27
+ all derived at runtime from the ticket and DNS. No password is ever entered —
28
+ the bind uses SASL/GSSAPI against the existing ticket.
29
+
30
+ ## Usage
31
+
32
+ ```bash
33
+ bash .claude/skills/identify-user/scripts/identify.sh
34
+ ```
35
+
36
+ This prints the user's directory record, resolves the manager to a name, and
37
+ writes the result to the identity cache (below).
38
+
39
+ ## Identity cache
40
+
41
+ The script writes `~/.cache/fit/outpost/state/identity.md` — the **canonical
42
+ identity source** for the rest of the knowledge base, replacing the old static
43
+ `USER.md`. It is auto-generated markdown with `Name`, `Email`, and `Domain`
44
+ fields (plus title, department, company, employee ID, office, and manager):
45
+
46
+ ```markdown
47
+ - **Name:** Jane Doe
48
+ - **Email:** jane.doe@example.com
49
+ - **Domain:** example.com
50
+ ```
51
+
52
+ Other skills (e.g. `extract-entities`, `anarlog-process`, `req-track`,
53
+ `req-workday`, `candidate-report`, `sync-teams`) read this file for the user's
54
+ name/email/domain — for self-exclusion and author attribution. They run this
55
+ skill first if the cache is missing or stale. Never hand-edit the cache; re-run
56
+ the skill to refresh it.
57
+
58
+ ## How it works
59
+
60
+ The script is a handful of generic one-liners:
61
+
62
+ ```bash
63
+ # 1. Identity from the Kerberos ticket: USER@REALM.EXAMPLE.COM
64
+ princ=$(klist 2>/dev/null | sed -n 's/.*[Pp]rincipal: *//p' | head -1)
65
+ user=${princ%@*}; realm=${princ#*@}
66
+
67
+ # 2. Realm -> base DN (REALM.EXAMPLE.COM -> DC=REALM,DC=EXAMPLE,DC=COM)
68
+ base=$(printf '%s' "$realm" | awk -F. '{for(i=1;i<=NF;i++) printf "%sDC=%s",(i>1?",":""),$i}')
69
+ dom=$(printf '%s' "$realm" | tr '[:upper:]' '[:lower:]')
70
+
71
+ # 3. Find a domain controller via DNS SRV (any AD domain)
72
+ dc=$(dig +short SRV "_ldap._tcp.dc._msdcs.$dom" | awk 'NR==1{print $4}' | sed 's/\.$//')
73
+
74
+ # 4. Look up the current user (GSSAPI = existing ticket, no password)
75
+ ldapsearch -Y GSSAPI -LLL -o ldif-wrap=no -H "ldap://$dc" -b "$base" \
76
+ "(sAMAccountName=$user)" displayName company title department employeeID mail manager
77
+ ```
78
+
79
+ The `manager` attribute is a DN that may live in another domain, so the script
80
+ resolves it against the **Global Catalog** (port 3268), which is forest-wide.
81
+
82
+ ## Output
83
+
84
+ Key attributes returned (names per Active Directory schema):
85
+
86
+ | Attribute | Meaning |
87
+ | --------------------------- | ----------------------- |
88
+ | `displayName` / `givenName` / `sn` | Real name |
89
+ | `company` | Company |
90
+ | `title` | Job title |
91
+ | `department` | Department |
92
+ | `employeeID` | Employee ID |
93
+ | `mail` | Email address |
94
+ | `physicalDeliveryOfficeName`| Office / location |
95
+ | `manager` | Manager (DN → resolved to name) |
96
+
97
+ ## Notes
98
+
99
+ - To look up **someone else**, swap `sAMAccountName=<their network ID>` and, for
100
+ another region, point `-H`/`-b` at their domain or use the Global Catalog
101
+ (`ldap://$dc:3268 -b ''`) for a forest-wide search.
102
+ - Not Active Directory? The same `ldapsearch -Y GSSAPI` shape works against any
103
+ Kerberos-backed LDAP directory; only the attribute names differ.
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env bash
2
+ # Identify the current user from the corporate directory (Active Directory over LDAP)
3
+ # and cache the result at ~/.cache/fit/outpost/state/identity.md for other skills.
4
+ #
5
+ # Generic by design: nothing is hardcoded. The user, realm, and base DN are all
6
+ # derived from the existing Kerberos ticket, and the domain controller is found
7
+ # via DNS SRV records. Works for any AD domain, on or off VPN, as long as a
8
+ # Kerberos ticket exists and a DC is reachable.
9
+ #
10
+ # Auth uses SASL/GSSAPI against the existing ticket — no password is ever entered.
11
+ set -u
12
+
13
+ CACHE="$HOME/.cache/fit/outpost/state/identity.md"
14
+
15
+ # 1. Who are we? Take the principal from the Kerberos ticket: USER@REALM.EXAMPLE.COM
16
+ princ=$(klist 2>/dev/null | sed -n 's/.*[Pp]rincipal: *//p' | head -1)
17
+ if [ -z "$princ" ]; then
18
+ echo "No Kerberos ticket found. Get one first, e.g.: kinit <user>@<REALM>" >&2
19
+ exit 1
20
+ fi
21
+ user=${princ%@*}
22
+ realm=${princ#*@}
23
+
24
+ # 2. Realm -> LDAP base DN (REALM.EXAMPLE.COM -> DC=REALM,DC=EXAMPLE,DC=COM)
25
+ base=$(printf '%s' "$realm" | awk -F. '{for(i=1;i<=NF;i++) printf "%sDC=%s",(i>1?",":""),$i}')
26
+ dom=$(printf '%s' "$realm" | tr '[:upper:]' '[:lower:]')
27
+
28
+ # 3. Find a reachable domain controller via DNS SRV (msdcs first, then plain ldap)
29
+ dc=$(dig +short SRV "_ldap._tcp.dc._msdcs.$dom" | awk 'NR==1{print $4}' | sed 's/\.$//')
30
+ [ -z "$dc" ] && dc=$(dig +short SRV "_ldap._tcp.$dom" | awk 'NR==1{print $4}' | sed 's/\.$//')
31
+ if [ -z "$dc" ]; then
32
+ echo "Could not find a domain controller for $dom via DNS SRV." >&2
33
+ exit 1
34
+ fi
35
+
36
+ # 4. Look up the current user's record (GSSAPI = use the existing ticket, no password)
37
+ attrs="displayName givenName sn company title department employeeID mail telephoneNumber physicalDeliveryOfficeName manager"
38
+ rec=$(ldapsearch -Y GSSAPI -LLL -o ldif-wrap=no -H "ldap://$dc" -b "$base" "(sAMAccountName=$user)" $attrs 2>/dev/null)
39
+ if [ -z "$rec" ]; then
40
+ echo "No directory record found for '$user' under $base on $dc." >&2
41
+ exit 1
42
+ fi
43
+
44
+ # Pull a single attribute value out of the LDIF record.
45
+ field() { printf '%s\n' "$rec" | sed -n "s/^$1: //p" | head -1; }
46
+
47
+ disp=$(field displayName); gn=$(field givenName); sn=$(field sn)
48
+ company=$(field company); title=$(field title); dept=$(field department)
49
+ empid=$(field employeeID); mail=$(field mail)
50
+ office=$(field physicalDeliveryOfficeName)
51
+
52
+ # Real name from given+surname, falling back to displayName. Domain from the email.
53
+ name="$gn $sn"; name=$(printf '%s' "$name" | sed 's/^ *//;s/ *$//')
54
+ [ -z "$name" ] && name="$disp"
55
+ domain=$(printf '%s' "$mail" | sed 's/.*@//' | tr '[:upper:]' '[:lower:]')
56
+
57
+ # 5. Resolve the manager DN to a name, if present. Manager may live in another
58
+ # domain, so query the Global Catalog (port 3268), which is forest-wide.
59
+ mgr=$(field manager)
60
+ mgr_name=""
61
+ if [ -n "$mgr" ]; then
62
+ mgr_name=$(ldapsearch -Y GSSAPI -LLL -o ldif-wrap=no -H "ldap://$dc:3268" -b "$mgr" -s base \
63
+ displayName 2>/dev/null | sed -n 's/^displayName: //p' | head -1)
64
+ fi
65
+
66
+ # 6. Write the cache. Same Name/Email/Domain shape other skills already parse,
67
+ # plus extra fields. Auto-generated — never hand-edited.
68
+ mkdir -p "$(dirname "$CACHE")"
69
+ {
70
+ echo "# User Identity"
71
+ echo
72
+ echo "Auto-generated by the \`identify-user\` skill from the corporate directory."
73
+ echo "Do not edit by hand — re-run the skill to refresh."
74
+ echo
75
+ echo "- **Name:** $name"
76
+ echo "- **Email:** $mail"
77
+ echo "- **Domain:** $domain"
78
+ echo "- **Title:** $title"
79
+ echo "- **Department:** $dept"
80
+ echo "- **Company:** $company"
81
+ echo "- **Employee ID:** $empid"
82
+ echo "- **Office:** $office"
83
+ [ -n "$mgr_name" ] && echo "- **Manager:** $mgr_name"
84
+ } > "$CACHE"
85
+
86
+ # 7. Show the result.
87
+ cat "$CACHE"
88
+ echo
89
+ echo "(cached at $CACHE)"
@@ -25,7 +25,7 @@ This is **Stage 2** of the three-stage hiring pipeline:
25
25
  - A new `transcript-*.md` file appears in `knowledge/Candidates/{Name}/`.
26
26
  - The user asks to analyze an interview or debrief.
27
27
  - The user asks to prepare a panel brief.
28
- - The concierge agent processes a Hyprnote interview recording.
28
+ - The concierge agent processes a Anarlog interview recording.
29
29
 
30
30
  ## Prerequisites
31
31
 
@@ -20,7 +20,8 @@ pipeline from scattered email threads.
20
20
 
21
21
  - Synced email data in `~/.cache/fit/outpost/apple_mail/` (from
22
22
  `sync-apple-mail`).
23
- - User identity configured in `USER.md`.
23
+ - User identity run the `identify-user` skill to populate
24
+ `~/.cache/fit/outpost/state/identity.md`.
24
25
 
25
26
  ## Inputs
26
27
 
@@ -31,7 +32,8 @@ pipeline from scattered email threads.
31
32
  - `knowledge/Roles/*.md` — open role/requisition files (metadata inheritance).
32
33
  - `~/.cache/fit/outpost/state/graph_processed` — processed-file index (shared
33
34
  with `extract-entities`).
34
- - `USER.md` — user identity for self-exclusion.
35
+ - `~/.cache/fit/outpost/state/identity.md` — user identity for self-exclusion
36
+ (written by the `identify-user` skill).
35
37
 
36
38
  ## Outputs
37
39
 
@@ -68,8 +70,9 @@ Process **10 files per run**.
68
70
 
69
71
  ### 1. Load context and pick the batch
70
72
 
71
- Read `USER.md` for the user's name, email, and domain. List new or changed
72
- source files:
73
+ Read the user's name, email, and domain from
74
+ `~/.cache/fit/outpost/state/identity.md` (run the `identify-user` skill first if
75
+ it is missing or stale). List new or changed source files:
73
76
 
74
77
  ```bash
75
78
  node .claude/skills/extract-entities/scripts/state.mjs check
@@ -27,7 +27,8 @@ integrate with the `req-track` pipeline format.
27
27
  - A Workday requisition export accessible on the filesystem.
28
28
  - `read-excel-file` package installed:
29
29
  `bun pm ls read-excel-file 2>/dev/null || bun install read-excel-file`.
30
- - User identity in `USER.md`.
30
+ - User identity run the `identify-user` skill to populate
31
+ `~/.cache/fit/outpost/state/identity.md`.
31
32
 
32
33
  ## Inputs
33
34
 
@@ -64,8 +65,9 @@ Process **10 candidates per run**.
64
65
 
65
66
  ### 1. Set up
66
67
 
67
- Read `USER.md`. Confirm the XLSX path. Ensure the parser dependency is
68
- installed:
68
+ Read the user's identity from `~/.cache/fit/outpost/state/identity.md` (run the
69
+ `identify-user` skill first if it is missing or stale). Confirm the XLSX path.
70
+ Ensure the parser dependency is installed:
69
71
 
70
72
  ```bash
71
73
  bun pm ls read-excel-file 2>/dev/null || bun install read-excel-file
@@ -267,11 +267,12 @@ function writeChatMarkdown(
267
267
 
268
268
  function loadUserIdentity() {
269
269
  try {
270
- const userMd = readFileSync(join(process.cwd(), "USER.md"), "utf-8");
271
- const nameMatch = userMd.match(/\*\*Name:\*\*\s*(.+)/);
270
+ // Identity cache written by the identify-user skill (replaces USER.md).
271
+ const identityMd = readFileSync(join(STATE_DIR, "identity.md"), "utf-8");
272
+ const nameMatch = identityMd.match(/\*\*Name:\*\*\s*(.+)/);
272
273
  if (nameMatch) return nameMatch[1].trim();
273
274
  } catch {
274
- // USER.md not found or not readable
275
+ // identity cache not found or not readable — run the identify-user skill
275
276
  }
276
277
  return "";
277
278
  }
@@ -31,23 +31,23 @@ was invisible without structured gender data.
31
31
 
32
32
  ## New skill
33
33
 
34
- `.claude/skills/hyprnote-process/CHANGELOG.md`:
34
+ `.claude/skills/anarlog-process/CHANGELOG.md`:
35
35
 
36
36
  ```markdown
37
- # hyprnote-process Changelog
37
+ # anarlog-process Changelog
38
38
 
39
39
  Changes to this skill that should be considered for upstream inclusion in
40
40
  the Forward Impact monorepo.
41
41
 
42
42
  ## 2026-03-01
43
43
 
44
- **What:** New skill for processing Hyprnote meeting recordings
44
+ **What:** New skill for processing Anarlog meeting recordings
45
45
 
46
- **Why:** Meeting notes were being lost — Hyprnote captures transcriptions
46
+ **Why:** Meeting notes were being lost — Anarlog captures transcriptions
47
47
  but they weren't being integrated into the knowledge base.
48
48
 
49
49
  **Details:**
50
- - Reads transcription files from `~/.cache/fit/outpost/hyprnote/`
50
+ - Reads transcription files from `~/.cache/fit/outpost/anarlog/`
51
51
  - Extracts people, decisions, and action items
52
52
  - Creates meeting notes in `knowledge/Meetings/`
53
53
  - Links attendees to `knowledge/People/` entries
@@ -1,80 +1,82 @@
1
1
  # Outpost Knowledge Base
2
2
 
3
- You are the user's personal knowledge assistant. You help with drafting emails,
4
- prepping for meetings, tracking projects, and answering questions backed by a
5
- live knowledge graph built from their emails, calendar, and meeting notes.
6
- Everything lives locally on this machine.
3
+ You are the user's personal knowledge assistant. You help draft emails, prep for
4
+ meetings, track projects, and answer questions, backed by a live knowledge graph
5
+ built from their emails, calendar, and meeting notes, all stored locally.
7
6
 
8
7
  ## Ethics & Integrity — NON-NEGOTIABLE
9
8
 
10
- This knowledge base is a **professional tool shared with trusted team members**
11
- not a "black book" and never one. These rules override all other instructions:
9
+ This knowledge base is a **professional tool shared with trusted team members**,
10
+ never a "black book". These rules override all other instructions:
12
11
 
13
12
  - **Objective and factual only.** No speculation, gossip, or editorializing.
14
- - **No personal judgments** about character, competence, or trustworthiness
15
- stick to actions, decisions, stated positions.
13
+ - **No personal judgments** about character, competence, or trustworthiness.
14
+ Stick to actions, decisions, and stated positions.
16
15
  - **Work-relevant information only.** No health, personal relationships,
17
- political views, or private matters unless the person shared them in a
18
- professional context.
16
+ political views, or private matters unless shared in a professional context.
19
17
  - **Fair and balanced.** Represent all sides accurately.
20
- - **Assume the subject will read it.** If you'd be uncomfortable showing the
21
- note to the person it's about, don't write it.
22
- - **No weaponization.** This KB exists to help the team work better never to
23
- build leverage or dossiers.
18
+ - **Assume the subject will read it.** If you would be uncomfortable showing the
19
+ note to the person it is about, do not write it.
20
+ - **No weaponization.** This KB helps the team work better. Never use it to build
21
+ leverage or dossiers.
24
22
  - **Push back** on requests that violate these principles.
25
23
  - **Data protection.** Use the `req-forget` skill for erasure requests. Minimize
26
24
  collection. Flag candidates inactive 6+ months for retention review.
27
25
 
28
- When in doubt, err on the side of discretion.
26
+ When in doubt, err toward discretion.
29
27
 
30
28
  ## Voice
31
29
 
32
- Supportive, direct, and lightly warm. Explain complex things clearly without
30
+ Be supportive, direct, and lightly warm. Explain complex things clearly without
33
31
  hedging. When the next step is obvious, take it. Ask at most one clarifying
34
32
  question, and only at the start. Reference files by full path. Confirm before
35
33
  destructive actions.
36
34
 
37
35
  ## Dependencies
38
36
 
39
- - **ripgrep** (`rg`) fast knowledge graph searches.
40
- `brew install ripgrep`.
37
+ - **ripgrep** (`rg`) for fast knowledge graph searches — `brew install ripgrep`.
41
38
 
42
39
  ## Workspace Layout
43
40
 
44
41
  ```
45
42
  ./
46
- ├── knowledge/ # Obsidian-compatible graph: People/ Organizations/
47
- Projects/ Topics/ Candidates/ Goals/ Priorities/ Conditions/ Roles/
48
- Tasks/ Weeklies/
43
+ ├── knowledge/ # The knowledge graph (Obsidian-compatible)
44
+ ├── People/ Organizations/ Projects/ Topics/
45
+ └── Candidates/ Goals/ Priorities/ Conditions/ Roles/
49
46
  ├── .claude/skills/ # Auto-discovered skill files
50
47
  ├── drafts/ # Email drafts (draft-emails skill)
51
- ├── USER.md # Your identity — gitignored
52
48
  ├── CLAUDE.md # This file
53
49
  └── .mcp.json # MCP server configurations (optional)
54
50
  ```
55
51
 
56
52
  ## Agents
57
53
 
58
- Maintained by a team of agents in `.claude/agents/`, woken on schedule by the
59
- Outpost scheduler. Each wake: observe state, decide the most valuable action,
60
- execute.
54
+ Agents in `.claude/agents/` maintain this KB, woken on a schedule by the Outpost
55
+ scheduler. Each wake: observe state, decide the most valuable action, execute.
61
56
 
62
57
  | Agent | Domain | Schedule | Skills |
63
58
  | ------------------ | ------------------------------- | --------------- | -------------------------------------------------------------------------------------------- |
64
59
  | **postman** | Communication triage and drafts | Every 5 min | sync-apple-mail, sync-teams, draft-emails |
65
- | **concierge** | Meeting prep and transcripts | Every 10 min | sync-apple-calendar, meeting-prep, hyprnote-process |
66
- | **librarian** | Knowledge graph maintenance | Every 15 min | extract-entities, organize-files, manage-tasks |
60
+ | **concierge** | Meeting prep and transcripts | Every 10 min | sync-apple-calendar, meeting-prep, anarlog-process |
61
+ | **librarian** | Knowledge graph maintenance | Every 15 min | extract-entities, organize-files |
67
62
  | **recruiter** | Engineering recruitment | Every 30 min | req-track, req-screen, req-assess, req-decide, req-workday, req-forget, fit-pathway, fit-map |
68
63
  | **head-hunter** | Passive talent scouting | Every 60 min | req-scan, fit-pathway, fit-map |
69
- | **chief-of-staff** | Daily briefings and priorities | 7am, Mon 7:30am | weekly-update _(Mon)_, _(reads all state for daily briefings)_ |
64
+ | **chief-of-staff** | Daily briefings and priorities | 7am, Mon 7:30am | _(reads all state for daily briefings)_ |
70
65
 
71
66
  Each agent writes `~/.cache/fit/outpost/state/{agent}_triage.md` per wake. The
72
- **chief-of-staff** reads all five triage files to synthesize daily briefings in
67
+ **chief-of-staff** reads all five to write daily briefings in
73
68
  `knowledge/Briefings/`.
74
69
 
75
70
  ## Cache Directory (`~/.cache/fit/outpost/`)
76
71
 
77
- Synced data and runtime state live outside the KB. Top-level subdirs:
72
+ Synced data and runtime state live outside the KB; only notes and drafts live
73
+ inside it.
74
+
75
+ **Resolve `~` before passing a path to a tool.** Paths like
76
+ `~/.cache/fit/outpost/` are shorthand; read `$HOME` at runtime and never hardcode
77
+ it. Shell commands expand `~`, but the Write and Edit tools do not — a literal
78
+ `~/...` given to those creates a stray `.cache/` inside the KB. Always pass them
79
+ the full `$HOME/...` path.
78
80
 
79
81
  - `apple_mail/` — Mail threads as `.md` (plus `attachments/`)
80
82
  - `apple_calendar/` — Calendar events as `.json`
@@ -93,18 +95,14 @@ rg "Sarah Chen" knowledge/ # Search by name
93
95
  cat "knowledge/People/Sarah Chen.md" # Read a note
94
96
  ```
95
97
 
96
- **Always search broadly first.** When the user mentions any person,
97
- organization, project, or topic, run `rg "keyword" knowledge/` to surface every
98
- mentioning note before responding a single note is never the full story.
99
- Access the graph for any task involving named entities, specific people,
100
- projects, past context, meetings, emails, or calendar data. Skip for general
101
- knowledge questions, brainstorming, or unrelated tasks.
102
-
103
- Use the graph context to personalize responses.
98
+ **Always search broadly first.** When the user mentions any person, org, project,
99
+ or topic, run `rg "keyword" knowledge/` to surface every note first — one note is
100
+ never the full story. Use it for tasks involving named entities, people, projects,
101
+ meetings, emails, or calendar data; skip general knowledge and brainstorming.
104
102
 
105
103
  ## Synced Sources
106
104
 
107
- For upcoming meetings, recent emails, or messages, read directly from:
105
+ Read upcoming meetings, recent emails, and messages directly from:
108
106
 
109
107
  - `~/.cache/fit/outpost/apple_mail/`
110
108
  - `~/.cache/fit/outpost/apple_calendar/`
@@ -112,17 +110,18 @@ For upcoming meetings, recent emails, or messages, read directly from:
112
110
 
113
111
  ## Skills
114
112
 
115
- Skills auto-discover from `.claude/skills/` and load by context. They cluster
116
- around three functions: data sync (Apple Mail/Calendar, Teams), knowledge-graph
117
- maintenance (extract-entities, manage-tasks, recruitment pipeline), and
118
- communication (draft-emails, send-chat, meeting-prep, document and deck
119
- generation).
113
+ Skills auto-discover from `.claude/skills/` and load by context: data sync (Apple
114
+ Mail, Calendar, Teams), knowledge-graph maintenance (extract-entities, recruitment
115
+ pipeline), and communication (draft-emails, send-chat, meeting-prep, decks, docs).
120
116
 
121
117
  ## User Identity
122
118
 
123
- @import USER.md
119
+ The current user's identity is cached at
120
+ `~/.cache/fit/outpost/state/identity.md` — read it directly. If it is missing or
121
+ stale, run the `identify-user` skill to refresh it from the corporate directory.
124
122
 
125
123
  ## Working Outside This Directory
126
124
 
127
125
  You have full filesystem access (macOS). For tasks outside this KB
128
- (organizing Desktop, finding files in Downloads), use shell commands directly.
126
+ (organizing the Desktop, finding files in Downloads), use shell commands
127
+ directly.