snowshoe-scratch
Study a path that is not this repo's Snowshoe map. Keeps an ephemeral mental map at ~/.snowshoe/learn/<sha256(utf8(realpath))> (not the git ledger). Optional read-only map status --cwd of a main check
Files1
View on GitHubSKILL.mdskills/snowshoe-scratch/SKILL.md
GitHubSnowshoe-scratch
Satellite of the product skill. Not the git-map wedge. Product drain/learn
stays skills/snowshoe/. Do not add this as a third gate there.
Assume snowshoe is on PATH when you query a map. Always pass --json.
Global --cwd <dir> is git -C (discovery start). Not --repo.
On an offered main-map root, the atlas allowlist is only:
snowshoe map status --json --cwd <main> …- optional
snowshoe help --json(command index;--cwdnot required)
Do not run any other snowshoe command against that root. Do not write
ledger.sqlite. Viewport files on disk win over map prose.
Until install ships, using this skill outside the Snowshoe clone means
copying skills/snowshoe-scratch/ into the harness skills dir (not
snowshoe skill install).
Hash recipe (reconstruct the dir from a path)
Another chat must be able to open the same directory from the same target.
target= the explicit path they named, else cwd.realpath= canonical absolute path (realpath/os.path.realpath/fs.realpathSync). Follows symlinks.- If
realpathis not exactly/, strip one trailing/(keep/for root). Do not strip any other characters. id= SHA-256 of the UTF-8 bytes of that string, lowercase hex (64 characters).- Directory:
$HOME/.snowshoe/learn/<id>/.
python3 -c 'import hashlib, os, sys
p = os.path.realpath(sys.argv[1])
p = "/" if p == "/" else p.rstrip("/")
print(hashlib.sha256(p.encode("utf-8")).hexdigest())' "$TARGET"
$HOME/.snowshoe/learn/<id>/ is personal/local. It is not .snowshoe/ in the
target and not the ledger.
origin.md
On bootstrap, write origin.md in the hashed dir:
# origin
- realpath: `/abs/path/to/target`
- id: `<64 hex>`
- mainRoot: `/abs/path/to/main/checkout`
realpath and id are required. Omit the mainRoot line until a read-only
map was offered and accepted.
Layout
| File | Role |
|---|---|
origin.md |
realpath, id, optional mainRoot |
CURRENT.md |
Ephemeral mental map of the target (concepts, not files/TOC) |
STATE.md |
Now / Re-entry / voice / journal |
PLAN.md |
Plan; read on phase shifts |
discrepancies.md |
Standing “should change” / bugs (not STATE) |
sessions.md |
Host chat ids for this dir (append-only; not teaching context) |
No ledger. No mines.md requirement. Scratch STATE.md is a journal plus a
Re-entry block (not product-learn retention cards or check-ins).
Host chats (sessions.md)
The same hashed dir is reused across chats. Keep host conversation/session ids out of STATE / CURRENT / origin.
sessions.md is an append-only list. When this turn has a host conversation
or session id (the opaque string the host already uses to name this chat;
look in the environment): if that id is not already in the file, append one
UTC line. Do not invent URLs. No id → skip; do not call host APIs.
- 2026-10-19: `<id>`
Do not read sessions.md in the teaching loop (CURRENT / STATE / PLAN).
Read it only to check/append, or when they ask to find a prior chat.
Loop
- Resolve
target→realpath→id→$HOME/.snowshoe/learn/<id>/. - If the hashed dir is missing, or it exists but
CURRENT.mdis missing (partial bootstrap): briefly propose creating the scaffold (and offer to write it if they agree). On OK: create the layout files (includingsessions.md); write a mental map of the target (section below) intoCURRENT.mdand into the chat (same text). Append this chat’s host id if present. Do not block a one-shot question on scaffold. Do not resume a partial dir. - If the hashed dir exists and
CURRENT.mdis present: if a host chat id is visible and not already listed, append it tosessions.md. ReadCURRENT.md, thenSTATE.md. If this turn is re-entry (section below), do that beat before any new slice. Voice after compaction: tutor prose in full sentences (not a status telegram). MatchSTATE.md→ Now →voicewhen present; persist journal and Re-entry lines toSTATE.mdimmediately so compaction cannot wipe them. Local STATE may use any language the human prefers; this skill stays English. Do not import productlearn.mdretention cards / check-ins. - Stay on the atlas allowlist above. Do not write
ledger.sqlite. Scratch is not the git-map wedge. - Drain-shaped prompt on the mapped checkout (drain /
work next/ catch up the queue): one line pointing at product skillskills/snowshoe/(drain.md). Stay on scratch for this path; do not hard-block, and do not run drain commands from this skill.
Teaching
- If something in the viewport looks wrong, incomplete, or an eye-catcher:
raise it in the chat this turn. Do not swallow it to stay on the lesson.
Do not start a fix unless they ask. If they agree it should change, one line
in
discrepancies.md. - When a beat is about a real fragment, cite repo-relative
path:line(compiler style — opens the editor). Prose first. KeepCURRENT.mdreadable without jumping — paths belong in chat / discrepancies, not as the map’s spine. - If they ask to review local / agent patches mid-learn: do that, then return
to the slice. If the picture of the target changed, refresh
CURRENT.md. Patch review is not re-entry. - End a teaching beat with a next proposal (or a pause). Short steering (“what’s next”, “go”, “use prose”) means take that default or fix voice — not re-entry.
- Landing a floor is progress, not re-entry. Quietly rewrite
STATE.md→ Re-entry (Landed / Current / Next / Do not reopen) and keep teaching — next-proposal as usual. Do not reprint the floor in chat. - Stopping (they say they are leaving, ending the day, parking the session):
same quiet rewrite. Then stop. Do not open a new slice. Still not the chat
ritual unless they also typed
re-entry.
Re-entry
Assume wipe. Do not continue the last telegram.
Trigger (one branch): they type re-entry (optional leading /). Do not
treat short steering (“what’s next” / “go” / “ok”), a confirmation that the
floor landed, or a landed floor itself as this.
Short auto: first teaching turn after compaction, hashed dir already has a journal, and this turn is not a content question about a named fragment. Then print Landed / Current / Do not reopen in a few sentences and wait. A named fragment question: answer it; do not dump the floor.
Explicit re-entry:
- Read
CURRENT.mdandSTATE.md→ Re-entry. If that block is missing, reconstruct from Now + last journal lines + CURRENT first-level nodes, write it, then speak. - Chat in tutor prose (no file tree, no CURRENT dump):
- what already landed (the floor), in words
- the open slice
- what not to reopen
- one check question on the current slice only
- Do not start the next slice until they confirm the floor is back or name the fog. Missed check → reprint that floor; do not go deeper.
STATE.md → Re-entry shape:
## Re-entry
- Landed:
- Current:
- Next:
- Do not reopen:
Skill labels stay English. Local STATE / CURRENT may use any language the human prefers.
CURRENT.md (mental map)
Same job as the product map tree. drain.md: the map is a mental model, not
1:1 with code. Scratch is markdown-only (no ledger, no slugs).
- Nodes are concepts (responsibility, flow, decision, seam) — not files, not
the author's
##headings. - Shallow: about two listing levels; a handful of first-level nodes. If the
honest list is huge, add a grouping layer (
drain.mdexpand hop). - Readable without jumping. A title is a named thing or a claim in words.
A person scanning
CURRENT.mdmust understand each node without opening the target. Coded labels (A–F,P1,§6) may follow in parentheses only after the words already stand alone. No telegram. Same posture as product entity bodies (drain.mdBody shape). - File TARGET: do not copy the table of contents. Directory TARGET: do not
ls. Related files are edges, not extra chapters. - Design-record scaffolding (tests, acceptance, canon touchpoints) is one grouped node, or omit until they ask to implement.
- Titles/tree match the human's session language. This skill file stays English.
Anti-patterns: filesystem dump; heading TOC; titles that only make sense after
opening the file (Options A–F, Header, §8–14).
Optional read-only atlas
GIT_C = $TARGET if it is a directory, else the dirname of its realpath
(file-shaped TARGET still offers the atlas for its containing checkout).
git -C "$GIT_C" rev-parse --path-format=absolute --git-common-dir
If --path-format=absolute is unavailable, realpath the printed common-dir
relative to $GIT_C so a relative .git does not bind the agent cwd’s ledger.
Resolve that to the main checkout (parent of the .git directory when the
common dir ends in .git). If <main>/.snowshoe/ledger.sqlite exists, ask
once whether to use it as a read-only atlas. On yes: set mainRoot in
origin.md. If they decline, continue with viewport files only.
Slug from a filesystem path
Do not dump --all-fields from root. Map TARGET (or the file under study)
to --slug:
TOPLEVEL=git -C "$GIT_C" rev-parse --show-toplevel.rel= path of TARGET relative to that checkout toplevel (posix, no leading./) — not relative to<main>on disk. Still query--cwd <main>(ledger lives there).- If TARGET is a directory and
relis empty or.(this checkout’s root): skip slug lookup. Do not pick a nested file as focus. If they already opted in, you may query--slug root(default fields / neighborhood only). Do not--all-fieldsfromroot. - Otherwise:
snowshoe map status --json --cwd <main> --fields slug,anchors(tree, not--all-fields;anchors[].pathis repo-relative). - Match a node whose
anchors[].pathequalsrel, or (directory TARGET) whose anchor path is underrel/. Prefer the most specific match. - If none match: skip the atlas for that file; keep the viewport.
Then query only (allowlist):
snowshoe map status --json --cwd <main> --neighborhood --slug <focus>
snowshoe map status --json --cwd <main> --fields title,type,leaf,children,refs,bodyOverview --slug <focus>
Neighborhood / bodyOverview for the files under study — not full
--all-fields from root. Prefer viewport files you actually read over map
prose when they disagree; say so.
Optional: snowshoe help --json (no --cwd).