Repository navigation
feat(skills): trail init look-back, hook wiring with skills on by default, and learnings without repeats - #658
Conversation
🌱 graft blast radius5 areas changed → 15 areas can be affected. 105 dependent symbols, depth 2. flowchart TB
A0(("Note Repository<br/>25 symbols"))
A1(("Graph Building<br/>17 symbols"))
A2(("Installation Records<br/>12 symbols"))
A3(("Host Initialization<br/>9 symbols"))
A4(("Skill Lessons<br/>6 symbols"))
AX(("10 smaller areas<br/>36 symbols"))
classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
class A0,A1,A2,A3,A4 reached;
classDef tail fill:#EEF2F3,stroke:#9AA4A9,stroke-width:1px,color:#3A4247;
class AX tail;
Who knows this code — 3 people across 20 areas
Ownership is git history over each area's own files, weighted towards recent work (120-day half-life). Merge commits and bots are dropped, and you are dropped from your own PR. A name with no All 105 dependent symbols, grouped by areaNote Repository — 25 symbols in 12 files
Graph Building — 17 symbols in 11 files
Installation Records — 12 symbols in 4 files
Host Initialization — 9 symbols in 5 files
…44 further symbols not listed. Test signal per changed area — 5 ✓Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.
76 test suites also reference this code99 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.
Open the interactive graph → — click an area to see its dependent symbols at file:line. |
…lls hook handlers
6af78df to
8241d18
Compare
641bb51 to
a631e01
Compare
- anchors and the timeout guard split PATH on ';' and look for git.exe, npm.cmd and the like (PATHEXT); Windows has no exec bit to check - a scratchpad folder is found with either slash, and Windows paths are compared without case (scratch folders, tamper's protected places) - tamper's cd from an unknown folder stays unknown on Windows, where resolve() puts a drive before the '/\0' it starts from
- POSIX file modes are asserted only off Windows; the FIFO and /dev/zero cases run only where those exist - expected paths are built with resolve()/join(), and the fold fixture compares checkouts resolved - capped children import the source by file URL, and say why they failed - os.homedir() follows USERPROFILE on Windows, so the cd test sets it too
A Windows stack frame joins its folders with '\', so the hook-errors log kept the whole path, user name included, with the slashes stripped.
…backtracking pattern still misses by seconds
A small matcher with no model reads tool and command preferences from a
learning ("use pnpm, not npm", "never run X", "always run Y before Z",
"run X instead of editing F") and matches them against each step's program
and arguments. It is conservative: when unsure it says nothing.
- At a save or offer, steps follow the person's live learnings: a step one
goes against is rewritten when that is safe, else left out, and the offer
names it in one plain line.
- At recall, a learning that only repeats a step is said once, in the run
block, and left out of the prompt's learnings lines. One that goes against
a step wins; the block marks the step, and the update offer proposes the
change with its usual typed yes.
- At trail init, a preference that only repeats a step of a skill kept on
the same screen goes into that skill as a lesson.
Retired, replaced and held learnings are ignored.
command -v split PATH on the platform's delimiter but looked only for the bare name, so on Windows every program read as not installed. It now uses pathDirs and programFiles from guard-fast, as anchors and the timeout guard do.
- POSIX file modes are asserted only off Windows - the FIFO cases and the socket, /tmp and ':' PATH probe test run only off Windows - a non-executable timeout on PATH counts on Windows, which has no exec bit - children import the source by file URL
On Windows HOME is often unset. The update gate then showed a path in full instead of as ~/..., and a saved skill's repairs never turned the home folder into $HOME. Both now fall back to homedir().
- the FIFO half of the value-line link test runs only off Windows - apply_patch's relative file and tamper's hit are compared resolved
- the wall fixes' program check splits PATH on ';' and looks for git.exe, npm.cmd and the like (PATHEXT); Windows has no exec bit to check - look-back finds a scratchpad folder with either slash and ignores case on Windows, so it no longer mines scratch sessions there
- the FIFO cases and the file name with a newline run only off Windows - capped children import the source by file URL - the naming calls' shebang stand-ins run only off Windows, as in init-claude-call
# Conflicts: # test/hosts-codex-trust.test.ts
… only USERPROFILE is set As in the save gate: on Windows HOME is often unset, so fall back to homedir().
The file-open text said "it's a note from your team". It now says what the prompt hook says: a learning from past sessions, this repo's or the user's own.
- the FIFO cases, the unwritable Trail home and the cache's file mode are tried only off Windows; the corrupt-file cases run everywhere - PATHs are joined with the platform's delimiter - the stand-down test sets USERPROFILE with HOME, which os.homedir() reads - the naming call's shebang stand-in runs only off Windows
…p, and run again when one finds the lock busy On a loaded Windows runner the two processes took longer than the fixed 1.5 s to start, and the first held the ledger lock past the 200 ms the second waits, so the second gave up and wrote nothing (by design). The lock itself works there: the real-processes test in the same file passed with no lock file left. Each hook now warms up, says it is ready, and starts at an instant sent after both are up. A round where one found the lock busy proves nothing and runs again, up to 5 times. Reading the ledger outside the lock still fails it 5/5.
…s part 4 adds and the ones that failed on Windows timeBar(ms, floor) in machine-speed.ts: the bar where it was set, times slowness(), never under a floor of 3 to 5 times it; exactly the bar under TRAIL_PERF=1. The 2 MB walls probe times CPU, not the wall clock. The busy value.json lock wait is measured over the same call with the lock free.
The 20,000-line clustering bar and the time caps' slack (the 1.5 s replay cap, the prompt's 400 ms deadline) use timeBar. The caps themselves stay as they are. The stand-in timeouts that are posix-only and already bounded by what a broken cap would take are left alone.
Absolute bars use timeBar (3 to 5 times the bar as the floor). Budget tests keep the budget and scale only the slack around it, held under whatever a broken budget would take (the 4 s default, the stub's 3 s parse). The pre-bash host runs kill the child 3.5 s past the scaled bar, as before. TRAIL_PERF-only tests keep their bars.
feat(skills): learnings and skills never repeat or contradict each other
feat(skills): wire skills into the hooks and the CLI, on by default
…chors - a shell edit's file keeps its drive and backslashes, so the Stop ask names it - trail check queues a learning's file name, not its whole Windows path - a plain-file read refuses a link on Windows, where open has no O_NOFOLLOW - a bin target and a node <file> word compare as dist/cli.js on every platform - the cp line for a hand-edited skill uses forward slashes, which Git Bash and PowerShell both take
- the journey box aliases CWD's own key (local/d-home-dev-shop on Windows), not a hand-written one - the fail-open hook commands run in Git Bash on Windows, the shell Claude Code runs hooks in - the J16 deny tests skip where Trail still finds a timeout: Windows ships System32\timeout.exe - the Codex sandbox tests skip where chmod refuses nothing (Windows, root) - CRLF in TELEMETRY.md, native separators in a skills path, a Claude projects folder name - the prompt-activity ask child from source gets the installed 60 s, not the hook's 4 s
…fuse a nested repeat A grep takes a regex, so the pattern's syntax is kept: every literal character goes through the metacharacter escape and only fixed syntax is written as itself, so RegExp gets the typed pattern rebuilt from known parts (CodeQL js/regex-injection, alert 23). A repeat of a group that repeats inside, like (a+)+, is refused as an invalid pattern is: on one long line it backtracks for minutes and holds the MCP server. Every other pattern compiles exactly as before.
…en two Windows test expectations
Parts 5 to 7 of the learned-skills stack, landing together. Parts 6 (#659) and 7 (#665) were merged into this branch so CI runs once on the whole thing against main. Their descriptions explain those parts.
trail init, the review screen, and the skills hook handlers.trail initand the hooks, and turns skills on by default. There's notrail skills onstep.Part 5 of 6 of the learned-skills stack. Base: part 4.
What it adds:
init/sessions.ts,transcript.ts,look-back*.ts,miners.ts,candidates.ts,howtos.ts). It reads the person's own typed messages from past Claude Code sessions about the repo, with no model, and finds what came up on two or more days: preferences, guardrails and repeated jobs.init/review-tty.ts), keep and handover (init/keep.ts,handover.ts), and replays of a past run to build a skill from it (init/replay-runs.ts).claude/start-skills.ts,prompt-skills.ts,stop-skills.ts,post-bash.ts,walls-hook.ts).Nothing calls any of it yet.
trail initand the hooks switch to it in the last part.What to look at:
init/look-back-mine.ts: what is read, and what is skipped (headless runs, scratch folders, old sessions).init/keep.ts: nothing is kept without the person's pick.🤖 Generated with Claude Code