@maccesar/aiskills 1.15.0 → 1.16.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/README.md CHANGED
@@ -74,6 +74,7 @@ All three platforms use the same Agent Skills format: a `SKILL.md` file with YAM
74
74
  | audit-codebase | Auditing | Evidence-based audit methodology | 2 files |
75
75
  | vscode-extension-dev | VS Code | VS Code Extension API docs | 14 files |
76
76
  | stitch-showcase | Design Tools | Google Stitch export workflow | 16 files |
77
+ | session-log | Project | Convention + 3 A/B rounds | 2 files |
77
78
 
78
79
  Use `aiskills list` to see available skills from the command line. Pull requests are welcome.
79
80
 
@@ -133,8 +134,6 @@ Hard restrictions:
133
134
  Distribution note:
134
135
  - Available via the plugin install (Option A above). Slash commands are not distributed by the npm CLI (Option B) because they are a Claude Code feature.
135
136
 
136
- ---
137
-
138
137
  ## How skills work
139
138
 
140
139
  Skills activate based on what you ask. You can write prompts normally:
@@ -308,6 +307,52 @@ Reference files:
308
307
 
309
308
  ---
310
309
 
310
+ ### session-log
311
+
312
+ Gives a project one predictable place for its working state, so both you and any assistant know where to look instead of hunting through scattered notes. It installs a fixed four-file convention under `docs/project/` and writes a short pointer into every context file the repo has — `CLAUDE.md`, `AGENTS.md`, `GEMINI.md` — so the notes stay findable no matter which assistant opens the project next.
313
+
314
+ The convention:
315
+
316
+ | File | Holds | Loaded at startup |
317
+ | --- | --- | --- |
318
+ | `status.md` | Where the work stands: half-done things, next step, what's blocked, deployment state | **No** |
319
+ | `requirements.md` | What the system must do, and the acceptance criterion for each item | Yes |
320
+ | `decisions.md` | What was chosen and why. Append-only, dated | Yes |
321
+ | `context.md` | Documentation map, architecture, conventions, traps | Yes |
322
+
323
+ **Why `status.md` is excluded from startup.** Cached context is matched as a prefix — the first byte that differs invalidates everything after it. Status written inside a startup-loaded file means every update throws away the cache for all the stable content behind it. The file you edit most often is the one that must not load at startup.
324
+
325
+ How to use it — just say it, in whatever words you'd use anyway:
326
+
327
+ ```
328
+ "set up the project notes here — the mobile app lives at ../../Apps/MyApp"
329
+ "ya me voy, déjame anotado dónde quedé"
330
+ "where did we leave off? I haven't touched this repo in weeks"
331
+ "my CLAUDE.md has the progress and a date inside it — should I move that?"
332
+ ```
333
+
334
+ Closing a session and resuming one are different jobs and it treats them differently. On the way out it writes; on the way back in it reads `status.md` and then checks it against the repo before repeating it to you — what landed since the file was written, whether the branch it names still exists, what's uncommitted that it never mentioned. A three-week-old note is a snapshot, and the most expensive way to use one is to trust it.
335
+
336
+ There is no slash command, by design: a command and a skill doing the same job means two copies of the logic that drift apart, and a command only works in Claude Code. This is one file that Claude, Codex and Gemini all read the same way — point any of them at `skills/session-log/SKILL.md` if it doesn't pick it up on its own.
337
+
338
+ Once the convention is installed, finding the notes no longer depends on the skill at all — the pointer in `CLAUDE.md`, `AGENTS.md` and `GEMINI.md` is what any assistant reads at startup.
339
+
340
+ What it will not do:
341
+ - Commit, tag, push, or write CHANGELOG entries — that is a release, and releasing assumes the work is finished, which is the opposite of why this exists. Use `/release` for that.
342
+ - Edit your uncommitted code. It reports what it finds broken and leaves it alone.
343
+ - Invent a completion percentage. Without a fixed denominator any number is made up, so it counts what is enumerable or describes status in words.
344
+ - Write a token, a password or a client's private details into the files. They get committed, and a secret deleted in a later commit is still in the history — it records where the credential lives instead.
345
+ - Overwrite the record on arrival. If a resumed file turns out to be badly out of date it says so and offers; rewriting is your call.
346
+
347
+ Measured behaviour, across three A/B rounds against a no-skill baseline (18 runs, adversarially graded):
348
+
349
+ | | With skill | Without |
350
+ | --- | --- | --- |
351
+ | Kept volatile status out of the startup chain | 9 / 9 | 0 / 9 |
352
+ | Left the user's broken uncommitted code untouched | yes | no — fixed it unasked |
353
+
354
+ Token cost is 3–13% higher per run. **Those rounds graded an earlier layout** — a single status file versus an imported memory index — so what they establish is the split itself, not the four filenames. The paths added since (resuming against a stale file, upgrading an earlier install, monorepos, a gitignored `docs/`) have prompts written for them and have not been run. The grading notes, and an explicit account of what is and isn't measured, are in `skills/session-log/evals/`.
355
+
311
356
  ### stitch-showcase
312
357
 
313
358
  A workflow skill for processing Google Stitch design exports. It handles the full lifecycle: from raw zips to a navigable showcase, component standardization, and a visual component catalog.
package/lib/config.js CHANGED
@@ -30,6 +30,7 @@ export const SKILLS = [
30
30
  'audit-codebase',
31
31
  'humaniza',
32
32
  'refactoring-ui',
33
+ 'session-log',
33
34
  'stitch-showcase',
34
35
  'vscode-extension-dev',
35
36
  ];
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@maccesar/aiskills",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "AI coding assistant skills for Claude Code, Gemini CLI, and Codex CLI",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "aiskills": "./bin/aiskills.js"
8
8
  },
9
9
  "scripts": {
10
- "test": "node --test test/**/*.test.js",
10
+ "test": "node --test test/*.test.js",
11
11
  "lint": "eslint lib/**/*.js",
12
12
  "format": "prettier --write lib/**/*.js"
13
13
  },
@@ -0,0 +1,524 @@
1
+ ---
2
+ name: session-log
3
+ description: 'The convention that decides WHERE a project keeps its working state, and why part of it must not load at startup. Four fixed files under docs/project/ — status (volatile, never imported), requirements, decisions, context (stable, imported) — plus a pointer written into every context file the repo has, so the notes are findable from Claude Code, Codex or Gemini alike. Use this whenever someone closes a working session or picks one up ("ya me voy, déjame anotado dónde quedé", "where did we leave off?"), asks where project notes should live or why they keep ending up scattered, wonders whether progress and dates belong inside CLAUDE.md / AGENTS.md / GEMINI.md, or wants project tracking set up or migrated — even when they never say "notes" or name this skill. Not for: releases and version bumps, commit messages, CHANGELOG entries, build or deploy status, issue trackers, or a spoken recap the user only wants to read.'
4
+ ---
5
+
6
+ # Session Log
7
+
8
+ Work spans sessions; context does not. Notes end up scattered — some in a context
9
+ file, some in a README, some in a doc nobody opens — so neither the person nor the
10
+ next assistant knows where to look.
11
+
12
+ This skill fixes that with one fixed convention, installed once per project. After
13
+ that, finding the notes no longer depends on this skill at all: any assistant that
14
+ reads the repo's context file finds the pointer and knows where everything lives.
15
+ That's the point — the convention has to survive being used by tools that never
16
+ heard of it.
17
+
18
+ ## The convention
19
+
20
+ Four files, always the same names, always the same place:
21
+
22
+ ```
23
+ docs/project/
24
+ status.md Where the work stands right now. Half-done things,
25
+ next step, what's blocked, deployment state.
26
+ VOLATILE — never loaded at startup.
27
+
28
+ requirements.md What the system must do, and how you'd know it does.
29
+ The contract. STABLE — loaded at startup.
30
+
31
+ decisions.md What was chosen and why. Append-only, dated.
32
+ STABLE — loaded at startup.
33
+
34
+ context.md How the project is put together: documentation map,
35
+ architecture, conventions, the traps that cost a day.
36
+ STABLE — loaded at startup.
37
+ ```
38
+
39
+ The split between `requirements.md` and `status.md` is deliberate and easy to get
40
+ wrong. **The contract goes in requirements; the progress goes in status.** What a
41
+ feature must do changes when the scope changes — rarely. Whether it's finished
42
+ changes constantly. Putting them in one file means the contract gets rewritten
43
+ every day, which invalidates the cached prefix behind it: the exact failure this
44
+ convention exists to prevent.
45
+
46
+ Fixed names are the whole point. A convention that adapts per project isn't a
47
+ convention — it's the scattered-notes problem with extra steps. Someone opening
48
+ any repo should know where to look without reading anything first.
49
+
50
+ ### The client's vocabulary goes in the content, never in the paths
51
+
52
+ Projects grow words: *modules*, *phases*, *blocks*, *deliverables*, *sprints*.
53
+ Those words usually come from a conversation with whoever is paying — someone said
54
+ "the work orders module" and it stuck. That's fine as a way to talk. It's a
55
+ mistake as a directory structure.
56
+
57
+ The moment the vocabulary becomes folders, two things happen. The layout stops
58
+ being predictable across projects, because the next client uses a different word.
59
+ And renaming becomes expensive, so the structure outlives the conversation that
60
+ produced it — you end up with `docs/modulos/modulo-3-.../02-implementacion/` in
61
+ one repo and `documentacion-importante/backend/` in another, both reasonable when
62
+ they were created and neither findable from the outside.
63
+
64
+ So: the four files are always the four files. Parts of the project are **headings
65
+ inside them** — a section per module in `requirements.md`, a line per module in
66
+ `status.md`. When the vocabulary changes, you edit a heading instead of moving a
67
+ tree.
68
+
69
+ This also keeps the depth. A project with real modules still gets a detailed
70
+ breakdown; it just lives under a heading rather than a path.
71
+
72
+ ### Never put the date in the filename
73
+
74
+ `status-2026-07-21.md`, `resumen-avances-julio.md`, `progreso-etapa-1.md` — each
75
+ one is a session that created a new file instead of updating the existing one.
76
+ After a month there are twenty and none of them is *the current one*; finding out
77
+ which is means opening several and comparing dates. That's the scattered-notes
78
+ problem reappearing inside the folder that was supposed to solve it.
79
+
80
+ The date goes **inside** `status.md`, at the top, and the file is overwritten.
81
+ History is what git is for: `git log docs/project/status.md` gives you every past
82
+ state, with its date, for free.
83
+
84
+ The same applies to anything that sounds like a holding area — `to-review/`,
85
+ `pending/`, `notes-temp/`. A file whose location says "somebody should look at
86
+ this eventually" gets neither read nor deleted. Either it's current and belongs in
87
+ one of the four files, or it's stale and should say so.
88
+
89
+ ### When the project spans more than one repo
90
+
91
+ A system with a web backend and a mobile client is one project in two
92
+ repositories. Very often it's also **one working session**: someone adds an
93
+ endpoint on the API side and, without switching context, wires the app that
94
+ consumes it. The work is a single thought; only the folders are separate.
95
+
96
+ **Install from inside each repo, separately.** Open the backend, install; open the
97
+ app, install. It's a one-time act per repo and it's worth doing from the right
98
+ place: sitting inside the project means its own context file loads, its own MCP
99
+ servers connect, and its stack-specific skills detect themselves. Installing a
100
+ repo's notes from its sibling means describing a project you're looking at from
101
+ outside — and the result reads like it, because the detail that makes `context.md`
102
+ useful is exactly what you don't see from across the fence.
103
+
104
+ Each keeps its own `status.md` — two repos have two branches, two deploy states
105
+ and two histories, and one shared file would go stale on whichever side isn't
106
+ being edited.
107
+
108
+ Put the sibling's **path** in the header, not just its name, so whoever reads it
109
+ next can actually go there:
110
+
111
+ ```markdown
112
+ **Sibling:** `../../Apps/EM Industrial` (Titanium client) — waiting on
113
+ `/work-orders/{id}/progress`, not built here yet.
114
+ ```
115
+
116
+ **Once both are installed, updating them from one session is fine** — that's the
117
+ day-to-day case, and it's different from installing. The files already exist and
118
+ carry the project's own vocabulary; you're appending what changed, not inventing
119
+ a description of a repo you can't see.
120
+
121
+ **When a session touched both, close both.** This is the part that gets skipped,
122
+ and it's where the two halves drift into separate realities: the mobile notes say
123
+ "waiting on the API" for three weeks while the backend's notes never mention that
124
+ anything is waiting. If you added the endpoint and consumed it in the same
125
+ session, both `status.md` files changed — write both before finishing.
126
+
127
+ Even then, write the sibling's status from what you did to it, not from what you
128
+ assume about it. "Added the client call for `/work-orders/{id}/progress`" is
129
+ something you know. "The app is now feature-complete for E5" is something the app
130
+ would have to tell you.
131
+
132
+ If the sibling isn't reachable from where you're working, say so in the handoff
133
+ rather than guessing at its state. "Endpoint added here; the app side needs its
134
+ status updated, I couldn't reach that repo" is honest and actionable. A confident
135
+ claim about a repo you didn't open is neither.
136
+
137
+ A **monorepo** is the opposite case and takes the opposite answer — one
138
+ `docs/project/` at the root, packages as headings — because one repo has one branch,
139
+ one deploy and one history to describe. And `status.md` being rewritten whole every
140
+ session makes it **conflict-prone the moment a second person or branch touches it**.
141
+ Both cases are in `references/file-layout.md`; neither comes up on a project with one
142
+ person and one branch, which is most of them.
143
+
144
+ ### Why status.md is not loaded at startup
145
+
146
+ Context files load at the start of every session, along with everything they
147
+ import. Cached context is matched as a **prefix**: byte by byte from the start,
148
+ and the first byte that differs invalidates everything after it.
149
+
150
+ So a status line inside a startup-loaded file means every update to that line
151
+ throws away the cache for all the stable content behind it — content that didn't
152
+ change. The file you edit most often is the one that must not load at startup.
153
+
154
+ There's a second reason. Stable context is *instructions*: it shapes how the
155
+ assistant works. Status is *data*: it answers a question. Loading data as
156
+ instructions every session costs tokens and dilutes the instructions that matter.
157
+
158
+ `status.md` is read on demand — when someone resumes work and asks where things
159
+ stand. That's cheap, and it's when the information is actually wanted.
160
+
161
+ The same arithmetic catches `decisions.md` eventually. Append-only *and* imported
162
+ only works while the file is young; after two years it's a long document loaded in
163
+ full every session to answer a question nobody asked. Past roughly two hundred
164
+ lines, everything but the current year moves to `decisions-archive.md`, which is not
165
+ imported — nothing deleted, still searchable when someone needs it.
166
+ `references/file-layout.md` has the mechanics.
167
+
168
+ ## Installing it
169
+
170
+ Write the same block into **every** context file the repo has. Not one; all of
171
+ them. Different people and different tools read different files, and a note only
172
+ one assistant can find is a note that disappears the day someone switches.
173
+
174
+ The usual ones are `CLAUDE.md`, `AGENTS.md` and `GEMINI.md`, but the list keeps
175
+ growing: `.github/copilot-instructions.md`, `.cursorrules` or `.cursor/rules/`,
176
+ `.windsurfrules`, `CONVENTIONS.md`. Write into the ones that exist rather than
177
+ creating new ones — a `GEMINI.md` invented for a repo where nobody uses Gemini is a
178
+ file that will rot unread, and the point is to reach the readers who are already
179
+ there.
180
+
181
+ Keep the block short. Duplicated text drifts out of sync — three lines that say
182
+ the same thing survive that; three paragraphs don't.
183
+
184
+ ```markdown
185
+ ## Project state
186
+
187
+ - `docs/project/requirements.md` — what the system must do
188
+ - `docs/project/context.md` — architecture and conventions
189
+ - `docs/project/decisions.md` — what was decided and why
190
+ - `docs/project/status.md` — where the work stands right now
191
+
192
+ Read `status.md` when resuming work. Do not import it at startup: it changes
193
+ constantly, and loading it invalidates the cached prefix behind it.
194
+ ```
195
+
196
+ Import `requirements.md`, `context.md` and `decisions.md` if the tool supports
197
+ imports; leave `status.md` out of every import chain. Then create the files with real
198
+ content read from the repo, never placeholders — a template nobody filled in is
199
+ worse than nothing, because it looks maintained.
200
+
201
+ **Write the content in the language the project is already documented in.** The
202
+ templates here are in English because the skill is; the files are for whoever opens
203
+ the repo next. A `status.md` in English in a project whose README, commits and
204
+ client conversations are in Spanish is a small tax on every future read, and the
205
+ acceptance criteria are the part that suffers most — they're quoting what someone
206
+ actually agreed to, and translating that loses the words the agreement was made in.
207
+ File and section names stay fixed regardless; that's what makes them findable.
208
+
209
+ ### Check that the location is actually tracked
210
+
211
+ Before writing anything, confirm the target path isn't ignored:
212
+
213
+ ```bash
214
+ git check-ignore -v docs/project/status.md
215
+ ```
216
+
217
+ Plenty of repos ignore `docs/` because they generate documentation into it. If
218
+ that's the case here, the notes you're about to write will look fine locally and
219
+ vanish on clone — the failure is silent, and it surfaces weeks later when someone
220
+ else opens the project and finds nothing.
221
+
222
+ Fixing it needs care: git can't re-include a file whose parent directory is
223
+ excluded, so `!docs/project/` under a `docs/` rule does nothing. The pattern has
224
+ to exclude the *contents* instead:
225
+
226
+ ```gitignore
227
+ docs/*
228
+ !docs/project/
229
+ ```
230
+
231
+ If the repo ignores `docs/` for a reason you'd rather not touch, put the
232
+ convention somewhere tracked and say where — a predictable location that exists
233
+ beats a canonical one that doesn't.
234
+
235
+ ### Tracked means published
236
+
237
+ Being tracked is the point and also the risk: these files get committed, pushed, and
238
+ on a public repo indexed. Session notes attract exactly what shouldn't travel — a
239
+ token pasted while debugging, a staging URL with credentials in it, a client's phone
240
+ number, the reason a particular customer is unhappy.
241
+
242
+ Write around it. "The API key is in 1Password under *Gym staging*" carries the same
243
+ information to the next session and none of the exposure; "blocked on the client's
244
+ approval" says what's blocked without narrating a conversation someone would rather
245
+ not find on GitHub. Anything that genuinely has to be verbatim belongs wherever the
246
+ project already keeps secrets, pointed at from `status.md`. Git makes this expensive
247
+ to undo — a secret deleted in a later commit is still in the history — so it's much
248
+ cheaper not to write it.
249
+
250
+ ### Map the documentation that already exists
251
+
252
+ Before writing `context.md`, inventory what the project has documented: everything
253
+ under `docs/`, plus `README.md`, `CONTRIBUTING.md`, and any spec or plan sitting
254
+ elsewhere. Open each one far enough to say what it's for in a line.
255
+
256
+ Then put that map in `context.md` as a section — one line per document, saying
257
+ what it covers and when someone would need it. Not a file listing; a listing is
258
+ what `ls` already does. The value is in "read this before touching X".
259
+
260
+ This matters more than it looks. A repo usually has more documentation than
261
+ anyone remembers, and the parts nobody remembers are functionally lost — the same
262
+ scattered-notes problem, just with better-looking files. A doc that exists and
263
+ isn't referenced anywhere will be rediscovered by accident or rewritten from
264
+ scratch.
265
+
266
+ Two rules while mapping:
267
+
268
+ - **Reference, don't absorb.** A plan, a PRD, a numbered checklist has structure
269
+ someone built on purpose. Point at it and say what it's for. Flattening it into
270
+ `context.md` destroys the structure and creates a second copy that will drift.
271
+ - **Say when it's stale.** If a document contradicts the code, that's worth a line
272
+ in the map — "describes the v2 schema, superseded by decisions.md 2026-07-31".
273
+ A map that presents rotten docs as current is worse than no map.
274
+
275
+ Keep it current the same way: when a session adds or invalidates a document,
276
+ the map gets a line. That's cheap, and it's what keeps the map trustworthy.
277
+
278
+ Documents other tools generate belong in the map too, and they go missing fastest —
279
+ an audit report, a migration plan, a design review, read once and then the stalest
280
+ file in the repo. Map them **with the date they describe**: an audit of the codebase
281
+ as it stood three months ago is a historical record, not a to-do list, and whatever
282
+ survived from it should already be a line in `status.md` or an entry in
283
+ `decisions.md`.
284
+
285
+ **Migrating a project that already has notes elsewhere.** Move the content into
286
+ the four files, then delete the old location and point anything that referenced
287
+ it at the new place. Leaving both is how you get scattered notes again. Tell the
288
+ person exactly what moved where.
289
+
290
+ Templates and wiring detail: `references/file-layout.md`.
291
+
292
+ ## Requirements: the denominator
293
+
294
+ "What's left?" is unanswerable without knowing what finished looks like. That's
295
+ what `requirements.md` is for, and it's the one file that lets you say how much
296
+ remains without inventing a number.
297
+
298
+ Most projects already have this somewhere — a PRD, a proposal, a numbered
299
+ checklist, an email thread that got pasted into a doc. **Reference it, don't
300
+ rewrite it.** `requirements.md` is an index: what the system must do, the
301
+ acceptance criterion for each item, and a pointer to wherever the detail lives.
302
+ If the project genuinely has nothing written, this is the file you write first —
303
+ before any code, and often before there's a repo worth speaking of.
304
+
305
+ An acceptance criterion is the useful half. "Payments work" isn't checkable;
306
+ "charging a member writes a Payment row and the receipt shows the folio" is. When
307
+ someone later asks whether a requirement is done, the criterion is what you
308
+ verify against — and if you can't write one, the requirement isn't specified yet,
309
+ which is itself worth recording.
310
+
311
+ ### When there is no code yet
312
+
313
+ Proposal, requirements gathering, design — the work is real and it's exactly where
314
+ people forget where they left off, but there's no diff to verify against. Adapt
315
+ rather than skip: `requirements.md` and `decisions.md` carry the weight, `status.md`
316
+ records what the client agreed and what's still open, and verification runs against
317
+ the artifacts that do exist — a requirement that says "as agreed in the proposal"
318
+ can be checked against the proposal. Don't create empty files waiting for a phase
319
+ that hasn't arrived; `references/file-layout.md` covers how to size this down.
320
+
321
+ ## Which job this is
322
+
323
+ Three jobs share this skill — install the convention, resume work, close a session —
324
+ and the first has a variant worth catching before you write anything. Which one it
325
+ is depends on the repo and on whether the person is arriving or leaving, not on how
326
+ the request was phrased. Look before deciding:
327
+
328
+ ```bash
329
+ ls docs/project/ # installed already?
330
+ ls CLAUDE.md AGENTS.md GEMINI.md CONVENTIONS.md \
331
+ .cursorrules .github/copilot-instructions.md # which context files exist
332
+ ls -d .claude/memory .codex .gemini .cursor/rules # notes living somewhere else
333
+ find docs -name "*.md" -not -path "docs/project/*"; ls README.md CONTRIBUTING.md
334
+ ```
335
+
336
+ Read the output, not the exit status. These lines report "No such file" for whatever
337
+ is absent, and that *is* the answer — but a command that failed on a missing path
338
+ looks a lot like one that found nothing, and mistaking the two here is how you end
339
+ up installing on top of a setup that already existed.
340
+
341
+ **Nothing under `docs/project/`** — install the convention. Create the files that
342
+ have content, fill them from what you actually read in the repo, add the pointer
343
+ block to every context file found. If the third line turned something up, migrate
344
+ it in and delete the old location; two places is the problem this solves. Say
345
+ exactly what moved where, so the person can audit it.
346
+
347
+ **Something that is almost this convention** — a single `docs/status/current.md`, or
348
+ three of the four files under names someone chose by hand. That's an upgrade, not a
349
+ fresh install: rename into the fixed names, fold the content into the right file,
350
+ and update the pointer blocks that referenced the old paths. Treat the existing
351
+ content as correct until the repo says otherwise — it was written by someone who was
352
+ there.
353
+
354
+ **Already there and the person is arriving** — resume. That's the next section, and
355
+ it writes nothing unless they ask.
356
+
357
+ **Already there and the person is leaving** — close the session: update `status.md`,
358
+ and touch the other three only if something stable changed. That's "Closing a
359
+ session", below.
360
+
361
+ ## Resuming work
362
+
363
+ "Where did we leave off?" is a read, and it's the moment `status.md` was written
364
+ for. It's also where the file is most likely to lie — it's a snapshot of the day it
365
+ was written, and nothing keeps it honest in between. Work landed, a branch got
366
+ merged, someone deployed. Check it against the repo before repeating it back:
367
+
368
+ ```bash
369
+ git log -1 --format='%cd' --date=short -- docs/project/status.md # when it was last committed
370
+ BASE=$(git log -1 --format=%H -- docs/project/status.md)
371
+ git log --oneline "$BASE"..HEAD # what landed since
372
+ git branch --show-current # versus the branch it names
373
+ git status --short # what's uncommitted now
374
+ ```
375
+
376
+ If `BASE` comes back empty the file has never been committed, so the date at the top
377
+ of it is all you have — worth saying out loud, because an uncommitted `status.md`
378
+ also means it exists on exactly one machine.
379
+
380
+ Three kinds of drift are worth naming, because each one changes what to do next:
381
+
382
+ - **Commits landed after it was written.** The "next step" may already be done.
383
+ Say how many and from when instead of reading a stale plan as current.
384
+ - **The branch moved.** A status naming `feature/payments` while HEAD is on `main`
385
+ describes work that was merged, abandoned, or is sitting in a worktree — three
386
+ very different situations, and the file can't tell you which.
387
+ - **The tree is dirty in ways the file never mentions.** Uncommitted work from a
388
+ session that ended without closing, which is the usual reason someone can't
389
+ remember where they were.
390
+
391
+ Then answer what was asked: where things stand, what's in flight, the next step, and
392
+ which parts of the file you couldn't confirm. Keep it to what someone reads in
393
+ fifteen seconds — they asked to be caught up, not to be handed the file back.
394
+
395
+ If the drift is bad enough that the file misleads, say so and offer to rewrite it.
396
+ Rewriting is a separate act and it's their call; arriving at a project shouldn't
397
+ silently overwrite the record of how it was left.
398
+
399
+ ## Closing a session
400
+
401
+ The evidence comes first. Base what you write on this, not on recall of the
402
+ conversation:
403
+
404
+ ```bash
405
+ git status --short # what's still uncommitted
406
+ git log --oneline <base>.. # what landed
407
+ git diff --stat # the shape of it
408
+ ```
409
+
410
+ Write: **what changed** as outcomes, not a file list; **what's half-done**, naming
411
+ which half works; **the next step**; and **what was verified versus assumed** — if
412
+ tests ran, the numbers; if they never ran, say so, because an unqualified "done"
413
+ that turns out to be untested costs the next session an afternoon.
414
+
415
+ Three more things belong in `status.md` and are routinely left out:
416
+
417
+ - **What's deployed, and since when.** Shipped and committed are different states,
418
+ and on projects that deploy by file sync rather than by git they drift apart
419
+ constantly — a file can be live on the server and uncommitted, or committed and
420
+ never uploaded. Never infer one from the other. Record what you actually know,
421
+ and say when you don't know.
422
+ - **What's blocked by someone else.** A client who hasn't sent the copy, a store
423
+ review, a provider whose sandbox is down. These read like pending work but
424
+ can't be unblocked by working, so mixing them into the technical list makes the
425
+ list lie about what's actionable.
426
+ - **Which phase the project is in** — proposal, requirements, design, build,
427
+ testing, live. One line. It tells whoever arrives which of these files matters
428
+ today.
429
+
430
+ Update `requirements.md`, `decisions.md` or `context.md` only when something
431
+ genuinely stable changed: scope moved, a choice was made, a new document appeared.
432
+ Most sessions change nothing there, and that's normal.
433
+
434
+ **When `status.md` grows, the cause is usually stable content that drifted in.**
435
+ The test is simple: would this text be the same next week? A test checklist, an
436
+ acceptance walkthrough, a list of platform-specific gotchas — those don't change
437
+ between sessions, so they belong in `requirements.md` or `context.md` even though
438
+ you're using them right now. Being *currently relevant* is not the same as being
439
+ *volatile*, and confusing the two is how the volatile file ends up carrying half
440
+ the project.
441
+
442
+ The next step points at them: "run the acceptance walkthrough for requirements
443
+ 13–18" is a next step. Pasting the walkthrough into `status.md` means rewriting it
444
+ every session, which is both noise and the same cache problem in miniature.
445
+
446
+ ### Follow the chain, not the checklist
447
+
448
+ This is where a skill like this one can make things worse. A procedure followed
449
+ carefully still produces a tidy record of a misunderstanding, and the failure
450
+ looks like competence: correct format, specific file names, confident next step —
451
+ resting on something that isn't there.
452
+
453
+ Before writing a next step, follow what it depends on. A plan to add a refund
454
+ route is worthless if nothing in the codebase ever persists a payment, and that
455
+ gap is invisible if you're working down a list instead of reading the code. Ask
456
+ what has to be true for the next step to be possible, then check that it is.
457
+
458
+ When the code and the plan disagree, the code wins and the note says so. "The
459
+ refund route can't be built yet — nothing writes a Payment record, so there's no
460
+ id to refund against" beats a well-formatted plan built on sand.
461
+
462
+ ### Recording finished work
463
+
464
+ Check the claim before writing it down. Name the artifacts it implies, look for
465
+ those specific things, record what you found, and report the evidence with the
466
+ verdict — "found `PaymentGateway.php` and the `payments.*` routes" lets the person
467
+ catch a wrong conclusion; a bare "✅" doesn't.
468
+
469
+ Then **answer what was asked.** Someone asking you to mark work complete wants it
470
+ marked, not a lecture on epistemics. Record the part that checks out and note the
471
+ rest as open. Hedging everything into "implemented but unverified" and leaving the
472
+ file untouched is refusing the request while appearing thorough.
473
+
474
+ Per-stack specifics — Laravel, Titanium, Node, Python, Rails, Go — are in
475
+ `references/verification.md`.
476
+
477
+ ### Closing is not permission to edit
478
+
479
+ You'll find real problems while taking inventory. Write them down and leave them.
480
+ The uncommitted tree is the person's work in progress; a fix applied while they
481
+ weren't looking is a fix they didn't review, landing in a diff they'll read
482
+ tomorrow as their own.
483
+
484
+ Same for publishing: don't commit, tag or push. Releasing assumes the work is
485
+ finished, which is the opposite of why this exists. A log entry says "auth is
486
+ half-wired, the form is missing"; a release note never says that. If the project
487
+ has a release path — a `/release` command, a documented procedure — name it and
488
+ stop there; deciding that this is the moment to run it is the person's call.
489
+
490
+ The same boundary holds in the other direction. `status.md` records that an audit
491
+ found twelve issues and where the report lives; it isn't the place to fix them, and
492
+ a session that quietly repaired three on the way past leaves a record that no longer
493
+ matches either the report or the diff.
494
+
495
+ ## Before finishing
496
+
497
+ Resolve the import chain from each context file and confirm `status.md` isn't in
498
+ it. This is worth checking every time rather than assuming, because it breaks
499
+ quietly: someone adds an `@` line meaning well, and from then on every progress
500
+ update throws away the cached prefix behind it — the one failure this convention
501
+ exists to prevent.
502
+
503
+ Check it, don't eyeball it — and check the files the inventory actually found, not
504
+ a fixed list:
505
+
506
+ ```bash
507
+ grep -n 'status\.md' CLAUDE.md AGENTS.md # add whichever others exist
508
+ grep -rn '^@' CLAUDE.md AGENTS.md # every import, including nested ones
509
+ ```
510
+
511
+ A mention of `status.md` in the pointer block is correct and expected; an `@` line
512
+ pulling it in is the failure. Follow each `@` to its target and grep that file too —
513
+ the break usually happens one level down, where someone imported an index that
514
+ imports everything.
515
+
516
+ Naming a file that doesn't exist makes `grep` exit non-zero and print nothing, which
517
+ looks exactly like a clean result. If you list `GEMINI.md` on a repo that has no
518
+ `GEMINI.md`, you get silence and a failed command, and reading that as "no imports
519
+ found" is how a broken chain ships as verified.
520
+
521
+ Then close with a short summary in the person's language: where things stand,
522
+ what's half-done, the next step, and the paths you wrote. Fifteen seconds of
523
+ reading — the files hold the detail, and a handoff nobody reads is a handoff that
524
+ failed.