Skip to content

Supported read-only thread status stream for external tools (OpenDeck use case) #10929

Description

@beastyrabbit

Note

🤖 Codex responding on behalf of beastyrabbit

We are developing T3 Code Status for OpenDeck, an external plugin that displays running thread counts and highlights pending user input, approvals, and plan reviews on Stream Deck keys.

The plugin currently checks the local environment endpoint and reads T3 Code's local Chromium shell cache on a timer. A shorter interval would make question alerts more responsive, but it would also repeatedly read the cache when nothing has changed. We would prefer an authenticated status subscription.

Smallest useful scope

  • An initial snapshot of current thread states.
  • Updates when work starts or stops, input or approval requests appear or are resolved, or a plan needs review.
  • Updates when threads leave the displayed set, and a way to recover the current state after reconnecting.
  • Read-only access with the narrowest available permissions.

The OpenDeck integration would remain in our project. We only need status metadata for the display; we do not need to send prompts, answer approvals, read conversation bodies, or access workspace files.

Question about the existing interface

In v0.0.40, we found read-only pairing and orchestration.subscribeShell, including the pending-input and approval flags and sequence-based resume support. This looks close to what we need already.

Is read-only pairing plus orchestration.subscribeShell the recommended interface for an external status client? If so, could a minimal supported connection example or contract be documented, covering authentication, session expiry, reconnection, and compatibility expectations?

The current orchestration:read permission also allows file reads. A narrower status-only permission would fit this use case if one is planned. If a different event interface is preferred, guidance on that would also help.

We would be happy to use the existing WebSocket stream if it is intended for this purpose. This request could be addressed independently of a broader SDK or an embedded-plugin system.

Related discussions

I understand feature proposals normally belong in Ideas discussions. Please feel free to move this there or point us to an existing thread if that is the preferred place for this specific integration question.

Activity

  1. juliusmarminge commented on Sep 9, 2026

    @juliusmarminge
    Member

    Thanks for the clear write-up — this is a question about an existing first-party stream, not a missing status API.

    Use subscribeShell

    Read-only pairing + orchestration.subscribeShell is the existing interface for this. It is the same shell projection web, desktop, and mobile use for the thread list. It already covers the scope you listed:

    • Initial snapshot (kind: "snapshot", or GET /api/orchestration/shell)
    • Live upserts/removals (thread-upserted, thread-removed, plus the project equivalents)
    • Pending input / approval / plan review: hasPendingUserInput, hasPendingApprovals, hasActionableProposedPlan
    • Work start/stop: session.status, latestTurn.state, settledAt, backgroundLiveness
    • Reconnect: pass afterSequence from the last snapshot; a large gap or a cursor ahead of the head gets a fresh snapshot instead of unbounded replay. requestCompletionMarker: true emits synchronized before live events.

    Stay on the shell stream. orchestration.subscribeThread includes conversation bodies, which you said you do not want.

    Polling the Chromium shell cache is unsupported. Prefer the authenticated WebSocket subscription.

    This is independent of a broader SDK or embedded plugins.

    Auth, expiry, reconnect (current behavior)

    These are implementation facts for first-party clients, not a published external-client contract.

    1. Mint a read-only pairing link from Settings → Connections → Read only. That grant is orchestration:read only.
    2. Do not use npx t3 pair for this plugin. The CLI pairing command issues the standard client set, which includes orchestration:operate.
    3. Exchange the one-time pairing token at POST /oauth/token (RFC 8693-style). The pairing token is single-use and expires in about 5 minutes. The resulting bearer session lasts about 30 days.
    4. Authenticate HTTP with the bearer token. Open the socket with a short-lived ticket from POST /api/auth/websocket-ticket (~5 minutes). Tickets keep long-lived tokens out of the WebSocket URL.
    5. After a drop: get a new ticket, subscribe again with afterSequence (and requestCompletionMarker if the server advertises shellResumeCompletionMarker). If resume is stale, omit afterSequence and take a new snapshot.
    6. Revoke the session from Settings → Connections (or npx t3 auth) when the plugin should lose access.

    orchestration:read is currently the narrowest grant that includes subscribeShell. It also allows file reads (and thread bodies, diffs, settings, PRs, and more). That is documented as intentional in internals: projects are not a filesystem sandbox.

    There is no status:read / orchestration:status scope, and none is in flight. Open auth-split work (#9788, #9790, and siblings) would peel filesystem and diagnostics off orchestration:read. That would make a read-only pairing closer to “no host file access,” but it is not a status-only permission, and it has not landed yet.

    Compatibility

    @t3tools/contracts is the schema first-party clients follow. It is not a versioned public SDK. Optional fields exist so older peers still decode; treat new fields as additive and expect this stream to change with the app. #6977 is the place for a packaged client SDK if that is what you want later.

    We do not have a user-facing “external status client” page today. A short supported example (auth, expiry, reconnect) would be a docs change if we decide to bless this for third parties. Until then, follow the contracts and the pairing UI above.

    Related Ideas (not duplicates)

    • #6686 — local lifecycle hooks / notifiers. Push events, not a reconnectable snapshot.
    • #6933 — outbound completion webhooks. Terminal events only.
    • #6977 — full SDK + plugin surfaces.

    Your display needs current state on connect and after a gap; subscribeShell is the fit. Those threads are different products.

    CONTRIBUTING.md sends new feature proposals to Ideas. This issue is answered as a question about the existing stream. If you want a status-only scope or a blessed public contract/docs page, open (or convert this to) an Ideas discussion for that slice. No need to re-litigate the three threads above.

    The OpenDeck plugin can stay in your repo. Nothing to change in T3 for the path you already found.

  2. added
    questionFurther information is requested
    documentationImprovements or additions to documentation
    via-triageFiled through npx t3 triage
    on Sep 9, 2026
  3. beastyrabbit commented on Sep 9, 2026

    @beastyrabbit
    Author

    Thanks for the explanation—that clears things up!
    I’m considering opening an Ideas discussion about longer-lived authorization with a minimal status-only scope, so users wouldn’t need to manually re-pair every 30 days.

    Should I close this issue since my question is answered, or leave it open for the contract/docs question raised above?

  4. juliusmarminge commented on Oct 2, 2026

    @juliusmarminge
    Member

    Thanks for taking the time to report this and provide the details. We revisited it during the orchestrator V2 cleanup.

    You confirmed that the interface question was answered. The V2 shell subscription still provides a read-authorized status path, although integrations need the current V2 contracts. This does not promise a stable public SDK or a status-only permission.

    I’m closing this as answered, rather than attributing it to a new V2 fix.

    Source reviewed.

    Original reply names V1 schemas; integrations must follow V2 contracts. No claim of a stable external SDK or status-only permission.

    If you still hit this on a current build, please reply with the app/server versions and the steps that reproduce it. We can reopen this if the original problem is still there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationquestionFurther information is requestedvia-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions