@theronap/cortex-mcp 0.9.62 → 0.9.63
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/lib/capture.mjs +104 -1
- package/package.json +1 -1
- package/skills/walkthrough/SKILL.md +189 -0
package/lib/capture.mjs
CHANGED
|
@@ -76,6 +76,97 @@ export function repoFullNameFrom(cwd) {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
// ── SHR-01/T9 — stamp the repos the session WORKED IN, not the one it was launched from ─────────
|
|
80
|
+
//
|
|
81
|
+
// WHY THIS EXISTS. `repoFullNameFrom(cwd)` above reads the session's LAUNCH directory. Measured
|
|
82
|
+
// 2026-08-03, four days after the stamp shipped: 3,598 → 3,663 claude-code records, and **still zero
|
|
83
|
+
// carried an identifier**. Not because the code was broken — because Claude Code sessions launch from
|
|
84
|
+
// wherever the terminal happened to be. Theron's launch from `~/Documents/brain` (a git repo with no
|
|
85
|
+
// remote), while every bit of the work happened in `~/dev/cortex-worktrees/*` on theronap/cortex.
|
|
86
|
+
// One session that day touched 319+ paths under those worktrees and was stamped with nothing.
|
|
87
|
+
//
|
|
88
|
+
// So the launch directory is the wrong question. What the clearance rule (ADR-0019) actually asks is
|
|
89
|
+
// whether two people *participated in the same work context* — and the transcript already records
|
|
90
|
+
// that directly, as the files the session read and wrote.
|
|
91
|
+
//
|
|
92
|
+
// ⚠ THE THRESHOLD IS A SECURITY KNOB, NOT A TUNING PARAMETER. Every repo stamped here becomes a key
|
|
93
|
+
// that lets that repo's other workers read this session's SCOPED records. Too low and glancing at one
|
|
94
|
+
// file in repo X hands X's members a session that was really about Y; too high and genuine work goes
|
|
95
|
+
// unstamped, which is the bug above. 3 sits in a wide empty gap — real work in a repo touches dozens
|
|
96
|
+
// to hundreds of files, a drive-by check touches one or two — so the rule rarely makes a close call.
|
|
97
|
+
//
|
|
98
|
+
// Chosen deliberately conservative because the direction matters: LOWERING this later takes effect
|
|
99
|
+
// immediately and safely, while RAISING it does NOT revoke stamps already written to
|
|
100
|
+
// records.event_identifiers. Start tight, loosen once there is real collaborator data.
|
|
101
|
+
export const MIN_FILES_FOR_STAMP = 3
|
|
102
|
+
|
|
103
|
+
// Bounds the clearance surface a single session can claim, and the work done to compute it.
|
|
104
|
+
export const MAX_STAMPED_REPOS = 5
|
|
105
|
+
const MAX_DIRS_PROBED = 25
|
|
106
|
+
|
|
107
|
+
// Absolute paths this session touched: file_path/path/notebook_path on any tool call, plus absolute
|
|
108
|
+
// paths appearing in Bash commands. Best-effort and total — a malformed transcript yields [], never
|
|
109
|
+
// throws, because capture must never break a session.
|
|
110
|
+
export function touchedPaths(transcript) {
|
|
111
|
+
const out = []
|
|
112
|
+
if (!transcript) return out
|
|
113
|
+
for (const line of String(transcript).split('\n')) {
|
|
114
|
+
if (!line) continue
|
|
115
|
+
let d
|
|
116
|
+
try { d = JSON.parse(line) } catch { continue }
|
|
117
|
+
const content = d?.message?.content
|
|
118
|
+
if (!Array.isArray(content)) continue
|
|
119
|
+
for (const b of content) {
|
|
120
|
+
if (b?.type !== 'tool_use') continue
|
|
121
|
+
const inp = b.input ?? {}
|
|
122
|
+
for (const k of ['file_path', 'path', 'notebook_path']) {
|
|
123
|
+
if (typeof inp[k] === 'string' && inp[k].startsWith('/')) out.push(inp[k])
|
|
124
|
+
}
|
|
125
|
+
if (typeof inp.command === 'string') {
|
|
126
|
+
// Non-repo matches (/tmp, /usr, …) simply resolve to no repo and cost one cached probe.
|
|
127
|
+
for (const m of inp.command.match(/\/(?:Users|home|opt|srv|var)\/[^\s"'`;|&)<>]+/g) ?? []) out.push(m)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return out
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// The repos this session actually worked in. Always a SUPERSET of the launch-cwd behaviour: the
|
|
135
|
+
// launch repo is included unconditionally when it resolves, so nothing that stamps correctly today
|
|
136
|
+
// stops stamping. Everything else must clear MIN_FILES_FOR_STAMP.
|
|
137
|
+
export function repoFullNamesFrom(transcript, cwd) {
|
|
138
|
+
const launch = repoFullNameFrom(cwd)
|
|
139
|
+
const filesByRepo = new Map() // repo -> Set(distinct file paths)
|
|
140
|
+
const touchesByDir = new Map() // dir -> touch count
|
|
141
|
+
|
|
142
|
+
for (const p of touchedPaths(transcript)) {
|
|
143
|
+
const dir = dirname(p)
|
|
144
|
+
touchesByDir.set(dir, (touchesByDir.get(dir) ?? 0) + 1)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Probe the most-touched directories first, so a bounded budget still covers the real work.
|
|
148
|
+
const dirs = [...touchesByDir.entries()].sort((a, b) => b[1] - a[1]).slice(0, MAX_DIRS_PROBED)
|
|
149
|
+
const repoOfDir = new Map()
|
|
150
|
+
for (const [dir] of dirs) {
|
|
151
|
+
if (!repoOfDir.has(dir)) repoOfDir.set(dir, repoFullNameFrom(dir))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
for (const p of touchedPaths(transcript)) {
|
|
155
|
+
const repo = repoOfDir.get(dirname(p))
|
|
156
|
+
if (!repo) continue
|
|
157
|
+
if (!filesByRepo.has(repo)) filesByRepo.set(repo, new Set())
|
|
158
|
+
filesByRepo.get(repo).add(p)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const earned = [...filesByRepo.entries()]
|
|
162
|
+
.filter(([repo, files]) => files.size >= MIN_FILES_FOR_STAMP || repo === launch)
|
|
163
|
+
.sort((a, b) => b[1].size - a[1].size)
|
|
164
|
+
.map(([repo]) => repo)
|
|
165
|
+
|
|
166
|
+
const all = launch ? [launch, ...earned.filter((r) => r !== launch)] : earned
|
|
167
|
+
return all.slice(0, MAX_STAMPED_REPOS)
|
|
168
|
+
}
|
|
169
|
+
|
|
79
170
|
// (no bun, no repo clone). Always exits 0 — capture must never break a session.
|
|
80
171
|
|
|
81
172
|
function readStdin() {
|
|
@@ -202,6 +293,17 @@ async function captureWork(stdinRaw) {
|
|
|
202
293
|
// when the cwd is not a GitHub worktree — the record still lands, it just stays private (D2).
|
|
203
294
|
const repoFullName = repoFullNameFrom(hook.cwd)
|
|
204
295
|
|
|
296
|
+
// SHR-01/T9: ...and the repos the session actually WORKED IN, which is usually not the same thing —
|
|
297
|
+
// the launch cwd stamped 0 of 3,663 sessions. Reads the RAW transcript, not the redacted tail above:
|
|
298
|
+
// the tail is truncated to ~6k chars and would miss most of the session's file paths. Nothing from
|
|
299
|
+
// this raw read is transmitted — only the derived 'owner/name' strings leave the machine.
|
|
300
|
+
let repoFullNames = repoFullName ? [repoFullName] : []
|
|
301
|
+
try {
|
|
302
|
+
if (hook.transcript_path) {
|
|
303
|
+
repoFullNames = repoFullNamesFrom(readFileSync(hook.transcript_path, 'utf8'), hook.cwd)
|
|
304
|
+
}
|
|
305
|
+
} catch { /* best-effort — a session with no derivable repo is private, not broken */ }
|
|
306
|
+
|
|
205
307
|
const common = {
|
|
206
308
|
source: 'claude-code',
|
|
207
309
|
project: repo,
|
|
@@ -209,7 +311,8 @@ async function captureWork(stdinRaw) {
|
|
|
209
311
|
title: `Worked in ${repo}`,
|
|
210
312
|
payload: { session_id: hook.session_id, cwd: hook.cwd },
|
|
211
313
|
captureSource: 'hook', // T8: fallback writer — never clobbers a cortex-log ('skill') record
|
|
212
|
-
...(repoFullName ? { repoFullName } : {}),
|
|
314
|
+
...(repoFullName ? { repoFullName } : {}), // back-compat: older servers read only this
|
|
315
|
+
...(repoFullNames.length ? { repoFullNames } : {}),
|
|
213
316
|
...(hydratedFrom.length ? { hydratedFrom } : {}),
|
|
214
317
|
}
|
|
215
318
|
const extracted = transcript ? extractSession(transcript) : null
|
package/package.json
CHANGED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cortex-walkthrough
|
|
3
|
+
description: Run the guided Agnoclast walkthrough for someone new. Use when the person asks for the walkthrough, a tutorial, or getting started — "give me the walkthrough", "walk me through this", "how do I use this", "show me around", "what can this do", "remind me how this works" — or when a brand-new user needs orienting for the first time.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **Cortex-managed skill.** This file is installed and kept up to date by Cortex. Local edits are
|
|
7
|
+
> restored on the next session (a backup of your version is saved alongside). Don't rely on changes here.
|
|
8
|
+
|
|
9
|
+
# The Agnoclast walkthrough
|
|
10
|
+
|
|
11
|
+
You are orienting someone who is probably **not technical** and did not ask for a lecture. Treat
|
|
12
|
+
this file as a script to perform, not a document to display.
|
|
13
|
+
|
|
14
|
+
## The rules, in priority order
|
|
15
|
+
|
|
16
|
+
1. **Never paste this file at them.** Say the first idea in your own words, ask one question, wait.
|
|
17
|
+
A wall of text is a failed walkthrough even if every word is correct.
|
|
18
|
+
2. **No jargon. None.** Do not say *node, page, tier, MCP, grep, authoring, graph, retrieval,
|
|
19
|
+
scoped, red-link, records, timeline*. Say "I wrote that down", not "I authored a node". This is
|
|
20
|
+
not a style preference — it is the measured failure mode of this product. A new user was given
|
|
21
|
+
identifier-dense terminology and had to stop and ask what the assistant was talking about.
|
|
22
|
+
*Brain* is the one term you may introduce, and only in walkthrough 3.
|
|
23
|
+
3. **Use their real life immediately.** Never demo with a made-up example. Ask what is actually on
|
|
24
|
+
their plate and build the walkthrough out of their answer. Someone who ends this holding a list
|
|
25
|
+
of their own real things is converted; someone who watched a demo is not.
|
|
26
|
+
4. **Do it, don't describe it.** When they mention something, write it down for real, then show them
|
|
27
|
+
it came back. The first run must end with something true stored and retrieved — not with them
|
|
28
|
+
understanding an architecture.
|
|
29
|
+
5. **One step at a time, and check in.** After each step: *"want to keep going, or is that enough for
|
|
30
|
+
now?"* Stopping early is a success. Say so.
|
|
31
|
+
6. **When they ramble, that is the product working.** Do not redirect them to be more concise.
|
|
32
|
+
Extract from the mess yourself. Their willingness to talk sloppily is the behaviour you want.
|
|
33
|
+
7. **Never make them feel behind.** No streaks, no "you haven't used this in a while", no half-done
|
|
34
|
+
setup checklists. If they return after three weeks, pick up like nothing happened.
|
|
35
|
+
8. **If they ask what it costs or how it works underneath, answer plainly and briefly, then get back
|
|
36
|
+
to their stuff.** Do not pitch.
|
|
37
|
+
|
|
38
|
+
**You are done when** they have said something real, you stored it, and they saw it come back. Ten
|
|
39
|
+
minutes, one loop closed. Everything else is optional.
|
|
40
|
+
|
|
41
|
+
## Opening
|
|
42
|
+
|
|
43
|
+
Say roughly this, in your own words:
|
|
44
|
+
|
|
45
|
+
> Agnoclast is a memory you and I share. Anything you tell me — a decision, something you need to do,
|
|
46
|
+
> how something works, what someone said — gets written down in one place I read before I answer you.
|
|
47
|
+
> So you stop re-explaining your own life every time you open a chat. It remembers; you don't have to.
|
|
48
|
+
> It's Jarvis, minus the flying suit.
|
|
49
|
+
|
|
50
|
+
Then offer the menu below and let them pick. If they don't care, start with walkthrough 1.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Walkthrough 1 — keeping track of your life
|
|
55
|
+
|
|
56
|
+
*The one most people should do first. About ten minutes.*
|
|
57
|
+
|
|
58
|
+
**The problem it solves:** the cost of holding a hundred small things in your head isn't the
|
|
59
|
+
forgetting, it's the background hum of trying not to forget, running all day underneath everything
|
|
60
|
+
else. This puts that down. Unlike every to-do app they have quit, they never maintain it — they
|
|
61
|
+
mention things in passing and later ask what they were supposed to follow up on.
|
|
62
|
+
|
|
63
|
+
**Step 1 — empty their head.** Ask ONE question and then stop talking: *"What's actually on your
|
|
64
|
+
plate this week?"* Let them talk. Do not interrupt to confirm items or number things back at them
|
|
65
|
+
mid-flow. Interrupting the dump is the most common way to break this.
|
|
66
|
+
|
|
67
|
+
They will undersell it — most people give three things and stop. Follow up **once**, gently, with a
|
|
68
|
+
specific probe: *"anything you're overdue getting back to?"* That usually yields another five. Once.
|
|
69
|
+
Twice is an interrogation.
|
|
70
|
+
|
|
71
|
+
**Step 2 — store it for real while they are still talking**, not in a tidy summary at the end. Then
|
|
72
|
+
play it back grouped plainly: what needs doing, what they're waiting on someone else for, what's
|
|
73
|
+
just worth remembering. Do not invent priorities, due dates or categories they didn't give you —
|
|
74
|
+
inventing structure is how this starts feeling like an app they have to maintain.
|
|
75
|
+
|
|
76
|
+
Invite correction explicitly: *"Tell me what I got wrong."* Then actually change it. The first
|
|
77
|
+
correction is the moment it becomes theirs.
|
|
78
|
+
|
|
79
|
+
**Step 3 — close the loop, for real.** Start a fresh conversation (or at minimum ask the retrieval
|
|
80
|
+
question and answer it purely from what's stored, saying plainly that a brand-new conversation would
|
|
81
|
+
have seen the same): **"What was I supposed to follow up on?"**
|
|
82
|
+
|
|
83
|
+
That is the whole point and it must actually happen. They saved no file, named no document, picked
|
|
84
|
+
no folder. They talked, and it came back.
|
|
85
|
+
|
|
86
|
+
**Step 4 — hand them the one habit that matters**, then stop: *"From now on, whenever something
|
|
87
|
+
lands on you, just say 'don't let me forget X'. That's the whole thing."*
|
|
88
|
+
|
|
89
|
+
**Never** propose a tagging scheme, folder structure, priority system, daily review ritual or naming
|
|
90
|
+
convention. Every one of those is why they quit the last four apps. If they *ask* for structure,
|
|
91
|
+
give the least you can get away with.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Walkthrough 2 — just tell it what's going wrong
|
|
96
|
+
|
|
97
|
+
*The one people are most surprised by, and the highest-converting. Also the easiest to run badly.*
|
|
98
|
+
|
|
99
|
+
**Open by inviting the complaint directly:** *"What's the most annoying thing on your plate right
|
|
100
|
+
now? Don't organise it — just tell me what's going wrong."* Explicit permission to be messy is the
|
|
101
|
+
entire opening move. Do not ask them to "describe a challenge".
|
|
102
|
+
|
|
103
|
+
**Why it works, if they ask:** a frustrated ramble is a *better* input than a careful question. It's
|
|
104
|
+
loaded with who's involved, what's blocked, what has a deadline and what they're worried about — and
|
|
105
|
+
it took nine seconds. A polished prompt would contain less.
|
|
106
|
+
|
|
107
|
+
**Then do all three steps in one turn:**
|
|
108
|
+
|
|
109
|
+
1. **Untangle it.** Give the mess back as its actual separate parts. Most of the relief is here — a
|
|
110
|
+
mess is heavy mostly because it's undifferentiated.
|
|
111
|
+
2. **Name the load-bearing piece.** Usually one thing blocks everything else, and usually it isn't
|
|
112
|
+
the part they're angriest about.
|
|
113
|
+
3. **Produce the artifact.** Draft the email. Write the message. Give them the actual words. **Never
|
|
114
|
+
end on "would you like me to draft that?"** — draft it; they can tell you it's wrong. Stopping at
|
|
115
|
+
analysis is the single most common way to blow this walkthrough, because step 2 feels complete.
|
|
116
|
+
|
|
117
|
+
**Then make the persistence visible, once:** *"I've kept the background on this — next time you can
|
|
118
|
+
just say 'the Henderson thing' and I'll know."* One sentence about the benefit. Do not explain how
|
|
119
|
+
storage works.
|
|
120
|
+
|
|
121
|
+
**Do not clean up their language back at them.** If they were sarcastic or profane, engage with the
|
|
122
|
+
substance in your normal register. Sanitising their framing into corporate-speak reads as
|
|
123
|
+
disapproval and they will start self-editing, which destroys the exact input quality this unlocks.
|
|
124
|
+
|
|
125
|
+
**Do not moralise about venting.** No "sounds like you're under a lot of stress", no wellness pivot,
|
|
126
|
+
no suggesting a break. They came for leverage, not to be handled. Treat the complaint as information
|
|
127
|
+
and move. Match their energy — if they're being funny about how bad it is, be a little funny back.
|
|
128
|
+
|
|
129
|
+
**If they push back on the draft, take it and revise immediately without defending it.**
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Walkthrough 3 — personal and work, kept separate
|
|
134
|
+
|
|
135
|
+
*Only run this if they have raised work. Offer once and drop it otherwise — pushing it on someone
|
|
136
|
+
who didn't ask is how onboarding starts feeling like a sales funnel.*
|
|
137
|
+
|
|
138
|
+
**Lead with the guarantee, not the feature.** Their personal brain is private and unreachable from
|
|
139
|
+
anywhere else. Say that before they ask, because it's the concern they have whether or not they
|
|
140
|
+
voice it.
|
|
141
|
+
|
|
142
|
+
*Brain* is the one piece of vocabulary you may introduce. Define it once in plain words — "a
|
|
143
|
+
walled-off set of what it knows" — then use it normally. Do not add *tier, scope, org, member,
|
|
144
|
+
permission, isolation* on top.
|
|
145
|
+
|
|
146
|
+
**The shape:** they have a personal one now. For work they make a second, separate one. Separate
|
|
147
|
+
means separate — the work one cannot reach the personal one, and colleagues invited into the work
|
|
148
|
+
one see only that. The rule that covers ninety percent of cases: *would it be fine if a colleague
|
|
149
|
+
read this?* If they had to think about it, personal.
|
|
150
|
+
|
|
151
|
+
**Be precise and honest about privacy.** If they ask a pointed question about who can see their data
|
|
152
|
+
— including whether the company operating the product can — answer accurately and without spin. If
|
|
153
|
+
you don't know, say so and offer to find out. A confident wrong answer here is far more damaging
|
|
154
|
+
than an admitted gap.
|
|
155
|
+
|
|
156
|
+
**Mention employer rules plainly, as useful advice rather than legal throat-clearing:** some
|
|
157
|
+
workplaces and industries have real constraints on putting client or company data into a new system.
|
|
158
|
+
Being the person who checked first is a much better position than the alternative.
|
|
159
|
+
|
|
160
|
+
**Do not create anything without an explicit yes** — a second brain is a real thing that exists
|
|
161
|
+
afterwards. And if they ask about bringing colleagues in, describe the outcome (shared context, no
|
|
162
|
+
one is the bottleneck, knowledge doesn't leave when someone does), not the mechanics. Walk the
|
|
163
|
+
actual invite only when they say they want to send one.
|
|
164
|
+
|
|
165
|
+
**Do not coach them on selling it to their boss unless they ask.**
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Ten things to try, written the way people actually say them
|
|
170
|
+
|
|
171
|
+
Offer a few of these when the walkthrough ends, or if someone just wants ideas.
|
|
172
|
+
|
|
173
|
+
1. *"Here's everything I'm juggling right now"* — then just talk for two minutes.
|
|
174
|
+
2. *"What was I supposed to follow up on?"* — the highest-value question in the product. Monday morning.
|
|
175
|
+
3. *"Remind me what I decided about ___ and why."*
|
|
176
|
+
4. *"I need to write a ___ ."* It already knows the background, so they skip explaining it.
|
|
177
|
+
5. *"What am I forgetting?"*
|
|
178
|
+
6. *"Who was that person who ___ ?"*
|
|
179
|
+
7. *"This is driving me crazy: ___"* — see walkthrough 2.
|
|
180
|
+
8. *"Catch me up on ___ ."* Assembles the story rather than listing.
|
|
181
|
+
9. *"Don't let me forget ___ ."* The one-line capture.
|
|
182
|
+
10. *"What did I do last week?"* Good for status updates, timesheets, and remembering you got things done.
|
|
183
|
+
|
|
184
|
+
**If they only ever use two, make them #2 and #7.** That is the whole product for most people.
|
|
185
|
+
|
|
186
|
+
## Closing
|
|
187
|
+
|
|
188
|
+
Tell them how to come back, once, at the end — and then stop: *"Any time you want this again, just
|
|
189
|
+
say 'give me the walkthrough'."*
|