Skip to content

Connect to Trail Cloud at the moments trail is used - #708

Merged
anirudhkumar-nanonets merged 2 commits into
mainfrom
feat/link-repo-to-workspace
Oct 27, 2026
Merged

anirudhkumar-nanonets merged 2 commits into
mainfrom
feat/link-repo-to-workspace

Conversation

@anirudhkumar-nanonets

Copy link
Copy Markdown
Collaborator

Trail now acts at the moments a session needs it, instead of waiting for Claude to run a trail command, which it often doesn't. In a plain assign session on 2026-10-27, Claude answered with grep and never ran trail, so the sign-in link never showed. A laptop can also link each repo to its own Trail workspace.

Moves: connect, Trail Cloud sign-in links shown → linked, trail only. It's read in PostHog DB 11:

SELECT properties->>'mode' AS mode,
       count(DISTINCT distinct_id) FILTER (WHERE event = 'brain_signup_opened') AS shown,
       count(DISTINCT distinct_id) FILTER (WHERE event = 'brain_signup_settled' AND properties->>'outcome' = 'linked') AS linked
FROM posthog_event_full_view
WHERE timestamp >= now() - interval '7 days' AND event IN ('brain_signup_opened','brain_signup_settled')
  AND properties->>'cli_name' = 'trail'
GROUP BY 1;

On 2026-10-27 that was 0 nudge links shown in the last 30 days (mode: nudge). Metabase wasn't reachable when this PR opened, so that figure is from earlier the same day. The link is still off unless TRAIL_CLOUD=1.

Trail at a session's moments

When What happens Where
Just before an edit A new PreToolUse pre-edit hook hands Claude the learnings on that file. Until now they arrived after the edit. hooks.ts handlePreEdit, settings-merge.ts
Before git commit, git push, gh pr create pre-bash runs trail check and stops the command once per set of conflicts. Claude fixes it, or says why and runs the same command again, which goes through. It's capped at 3.5 s and fails open. pre-bash-check.ts (new), pre-bash.ts
End of a turn Two new save signs. overrode: a check conflict that shipped anyway asks for a replacing learning. Deploy and CI steps that failed then passed (docker, kubectl, terraform, helm) now count as fixes. A check run with a folder flag (go -C backend test, npm --prefix web test) counts too, and the sign was missed without it. note-signals.ts
Tickets, debugging The trail skill now says to run trail ask when starting from a ticket and after a test fails, and that learnings arrive before an edit. skill-template.ts
A hook just used trail The Trail Cloud link reaches the person as a notice when the prompt hook or the pre-edit hook surfaced a teammate's learning. That's once a session, on the same rules as before. "Connected" news shows on the next prompt instead of the next trail command. nudge.ts hookNotice, linkedNews, prompt-hook.ts

One repo, one workspace; a laptop can have several

  • cloud.json holds one connection per workspace (a trl_ token each). trail-cloud already mints one per handoff, so it needs no server change.
  • The newest connection stays at the top level, so an older trail still reads it, and keeps the rest under others when it writes it back.
  • Each repo goes to the newest connection that has it (cloudForRepo). Sync, the activity outbox, recordLookup, recordSkillUse, the MCP connector (by its cwd), team and status all look up the repo's workspace first.
  • Signed in, a repo that no workspace has gets its own link, "Pick a Trail workspace for ", in place of the old "add it?" question asked once, ever.
  • trail workspace lists every workspace. workspace add --to <slug> picks one. logout --workspace <slug> drops one.

trail check conflicts on this branch: word matches, not real

trail check flags 4 lines. Each matches a learning's ruled-out words without doing what the learning ruled out:

  • src/claude/note-signals.ts:83: the check pattern. It doesn't match failing and passing runs by full command string.
  • src/claude/note-signals.ts:318: the overrode sign. It filters nothing out of listNotes.
  • src/cli.ts:75: an import line.
  • src/cli.ts:2241: logout. It doesn't touch pair reviews or replaced learnings.

The new commit check would stop the first commit here for these. That's worth deciding on before release: it could warn instead of stop until the check's matching improves.

Tested

  • New tests:
    • test/trail-workspaces.test.ts: the store, routing, an old-format file, logout of one, and uses per workspace.
    • test/trail-scenario-hooks.test.ts: before-edit wording, the commit check once per conflict set, overrode, deploy fixes, folder-flag checks, and the hook notice.
    • trail-nudge.test.ts updated for the per-repo link.
  • Pinned-hook tests updated for the second PreToolUse entry. The PreToolUse load budget goes from ≤12 to ≤13 files for the commit check.
  • Full suite in a scratch HOME: all pass except 3 that fail the same way on main on this machine (graft-to-trail, hosts-trail, upkeep-hooks).
  • End to end against a local trail-cloud (trailhq/trail-cloud#74):
    • Bug fix: in a clone of assign with a real regression, the pre-edit hook gave Claude Aman's learning on apply.go and showed the link. The link connected Acme, and 14 items uploaded.
    • Save ask: in a clean session, go -C backend test failed and then passed. The Stop hook asked to save, and Claude said the existing learning already covers it.
    • Prompt hook: a ticket prompt got the "TriggerService is built in three binaries" learning and the "connected" news.
    • Second repo: it got "isn't in any of your Trail workspaces · pick one" and went to a second workspace, and its uses reached only that one.
    • Commit check: run on this branch, it stopped the first commit in 476 ms and let the second through.

🤖 Generated with Claude Code

@trailhq-graft

trailhq-graft Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🌱 graft blast radius

5 areas changed → 9 areas can be affected. 35 dependent symbols, depth 2.
Tests: no test reaches CLI Commands; Workspace Connectivity has tests the diff did not touch; 2 areas updated their tests.
Tag: @shhdwi — 14 of 14 areas · Daniel JB Clark — 6 of 14 areas · Rushabh Nagda — Workspace Connectivity

flowchart TB
  A0(("Session Management<br/>13 symbols"))
  A1(("Host Configuration<br/>8 symbols"))
  A2(("Tool Invocation<br/>3 symbols"))
  A3(("Installation Process<br/>3 symbols"))
  A4(("Note Management<br/>2 symbols"))
  AX(("4 smaller areas<br/>6 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;
Loading
Can be affected Symbols Nearest hop Reached from
Session Management 13 src/claude/init.ts:L1-L305 init.ts — imports, depth 1 Skill Handling, Cloud Synchronization +1
Host Configuration 8 src/hosts/antigravity.ts:L1-L62 antigravity.ts — imports, depth 1 Skill Handling
Tool Invocation 3 src/mcp/tools.ts:L250-L336 callSingleTool — calls, depth 1 Cloud Synchronization, Contract Management
Installation Process 3 src/init/run.ts:L1-L447 run.ts — imports, depth 1 Skill Handling, Contract Management
Note Management 2 src/notes/memory-notes.ts:L1-L280 memory-notes.ts — imports, depth 1 Contract Management
Telemetry Tracking 2 src/telemetry/sessions.ts:L1-L113 sessions.ts — imports, depth 1 Contract Management
3 smaller areas 4 Upkeep Process, CLI Skills, Learning Sessions see below
Who knows this code — 3 people across 14 areas
Area Who knows it
Contract Management · changed @shhdwi — 1 commit, last 5d ago · Daniel JB Clark — 1 commit, last 5d ago
Skill Handling · changed @shhdwi — 7 commits, last today
Cloud Synchronization · changed @shhdwi — 26 commits, last today
Workspace Connectivity · changed @shhdwi — 3 commits, last today · Rushabh Nagda — 1 commit, last 7d ago
CLI Commands · changed @shhdwi — 24 commits, last today
Session Management · affected @shhdwi — 4 commits, last 4d ago · Daniel JB Clark — 1 commit, last 5d ago
Host Configuration · affected @shhdwi — 3 commits, last yesterday · Daniel JB Clark — 1 commit, last 5d ago
Tool Invocation · affected @shhdwi — 2 commits, last 5d ago
…6 further 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 @ 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 35 dependent symbols, grouped by area

Session Management — 13 symbols in 10 files

  • src/claude/init.ts:L1-L305 — init.ts (imports, depth 1)
  • src/claude/session-metrics.ts:L1-L215 — session-metrics.ts (imports, depth 1)
  • src/claude/skills-wiring.ts:L1-L116 — skills-wiring.ts (imports, depth 1)
  • src/claude/state.ts:L1-L165 — state.ts (imports, depth 1)
  • src/claude/stop.ts:L142-L156 — askForNote (calls, depth 1)
  • src/claude/stop.ts:L183-L204 — handleStopEvent (calls, depth 1)
  • src/claude/hook-io.ts:L1-L140 — hook-io.ts (imports, depth 2)
  • src/claude/init.ts:L194-L245 — runTrailInit (calls, depth 2)
  • src/claude/prompt-skills.ts:L1-L327 — prompt-skills.ts (imports, depth 2)
  • src/claude/stats.ts:L1-L27 — stats.ts (imports, depth 2)
  • src/claude/statusline.ts:L1-L39 — statusline.ts (imports, depth 2)
  • src/claude/stop.ts:L1-L216 — stop.ts (imports, depth 2)
  • src/claude/sync-run.ts:L1-L48 — sync-run.ts (imports, depth 2)

Host Configuration — 8 symbols in 8 files

  • src/hosts/antigravity.ts:L1-L62 — antigravity.ts (imports, depth 1)
  • src/hosts/instructions.ts:L1-L83 — instructions.ts (imports, depth 1)
  • src/hosts/registry.ts:L1-L186 — registry.ts (imports, depth 1)
  • src/hosts/auto.ts:L1-L155 — auto.ts (imports, depth 2)
  • src/hosts/cursor-hooks.ts:L1-L117 — cursor-hooks.ts (imports, depth 2)
  • src/hosts/init.ts:L1-L124 — init.ts (imports, depth 2)
  • src/hosts/plan.ts:L1-L101 — plan.ts (imports, depth 2)
  • src/hosts/retract.ts:L1-L545 — retract.ts (imports, depth 2)

Tool Invocation — 3 symbols in 1 file

  • src/mcp/tools.ts:L250-L336 — callSingleTool (calls, depth 1)
  • src/mcp/tools.ts:L219-L247 — callTool (calls, depth 2)
  • src/mcp/tools.ts:L1-L337 — tools.ts (imports, depth 2)

Installation Process — 3 symbols in 3 files

  • src/init/run.ts:L1-L447 — run.ts (imports, depth 1)
  • src/init/install-paths.ts:L1-L84 — install-paths.ts (imports, depth 2)
  • src/init/keep.ts:L1-L386 — keep.ts (imports, depth 2)

Note Management — 2 symbols in 2 files

  • src/notes/memory-notes.ts:L1-L280 — memory-notes.ts (imports, depth 1)
  • src/notes/pr-reviews.ts:L1-L577 — pr-reviews.ts (imports, depth 1)

Telemetry Tracking — 2 symbols in 2 files

  • src/telemetry/sessions.ts:L1-L113 — sessions.ts (imports, depth 1)
  • src/telemetry/track.ts:L1-L162 — track.ts (imports, depth 1)

Upkeep Process — 2 symbols in 2 files

  • src/upkeep-run.ts:L1-L103 — upkeep-run.ts (imports, depth 2)
  • src/upkeep.ts:L1-L326 — upkeep.ts (imports, depth 2)

CLI Skills — 1 symbol in 1 file

  • src/skills/cli-skills.ts:L1-L376 — cli-skills.ts (imports, depth 2)

Learning Sessions — 1 symbol in 1 file

  • src/learn/sessions.ts:L1-L310 — sessions.ts (imports, depth 1)
Test signal per changed area — 2 ✓ · 1 ⚠ · 1 ✗ · 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.

  • – Contract Management — 8 test files reach it, none changed here
  • ✓ Skill Handling — 7 of 16 reached · 2 test files changed here: test/claude-hook-timeouts.test.ts, test/trail-scenario-hooks.test.ts
    • not reached: learningsOnTouch, handlePreEdit, main, branchConflicts, sessionOf, shipping, main, say, …1 more
  • ✓ Cloud Synchronization — 16 of 27 reached · 3 test files changed here: test/trail-nudge.test.ts, test/trail-scenario-hooks.test.ts, test/trail-workspaces.test.ts
    • not reached: linkLines, live, register, waitAndUpload, teamSignInLine, syncWorkspaceRepos, runSyncChild, validCloud, …3 more
  • ⚠ Workspace Connectivity — 1 of 4 reached · 2 test files reach it, none changed here
    • not reached: constructor, cloud, startMcpServer
  • ✗ CLI Commands — 0 of 6 reached · no test file reaches it
    • not reached: loginCommand, loginWithCode, logoutCommand, workspaceCommand, teamCommand, statusCommand
76 test suites also reference this code

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

  • test/activity-saved-tokens.test.ts
  • test/claude-copy-dashes.test.ts
  • test/claude-format.test.ts
  • test/claude-hooks-1b.test.ts
  • test/claude-hooks-perf.test.ts
  • test/claude-hooks-skills.test.ts
  • test/claude-hooks.test.ts
  • test/claude-host-standdown.test.ts
  • test/claude-init.test.ts
  • test/claude-post-bash-walls.test.ts
  • test/claude-prompt-learnings.test.ts
  • test/claude-prompt-private.test.ts
  • test/claude-session-start-learnings.test.ts
  • test/claude-settings-merge.test.ts
  • test/claude-shim-template.test.ts
  • test/claude-skill-template.test.ts
  • test/claude-skills-journey-fixtures.ts
  • test/claude-start-skills-1b.test.ts
  • test/claude-start-skills-2.test.ts
  • test/claude-state.test.ts
  • …56 more

⚠️ 5 changed files not in the graph (.trail/learnings/2026-10-27-a-laptop-links-each-repo-to-anirudhkumar.md, .trail/learnings/2026-10-27-a-sandbox-s-trail-hooks-stand-anirudhkumar.md, .trail/learnings/2026-10-27-testing-the-cloud-nudge-locally-rebuild-anirudhkumar.md, TELEMETRY.md, test/fixtures/skills/trail/SKILL.md) — no parser claims the extension, or the index predates the file.

graft blast · refs/graft/base...HEAD · depth 2 · 31 changed files

Open the interactive graph → — click an area to see the code that changed, and the line that reaches it.

…kspace

# Conflicts:
#	src/cli.ts
#	src/cloud/workspace-sync.ts
@anirudhkumar-nanonets
anirudhkumar-nanonets merged commit 961a9e8 into main Oct 27, 2026
6 of 7 checks passed
shhdwi pushed a commit that referenced this pull request Oct 27, 2026
0.28.0 rather than 0.27.1: #708 adds behaviour (learnings before an edit,
a check before commit/push/PR, several workspaces per laptop), not just
the npx fix. Release notes describe both in plain words.

Also: logout --workspace of the last workspace now removes Cursor's
workspace entry too, as plain logout does.
shhdwi added a commit that referenced this pull request Oct 27, 2026
… npx sign-in (#709)

* fix(login): agents get Trail's tools after a sign-in run through npx; release 0.27.1

`npx -y @trailhq/trail-code login --code` on a laptop without trail wrote
Claude Code, Cursor and Codex entries with `"command": "trail"`. Under
npx, trail is on PATH only for that process (npx's temporary
node_modules/.bin), so trailOnPath() said yes. Agents start with the
person's PATH and got no tools.

commandOnPath now skips node_modules/.bin folders, so those laptops get
the npx launch. Verified end to end: a fresh sandbox laptop with no trail
ran the page's prompt in Claude Code, and a new session got all 6
workspace tools.

* chore(release): 0.28.0, with Anirudh's #708

0.28.0 rather than 0.27.1: #708 adds behaviour (learnings before an edit,
a check before commit/push/PR, several workspaces per laptop), not just
the npx fix. Release notes describe both in plain words.

Also: logout --workspace of the last workspace now removes Cursor's
workspace entry too, as plain logout does.

* learning: an agent with no Trail tools on a busy machine isn't proof the sign-in broke

* Commit check warns instead of stopping, and runs in Claude Code's hooks

As asked: until trail check's matching improves, a conflict before
commit/push/PR is a warning. The hook adds additionalContext with no
permission decision, so the command runs and Claude reads which learning
it goes against. SHIP_CHECK_STOPS turns the once-per-conflict stop back on.

Two bugs found testing it in a real Claude Code session:
- The check only ran with TRAIL_INVOKED_AS=trail, which Claude Code's hooks
  never have. It now also runs in a repo wired for trail, as the other
  hooks decide.
- `git -C dir push` and `git -c k=v commit` weren't seen as a commit/push.

Verified: a real session committed against a learning; the commit ran and
Claude quoted the warning and recommended reverting.

---------

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