Skip to content

Add provider skill discovery#1905

Merged
juliusmarminge merged 12 commits intomainfrom
t3code/server-provider-skills
Apr 11, 2026
Merged

Add provider skill discovery#1905
juliusmarminge merged 12 commits intomainfrom
t3code/server-provider-skills

Conversation

@juliusmarminge
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge commented Apr 10, 2026

Summary

  • Adds provider skill presentation and slash-command discovery so composer UI can surface provider capabilities more directly.
  • Updates server/provider orchestration and Codex app-server plumbing to carry the new skill metadata through session and turn flows.
  • Refactors several effect service tags and ID constructors to the newer ServiceMap/makeUnsafe patterns for consistency.
  • Adjusts CLI publish/package metadata and related tests to match the new build outputs and config behavior.

Testing

  • Not run
  • Existing unit and integration tests were updated alongside the feature changes
  • Full project checks still need to pass: bun fmt, bun lint, bun typecheck, and bun run test

Note

Medium Risk
Extends the ServerProvider contract and provider health/probing flows to carry new capability metadata, and updates chat composer parsing/rendering and menu ranking logic; regressions could affect provider snapshots or composer input behavior across clients.

Overview
Provider snapshots now include capability metadata: ServerProvider gains slashCommands and skills arrays (with decoding defaults for backward compatibility), and buildServerProvider populates them.

Server-side probing is extended to fill these fields: Claude’s SDK init probe now collects and dedupes slash commands (and caches the combined probe), while Codex switches from account-only probing to probeCodexDiscovery via the app-server JSON-RPC to return both account info and per-CWD skills.

The web composer UI now surfaces provider capabilities: it adds $skill token detection/rendering (Lexical ComposerSkillNode chips with tooltip descriptions), expands slash-command completion to include provider commands, adds skill search/completion, and refactors menu highlighting + ranking using a new shared searchRanking utility (also reused for workspace entry ranking). Tests and fixtures are updated accordingly.

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

Note

Add provider skill discovery and skill/slash-command support in the composer

  • Adds ServerProviderSkill and ServerProviderSlashCommand schemas to the contracts layer; both default to empty arrays when decoding legacy snapshots.
  • Probes the Codex provider via a new probeCodexDiscovery API to return discovered skills alongside account info, and parses Claude Agent SDK initialization commands into normalized slash commands.
  • Introduces a ComposerSkillNode Lexical node that renders inline skill chips with tooltips, and extends splitPromptTextIntoComposerSegments to parse $<name> tokens as skill segments.
  • Extends the composer command menu to show ranked, grouped results for both provider slash commands and skills, with correct /<command> and $<skill> insertion on selection.
  • Extracts a shared searchRanking package (scoreQueryMatch, insertRankedSearchResult, etc.) used by workspace entry search, skill search, and slash command search.
  • Risk: ComposerPromptEditor now requires a skills prop; any caller that does not pass it will get a type error.

Macroscope summarized 016dbfd.

- Probe Codex skills and Claude slash commands during provider checks
- Surface discovered items in server snapshots and composer UI
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 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: 1385ec2d-bc74-4b7b-b23e-c104f25cb89c

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
  • Commit unit tests in branch t3code/server-provider-skills

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

@github-actions github-actions bot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 10, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

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 and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Ref assignments moved to useEffect cause stale reads
    • Moved the three ref assignments (composerMenuOpenRef, composerMenuItemsRef, activeComposerMenuItemRef) back to synchronous render phase by removing the useEffect wrapper, ensuring event handlers always read current values.
  • ✅ Fixed: Exported probeCodexAccount function is now unused
    • Removed the dead probeCodexAccount function from codexAppServer.ts since it has no remaining imports anywhere in the codebase.

Create PR

Or push these changes by commenting:

@cursor push 2d23dae3cc
Preview (2d23dae3cc)
diff --git a/apps/server/src/provider/codexAppServer.ts b/apps/server/src/provider/codexAppServer.ts
--- a/apps/server/src/provider/codexAppServer.ts
+++ b/apps/server/src/provider/codexAppServer.ts
@@ -244,16 +244,3 @@
     });
   });
 }
-
-export async function probeCodexAccount(input: {
-  readonly binaryPath: string;
-  readonly homePath?: string;
-  readonly signal?: AbortSignal;
-}): Promise<CodexAccountSnapshot> {
-  return (
-    await probeCodexDiscovery({
-      ...input,
-      cwd: process.cwd(),
-    })
-  ).account;
-}

diff --git a/apps/web/src/components/chat/ChatComposer.tsx b/apps/web/src/components/chat/ChatComposer.tsx
--- a/apps/web/src/components/chat/ChatComposer.tsx
+++ b/apps/web/src/components/chat/ChatComposer.tsx
@@ -820,11 +820,9 @@
       [composerHighlightedItemId, composerMenuItems],
     );
 
-    useEffect(() => {
-      composerMenuOpenRef.current = composerMenuOpen;
-      composerMenuItemsRef.current = composerMenuItems;
-      activeComposerMenuItemRef.current = activeComposerMenuItem;
-    }, [activeComposerMenuItem, composerMenuItems, composerMenuOpen]);
+    composerMenuOpenRef.current = composerMenuOpen;
+    composerMenuItemsRef.current = composerMenuItems;
+    activeComposerMenuItemRef.current = activeComposerMenuItem;
 
     const nonPersistedComposerImageIdSet = useMemo(
       () => new Set(nonPersistedComposerImageIds),

You can send follow-ups to the cloud agent here.

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp bot commented Apr 10, 2026

Approvability

Verdict: Needs human review

This PR introduces a significant new feature: provider skill and slash command discovery. It adds new user-facing capabilities including skill autocomplete via $ syntax, skill pills in the composer, provider slash commands in the command menu, and supporting search/ranking infrastructure. New features of this scope warrant human review to validate the design and integration.

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

- Map provider slash command hints into the shared contract
- Surface provider command metadata in the chat composer
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

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 and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: skills/list failure rejects entire account probe
    • Changed the skills/list error handler to gracefully fall back to an empty skills array instead of calling fail(), so account probing remains resilient when skills/list is unsupported or errors.

Create PR

Or push these changes by commenting:

@cursor push 26dfbbe0ac
Preview (26dfbbe0ac)
diff --git a/apps/server/src/provider/codexAppServer.ts b/apps/server/src/provider/codexAppServer.ts
--- a/apps/server/src/provider/codexAppServer.ts
+++ b/apps/server/src/provider/codexAppServer.ts
@@ -205,12 +205,7 @@
 
       if (response.id === 2) {
         const errorMessage = readErrorMessage(response);
-        if (errorMessage) {
-          fail(new Error(`skills/list failed: ${errorMessage}`));
-          return;
-        }
-
-        skills = parseCodexSkillsResult(response.result, input.cwd);
+        skills = errorMessage ? [] : parseCodexSkillsResult(response.result, input.cwd);
         maybeResolve();
         return;
       }

You can send follow-ups to the cloud agent here.

cursoragent and others added 3 commits April 10, 2026 22:56
…tire probe

When skills/list returns an error (e.g. on older Codex CLI versions that
don't support it), fall back to an empty skills array instead of calling
fail() which would reject the entire discovery promise and break account
probing.
Co-authored-by: codex <codex@users.noreply.github.com>
- Restore serialized composer skill node state
- Sync skill labels before paint to avoid stale UI
- Keep composer menu refs current during render
@juliusmarminge
Copy link
Copy Markdown
Member Author

@cursor push 26dfbbe

…tire probe

When skills/list returns an error (e.g. on older Codex CLI versions that
don't support it), fall back to an empty skills array instead of calling
fail() which would reject the entire discovery promise and break account
probing.

Applied via @cursor push command
@juliusmarminge juliusmarminge changed the title Add provider skill discovery to Codex sessions Add provider skill discovery Apr 10, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

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 and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Inconsistent field lookup for displayName vs shortDescription
    • Updated displayName lookup to check skill?.displayName first, falling back to display?.displayName, matching the same pattern used for shortDescription.

Create PR

Or push these changes by commenting:

@cursor push 6b028d659a
Preview (6b028d659a)
diff --git a/apps/server/src/provider/codexAppServer.ts b/apps/server/src/provider/codexAppServer.ts
--- a/apps/server/src/provider/codexAppServer.ts
+++ b/apps/server/src/provider/codexAppServer.ts
@@ -64,8 +64,11 @@
           ? { description: nonEmptyTrimmed(skill?.description) }
           : {}),
         ...(nonEmptyTrimmed(skill?.scope) ? { scope: nonEmptyTrimmed(skill?.scope) } : {}),
-        ...(nonEmptyTrimmed(display?.displayName)
-          ? { displayName: nonEmptyTrimmed(display?.displayName) }
+        ...(nonEmptyTrimmed(skill?.displayName) || nonEmptyTrimmed(display?.displayName)
+          ? {
+              displayName:
+                nonEmptyTrimmed(skill?.displayName) ?? nonEmptyTrimmed(display?.displayName),
+            }
           : {}),
         ...(nonEmptyTrimmed(skill?.shortDescription) || nonEmptyTrimmed(display?.shortDescription)
           ? {

You can send follow-ups to the cloud agent here.

- Introduced a new scoring mechanism for workspace entries that prioritizes exact basename matches over broader path matches.
- Updated the search logic to utilize shared ranking functions for improved performance and maintainability.
- Added a test case to validate the new ranking behavior for exact matches in workspace entries.
- Removed deprecated functions related to scoring and ranking to streamline the codebase.
@github-actions github-actions bot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 10, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

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 and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Callback recreated on every keystroke causing unnecessary re-renders
    • Replaced the prompt state variable with promptRef.current in the setPromptFromTraits callback and removed prompt from the dependency array, restoring the stable ref-based pattern that prevents callback recreation on every keystroke.

Create PR

Or push these changes by commenting:

@cursor push aadef2980e
Preview (aadef2980e)
diff --git a/apps/web/src/components/chat/ChatComposer.tsx b/apps/web/src/components/chat/ChatComposer.tsx
--- a/apps/web/src/components/chat/ChatComposer.tsx
+++ b/apps/web/src/components/chat/ChatComposer.tsx
@@ -868,7 +868,8 @@
     // ------------------------------------------------------------------
     const setPromptFromTraits = useCallback(
       (nextPrompt: string) => {
-        if (nextPrompt === prompt) {
+        const currentPrompt = promptRef.current;
+        if (nextPrompt === currentPrompt) {
           scheduleComposerFocus();
           return;
         }
@@ -879,7 +880,7 @@
         setComposerTrigger(detectComposerTrigger(nextPrompt, nextPrompt.length));
         scheduleComposerFocus();
       },
-      [composerDraftTarget, prompt, promptRef, scheduleComposerFocus, setComposerDraftPrompt],
+      [composerDraftTarget, promptRef, scheduleComposerFocus, setComposerDraftPrompt],
     );
 
     const providerTraitsMenuContent = renderProviderTraitsMenuContent({

You can send follow-ups to the cloud agent here.

Co-authored-by: codex <codex@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

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 and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Double-lowercasing in shared scoring utility is redundant
    • Removed the redundant .trim().toLowerCase() calls inside scoreQueryMatch since all callers already pass pre-normalized inputs, replacing them with a direct destructure and a JSDoc contract documenting the pre-normalization requirement.

Create PR

Or push these changes by commenting:

@cursor push 20f5a4b15c
Preview (20f5a4b15c)
diff --git a/packages/shared/src/searchRanking.ts b/packages/shared/src/searchRanking.ts
--- a/packages/shared/src/searchRanking.ts
+++ b/packages/shared/src/searchRanking.ts
@@ -77,6 +77,12 @@
   return bestIndex;
 }
 
+/**
+ * Scores how well `value` matches `query` using tiered match strategies.
+ *
+ * **Expects pre-normalized inputs**: both `value` and `query` must already be
+ * trimmed and lowercased (e.g. via {@link normalizeSearchQuery}).
+ */
 export function scoreQueryMatch(input: {
   value: string;
   query: string;
@@ -87,8 +93,7 @@
   fuzzyBase?: number;
   boundaryMarkers?: readonly string[];
 }): number | null {
-  const value = input.value.trim().toLowerCase();
-  const query = input.query.trim().toLowerCase();
+  const { value, query } = input;
 
   if (!value || !query) {
     return null;

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit b0488e2. Configure here.

cursoragent and others added 2 commits April 10, 2026 23:54
All callers already pass pre-normalized (trimmed and lowercased) inputs,
so the internal .trim().toLowerCase() calls were redundant O(n) string
operations allocating unnecessary copies on every candidate per keystroke.

Replace with a destructured read and a JSDoc contract stating that inputs
must be pre-normalized.
Co-authored-by: codex <codex@users.noreply.github.com>
@juliusmarminge juliusmarminge changed the title Add provider skill discovery Add provider skill discovery Apr 11, 2026
@juliusmarminge
Copy link
Copy Markdown
Member Author

@cursor push 20f5a4b

All callers already pass pre-normalized (trimmed and lowercased) inputs,
so the internal .trim().toLowerCase() calls were redundant O(n) string
operations allocating unnecessary copies on every candidate per keystroke.

Replace with a destructured read and a JSDoc contract stating that inputs
must be pre-normalized.

Applied via @cursor push command
@juliusmarminge juliusmarminge merged commit 58e5f71 into main Apr 11, 2026
12 checks passed
@juliusmarminge juliusmarminge deleted the t3code/server-provider-skills branch April 11, 2026 00:19
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:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants