Skip to content

[Feature]: Provider-agnostic orchestration ("ultracode for every model") — a fork-owned MCP toolkit that lets any adapter fan out into real T3 threads #43

Description

@radroid

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I am describing a concrete problem or use case, not just a vague idea.

Area

apps/server

Problem or use case

What "ultracode" is, for a reader who has never used it

"Ultracode" is shorthand for a cluster of behaviours people expect from a high-effort coding agent, none of which are a single feature:

  • Parallel fan-out. The agent decomposes a task and runs several workers at once (explore three call sites, write tests while another writes the implementation) instead of doing everything serially in one context.
  • Structured output. Workers return machine-readable results (a verdict, a file list, a JSON summary) rather than prose the parent has to re-read and re-parse.
  • Adversarial verification. A second agent is asked to break the first one's work — find the bug, find the missing test — rather than to agree with it.
  • Judge panels / best-of-N. The same task is attempted N ways and a separate adjudicator picks a winner or merges the outputs.
  • Loop-until-dry. The agent keeps iterating (fix → run tests → fix) until a stopping condition is met, rather than stopping after one pass.

What T3 Code actually has today

In this repo, ultracode is only a Claude effort level, not any of the above. It is a dropdown value that normalises to --effort xhigh plus a settings.ultracode: true flag handed to the Claude Agent SDK:

  • apps/server/src/provider/Layers/ClaudeProvider.ts:75 (and :106, :142) — { value: "ultracode", label: "Ultracode" }, listed only for Claude models
  • apps/server/src/provider/Layers/ClaudeProvider.ts:406if (effort === "ultracode") { return "xhigh"; }
  • apps/server/src/provider/Layers/ClaudeAdapter.ts:3510 / :3521const ultracode = isClaudeUltracodeEffort(effort)...(ultracode ? { ultracode: true } : {})

So every one of the five ultracode behaviours, when it happens at all, happens inside the Claude CLI process, where T3 cannot inspect, interrupt, checkpoint, or steer it. That is the direct cause of "ultracode does not always work well in T3 Code": T3 renders provider-internal fan-out as flat, opaque rows.

  • Subagent activity is a display heuristic, not a model: tool names containing agent/task/subagent get bucketed into the canonical item type collab_agent_tool_call, titled "Subagent task" (ClaudeAdapter.ts:596, :865). The same heuristic exists in OpenCodeAdapter.ts and CodexAdapter.ts and is absent from CursorAdapter.ts and GrokAdapter.ts.
  • task.started / task.progress / task.completed exist in the canonical union (packages/contracts/src/providerRuntime.ts:177) and are ingested (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts), but only ClaudeAdapter.ts ever emits them — verified: grep -rl 'task\.started' apps/server/src packages/contracts/src returns only ClaudeAdapter.ts, ProviderRuntimeIngestion.ts, and the contracts file. They are read-only telemetry about work T3 does not own.

Why this cannot be fixed inside the adapters

ProviderAdapterCapabilities has exactly one field, and all five adapters set it to the same value — the declarative capability surface differentiates nothing today:

// apps/server/src/provider/Services/ProviderAdapter.ts:28
export interface ProviderAdapterCapabilities {
  readonly sessionModelSwitch: ProviderSessionModelSwitchMode;
}

ClaudeAdapter.ts:3934, CodexAdapter.ts:1705, CursorAdapter.ts:1167, GrokAdapter.ts:1449, OpenCodeAdapter.ts:1703 — all sessionModelSwitch: "in-session".

There is no spawn/subagent primitive anywhere in ProviderAdapterShape, and there is no parent/child thread concept in T3's own domain: grep -rn parentThreadId apps/server/src packages/contracts/src returns nothing (the identifier exists only in the vendored Codex app-server generated schema). OrchestrationThread (packages/contracts/src/orchestration.ts:352) has no parent field.

Building fan-out inside adapters would mean five implementations against five unrelated protocols (Claude Agent SDK, Codex app-server JSON-RPC, ACP ×2, OpenCode HTTP), and two of them (Cursor, Grok) have no subagent concept at all. The repo already documents what happens when capability is under-declared: the web app hardcodes a per-driver allowlist because there is no flag to read —

// apps/web/src/outbox/composerSteering.logic.ts:13
 * The catch is that there is no steering capability flag anywhere in the
 * contracts, so support is implicit per adapter and has to be asserted here.
// :43
const STEERABLE_PROVIDER_DRIVER_KINDS: ReadonlySet<string> = new Set([...]);

Proposed solution

Shape: one orchestrator thread + N child threads, driven entirely above the adapter layer

The orchestrator is an ordinary T3 thread on any provider. Its children are ordinary T3 threads. The only new machinery is a fork-owned MCP toolkit the model calls, plus a fork-owned store that tracks runs. Nothing touches ProviderAdapterShape, and no provider-native subagent feature is used or required.

Why this is provider-agnostic for free

Every one of the five adapters already mounts a T3-hosted MCP server into its provider session, with a per-thread bearer credential issued by T3:

  • apps/server/src/provider/Layers/ClaudeAdapter.ts:3523
  • apps/server/src/provider/Layers/CursorAdapter.ts:534
  • apps/server/src/provider/Layers/CodexAdapter.ts:1397
  • apps/server/src/provider/Layers/GrokAdapter.ts:572
  • apps/server/src/provider/Layers/OpenCodeAdapter.ts:1217

all calling McpProviderSession.readMcpProviderSession(input.threadId). The invocation scope carries the calling thread's id, so a tool handler natively knows who the parent is:

// apps/server/src/mcp/McpInvocationContext.ts:12
export interface McpInvocationScope {
  readonly environmentId: EnvironmentId;
  readonly threadId: ThreadId;
  readonly providerSessionId: string;
  readonly providerInstanceId: ProviderInstanceId;
  readonly capabilities: ReadonlySet<McpCapability>;
  readonly issuedAt: number;
}

Adding tools here means every provider gets them on the same day, with zero adapter edits.

New files (all fork-owned, zero upstream conflict)

apps/server/src/t3x/orchestrate/
  tools.ts        # Effect Tool.make definitions — copy apps/server/src/mcp/toolkits/preview/tools.ts
  handlers.ts     # copy apps/server/src/mcp/toolkits/preview/handlers.ts
  RunStore.ts     # JSON persistence in stateDir, modelled on t3x-auto-resume.json
  Runner.ts       # dispatches thread.create + thread.turn.start, watches for completion
  index.ts        # exports OrchestrateToolkitRegistrationLive + OrchestrateLayerLive
apps/server/src/t3x/mcp/index.ts   # single aggregator for all future fork MCP toolkits

apps/server/src/mcp/toolkits/preview/ is a complete, shipping template (tools.ts, handlers.ts, plus tests for both) — it is currently the only toolkit (ls apps/server/src/mcp/toolkitspreview).

The three tools (v1)

Tool Behaviour
subagent_spawn Takes { tasks: [{ label, prompt, providerInstanceId?, modelId?, runtimeMode? }] }, max 4. Creates one child thread per task, dispatches thread.turn.start with only the task prompt (no parent history), returns { runId, children: [{ childThreadId, label }] } immediately. Never blocks.
subagent_status { runId } → per-child { label, childThreadId, phase } where phase comes from projectThreadAwareness. Cheap to poll.
subagent_result { runId } or { childThreadId } → final assistant message text for each completed child, plus its phase.

Async-return + poll is deliberate: an MCP handler that blocks for minutes holds the parent's tool call open against adapter and CLI tool timeouts. Polling burns orchestrator turns but cannot deadlock.

Dispatch: reuse the proven fork precedent verbatim

AutoResumeReactor is already a server-side autonomous dispatcher that synthesises turns indistinguishable from a keystroke:

// apps/server/src/t3x/autoResume/Reactor.ts:111
commandId: CommandId.make(`t3x-auto-resume:${commandUuid}`),

and it already writes its own audit trail with thread.activity.append (Reactor.ts:75; command declared at packages/contracts/src/orchestration.ts:865).

The orchestrator does the same: engine.dispatch({ type: "thread.create", ... }) then engine.dispatch({ type: "thread.turn.start", ... }) with commandId prefixed t3x-orchestrate:, and appends a breadcrumb to the parent thread for every spawn, phase change, and result read. That trail is provider-agnostic and shows up on Cursor/Grok/OpenCode identically — which is exactly why the design must not build on task.* (Claude-only, ClaudeAdapter.ts is the sole emitter).

Completion detection: already solved, do not reinvent

// packages/shared/src/agentAwareness.ts:53
export function projectThreadAwareness(...)
// :77
function resolveThreadAwarenessPhase(thread): AgentAwarenessPhase | null

This reads only shell-projection fields — never provider internals — and is already consumed server-side by the fork's Web Push seam (apps/server/src/t3x/webPush/attention.ts). It returns waiting_for_approval / completed / null, which is precisely the "is this child done, stuck on an approval, or still working" distinction the orchestrator needs.

Do not gate on session.status alone. The existing code documents settled/teardown races, and fork issue #38 records the hazard that synthetic turns deadlock status-gated logic.

Result collection

OrchestrationLatestTurn (packages/contracts/src/orchestration.ts:335) carries assistantMessageId: Schema.NullOr(MessageId) at :341, and ProjectionSnapshotQuery.getThreadDetailById (apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts:168) returns the full thread including messages. subagent_result is a projection read, not a provider call.

Registration seam (the only upstream edit)

The MCP server builds its toolkit layer in apps/server/src/mcp/McpHttpServer.ts:206-225:

const PreviewStandardToolkitRegistrationLive = McpServer.toolkit(PreviewStandardToolkit).pipe(
  Layer.provide(PreviewStandardToolkitHandlersLive),
);
export const PreviewToolkitRegistrationLive = Layer.mergeAll(...);
export const layer = PreviewToolkitRegistrationLive.pipe(Layer.provideMerge(McpTransportLive));

Add one merged layer sourced from apps/server/src/t3x/mcp/index.ts — the same aggregator discipline apps/server/src/t3x/index.ts:71/:100 already enforces for T3xLayerLive / T3xRoutesLive. Every future fork toolkit then costs zero additional upstream churn.

Deliberately avoid the capability gate in v1. McpCapability is a closed union with one member (apps/server/src/mcp/McpInvocationContext.ts:10 — export type McpCapability = "preview";) and it is issued from a hardcoded set (apps/server/src/mcp/McpSessionRegistry.ts:131 — capabilities: new Set(["preview"])). Extending both would add two more ledger rows for no v1 benefit. Gate the toolkit on a fork-local setting inside handlers.ts instead, and revisit if v2 needs per-thread scoping.

What degrades, per adapter, and how

Because the design uses no provider-native subagent feature, the capability does not degrade — the presentation and reliability do:

Concern Claude Codex OpenCode Cursor Grok
Can call the tools (MCP mounted) yes yes yes yes yes
Spawn tool call renders as "Subagent task" yes (ClaudeAdapter.ts:596) yes yes no — generic tool row no — generic tool row
Native task.* telemetry yes no no no no
Structured judge verdicts native --json-schema native --output-schema prompt-instructed prompt-instructed prompt-instructed
Steering the orchestrator mid-run yes no (excluded from STEERABLE_PROVIDER_DRIVER_KINDS) yes yes yes

Mitigations: emit the fan-out trail via thread.activity.append so it is legible everywhere (not task.*); accept prose results in v1 and defer structured verdicts; document that Codex orchestrators cannot be steered mid-run.

Fan-out cap and why it is low

Session startup is serialized. ensureSessionForThread (ProviderCommandReactor.ts:684) runs inside buildSendTurnRequestForThread, which runs inside a single-item-at-a-time DrainableWorker (ProviderCommandReactor.ts:1323). Spawning N children means N sequential CLI process spawns before any of them runs. The turn itself is forked (ProviderCommandReactor.ts:1117-1119 — .pipe(Effect.catchCause(recoverTurnStartFailure), Effect.forkScoped)), so once started they do run concurrently. Cap v1 at 4 and make the cap a fork-local constant.

Separately, ProviderSessionReaper.ts:17 sets DEFAULT_INACTIVITY_THRESHOLD_MS = 30 * 60 * 1000 — a parked child session is reaped after 30 minutes, invisibly to a polling orchestrator. subagent_status must report a reaped child as a distinct phase, not silently as "still working".

Restart durability

RunStore.ts persists { runId, parentThreadId, children: [{ childThreadId, label, phase }] } to stateDir, mirroring t3x-auto-resume.json. On boot, reconcile every non-terminal run against getThreadDetailById. Without this a server restart orphans every child thread with no trace.

Why this matters

Today "high-effort agent" in T3 Code means one Claude-only dropdown value that changes a flag on one provider's CLI, and whatever fan-out happens is invisible and unsteerable because it lives inside that CLI's process. This inverts that: each unit of parallel work becomes a first-class T3 thread, which means it inherits everything T3 already built — the activity timeline, approvals, checkpoints, per-turn diffs, interrupt, Web Push, auto-resume, mobile — with no per-feature work.

It is genuinely model-agnostic rather than nominally so: the orchestrator can be a Grok thread spawning Codex children, because the only interface it touches is OrchestrationEngineService.dispatch. That is a capability no single provider gives you, and it is the one thing a wrapper app is uniquely positioned to build.

It also removes a class of "why did nothing happen" confusion: a stalled child shows up as a thread with a phase and an approval card, not as a silent gap inside another process.

Smallest useful scope

v1 = async spawn + poll + collect, on shared cwd, no UI.

Ships:

  • apps/server/src/t3x/orchestrate/ with subagent_spawn, subagent_status, subagent_result
  • one aggregator seam line in apps/server/src/mcp/McpHttpServer.ts via apps/server/src/t3x/mcp/index.ts
  • fan-out cap 4, fork-local constant
  • RunStore JSON persistence + boot reconciliation
  • thread.activity.append breadcrumbs on the parent for spawn / phase-change / result
  • completion via projectThreadAwareness, results via getThreadDetailById + latestTurn.assistantMessageId
  • tests mirroring apps/server/src/mcp/toolkits/preview/{tools,handlers}.test.ts

Explicitly out of scope for v1 (each is a follow-up issue):

  • Git worktrees per child. This is the big one. Worktree bootstrap is not in the engine — it is implemented inline in the WebSocket transport (apps/server/src/ws.ts:750 dispatchBootstrapTurnStart, :891 thread.create, :908 gitWorkflow.createWorktree, :940 runSetupProgram()). A server-side dispatcher calling engine.dispatch directly gets none of it. ws.ts measured churn is 41 commits in the 60 days before merge-base 64bf01619 — the highest of any candidate file. So v1 children share the parent's cwd, which makes it safe for read-heavy fan-out (parallel investigation, review, test authoring in disjoint directories) and unsafe for parallel edits to the same files. State that limit in the tool description so the model does not attempt it.
  • Judge panels / best-of-N adjudication. Needs structured verdicts; see alternatives.
  • UI grouping. With no parent link in OrchestrationThreadShell, 4 children land flat in the shell snapshot and each completion fires the needs-attention / Web Push coordinator.
  • Extending ProviderAdapterCapabilities.
  • Generic structured output in TextGenerationService.

Alternatives considered

1. Wait for upstream orchestrator-v2. PR pingdotgg#3638 already merged delegate_task / task_status / task_cancel / create_threads / t3_thread_* as orchestrator MCP tools — but into the stack branch t3code/codex-turn-mapping, not main. Its gate, pingdotgg#2829, is still open against main. Verified: merge commit dac514e6b is not an ancestor of upstream/main, origin/main, or fork HEAD. This is the strongest alternative and the honest reason to keep v1 tiny — the whole toolkit is three tools in fork-owned files and is cheap to delete when v2 lands. Naming should deliberately not collide with delegate_task/task_status so both can coexist during a transition.

2. Cherry-pick the v2 toolkit onto today's main. git show dac514e6b:apps/server/src/mcp/toolkits/orchestrator/tools.ts is real, reviewed code. But it targets the v2 orchestrator's data model, so porting it means porting or stubbing that model — a much larger change than three fork-local tools, and it creates the "parallel paths" hazard the fork has already been bitten by (a fork path that duplicates an upstream capability silently bypasses new upstream guards).

3. A declarative t3x reactor instead of model-callable tools. Model AutoResumeReactor directly: a server-side supervisor that runs a user-configured plan (stages, providers, prompts) without the model deciding anything. Better for deterministic verification pipelines and judge panels; worse for the "ultracode" experience the user asked for, where the model authors its own fan-out. They share ~80% of the machinery (RunStore, Runner, awareness polling) so (a) can be added on top of (b) later. Picking the MCP toolkit first is the choice that matches the request.

4. createSdkMcpServer from the Claude Agent SDK. Exported and typed but unused anywhere in the repo. Strictly worse here: Claude-only, requires a ClaudeAdapter.ts edit (churn 12), and defeats the entire point of the issue.

5. Extend TextGenerationService with a generic generateStructured(schema, prompt) for judge verdicts. The interface is closed at four git-flavoured operations (apps/server/src/textGeneration/TextGeneration.ts:77-82), so this means five implementations, and only Claude and Codex get a hard schema constraint — Cursor/Grok/OpenCode scrape prompt-instructed JSON with extractJsonObject. Cheaper: run the judge as its own child thread and parse its final assistant message with the same lenient extractor those three adapters already use. Loses per-call model/effort control.

6. Do nothing and document that ultracode is Claude-only. Legitimate. The counter is that ultracode's value is mostly the orchestration pattern, not the effort flag, and that pattern is provider-independent.

Risks or tradeoffs

Seam cost (measured against merge-base 64bf01619, 60-day window)

docs/t3x/SEAMS.md:5 records 34 upstream-owned files, +1616 / -187 lines, and :21 carries an explicit tripwire: "Before adding row 35, re-isolate something instead." This feature adds one row.

File Edit Lines Churn Risk
apps/server/src/mcp/McpHttpServer.ts one merged layer sourced from t3x/mcp/index.ts ~3 6 ~18

Measured with git log --oneline --since="@$((MBTS-60*86400))" 64bf01619 -- <path>. For contrast, the paths this design deliberately avoids: apps/server/src/ws.ts = 41, apps/server/src/server.ts = 29, packages/contracts/src/orchestration.ts = 12, apps/server/src/provider/Layers/ClaudeAdapter.ts = 12, apps/web/src/components/ChatView.tsx = 63 (already the fork's worst row at risk 11466, SEAMS.md:41). Fork-owned apps/server/src/t3x/ has churn 0.

Rejected-but-tempting rows and their cost: McpSessionRegistry.ts (churn 7) + McpInvocationContext.ts (churn 3) for a capability gate — two rows for a v1 that has no per-thread scoping requirement. ProviderAdapter.ts has churn 0 and is cheap in isolation, but extending it forces edits to all five adapters (ClaudeAdapter.ts churn 12 among them).

The ledger must be updated in the same commit — header totals plus the new row — per the self-reference rule at SEAMS.md:22-28, and the t3x/mcp/index.ts aggregator should be documented there as the reason no further MCP rows will follow.

Parallel-paths hazard

This is the fork's known failure mode: a fork path that duplicates an upstream capability silently bypasses new upstream guards. Upstream is actively building the same thing (pingdotgg#3138, pingdotgg#4649, PRs pingdotgg#4663 / pingdotgg#5219 / pingdotgg#3638). Concretely: use distinct tool names from delegate_task/task_status, keep the entire implementation deletable in one rm -rf apps/server/src/t3x/orchestrate/, and re-check the SEAMS table every sync.

Machine and cost risks

  • Fan-out thrashes a 16GB Mac. Each child is a full provider CLI process, and startup is serialized through the DrainableWorker. Cap 4, and expect the first child to start well before the fourth.
  • No budget ceiling exists. Nothing in T3 bounds a run's token spend. A model that spawns 4 children, polls, and re-spawns can burn a lot unattended. v1 should hard-cap total spawns per parent thread.
  • The 30-minute idle reaper (ProviderSessionReaper.ts:17) silently kills parked children.

UNVERIFIED — do not present these as settled

  1. Do Cursor and Grok's ACP clients actually expose T3's MCP tools to the model? The mcpServers wiring is verified present (CursorAdapter.ts:544, GrokAdapter.ts:582), but nobody has confirmed the tool reaches the model's tool list on those providers. Experiment: start a thread on each of the five providers and ask the model to call mcp__t3-code__preview_status; a tool result on all five proves the channel end-to-end before any orchestration code is written. Do this first — it is the load-bearing assumption of the whole design.
  2. Does a child thread created via engine.dispatch({type:"thread.create"}) without the ws.ts bootstrap path actually start a working session? All existing evidence is that AutoResumeReactor dispatches thread.turn.start to threads that already exist. Experiment: dispatch thread.create then thread.turn.start from a scratch Effect script and confirm turn.completed.
  3. Whether the reaper's 30-minute teardown produces a distinguishable phase from projectThreadAwareness, or looks identical to "completed". Experiment: let a thread idle past 30 minutes and diff the projected phase.
  4. What settings.ultracode: true actually does inside the Claude binary. This repo only sets the flag (ClaudeAdapter.ts:3521); the semantics are undocumented here. The claim "ultracode means parallel fan-out" is inferred from observed behaviour, not from this codebase. Experiment: strings the bundled Claude platform binary for ultracode and read the surrounding tool-registry code.
  5. Whether 4 concurrent children is survivable on this machine. Nobody has measured it.

Examples or references

Upstream issues this overlaps (this is NOT a clean-slate feature)

File:line evidence (all verified in this checkout at main)

  • Capabilities: apps/server/src/provider/Services/ProviderAdapter.ts:26-32; identical values at ClaudeAdapter.ts:3934, CodexAdapter.ts:1705, CursorAdapter.ts:1167, GrokAdapter.ts:1449, OpenCodeAdapter.ts:1703
  • Five drivers: apps/server/src/provider/builtInDrivers.ts:47
  • MCP mounted by every adapter: ClaudeAdapter.ts:3523, CursorAdapter.ts:534, CodexAdapter.ts:1397, GrokAdapter.ts:572, OpenCodeAdapter.ts:1217
  • MCP scope carries parent threadId: apps/server/src/mcp/McpInvocationContext.ts:10-19; issuance apps/server/src/mcp/McpSessionRegistry.ts:131
  • Toolkit registration point: apps/server/src/mcp/McpHttpServer.ts:206-225; only toolkit today: apps/server/src/mcp/toolkits/preview/ (tools.ts, handlers.ts, tools.test.ts, handlers.test.ts)
  • Fork aggregators: apps/server/src/t3x/index.ts:71 (T3xLayerLive), :100 (T3xRoutesLive); existing seams autoResume/, webPush/
  • Autonomous dispatch precedent: apps/server/src/t3x/autoResume/Reactor.ts:75 (thread.activity.append), :111 (commandId)
  • Bootstrap trapped in the transport: apps/server/src/ws.ts:750, :891, :908, :940, :961
  • Serialized startup / forked turn: apps/server/src/orchestration/Layers/ProviderCommandReactor.ts:684, :1117-1119, :1323
  • Idle reaper: apps/server/src/provider/Layers/ProviderSessionReaper.ts:17
  • Completion phase: packages/shared/src/agentAwareness.ts:53, :77
  • Result addressing: packages/contracts/src/orchestration.ts:335, :341; apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts:168
  • Bootstrap schema (unused by engine): packages/contracts/src/orchestration.ts:677, :701, :720
  • thread.activity.append command: packages/contracts/src/orchestration.ts:865
  • Ultracode today: ClaudeProvider.ts:75, :406, :425; ClaudeAdapter.ts:3510, :3521
  • Closed structured-output interface: apps/server/src/textGeneration/TextGeneration.ts:77-82
  • Steering allowlist precedent: apps/web/src/outbox/composerSteering.logic.ts:13, :43, :51
  • Seam ledger: docs/t3x/SEAMS.md:5, :21, :22-28, :41

Duplicate search performed before filing

Searched all 1,615 upstream pingdotgg/t3code issues (open + closed — count confirmed against gh api search/issues total_count) by dumping the full title corpus locally and grepping ~80 term variants, plus body-level gh search issues per concept (orchestration, delegation, subagent, parallel agents, swarm, judge, voting, best of n, consensus, agent team, teammate, ultracode, fan-out, pipeline, workflow), plus a gh search prs sweep. Also searched all 21 radroid/t3code fork issues. Upstream Discussions are disabled (hasDiscussionsEnabled: false), so issues and PRs are the complete surface.

Result: this is not a duplicate, but it is a strong overlap and the body says so explicitly.

Found and cross-referenced above: pingdotgg#3138 (Orchestration/Delegation — closest, owns the goal statement), pingdotgg#4649 (configurable pipelines — owns the staged-workflow half), pingdotgg#5218 / pingdotgg#4456 / pingdotgg#1740 / pingdotgg#538 / pingdotgg#2921 (subagent UI, nested threads, CLI orchestration — all the presentation half this issue defers), and in-flight PRs pingdotgg#4663, pingdotgg#5219.

Most decisive finding: PR pingdotgg#3638 is MERGED — but into the stack branch t3code/codex-turn-mapping, gated behind still-open pingdotgg#2829. Verified git merge-base --is-ancestor dac514e6b upstream/main → NOT an ancestor of upstream/main, origin/main, or fork HEAD, and no scheduled_tasks/orchestrator toolkit files are tracked in this checkout (ls apps/server/src/mcp/toolkitspreview only). So the capability exists upstream on a branch but is not reachable from main today, which is the justification for filing this on the fork rather than upstream.

Zero hits in either repo for judge panels, best-of-N, adjudication, voting, consensus, or swarm — that slice is genuinely unclaimed, and is called out as a deferred follow-up rather than folded into v1.

No fork issue duplicates this. The only adjacent fork issue is #38 (Loop Watch), which is about supervising a single long-running thread and explicitly rules cron out of scope; it is referenced for its session.status hazard note, not as an overlap.

Contribution

  • I would be open to helping implement this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions