Skip to content

init: learnings worth reading, from past sessions and the PRs - #701

Merged
shhdwi merged 11 commits into
mainfrom
feat/fast-valuable-learnings
Oct 27, 2026
Merged

shhdwi merged 11 commits into
mainfrom
feat/fast-valuable-learnings

Conversation

@shhdwi

@shhdwi shhdwi commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

trail init now finds learnings a teammate would actually want to read, and finds them in one go.

What changes

  • Past sessions are read. Init reads both sides of the person's past Claude Code sessions in this repo (what they said, what Claude said, answers, plans, commits) and asks their own Claude Code what was decided, ruled out or went wrong. Session text stays on the laptop. Only the learnings they keep are shared. This reverses D87 at Shrish's call.
  • The PR read is wider. It covers merged and closed PRs, descriptions, reviews, every thread, reverts, and the repo's ADR and CONTRIBUTING docs. Before, it read only inline threads that were acted on.
  • One bar for every read (src/learn/bar.ts). Each learning must be a decision a teammate would nod at. The title is a plain headline with no file names. Files, commands and values go in the body under "In the code:". A learning is kept only if its quotes really appear in what was read.
  • Both reads run side by side. Each prints a line when it lands. A learning found by both is saved once, as the PR one.
  • The agent saves learnings the same way. In-session save guidance now asks for the plain headline and puts files in the body.

Real runs

Published 0.26.0 against this branch, at a real terminal, on a fresh clone:

Repo Old New
trailhq/trail-cloud (8 real sessions) 10 s, 0 learnings 29 s, 14 learnings (8 from PRs, 6 from sessions, 2 duplicates dropped); first line at 0.9 s
honojs/hono (no sessions) 11 s, 1 learning: "hono-base.ts: extend notFound() for routable handlers, no onNotFound()" 25 s, 8 learnings

Cost of a first init on trail-cloud, cold cache: $0.16 for the PR read and $0.21 for the session read, about $0.36, on the person's own plan. Each read runs once per repo, and --look-back reads only the sessions since.

Sample titles from the new run:

  • Sign up comes first, before any onboarding screen or website read
  • No sample deck after the website read; show what Trail learned
  • Re-running setup must not revive learnings the team already dropped
  • Adapters move out of core into separate packages in v5, so new runtime adapters ship standalone
  • Wildcard routes failed on encoded line breaks; v5 fixed it, v4 deliberately did not

The extra time is the two Claude reads, which run together. Graph building and wiring happen while they run.

Safety

  • The PR read keeps only what the repo's owner, members and collaborators said. A closed PR from an outsider is read without its description, and PRs that bots opened are skipped. A stranger's PR can't become a learning every teammate's agent follows.
  • Secrets are scrubbed before any text is clipped, so a clip never leaves part of a key behind. Stripe keys, env-style secrets and private keys with no end marker are now caught too.
  • Opening a learning's row on the screen (s) shows what its file will say before it's kept.

trail check

It flags src/cli.ts:1447 against "Reading reviews in the detached _trail-pair child after init returns". That isn't what happens here. Both reads finish inside init: finishLookBack awaits them before the page hears the run is done, and the paired test checks the page's count. The check matched on shared words.

Design: docs/superpowers/specs/2026-10-27-valuable-learnings-design.md. Install size is a separate PR.

🤖 Generated with Claude Code

Shrish Dwivedi and others added 10 commits October 27, 2026 04:58
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… shared bar

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Setup now starts the past-session read alongside the PR read, prints a
line as each one lands with an example headline, shows session rows on
the same screen as the PR rows, and drops a session learning the PR read
already found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The agent is now asked for a title a teammate understands with no file
names, and to put files, commands and values in the body under
"In the code:", in the session-start guidance, the trail skill and the
in-session nudges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The session read no longer starts (or says it's reading) when the repo
has no past sessions here; the wait line says pull requests, like the
rest; a long title ends at its last clause break instead of mid-word.
Found on a real run on honojs/hono.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cord

Found on a real run on trailhq/trail-cloud with real past sessions:
- session discovery (1.8 s over 1.6 GB of transcripts) ran before init
  printed anything; it now runs in the look-back's worker, and the
  look-back and session read share one line
- the same learning came from the PRs and from a session in other words;
  learnings whose bodies name the same code are now one
- "nothing to keep from your past sessions" printed beside 8 found
- a read that finds no sessions leaves no mark, so a later init reads
- each read's local mark keeps what it cost and how long it took

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…what differs

From the final review:
- the PR read keeps only what the owner, members and collaborators said;
  a closed PR from an outsider is read without its description and a PR a
  bot opened is skipped, so a stranger's PR can't become a team learning
- secrets are scrubbed before text is clipped, and Stripe keys, env-style
  secrets and private keys with no end marker are caught
- two learnings count as one only when they share 3 headline words and
  both or neither say not, or are the same kind naming the same code
- a session bigger than the digest keeps its newest lines, and quotes are
  checked only against the lines Claude was sent
- a session read Claude couldn't finish says why, and the page says
  skipped instead of 0 learnings
- opening a learning row on the screen shows what its file will say

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@trailhq-graft

trailhq-graft Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🌱 graft blast radius

5 areas changed → 4 areas can be affected. 17 dependent symbols, depth 2.
Tests: no test reaches runInitCommand; 4 areas updated their tests.
Tag: @anirudhkumar-nanonets — 5 of 9 areas · @afeddersen — Host Registry · Stawiari — Host Registry

flowchart TB
  A0(("Keep Review Workflow<br/>7 symbols"))
  A1(("Claude Initialization<br/>6 symbols"))
  A2(("Host Registry<br/>2 symbols"))
  A3(("Memory Notes<br/>2 symbols"))
  classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
  class A0,A1,A2,A3 reached;
Loading
Can be affected Symbols Nearest hop Reached from
Keep Review Workflow 7 src/init/keep.ts:L326-L369 keepCommand — calls, depth 1 Review Candidate Selection, PR Review Learning
Claude Initialization 6 src/claude/hooks.ts:L459-L469 orientationAtStart — calls, depth 1 Claude Formatting
Host Registry 2 src/hosts/antigravity.ts:L43-L61 installAntigravitySkill — calls, depth 2 Claude Formatting
Memory Notes 2 src/notes/memory-notes.ts:L161-L169 memoryBody — calls, depth 1 Review Candidate Selection
Who knows this code — 3 people across 9 areas
Area Who knows it
Claude Formatting · changed @anirudhkumar-nanonets — 18 commits, last 5d ago
PR Review Learning · changed @anirudhkumar-nanonets — 2 commits, last 5d ago
runInitCommand · changed @anirudhkumar-nanonets — 61 commits, last 5d ago
Claude Initialization · affected @anirudhkumar-nanonets — 25 commits, last 5d ago
Host Registry · affected @afeddersen — 1 commit, last 2mo ago · Stawiari — 1 commit, last 2mo ago
Memory Notes · affected @anirudhkumar-nanonets — 1 commit, last 5d ago
Review Candidate Selection · changed only you — nobody else has touched these files
Learning Sessions · changed only you — nobody else has touched these files
…1 further area

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 @ has no GitHub handle in its commit email — tag them by hand, or add a .mailmap entry. A suggestion from history, not a CODEOWNERS rule.

All 17 dependent symbols, grouped by area

Keep Review Workflow — 7 symbols in 4 files

  • src/init/keep.ts:L326-L369 — keepCommand (calls, depth 1)
    368: return { code: 0, lines: afterKeepLines({ ...result, how: 'keep' }, facts) };
  • src/init/keep.ts:L171-L176 — keepReview (calls, depth 1)
    174: const [n] = saveReviewFindings(place.dir, [f]);
  • src/init/look-back-mine.ts:L118-L213 — lookBack (calls, depth 1)
    124: const fail = (what: string, e: unknown) => lb.errors.push(`couldn't read ${what} this time (${e instanceof Error ? e.message.slice(0, 80) : String(e).slice(0, 80)})`);
  • src/init/discover-worker.ts:L1-L109 — discover-worker.ts (calls, depth 2)
    15: /** Past the cap, how long the main thread waits for the worker's answer before it gives up on it. */
  • src/init/discover-worker.ts:L50-L96 — lookBackOffThread (calls, depth 2)
    55: errors: [`couldn't read your past sessions this time (${why})`],
  • src/init/handover.ts:L55-L90 — initHandover (calls, depth 2)
    74: // fix-lab5: the session that showed this list, resumed (every `claude -p` turn is one), already holds it. Handing
  • src/init/keep.ts:L183-L251 — keepItems (calls, depth 2)
    189: // Part 7: skills first, so a preference that only repeats a step of one kept here goes into it as a lesson.

Claude Initialization — 6 symbols in 3 files

  • src/claude/hooks.ts:L459-L469 — orientationAtStart (calls, depth 1)
    467: return learnings.kept ? `${tag()} ${teamNotesDirective(learnings.count, true)}${learnings.extra}` : learnings.extra;
  • src/claude/stop.ts:L142-L156 — askForNote (calls, depth 1)
    151: return { block: noteAsk(sign) };
  • src/claude/hooks.ts:L480-L560 — main (calls, depth 2)
    484: // trail's own headless Claude calls (the first-run read of past sessions) run with this set.
  • src/claude/init.ts:L133-L181 — runInit (calls, depth 2)
    172: // The same wiring again, one level up in `~/.claude`, because everything above
  • src/claude/init.ts:L194-L245 — runTrailInit (calls, depth 2)
    235: // An old settings.json left as it was still runs the old shims: they stay until it can be rewritten.
  • src/claude/stop.ts:L183-L204 — handleStopEvent (calls, depth 2)
    194: // A turn always ends; an offer can wait for the next one.

Host Registry — 2 symbols in 2 files

  • src/hosts/antigravity.ts:L43-L61 — installAntigravitySkill (calls, depth 2)
  • src/hosts/registry.ts:L1-L186 — registry.ts (references, depth 2)
    3: * Adding a host = adding one entry here (plus a renderer if it needs

Memory Notes — 2 symbols in 1 file

  • src/notes/memory-notes.ts:L161-L169 — memoryBody (calls, depth 1)
    166: let out = `## Decided\n${clip(decided, BODY_CHARS)}`;
  • src/notes/memory-notes.ts:L190-L212 — memoryCandidates (calls, depth 2)
Test signal per changed area — 4 ✓ · 1 ✗

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.

  • ✓ Review Candidate Selection — 7 of 17 reached · 2 test files changed here: test/init-screen.test.ts, test/init-team-rows.test.ts
    • not reached: scopeWords, countSentence, press, detailOf, reviewItems, sessionItems, isTeam, landed, …2 more
  • ✓ Claude Formatting — 2 of 3 reached · 2 test files changed here: test/trail-note-ask.test.ts, test/trail-notes.test.ts
    • not reached: trailSkill
  • ✓ PR Review Learning — 8 of 17 reached · 1 test file changed here: test/trail-pr-reviews.test.ts
    • not reached: onTeam, fetchMergedPRs, descriptionWords, read, prBlock, prSource, repoDocs, revertCommits, …1 more
  • ✓ Learning Sessions — 8 of 19 reached · 2 test files changed here: test/learn-bar.test.ts, test/learn-sessions.test.ts
    • not reached: citedSource, codeNames, contentWords, kindOf, clip, left, offeredSessions, oneLine, …3 more
  • ✗ runInitCommand — 0 of 3 reached · no test file reaches it
    • not reached: pairProgress, runInitCommand, constructor
26 test suites also reference this code

31 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.

  • test/claude-copy-dashes.test.ts
  • test/claude-format.test.ts
  • test/claude-hooks-1b-review-trust.test.ts
  • test/claude-hooks-1b.test.ts
  • test/claude-start-skills-2.test.ts
  • test/cli-1b.test.ts
  • test/init-b6-review.test.ts
  • test/init-candidates.test.ts
  • test/init-disk-review.test.ts
  • test/init-fold-lessons.test.ts
  • test/init-keep-cli-review.test.ts
  • test/init-keep-cli.test.ts
  • test/init-keep-shell-noise.test.ts
  • test/init-lookback.test.ts
  • test/init-run.test.ts
  • test/init-screen-review.test.ts
  • test/init-uncompiled-record.test.ts
  • test/skills-agent-trust.test.ts
  • test/skills-fixtures.test.ts
  • test/skills-validate.test.ts
  • …6 more

⚠️ 6 changed files not in the graph (.trail/learnings/2026-10-26-setup-reads-past-sessions-with-the-shrish.md, .trail/learnings/2026-10-27-measure-init-s-cost-cold-back-shrish.md, .trail/learnings/2026-10-27-testing-init-as-a-person-at-shrish.md, docs/superpowers/plans/2026-10-27-valuable-learnings.md, docs/superpowers/specs/2026-10-27-valuable-learnings-design.md) — no parser claims the extension, or the index predates the file.

graft blast · origin/main...HEAD · depth 2 · 33 changed files

Open the interactive graph → — click an area to see its dependent symbols at file:line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Oct 27, 2026
@shhdwi
shhdwi merged commit a298b4c into main Oct 27, 2026
8 checks passed
github-actions Bot added a commit that referenced this pull request Oct 27, 2026
shhdwi pushed a commit that referenced this pull request Oct 27, 2026
trail check flags hooks.ts:525 and cli.ts:77/2215/2266 against the
"trail skill not loaded on Sonnet", "_trail-pair reads reviews" and
"listNotes filter" learnings. Those are word matches: these lines add
the team sign-in line, an import, and trail login --code. None reads
reviews after init, filters listNotes or changes how the skill loads.
shhdwi added a commit that referenced this pull request Oct 27, 2026
…706)

* Sign a laptop in from an agent: trail login --code, --workspace, and the team file

- `trail login --code <TRL-…>` trades the one-time code Trail's web app
  makes for the signed-in person for this laptop's token: no browser step.
- `trail login` run by an agent prints the sign-in link for its reply and
  leaves a background wait, instead of blocking; `--workspace` picks the
  workspace on the sign-in page. Always listed in --help.
- Once signed in, Claude Code and Cursor get a user-level workspace-only
  `trail` server and Codex its user-level `trail` server, so every agent on
  the laptop has the workspace's tools.
- A signed-in laptop writes `.trail/workspace.json` when it syncs a repo. A
  teammate who pulls it and isn't signed in gets one line (MCP instructions
  and Claude Code's session start) to run `trail login --workspace`. The
  file's address is trusted only when it's the Trail this laptop signs in
  to anyway.
- "Not connected" messages say `trail login`, not the retired connect code.

trail check flags four conflicts; all are keyword matches on "trail":
the Sonnet skill-loading learning, reading reviews in `_trail-pair`, and
filtering in `listNotes`. None of that code changes here.

* chore(release): 0.27.0

* docs(changelog): 0.27.0 notes for #701 and #703 in plain words

trail check flags hooks.ts:525 and cli.ts:77/2215/2266 against the
"trail skill not loaded on Sonnet", "_trail-pair reads reviews" and
"listNotes filter" learnings. Those are word matches: these lines add
the team sign-in line, an import, and trail login --code. None reads
reviews after init, filters listNotes or changes how the skill loads.

* test: the team sign-in line names npx where trail isn't installed (CI)

* learning: tests that name the trail command pass with or without it installed

---------

Co-authored-by: Shrish Dwivedi <shrish@nanonets.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant