sandbox-quantum / sandbox-quantum/switch

switch-connector: agents launched via npx never receive pushed events — hook resolves the channel port from the wrong pid

Open
#320 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug help wanted
Dominant language
Python
Stars
646
Forks
52
Avg merge
1d 7h
Merged PRs (30d)
151

Description

Summary

An agent connects, appears live in the room, and can read_context — but never receives an addressed message. There is no error anywhere. Seen on switch-connector 0.9.10.

Impact

Indistinguishable from a healthy but slow agent. Every observable signal says the agent is fine: the process is up, the MCP server is registered, the package resolves, the room shows the agent present. Only delivery is missing.

This is reproducible from a clean install — the npx line below is what the plugin ships, so anyone running the stock connector on a remote host hits it. It is not a one-off environment problem.

Root cause

hooks/switch_hook.py:333 resolves the channel port from the hook's own parent pid:

return os.path.join(
    os.path.expanduser("~"), ".switch", "sessions", str(os.getppid()), "port"
)

That is correct only if the runtime is a direct child of Claude Code. The comment above it says so, and even warns about the mirror case (a hook wrapped in a shell). But .mcp.json at HEAD wraps the other side:

{ "command": "npx", "args": ["-y", "@sandboxaq/switch-agent-runtime@0.3.3"] }

npx inserts npm execsh -cnode, so the runtime registers its port under a different pid than the hook computes. Both sides resolve the path independently — to two different paths.

Why it is silent

_notify_channel swallows the miss:

except (FileNotFoundError, ValueError):
    return

No log, no warning. This is precisely the failure CLAUDE.md's "Fail Loud, Never Fake" section exists to prevent — item 4, silently degrading to look fine.

Suggested fix

  1. Don't infer the pid. Have the runtime pass its port (or the port-file path) to the hook explicitly — via env at session launch, or a fixed per-session path both sides derive from the session id rather than from a process relationship. The pid coupling is fragile regardless of npx: any future wrapper reintroduces it.
  2. Warn once when the port file is absent. A single stderr line naming the path it looked for would turn days of debugging into minutes.

Workaround (confirmed working)

Point the MCP command straight at the installed binary, no npx:

{ "mcpServers": { "switch": { "command": "<prefix>/bin/switch-agent-runtime", "args": [] } } }

Delivery works immediately. Note this is overwritten by any plugin update, and the agent goes silently deaf again when it does.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read hooks/switch_hook.py around line 333, then inspect .mcp.json and the switch-agent-runtime launch path. Reproduce the missing delivery from a clean install using the npx command and trace which session paths each process resolves. Done means the hook and runtime share a stable session-specific port path, and a missing port file emits a warning instead of failing silently.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, python
Domain
backend, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.