Skip to content

feat(codex): preserve bounded custom prompts - #912

Merged
chuks-qua merged 1 commit into
mainfrom
feat/896-preserve-codex-custom-prompts
Jul 21, 2026
Merged

chuks-qua merged 1 commit into
mainfrom
feat/896-preserve-codex-custom-prompts

Conversation

@chuks-qua

@chuks-qua chuks-qua commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

What

Add first-class support for Codex custom prompts from CODEX_HOME/prompts, with bounded loading and source-aware invocation.

Why

Mcode previously mixed Codex custom prompts into its general skill scan. That lost prompt identity, delayed picker updates, and could invoke a same-named skill or project command through the wrong path.

Key Changes

  • Load direct .md prompt files from the same Codex home used to launch the provider, with entry, file-count, file-size, and diagnostic limits.
  • Parse prompt descriptions, retain the last good catalog snapshot, and isolate invalid files through per-file diagnostics.
  • Refresh the picker when it opens and reconcile added, changed, and removed entries without closing it.
  • Preserve capability identity through the composer and provider so same-named skills, custom prompts, and project commands remain distinct.
  • Refresh /prompts:* before manual invocation and apply the existing prompt argument expansion.
  • Remove ~/.codex/prompts from the general skill scanner and watcher.

Verification

  • Monorepo typecheck passed in all five packages, and lint passed.
  • Focused conflict coverage passed: 83 server tests, 54 web tests, and 4 contract tests.
  • The Electron app refreshed an open prompt picker from the cached v3 prompt to the edited v4 prompt without closing the picker.
  • The full server suite passed 197 of 198 files and 1,885 of 1,886 tests. One unrelated TurnFileTracker test reached its five-second timeout under full-suite load, then passed in a 45-test focused rerun.

Closes #896

@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@chuks-qua, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 26b6ccc3-63f3-4bf5-bd60-1580de4a0103

📥 Commits

Reviewing files that changed from the base of the PR and between 6a431f7 and ade6e8b.

📒 Files selected for processing (29)
  • apps/server/src/container.ts
  • apps/server/src/providers/codex/__tests__/codex-provider-first-turn.test.ts
  • apps/server/src/providers/codex/__tests__/codex-provider-permission.test.ts
  • apps/server/src/providers/codex/__tests__/codex-provider-subagent-turn.test.ts
  • apps/server/src/providers/codex/codex-prompt.ts
  • apps/server/src/providers/codex/codex-provider.ts
  • apps/server/src/services/__tests__/codex-catalog-service.test.ts
  • apps/server/src/services/__tests__/codex-custom-prompt-service.test.ts
  • apps/server/src/services/codex-catalog-service.ts
  • apps/server/src/services/codex-custom-prompt-service.ts
  • apps/server/src/services/provider-catalog-service.test.ts
  • apps/server/src/services/provider-catalog-service.ts
  • apps/server/src/services/skill-service.test.ts
  • apps/server/src/services/skill-service.ts
  • apps/server/src/services/skill-watcher-service.test.ts
  • apps/server/src/services/skill-watcher-service.ts
  • apps/server/src/transport/provider-catalog.test.ts
  • apps/server/src/transport/provider-catalog.ts
  • apps/server/src/transport/ws-router.ts
  • apps/server/src/transport/ws-router.validation.test.ts
  • apps/web/src/__tests__/slash-command-node.test.ts
  • apps/web/src/__tests__/slash-command.test.ts
  • apps/web/src/components/chat/Composer.tsx
  • apps/web/src/components/chat/lexical/SlashCommandNode.tsx
  • apps/web/src/components/chat/lexical/SlashCommandPlugin.tsx
  • apps/web/src/components/chat/lexical/cursor-utils.ts
  • apps/web/src/components/chat/useSlashCommand.ts
  • packages/contracts/src/models/__tests__/mention.test.ts
  • packages/contracts/src/models/mention.ts
📝 Walkthrough

Walkthrough

Adds bounded Codex custom-prompt discovery and catalog integration, identity-aware prompt/Skill resolution, partial catalog reconciliation, and capability-identity persistence through the web slash-command pipeline.

Changes

Codex prompt compatibility flow

Layer / File(s) Summary
Bounded prompt discovery and catalog integration
apps/server/src/services/codex-custom-prompt-service.ts, apps/server/src/services/codex-catalog-service.ts, apps/server/src/container.ts, apps/server/src/services/__tests__/*
Discovers direct Codex prompt files with bounded reads, diagnostics, caching, refresh coalescing, and catalog availability flags.
Catalog transport and partial reconciliation
apps/server/src/transport/*, apps/server/src/services/provider-catalog-service.*, apps/server/src/services/skill-service.*, apps/server/src/services/skill-watcher-service.*
Includes prompts in Codex snapshots, distinguishes custom prompts from similarly named commands, caps diagnostics, and reconciles confirmed capability kinds.
Identity-aware Codex invocation
apps/server/src/providers/codex/*
Uses command mentions and capability identities to resolve colliding Skills and custom prompts, refreshing prompts for prompts:* invocations.
Slash-command identity propagation and picker reconciliation
apps/web/src/components/chat/*, apps/web/src/__tests__/*, packages/contracts/src/models/*
Persists validated capability identities in slash-command nodes and mentions, and retains picker entries and selection across catalog updates.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

  • #896 — Directly covers the bounded Codex custom-prompt adapter implemented here.
  • #890 — Defines the broader Codex capability-catalog architecture extended by this change.

Possibly related PRs

Poem

A rabbit found prompts in a bounded moonlit den,
Kept Skills and names from colliding again.
Identity hopped through each command node,
Fresh catalog paths were carefully shown.
“Refresh!” cried the bunny, ears held high—
Prompts now persist as the pickers fly.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The new Claude skills watch root in skill-watcher-service.ts is unrelated to the Codex custom-prompt adapter scope. Remove the Claude watcher change or move it to a separate PR focused on cross-provider skill roots.
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement the bounded Codex custom-prompt adapter, stable identity handling, prompt expansion, diagnostics, and test coverage required by #896.
Title check ✅ Passed The title is concise and accurately reflects the main change: bounded Codex custom prompt support.
Description check ✅ Passed The description covers What, Why, Key Changes, and Verification, closely matching the template.

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.

@chuks-qua
chuks-qua force-pushed the feat/896-preserve-codex-custom-prompts branch from fbb453c to bd089fa Compare July 21, 2026 00:59
@chuks-qua
chuks-qua force-pushed the feat/896-preserve-codex-custom-prompts branch from bd089fa to ade6e8b Compare July 21, 2026 01:03
@chuks-qua

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 46 minutes.

@chuks-qua
chuks-qua merged commit 5b267c2 into main Jul 21, 2026
9 of 10 checks passed
@chuks-qua
chuks-qua deleted the feat/896-preserve-codex-custom-prompts branch July 21, 2026 01:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/server/src/transport/provider-catalog.ts (1)

58-67: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Centralize the diagnostics cap instead of duplicating the 100 literal.

codex-catalog-service.ts independently hardcodes .slice(0, 100) twice for the same concept. Defining PROVIDER_CATALOG_MAX_DIAGNOSTICS here only locally means three independent sources of truth for the same cap; consider hoisting it into @mcode/contracts alongside PROVIDER_CATALOG_MAX_ENTRIES and friends, and importing it in both files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/transport/provider-catalog.ts` around lines 58 - 67, Move
PROVIDER_CATALOG_MAX_DIAGNOSTICS from provider-catalog.ts into `@mcode/contracts`
alongside the existing catalog limits, then import and reuse that shared
constant in both appendDiagnostic and the two codex-catalog-service.ts slice
calls, removing the duplicated literal 100.
apps/server/src/services/codex-catalog-service.ts (1)

423-429: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Consider catching promptRefresh to prevent masking catalog errors.

If this.customPromptService.refresh() were to reject, await promptRefresh in the catch block below would throw the exact same error. This would bypass the generation of the fallback catalog snapshot and potentially mask the original client.listSkills error.

While prompt discovery may currently suppress its own errors, appending a .catch guarantees that the main catalog fallback safely completes.

♻️ Proposed fix
-    const promptRefresh = this.customPromptService.refresh();
+    const promptRefresh = this.customPromptService.refresh().catch((err) => ({
+      prompts: [],
+      diagnostics: [{ severity: "warning", code: "source-unavailable", message: String(err) }],
+      available: false,
+    }));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/services/codex-catalog-service.ts` around lines 423 - 429,
Update the promptRefresh initialization in the catalog refresh method to catch
and suppress refresh failures, ensuring the promise resolves safely. Keep the
existing Promise.all flow and fallback catalog handling unchanged so
client.listSkills or listPlugins errors still reach the original catch path
without being masked by awaiting promptRefresh.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/server/src/services/codex-custom-prompt-service.ts`:
- Around line 258-271: Update the non-ENOENT catch block in the prompt-loading
method to preserve existing diagnostics collected before fileSystem.entries()
failed, appending the source-unavailable warning instead of replacing the
diagnostics array. Keep already-collected prompts and the available: false
result unchanged.

---

Nitpick comments:
In `@apps/server/src/services/codex-catalog-service.ts`:
- Around line 423-429: Update the promptRefresh initialization in the catalog
refresh method to catch and suppress refresh failures, ensuring the promise
resolves safely. Keep the existing Promise.all flow and fallback catalog
handling unchanged so client.listSkills or listPlugins errors still reach the
original catch path without being masked by awaiting promptRefresh.

In `@apps/server/src/transport/provider-catalog.ts`:
- Around line 58-67: Move PROVIDER_CATALOG_MAX_DIAGNOSTICS from
provider-catalog.ts into `@mcode/contracts` alongside the existing catalog limits,
then import and reuse that shared constant in both appendDiagnostic and the two
codex-catalog-service.ts slice calls, removing the duplicated literal 100.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7fc08744-a087-4d0b-9c3e-44b10314e2d8

📥 Commits

Reviewing files that changed from the base of the PR and between 6a431f7 and bd089fa.

📒 Files selected for processing (29)
  • apps/server/src/container.ts
  • apps/server/src/providers/codex/__tests__/codex-provider-first-turn.test.ts
  • apps/server/src/providers/codex/__tests__/codex-provider-permission.test.ts
  • apps/server/src/providers/codex/__tests__/codex-provider-subagent-turn.test.ts
  • apps/server/src/providers/codex/codex-prompt.ts
  • apps/server/src/providers/codex/codex-provider.ts
  • apps/server/src/services/__tests__/codex-catalog-service.test.ts
  • apps/server/src/services/__tests__/codex-custom-prompt-service.test.ts
  • apps/server/src/services/codex-catalog-service.ts
  • apps/server/src/services/codex-custom-prompt-service.ts
  • apps/server/src/services/provider-catalog-service.test.ts
  • apps/server/src/services/provider-catalog-service.ts
  • apps/server/src/services/skill-service.test.ts
  • apps/server/src/services/skill-service.ts
  • apps/server/src/services/skill-watcher-service.test.ts
  • apps/server/src/services/skill-watcher-service.ts
  • apps/server/src/transport/provider-catalog.test.ts
  • apps/server/src/transport/provider-catalog.ts
  • apps/server/src/transport/ws-router.ts
  • apps/server/src/transport/ws-router.validation.test.ts
  • apps/web/src/__tests__/slash-command-node.test.ts
  • apps/web/src/__tests__/slash-command.test.ts
  • apps/web/src/components/chat/Composer.tsx
  • apps/web/src/components/chat/lexical/SlashCommandNode.tsx
  • apps/web/src/components/chat/lexical/SlashCommandPlugin.tsx
  • apps/web/src/components/chat/lexical/cursor-utils.ts
  • apps/web/src/components/chat/useSlashCommand.ts
  • packages/contracts/src/models/__tests__/mention.test.ts
  • packages/contracts/src/models/mention.ts
💤 Files with no reviewable changes (1)
  • apps/server/src/services/skill-watcher-service.ts

Comment on lines +258 to +271
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
return { prompts: [], diagnostics: [], available: true };
}
return {
prompts,
diagnostics: [{
severity: "warning",
code: "source-unavailable",
message: "The effective Codex custom prompt directory could not be read.",
}],
available: false,
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Directory-level failure discards already-collected per-file diagnostics.

If fileSystem.entries() throws after some files were already processed (and diagnosed), prompts gathered so far are preserved but the earlier diagnostics entries are replaced wholesale by a single source-unavailable diagnostic, losing per-file context for files already inspected in this refresh.

🩹 Proposed fix to preserve earlier diagnostics
     return {
       prompts,
-      diagnostics: [{
-        severity: "warning",
-        code: "source-unavailable",
-        message: "The effective Codex custom prompt directory could not be read.",
-      }],
+      diagnostics: [
+        ...diagnostics,
+        {
+          severity: "warning",
+          code: "source-unavailable",
+          message: "The effective Codex custom prompt directory could not be read.",
+        },
+      ].slice(0, CODEX_CUSTOM_PROMPT_MAX_DIAGNOSTICS),
       available: false,
     };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
return { prompts: [], diagnostics: [], available: true };
}
return {
prompts,
diagnostics: [{
severity: "warning",
code: "source-unavailable",
message: "The effective Codex custom prompt directory could not be read.",
}],
available: false,
};
}
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
return { prompts: [], diagnostics: [], available: true };
}
return {
prompts,
diagnostics: [
...diagnostics,
{
severity: "warning",
code: "source-unavailable",
message: "The effective Codex custom prompt directory could not be read.",
},
].slice(0, CODEX_CUSTOM_PROMPT_MAX_DIAGNOSTICS),
available: false,
};
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/services/codex-custom-prompt-service.ts` around lines 258 -
271, Update the non-ENOENT catch block in the prompt-loading method to preserve
existing diagnostics collected before fileSystem.entries() failed, appending the
source-unavailable warning instead of replacing the diagnostics array. Keep
already-collected prompts and the available: false result unchanged.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: preserve Codex custom prompts with a bounded adapter

1 participant