Repository navigation
Inbox: replies go into running Qwen Code sessions - #2274
Merged
Merged
Conversation
Plannotator registers itself as Qwen Code's trusted sender when it connects Qwen (qwen sessions controllers add, Qwen 0.24+), keeps the token 0600 in its data dir, says so in the Connected band, and revokes it when Qwen Code is turned off in Settings or Plannotator is uninstalled. The Qwen wake (inbox-qwen-wake.ts, after the Codex wake) finds a live session in Qwen's registry and sends the reply over its socket: the auth line with the token and one user frame naming the session, once per item (claim folders), with Qwen's receipts read on a socket of the Inbox's own. Held, refused or unconfirmed replies are saved for the next read and never sent twice; misaddressed or a dead process ends the session; ACP, headless, daemon, hold/refuse settings and Windows fall back to MCP.
# Conflicts: # apps/hook/server/inbox-cli.test.ts # apps/hook/server/inbox-mcp-shim.ts # docs/agent-guides/inbox-foundation.md # packages/server/inbox-agents.ts # packages/server/inbox.ts
- Read the pid namespace with stat (the namespace's inode, as Qwen records it); the test reads it in another process. - A grant label unique to each data dir; a grant in another QWEN_HOME is revoked there before one is minted here; a grant revoked outside is said once. - No token on Windows, where nothing is woken. - Settings off: remove the MCP entry, record off, then revoke; a revoke that fails keeps the token and never mints a new one. - Receipt tokens compared as bytes; a bad receipt line ends only its socket. - A missing receipt asks Qwen (at most every 5 min) whether the grant is still listed; a revoked one drops the token. - Qwen settings merged as Qwen merges them (system defaults, user, workspace tighten-only, system); an unknown inbound value holds. - Turn-on says a failing mint; the band and terminal say what the grant allows. - --version answers cached a minute; leftover socket folders cleaned.
# Conflicts: # docs/agent-guides/inbox-foundation.md
- Turning Qwen Code off when Qwen refuses the revoke drops the token at once
(the wake stops) and keeps only the grant id (revoke_pending). Each connect
run while Qwen Code is not connected retries the revoke; turning it on
revokes it before minting; uninstall revokes it too. The message names the
command to remove it by hand.
- A controllers list line that is not an {id, label} object makes the list
unknown (token kept, retried later), never "revoked".
- Tests: the wake stops after a failed-revoke turn-off; retries until it works;
a list of another shape.
…ntry is elsewhere
# Conflicts: # apps/hook/server/inbox-command.ts
# Conflicts: # packages/inbox/agents.test.ts # packages/inbox/agents.ts # packages/inbox/components/AgentNoteDialog.tsx # packages/server/inbox-agents.ts
- A run under another QWEN_HOME than the entry's moves no grant; turning Qwen Code on in Settings there moves the entry, then the grant. - Turning off (and uninstall) takes the token out of the data folder before Qwen is asked to revoke (revoke_pending), so a stop mid-call never leaves it in use. A data folder that cannot be written never throws: uninstall goes on to the entries and the binary, and says so. - Settings writes agents.json before it calls qwen (on and off). - Tests: no grant moved by a run elsewhere; a pending grant in another home revoked at the next run and before a mint; the token gone while Qwen is asked; an unwritable data folder (trust and uninstall).
# Conflicts: # packages/server/inbox-agents.ts
… kept before qwen runs
… fold case; test the revoke command's home Two Qwen homes that differ only by case are two homes on a case-sensitive volume: a grant in one is never taken for removed from the other. The revoke command names QWEN_HOME only for another home, never for the same one spelled another way.
# Conflicts: # packages/server/uninstall.test.ts
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
When you reply to a running Qwen Code session, your reply now arrives in that session as its next turn, the same way Codex works today. It is stacked on #2271 (connect Qwen Code and tag its sessions), so please review that one first.
qwen sessions controllers add. The label is "Plannotator Inbox" plus a short code for the Plannotator data folder, so two data folders on one Qwen home never revoke each other's grant. The token is kept ininbox/qwen-trust.jsonwith mode 0600. The Connected band and the terminal say what it allows: Plannotator can put your replies straight into any running Qwen session, without Qwen asking you first, and Settings → Agents turns it off. No token is made on Windows, where nothing is woken.plannotator uninstallrevokes it too. Before Qwen is asked to revoke, the token is taken out of the data folder, so stopping mid-call never leaves it in use. A data folder that cannot be written never stopsplannotator uninstall; it says so. A run that starts with a differentQWEN_HOMEmoves no grant: the grant stays with the entry. Turning Qwen Code on in Settings → Agents there moves both, the entry first.qwen sessions controllers removeis said once and never made again on its own. A grant list in a shape Plannotator does not know counts as unknown, never as revoked. This is checked at each connect run, and also while the Inbox runs: when Qwen stops confirming, the Inbox asks Qwen (at most every five minutes) whether the grant is still there, and drops the token if not.packages/server/inbox-qwen-wake.tsfollows the Codex wake.$QWEN_HOME/sessions/) and checks that the process is alive. On Linux it also checks the boot and the pid namespace, read as Qwen records them.userframe that names the session.delivered: "Queued for Qwen Code".held,refused,deniedor no receipt: "Saved for its next read", never sent again.misaddressedor a dead process: the session has ended.dropped: tried again later with a new id. A resumed session gets the reply then.qwen -pruns, sessions an editor orqwen servedrives, daemon calls, Windows, and sessions whose Qwen settings hold or refuse other programs' messages. Those settings are merged as Qwen merges them: system defaults, the person's, the project's (which can only tighten), then system settings. A value Qwen does not know counts as holding.Why
The owner asked for full Qwen Code support in the Inbox, including replies going straight to Qwen (2026-10-27). On who creates the token, the owner decided that Plannotator registers itself as Qwen's trusted sender automatically when it connects Qwen. The Connected band and the terminal say so, and the token is revoked on disconnect or uninstall.
INBOX_QWEN_TRUST_ON_CONNECTholds that decision, so moving it behind a Settings switch later would be a small change.Changes for existing users
peer-controllers.json) the next timeplannotator inboxruns. The band and the terminal say so.How it was tested
packages/server/inbox-qwen-wake.test.ts(17 tests) uses a fake Qwen session: a socket owned by the test and a registry record in a scratch Qwen home. It covers a reply sent once across sweeps and a restart, delivery at the next tool call, no token, ACP/headless/daemon sessions, settings that hold (system, the person's, the project's, an unknown value) and the merge rules, misaddressed, a dead process then a resume, held then released, no receipt, refused, dropped and retried, a grant revoked mid-run, Qwen Code turned off while Qwen refuses the revoke (the wake stops at once), a malformed receipt, a forged receipt, a crashed Inbox's socket folder, and record liveness with the pid namespace read in another process.packages/server/inbox-qwen-trust.test.ts(27 tests) uses a fakeqwenwithsessions controllers add/list/remove. It covers the token made once and kept 0600, a Qwen that is too old, Windows, a revoke outside said once and not made again, Settings off (entry first, then revoke), an entry that cannot be removed, a revoke that fails (token dropped, retried each run, revoked before a new mint), a grant list of another shape, a failing mint at turn-on, a run under anotherQWEN_HOME(no grant moved) and Settings moving both, a grant waiting to be revoked in another home (revoked there at the next run, and before a new mint), the token gone from disk while Qwen is asked, a data folder that cannot be written, noqwento run, uninstall, an orphan grant, two data folders on one Qwen home, one home spelled two ways (never re-minted, and noQWEN_HOME=in the revoke command), two homes that differ only by case on a case-sensitive disk (the grant is never taken for removed), andPLANNOTATOR_INBOX_CONNECT=0.agents.jsonbefore it callsqwen, for both on and off.agents.jsonat its start and writes it at its end (up to 30 s later), so a Settings switch made in that window can be overwritten. The UI does not disable the switches while a run is in progress. Left as is.qwen.qwenwas never run, and the real~/.qwenwas never read.controllers add --jsonoutput and--versionline, real socket and receipt behaviour, and that Qwen's TUI starts a turn for a queued message at once when idle.