Repository navigation
Port the CLI to orchestrator V2 (0.3.0) - #10
Conversation
T3 Code's orchestrator V2 (orchestration protocol 2) removed the HTTP dispatch and snapshot routes, moved its state to statev2.sqlite, and requires protocol 2 on every orchestration request. CLI 0.2 could no longer sign in or send anything to a V2 server. - Speak protocol 2 only and refuse other servers with T3_PROTOCOL_UNSUPPORTED before signing in. 0.2 stays the release for T3 builds before orchestrator V2. - Sign in through a `t3` whose version matches the server: the configured command, the installed desktop app's bundled server, a matching `t3` on PATH, or npx pinned to the server version. The bundled t3 package is gone. - Launch handovers through orchestration.launchThread and send every other write through orchestration.dispatchCommand. Every write is verified in T3's projection before success is reported. - Read threads as runs and runtime requests, including the history a fork inherits, and drop the V1 heuristics that guessed which turn a message belonged to. - Add handover --wait, --if-busy queue|steer|restart, provider switches through threads set, threads fork, merge-back, queue, search, pin, snooze, archive, rename, and the schedules commands. - Discover servers with Node's http client: two global fetch calls followed by process.exit crashed Node 26 on Windows at exit. - Replace the V1 test suite with tests against an in-memory protocol 2 server, and document the changes in README, AGENTS.md, and the skills. BREAKING CHANGE: requires a T3 Code build with orchestrator V2. JSON fields that described V1 sessions and turns changed; README lists them under "Upgrading from 0.2".
A prerelease is a beta for testing, so the publish job skips it. README documents building, packing, and installing a beta from its GitHub release.
…tions A user test of 0.3.0-beta.1 on Linux found three issues: - Sign-in found no desktop install when T3 ran as an AppImage and fell back to npx, a 117 MB download. On Linux the CLI now uses the running server's own executable and entry, read from /proc through the pid in T3's runtime file. A relative entry resolves against the server's working directory. - handover --thinking-effort wrote three effort option ids for a Codex model. Overrides now resolve through the model catalog, as threads set does, with the old behavior when T3 returns no catalog. - The last message of an interrupted turn rendered as "assistant (final)". Only a completed turn has a final answer again. Parallel version probes of several desktop installs could also lose a cache entry; they now share one read and one write.
A handover from a linked worktree launched with existing_worktree and no branch, so T3 recorded the thread without one. T3's own client sends the branch for existing_worktree and root launches, and T3 uses it for pull request discovery, settlement, and recreating a missing worktree. The CLI now sends the checkout's branch on both. It leaves out a temporary t3code/<hex> branch in a worktree: T3 renames such a branch after the first message, even in an existing worktree, which would pull it from under the thread that created it. Schedules are unchanged, because a scheduled run happens later on whatever branch is checked out. The fake server recorded "main" for a launch without a branch, which hid the bug. It now records none, as T3 does. The README also notes the Windows shells that change prompts: Windows PowerShell 5.1 and PowerShell before 7.3 drop double quotes from arguments, 5.1 sends stdin as ASCII, and Git Bash rewrites an argument that starts with a slash into a Windows path.
The README opens with the requirement and maps T3 Code builds to CLI versions: nightly 0.0.46-nightly.20261003.2610 or later needs 0.3, and stable v0.0.45 or earlier needs 0.2. The npm description, the --help text, and both shipped skills name the requirement and the 0.2 fallback too.
Mira PR WalkthroughThis PR ports the CLI to orchestrator V2 and releases version 0.3.0, requiring a compatible T3 Code build and rejecting older server protocols before sign-in. It expands thread and schedule commands, adds busy-handling policies and handover waiting, and verifies writes against server state before reporting success. The migration also replaces the bundled T3 dependency with server-matched sign-in execution and substantially updates test coverage. graph LR
cli["src/cli.ts"] --> cliV2["src/cliV2.ts"]
cli --> shared["src/cliShared.ts"]
cliV2 --> shared
cliV2 --> commands["src/v2Commands.ts"]
tests["src/v2Commands.test.ts"] --> commands
tests --> fake["src/testing/fakeT3.ts"]
Confidence: 3/5 ◉◉◉○○ Moderate confidence
Key files to review:
12 files reviewed · 1 comment ( 📋 Reviewed 12 of 34 filesThis PR is large enough that some files were skipped to keep the review focused on the highest-priority changes. To review the rest, comment Skipped:
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
Security findingsAdvisory findings (1)ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
Mira Review Summary
The schedule verification in src/v2Commands.ts:898 accepts schedules that retain weekday restrictions or contain unexpected model options. It should verify that cleared schedule fields and model options match the requested values exactly.
Key Issues
| Issue | Location | |
|---|---|---|
| 🔴 | Schedule verification accepts retained weekday restrictions and unexpected model options. | src/v2Commands.ts:898 |
| }; | ||
| const saved = taskOf(await scheduleRpc(api, "scheduledTasks.upsert", input), "scheduledTasks.upsert"); | ||
| const expected = savedFields(input); | ||
| const task = await verifyTask(api, saved.id, (candidate) => includes(savedFields(candidate), expected), `T3 did not list scheduled task ${saved.id} as it was saved.`); |
There was a problem hiding this comment.
Bug
Verify cleared schedule fields and model options exactly
includes only checks keys present in the expected object, so it accepts persisted settings that change the task's behavior. For example, an expected daily schedule omits weekdays, and a stored weekday-only schedule passes verification. Similarly, expected empty model options accept any stored options. The same comparison in updateSchedule reports success when --days daily fails to clear an existing weekday restriction. Normalize absent weekdays to an empty array and compare the normalized option maps exactly, while allowing unrelated server metadata.
Prompt for AI Agents
Fix scheduled-task verification in src/v2Commands.ts at line 898 and the equivalent updateSchedule check. Normalize fixed-time schedules so absent weekdays become an empty array, and compare normalized model option maps with exact key/value equality rather than recursive subset matching. Continue allowing unrelated server metadata. Add regression tests in src/v2Commands.test.ts where T3 retains weekday restrictions after --days daily and retains unexpected model options; both saves must fail verification.
Not useful? Reply
@miracodeai rejectto dismiss this suggestion.
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: 17fff48d19
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
| const npx = process.platform === "win32" ? "npx.cmd" : "npx"; | ||
| if (await commandExists(npx)) { | ||
| return { command: npx, argsPrefix: ["--yes", "t3@latest"], source: "npx", version: null }; | ||
| const spec = serverVersion ? `t3@${serverVersion}` : "t3@latest"; |
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Security: Reject non-version server selectors before invoking npx
When a user or automation points --origin at an attacker-controlled T3 endpoint and no matching local t3 command is found, the endpoint can return a serverVersion such as https://attacker/evil.tgz. This line builds t3@<serverVersion> without validating that it is a version; npm accepts URLs, aliases, Git references, and file paths as package selectors, so npx --yes installs and executes the attacker's package before authentication. Restrict this value to the exact supported semver grammar or require an explicitly trusted installation mechanism.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 17fff48d19
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (configured && configured.length > 0) { | ||
| const [command, ...argsPrefix] = configured; | ||
| if (!command) throw new CliError("INVALID_T3_COMMAND", "Configured t3Command is empty."); | ||
| return { command, argsPrefix, source: "configured", version: null }; |
There was a problem hiding this comment.
Validate the configured T3 command version
When t3Command points to a different installed T3 version—such as after the server is upgraded—this branch returns it without probing --version, even if a matching server, desktop, PATH, or npx invocation is available. withT3Api then issues the session in the wrong version's database, causing every authenticated command to fail; validate the configured invocation against serverVersion before selecting it.
AGENTS.md reference: AGENTS.md:L15-L15
Useful? React with 👍 / 👎.
| const dispatch = dryRun ? null : await api.dispatch(create.command); | ||
| return { project, created: true, command: create.command, dispatch }; | ||
| if (dryRun) return { project: planned, created: true, command, dispatch: null }; | ||
| const dispatch = await api.mutateProject(command); |
There was a problem hiding this comment.
Dispatch and verify project creation through V2
When projects ensure creates a missing project, this call bypasses orchestration.dispatchCommand and treats any successful HTTP response—even one without a project id—as success by returning the synthetic planned object without checking the projection. The analogous handover path does the same, so a dropped or unapplied mutation can be reported as created; route project.create through the V2 dispatcher and poll the project projection before returning success.
AGENTS.md reference: AGENTS.md:L18-L18
Useful? React with 👍 / 👎.
| messageCount: messages.length, | ||
| turnCount: transcript.view.totalTurns, |
There was a problem hiding this comment.
Avoid presenting bounded counts as totals
inspectThread obtains this projection through the /bounded detail endpoint, which intentionally contains only a recent message window, but these fields are displayed as the thread's total turn and message counts. Long threads therefore underreport messageCount, and migrated V1 threads without run records also underreport turnCount; use a full read or expose these values as bounded-window counts instead.
Useful? React with 👍 / 👎.
Ports the CLI to T3 Code's orchestrator V2 and releases it as 0.3.0.
0.3 works only with T3 Code builds that include orchestrator V2. That means nightly
0.0.46-nightly.20261003.2610or later. Stable T3 Code v0.0.45 and earlier run orchestrator V1 and need@bvdm/t3code-cli@0.2. 0.3 checks the server's protocol before it signs in and refuses anything other than protocol 2 withT3_PROTOCOL_UNSUPPORTED. The README, the npm description,--help, and both shipped skills say so.Changes
t3command whose version matches the server. The bundledt3package is gone.orchestration.launchThreadcall, gain--wait, and record the checkout's branch on the thread.threads send --if-busy refuse|queue|steer|restart, provider switching through T3's handoff, and new commands: fork, merge-back, queue, search, pin, snooze, archive, rename, andschedules.Breaking changes for scripts that read the JSON output are listed under "Upgrading from 0.2" in the README.
Testing
pnpm checkpasses on Windows: 249 tests, with 2 Linux-only tests skipped. CI runs both on Ubuntu with Node 22 and 24.