Skip to content

Sign in from your coding agent with a one-time code; release 0.27.0 - #706

Merged
shhdwi merged 5 commits into
mainfrom
feat/browser-sign-in
Oct 27, 2026
Merged

shhdwi merged 5 commits into
mainfrom
feat/browser-sign-in

Conversation

@shhdwi

@shhdwi shhdwi commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

What changes

Trail's connect step (after the first deck) gives coding agents one prompt. The person pastes it into Claude Code, Codex or Cursor, and the laptop is signed in. No browser step, and no pair code to read.

  • trail login --code TRL-…: trades the one-time code Trail's web app makes for the signed-in person for this laptop's token. The code works once, for 15 minutes.
  • trail login from an agent: with no terminal, it prints the sign-in link for the agent's reply and finishes in a background wait instead of blocking. --workspace <slug> opens the sign-in page on that workspace. Always listed in --help.
  • Every agent on the laptop: once signed in, Claude Code and Cursor get a user-level workspace-only trail server, and Codex its user-level trail server.
  • Teammates: 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, in the MCP instructions and in Claude Code's session start, to run trail login --workspace. The address in the file is used only when it's the Trail this laptop signs in to anyway, so a repo can't send someone to sign in elsewhere.
  • Every "not connected" message says trail login.
  • Release bump to 0.27.0, with the changelog (also covers init: learnings worth reading, from past sessions and the PRs #701 and Build a missing code map on the first trail query #704).

Needs trailhq/trail-cloud's POST /api/cli/login-codes/claim for --code. Until that ships, an older server answers 404 and the CLI says so.

Tested

  • Unit and integration tests for the new paths: the code claim, the login link with --workspace, the team file and its address check, the team line in the MCP instructions, and help listing. 107 pass in the touched files.
  • The full suite: 4084 of 4096 passed before the final changes. Two graft → trail move tests fail the same way on clean main (they depend on the machine's installed trail), and one FIFO timing test is flaky.
  • Real headless Claude Code sessions against a local trail-cloud, on a sandboxed laptop with this build installed from the packed tarball:
    • The connect page's copied prompt, pasted as is: Claude ran trail login --code, and the laptop signed in with no browser.
    • A fresh session then answered "what are our brand colours?" from the workspace.
    • A teammate's laptop (cloned repo, not signed in) asked for a deck outline, and its Claude offered the sign-in unprompted.

trail check flags four conflicts. All are keyword matches on "trail" (the Sonnet skill-loading learning, reading reviews in _trail-pair, filtering in listNotes), and none of that code changes here.

🤖 Generated with Claude Code

@trailhq-graft

trailhq-graft Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🌱 graft blast radius

5 areas changed → 2 areas can be affected. 4 dependent symbols, depth 2.
Tests: no test reaches MCP Configuration, Authentication CLI, Claude Hooks; 2 areas updated their tests.
Tag: @anirudhkumar-nanonets — 6 of 7 areas · Rushabh Nagda — Workspace Synchronization, MCP Server · @afeddersen — Hosts Initialization

flowchart TB
  A0(("Device Pairing<br/>3 symbols"))
  A1(("Hosts Initialization<br/>1 symbol"))
  classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
  class A0,A1 reached;
Loading
Can be affected Symbols Nearest hop Reached from
Device Pairing 3 src/cloud/other-repos.ts:L102-L135 setUpPicked — calls, depth 1 Workspace Synchronization
Hosts Initialization 1 src/hosts/init.ts:L53-L123 runHostsInit — calls, depth 2 MCP Configuration
Who knows this code — 3 people across 7 areas
Area Who knows it
Workspace Synchronization · changed Rushabh Nagda — 2 commits, last 6d ago · @anirudhkumar-nanonets — 1 commit, last 14d ago
MCP Configuration · changed @anirudhkumar-nanonets — 7 commits, last 12d ago
MCP Server · changed @anirudhkumar-nanonets — 6 commits, last 14d ago · Rushabh Nagda — 1 commit, last 7d ago
Authentication CLI · changed @anirudhkumar-nanonets — 61 commits, last 5d ago
Claude Hooks · changed @anirudhkumar-nanonets — 16 commits, last 5d ago
Hosts Initialization · affected @anirudhkumar-nanonets — 2 commits, last 14d ago · @afeddersen — 1 commit, last 2mo ago
Device Pairing · affected only you — nobody else has touched these files

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 4 dependent symbols, grouped by area

Device Pairing — 3 symbols in 2 files

  • src/cloud/other-repos.ts:L102-L135 — setUpPicked (calls, depth 1)
    127: const synced = await syncRepo(r.checkout, { ...cloud, repos: repoKeys }, { fetch: false, fetchImpl: opts.fetchImpl });
  • src/cloud/pair.ts:L308-L366 — waitAndUpload (calls, depth 1)
    359: const res = place.git ? await syncRepo(place.checkout, readCloud() ?? cloud, { fetch: false, fetchImpl: opts.fetchImpl }) : null;
  • src/cloud/pair.ts:L293-L304 — finishPair (calls, depth 2)

Hosts Initialization — 1 symbol in 1 file

  • src/hosts/init.ts:L53-L123 — runHostsInit (calls, depth 2)
    65: /** The name `init` runs under; trail's moves the repo to trail's names (see `hostWiringName`). */
Test signal per changed area — 2 ✓ · 3 ✗

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.

  • ✓ Workspace Synchronization — 8 of 11 reached · 2 test files changed here: test/cloud-login-code.test.ts, test/trail-nudge.test.ts
    • not reached: teamLine, teamPath, teamSignInLine
  • ✗ MCP Configuration — 0 of 3 reached · no test file reaches it
    • not reached: installCursorBrainsServer, removeCursorBrainsServer, upsertCodexToml
  • ✓ MCP Server — 0 of 1 reached · 1 test file changed here: test/mcp-connector.test.ts
    • not reached: startMcpServer
  • ✗ Authentication CLI — 0 of 4 reached · no test file reaches it
    • not reached: loginCommand, addAgentEntries, loginWithCode, logoutCommand
  • ✗ Claude Hooks — 0 of 1 reached · no test file reaches it
    • not reached: main
10 test suites also reference this code

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

  • test/hosts-mcp-config.test.ts
  • test/hosts-retract.test.ts
  • test/hosts-trail.test.ts
  • test/mcp-connector-review.test.ts
  • test/pair-late-connect.test.ts
  • test/trail-cloud.test.ts
  • test/trail-connect.test.ts
  • test/trail-skill-use.test.ts
  • test/trail-upload-names.test.ts
  • test/trail-upload-safety.test.ts

⚠️ 4 changed files not in the graph (.trail/learnings/2026-10-27-tests-of-lines-that-name-the-shrish.md, CHANGELOG.md, package-lock.json, package.json) — no parser claims the extension, or the index predates the file.

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

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

github-actions Bot added a commit that referenced this pull request Oct 27, 2026
Shrish Dwivedi added 3 commits October 27, 2026 17:02
…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.
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
shhdwi force-pushed the feat/browser-sign-in branch from f79d3d0 to 5dedfd9 Compare October 27, 2026 12:56
github-actions Bot added a commit that referenced this pull request Oct 27, 2026
github-actions Bot added a commit that referenced this pull request Oct 27, 2026
@shhdwi
shhdwi merged commit bc9544d into main Oct 27, 2026
10 of 11 checks passed
github-actions Bot added a commit that referenced this pull request Oct 27, 2026
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