@forwardimpact/outpost 3.11.0 → 3.12.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.
- package/README.md +2 -2
- package/bin/fit-outpost.js +3 -2
- package/package.json +4 -4
- package/src/agent-path.js +10 -6
- package/src/agent-runner.js +28 -24
- package/src/index.js +2 -3
- package/src/kb-manager.js +21 -19
- package/src/outpost.js +37 -33
- package/src/posture.js +3 -3
- package/src/privilege.js +11 -11
- package/src/scheduler.js +14 -12
- package/src/socket-server.js +19 -18
- package/src/spawn-env.js +7 -6
- package/src/state-manager.js +2 -2
- package/templates/.claude/agents/chief-of-staff.md +22 -22
- package/templates/.claude/agents/concierge.md +19 -17
- package/templates/.claude/agents/head-hunter.md +27 -26
- package/templates/.claude/agents/librarian.md +17 -16
- package/templates/.claude/agents/postman.md +19 -18
- package/templates/.claude/agents/recruiter.md +31 -27
- package/templates/.claude/skills/anarlog-follow/SKILL.md +50 -49
- package/templates/.claude/skills/anarlog-follow/references/coaching.md +22 -21
- package/templates/.claude/skills/anarlog-follow/scripts/follow.mjs +4 -4
- package/templates/.claude/skills/anarlog-process/SKILL.md +35 -32
- package/templates/.claude/skills/anarlog-process/references/extraction.md +26 -22
- package/templates/.claude/skills/anarlog-process/references/sessions.md +10 -10
- package/templates/.claude/skills/anarlog-process/scripts/scan.mjs +10 -9
- package/templates/.claude/skills/anarlog-trim/SKILL.md +43 -40
- package/templates/.claude/skills/candidate-report/SKILL.md +30 -28
- package/templates/.claude/skills/candidate-report/references/report-template.html +10 -10
- package/templates/.claude/skills/candidate-report/references/report.css +4 -4
- package/templates/.claude/skills/candidate-report/references/rubric.md +15 -14
- package/templates/.claude/skills/candidate-report/scripts/render-pdf.mjs +2 -2
- package/templates/.claude/skills/changelog/SKILL.md +55 -50
- package/templates/.claude/skills/deck-create/SKILL.md +30 -30
- package/templates/.claude/skills/deck-create/references/slide.css +4 -4
- package/templates/.claude/skills/deck-create/scripts/convert-to-pdf.mjs +6 -6
- package/templates/.claude/skills/deck-review/SKILL.md +59 -57
- package/templates/.claude/skills/deck-review/assets/slide-annotator.js +58 -49
- package/templates/.claude/skills/deck-summarize/SKILL.md +49 -43
- package/templates/.claude/skills/deck-summarize/references/brief-template.md +4 -3
- package/templates/.claude/skills/deck-summarize/scripts/extract-pptx.mjs +8 -7
- package/templates/.claude/skills/doc-collab/SKILL.md +25 -25
- package/templates/.claude/skills/doc-create/SKILL.md +21 -20
- package/templates/.claude/skills/doc-create/scripts/convert-to-pdf.mjs +6 -6
- package/templates/.claude/skills/draft-emails/SKILL.md +37 -33
- package/templates/.claude/skills/draft-emails/references/template.md +2 -2
- package/templates/.claude/skills/draft-emails/scripts/scan-emails.mjs +5 -4
- package/templates/.claude/skills/draft-emails/scripts/send-email.mjs +11 -9
- package/templates/.claude/skills/extract-entities/SKILL.md +65 -65
- package/templates/.claude/skills/extract-entities/references/TEMPLATES.md +5 -5
- package/templates/.claude/skills/extract-entities/references/conditions.md +14 -13
- package/templates/.claude/skills/extract-entities/references/content.md +10 -9
- package/templates/.claude/skills/extract-entities/references/links.md +5 -5
- package/templates/.claude/skills/extract-entities/references/recruitment.md +19 -18
- package/templates/.claude/skills/extract-entities/references/resolution.md +13 -13
- package/templates/.claude/skills/extract-entities/references/sources.md +8 -8
- package/templates/.claude/skills/extract-entities/references/templates-conditions.md +2 -2
- package/templates/.claude/skills/extract-entities/references/templates-priorities.md +2 -2
- package/templates/.claude/skills/extract-entities/scripts/state.mjs +9 -8
- package/templates/.claude/skills/meeting-prep/SKILL.md +25 -24
- package/templates/.claude/skills/organize-files/SKILL.md +24 -22
- package/templates/.claude/skills/organize-files/scripts/organize-by-type.mjs +5 -4
- package/templates/.claude/skills/organize-files/scripts/summarize.mjs +4 -4
- package/templates/.claude/skills/person-identify/SKILL.md +24 -22
- package/templates/.claude/skills/person-identify/scripts/identify.sh +17 -17
- package/templates/.claude/skills/person-lookup/SKILL.md +28 -29
- package/templates/.claude/skills/person-lookup/scripts/lookup.sh +19 -16
- package/templates/.claude/skills/req-assess/SKILL.md +27 -27
- package/templates/.claude/skills/req-assess/references/interview-template.md +1 -1
- package/templates/.claude/skills/req-assess/references/panel-template.md +3 -2
- package/templates/.claude/skills/req-assess/references/rubric.md +13 -13
- package/templates/.claude/skills/req-decide/SKILL.md +28 -25
- package/templates/.claude/skills/req-decide/references/rubric.md +11 -10
- package/templates/.claude/skills/req-forget/SKILL.md +28 -26
- package/templates/.claude/skills/req-forget/references/classify.md +13 -13
- package/templates/.claude/skills/req-forget/references/locations.md +2 -2
- package/templates/.claude/skills/req-forget/references/report-template.md +1 -1
- package/templates/.claude/skills/req-scan/SKILL.md +21 -22
- package/templates/.claude/skills/req-scan/references/fallbacks.md +9 -9
- package/templates/.claude/skills/req-scan/references/filters.md +13 -13
- package/templates/.claude/skills/req-scan/references/sources.md +7 -7
- package/templates/.claude/skills/req-scan/references/state.md +1 -1
- package/templates/.claude/skills/req-scan/scripts/state.mjs +3 -2
- package/templates/.claude/skills/req-screen/SKILL.md +31 -29
- package/templates/.claude/skills/req-screen/references/rubric.md +18 -18
- package/templates/.claude/skills/req-screen/references/template.md +4 -4
- package/templates/.claude/skills/req-track/SKILL.md +40 -40
- package/templates/.claude/skills/req-track/references/fields.md +19 -18
- package/templates/.claude/skills/req-track/references/signals.md +12 -12
- package/templates/.claude/skills/req-track/references/statuses.md +3 -2
- package/templates/.claude/skills/req-track/references/templates.md +4 -4
- package/templates/.claude/skills/req-workday/SKILL.md +24 -24
- package/templates/.claude/skills/req-workday/references/status-mapping.md +5 -5
- package/templates/.claude/skills/req-workday/references/templates.md +13 -13
- package/templates/.claude/skills/req-workday/references/xlsx-format.md +7 -7
- package/templates/.claude/skills/req-workday/scripts/parse-workday.mjs +19 -17
- package/templates/.claude/skills/send-chat/SKILL.md +47 -43
- package/templates/.claude/skills/sync-apple-calendar/SKILL.md +20 -19
- package/templates/.claude/skills/sync-apple-calendar/references/SCHEMA.md +7 -7
- package/templates/.claude/skills/sync-apple-calendar/scripts/query.mjs +6 -6
- package/templates/.claude/skills/sync-apple-calendar/scripts/sync.mjs +9 -8
- package/templates/.claude/skills/sync-apple-mail/SKILL.md +17 -14
- package/templates/.claude/skills/sync-apple-mail/references/SCHEMA.md +10 -10
- package/templates/.claude/skills/sync-apple-mail/scripts/parse-emlx.mjs +9 -9
- package/templates/.claude/skills/sync-apple-mail/scripts/sync-helpers.mjs +16 -13
- package/templates/.claude/skills/sync-apple-mail/scripts/sync.mjs +3 -3
- package/templates/.claude/skills/sync-teams/SKILL.md +43 -43
- package/templates/.claude/skills/sync-teams/scripts/idb-reader.mjs +22 -21
- package/templates/.claude/skills/sync-teams/scripts/leveldb-reader.mjs +4 -4
- package/templates/.claude/skills/sync-teams/scripts/sync.mjs +4 -4
- package/templates/.claude/skills/upstream-instructions/SKILL.md +39 -40
- package/templates/.claude/skills/upstream-instructions/references/examples.md +2 -2
- package/templates/CLAUDE.md +40 -37
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Priority Templates
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
deliberately
|
|
3
|
+
`extract-entities` **never auto-creates** Priorities. The user sets them
|
|
4
|
+
deliberately. Use this template only for a note you write by hand.
|
|
5
5
|
`extract-entities` and `anarlog-process` only **link to** and **update progress
|
|
6
6
|
on** existing notes.
|
|
7
7
|
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Manage graph_processed state for entity extraction.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* that are new or changed since their last recorded hash
|
|
8
|
-
* as processed
|
|
5
|
+
* The script tracks which source files the extract-entities skill already
|
|
6
|
+
* processed. Those files are synced emails and calendar events. The `check`
|
|
7
|
+
* command lists files that are new or changed since their last recorded hash.
|
|
8
|
+
* The `update` command marks files as processed. It stores the current
|
|
9
|
+
* SHA-256 hash of each file.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
+
* The script keeps the state in a TSV file at
|
|
11
12
|
* ~/.cache/fit/outpost/state/graph_processed (path<TAB>hash).
|
|
12
13
|
*/
|
|
13
14
|
|
|
@@ -43,7 +44,7 @@ const SOURCE_DIRS = [
|
|
|
43
44
|
join(HOME, ".cache/fit/outpost/teams_chat"),
|
|
44
45
|
];
|
|
45
46
|
|
|
46
|
-
/** Compute SHA-256 hash of a file. */
|
|
47
|
+
/** Compute the SHA-256 hash of a file. */
|
|
47
48
|
function fileHash(filePath) {
|
|
48
49
|
const data = readFileSync(filePath);
|
|
49
50
|
return createHash("sha256").update(data).digest("hex");
|
|
@@ -74,7 +75,7 @@ function saveState(state) {
|
|
|
74
75
|
writeFileSync(STATE_FILE, text);
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
/** Find source files that are new or
|
|
78
|
+
/** Find source files that are new or changed since the last run. */
|
|
78
79
|
function check() {
|
|
79
80
|
const state = loadState();
|
|
80
81
|
const newFiles = [];
|
|
@@ -97,7 +98,7 @@ function check() {
|
|
|
97
98
|
return newFiles.length;
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
/** Mark files as processed
|
|
101
|
+
/** Mark files as processed. Update their hashes in the state file. */
|
|
101
102
|
function update(filePaths) {
|
|
102
103
|
const state = loadState();
|
|
103
104
|
for (const fp of filePaths) {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: meeting-prep
|
|
3
|
-
description: Prepare for meetings
|
|
3
|
+
description: Prepare for meetings. Gather context from the knowledge base and calendar. Use when the user asks to prep for a meeting or wants a briefing on upcoming meetings. Creates personalized briefings with attendee history, open items, and suggested talking points.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Meeting Prep
|
|
7
7
|
|
|
8
|
-
Help the user prepare for meetings
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
Help the user prepare for meetings. Gather context from the knowledge base and
|
|
9
|
+
calendar. Create personalized briefing documents with attendee history, open
|
|
10
|
+
items, and suggested talking points.
|
|
11
11
|
|
|
12
12
|
## Trigger
|
|
13
13
|
|
|
@@ -17,7 +17,7 @@ meetings.
|
|
|
17
17
|
## Prerequisites
|
|
18
18
|
|
|
19
19
|
- Calendar data synced in `~/.cache/fit/outpost/apple_calendar/`
|
|
20
|
-
-
|
|
20
|
+
- A populated knowledge base (from the `extract-entities` skill)
|
|
21
21
|
|
|
22
22
|
## Inputs
|
|
23
23
|
|
|
@@ -25,11 +25,11 @@ meetings.
|
|
|
25
25
|
- `Knowledge/People/*.md` — attendee context
|
|
26
26
|
- `Knowledge/Organizations/*.md` — company context
|
|
27
27
|
- `Knowledge/Projects/*.md` — project context
|
|
28
|
-
- `Knowledge/Priorities/*.md` — active priorities and strategic context
|
|
29
|
-
|
|
28
|
+
- `Knowledge/Priorities/*.md` — active priorities and strategic context to
|
|
29
|
+
frame the brief
|
|
30
30
|
- `Knowledge/Candidates/*/brief.md` — candidate context (for interview meetings)
|
|
31
|
-
- `Knowledge/Roles/*.md` — role/requisition context (for interview meetings)
|
|
32
|
-
|
|
31
|
+
- `Knowledge/Roles/*.md` — role/requisition context (for interview meetings).
|
|
32
|
+
Check the `**Status:**` field to distinguish active from historical reqs
|
|
33
33
|
|
|
34
34
|
## Outputs
|
|
35
35
|
|
|
@@ -39,7 +39,7 @@ meetings.
|
|
|
39
39
|
|
|
40
40
|
## Critical: Always Look Up Context First
|
|
41
41
|
|
|
42
|
-
**BEFORE
|
|
42
|
+
**BEFORE you create any meeting brief, you MUST look up the attendees in the
|
|
43
43
|
knowledge base.**
|
|
44
44
|
|
|
45
45
|
When the user asks to prep for a meeting:
|
|
@@ -48,23 +48,23 @@ When the user asks to prep for a meeting:
|
|
|
48
48
|
2. **SEARCH** — Look up each attendee: `rg -l "Attendee Name" Knowledge/`
|
|
49
49
|
3. **READ** — Read their notes: `cat "Knowledge/People/Attendee Name.md"`
|
|
50
50
|
4. **UNDERSTAND** — Extract role, organization, history, open items
|
|
51
|
-
5. **THEN BRIEF** — Create the meeting brief
|
|
51
|
+
5. **THEN BRIEF** — Create the meeting brief with this context
|
|
52
52
|
|
|
53
53
|
## Key Principles
|
|
54
54
|
|
|
55
|
-
**Ask
|
|
55
|
+
**Ask. Do not guess:**
|
|
56
56
|
|
|
57
57
|
- If unclear which meeting, ASK
|
|
58
58
|
- If multiple upcoming meetings, offer choices
|
|
59
59
|
- **WRONG:** "Here's a generic meeting prep template"
|
|
60
60
|
- **RIGHT:** "I see meetings with Sarah (2pm) and John (4pm). Which one?"
|
|
61
61
|
|
|
62
|
-
**Be thorough
|
|
62
|
+
**Be thorough. Do not be generic:**
|
|
63
63
|
|
|
64
|
-
- Include specific history, open items, and context from knowledge base
|
|
64
|
+
- Include specific history, open items, and context from the knowledge base
|
|
65
65
|
- Reference actual past interactions and commitments
|
|
66
66
|
|
|
67
|
-
##
|
|
67
|
+
## Process Flow
|
|
68
68
|
|
|
69
69
|
### Step 1: Identify the Meeting
|
|
70
70
|
|
|
@@ -82,7 +82,7 @@ If "prep me for my next meeting":
|
|
|
82
82
|
|
|
83
83
|
- Query upcoming events with `--upcoming 2h`
|
|
84
84
|
- Find the next meeting with external attendees
|
|
85
|
-
- Confirm with user if unclear
|
|
85
|
+
- Confirm with the user if unclear
|
|
86
86
|
|
|
87
87
|
### Step 2: Parse Calendar Event
|
|
88
88
|
|
|
@@ -102,9 +102,9 @@ rg -l "attendee_name" Knowledge/Projects/
|
|
|
102
102
|
|
|
103
103
|
Extract: role/title, company, key facts, previous interactions, open items.
|
|
104
104
|
|
|
105
|
-
Also check `Knowledge/Priorities/` for context relevant
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
Also check `Knowledge/Priorities/` for context relevant to the meeting topic.
|
|
106
|
+
For example, if the meeting is about hiring, surface the relevant hiring
|
|
107
|
+
Priority's status and progress.
|
|
108
108
|
|
|
109
109
|
### Step 4: Create Meeting Brief
|
|
110
110
|
|
|
@@ -134,19 +134,20 @@ Suggested Talking Points
|
|
|
134
134
|
**Guidelines:**
|
|
135
135
|
|
|
136
136
|
- Use `[[Name]]` wiki-link syntax for cross-references
|
|
137
|
-
- Keep "About" section to 2-3 sentences max
|
|
137
|
+
- Keep the "About" section to 2-3 sentences max
|
|
138
138
|
- History: reverse chronological, 3-5 most relevant items
|
|
139
|
-
- Talking points: concrete
|
|
139
|
+
- Talking points: concrete. Avoid generic suggestions
|
|
140
140
|
- If no notes exist for a person, mention that and offer to create one
|
|
141
141
|
|
|
142
142
|
### Interview Meeting Context
|
|
143
143
|
|
|
144
|
-
When
|
|
145
|
-
"Decomposition", "Panel", or a candidate name from
|
|
144
|
+
When you prepare for interview meetings (title contains "Interview",
|
|
145
|
+
"Screening", "Decomposition", "Panel", or a candidate name from
|
|
146
|
+
`Knowledge/Candidates/`):
|
|
146
147
|
|
|
147
148
|
1. **Read the candidate brief:** `Knowledge/Candidates/{Name}/brief.md`
|
|
148
149
|
2. **Read the Role file:** Look up the `Req` field and read the corresponding
|
|
149
|
-
`Knowledge/Roles/*.md` file
|
|
150
|
+
`Knowledge/Roles/*.md` file. Check the `**Status:**` field for context.
|
|
150
151
|
3. **Include in the briefing:**
|
|
151
152
|
- Candidate's current status, skills, and screening recommendation
|
|
152
153
|
- Role context: hiring manager, domain lead, remaining positions
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: organize-files
|
|
3
|
-
description: Organize, tidy up, and find files in ~/Desktop/ and ~/Downloads/. Use when the user asks to find, organize, clean up, or tidy files on their Mac. Always previews changes before
|
|
3
|
+
description: Organize, tidy up, and find files in ~/Desktop/ and ~/Downloads/. Use when the user asks to find, organize, clean up, or tidy files on their Mac. Always previews changes before it acts. Never deletes without explicit confirmation. Extracts entities from document files with the extract-entities skill.
|
|
4
4
|
compatibility: Requires macOS filesystem access
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Organize Files
|
|
8
8
|
|
|
9
9
|
Organize, tidy up, and find files in `~/Desktop/` and `~/Downloads/`. Always
|
|
10
|
-
|
|
10
|
+
preview changes before you act. Never delete without explicit confirmation.
|
|
11
11
|
|
|
12
|
-
After
|
|
12
|
+
After you organize, extract entities from document files. Invoke the
|
|
13
13
|
**`extract-entities`** skill.
|
|
14
14
|
|
|
15
15
|
## Trigger
|
|
@@ -29,7 +29,7 @@ Run when the user asks to find, organize, clean up, or tidy files on their Mac.
|
|
|
29
29
|
|
|
30
30
|
- Organized files moved to logical subdirectories within `~/Desktop/` and
|
|
31
31
|
`~/Downloads/`
|
|
32
|
-
- Entity extraction triggered on document files
|
|
32
|
+
- Entity extraction triggered on document files with the **`extract-entities`**
|
|
33
33
|
skill
|
|
34
34
|
- Summary of actions taken
|
|
35
35
|
|
|
@@ -42,22 +42,23 @@ Run when the user asks to find, organize, clean up, or tidy files on their Mac.
|
|
|
42
42
|
2. **Organize files** — Move files into logical subfolders
|
|
43
43
|
3. **Tidy up** — Clean up cluttered `~/Desktop/` and `~/Downloads/`
|
|
44
44
|
4. **Create structure** — Set up folder hierarchies
|
|
45
|
-
5. **Extract entities** — After
|
|
46
|
-
skill on document files to populate the knowledge
|
|
45
|
+
5. **Extract entities** — After you organize, invoke the
|
|
46
|
+
**`extract-entities`** skill on document files to populate the knowledge
|
|
47
|
+
graph
|
|
47
48
|
|
|
48
49
|
## Key Principles
|
|
49
50
|
|
|
50
|
-
**Always preview before
|
|
51
|
+
**Always preview before you act:**
|
|
51
52
|
|
|
52
|
-
- Show
|
|
53
|
+
- Show which files change BEFORE you move or delete them
|
|
53
54
|
- List proposed changes and ask for confirmation
|
|
54
55
|
|
|
55
56
|
**Be conservative with destructive operations:**
|
|
56
57
|
|
|
57
58
|
- Never delete without explicit confirmation
|
|
58
|
-
-
|
|
59
|
+
- Move to a "to-review" folder rather than delete
|
|
59
60
|
|
|
60
|
-
##
|
|
61
|
+
## Summarize the Contents
|
|
61
62
|
|
|
62
63
|
Get an overview of both directories:
|
|
63
64
|
|
|
@@ -65,7 +66,7 @@ Get an overview of both directories:
|
|
|
65
66
|
node scripts/summarize.mjs
|
|
66
67
|
```
|
|
67
68
|
|
|
68
|
-
##
|
|
69
|
+
## Find Files
|
|
69
70
|
|
|
70
71
|
```bash
|
|
71
72
|
find ~/Downloads -maxdepth 1 -name "*.pdf" -type f
|
|
@@ -76,7 +77,7 @@ find ~/Downloads -maxdepth 1 -type f -mtime +30 # older than 30 days
|
|
|
76
77
|
find ~/Desktop -maxdepth 1 \( -name "Screenshot*" -o -name "Screen Shot*" \)
|
|
77
78
|
```
|
|
78
79
|
|
|
79
|
-
##
|
|
80
|
+
## Organize by File Type
|
|
80
81
|
|
|
81
82
|
Organize a directory into type-based subdirectories (Documents, Images,
|
|
82
83
|
Archives, Installers, Screenshots):
|
|
@@ -86,13 +87,13 @@ node scripts/organize-by-type.mjs ~/Downloads
|
|
|
86
87
|
node scripts/organize-by-type.mjs ~/Desktop
|
|
87
88
|
```
|
|
88
89
|
|
|
89
|
-
The script creates subdirectories and moves
|
|
90
|
-
anything.
|
|
90
|
+
The script creates subdirectories and moves the files that match. It does NOT
|
|
91
|
+
delete anything.
|
|
91
92
|
|
|
92
93
|
## Entity Extraction
|
|
93
94
|
|
|
94
|
-
After
|
|
95
|
-
information (people, organizations, projects, topics)
|
|
95
|
+
After you organize the files, identify document files that may contain entity
|
|
96
|
+
information (people, organizations, projects, topics). Then invoke the
|
|
96
97
|
**`extract-entities`** skill to process them.
|
|
97
98
|
|
|
98
99
|
### Which files to send for extraction
|
|
@@ -103,8 +104,8 @@ information (people, organizations, projects, topics) and invoke the
|
|
|
103
104
|
|
|
104
105
|
### How to invoke
|
|
105
106
|
|
|
106
|
-
After
|
|
107
|
-
**`extract-entities`** skill
|
|
107
|
+
After you organize, collect the paths of the document files. Then invoke the
|
|
108
|
+
**`extract-entities`** skill and pass the file paths as ad-hoc file inputs.
|
|
108
109
|
|
|
109
110
|
## Output Format
|
|
110
111
|
|
|
@@ -141,10 +142,11 @@ Entity extraction: invoked extract-entities on 12 document files
|
|
|
141
142
|
|
|
142
143
|
## Safety Rules
|
|
143
144
|
|
|
144
|
-
1. **Never delete without permission** — "cleanup" means organize
|
|
145
|
+
1. **Never delete without permission** — "cleanup" means organize. It does not
|
|
146
|
+
mean delete
|
|
145
147
|
2. **Don't touch system folders** — /System, /Library, /Applications
|
|
146
|
-
3. **Don't touch hidden files** — files
|
|
148
|
+
3. **Don't touch hidden files** — files that start with `.` unless asked
|
|
147
149
|
4. **Limit scope** — only operate on `~/Desktop/` and `~/Downloads/`
|
|
148
|
-
5. **Limit depth** — use `-maxdepth 1` unless user wants recursive
|
|
149
|
-
6. **Show before
|
|
150
|
+
5. **Limit depth** — use `-maxdepth 1` unless the user wants recursive
|
|
151
|
+
6. **Show before you act** — always preview first
|
|
150
152
|
7. **Quote paths** — handle spaces: `"$HOME/My Documents"`
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Organize files in a directory by type into subdirectories.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* subdirectories: Screenshots, Documents, Images, Archives, and
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* The script scans the top level of the given directory. It moves files into
|
|
6
|
+
* category subdirectories: Screenshots, Documents, Images, Archives, and
|
|
7
|
+
* Installers. The file extension and the name prefix set the category. The
|
|
8
|
+
* script leaves a file in place if it matches no category. It does NOT delete
|
|
9
|
+
* anything.
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
12
|
import {
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Summarize the contents of ~/Desktop/ and ~/Downloads/.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* Images, Documents, Archives, Installers, Other)
|
|
7
|
-
* table for each.
|
|
8
|
-
* contents before
|
|
5
|
+
* The script counts top-level files in both directories by type
|
|
6
|
+
* (Screenshots, PDFs, Images, Documents, Archives, Installers, Other). It
|
|
7
|
+
* prints a human-readable table for each directory. The organize-files skill
|
|
8
|
+
* uses this script to preview directory contents before it organizes them.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: person-identify
|
|
3
|
-
description: Look up the current user's identity (real name, company, job title, department, email, employee ID, and manager) from the corporate directory
|
|
3
|
+
description: Look up the current user's identity (real name, company, job title, department, email, employee ID, and manager) from the corporate directory through LDAP. The bind uses 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. To look up someone *other* than the current user, use the sibling `person-lookup` skill instead.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Person Identify
|
|
7
7
|
|
|
8
8
|
Resolve the current user's identity from the corporate Active Directory over
|
|
9
9
|
LDAP. This is the canonical way to establish **who the knowledge base belongs
|
|
10
|
-
to
|
|
11
|
-
so a job change or reorg
|
|
10
|
+
to**. It replaces any static identity file. Results reflect the live
|
|
11
|
+
directory, so the skill picks up a job change or a reorg automatically.
|
|
12
12
|
|
|
13
13
|
## Trigger
|
|
14
14
|
|
|
@@ -20,12 +20,12 @@ so a job change or reorg is picked up automatically.
|
|
|
20
20
|
|
|
21
21
|
- A valid **Kerberos ticket** for the user (`klist` shows a principal).
|
|
22
22
|
If absent, get one with `kinit <user>@<REALM>`.
|
|
23
|
-
- Network
|
|
24
|
-
- `ldapsearch` and `dig` — both ship with macOS
|
|
23
|
+
- Network access to a domain controller (on-site or through VPN).
|
|
24
|
+
- `ldapsearch` and `dig` — both ship with macOS. You install nothing.
|
|
25
25
|
|
|
26
|
-
Nothing is hardcoded
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
Nothing is hardcoded. The script derives the username, realm, base DN, and
|
|
27
|
+
domain controller at runtime from the ticket and DNS. You never enter a
|
|
28
|
+
password. The bind uses SASL/GSSAPI against the existing ticket.
|
|
29
29
|
|
|
30
30
|
## Usage
|
|
31
31
|
|
|
@@ -38,10 +38,11 @@ writes the result to the identity cache (below).
|
|
|
38
38
|
|
|
39
39
|
## Identity cache
|
|
40
40
|
|
|
41
|
-
The script writes `~/.cache/fit/outpost/state/identity.md
|
|
42
|
-
identity source** for the rest of the knowledge base
|
|
43
|
-
`USER.md`. It is auto-generated markdown with `Name`, `Email`,
|
|
44
|
-
fields (plus title, department, company, employee ID, office, and
|
|
41
|
+
The script writes `~/.cache/fit/outpost/state/identity.md`. That file is the
|
|
42
|
+
**canonical identity source** for the rest of the knowledge base. It replaces
|
|
43
|
+
the old static `USER.md`. It is auto-generated markdown with `Name`, `Email`,
|
|
44
|
+
and `Domain` fields (plus title, department, company, employee ID, office, and
|
|
45
|
+
manager):
|
|
45
46
|
|
|
46
47
|
```markdown
|
|
47
48
|
- **Name:** Jane Doe
|
|
@@ -51,9 +52,9 @@ fields (plus title, department, company, employee ID, office, and manager):
|
|
|
51
52
|
|
|
52
53
|
Other skills (e.g. `extract-entities`, `anarlog-process`, `req-track`,
|
|
53
54
|
`req-workday`, `candidate-report`, `sync-teams`) read this file for the user's
|
|
54
|
-
name/email/domain
|
|
55
|
-
skill first if the cache is missing or stale. Never hand-edit the
|
|
56
|
-
the skill to refresh it.
|
|
55
|
+
name/email/domain. They use it for self-exclusion and author attribution. They
|
|
56
|
+
run this skill first if the cache is missing or stale. Never hand-edit the
|
|
57
|
+
cache. Run the skill again to refresh it.
|
|
57
58
|
|
|
58
59
|
## How it works
|
|
59
60
|
|
|
@@ -76,8 +77,9 @@ ldapsearch -Y GSSAPI -LLL -o ldif-wrap=no -H "ldap://$dc" -b "$base" \
|
|
|
76
77
|
"(sAMAccountName=$user)" displayName company title department employeeID mail manager
|
|
77
78
|
```
|
|
78
79
|
|
|
79
|
-
The `manager` attribute is a DN that may live in another domain
|
|
80
|
-
resolves it against the **Global Catalog** (port 3268)
|
|
80
|
+
The `manager` attribute is a DN that may live in another domain. So the script
|
|
81
|
+
resolves it against the **Global Catalog** (port 3268). The Global Catalog is
|
|
82
|
+
forest-wide.
|
|
81
83
|
|
|
82
84
|
## Output
|
|
83
85
|
|
|
@@ -96,9 +98,9 @@ Key attributes returned (names per Active Directory schema):
|
|
|
96
98
|
|
|
97
99
|
## Notes
|
|
98
100
|
|
|
99
|
-
- To look up **someone else**, use the sibling `person-lookup` skill
|
|
100
|
-
free-text input (email or name)
|
|
101
|
-
(`ldap://$dc:3268 -b ''`)
|
|
101
|
+
- To look up **someone else**, use the sibling `person-lookup` skill. It takes
|
|
102
|
+
free-text input (email or name). It searches the Global Catalog forest-wide
|
|
103
|
+
(`ldap://$dc:3268 -b ''`). It handles multiple matches. It does **not** touch
|
|
102
104
|
the identity cache.
|
|
103
|
-
-
|
|
104
|
-
Kerberos-backed LDAP directory
|
|
105
|
+
- Active Directory is not required. The same `ldapsearch -Y GSSAPI` shape works
|
|
106
|
+
against any Kerberos-backed LDAP directory. Only the attribute names differ.
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Identify the current user from the corporate directory (Active Directory over LDAP)
|
|
3
|
-
#
|
|
2
|
+
# Identify the current user from the corporate directory (Active Directory over LDAP).
|
|
3
|
+
# Cache the result at ~/.cache/fit/outpost/state/identity.md for other skills.
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# Kerberos ticket
|
|
5
|
+
# The script is generic. Nothing is hardcoded. It derives the user, the realm,
|
|
6
|
+
# and the base DN from the existing Kerberos ticket. It finds the domain
|
|
7
|
+
# controller with DNS SRV records. It works for any AD domain, on or off VPN.
|
|
8
|
+
# It needs a Kerberos ticket and a reachable DC.
|
|
9
9
|
#
|
|
10
|
-
# Auth uses SASL/GSSAPI against the existing ticket
|
|
10
|
+
# Auth uses SASL/GSSAPI against the existing ticket. You never enter a password.
|
|
11
11
|
set -u
|
|
12
12
|
|
|
13
13
|
CACHE="$HOME/.cache/fit/outpost/state/identity.md"
|
|
14
14
|
|
|
15
|
-
# 1.
|
|
15
|
+
# 1. Take the user principal from the Kerberos ticket: USER@REALM.EXAMPLE.COM
|
|
16
16
|
princ=$(klist 2>/dev/null | sed -n 's/.*[Pp]rincipal: *//p' | head -1)
|
|
17
17
|
if [ -z "$princ" ]; then
|
|
18
18
|
echo "No Kerberos ticket found. Get one first, e.g.: kinit <user>@<REALM>" >&2
|
|
@@ -25,11 +25,11 @@ realm=${princ#*@}
|
|
|
25
25
|
base=$(printf '%s' "$realm" | awk -F. '{for(i=1;i<=NF;i++) printf "%sDC=%s",(i>1?",":""),$i}')
|
|
26
26
|
dom=$(printf '%s' "$realm" | tr '[:upper:]' '[:lower:]')
|
|
27
27
|
|
|
28
|
-
# 3. Find a reachable domain controller
|
|
28
|
+
# 3. Find a reachable domain controller with DNS SRV (msdcs first, then plain ldap)
|
|
29
29
|
dc=$(dig +short SRV "_ldap._tcp.dc._msdcs.$dom" | awk 'NR==1{print $4}' | sed 's/\.$//')
|
|
30
30
|
[ -z "$dc" ] && dc=$(dig +short SRV "_ldap._tcp.$dom" | awk 'NR==1{print $4}' | sed 's/\.$//')
|
|
31
31
|
if [ -z "$dc" ]; then
|
|
32
|
-
echo "Could not find a domain controller for $dom
|
|
32
|
+
echo "Could not find a domain controller for $dom with DNS SRV." >&2
|
|
33
33
|
exit 1
|
|
34
34
|
fi
|
|
35
35
|
|
|
@@ -49,13 +49,13 @@ company=$(field company); title=$(field title); dept=$(field department)
|
|
|
49
49
|
empid=$(field employeeID); mail=$(field mail)
|
|
50
50
|
office=$(field physicalDeliveryOfficeName)
|
|
51
51
|
|
|
52
|
-
# Real name from given+surname
|
|
52
|
+
# Real name from given+surname. Fall back to displayName. Domain from the email.
|
|
53
53
|
name="$gn $sn"; name=$(printf '%s' "$name" | sed 's/^ *//;s/ *$//')
|
|
54
54
|
[ -z "$name" ] && name="$disp"
|
|
55
55
|
domain=$(printf '%s' "$mail" | sed 's/.*@//' | tr '[:upper:]' '[:lower:]')
|
|
56
56
|
|
|
57
|
-
# 5. Resolve the manager DN to a name, if present.
|
|
58
|
-
# domain
|
|
57
|
+
# 5. Resolve the manager DN to a name, if present. The manager may live in
|
|
58
|
+
# another domain. Query the Global Catalog (port 3268). It is forest-wide.
|
|
59
59
|
mgr=$(field manager)
|
|
60
60
|
mgr_name=""
|
|
61
61
|
if [ -n "$mgr" ]; then
|
|
@@ -63,14 +63,14 @@ if [ -n "$mgr" ]; then
|
|
|
63
63
|
displayName 2>/dev/null | sed -n 's/^displayName: //p' | head -1)
|
|
64
64
|
fi
|
|
65
65
|
|
|
66
|
-
# 6. Write the cache.
|
|
67
|
-
# plus extra fields.
|
|
66
|
+
# 6. Write the cache. It keeps the Name/Email/Domain shape other skills already
|
|
67
|
+
# parse, plus extra fields. The script generates it. Never edit it by hand.
|
|
68
68
|
mkdir -p "$(dirname "$CACHE")"
|
|
69
69
|
{
|
|
70
70
|
echo "# User Identity"
|
|
71
71
|
echo
|
|
72
|
-
echo "
|
|
73
|
-
echo "Do not edit by hand
|
|
72
|
+
echo "The \`person-identify\` skill generates this file from the corporate directory."
|
|
73
|
+
echo "Do not edit it by hand. Run the skill again to refresh it."
|
|
74
74
|
echo
|
|
75
75
|
echo "- **Name:** $name"
|
|
76
76
|
echo "- **Email:** $mail"
|
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: person-lookup
|
|
3
|
-
description: Look up ANY person in the corporate directory from free-text input (an email address, or a first / last / full name) and return their record
|
|
3
|
+
description: Look up ANY person in the corporate directory from free-text input (an email address, or a first / last / full name) and return their record: real name, title, department, company, email, employee ID, office, and manager. Searches the Global Catalog forest-wide through LDAP. The bind uses the existing Kerberos ticket. Use when the user asks "who is X", needs someone's title / department / manager / email, or wants to disambiguate a name. For the *current* user's own identity, use the sibling `person-identify` skill instead.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Person Lookup
|
|
7
7
|
|
|
8
8
|
Resolve **any** person in the corporate Active Directory from natural-language
|
|
9
|
-
input
|
|
10
|
-
`person-identify`,
|
|
11
|
-
Catalog** (forest-wide)
|
|
12
|
-
|
|
13
|
-
cache. It
|
|
9
|
+
input. The input is an email, a login, or any part of a name. This skill is the
|
|
10
|
+
sibling of `person-identify`, and it aims at *other* people. It searches the
|
|
11
|
+
**Global Catalog** (forest-wide). It handles multiple matches. It flags
|
|
12
|
+
external contacts and vendor accounts. Unlike `person-identify`, it never
|
|
13
|
+
writes the identity cache. It is a read-only, throwaway lookup.
|
|
14
14
|
|
|
15
15
|
## Trigger
|
|
16
16
|
|
|
17
17
|
- The user asks "who is <name>", or for someone's title, department, manager,
|
|
18
18
|
email, or employee ID.
|
|
19
|
-
- A name is ambiguous and
|
|
19
|
+
- A name is ambiguous, and you must disambiguate it against the directory.
|
|
20
20
|
- Another skill needs to resolve a person who is **not** the current user.
|
|
21
21
|
|
|
22
|
-
For the current user's own record
|
|
23
|
-
|
|
22
|
+
For the current user's own record, use `person-identify` instead. It also
|
|
23
|
+
populates the identity cache that other skills read.
|
|
24
24
|
|
|
25
25
|
## Prerequisites
|
|
26
26
|
|
|
27
|
-
- A valid **Kerberos ticket** (`klist` shows a principal). If absent
|
|
27
|
+
- A valid **Kerberos ticket** (`klist` shows a principal). If absent, run
|
|
28
28
|
`kinit <user>@<REALM>`.
|
|
29
|
-
- Network
|
|
30
|
-
- `ldapsearch` and `dig` — both ship with macOS
|
|
29
|
+
- Network access to a domain controller (on-site or VPN).
|
|
30
|
+
- `ldapsearch` and `dig` — both ship with macOS. You install nothing.
|
|
31
31
|
|
|
32
|
-
Nothing is hardcoded
|
|
33
|
-
from the ticket and DNS. The bind uses SASL/GSSAPI against the existing
|
|
34
|
-
|
|
32
|
+
Nothing is hardcoded. The script derives the realm and a domain controller at
|
|
33
|
+
runtime from the ticket and DNS. The bind uses SASL/GSSAPI against the existing
|
|
34
|
+
ticket. You never enter a password.
|
|
35
35
|
|
|
36
36
|
## Usage
|
|
37
37
|
|
|
@@ -44,20 +44,20 @@ The argument is free text: an email, a full name, or just a surname.
|
|
|
44
44
|
|
|
45
45
|
## How it works
|
|
46
46
|
|
|
47
|
-
1. **Derive a domain controller** from the Kerberos principal's realm
|
|
48
|
-
SRV (same bootstrap as `person-identify`).
|
|
47
|
+
1. **Derive a domain controller** from the Kerberos principal's realm through
|
|
48
|
+
DNS SRV (same bootstrap as `person-identify`).
|
|
49
49
|
2. **Search the Global Catalog** (`ldap://$dc:3268`, base `""`). The GC spans
|
|
50
|
-
*every* domain in the forest
|
|
51
|
-
your own ticket
|
|
50
|
+
*every* domain in the forest. So you find a colleague in another region from
|
|
51
|
+
your own ticket. A plain domain-scoped search would miss them. It also
|
|
52
52
|
returns the common attributes (title, department, mail, manager), so one
|
|
53
53
|
query is enough.
|
|
54
|
-
3. **Match with ANR** (Ambiguous Name Resolution)
|
|
54
|
+
3. **Match with ANR** (Ambiguous Name Resolution). The `(anr=<input>)` filter
|
|
55
55
|
matches an email, a login, or any name part in one shot. If ANR finds
|
|
56
56
|
nothing, fall back to a substring search on `mail` / `displayName` /
|
|
57
57
|
`proxyAddresses`.
|
|
58
58
|
4. **Resolve per match.** For a single hit, print the full record and resolve
|
|
59
59
|
the `manager` DN to a name. For several hits, print a compact
|
|
60
|
-
disambiguation list and suggest
|
|
60
|
+
disambiguation list and suggest a narrower search by email.
|
|
61
61
|
|
|
62
62
|
## Output
|
|
63
63
|
|
|
@@ -80,18 +80,17 @@ The argument is free text: an email, a full name, or just a surname.
|
|
|
80
80
|
external **Contact** object (e.g. a vendor email alias), returns several
|
|
81
81
|
entries. The **Type** column distinguishes an internal **Employee** from an
|
|
82
82
|
external **Contact** (standard `objectClass=contact`). Some directories also
|
|
83
|
-
park external/vendor *user* accounts under a dedicated OU
|
|
83
|
+
park external/vendor *user* accounts under a dedicated OU. Set
|
|
84
84
|
`VENDOR_OU_PATTERN` at the top of `scripts/lookup.sh` to your directory's OU
|
|
85
|
-
substring (e.g. `OU=Contractors`)
|
|
86
|
-
since the OU convention is organization-specific. Narrow with an
|
|
87
|
-
exact hit.
|
|
85
|
+
substring (e.g. `OU=Contractors`). This flags those accounts too. It is empty
|
|
86
|
+
by default, since the OU convention is organization-specific. Narrow with an
|
|
87
|
+
email for an exact hit.
|
|
88
88
|
- **Silent partial results.** Under load the directory occasionally returns an
|
|
89
89
|
entry's DN with no attributes (exit 0, no error). Every attribute fetch
|
|
90
90
|
retries with backoff, so a throttled response never masquerades as a person
|
|
91
91
|
with a blank title or email.
|
|
92
92
|
- **No cache.** This skill prints and exits. It never touches
|
|
93
|
-
`~/.cache/fit/outpost/state/identity.md`
|
|
94
|
-
|
|
93
|
+
`~/.cache/fit/outpost/state/identity.md`. `person-identify` owns that file
|
|
94
|
+
alone.
|
|
95
95
|
- **Ethics.** This reads objective, work-relevant directory data only, in line
|
|
96
|
-
with the knowledge base's integrity rules.
|
|
97
|
-
dossiers.
|
|
96
|
+
with the knowledge base's integrity rules. Never use it to build dossiers.
|