@forwardimpact/outpost 3.10.0 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/.claude/skills/anarlog-follow/SKILL.md +2 -2
- package/templates/.claude/skills/deck-review/SKILL.md +7 -1
- package/templates/.claude/skills/deck-review/assets/slide-annotator.js +100 -15
- package/templates/.claude/skills/extract-entities/SKILL.md +3 -2
- package/templates/.claude/skills/extract-entities/references/recruitment.md +13 -3
- package/templates/.claude/skills/meeting-prep/SKILL.md +3 -2
- package/templates/.claude/skills/req-decide/SKILL.md +4 -2
- package/templates/.claude/skills/req-screen/SKILL.md +4 -2
- package/templates/.claude/skills/req-track/SKILL.md +17 -13
- package/templates/.claude/skills/req-track/references/fields.md +4 -2
- package/templates/.claude/skills/req-workday/SKILL.md +4 -2
- package/templates/.claude/skills/req-workday/references/templates.md +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/outpost",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0",
|
|
4
4
|
"description": "Personal operations center — context from email, calendar, and knowledge assembled so preparation is continuous, not a morning scramble.",
|
|
5
5
|
"homepage": "https://www.forwardimpact.team",
|
|
6
6
|
"repository": {
|
|
@@ -101,8 +101,8 @@ interactions.
|
|
|
101
101
|
#### 5. Load type-specific context
|
|
102
102
|
|
|
103
103
|
**Interviews:** read `Knowledge/Candidates/{Name}/{brief,screening,panel}.md`,
|
|
104
|
-
look up the `Req` field's matching `Knowledge/Roles/*.md
|
|
105
|
-
expectations:
|
|
104
|
+
look up the `Req` field's matching `Knowledge/Roles/*.md` file (check the
|
|
105
|
+
`**Status:**` field for context), and load standard expectations:
|
|
106
106
|
|
|
107
107
|
```bash
|
|
108
108
|
bunx fit-pathway job {discipline} {level} --track={track}
|
|
@@ -104,7 +104,13 @@ gracefully — but the correct fix is to make the deck arrow-keys-only per
|
|
|
104
104
|
**source line / column / context** for each highlight. (If the browser blocks
|
|
105
105
|
folder access on `file://`, **Save** downloads the JSON instead — move it
|
|
106
106
|
next to the deck.)
|
|
107
|
-
4.
|
|
107
|
+
4. The connected folder is **remembered across reloads** (the directory handle
|
|
108
|
+
is stored in IndexedDB, keyed per deck). After a reload the tool reconnects
|
|
109
|
+
silently if the browser still grants access; otherwise the button reads
|
|
110
|
+
**Reconnect folder** and a single click re-grants permission without
|
|
111
|
+
re-picking the folder. (Browsers require a user gesture to re-grant, so the
|
|
112
|
+
one click can't be avoided; clearing site data forgets the folder.)
|
|
113
|
+
5. Navigation while reviewing is the deck's normal **← / →** (the overlay's own
|
|
108
114
|
keystrokes never leak to the deck).
|
|
109
115
|
|
|
110
116
|
## Acting on the feedback (the review loop)
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
* (b) resolve each highlight to its SOURCE line/column + context lines by
|
|
14
14
|
* reading the page’s own source file. No build step, no server, no deps.
|
|
15
15
|
*
|
|
16
|
+
* The connected folder is remembered across reloads (the directory handle is
|
|
17
|
+
* stored in IndexedDB). On reload it reconnects silently if the browser still
|
|
18
|
+
* grants permission; otherwise the button reads “Reconnect folder” and one
|
|
19
|
+
* click re-grants access without re-picking the folder.
|
|
20
|
+
*
|
|
16
21
|
* Optional host hook: if the page defines `window.deckGoto(index)` the panel’s
|
|
17
22
|
* “Go” buttons will navigate to the right slide. Without it, the tool still
|
|
18
23
|
* works (it falls back to scrollIntoView).
|
|
@@ -60,7 +65,8 @@
|
|
|
60
65
|
/* ----------------------------- state ------------------------------------ */
|
|
61
66
|
var state = loadLocal(); // { version, tool, target, annotations:[] }
|
|
62
67
|
var review = false;
|
|
63
|
-
var dirHandle = null; // File System Access directory handle
|
|
68
|
+
var dirHandle = null; // File System Access directory handle (active)
|
|
69
|
+
var rememberedHandle = null; // handle from a prior session, awaiting re-grant
|
|
64
70
|
var sourceText = null; // page source (for line/column)
|
|
65
71
|
var pending = null; // annotation awaiting note + confirm
|
|
66
72
|
var ui = {}; // DOM refs
|
|
@@ -150,6 +156,7 @@
|
|
|
150
156
|
ui.count = ui.panel.querySelector(".sa-count");
|
|
151
157
|
ui.status = ui.panel.querySelector(".sa-status");
|
|
152
158
|
ui.list = ui.panel.querySelector(".sa-list");
|
|
159
|
+
ui.connectBtn = ui.panel.querySelector('[data-act="connect"]');
|
|
153
160
|
ui.note = ui.pop.querySelector("textarea");
|
|
154
161
|
var onlyThisSlide = false;
|
|
155
162
|
|
|
@@ -435,28 +442,105 @@
|
|
|
435
442
|
if (ui.count) ui.count.textContent = state.annotations.length;
|
|
436
443
|
}
|
|
437
444
|
|
|
445
|
+
/* Persist the connected directory handle across reloads. FileSystemHandles are
|
|
446
|
+
* structured-cloneable, so they live in IndexedDB (localStorage is strings
|
|
447
|
+
* only). Re-granting read/write permission after a reload needs a user
|
|
448
|
+
* gesture, so a remembered folder reconnects with one click via the same
|
|
449
|
+
* "Connect folder" button rather than the full directory picker. Keyed by
|
|
450
|
+
* cfg.target so distinct decks in a folder don't clobber each other. */
|
|
451
|
+
var IDB_NAME = "slide-annotator", IDB_STORE = "handles";
|
|
452
|
+
function idbOpen() {
|
|
453
|
+
return new Promise(function (resolve, reject) {
|
|
454
|
+
if (!window.indexedDB) { reject(new Error("no-idb")); return; }
|
|
455
|
+
var req = indexedDB.open(IDB_NAME, 1);
|
|
456
|
+
req.onupgradeneeded = function () { req.result.createObjectStore(IDB_STORE); };
|
|
457
|
+
req.onsuccess = function () { resolve(req.result); };
|
|
458
|
+
req.onerror = function () { reject(req.error); };
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
function idbGet(key) {
|
|
462
|
+
return idbOpen().then(function (db) {
|
|
463
|
+
return new Promise(function (resolve, reject) {
|
|
464
|
+
var r = db.transaction(IDB_STORE, "readonly").objectStore(IDB_STORE).get(key);
|
|
465
|
+
r.onsuccess = function () { resolve(r.result || null); };
|
|
466
|
+
r.onerror = function () { reject(r.error); };
|
|
467
|
+
});
|
|
468
|
+
}).catch(function () { return null; });
|
|
469
|
+
}
|
|
470
|
+
function idbSet(key, val) {
|
|
471
|
+
return idbOpen().then(function (db) {
|
|
472
|
+
return new Promise(function (resolve, reject) {
|
|
473
|
+
var tx = db.transaction(IDB_STORE, "readwrite");
|
|
474
|
+
tx.objectStore(IDB_STORE).put(val, key);
|
|
475
|
+
tx.oncomplete = function () { resolve(true); };
|
|
476
|
+
tx.onerror = function () { reject(tx.error); };
|
|
477
|
+
});
|
|
478
|
+
}).catch(function () { return false; });
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function updateConnectLabel() {
|
|
482
|
+
if (!ui.connectBtn) return;
|
|
483
|
+
ui.connectBtn.textContent = dirHandle ? "Folder connected"
|
|
484
|
+
: rememberedHandle ? "Reconnect folder" : "Connect folder";
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Adopt a (freshly picked or re-granted) handle: link source, load any
|
|
488
|
+
// sidecar, and remember it for next time. Shared by connect and restore.
|
|
489
|
+
async function adoptFolder(handle) {
|
|
490
|
+
dirHandle = handle;
|
|
491
|
+
// read page source → enables source line/column resolution
|
|
492
|
+
try {
|
|
493
|
+
var fh = await dirHandle.getFileHandle(cfg.target);
|
|
494
|
+
sourceText = await (await fh.getFile()).text();
|
|
495
|
+
state.annotations.forEach(function (a) { a.source = locateInSource(a); });
|
|
496
|
+
} catch (e) { sourceText = null; setStatus("Connected, but '" + cfg.target + "' not found in folder — line numbers unavailable."); }
|
|
497
|
+
// load an existing sidecar if present
|
|
498
|
+
try {
|
|
499
|
+
var sh = await dirHandle.getFileHandle(SIDECAR);
|
|
500
|
+
mergeLoaded(JSON.parse(await (await sh.getFile()).text()));
|
|
501
|
+
} catch (e) { /* none yet */ }
|
|
502
|
+
await idbSet(cfg.target, dirHandle);
|
|
503
|
+
rememberedHandle = null;
|
|
504
|
+
updateConnectLabel();
|
|
505
|
+
persistLocal(); renderPanel(); renderHighlights();
|
|
506
|
+
setStatus("Connected. Saving to " + SIDECAR + (sourceText ? " · source linked" : ""));
|
|
507
|
+
}
|
|
508
|
+
|
|
438
509
|
async function connectFolder() {
|
|
510
|
+
// Prefer a folder remembered from a prior session: re-granting permission is
|
|
511
|
+
// a single click (this click IS the required user gesture), no picker.
|
|
512
|
+
if (rememberedHandle) {
|
|
513
|
+
try {
|
|
514
|
+
var perm = await rememberedHandle.requestPermission({ mode: "readwrite" });
|
|
515
|
+
if (perm === "granted") { await adoptFolder(rememberedHandle); return; }
|
|
516
|
+
} catch (e) { /* fall through to the picker */ }
|
|
517
|
+
rememberedHandle = null; updateConnectLabel();
|
|
518
|
+
}
|
|
439
519
|
if (!window.showDirectoryPicker) { setStatus("Folder access unsupported in this browser. Use Save (downloads the JSON)."); return; }
|
|
440
520
|
try {
|
|
441
|
-
|
|
442
|
-
// read page source → enables source line/column resolution
|
|
443
|
-
try {
|
|
444
|
-
var fh = await dirHandle.getFileHandle(cfg.target);
|
|
445
|
-
sourceText = await (await fh.getFile()).text();
|
|
446
|
-
state.annotations.forEach(function (a) { a.source = locateInSource(a); });
|
|
447
|
-
} catch (e) { sourceText = null; setStatus("Connected, but '" + cfg.target + "' not found in folder — line numbers unavailable."); }
|
|
448
|
-
// load an existing sidecar if present
|
|
449
|
-
try {
|
|
450
|
-
var sh = await dirHandle.getFileHandle(SIDECAR);
|
|
451
|
-
mergeLoaded(JSON.parse(await (await sh.getFile()).text()));
|
|
452
|
-
} catch (e) { /* none yet */ }
|
|
453
|
-
persistLocal(); renderPanel(); renderHighlights();
|
|
454
|
-
setStatus("Connected. Saving to " + SIDECAR + (sourceText ? " · source linked" : ""));
|
|
521
|
+
await adoptFolder(await window.showDirectoryPicker({ mode: "readwrite" }));
|
|
455
522
|
} catch (e) {
|
|
456
523
|
if (e && e.name !== "AbortError") setStatus("Folder access blocked (" + e.name + "). Use Save to download the JSON instead.");
|
|
457
524
|
}
|
|
458
525
|
}
|
|
459
526
|
|
|
527
|
+
// On load, try to restore a previously connected folder. queryPermission needs
|
|
528
|
+
// no gesture; if it's still "granted" we reconnect silently. If it's "prompt",
|
|
529
|
+
// we keep the handle so the next "Connect folder" click reconnects with one
|
|
530
|
+
// grant dialog (no picker). Handles cleared/denied storage are ignored.
|
|
531
|
+
function restoreFolder() {
|
|
532
|
+
idbGet(cfg.target).then(function (handle) {
|
|
533
|
+
if (!handle || typeof handle.queryPermission !== "function") return;
|
|
534
|
+
handle.queryPermission({ mode: "readwrite" }).then(function (perm) {
|
|
535
|
+
if (perm === "granted") { adoptFolder(handle); }
|
|
536
|
+
else {
|
|
537
|
+
rememberedHandle = handle; updateConnectLabel();
|
|
538
|
+
if (review) setStatus("Folder '" + cfg.target + "' remembered — click Reconnect folder.");
|
|
539
|
+
}
|
|
540
|
+
}).catch(function () {});
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
460
544
|
async function saveDisk() {
|
|
461
545
|
if (sourceText) state.annotations.forEach(function (a) { if (!a.source) a.source = locateInSource(a); });
|
|
462
546
|
var json = JSON.stringify(serialize(), null, 2);
|
|
@@ -591,4 +675,5 @@
|
|
|
591
675
|
};
|
|
592
676
|
|
|
593
677
|
updateCount();
|
|
678
|
+
restoreFolder();
|
|
594
679
|
})();
|
|
@@ -41,8 +41,9 @@ under `Knowledge/`. The core knowledge-graph builder.
|
|
|
41
41
|
auto-created.
|
|
42
42
|
- `Knowledge/Conditions/` — created when cross-cutting patterns are detected, or
|
|
43
43
|
updated.
|
|
44
|
-
- `Knowledge/Roles
|
|
45
|
-
metadata.
|
|
44
|
+
- `Knowledge/Roles/*.md`, `Knowledge/Candidates/*/brief.md` — enriched with
|
|
45
|
+
inferred metadata. New role stubs created with `**Status:** open`; update to
|
|
46
|
+
`**Status:** closed` when a role closes.
|
|
46
47
|
- `~/.cache/fit/outpost/state/graph_processed` — updated.
|
|
47
48
|
|
|
48
49
|
<do_confirm_checklist goal="Verify the batch produced clean, linked,
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
Reference for `extract-entities` Step 7b. Enrich `Knowledge/Roles/` and
|
|
4
4
|
`Knowledge/Candidates/` with metadata that no single source carries.
|
|
5
5
|
|
|
6
|
+
All Role files are flat in `Knowledge/Roles/`. The `**Status:**` field
|
|
7
|
+
distinguishes:
|
|
8
|
+
|
|
9
|
+
- **`Status: open`** — active openings (use for new candidates and table
|
|
10
|
+
rebuilds).
|
|
11
|
+
- **`Status: closed`** — completed/withdrawn roles (read-only).
|
|
12
|
+
|
|
6
13
|
## Requisition number detection
|
|
7
14
|
|
|
8
15
|
Scan email subjects and bodies for requisition numbers (e.g. 7-digit Workday
|
|
@@ -10,9 +17,12 @@ IDs).
|
|
|
10
17
|
|
|
11
18
|
1. `ls Knowledge/Roles/ | grep "{req_number}"` — does a Role file exist?
|
|
12
19
|
2. **No file:** create a stub using the Role-stub template in `req-track` Step
|
|
13
|
-
0b
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
0b, with `**Status:** open`. Search `rg "{req_number}" Knowledge/` for
|
|
21
|
+
context to enrich it.
|
|
22
|
+
3. **File exists:** check the `**Status:**` field. If `open`, check whether the
|
|
23
|
+
email provides new metadata (hiring manager, recruiter, locations) and update
|
|
24
|
+
the Role file. If `closed`, link for historical reference only; do not add
|
|
25
|
+
new candidates or rebuild tables.
|
|
16
26
|
|
|
17
27
|
## Hiring manager — calendar inference
|
|
18
28
|
|
|
@@ -28,7 +28,8 @@ meetings.
|
|
|
28
28
|
- `Knowledge/Priorities/*.md` — active priorities and strategic context for
|
|
29
29
|
framing
|
|
30
30
|
- `Knowledge/Candidates/*/brief.md` — candidate context (for interview meetings)
|
|
31
|
-
- `Knowledge/Roles/*.md` — role/requisition context (for interview meetings)
|
|
31
|
+
- `Knowledge/Roles/*.md` — role/requisition context (for interview meetings);
|
|
32
|
+
check the `**Status:**` field to distinguish active from historical reqs
|
|
32
33
|
|
|
33
34
|
## Outputs
|
|
34
35
|
|
|
@@ -145,7 +146,7 @@ When preparing for interview meetings (title contains "Interview", "Screening",
|
|
|
145
146
|
|
|
146
147
|
1. **Read the candidate brief:** `Knowledge/Candidates/{Name}/brief.md`
|
|
147
148
|
2. **Read the Role file:** Look up the `Req` field and read the corresponding
|
|
148
|
-
`Knowledge/Roles/*.md` file.
|
|
149
|
+
`Knowledge/Roles/*.md` file; check the `**Status:**` field for context.
|
|
149
150
|
3. **Include in the briefing:**
|
|
150
151
|
- Candidate's current status, skills, and screening recommendation
|
|
151
152
|
- Role context: hiring manager, domain lead, remaining positions
|
|
@@ -39,7 +39,8 @@ This is **Stage 3** of the three-stage pipeline:
|
|
|
39
39
|
- Standard data via `fit-pathway`.
|
|
40
40
|
- `Knowledge/Candidates/Insights.md` — cross-candidate context.
|
|
41
41
|
- `Knowledge/Roles/*.md` — the candidate's requisition (positions, hiring
|
|
42
|
-
manager, domain lead).
|
|
42
|
+
manager, domain lead). Check the `**Status:**` field to distinguish active
|
|
43
|
+
from historical reqs.
|
|
43
44
|
- `Knowledge/Priorities/*.md` — strategic context.
|
|
44
45
|
- Other active candidates at the same level — relative positioning.
|
|
45
46
|
|
|
@@ -118,7 +119,8 @@ ls Knowledge/Roles/ | grep "{req_number}"
|
|
|
118
119
|
cat "Knowledge/Roles/{matching file}"
|
|
119
120
|
```
|
|
120
121
|
|
|
121
|
-
Capture remaining positions, hiring manager,
|
|
122
|
+
Check the `**Status:**` field. Capture remaining positions, hiring manager,
|
|
123
|
+
domain lead, goal alignment, other
|
|
122
124
|
candidates on the same req, and channel (hr / vendor). Frame the recommendation
|
|
123
125
|
in terms of strategic impact.
|
|
124
126
|
|
|
@@ -39,7 +39,8 @@ This is **Stage 1** of a three-stage hiring pipeline:
|
|
|
39
39
|
- Target role (optional).
|
|
40
40
|
- Existing `Knowledge/Candidates/{Name}/brief.md`, if any.
|
|
41
41
|
- `Knowledge/Roles/*.md` matching the candidate's `Req` (provides `Level`,
|
|
42
|
-
`Discipline`, `Hiring manager`, `Domain lead
|
|
42
|
+
`Discipline`, `Hiring manager`, `Domain lead`, and the `**Status:**` field).
|
|
43
|
+
Look up by Req number or filename substring.
|
|
43
44
|
|
|
44
45
|
## Outputs
|
|
45
46
|
|
|
@@ -82,7 +83,8 @@ cat "Knowledge/Roles/{matching file}"
|
|
|
82
83
|
|
|
83
84
|
Use the Role's `Level` and `Discipline` as the target unless the user specified
|
|
84
85
|
a different target. Capture `Hiring manager` and `Domain lead` for the screening
|
|
85
|
-
header.
|
|
86
|
+
header. Note the `**Status:**` field, but don't let historical (`closed`) roles
|
|
87
|
+
block screening of still-active candidates.
|
|
86
88
|
|
|
87
89
|
If no target is available, estimate one using the level heuristics in
|
|
88
90
|
[references/rubric.md](references/rubric.md#level-estimation-heuristics).
|
|
@@ -29,7 +29,8 @@ pipeline from scattered email threads.
|
|
|
29
29
|
- `~/.cache/fit/outpost/apple_mail/attachments/` — CV/resume attachments.
|
|
30
30
|
- `~/.cache/fit/outpost/apple_calendar/*.json` — calendar events (for
|
|
31
31
|
cross-source inference).
|
|
32
|
-
- `Knowledge/Roles/*.md` —
|
|
32
|
+
- `Knowledge/Roles/*.md` — role/requisition files (check the `**Status:**`
|
|
33
|
+
field: `open` for active roles, `closed` for historical).
|
|
33
34
|
- `~/.cache/fit/outpost/state/graph_processed` — processed-file index (shared
|
|
34
35
|
with `extract-entities`).
|
|
35
36
|
- `~/.cache/fit/outpost/state/identity.md` — user identity for self-exclusion
|
|
@@ -40,8 +41,8 @@ pipeline from scattered email threads.
|
|
|
40
41
|
- `Knowledge/Candidates/{Full Name}/brief.md` — candidate profile note.
|
|
41
42
|
- `Knowledge/Candidates/{Full Name}/CV.pdf` (or `CV.docx`) — local CV copy.
|
|
42
43
|
- `Knowledge/Candidates/{Full Name}/headshot.jpeg` — candidate photo.
|
|
43
|
-
- `Knowledge/Roles/*.md` — created/updated
|
|
44
|
-
|
|
44
|
+
- `Knowledge/Roles/*.md` — role files created/updated; the `**Status:**` field
|
|
45
|
+
determines visibility (open/closed).
|
|
45
46
|
- `~/.cache/fit/outpost/state/graph_processed` — updated with processed threads.
|
|
46
47
|
|
|
47
48
|
<do_confirm_checklist goal="Verify candidate processing batch is complete and
|
|
@@ -94,21 +95,24 @@ links.
|
|
|
94
95
|
|
|
95
96
|
### 3. Sync `Knowledge/Roles/`
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
Role files are flat here; the `**Status:**` field is `open` or `closed`.
|
|
98
99
|
|
|
99
100
|
1. Read each Role file's Info block to map Req → Role file path, Hiring manager,
|
|
100
|
-
Domain lead, recruiter, Channel.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
the
|
|
106
|
-
|
|
101
|
+
Domain lead, recruiter, Channel. Look up by filename substring so a req-less
|
|
102
|
+
role stays findable: `ls Knowledge/Roles/ | grep "{partial_name_or_req}"`.
|
|
103
|
+
2. Find Reqs in candidate briefs missing a Role file:
|
|
104
|
+
`rg "^\*\*Req:\*\*" Knowledge/Candidates/*/brief.md`. Check all Role files
|
|
105
|
+
first; for a genuinely missing open role, create a stub with `**Status:**
|
|
106
|
+
open` using the **Role file stub** in
|
|
107
|
+
[references/templates.md](references/templates.md), then enrich:
|
|
108
|
+
`rg "{req_number}" Knowledge/`.
|
|
109
|
+
3. Rebuild each **open** Role file's `## Candidates` table by scanning briefs:
|
|
107
110
|
`rg -l "Req:.*{req_number}" Knowledge/Candidates/*/brief.md`. Use the **Role
|
|
108
|
-
Candidates table** format from `references/templates.md
|
|
109
|
-
newest first.
|
|
111
|
+
Candidates table** format from `references/templates.md`, newest first.
|
|
110
112
|
4. If a Role file has a hiring manager but no domain lead, walk the
|
|
111
113
|
`**Reports to:**` chain in `Knowledge/People/` to a VP or senior leader.
|
|
114
|
+
5. When a role closes (filled, cancelled, or frozen 6+ months), set its
|
|
115
|
+
`**Status:**` field to `closed` — only on a clear signal.
|
|
112
116
|
|
|
113
117
|
### 4. Identify recruitment threads
|
|
114
118
|
|
|
@@ -43,8 +43,10 @@ Field map and resolution rules for Step 2 of `req-track`.
|
|
|
43
43
|
|
|
44
44
|
Stop at the first match:
|
|
45
45
|
|
|
46
|
-
1. **Req-first inheritance** —
|
|
47
|
-
Req
|
|
46
|
+
1. **Req-first inheritance** — search `Knowledge/Roles/` for a file matching the
|
|
47
|
+
Req number or role description (use filename substring lookup for req-less
|
|
48
|
+
roles); check the `**Status:**` field (open/closed), then inherit Hiring
|
|
49
|
+
manager and Domain lead from the Role file.
|
|
48
50
|
2. **Calendar inference** —
|
|
49
51
|
`rg -l "{Candidate Name}" ~/.cache/fit/outpost/apple_calendar/`. The non-user
|
|
50
52
|
organizer of an interview event is likely the hiring manager.
|
|
@@ -38,7 +38,8 @@ integrate with the `req-track` pipeline format.
|
|
|
38
38
|
|
|
39
39
|
- `Knowledge/Candidates/{Clean Name}/brief.md` — candidate profile.
|
|
40
40
|
- `Knowledge/Candidates/{Clean Name}/CV.md` — resume text as markdown.
|
|
41
|
-
- `Knowledge/Roles/{Req ID} — {Title}.md` — created or updated
|
|
41
|
+
- `Knowledge/Roles/{Req ID} — {Title}.md` — created or updated with
|
|
42
|
+
`**Status:** open`. Update to `**Status:** closed` when the role closes.
|
|
42
43
|
- Updated existing briefs when a candidate already exists.
|
|
43
44
|
|
|
44
45
|
<do_confirm_checklist goal="Verify the Workday import is consistent with
|
|
@@ -96,7 +97,8 @@ header indices, name annotations) are in
|
|
|
96
97
|
ls Knowledge/Roles/ | grep "{Req ID}"
|
|
97
98
|
```
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
New role files go in `Knowledge/Roles/` with `**Status:** open`. Use the
|
|
101
|
+
**Role file stub** in
|
|
100
102
|
[references/templates.md](references/templates.md). Resolve the domain lead by:
|
|
101
103
|
|
|
102
104
|
1. `rg "{Req ID}" Knowledge/` — look in project timelines, People notes, Topics
|
|
@@ -5,13 +5,15 @@ Reference templates for `req-workday` Steps 1b, 4, and 5.
|
|
|
5
5
|
## Role file stub
|
|
6
6
|
|
|
7
7
|
Use when no Role file exists for the requisition. Filename:
|
|
8
|
-
`Knowledge/Roles/{Req ID} — {Short Title}.md`.
|
|
8
|
+
`Knowledge/Roles/{Req ID} — {Short Title}.md`. The `**Status:**` field
|
|
9
|
+
(`open`/`closed`) is updated in place — never move files.
|
|
9
10
|
|
|
10
11
|
```markdown
|
|
11
12
|
# {Requisition Title}
|
|
12
13
|
|
|
13
14
|
## Info
|
|
14
15
|
**Req:** {Req ID}
|
|
16
|
+
**Status:** open
|
|
15
17
|
**Title:** {Full title from export}
|
|
16
18
|
**Level:** {Infer from title: "Principal" → J100, "Staff" → J090, "Director" → J100 M-track, "Senior" → J070}
|
|
17
19
|
**Track:** {P-track for IC roles, M-track for Director/Manager roles}
|