Skip to content

fix(server): count a live session as connection evidence in initialize - #1192

Merged
divshekhar merged 1 commit into
reticlehq:mainfrom
drakeo338:claude/1138-fix
Sep 29, 2026
Merged

divshekhar merged 1 commit into
reticlehq:mainfrom
drakeo338:claude/1138-fix

Conversation

@drakeo338

Copy link
Copy Markdown
Contributor

What & why

Closes #1138.

Both initialize call sites used only hasAnyProjectConnectedBefore, durable memory that can be empty or stale for a project wired without .reticle.json. An agent attaching with a live browser session was still told "no app has ever connected" and pointed at init/restart. The fix ORs in bridge.sessions.count() > 0, so a live session outweighs stale durable memory.

I released my claim on the issue earlier while unsure a PR was wanted; since it is still open, here is the fix in case it helps. Happy to close it if you'd rather handle it differently.

How it was verified

New test in server/src/index.mcp-live-session.test.ts fails on the unfixed tree and passes with the fix. Per CONTRIBUTING.md's AI-assisted policy: checked.

Gates run

  • pnpm lint && pnpm typecheck && pnpm test:unit (~2 min — always)
  • pnpm test:e2e (~8 min) — touched the tool surface, core, an observer, or telemetry
  • pnpm gate:install (~15 min) — touched reticle init, vite-plugin, next, or babel-plugin
  • pnpm test:e2e:desktop (~3 min) — touched adapters/realm/electron, adapters/realm/tauri, or desktop capture
  • None of the above tiers apply to this change

Checklist

  • Every commit is signed off (git commit -s) — CI's DCO check fails the PR without it. Already pushed? git rebase --signoff origin/main && git push --force-with-lease
  • Tests added/updated (RED → GREEN); the change is covered by a test that would fail without it
  • No any, no free strings (wire strings live in @reticlehq/core), no non-null !
  • No console.log or internal tracking codes left in the diff
  • Each changed file is under the 1000-line cap
  • Docs updated, and a user-facing change adds a new file under .changes/ (never edit CHANGELOG.md — that file is assembled at release time, and editing it is what makes PRs conflict; format in .changes/README.md)
  • Security-affecting? Auth/redaction/trust-boundary changes keep the localhost-only, no-app-data-leaves-the-machine, no-arbitrary-JS posture (usage telemetry stays anonymous + opt-out per docs/telemetry.md) and are covered by a test — not applicable, no auth/redaction/trust-boundary change here

🤖 Generated with Claude Code

hasAnyProjectConnectedBefore alone decided whether the MCP `initialize`
instructions led with the first-install steps. That durable memory can
be empty or stale for a project the plugin wired without writing
.reticle.json, so an agent attaching while a browser session was
already live was told "no app has ever connected" and pointed at
init/restart/load instead of getting straight to work.

Both createMcpServer call sites (start(), startDaemon()) now OR in
bridge.sessions.count() > 0, so a session connected right now outweighs
empty or stale durable memory.

Closes reticlehq#1138. AI-assisted: the added test was run against the
unfixed tree and confirmed to fail before this change, per
CONTRIBUTING.md's AI-assisted contributions policy.

Signed-off-by: drakeo338 <paranoyouz@gmail.com>
@github-actions github-actions Bot added area/server Affects packages/server area/docs Documentation and docs site labels Sep 29, 2026
@github-actions

Copy link
Copy Markdown

Thanks for your first pull request to Reticle! A maintainer aims to review within two days. Before then, pnpm verify locally catches most of what CI will, and CONTRIBUTING.md explains the rest. If CI does not start, a maintainer needs to approve it for first-time contributors; that is normal.

@greptile-apps

greptile-apps Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 3/5

[Medium risk] Changes the logic that decides whether to show first-install steps.

The PR is not ready to merge because another project’s session can suppress setup guidance and the standalone handshake can still miss a newly live session.

Findings

  1. P1 Other projects count as connected ▶
  2. P1 Standalone handshake misses later sessions ▶
  3. P2 Handshake test inlines wire strings ▶

Summary

The PR adds live browser sessions as evidence when choosing MCP initialize instructions and adds a daemon/SSE regression test and changelog entry. The new check needs project scoping, and the standalone stdio path still snapshots liveness before its handshake.

Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  B[Browser sessions from multiple projects] --> C[Global session count]
  D[Directory project IDs] --> M[Durable connection memory]
  C --> O[Previously connected OR]
  M --> O
  O --> I[Initialize instructions]
Loading

Reviews (1) · Last reviewed commit: "fix(server): count a live session as con..."

Comment thread server/src/index.ts
profile,
hasAnyProjectConnectedBefore(reticleStateHome(), port, projectIdsAt(process.cwd())),
// See the sibling call in `start`: a live session outweighs empty/stale durable memory (#1138).
bridge.sessions.count() > 0 ||

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Other projects count as connected

A shared daemon can have a live browser session for project A while project B has never been wired. This count includes A’s session, so an agent attaching for B is treated as previously connected and does not receive B’s first-install instructions. The live-session check needs to consider the project or projects represented by the handshake.

Comment thread server/src/index.ts
// stale for a project the plugin wired without writing `.reticle.json` (see connection-memory.ts's
// KNOWN LIMIT). Without this OR, that project's `initialize` led with the first-install steps
// while a real session was already connected — see #1138.
bridge.sessions.count() > 0 ||

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Standalone handshake misses later sessions

The standalone stdio path reads the session count once while constructing the MCP server, before the client’s initialize. If a browser connects afterward and durable memory is empty, the instructions still say no app has connected, even though that session is live by the time the agent initializes.

port,
endpoint.data,
rpc(1, 'initialize', {
protocolVersion: '2024-11-05',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Handshake test inlines wire strings

The new test inlines the JSON-RPC version, initialize method, and protocol version in its request. The repository’s “No free strings” directive requires domain and wire strings to be named constants. Please use contract constants or named fixture constants before merging.

Context Used: CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@divshekhar
divshekhar added this pull request to the merge queue Sep 29, 2026
Merged via the queue into reticlehq:main with commit 37d1022 Sep 29, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs Documentation and docs site area/server Affects packages/server

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[agent] The MCP handshake tells the agent no app has ever connected while a session is live

2 participants