Skip to content

test#1127

Closed
QyperXit wants to merge 1 commit intopingdotgg:mainfrom
QyperXit:t3code/validate-subagent-worktree-architecture
Closed

test#1127
QyperXit wants to merge 1 commit intopingdotgg:mainfrom
QyperXit:t3code/validate-subagent-worktree-architecture

Conversation

@QyperXit
Copy link

@QyperXit QyperXit commented Mar 16, 2026

test

Note

Add sub-agent skill orchestration with /skill composer command and worktree thread management

  • Introduces a full sub-agent lifecycle: clients dispatch thread.subagent.start via /skill <id> <task> in the composer, the SubagentCoordinator service starts runs, and users can accept reports, open worktree threads, or discard runs from the new SubagentReportCard UI.
  • Adds new orchestration commands and events (thread.subagent-upserted, thread.subagent-start-requested, thread.subagent-cleanup-requested, thread.subagent-report-accepted) with corresponding decider handlers and projector logic in orchestration.ts.
  • Adds a filesystem-backed SkillCatalog service that reads SKILL.md files from ~/.codex/skills, exposes skills via listSkills/getSkillById, and surfaces them in the serverGetConfig WebSocket response.
  • Persists sub-agent run state in a new projection_thread_subagent_runs table (migration 014) and attaches sorted subagentRuns arrays to thread snapshots.
  • Extends GitCore with deleteLocalBranch and makes removeWorktree a no-op for missing paths; forwards developerInstructions through the provider turn pipeline to the Codex manager.
  • Behavioral Change: removeWorktree no longer errors on missing paths or when git reports 'is not a working tree'.
📊 Macroscope summarized aa07df8. 44 files reviewed, 9 issues evaluated, 3 issues filtered, 3 comments posted

🗂️ Filtered Issues

apps/server/src/git/Layers/GitCore.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 1285: Accessing result.failure on a Result.Result type returned by Effect.result will fail at runtime. The Result.Result failure case uses the property error, not failure. This causes a crash when removeWorktree encounters a git error that is not "is not a working tree" - the code at lines 1285, 1293, and 1294 will throw Cannot read properties of undefined (reading 'message') because result.failure is undefined. [ Failed validation ]
apps/server/src/wsServer.test.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 466: In the removeWorktree function in apps/server/src/git/Layers/GitCore.ts (changed in this commit), after calling Effect.result(...), the code accesses result.failure.message on the failure branch. However, Effect.result returns a Result.Result<A, E> whose failure variant has an error property, not failure. Accessing result.failure yields undefined, causing TypeError: Cannot read properties of undefined (reading 'message') at runtime whenever git worktree remove fails. The same incorrect property access (result.failure) appears three times in the error-handling path. The fix is to replace result.failure with result.error. While this bug is in a reference file, it is introduced by this commit and would surface at runtime when the SubagentCoordinator's cleanupResources invokes git.removeWorktree on a failed worktree removal. [ Cross-file consolidated ]
apps/web/src/composer-logic.ts — 1 comment posted, 2 evaluated, 1 filtered
  • line 18: The type ComposerTriggerKind includes "slash-skill" and SLASH_COMMANDS includes "skill", but detectComposerTrigger lacks early-return handling for the completed /skill command. When a user types exactly /skill (no trailing space), the function returns { kind: "slash-command", query: "skill" } instead of { kind: "slash-skill", ... }. This is inconsistent with the /model case (lines 168-175) which returns "slash-model" immediately when commandQuery === "model". Consumers expecting "slash-skill" kind for skill autocomplete triggering won't receive it until a space is typed. [ Out of scope ]

- add subagent run contracts, coordinator, and skill catalog wiring across server orchestration
- persist/project subagent runs and hide subagent threads from normal snapshot thread lists
- add web report card UX for subagent runs and composer integration for report reuse
- harden git/worktree lifecycle with safe missing-worktree cleanup and local branch delete support
@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

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

Run ID: b0409a69-3d71-4ede-b8b7-10c32c3079d6

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Tip

CodeRabbit can suggest fixes for GitHub Check annotations.

Configure the reviews.tools.github-checks setting to adjust the time to wait for GitHub Checks to complete.

@github-actions github-actions bot added size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Mar 16, 2026
@QyperXit QyperXit closed this Mar 16, 2026
@QyperXit QyperXit deleted the t3code/validate-subagent-worktree-architecture branch March 16, 2026 00:42
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aa07df8452

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

projectId: parentThread.projectId,
title: buildSubagentThreadTitle(skill, event.payload.task),
model: parentThread.model,
runtimeMode: parentThread.runtimeMode,

Choose a reason for hiding this comment

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

P1 Badge Force hidden subagent threads to run in full-access mode

Creating the sub-agent thread with runtimeMode: parentThread.runtimeMode breaks /skill when the parent thread is in approval-required mode: hidden sub-agent turns can emit approval/user-input requests, but those threads are intentionally omitted from client snapshots (ProjectionSnapshotQuery filters out threadKind === "subagent"), so users have no UI path to answer them and the run can stall in running indefinitely. Use a non-interactive mode for hidden threads or surface those requests on the parent thread.

Useful? React with 👍 / 👎.

@QyperXit QyperXit restored the t3code/validate-subagent-worktree-architecture branch March 16, 2026 00:53
pr: null,
};

const makeSubagentCoordinator = Effect.gen(function* () {
Copy link
Contributor

Choose a reason for hiding this comment

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

🟠 High Layers/SubagentCoordinator.ts:178

The try/catch in processStartRequested only catches synchronous exceptions, not Effect failures from yield*. When git.createWorktree, orchestrationEngine.dispatch, or upsertRun fail as Effects, the error propagates through the Effect error channel and bypasses the catch block entirely—so cleanup never runs and the run stays stuck without error state. Consider using Effect.catchAll or a similar Effect error handler instead of try/catch to ensure all failure paths execute cleanup and mark the run as failed.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file apps/server/src/subagents/Layers/SubagentCoordinator.ts around line 178:

The `try/catch` in `processStartRequested` only catches synchronous exceptions, not Effect failures from `yield*`. When `git.createWorktree`, `orchestrationEngine.dispatch`, or `upsertRun` fail as Effects, the error propagates through the Effect error channel and bypasses the catch block entirely—so cleanup never runs and the run stays stuck without error state. Consider using Effect.catchAll or a similar Effect error handler instead of try/catch to ensure all failure paths execute cleanup and mark the run as failed.

Evidence trail:
apps/server/src/subagents/Layers/SubagentCoordinator.ts lines 255-378 (REVIEWED_COMMIT) - shows processStartRequested function with try/catch inside Effect.gen and yield* statements inside the try block. Effect-TS/language-service README.md on GitHub (https://github.com/Effect-TS/language-service/blob/main/README.md) - documents `tryCatchInEffectGen` diagnostic that 'Discourages try/catch in Effect generators in favor of Effect error handling'. The same file also uses Effect.catch() at lines 215, 228, 252, 364, 423, 457, 537 showing proper Effect error handling patterns in the codebase.

}

function extractSection(markdown: string, heading: string): string | null {
const pattern = new RegExp(`^##\\s+${heading}\\s*$([\\s\\S]*?)(?=^##\\s+|$)`, "im");
Copy link
Contributor

Choose a reason for hiding this comment

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

🟠 High Layers/SubagentCoordinator.ts:96

The $ inside the lookahead (?=^##\s+|$) matches end-of-line (not end-of-string) because the m flag is set. Since [\s\S]*? is non-greedy, it matches zero characters and then the lookahead immediately succeeds via $ at the end of the heading line. This causes the capture group to always be empty, so extractSection returns null for every heading. Replace $ in the lookahead with (?![\s\S]) to anchor to end-of-string instead of end-of-line.

Suggested change
const pattern = new RegExp(`^##\\s+${heading}\\s*$([\\s\\S]*?)(?=^##\\s+|$)`, "im");
const pattern = new RegExp(`^##\\s+${heading}\\s*$([\\s\\S]*?)(?=^##\\s+|(?![\\s\\S]))`, "im");
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file apps/server/src/subagents/Layers/SubagentCoordinator.ts around line 96:

The `$` inside the lookahead `(?=^##\s+|$)` matches end-of-line (not end-of-string) because the `m` flag is set. Since `[\s\S]*?` is non-greedy, it matches zero characters and then the lookahead immediately succeeds via `$` at the end of the heading line. This causes the capture group to always be empty, so `extractSection` returns `null` for every heading. Replace `$` in the lookahead with `(?![\s\S])` to anchor to end-of-string instead of end-of-line.

Evidence trail:
apps/server/src/subagents/Layers/SubagentCoordinator.ts line 96 (commit REVIEWED_COMMIT) shows the regex pattern: `new RegExp(`^##\\s+${heading}\\s*$([\\s\\S]*?)(?=^##\\s+|$)`, "im")`. The `m` flag enables multiline mode where `$` matches before newlines, not just at end-of-string. JavaScript MDN documentation confirms multiline flag behavior: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/multiline

Copy link
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

}
if (SLASH_COMMANDS.some((command) => command.startsWith(commandQuery.toLowerCase()))) {

When the user types exactly /skill (no trailing space), commandQuery is "skill", which matches the generic SLASH_COMMANDS check on line 176 and returns kind: "slash-command" instead of kind: "slash-skill". This is inconsistent with /model, which has a dedicated check on line 168 that returns kind: "slash-model" immediately. Add an equivalent special case for "skill" before the generic SLASH_COMMANDS check.

       }
+      if (commandQuery.toLowerCase() === "skill") {
+        return {
+          kind: "slash-skill",
+          query: "",
+          rangeStart: lineStart,
+          rangeEnd: cursor,
+        };
+      }
       if (SLASH_COMMANDS.some((command) => command.startsWith(commandQuery.toLowerCase()))) {
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file apps/web/src/composer-logic.ts around lines 175-176:

When the user types exactly `/skill` (no trailing space), `commandQuery` is `"skill"`, which matches the generic `SLASH_COMMANDS` check on line 176 and returns `kind: "slash-command"` instead of `kind: "slash-skill"`. This is inconsistent with `/model`, which has a dedicated check on line 168 that returns `kind: "slash-model"` immediately. Add an equivalent special case for `"skill"` before the generic `SLASH_COMMANDS` check.

Evidence trail:
apps/web/src/composer-logic.ts lines 18, 165-182, 197-205 at REVIEWED_COMMIT. Line 18 shows SLASH_COMMANDS includes 'skill'. Lines 168-174 show special case for 'model' returning 'slash-model'. Line 176 shows generic SLASH_COMMANDS check returning 'slash-command'. Lines 197-205 show skillMatch regex (returning 'slash-skill') is only reached after the generic check, making it unreachable for `/skill` without trailing space.

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

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant