feat(agents): surface managed Codex agent runs - #6416

Closed
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar
Closed

feat(agents): surface managed Codex agent runs#6416
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar

Conversation

@Juliusicon

@JuliusiconJuliusicon commented Aug 13, 2026

Copy link
Copy Markdown

What changed

Adds first-class visibility and lifecycle ownership for Codex agents in T3 Code. Native Codex subagents retain parent/child hierarchy, model, effort, and late-arriving metadata. T3-managed codex exec runs use typed RPC contracts, stable IDs, lifecycle events, exact process-tree cancellation, and sidebar controls.

Why

Raw nested CLI agents were invisible to T3 and could survive supervisor cancellation. Native lifecycle rows also lost hierarchy or metadata under retention and out-of-order event delivery.

Impact

Users can see native and T3-managed Codex agents in the Agents panel, including nested ownership and terminal state. Only T3-managed CLI runs are surfaced; arbitrary external processes are intentionally not discovered by process scanning.

Checks

  • Focused unit/replay tests: 80/80
  • Runtime integration tests: 3/3
  • Server and client-runtime typechecks
  • Targeted lint and formatting
  • git diff --check
  • Final adversarial GPT-5.6 Terra review: PASS

Built with GPT-5.6 Sol through the Codex harness; reviewed with GPT-5.6 Terra.


Note

Medium Risk
Spawns child processes with user prompts and operate-scoped RPC; changes are well-tested but touch orchestration ingestion, Codex event mapping, and cancellation ownership.

Overview
Adds T3-owned codex exec runs with WebSocket RPC (launchManagedCodexExec, cancelManagedAgent), a ManagedCodexExec service that spawns processes and pushes lifecycle events through ingestRuntimeEvent, and operate-scope auth. Launch errors redact prompts from wire payloads.

Improves native Codex collab agents by correlating spawnAgent tool calls to model/effort/parent, emitting collabAgent/metadata for late identity patches, and upserting task-identity:* activities so terminal rows keep hierarchy without reopening. Payloads gain agentSource and cancellationOwner.

Updates the Agents UI and client model with childrenByParentId, nested tree rendering, and a stop control when cancellationOwner === 't3'.

Reviewed by Cursor Bugbot for commit e1f841c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Surface managed Codex agent runs with launch, cancel, and hierarchical UI

  • Adds ManagedCodexExec service that spawns codex exec as a child process, streams stdout/stderr as task.progress events, and emits task.started/task.completed with rich status and summaries.
  • Exposes launchManagedCodexExec and cancelManagedAgent WebSocket RPC endpoints (with orchestration scope authorization) and wires client-side command atoms in createOrchestrationEnvironmentAtoms.
  • Extends the Codex provider adapter to emit collabAgent/metadata events carrying enriched child agent identity (model, effort, parentAgentId), correlated to the originating turn/item.
  • Adds agentSource and cancellationOwner fields to RuntimeSubagent and TaskAgentLinkage, and builds childrenByParentId in AgentPanelModel for non-workflow parent-child relationships.
  • Renders agents as an indented hierarchy in AgentsPanel and shows a stop button for managed agents in active states, dispatching cancelManagedAgent on click.
  • Risk: cancellation relies on SIGTERM with a 3-second force-kill; processes that ignore SIGTERM will be hard-killed after the timeout with no further retry.

Macroscope summarized e1f841c.

@coderabbitai

coderabbitaiBot commented Aug 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c22faf77-495f-493a-b8a5-de4f794f7636

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 13, 2026
Comment on lines 772 to +785
@@ -751,6 +779,10 @@ export function deriveAgentPanelModel({
const list = members.get(agent.parentAgentId) ?? [];
list.push(agent);
members.set(agent.parentAgentId, list);
} else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {
const list = childrenByParentId.get(agent.parentAgentId) ?? [];
list.push(agent);
childrenByParentId.set(agent.parentAgentId, list);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumstate/subagentRuntime.ts:772

Cyclic parent relationships are omitted from directAgents without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The childrenByParentId branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

 const agentIds = new Set(source.map((agent) => agent.id));
+ const parentById = new Map(source.map((agent) => [agent.id, agent.parentAgentId] as const));
for (const agent of source) {
@@
- } else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {+ } else if (+ agent.parentAgentId !== null &&+ agentIds.has(agent.parentAgentId) &&+ !(() => {+ const seen = new Set<string>();+ let current: string | null = agent.id;+ while (current !== null && agentIds.has(current)) {+ if (seen.has(current)) return true;+ seen.add(current);+ current = parentById.get(current) ?? null;+ }+ return false;+ })()+ ) {
🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/client-runtime/src/state/subagentRuntime.ts around lines 772-785:
Cyclic parent relationships are omitted from `directAgents` without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The `childrenByParentId` branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

collabSpawnMetadata.set(childThreadId, metadata);
}
yield* Ref.set(collabSpawnMetadataRef, collabSpawnMetadata);
const enrichedChildren =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MediumLayers/CodexSessionRuntime.ts:1314

Late spawnAgent metadata for a child-scoped item/started or item/completed notification never reaches ingestion or replay. interceptCollabChildNotification returns at line 1343 before the collabAgent/metadata loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/CodexSessionRuntime.ts around line 1314:
Late `spawnAgent` metadata for a child-scoped `item/started` or `item/completed` notification never reaches ingestion or replay. `interceptCollabChildNotification` returns at line 1343 before the `collabAgent/metadata` loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

const cyclic = ancestors.has(agent.id);
const nextAncestors = new Set(ancestors).add(agent.id);
return (
<div style={{ paddingLeft: `${Math.min(depth, 6) * 12}px` }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/AgentsPanel.tsx:230

Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded <div> while this line applies 12px * depth again, use a constant per-level padding for nested wrappers.

Suggested change
<divstyle={{paddingLeft: `${Math.min(depth,6)*12}px`}}>
<divstyle={{paddingLeft: depth>0 ? "12px" : "0px"}}>
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/AgentsPanel.tsx around line 230:
Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded `<div>` while this line applies `12px * depth` again, use a constant per-level padding for nested wrappers.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the new ManagedCodexExec service and its contract error. Findings are limited to the service definition shape, construction/layer exports, dependency acquisition, and error modeling.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadpackages/contracts/src/orchestration.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 865817f. Configure here.

Comment threadapps/server/src/provider/Layers/CodexSessionRuntime.ts
@macroscopeapp

macroscopeappBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

4 blocking correctness issues found. This PR introduces a substantial new feature for managed Codex agent runs, including process spawning/cancellation, new RPC endpoints, and UI agent tree management with cancel actions. New capability of this scope warrants human review to validate the feature design and cross-system integration.

You can customize Macroscope's approvability policy. Learn more.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One convention finding: ManagedAgentRunError now carries good structural attributes, but every wrapping site discards the underlying failure entirely, so no cause survives. Details inline.

Posted via Macroscope — Effect Service Conventions

Comment on lines +67 to +69
reason: Schema.Literals(["thread-not-found", "spawn-failed", "run-not-found", "not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManagedAgentRunError has no cause, and every wrapping site in ManagedCodexExec.ts (getThreadDetailById, getProjectShellById, randomUUIDv4, spawner.spawn, child.kill) maps with () => new ManagedAgentRunError({...}), so the immediate platform/spawn failure and its stack are dropped with no diagnostic left anywhere. Convention here is to keep the structural fields and preserve the real failure as cause (as sibling contract errors such as VcsProcessSpawnError and GitCommandError do).

Suggest adding an optional cause and passing the underlying error at each mapError:

Suggested change
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
cause: Schema.optional(Schema.Defect()),

If the redaction guarantee asserted in ManagedCodexExec.test.ts means the encoded wire payload must stay free of the spawn command, keep the cause server-side instead (e.g. Effect.tapCause(Effect.logError) before the mapError) rather than discarding it.

Posted via Macroscope — Effect Service Conventions

Effect.mapError(
(cause) =>
new ManagedCodexExecInternalError({
reason: "not-owned",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumorchestration/ManagedCodexExec.ts:330

A failure from run.child.kill(...) is reported as not-owned even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through toManagedAgentRunError as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/ManagedCodexExec.ts around line 330:
A failure from `run.child.kill(...)` is reported as `not-owned` even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through `toManagedAgentRunError` as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new/changed Effect service code (ManagedCodexExec.ts, Services/ProviderRuntimeIngestion.ts, ws.ts wiring, contracts). Service definition (inline Context.Service interface, make then layer), environment-based dependency acquisition (ProviderRuntimeIngestionService, ProjectionSnapshotQuery, ChildProcessSpawner), namespace imports, and cause preservation all match the conventions now. One error-modeling issue remains: the reason discriminator does not identify the failing stage.

Posted via Macroscope — Effect Service Conventions

export class ManagedCodexExecInternalError extends Schema.TaggedErrorClass<ManagedCodexExecInternalError>()(
"ManagedCodexExecInternalError",
{
reason: Schema.Literals(["thread-not-found", "spawn-failed", "not-owned"]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reason is this error's stage/operation discriminator and it also becomes the caller-visible ManagedAgentRunError.reason (via toManagedAgentRunError), but four structurally different failures are folded into reasons that describe something else:

  • projection query failure (lines 127, 144) -> thread-not-found, indistinguishable from the genuine missing-thread branches (lines 135, 152)
  • crypto.randomUUIDv4 failure (line 162) -> spawn-failed
  • task.started ingest failure (line 238) -> spawn-failed
  • child.kill() failure (line 330) -> not-owned, so a run that is owned but could not be killed surfaces as Managed agent run failed (not-owned)

Since the message and client behavior are derived from reason, suggest giving each wrapping site a stage-accurate literal (e.g. thread-lookup-failed, agent-id-failed, ingest-failed, cancel-failed) and extending/mapping ManagedAgentRunError.reason in packages/contracts/src/orchestration.ts accordingly, so the caller-visible reason matches the failure that actually occurred.

Posted via Macroscope — Effect Service Conventions

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

This adds managed Codex agent runs across server orchestration, contracts, and the Agents panel. We are not taking this separate managed-agent workflow forward through the current backlog.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Juliusicon@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(agents): surface managed Codex agent runs - #6416

Closed
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar
Closed

feat(agents): surface managed Codex agent runs#6416
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar

Conversation

@Juliusicon

@JuliusiconJuliusicon commented Aug 13, 2026

Copy link
Copy Markdown

What changed

Adds first-class visibility and lifecycle ownership for Codex agents in T3 Code. Native Codex subagents retain parent/child hierarchy, model, effort, and late-arriving metadata. T3-managed codex exec runs use typed RPC contracts, stable IDs, lifecycle events, exact process-tree cancellation, and sidebar controls.

Why

Raw nested CLI agents were invisible to T3 and could survive supervisor cancellation. Native lifecycle rows also lost hierarchy or metadata under retention and out-of-order event delivery.

Impact

Users can see native and T3-managed Codex agents in the Agents panel, including nested ownership and terminal state. Only T3-managed CLI runs are surfaced; arbitrary external processes are intentionally not discovered by process scanning.

Checks

  • Focused unit/replay tests: 80/80
  • Runtime integration tests: 3/3
  • Server and client-runtime typechecks
  • Targeted lint and formatting
  • git diff --check
  • Final adversarial GPT-5.6 Terra review: PASS

Built with GPT-5.6 Sol through the Codex harness; reviewed with GPT-5.6 Terra.


Note

Medium Risk
Spawns child processes with user prompts and operate-scoped RPC; changes are well-tested but touch orchestration ingestion, Codex event mapping, and cancellation ownership.

Overview
Adds T3-owned codex exec runs with WebSocket RPC (launchManagedCodexExec, cancelManagedAgent), a ManagedCodexExec service that spawns processes and pushes lifecycle events through ingestRuntimeEvent, and operate-scope auth. Launch errors redact prompts from wire payloads.

Improves native Codex collab agents by correlating spawnAgent tool calls to model/effort/parent, emitting collabAgent/metadata for late identity patches, and upserting task-identity:* activities so terminal rows keep hierarchy without reopening. Payloads gain agentSource and cancellationOwner.

Updates the Agents UI and client model with childrenByParentId, nested tree rendering, and a stop control when cancellationOwner === 't3'.

Reviewed by Cursor Bugbot for commit e1f841c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Surface managed Codex agent runs with launch, cancel, and hierarchical UI

  • Adds ManagedCodexExec service that spawns codex exec as a child process, streams stdout/stderr as task.progress events, and emits task.started/task.completed with rich status and summaries.
  • Exposes launchManagedCodexExec and cancelManagedAgent WebSocket RPC endpoints (with orchestration scope authorization) and wires client-side command atoms in createOrchestrationEnvironmentAtoms.
  • Extends the Codex provider adapter to emit collabAgent/metadata events carrying enriched child agent identity (model, effort, parentAgentId), correlated to the originating turn/item.
  • Adds agentSource and cancellationOwner fields to RuntimeSubagent and TaskAgentLinkage, and builds childrenByParentId in AgentPanelModel for non-workflow parent-child relationships.
  • Renders agents as an indented hierarchy in AgentsPanel and shows a stop button for managed agents in active states, dispatching cancelManagedAgent on click.
  • Risk: cancellation relies on SIGTERM with a 3-second force-kill; processes that ignore SIGTERM will be hard-killed after the timeout with no further retry.

Macroscope summarized e1f841c.

@coderabbitai

coderabbitaiBot commented Aug 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c22faf77-495f-493a-b8a5-de4f794f7636

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 13, 2026
Comment on lines 772 to +785
@@ -751,6 +779,10 @@ export function deriveAgentPanelModel({
const list = members.get(agent.parentAgentId) ?? [];
list.push(agent);
members.set(agent.parentAgentId, list);
} else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {
const list = childrenByParentId.get(agent.parentAgentId) ?? [];
list.push(agent);
childrenByParentId.set(agent.parentAgentId, list);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumstate/subagentRuntime.ts:772

Cyclic parent relationships are omitted from directAgents without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The childrenByParentId branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

 const agentIds = new Set(source.map((agent) => agent.id));
+ const parentById = new Map(source.map((agent) => [agent.id, agent.parentAgentId] as const));
for (const agent of source) {
@@
- } else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {+ } else if (+ agent.parentAgentId !== null &&+ agentIds.has(agent.parentAgentId) &&+ !(() => {+ const seen = new Set<string>();+ let current: string | null = agent.id;+ while (current !== null && agentIds.has(current)) {+ if (seen.has(current)) return true;+ seen.add(current);+ current = parentById.get(current) ?? null;+ }+ return false;+ })()+ ) {
🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/client-runtime/src/state/subagentRuntime.ts around lines 772-785:
Cyclic parent relationships are omitted from `directAgents` without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The `childrenByParentId` branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

collabSpawnMetadata.set(childThreadId, metadata);
}
yield* Ref.set(collabSpawnMetadataRef, collabSpawnMetadata);
const enrichedChildren =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MediumLayers/CodexSessionRuntime.ts:1314

Late spawnAgent metadata for a child-scoped item/started or item/completed notification never reaches ingestion or replay. interceptCollabChildNotification returns at line 1343 before the collabAgent/metadata loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/CodexSessionRuntime.ts around line 1314:
Late `spawnAgent` metadata for a child-scoped `item/started` or `item/completed` notification never reaches ingestion or replay. `interceptCollabChildNotification` returns at line 1343 before the `collabAgent/metadata` loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

const cyclic = ancestors.has(agent.id);
const nextAncestors = new Set(ancestors).add(agent.id);
return (
<div style={{ paddingLeft: `${Math.min(depth, 6) * 12}px` }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/AgentsPanel.tsx:230

Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded <div> while this line applies 12px * depth again, use a constant per-level padding for nested wrappers.

Suggested change
<divstyle={{paddingLeft: `${Math.min(depth,6)*12}px`}}>
<divstyle={{paddingLeft: depth>0 ? "12px" : "0px"}}>
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/AgentsPanel.tsx around line 230:
Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded `<div>` while this line applies `12px * depth` again, use a constant per-level padding for nested wrappers.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the new ManagedCodexExec service and its contract error. Findings are limited to the service definition shape, construction/layer exports, dependency acquisition, and error modeling.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadpackages/contracts/src/orchestration.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 865817f. Configure here.

Comment threadapps/server/src/provider/Layers/CodexSessionRuntime.ts
@macroscopeapp

macroscopeappBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

4 blocking correctness issues found. This PR introduces a substantial new feature for managed Codex agent runs, including process spawning/cancellation, new RPC endpoints, and UI agent tree management with cancel actions. New capability of this scope warrants human review to validate the feature design and cross-system integration.

You can customize Macroscope's approvability policy. Learn more.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One convention finding: ManagedAgentRunError now carries good structural attributes, but every wrapping site discards the underlying failure entirely, so no cause survives. Details inline.

Posted via Macroscope — Effect Service Conventions

Comment on lines +67 to +69
reason: Schema.Literals(["thread-not-found", "spawn-failed", "run-not-found", "not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManagedAgentRunError has no cause, and every wrapping site in ManagedCodexExec.ts (getThreadDetailById, getProjectShellById, randomUUIDv4, spawner.spawn, child.kill) maps with () => new ManagedAgentRunError({...}), so the immediate platform/spawn failure and its stack are dropped with no diagnostic left anywhere. Convention here is to keep the structural fields and preserve the real failure as cause (as sibling contract errors such as VcsProcessSpawnError and GitCommandError do).

Suggest adding an optional cause and passing the underlying error at each mapError:

Suggested change
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
cause: Schema.optional(Schema.Defect()),

If the redaction guarantee asserted in ManagedCodexExec.test.ts means the encoded wire payload must stay free of the spawn command, keep the cause server-side instead (e.g. Effect.tapCause(Effect.logError) before the mapError) rather than discarding it.

Posted via Macroscope — Effect Service Conventions

Effect.mapError(
(cause) =>
new ManagedCodexExecInternalError({
reason: "not-owned",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumorchestration/ManagedCodexExec.ts:330

A failure from run.child.kill(...) is reported as not-owned even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through toManagedAgentRunError as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/ManagedCodexExec.ts around line 330:
A failure from `run.child.kill(...)` is reported as `not-owned` even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through `toManagedAgentRunError` as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new/changed Effect service code (ManagedCodexExec.ts, Services/ProviderRuntimeIngestion.ts, ws.ts wiring, contracts). Service definition (inline Context.Service interface, make then layer), environment-based dependency acquisition (ProviderRuntimeIngestionService, ProjectionSnapshotQuery, ChildProcessSpawner), namespace imports, and cause preservation all match the conventions now. One error-modeling issue remains: the reason discriminator does not identify the failing stage.

Posted via Macroscope — Effect Service Conventions

export class ManagedCodexExecInternalError extends Schema.TaggedErrorClass<ManagedCodexExecInternalError>()(
"ManagedCodexExecInternalError",
{
reason: Schema.Literals(["thread-not-found", "spawn-failed", "not-owned"]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reason is this error's stage/operation discriminator and it also becomes the caller-visible ManagedAgentRunError.reason (via toManagedAgentRunError), but four structurally different failures are folded into reasons that describe something else:

  • projection query failure (lines 127, 144) -> thread-not-found, indistinguishable from the genuine missing-thread branches (lines 135, 152)
  • crypto.randomUUIDv4 failure (line 162) -> spawn-failed
  • task.started ingest failure (line 238) -> spawn-failed
  • child.kill() failure (line 330) -> not-owned, so a run that is owned but could not be killed surfaces as Managed agent run failed (not-owned)

Since the message and client behavior are derived from reason, suggest giving each wrapping site a stage-accurate literal (e.g. thread-lookup-failed, agent-id-failed, ingest-failed, cancel-failed) and extending/mapping ManagedAgentRunError.reason in packages/contracts/src/orchestration.ts accordingly, so the caller-visible reason matches the failure that actually occurred.

Posted via Macroscope — Effect Service Conventions

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

This adds managed Codex agent runs across server orchestration, contracts, and the Agents panel. We are not taking this separate managed-agent workflow forward through the current backlog.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Juliusicon@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(agents): surface managed Codex agent runs - #6416

Closed
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar
Closed

feat(agents): surface managed Codex agent runs#6416
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar

Conversation

@Juliusicon

@JuliusiconJuliusicon commented Aug 13, 2026

Copy link
Copy Markdown

What changed

Adds first-class visibility and lifecycle ownership for Codex agents in T3 Code. Native Codex subagents retain parent/child hierarchy, model, effort, and late-arriving metadata. T3-managed codex exec runs use typed RPC contracts, stable IDs, lifecycle events, exact process-tree cancellation, and sidebar controls.

Why

Raw nested CLI agents were invisible to T3 and could survive supervisor cancellation. Native lifecycle rows also lost hierarchy or metadata under retention and out-of-order event delivery.

Impact

Users can see native and T3-managed Codex agents in the Agents panel, including nested ownership and terminal state. Only T3-managed CLI runs are surfaced; arbitrary external processes are intentionally not discovered by process scanning.

Checks

  • Focused unit/replay tests: 80/80
  • Runtime integration tests: 3/3
  • Server and client-runtime typechecks
  • Targeted lint and formatting
  • git diff --check
  • Final adversarial GPT-5.6 Terra review: PASS

Built with GPT-5.6 Sol through the Codex harness; reviewed with GPT-5.6 Terra.


Note

Medium Risk
Spawns child processes with user prompts and operate-scoped RPC; changes are well-tested but touch orchestration ingestion, Codex event mapping, and cancellation ownership.

Overview
Adds T3-owned codex exec runs with WebSocket RPC (launchManagedCodexExec, cancelManagedAgent), a ManagedCodexExec service that spawns processes and pushes lifecycle events through ingestRuntimeEvent, and operate-scope auth. Launch errors redact prompts from wire payloads.

Improves native Codex collab agents by correlating spawnAgent tool calls to model/effort/parent, emitting collabAgent/metadata for late identity patches, and upserting task-identity:* activities so terminal rows keep hierarchy without reopening. Payloads gain agentSource and cancellationOwner.

Updates the Agents UI and client model with childrenByParentId, nested tree rendering, and a stop control when cancellationOwner === 't3'.

Reviewed by Cursor Bugbot for commit e1f841c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Surface managed Codex agent runs with launch, cancel, and hierarchical UI

  • Adds ManagedCodexExec service that spawns codex exec as a child process, streams stdout/stderr as task.progress events, and emits task.started/task.completed with rich status and summaries.
  • Exposes launchManagedCodexExec and cancelManagedAgent WebSocket RPC endpoints (with orchestration scope authorization) and wires client-side command atoms in createOrchestrationEnvironmentAtoms.
  • Extends the Codex provider adapter to emit collabAgent/metadata events carrying enriched child agent identity (model, effort, parentAgentId), correlated to the originating turn/item.
  • Adds agentSource and cancellationOwner fields to RuntimeSubagent and TaskAgentLinkage, and builds childrenByParentId in AgentPanelModel for non-workflow parent-child relationships.
  • Renders agents as an indented hierarchy in AgentsPanel and shows a stop button for managed agents in active states, dispatching cancelManagedAgent on click.
  • Risk: cancellation relies on SIGTERM with a 3-second force-kill; processes that ignore SIGTERM will be hard-killed after the timeout with no further retry.

Macroscope summarized e1f841c.

@coderabbitai

coderabbitaiBot commented Aug 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c22faf77-495f-493a-b8a5-de4f794f7636

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 13, 2026
Comment on lines 772 to +785
@@ -751,6 +779,10 @@ export function deriveAgentPanelModel({
const list = members.get(agent.parentAgentId) ?? [];
list.push(agent);
members.set(agent.parentAgentId, list);
} else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {
const list = childrenByParentId.get(agent.parentAgentId) ?? [];
list.push(agent);
childrenByParentId.set(agent.parentAgentId, list);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumstate/subagentRuntime.ts:772

Cyclic parent relationships are omitted from directAgents without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The childrenByParentId branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

 const agentIds = new Set(source.map((agent) => agent.id));
+ const parentById = new Map(source.map((agent) => [agent.id, agent.parentAgentId] as const));
for (const agent of source) {
@@
- } else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {+ } else if (+ agent.parentAgentId !== null &&+ agentIds.has(agent.parentAgentId) &&+ !(() => {+ const seen = new Set<string>();+ let current: string | null = agent.id;+ while (current !== null && agentIds.has(current)) {+ if (seen.has(current)) return true;+ seen.add(current);+ current = parentById.get(current) ?? null;+ }+ return false;+ })()+ ) {
🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/client-runtime/src/state/subagentRuntime.ts around lines 772-785:
Cyclic parent relationships are omitted from `directAgents` without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The `childrenByParentId` branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

collabSpawnMetadata.set(childThreadId, metadata);
}
yield* Ref.set(collabSpawnMetadataRef, collabSpawnMetadata);
const enrichedChildren =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MediumLayers/CodexSessionRuntime.ts:1314

Late spawnAgent metadata for a child-scoped item/started or item/completed notification never reaches ingestion or replay. interceptCollabChildNotification returns at line 1343 before the collabAgent/metadata loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/CodexSessionRuntime.ts around line 1314:
Late `spawnAgent` metadata for a child-scoped `item/started` or `item/completed` notification never reaches ingestion or replay. `interceptCollabChildNotification` returns at line 1343 before the `collabAgent/metadata` loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

const cyclic = ancestors.has(agent.id);
const nextAncestors = new Set(ancestors).add(agent.id);
return (
<div style={{ paddingLeft: `${Math.min(depth, 6) * 12}px` }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/AgentsPanel.tsx:230

Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded <div> while this line applies 12px * depth again, use a constant per-level padding for nested wrappers.

Suggested change
<divstyle={{paddingLeft: `${Math.min(depth,6)*12}px`}}>
<divstyle={{paddingLeft: depth>0 ? "12px" : "0px"}}>
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/AgentsPanel.tsx around line 230:
Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded `<div>` while this line applies `12px * depth` again, use a constant per-level padding for nested wrappers.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the new ManagedCodexExec service and its contract error. Findings are limited to the service definition shape, construction/layer exports, dependency acquisition, and error modeling.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadpackages/contracts/src/orchestration.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 865817f. Configure here.

Comment threadapps/server/src/provider/Layers/CodexSessionRuntime.ts
@macroscopeapp

macroscopeappBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

4 blocking correctness issues found. This PR introduces a substantial new feature for managed Codex agent runs, including process spawning/cancellation, new RPC endpoints, and UI agent tree management with cancel actions. New capability of this scope warrants human review to validate the feature design and cross-system integration.

You can customize Macroscope's approvability policy. Learn more.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One convention finding: ManagedAgentRunError now carries good structural attributes, but every wrapping site discards the underlying failure entirely, so no cause survives. Details inline.

Posted via Macroscope — Effect Service Conventions

Comment on lines +67 to +69
reason: Schema.Literals(["thread-not-found", "spawn-failed", "run-not-found", "not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManagedAgentRunError has no cause, and every wrapping site in ManagedCodexExec.ts (getThreadDetailById, getProjectShellById, randomUUIDv4, spawner.spawn, child.kill) maps with () => new ManagedAgentRunError({...}), so the immediate platform/spawn failure and its stack are dropped with no diagnostic left anywhere. Convention here is to keep the structural fields and preserve the real failure as cause (as sibling contract errors such as VcsProcessSpawnError and GitCommandError do).

Suggest adding an optional cause and passing the underlying error at each mapError:

Suggested change
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
cause: Schema.optional(Schema.Defect()),

If the redaction guarantee asserted in ManagedCodexExec.test.ts means the encoded wire payload must stay free of the spawn command, keep the cause server-side instead (e.g. Effect.tapCause(Effect.logError) before the mapError) rather than discarding it.

Posted via Macroscope — Effect Service Conventions

Effect.mapError(
(cause) =>
new ManagedCodexExecInternalError({
reason: "not-owned",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumorchestration/ManagedCodexExec.ts:330

A failure from run.child.kill(...) is reported as not-owned even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through toManagedAgentRunError as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/ManagedCodexExec.ts around line 330:
A failure from `run.child.kill(...)` is reported as `not-owned` even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through `toManagedAgentRunError` as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new/changed Effect service code (ManagedCodexExec.ts, Services/ProviderRuntimeIngestion.ts, ws.ts wiring, contracts). Service definition (inline Context.Service interface, make then layer), environment-based dependency acquisition (ProviderRuntimeIngestionService, ProjectionSnapshotQuery, ChildProcessSpawner), namespace imports, and cause preservation all match the conventions now. One error-modeling issue remains: the reason discriminator does not identify the failing stage.

Posted via Macroscope — Effect Service Conventions

export class ManagedCodexExecInternalError extends Schema.TaggedErrorClass<ManagedCodexExecInternalError>()(
"ManagedCodexExecInternalError",
{
reason: Schema.Literals(["thread-not-found", "spawn-failed", "not-owned"]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reason is this error's stage/operation discriminator and it also becomes the caller-visible ManagedAgentRunError.reason (via toManagedAgentRunError), but four structurally different failures are folded into reasons that describe something else:

  • projection query failure (lines 127, 144) -> thread-not-found, indistinguishable from the genuine missing-thread branches (lines 135, 152)
  • crypto.randomUUIDv4 failure (line 162) -> spawn-failed
  • task.started ingest failure (line 238) -> spawn-failed
  • child.kill() failure (line 330) -> not-owned, so a run that is owned but could not be killed surfaces as Managed agent run failed (not-owned)

Since the message and client behavior are derived from reason, suggest giving each wrapping site a stage-accurate literal (e.g. thread-lookup-failed, agent-id-failed, ingest-failed, cancel-failed) and extending/mapping ManagedAgentRunError.reason in packages/contracts/src/orchestration.ts accordingly, so the caller-visible reason matches the failure that actually occurred.

Posted via Macroscope — Effect Service Conventions

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

This adds managed Codex agent runs across server orchestration, contracts, and the Agents panel. We are not taking this separate managed-agent workflow forward through the current backlog.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Juliusicon@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(agents): surface managed Codex agent runs - #6416

Closed
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar
Closed

feat(agents): surface managed Codex agent runs#6416
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar

Conversation

@Juliusicon

@JuliusiconJuliusicon commented Aug 13, 2026

Copy link
Copy Markdown

What changed

Adds first-class visibility and lifecycle ownership for Codex agents in T3 Code. Native Codex subagents retain parent/child hierarchy, model, effort, and late-arriving metadata. T3-managed codex exec runs use typed RPC contracts, stable IDs, lifecycle events, exact process-tree cancellation, and sidebar controls.

Why

Raw nested CLI agents were invisible to T3 and could survive supervisor cancellation. Native lifecycle rows also lost hierarchy or metadata under retention and out-of-order event delivery.

Impact

Users can see native and T3-managed Codex agents in the Agents panel, including nested ownership and terminal state. Only T3-managed CLI runs are surfaced; arbitrary external processes are intentionally not discovered by process scanning.

Checks

  • Focused unit/replay tests: 80/80
  • Runtime integration tests: 3/3
  • Server and client-runtime typechecks
  • Targeted lint and formatting
  • git diff --check
  • Final adversarial GPT-5.6 Terra review: PASS

Built with GPT-5.6 Sol through the Codex harness; reviewed with GPT-5.6 Terra.


Note

Medium Risk
Spawns child processes with user prompts and operate-scoped RPC; changes are well-tested but touch orchestration ingestion, Codex event mapping, and cancellation ownership.

Overview
Adds T3-owned codex exec runs with WebSocket RPC (launchManagedCodexExec, cancelManagedAgent), a ManagedCodexExec service that spawns processes and pushes lifecycle events through ingestRuntimeEvent, and operate-scope auth. Launch errors redact prompts from wire payloads.

Improves native Codex collab agents by correlating spawnAgent tool calls to model/effort/parent, emitting collabAgent/metadata for late identity patches, and upserting task-identity:* activities so terminal rows keep hierarchy without reopening. Payloads gain agentSource and cancellationOwner.

Updates the Agents UI and client model with childrenByParentId, nested tree rendering, and a stop control when cancellationOwner === 't3'.

Reviewed by Cursor Bugbot for commit e1f841c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Surface managed Codex agent runs with launch, cancel, and hierarchical UI

  • Adds ManagedCodexExec service that spawns codex exec as a child process, streams stdout/stderr as task.progress events, and emits task.started/task.completed with rich status and summaries.
  • Exposes launchManagedCodexExec and cancelManagedAgent WebSocket RPC endpoints (with orchestration scope authorization) and wires client-side command atoms in createOrchestrationEnvironmentAtoms.
  • Extends the Codex provider adapter to emit collabAgent/metadata events carrying enriched child agent identity (model, effort, parentAgentId), correlated to the originating turn/item.
  • Adds agentSource and cancellationOwner fields to RuntimeSubagent and TaskAgentLinkage, and builds childrenByParentId in AgentPanelModel for non-workflow parent-child relationships.
  • Renders agents as an indented hierarchy in AgentsPanel and shows a stop button for managed agents in active states, dispatching cancelManagedAgent on click.
  • Risk: cancellation relies on SIGTERM with a 3-second force-kill; processes that ignore SIGTERM will be hard-killed after the timeout with no further retry.

Macroscope summarized e1f841c.

@coderabbitai

coderabbitaiBot commented Aug 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c22faf77-495f-493a-b8a5-de4f794f7636

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 13, 2026
Comment on lines 772 to +785
@@ -751,6 +779,10 @@ export function deriveAgentPanelModel({
const list = members.get(agent.parentAgentId) ?? [];
list.push(agent);
members.set(agent.parentAgentId, list);
} else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {
const list = childrenByParentId.get(agent.parentAgentId) ?? [];
list.push(agent);
childrenByParentId.set(agent.parentAgentId, list);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumstate/subagentRuntime.ts:772

Cyclic parent relationships are omitted from directAgents without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The childrenByParentId branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

 const agentIds = new Set(source.map((agent) => agent.id));
+ const parentById = new Map(source.map((agent) => [agent.id, agent.parentAgentId] as const));
for (const agent of source) {
@@
- } else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {+ } else if (+ agent.parentAgentId !== null &&+ agentIds.has(agent.parentAgentId) &&+ !(() => {+ const seen = new Set<string>();+ let current: string | null = agent.id;+ while (current !== null && agentIds.has(current)) {+ if (seen.has(current)) return true;+ seen.add(current);+ current = parentById.get(current) ?? null;+ }+ return false;+ })()+ ) {
🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/client-runtime/src/state/subagentRuntime.ts around lines 772-785:
Cyclic parent relationships are omitted from `directAgents` without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The `childrenByParentId` branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

collabSpawnMetadata.set(childThreadId, metadata);
}
yield* Ref.set(collabSpawnMetadataRef, collabSpawnMetadata);
const enrichedChildren =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MediumLayers/CodexSessionRuntime.ts:1314

Late spawnAgent metadata for a child-scoped item/started or item/completed notification never reaches ingestion or replay. interceptCollabChildNotification returns at line 1343 before the collabAgent/metadata loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/CodexSessionRuntime.ts around line 1314:
Late `spawnAgent` metadata for a child-scoped `item/started` or `item/completed` notification never reaches ingestion or replay. `interceptCollabChildNotification` returns at line 1343 before the `collabAgent/metadata` loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

const cyclic = ancestors.has(agent.id);
const nextAncestors = new Set(ancestors).add(agent.id);
return (
<div style={{ paddingLeft: `${Math.min(depth, 6) * 12}px` }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/AgentsPanel.tsx:230

Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded <div> while this line applies 12px * depth again, use a constant per-level padding for nested wrappers.

Suggested change
<divstyle={{paddingLeft: `${Math.min(depth,6)*12}px`}}>
<divstyle={{paddingLeft: depth>0 ? "12px" : "0px"}}>
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/AgentsPanel.tsx around line 230:
Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded `<div>` while this line applies `12px * depth` again, use a constant per-level padding for nested wrappers.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the new ManagedCodexExec service and its contract error. Findings are limited to the service definition shape, construction/layer exports, dependency acquisition, and error modeling.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadpackages/contracts/src/orchestration.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 865817f. Configure here.

Comment threadapps/server/src/provider/Layers/CodexSessionRuntime.ts
@macroscopeapp

macroscopeappBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

4 blocking correctness issues found. This PR introduces a substantial new feature for managed Codex agent runs, including process spawning/cancellation, new RPC endpoints, and UI agent tree management with cancel actions. New capability of this scope warrants human review to validate the feature design and cross-system integration.

You can customize Macroscope's approvability policy. Learn more.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One convention finding: ManagedAgentRunError now carries good structural attributes, but every wrapping site discards the underlying failure entirely, so no cause survives. Details inline.

Posted via Macroscope — Effect Service Conventions

Comment on lines +67 to +69
reason: Schema.Literals(["thread-not-found", "spawn-failed", "run-not-found", "not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManagedAgentRunError has no cause, and every wrapping site in ManagedCodexExec.ts (getThreadDetailById, getProjectShellById, randomUUIDv4, spawner.spawn, child.kill) maps with () => new ManagedAgentRunError({...}), so the immediate platform/spawn failure and its stack are dropped with no diagnostic left anywhere. Convention here is to keep the structural fields and preserve the real failure as cause (as sibling contract errors such as VcsProcessSpawnError and GitCommandError do).

Suggest adding an optional cause and passing the underlying error at each mapError:

Suggested change
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
cause: Schema.optional(Schema.Defect()),

If the redaction guarantee asserted in ManagedCodexExec.test.ts means the encoded wire payload must stay free of the spawn command, keep the cause server-side instead (e.g. Effect.tapCause(Effect.logError) before the mapError) rather than discarding it.

Posted via Macroscope — Effect Service Conventions

Effect.mapError(
(cause) =>
new ManagedCodexExecInternalError({
reason: "not-owned",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumorchestration/ManagedCodexExec.ts:330

A failure from run.child.kill(...) is reported as not-owned even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through toManagedAgentRunError as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/ManagedCodexExec.ts around line 330:
A failure from `run.child.kill(...)` is reported as `not-owned` even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through `toManagedAgentRunError` as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new/changed Effect service code (ManagedCodexExec.ts, Services/ProviderRuntimeIngestion.ts, ws.ts wiring, contracts). Service definition (inline Context.Service interface, make then layer), environment-based dependency acquisition (ProviderRuntimeIngestionService, ProjectionSnapshotQuery, ChildProcessSpawner), namespace imports, and cause preservation all match the conventions now. One error-modeling issue remains: the reason discriminator does not identify the failing stage.

Posted via Macroscope — Effect Service Conventions

export class ManagedCodexExecInternalError extends Schema.TaggedErrorClass<ManagedCodexExecInternalError>()(
"ManagedCodexExecInternalError",
{
reason: Schema.Literals(["thread-not-found", "spawn-failed", "not-owned"]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reason is this error's stage/operation discriminator and it also becomes the caller-visible ManagedAgentRunError.reason (via toManagedAgentRunError), but four structurally different failures are folded into reasons that describe something else:

  • projection query failure (lines 127, 144) -> thread-not-found, indistinguishable from the genuine missing-thread branches (lines 135, 152)
  • crypto.randomUUIDv4 failure (line 162) -> spawn-failed
  • task.started ingest failure (line 238) -> spawn-failed
  • child.kill() failure (line 330) -> not-owned, so a run that is owned but could not be killed surfaces as Managed agent run failed (not-owned)

Since the message and client behavior are derived from reason, suggest giving each wrapping site a stage-accurate literal (e.g. thread-lookup-failed, agent-id-failed, ingest-failed, cancel-failed) and extending/mapping ManagedAgentRunError.reason in packages/contracts/src/orchestration.ts accordingly, so the caller-visible reason matches the failure that actually occurred.

Posted via Macroscope — Effect Service Conventions

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

This adds managed Codex agent runs across server orchestration, contracts, and the Agents panel. We are not taking this separate managed-agent workflow forward through the current backlog.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Juliusicon@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(agents): surface managed Codex agent runs - #6416

Closed
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar
Closed

feat(agents): surface managed Codex agent runs#6416
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar

Conversation

@Juliusicon

@JuliusiconJuliusicon commented Aug 13, 2026

Copy link
Copy Markdown

What changed

Adds first-class visibility and lifecycle ownership for Codex agents in T3 Code. Native Codex subagents retain parent/child hierarchy, model, effort, and late-arriving metadata. T3-managed codex exec runs use typed RPC contracts, stable IDs, lifecycle events, exact process-tree cancellation, and sidebar controls.

Why

Raw nested CLI agents were invisible to T3 and could survive supervisor cancellation. Native lifecycle rows also lost hierarchy or metadata under retention and out-of-order event delivery.

Impact

Users can see native and T3-managed Codex agents in the Agents panel, including nested ownership and terminal state. Only T3-managed CLI runs are surfaced; arbitrary external processes are intentionally not discovered by process scanning.

Checks

  • Focused unit/replay tests: 80/80
  • Runtime integration tests: 3/3
  • Server and client-runtime typechecks
  • Targeted lint and formatting
  • git diff --check
  • Final adversarial GPT-5.6 Terra review: PASS

Built with GPT-5.6 Sol through the Codex harness; reviewed with GPT-5.6 Terra.


Note

Medium Risk
Spawns child processes with user prompts and operate-scoped RPC; changes are well-tested but touch orchestration ingestion, Codex event mapping, and cancellation ownership.

Overview
Adds T3-owned codex exec runs with WebSocket RPC (launchManagedCodexExec, cancelManagedAgent), a ManagedCodexExec service that spawns processes and pushes lifecycle events through ingestRuntimeEvent, and operate-scope auth. Launch errors redact prompts from wire payloads.

Improves native Codex collab agents by correlating spawnAgent tool calls to model/effort/parent, emitting collabAgent/metadata for late identity patches, and upserting task-identity:* activities so terminal rows keep hierarchy without reopening. Payloads gain agentSource and cancellationOwner.

Updates the Agents UI and client model with childrenByParentId, nested tree rendering, and a stop control when cancellationOwner === 't3'.

Reviewed by Cursor Bugbot for commit e1f841c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Surface managed Codex agent runs with launch, cancel, and hierarchical UI

  • Adds ManagedCodexExec service that spawns codex exec as a child process, streams stdout/stderr as task.progress events, and emits task.started/task.completed with rich status and summaries.
  • Exposes launchManagedCodexExec and cancelManagedAgent WebSocket RPC endpoints (with orchestration scope authorization) and wires client-side command atoms in createOrchestrationEnvironmentAtoms.
  • Extends the Codex provider adapter to emit collabAgent/metadata events carrying enriched child agent identity (model, effort, parentAgentId), correlated to the originating turn/item.
  • Adds agentSource and cancellationOwner fields to RuntimeSubagent and TaskAgentLinkage, and builds childrenByParentId in AgentPanelModel for non-workflow parent-child relationships.
  • Renders agents as an indented hierarchy in AgentsPanel and shows a stop button for managed agents in active states, dispatching cancelManagedAgent on click.
  • Risk: cancellation relies on SIGTERM with a 3-second force-kill; processes that ignore SIGTERM will be hard-killed after the timeout with no further retry.

Macroscope summarized e1f841c.

@coderabbitai

coderabbitaiBot commented Aug 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c22faf77-495f-493a-b8a5-de4f794f7636

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 13, 2026
Comment on lines 772 to +785
@@ -751,6 +779,10 @@ export function deriveAgentPanelModel({
const list = members.get(agent.parentAgentId) ?? [];
list.push(agent);
members.set(agent.parentAgentId, list);
} else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {
const list = childrenByParentId.get(agent.parentAgentId) ?? [];
list.push(agent);
childrenByParentId.set(agent.parentAgentId, list);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumstate/subagentRuntime.ts:772

Cyclic parent relationships are omitted from directAgents without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The childrenByParentId branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

 const agentIds = new Set(source.map((agent) => agent.id));
+ const parentById = new Map(source.map((agent) => [agent.id, agent.parentAgentId] as const));
for (const agent of source) {
@@
- } else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {+ } else if (+ agent.parentAgentId !== null &&+ agentIds.has(agent.parentAgentId) &&+ !(() => {+ const seen = new Set<string>();+ let current: string | null = agent.id;+ while (current !== null && agentIds.has(current)) {+ if (seen.has(current)) return true;+ seen.add(current);+ current = parentById.get(current) ?? null;+ }+ return false;+ })()+ ) {
🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/client-runtime/src/state/subagentRuntime.ts around lines 772-785:
Cyclic parent relationships are omitted from `directAgents` without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The `childrenByParentId` branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

collabSpawnMetadata.set(childThreadId, metadata);
}
yield* Ref.set(collabSpawnMetadataRef, collabSpawnMetadata);
const enrichedChildren =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MediumLayers/CodexSessionRuntime.ts:1314

Late spawnAgent metadata for a child-scoped item/started or item/completed notification never reaches ingestion or replay. interceptCollabChildNotification returns at line 1343 before the collabAgent/metadata loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/CodexSessionRuntime.ts around line 1314:
Late `spawnAgent` metadata for a child-scoped `item/started` or `item/completed` notification never reaches ingestion or replay. `interceptCollabChildNotification` returns at line 1343 before the `collabAgent/metadata` loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

const cyclic = ancestors.has(agent.id);
const nextAncestors = new Set(ancestors).add(agent.id);
return (
<div style={{ paddingLeft: `${Math.min(depth, 6) * 12}px` }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/AgentsPanel.tsx:230

Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded <div> while this line applies 12px * depth again, use a constant per-level padding for nested wrappers.

Suggested change
<divstyle={{paddingLeft: `${Math.min(depth,6)*12}px`}}>
<divstyle={{paddingLeft: depth>0 ? "12px" : "0px"}}>
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/AgentsPanel.tsx around line 230:
Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded `<div>` while this line applies `12px * depth` again, use a constant per-level padding for nested wrappers.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the new ManagedCodexExec service and its contract error. Findings are limited to the service definition shape, construction/layer exports, dependency acquisition, and error modeling.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadpackages/contracts/src/orchestration.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 865817f. Configure here.

Comment threadapps/server/src/provider/Layers/CodexSessionRuntime.ts
@macroscopeapp

macroscopeappBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

4 blocking correctness issues found. This PR introduces a substantial new feature for managed Codex agent runs, including process spawning/cancellation, new RPC endpoints, and UI agent tree management with cancel actions. New capability of this scope warrants human review to validate the feature design and cross-system integration.

You can customize Macroscope's approvability policy. Learn more.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One convention finding: ManagedAgentRunError now carries good structural attributes, but every wrapping site discards the underlying failure entirely, so no cause survives. Details inline.

Posted via Macroscope — Effect Service Conventions

Comment on lines +67 to +69
reason: Schema.Literals(["thread-not-found", "spawn-failed", "run-not-found", "not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManagedAgentRunError has no cause, and every wrapping site in ManagedCodexExec.ts (getThreadDetailById, getProjectShellById, randomUUIDv4, spawner.spawn, child.kill) maps with () => new ManagedAgentRunError({...}), so the immediate platform/spawn failure and its stack are dropped with no diagnostic left anywhere. Convention here is to keep the structural fields and preserve the real failure as cause (as sibling contract errors such as VcsProcessSpawnError and GitCommandError do).

Suggest adding an optional cause and passing the underlying error at each mapError:

Suggested change
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
cause: Schema.optional(Schema.Defect()),

If the redaction guarantee asserted in ManagedCodexExec.test.ts means the encoded wire payload must stay free of the spawn command, keep the cause server-side instead (e.g. Effect.tapCause(Effect.logError) before the mapError) rather than discarding it.

Posted via Macroscope — Effect Service Conventions

Effect.mapError(
(cause) =>
new ManagedCodexExecInternalError({
reason: "not-owned",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumorchestration/ManagedCodexExec.ts:330

A failure from run.child.kill(...) is reported as not-owned even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through toManagedAgentRunError as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/ManagedCodexExec.ts around line 330:
A failure from `run.child.kill(...)` is reported as `not-owned` even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through `toManagedAgentRunError` as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new/changed Effect service code (ManagedCodexExec.ts, Services/ProviderRuntimeIngestion.ts, ws.ts wiring, contracts). Service definition (inline Context.Service interface, make then layer), environment-based dependency acquisition (ProviderRuntimeIngestionService, ProjectionSnapshotQuery, ChildProcessSpawner), namespace imports, and cause preservation all match the conventions now. One error-modeling issue remains: the reason discriminator does not identify the failing stage.

Posted via Macroscope — Effect Service Conventions

export class ManagedCodexExecInternalError extends Schema.TaggedErrorClass<ManagedCodexExecInternalError>()(
"ManagedCodexExecInternalError",
{
reason: Schema.Literals(["thread-not-found", "spawn-failed", "not-owned"]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reason is this error's stage/operation discriminator and it also becomes the caller-visible ManagedAgentRunError.reason (via toManagedAgentRunError), but four structurally different failures are folded into reasons that describe something else:

  • projection query failure (lines 127, 144) -> thread-not-found, indistinguishable from the genuine missing-thread branches (lines 135, 152)
  • crypto.randomUUIDv4 failure (line 162) -> spawn-failed
  • task.started ingest failure (line 238) -> spawn-failed
  • child.kill() failure (line 330) -> not-owned, so a run that is owned but could not be killed surfaces as Managed agent run failed (not-owned)

Since the message and client behavior are derived from reason, suggest giving each wrapping site a stage-accurate literal (e.g. thread-lookup-failed, agent-id-failed, ingest-failed, cancel-failed) and extending/mapping ManagedAgentRunError.reason in packages/contracts/src/orchestration.ts accordingly, so the caller-visible reason matches the failure that actually occurred.

Posted via Macroscope — Effect Service Conventions

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

This adds managed Codex agent runs across server orchestration, contracts, and the Agents panel. We are not taking this separate managed-agent workflow forward through the current backlog.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Juliusicon@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(agents): surface managed Codex agent runs - #6416

Closed
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar
Closed

feat(agents): surface managed Codex agent runs#6416
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar

Conversation

@Juliusicon

@JuliusiconJuliusicon commented Aug 13, 2026

Copy link
Copy Markdown

What changed

Adds first-class visibility and lifecycle ownership for Codex agents in T3 Code. Native Codex subagents retain parent/child hierarchy, model, effort, and late-arriving metadata. T3-managed codex exec runs use typed RPC contracts, stable IDs, lifecycle events, exact process-tree cancellation, and sidebar controls.

Why

Raw nested CLI agents were invisible to T3 and could survive supervisor cancellation. Native lifecycle rows also lost hierarchy or metadata under retention and out-of-order event delivery.

Impact

Users can see native and T3-managed Codex agents in the Agents panel, including nested ownership and terminal state. Only T3-managed CLI runs are surfaced; arbitrary external processes are intentionally not discovered by process scanning.

Checks

  • Focused unit/replay tests: 80/80
  • Runtime integration tests: 3/3
  • Server and client-runtime typechecks
  • Targeted lint and formatting
  • git diff --check
  • Final adversarial GPT-5.6 Terra review: PASS

Built with GPT-5.6 Sol through the Codex harness; reviewed with GPT-5.6 Terra.


Note

Medium Risk
Spawns child processes with user prompts and operate-scoped RPC; changes are well-tested but touch orchestration ingestion, Codex event mapping, and cancellation ownership.

Overview
Adds T3-owned codex exec runs with WebSocket RPC (launchManagedCodexExec, cancelManagedAgent), a ManagedCodexExec service that spawns processes and pushes lifecycle events through ingestRuntimeEvent, and operate-scope auth. Launch errors redact prompts from wire payloads.

Improves native Codex collab agents by correlating spawnAgent tool calls to model/effort/parent, emitting collabAgent/metadata for late identity patches, and upserting task-identity:* activities so terminal rows keep hierarchy without reopening. Payloads gain agentSource and cancellationOwner.

Updates the Agents UI and client model with childrenByParentId, nested tree rendering, and a stop control when cancellationOwner === 't3'.

Reviewed by Cursor Bugbot for commit e1f841c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Surface managed Codex agent runs with launch, cancel, and hierarchical UI

  • Adds ManagedCodexExec service that spawns codex exec as a child process, streams stdout/stderr as task.progress events, and emits task.started/task.completed with rich status and summaries.
  • Exposes launchManagedCodexExec and cancelManagedAgent WebSocket RPC endpoints (with orchestration scope authorization) and wires client-side command atoms in createOrchestrationEnvironmentAtoms.
  • Extends the Codex provider adapter to emit collabAgent/metadata events carrying enriched child agent identity (model, effort, parentAgentId), correlated to the originating turn/item.
  • Adds agentSource and cancellationOwner fields to RuntimeSubagent and TaskAgentLinkage, and builds childrenByParentId in AgentPanelModel for non-workflow parent-child relationships.
  • Renders agents as an indented hierarchy in AgentsPanel and shows a stop button for managed agents in active states, dispatching cancelManagedAgent on click.
  • Risk: cancellation relies on SIGTERM with a 3-second force-kill; processes that ignore SIGTERM will be hard-killed after the timeout with no further retry.

Macroscope summarized e1f841c.

@coderabbitai

coderabbitaiBot commented Aug 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c22faf77-495f-493a-b8a5-de4f794f7636

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 13, 2026
Comment on lines 772 to +785
@@ -751,6 +779,10 @@ export function deriveAgentPanelModel({
const list = members.get(agent.parentAgentId) ?? [];
list.push(agent);
members.set(agent.parentAgentId, list);
} else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {
const list = childrenByParentId.get(agent.parentAgentId) ?? [];
list.push(agent);
childrenByParentId.set(agent.parentAgentId, list);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumstate/subagentRuntime.ts:772

Cyclic parent relationships are omitted from directAgents without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The childrenByParentId branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

 const agentIds = new Set(source.map((agent) => agent.id));
+ const parentById = new Map(source.map((agent) => [agent.id, agent.parentAgentId] as const));
for (const agent of source) {
@@
- } else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {+ } else if (+ agent.parentAgentId !== null &&+ agentIds.has(agent.parentAgentId) &&+ !(() => {+ const seen = new Set<string>();+ let current: string | null = agent.id;+ while (current !== null && agentIds.has(current)) {+ if (seen.has(current)) return true;+ seen.add(current);+ current = parentById.get(current) ?? null;+ }+ return false;+ })()+ ) {
🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/client-runtime/src/state/subagentRuntime.ts around lines 772-785:
Cyclic parent relationships are omitted from `directAgents` without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The `childrenByParentId` branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

collabSpawnMetadata.set(childThreadId, metadata);
}
yield* Ref.set(collabSpawnMetadataRef, collabSpawnMetadata);
const enrichedChildren =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MediumLayers/CodexSessionRuntime.ts:1314

Late spawnAgent metadata for a child-scoped item/started or item/completed notification never reaches ingestion or replay. interceptCollabChildNotification returns at line 1343 before the collabAgent/metadata loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/CodexSessionRuntime.ts around line 1314:
Late `spawnAgent` metadata for a child-scoped `item/started` or `item/completed` notification never reaches ingestion or replay. `interceptCollabChildNotification` returns at line 1343 before the `collabAgent/metadata` loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

const cyclic = ancestors.has(agent.id);
const nextAncestors = new Set(ancestors).add(agent.id);
return (
<div style={{ paddingLeft: `${Math.min(depth, 6) * 12}px` }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/AgentsPanel.tsx:230

Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded <div> while this line applies 12px * depth again, use a constant per-level padding for nested wrappers.

Suggested change
<divstyle={{paddingLeft: `${Math.min(depth,6)*12}px`}}>
<divstyle={{paddingLeft: depth>0 ? "12px" : "0px"}}>
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/AgentsPanel.tsx around line 230:
Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded `<div>` while this line applies `12px * depth` again, use a constant per-level padding for nested wrappers.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the new ManagedCodexExec service and its contract error. Findings are limited to the service definition shape, construction/layer exports, dependency acquisition, and error modeling.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadpackages/contracts/src/orchestration.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 865817f. Configure here.

Comment threadapps/server/src/provider/Layers/CodexSessionRuntime.ts
@macroscopeapp

macroscopeappBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

4 blocking correctness issues found. This PR introduces a substantial new feature for managed Codex agent runs, including process spawning/cancellation, new RPC endpoints, and UI agent tree management with cancel actions. New capability of this scope warrants human review to validate the feature design and cross-system integration.

You can customize Macroscope's approvability policy. Learn more.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One convention finding: ManagedAgentRunError now carries good structural attributes, but every wrapping site discards the underlying failure entirely, so no cause survives. Details inline.

Posted via Macroscope — Effect Service Conventions

Comment on lines +67 to +69
reason: Schema.Literals(["thread-not-found", "spawn-failed", "run-not-found", "not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManagedAgentRunError has no cause, and every wrapping site in ManagedCodexExec.ts (getThreadDetailById, getProjectShellById, randomUUIDv4, spawner.spawn, child.kill) maps with () => new ManagedAgentRunError({...}), so the immediate platform/spawn failure and its stack are dropped with no diagnostic left anywhere. Convention here is to keep the structural fields and preserve the real failure as cause (as sibling contract errors such as VcsProcessSpawnError and GitCommandError do).

Suggest adding an optional cause and passing the underlying error at each mapError:

Suggested change
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
cause: Schema.optional(Schema.Defect()),

If the redaction guarantee asserted in ManagedCodexExec.test.ts means the encoded wire payload must stay free of the spawn command, keep the cause server-side instead (e.g. Effect.tapCause(Effect.logError) before the mapError) rather than discarding it.

Posted via Macroscope — Effect Service Conventions

Effect.mapError(
(cause) =>
new ManagedCodexExecInternalError({
reason: "not-owned",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumorchestration/ManagedCodexExec.ts:330

A failure from run.child.kill(...) is reported as not-owned even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through toManagedAgentRunError as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/ManagedCodexExec.ts around line 330:
A failure from `run.child.kill(...)` is reported as `not-owned` even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through `toManagedAgentRunError` as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new/changed Effect service code (ManagedCodexExec.ts, Services/ProviderRuntimeIngestion.ts, ws.ts wiring, contracts). Service definition (inline Context.Service interface, make then layer), environment-based dependency acquisition (ProviderRuntimeIngestionService, ProjectionSnapshotQuery, ChildProcessSpawner), namespace imports, and cause preservation all match the conventions now. One error-modeling issue remains: the reason discriminator does not identify the failing stage.

Posted via Macroscope — Effect Service Conventions

export class ManagedCodexExecInternalError extends Schema.TaggedErrorClass<ManagedCodexExecInternalError>()(
"ManagedCodexExecInternalError",
{
reason: Schema.Literals(["thread-not-found", "spawn-failed", "not-owned"]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reason is this error's stage/operation discriminator and it also becomes the caller-visible ManagedAgentRunError.reason (via toManagedAgentRunError), but four structurally different failures are folded into reasons that describe something else:

  • projection query failure (lines 127, 144) -> thread-not-found, indistinguishable from the genuine missing-thread branches (lines 135, 152)
  • crypto.randomUUIDv4 failure (line 162) -> spawn-failed
  • task.started ingest failure (line 238) -> spawn-failed
  • child.kill() failure (line 330) -> not-owned, so a run that is owned but could not be killed surfaces as Managed agent run failed (not-owned)

Since the message and client behavior are derived from reason, suggest giving each wrapping site a stage-accurate literal (e.g. thread-lookup-failed, agent-id-failed, ingest-failed, cancel-failed) and extending/mapping ManagedAgentRunError.reason in packages/contracts/src/orchestration.ts accordingly, so the caller-visible reason matches the failure that actually occurred.

Posted via Macroscope — Effect Service Conventions

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

This adds managed Codex agent runs across server orchestration, contracts, and the Agents panel. We are not taking this separate managed-agent workflow forward through the current backlog.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Juliusicon@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(agents): surface managed Codex agent runs - #6416

Closed
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar
Closed

feat(agents): surface managed Codex agent runs#6416
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar

Conversation

@Juliusicon

@JuliusiconJuliusicon commented Aug 13, 2026

Copy link
Copy Markdown

What changed

Adds first-class visibility and lifecycle ownership for Codex agents in T3 Code. Native Codex subagents retain parent/child hierarchy, model, effort, and late-arriving metadata. T3-managed codex exec runs use typed RPC contracts, stable IDs, lifecycle events, exact process-tree cancellation, and sidebar controls.

Why

Raw nested CLI agents were invisible to T3 and could survive supervisor cancellation. Native lifecycle rows also lost hierarchy or metadata under retention and out-of-order event delivery.

Impact

Users can see native and T3-managed Codex agents in the Agents panel, including nested ownership and terminal state. Only T3-managed CLI runs are surfaced; arbitrary external processes are intentionally not discovered by process scanning.

Checks

  • Focused unit/replay tests: 80/80
  • Runtime integration tests: 3/3
  • Server and client-runtime typechecks
  • Targeted lint and formatting
  • git diff --check
  • Final adversarial GPT-5.6 Terra review: PASS

Built with GPT-5.6 Sol through the Codex harness; reviewed with GPT-5.6 Terra.


Note

Medium Risk
Spawns child processes with user prompts and operate-scoped RPC; changes are well-tested but touch orchestration ingestion, Codex event mapping, and cancellation ownership.

Overview
Adds T3-owned codex exec runs with WebSocket RPC (launchManagedCodexExec, cancelManagedAgent), a ManagedCodexExec service that spawns processes and pushes lifecycle events through ingestRuntimeEvent, and operate-scope auth. Launch errors redact prompts from wire payloads.

Improves native Codex collab agents by correlating spawnAgent tool calls to model/effort/parent, emitting collabAgent/metadata for late identity patches, and upserting task-identity:* activities so terminal rows keep hierarchy without reopening. Payloads gain agentSource and cancellationOwner.

Updates the Agents UI and client model with childrenByParentId, nested tree rendering, and a stop control when cancellationOwner === 't3'.

Reviewed by Cursor Bugbot for commit e1f841c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Surface managed Codex agent runs with launch, cancel, and hierarchical UI

  • Adds ManagedCodexExec service that spawns codex exec as a child process, streams stdout/stderr as task.progress events, and emits task.started/task.completed with rich status and summaries.
  • Exposes launchManagedCodexExec and cancelManagedAgent WebSocket RPC endpoints (with orchestration scope authorization) and wires client-side command atoms in createOrchestrationEnvironmentAtoms.
  • Extends the Codex provider adapter to emit collabAgent/metadata events carrying enriched child agent identity (model, effort, parentAgentId), correlated to the originating turn/item.
  • Adds agentSource and cancellationOwner fields to RuntimeSubagent and TaskAgentLinkage, and builds childrenByParentId in AgentPanelModel for non-workflow parent-child relationships.
  • Renders agents as an indented hierarchy in AgentsPanel and shows a stop button for managed agents in active states, dispatching cancelManagedAgent on click.
  • Risk: cancellation relies on SIGTERM with a 3-second force-kill; processes that ignore SIGTERM will be hard-killed after the timeout with no further retry.

Macroscope summarized e1f841c.

@coderabbitai

coderabbitaiBot commented Aug 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c22faf77-495f-493a-b8a5-de4f794f7636

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 13, 2026
Comment on lines 772 to +785
@@ -751,6 +779,10 @@ export function deriveAgentPanelModel({
const list = members.get(agent.parentAgentId) ?? [];
list.push(agent);
members.set(agent.parentAgentId, list);
} else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {
const list = childrenByParentId.get(agent.parentAgentId) ?? [];
list.push(agent);
childrenByParentId.set(agent.parentAgentId, list);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumstate/subagentRuntime.ts:772

Cyclic parent relationships are omitted from directAgents without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The childrenByParentId branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

 const agentIds = new Set(source.map((agent) => agent.id));
+ const parentById = new Map(source.map((agent) => [agent.id, agent.parentAgentId] as const));
for (const agent of source) {
@@
- } else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {+ } else if (+ agent.parentAgentId !== null &&+ agentIds.has(agent.parentAgentId) &&+ !(() => {+ const seen = new Set<string>();+ let current: string | null = agent.id;+ while (current !== null && agentIds.has(current)) {+ if (seen.has(current)) return true;+ seen.add(current);+ current = parentById.get(current) ?? null;+ }+ return false;+ })()+ ) {
🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/client-runtime/src/state/subagentRuntime.ts around lines 772-785:
Cyclic parent relationships are omitted from `directAgents` without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The `childrenByParentId` branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

collabSpawnMetadata.set(childThreadId, metadata);
}
yield* Ref.set(collabSpawnMetadataRef, collabSpawnMetadata);
const enrichedChildren =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MediumLayers/CodexSessionRuntime.ts:1314

Late spawnAgent metadata for a child-scoped item/started or item/completed notification never reaches ingestion or replay. interceptCollabChildNotification returns at line 1343 before the collabAgent/metadata loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/CodexSessionRuntime.ts around line 1314:
Late `spawnAgent` metadata for a child-scoped `item/started` or `item/completed` notification never reaches ingestion or replay. `interceptCollabChildNotification` returns at line 1343 before the `collabAgent/metadata` loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

const cyclic = ancestors.has(agent.id);
const nextAncestors = new Set(ancestors).add(agent.id);
return (
<div style={{ paddingLeft: `${Math.min(depth, 6) * 12}px` }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/AgentsPanel.tsx:230

Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded <div> while this line applies 12px * depth again, use a constant per-level padding for nested wrappers.

Suggested change
<divstyle={{paddingLeft: `${Math.min(depth,6)*12}px`}}>
<divstyle={{paddingLeft: depth>0 ? "12px" : "0px"}}>
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/AgentsPanel.tsx around line 230:
Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded `<div>` while this line applies `12px * depth` again, use a constant per-level padding for nested wrappers.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the new ManagedCodexExec service and its contract error. Findings are limited to the service definition shape, construction/layer exports, dependency acquisition, and error modeling.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadpackages/contracts/src/orchestration.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 865817f. Configure here.

Comment threadapps/server/src/provider/Layers/CodexSessionRuntime.ts
@macroscopeapp

macroscopeappBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

4 blocking correctness issues found. This PR introduces a substantial new feature for managed Codex agent runs, including process spawning/cancellation, new RPC endpoints, and UI agent tree management with cancel actions. New capability of this scope warrants human review to validate the feature design and cross-system integration.

You can customize Macroscope's approvability policy. Learn more.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One convention finding: ManagedAgentRunError now carries good structural attributes, but every wrapping site discards the underlying failure entirely, so no cause survives. Details inline.

Posted via Macroscope — Effect Service Conventions

Comment on lines +67 to +69
reason: Schema.Literals(["thread-not-found", "spawn-failed", "run-not-found", "not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManagedAgentRunError has no cause, and every wrapping site in ManagedCodexExec.ts (getThreadDetailById, getProjectShellById, randomUUIDv4, spawner.spawn, child.kill) maps with () => new ManagedAgentRunError({...}), so the immediate platform/spawn failure and its stack are dropped with no diagnostic left anywhere. Convention here is to keep the structural fields and preserve the real failure as cause (as sibling contract errors such as VcsProcessSpawnError and GitCommandError do).

Suggest adding an optional cause and passing the underlying error at each mapError:

Suggested change
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
cause: Schema.optional(Schema.Defect()),

If the redaction guarantee asserted in ManagedCodexExec.test.ts means the encoded wire payload must stay free of the spawn command, keep the cause server-side instead (e.g. Effect.tapCause(Effect.logError) before the mapError) rather than discarding it.

Posted via Macroscope — Effect Service Conventions

Effect.mapError(
(cause) =>
new ManagedCodexExecInternalError({
reason: "not-owned",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumorchestration/ManagedCodexExec.ts:330

A failure from run.child.kill(...) is reported as not-owned even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through toManagedAgentRunError as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/ManagedCodexExec.ts around line 330:
A failure from `run.child.kill(...)` is reported as `not-owned` even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through `toManagedAgentRunError` as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new/changed Effect service code (ManagedCodexExec.ts, Services/ProviderRuntimeIngestion.ts, ws.ts wiring, contracts). Service definition (inline Context.Service interface, make then layer), environment-based dependency acquisition (ProviderRuntimeIngestionService, ProjectionSnapshotQuery, ChildProcessSpawner), namespace imports, and cause preservation all match the conventions now. One error-modeling issue remains: the reason discriminator does not identify the failing stage.

Posted via Macroscope — Effect Service Conventions

export class ManagedCodexExecInternalError extends Schema.TaggedErrorClass<ManagedCodexExecInternalError>()(
"ManagedCodexExecInternalError",
{
reason: Schema.Literals(["thread-not-found", "spawn-failed", "not-owned"]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reason is this error's stage/operation discriminator and it also becomes the caller-visible ManagedAgentRunError.reason (via toManagedAgentRunError), but four structurally different failures are folded into reasons that describe something else:

  • projection query failure (lines 127, 144) -> thread-not-found, indistinguishable from the genuine missing-thread branches (lines 135, 152)
  • crypto.randomUUIDv4 failure (line 162) -> spawn-failed
  • task.started ingest failure (line 238) -> spawn-failed
  • child.kill() failure (line 330) -> not-owned, so a run that is owned but could not be killed surfaces as Managed agent run failed (not-owned)

Since the message and client behavior are derived from reason, suggest giving each wrapping site a stage-accurate literal (e.g. thread-lookup-failed, agent-id-failed, ingest-failed, cancel-failed) and extending/mapping ManagedAgentRunError.reason in packages/contracts/src/orchestration.ts accordingly, so the caller-visible reason matches the failure that actually occurred.

Posted via Macroscope — Effect Service Conventions

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

This adds managed Codex agent runs across server orchestration, contracts, and the Agents panel. We are not taking this separate managed-agent workflow forward through the current backlog.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Juliusicon@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(agents): surface managed Codex agent runs - #6416

Closed
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar
Closed

feat(agents): surface managed Codex agent runs#6416
Juliusicon wants to merge 7 commits into
pingdotgg:mainfrom
Juliusicon:feature/codex-agent-sidebar

Conversation

@Juliusicon

@JuliusiconJuliusicon commented Aug 13, 2026

Copy link
Copy Markdown

What changed

Adds first-class visibility and lifecycle ownership for Codex agents in T3 Code. Native Codex subagents retain parent/child hierarchy, model, effort, and late-arriving metadata. T3-managed codex exec runs use typed RPC contracts, stable IDs, lifecycle events, exact process-tree cancellation, and sidebar controls.

Why

Raw nested CLI agents were invisible to T3 and could survive supervisor cancellation. Native lifecycle rows also lost hierarchy or metadata under retention and out-of-order event delivery.

Impact

Users can see native and T3-managed Codex agents in the Agents panel, including nested ownership and terminal state. Only T3-managed CLI runs are surfaced; arbitrary external processes are intentionally not discovered by process scanning.

Checks

  • Focused unit/replay tests: 80/80
  • Runtime integration tests: 3/3
  • Server and client-runtime typechecks
  • Targeted lint and formatting
  • git diff --check
  • Final adversarial GPT-5.6 Terra review: PASS

Built with GPT-5.6 Sol through the Codex harness; reviewed with GPT-5.6 Terra.


Note

Medium Risk
Spawns child processes with user prompts and operate-scoped RPC; changes are well-tested but touch orchestration ingestion, Codex event mapping, and cancellation ownership.

Overview
Adds T3-owned codex exec runs with WebSocket RPC (launchManagedCodexExec, cancelManagedAgent), a ManagedCodexExec service that spawns processes and pushes lifecycle events through ingestRuntimeEvent, and operate-scope auth. Launch errors redact prompts from wire payloads.

Improves native Codex collab agents by correlating spawnAgent tool calls to model/effort/parent, emitting collabAgent/metadata for late identity patches, and upserting task-identity:* activities so terminal rows keep hierarchy without reopening. Payloads gain agentSource and cancellationOwner.

Updates the Agents UI and client model with childrenByParentId, nested tree rendering, and a stop control when cancellationOwner === 't3'.

Reviewed by Cursor Bugbot for commit e1f841c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Surface managed Codex agent runs with launch, cancel, and hierarchical UI

  • Adds ManagedCodexExec service that spawns codex exec as a child process, streams stdout/stderr as task.progress events, and emits task.started/task.completed with rich status and summaries.
  • Exposes launchManagedCodexExec and cancelManagedAgent WebSocket RPC endpoints (with orchestration scope authorization) and wires client-side command atoms in createOrchestrationEnvironmentAtoms.
  • Extends the Codex provider adapter to emit collabAgent/metadata events carrying enriched child agent identity (model, effort, parentAgentId), correlated to the originating turn/item.
  • Adds agentSource and cancellationOwner fields to RuntimeSubagent and TaskAgentLinkage, and builds childrenByParentId in AgentPanelModel for non-workflow parent-child relationships.
  • Renders agents as an indented hierarchy in AgentsPanel and shows a stop button for managed agents in active states, dispatching cancelManagedAgent on click.
  • Risk: cancellation relies on SIGTERM with a 3-second force-kill; processes that ignore SIGTERM will be hard-killed after the timeout with no further retry.

Macroscope summarized e1f841c.

@coderabbitai

coderabbitaiBot commented Aug 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c22faf77-495f-493a-b8a5-de4f794f7636

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 13, 2026
Comment on lines 772 to +785
@@ -751,6 +779,10 @@ export function deriveAgentPanelModel({
const list = members.get(agent.parentAgentId) ?? [];
list.push(agent);
members.set(agent.parentAgentId, list);
} else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {
const list = childrenByParentId.get(agent.parentAgentId) ?? [];
list.push(agent);
childrenByParentId.set(agent.parentAgentId, list);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumstate/subagentRuntime.ts:772

Cyclic parent relationships are omitted from directAgents without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The childrenByParentId branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

 const agentIds = new Set(source.map((agent) => agent.id));
+ const parentById = new Map(source.map((agent) => [agent.id, agent.parentAgentId] as const));
for (const agent of source) {
@@
- } else if (agent.parentAgentId !== null && agentIds.has(agent.parentAgentId)) {+ } else if (+ agent.parentAgentId !== null &&+ agentIds.has(agent.parentAgentId) &&+ !(() => {+ const seen = new Set<string>();+ let current: string | null = agent.id;+ while (current !== null && agentIds.has(current)) {+ if (seen.has(current)) return true;+ seen.add(current);+ current = parentById.get(current) ?? null;+ }+ return false;+ })()+ ) {
🤖 Copy this AI Prompt to have your agent fix this:
In file @packages/client-runtime/src/state/subagentRuntime.ts around lines 772-785:
Cyclic parent relationships are omitted from `directAgents` without a render root, so self-parented or mutually parented agents disappear from the panel entirely. The `childrenByParentId` branch only checks whether the parent ID exists; detect cycles while building it and treat cyclic nodes as orphaned roots (or otherwise break the cycle).

collabSpawnMetadata.set(childThreadId, metadata);
}
yield* Ref.set(collabSpawnMetadataRef, collabSpawnMetadata);
const enrichedChildren =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MediumLayers/CodexSessionRuntime.ts:1314

Late spawnAgent metadata for a child-scoped item/started or item/completed notification never reaches ingestion or replay. interceptCollabChildNotification returns at line 1343 before the collabAgent/metadata loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/CodexSessionRuntime.ts around line 1314:
Late `spawnAgent` metadata for a child-scoped `item/started` or `item/completed` notification never reaches ingestion or replay. `interceptCollabChildNotification` returns at line 1343 before the `collabAgent/metadata` loop, so nested-agent rows retain missing hierarchy, model, and effort fields even though the in-memory state is updated. Emit the metadata patch before this early return.

const cyclic = ancestors.has(agent.id);
const nextAncestors = new Set(ancestors).add(agent.id);
return (
<div style={{ paddingLeft: `${Math.min(depth, 6) * 12}px` }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/AgentsPanel.tsx:230

Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded <div> while this line applies 12px * depth again, use a constant per-level padding for nested wrappers.

Suggested change
<divstyle={{paddingLeft: `${Math.min(depth,6)*12}px`}}>
<divstyle={{paddingLeft: depth>0 ? "12px" : "0px"}}>
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/AgentsPanel.tsx around line 230:
Deep agent trees are indented quadratically, so a depth-6 row receives 252px of total padding instead of the intended capped indentation and its content is unnecessarily squeezed or hidden. Because each child is nested inside its parent’s padded `<div>` while this line applies `12px * depth` again, use a constant per-level padding for nested wrappers.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the new ManagedCodexExec service and its contract error. Findings are limited to the service definition shape, construction/layer exports, dependency acquisition, and error modeling.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadpackages/contracts/src/orchestration.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated
Comment threadapps/server/src/orchestration/ManagedCodexExec.ts Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 865817f. Configure here.

Comment threadapps/server/src/provider/Layers/CodexSessionRuntime.ts
@macroscopeapp

macroscopeappBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

4 blocking correctness issues found. This PR introduces a substantial new feature for managed Codex agent runs, including process spawning/cancellation, new RPC endpoints, and UI agent tree management with cancel actions. New capability of this scope warrants human review to validate the feature design and cross-system integration.

You can customize Macroscope's approvability policy. Learn more.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One convention finding: ManagedAgentRunError now carries good structural attributes, but every wrapping site discards the underlying failure entirely, so no cause survives. Details inline.

Posted via Macroscope — Effect Service Conventions

Comment on lines +67 to +69
reason: Schema.Literals(["thread-not-found", "spawn-failed", "run-not-found", "not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManagedAgentRunError has no cause, and every wrapping site in ManagedCodexExec.ts (getThreadDetailById, getProjectShellById, randomUUIDv4, spawner.spawn, child.kill) maps with () => new ManagedAgentRunError({...}), so the immediate platform/spawn failure and its stack are dropped with no diagnostic left anywhere. Convention here is to keep the structural fields and preserve the real failure as cause (as sibling contract errors such as VcsProcessSpawnError and GitCommandError do).

Suggest adding an optional cause and passing the underlying error at each mapError:

Suggested change
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
reason: Schema.Literals(["thread-not-found","spawn-failed","run-not-found","not-owned"]),
threadId: Schema.optional(ThreadId),
agentId: Schema.optional(TrimmedNonEmptyString),
cause: Schema.optional(Schema.Defect()),

If the redaction guarantee asserted in ManagedCodexExec.test.ts means the encoded wire payload must stay free of the spawn command, keep the cause server-side instead (e.g. Effect.tapCause(Effect.logError) before the mapError) rather than discarding it.

Posted via Macroscope — Effect Service Conventions

Effect.mapError(
(cause) =>
new ManagedCodexExecInternalError({
reason: "not-owned",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumorchestration/ManagedCodexExec.ts:330

A failure from run.child.kill(...) is reported as not-owned even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through toManagedAgentRunError as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/ManagedCodexExec.ts around line 330:
A failure from `run.child.kill(...)` is reported as `not-owned` even though ownership was verified immediately above, so process-control failures such as an inability to signal the child are exposed through `toManagedAgentRunError` as ownership denials. Wrap this failure with the cancellation/process-control error reason instead.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new/changed Effect service code (ManagedCodexExec.ts, Services/ProviderRuntimeIngestion.ts, ws.ts wiring, contracts). Service definition (inline Context.Service interface, make then layer), environment-based dependency acquisition (ProviderRuntimeIngestionService, ProjectionSnapshotQuery, ChildProcessSpawner), namespace imports, and cause preservation all match the conventions now. One error-modeling issue remains: the reason discriminator does not identify the failing stage.

Posted via Macroscope — Effect Service Conventions

export class ManagedCodexExecInternalError extends Schema.TaggedErrorClass<ManagedCodexExecInternalError>()(
"ManagedCodexExecInternalError",
{
reason: Schema.Literals(["thread-not-found", "spawn-failed", "not-owned"]),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reason is this error's stage/operation discriminator and it also becomes the caller-visible ManagedAgentRunError.reason (via toManagedAgentRunError), but four structurally different failures are folded into reasons that describe something else:

  • projection query failure (lines 127, 144) -> thread-not-found, indistinguishable from the genuine missing-thread branches (lines 135, 152)
  • crypto.randomUUIDv4 failure (line 162) -> spawn-failed
  • task.started ingest failure (line 238) -> spawn-failed
  • child.kill() failure (line 330) -> not-owned, so a run that is owned but could not be killed surfaces as Managed agent run failed (not-owned)

Since the message and client behavior are derived from reason, suggest giving each wrapping site a stage-accurate literal (e.g. thread-lookup-failed, agent-id-failed, ingest-failed, cancel-failed) and extending/mapping ManagedAgentRunError.reason in packages/contracts/src/orchestration.ts accordingly, so the caller-visible reason matches the failure that actually occurred.

Posted via Macroscope — Effect Service Conventions

@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

This adds managed Codex agent runs across server orchestration, contracts, and the Agents panel. We are not taking this separate managed-agent workflow forward through the current backlog.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL500-999 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Juliusicon@t3dotgg