Skip to main content

Karpathy Progress Memory

skills/karpathy-progress-memory/SKILL.md: records a successful KBD task, change, or phase boundary as a canonical, idempotent progress event. Use when a boundary transition succeeds, when recovering work after context loss, or when KBD progress must survive a memory-service outage without editing generated projections. Do not use it for changing KBD position or status — use kbd-process-orchestrator (the kbd-* skills) for that.

Compatibility declared in frontmatter: Node.js LTS (>=22), git, the prometheus CLI; pk optional.

Two independent jobs, neither can block the other​

JobOwnerWhere it writes
Record a task/change/phase boundary; make it idempotent; recover from a crash mid-writeThis pack's recorder (lib/karpathy/, scripts/record-progress.mjs).prometheus/session-log.md, .prometheus/progress-memory-receipts/
Distil that history into a searchable, cited knowledge bundlepk (optional, vendored as the tools/prometheus-knowledge submodule).prometheus/knowledge/

lib/karpathy/knowledge-bundle.test.mjs guards that no code under lib/ or scripts/ writes to .prometheus/knowledge/ — that directory belongs exclusively to pk.

lib/karpathy/ modules​

ModulePorted fromWhat it does
canonical-state.mjs—Resolves which project, run, and phase the recorder is recording for, and whether the event agrees with canonical KBD state. The full pack refuses every event it cannot confirm via prometheus kbd status --json; this pack may depend only on node, git, and the OpenSpec CLI, so the prometheus CLI is optional — state comes from it when available, else from the .kbd-orchestrator/current-waypoint.json projection, and the caller is told which so a receipt can record whether its event was confirmed or best-effort. .kbd-orchestrator/project.json is deliberately never read for this — its projectId differs from the canonical one, and reading it would silently fork every event id.
event.mjsrecord-progress.py:88-197Builds a progress event for a hook boundary, or reads one given as text. git is the only process invoked here, read-only (rev-parse, diff, ls-files), via spawnExecutable with an args array; an absent or failing git yields null/no files rather than an error.
validate.mjsrecord-progress.py:199-282Validates a progress event exactly as the source's validate_event does, so an event one pack accepts, the other accepts too. This is a trust boundary: no refusal reason ever echoes a value from the event, and field checks run before the secret-pattern scan, so an echoed value could never carry exactly what the scan exists to keep out.
hash.mjs—Computes the two hashes a receipt carries so they equal what the source pack's Python recorder computes for the same event — including matching Python's float() serialization quirk for the one field that can be a float (elapsedHours).
receipt.mjsrecord-progress.py:59-63,509-540Writes receipts in the source pack's on-disk shape, via lib/platform/atomic-write.mjs (temp file, exclusive create, then rename) rather than the source's NamedTemporaryFile + fsync + os.replace — same two-phase shape, but the platform helper's bounded Windows AV/indexer retry is something the source never needed.
record.mjsrecord-progress.py:541-671Orchestrates new-event recording, replay, and the flush trigger. A receipt is written twice for a new event: complete: false with memory.status: "pending" before the transport is ever called, then the final state after — what makes a crash between the two recoverable, since an incomplete receipt is retried from its own event snapshot on the next run, never re-validated against a fresh event.
session-log.mjsrecord-progress.py:315-358The human-readable session log: one markdown record per recorded boundary, appended under a lock, deduplicated by a marker.
transport.mjsrecord-progress.py:399-478Delivery to pk: optional, bounded, shell-free. Any pk failure here is degraded — the receipt itself is the retry queue (the source's Python outbox and pk-learning-worker daemon are not ported).

Reachable outcomes​

recorded | duplicate | degraded. The source pack's own queued state is read (for a receipt an old source-pack run wrote) but never emitted by this pack.

Bounds and safety​

The 256_000-byte payload bound and secret-pattern rejection are kept from the source. pk delivery is bounded by KPM_PK_TIMEOUT_SECONDS (default 5s, 0.1–10s range).

The CLI​

node scripts/record-progress.mjs --from-hook --boundary <boundary>
node scripts/record-progress.mjs --input <file|->
node scripts/record-progress.mjs --flush-degraded

scripts/record-progress.mjs holds no logic of its own — parse arguments, call lib/karpathy/, print one JSON line, set the exit code.

OKF v0.2 and the knowledge bundle​

.prometheus/ is the bundle root; .prometheus/knowledge/ is where pk writes concept files, each carrying the Open Knowledge Format v0.2 fields: type, generated: {by, at}, verified: [{by, at}], status, stale_after, sources: [...]. decisions.md, gotchas.md, and postmortems/ are this pack's own append-only memory, outside the bundle and not OKF-conformant.

pk stays optional per openspec/config.yaml's binding constraint: with it absent, no knowledge bundle is written or updated, but the recorder's own receipts and session-log.md are entirely unaffected either way.

See also​