Skip to content

feat(chat): add Claude Code as local chat provider#2668

Open
vibegui wants to merge 12 commits intomainfrom
vibegui/claude-code-chat
Open

feat(chat): add Claude Code as local chat provider#2668
vibegui wants to merge 12 commits intomainfrom
vibegui/claude-code-chat

Conversation

@vibegui
Copy link
Contributor

@vibegui vibegui commented Mar 11, 2026

CleanShot 2026-03-12 at 19 19 20 CleanShot 2026-03-12 at 19 20 09

Summary

  • When running locally with Claude Code installed, detects it via Bun.which("claude") and offers it as a model option in the chat UI
  • Routes messages through the Claude Agent SDK subprocess instead of OpenRouter — uses local Claude auth (no API key needed)
  • Adds "Claude Code" entry with "Local" badge at the top of the model selector (opt-in, not auto-selected)
  • Handles edge cases: no OpenRouter connection, empty model list, abort/cancellation

Changes

  • apps/mesh/src/api/routes/auth.tsclaudeCodeAvailable in AuthConfig
  • apps/mesh/src/api/routes/decopilot/claude-code-provider.ts — New SDK adapter (stream_event + assistant message handling)
  • apps/mesh/src/api/routes/decopilot/routes.ts — Fork stream handler for claude-code sentinel
  • apps/mesh/src/api/routes/decopilot/schemas.ts — Accept claude-code provider
  • apps/mesh/src/web/components/chat/select-model.tsx — Claude Code UI entry + guards
  • apps/mesh/src/web/components/chat/context.tsx — Handle claude-code connectionId in model state

Test plan

  • Start dev server locally with Claude Code installed (which claude)
  • Open chat UI — model selector should show "Claude Code" with "Local" badge
  • Select Claude Code and send a message — should stream response
  • Open model selector dialog — should not error when no OpenRouter connection exists
  • Test switching between Claude Code and OpenRouter models
  • Test cancellation mid-stream

🤖 Generated with Claude Code


Summary by cubic

Adds Claude Code as a local chat provider (Opus/Sonnet/Haiku) streamed via @anthropic-ai/claude-agent-sdk, plus a Connect Studio flow with per‑connection cards for one‑click setup of Mesh tools and GitHub MCP. Auto‑wires the MCP endpoint with a short‑lived API key during Claude Code chats and skips org model permissions for this local provider.

  • New Features

    • Local provider: static claude-code:* models in the factory/registry; server routes by models.thinking.provider === "claude-code"; /config exposes claudeCodeAvailable.
    • Streaming via @anthropic-ai/claude-agent-sdk with cancel, start/finish-step markers, real‑time thinking/text deltas (includePartialMessages), assistant text extraction, and usage/cost passthrough.
    • Connect Studio: status/POST/DELETE endpoints; auto‑registers deco-studio MCP; modal with per‑connection cards (Claude Code and GitHub via local gh token), auth info, connect/disconnect, and a sidebar entry.
  • Bug Fixes

    • Unified model/provider flow; fixed model selector init and tiering for synthetic claude-code models; handled empty connections and replaced connectionId sentinel with provider detection.
    • Removed Cursor; added CLI timeouts; small UI fixes (refresh icon, onboarding card), logos/types include claude-code.
    • Connect flow in org settings now supports one‑click Claude Code; better status/loading states.
    • Fixed GitHub status detection in Connect Studio (via gh auth status + gh api user) and compacted connection cards.

Written for commit fd36ce0. Summary will update on new commits.

@github-actions
Copy link
Contributor

🧪 Benchmark

Should we run the Virtual MCP strategy benchmark for this PR?

React with 👍 to run the benchmark.

Reaction Action
👍 Run quick benchmark (10 & 128 tools)

Benchmark will run on the next push after you react.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 11, 2026

Release Options

Should a new version be published when this PR is merged?

React with an emoji to vote on the release type:

Reaction Type Next Version
👍 Prerelease 2.165.2-alpha.1
🎉 Patch 2.165.2
❤️ Minor 2.166.0
🚀 Major 3.0.0

Current version: 2.165.1

Deployment

  • Deploy to production (triggers ArgoCD sync after Docker image is published)

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/mesh/src/api/routes/decopilot/routes.ts">

<violation number="1" location="apps/mesh/src/api/routes/decopilot/routes.ts:297">
P2: Validate Claude Code availability before starting the run/saving messages; currently an unavailable provider still creates a failed run and persists the user message.</violation>
</file>

<file name="apps/mesh/src/api/routes/decopilot/claude-code-provider.ts">

<violation number="1" location="apps/mesh/src/api/routes/decopilot/claude-code-provider.ts:33">
P1: Multi-turn conversation context is lost. `messagesToPrompt` strips the `role` from all messages and concatenates their text, so prior assistant replies are indistinguishable from user messages. Add role prefixes (e.g., `User:` / `Assistant:`) or only pass the last user message as the prompt.</violation>

<violation number="2" location="apps/mesh/src/api/routes/decopilot/claude-code-provider.ts:215">
P1: Text will be duplicated in the output. The `stream_event` handler already writes incremental text deltas, but the `assistant` handler then re-emits the full completed text from `message.message.content`. Remove the text extraction from the `assistant` case since it's already delivered via stream events, or gate it so it only fires when no stream events were received.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

/**
* Convert chat messages to a prompt string for the Claude Agent SDK.
*/
function messagesToPrompt(messages: ChatMessage[]): string {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 11, 2026

Choose a reason for hiding this comment

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

P1: Multi-turn conversation context is lost. messagesToPrompt strips the role from all messages and concatenates their text, so prior assistant replies are indistinguishable from user messages. Add role prefixes (e.g., User: / Assistant:) or only pass the last user message as the prompt.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/api/routes/decopilot/claude-code-provider.ts, line 33:

<comment>Multi-turn conversation context is lost. `messagesToPrompt` strips the `role` from all messages and concatenates their text, so prior assistant replies are indistinguishable from user messages. Add role prefixes (e.g., `User:` / `Assistant:`) or only pass the last user message as the prompt.</comment>

<file context>
@@ -0,0 +1,277 @@
+/**
+ * Convert chat messages to a prompt string for the Claude Agent SDK.
+ */
+function messagesToPrompt(messages: ChatMessage[]): string {
+  const parts: string[] = [];
+
</file context>
Fix with Cubic

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/mesh/src/api/routes/decopilot/routes.ts">

<violation number="1" location="apps/mesh/src/api/routes/decopilot/routes.ts:315">
P2: Guard the Claude Code sentinel model id before forwarding it to the SDK; otherwise restored sessions can pass `"claude-code"` as a concrete model value.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

vibegui and others added 3 commits March 12, 2026 16:35
When running locally with Claude Code installed, offer it as a model
option in the chat UI. Routes messages through the Claude Agent SDK
subprocess instead of OpenRouter, using the user's local Claude auth.

- Add `claudeCodeAvailable` to AuthConfig (detected via Bun.which)
- New claude-code-provider adapter wrapping @anthropic-ai/claude-agent-sdk
- Fork decopilot stream endpoint for claude-code connectionId sentinel
- Add Claude Code entry in model selector with "Local" badge
- Handle empty connections gracefully when only Claude Code is available

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract text from assistant message content blocks (SDK emits full
  messages, not stream_event deltas)
- Add start-step/finish-step markers for proper AI SDK status tracking
- Add Opus/Sonnet/Haiku model variants in the selector
- Pass selected model to SDK query options
- Fix selectedConnectionId initialization to skip claude-code sentinel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Connect Studio modal with one-click Claude Code / Cursor setup
- Server endpoint generates API key and runs `claude mcp add-json` or writes Cursor config
- Status endpoint checks if IDE is already connected
- Auto-wire MCP endpoint when using Claude Code as local chat provider
- Support mcpHeaders in Claude Agent SDK http transport

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vibegui vibegui force-pushed the vibegui/claude-code-chat branch from 9b795cb to 8002f8b Compare March 12, 2026 19:36
vibegui and others added 2 commits March 12, 2026 16:40
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…boarding

- Fix missing closing brace in model selector JSX
- Fix AiProviderModel type mismatches for Claude Code synthetic models
- Remove stale useAllowedModels import
- Add Claude Code card with "Local" badge to the AI provider onboarding screen
- Card shows connection status and one-click connect via CLI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/mesh/src/web/components/chat/select-model.tsx">

<violation number="1" location="apps/mesh/src/web/components/chat/select-model.tsx:1070">
P1: Selecting a Claude Code model never tags the request with `connectionId: "claude-code"`, so the backend will not take the local Claude Code streaming path.</violation>
</file>

<file name="apps/mesh/src/web/components/chat/no-llm-binding-empty-state.tsx">

<violation number="1" location="apps/mesh/src/web/components/chat/no-llm-binding-empty-state.tsx:57">
P2: Also guard the in-flight state here so repeated clicks do not trigger duplicate connect requests.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

vibegui and others added 2 commits March 12, 2026 19:19
Remove custom Claude Code UI from model selector and onboarding.
Claude Code now uses the same ConnectionModelList → groupByTier →
ModelTierSection pipeline as every other provider. Models are returned
from factory.ts via a static list, classified into tiers via prefixes,
and server detection uses thinking.provider instead of broken
connectionId field.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove Cursor support (not working), show Claude Code auth info
(email, org, subscription) when connected, add disconnect button,
and fix refresh icon positioning. Add timeouts to all CLI spawns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 8 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/mesh/src/api/routes/decopilot/routes.ts">

<violation number="1" location="apps/mesh/src/api/routes/decopilot/routes.ts:158">
P1: Don't trust `models.thinking.provider` to decide whether to skip model-permission checks.</violation>

<violation number="2" location="apps/mesh/src/api/routes/decopilot/routes.ts:321">
P2: This passes `credentialId` into a `connectionId` field, so Claude Code responses emit the wrong metadata shape for follow-up requests.</violation>
</file>

<file name="apps/mesh/src/web/components/settings-modal/pages/org-ai-providers.tsx">

<violation number="1" location="apps/mesh/src/web/components/settings-modal/pages/org-ai-providers.tsx:334">
P2: Gate the Claude Code connect path on actual CLI availability; right now it can create a unusable "connected" provider on servers where Claude Code is unavailable.</violation>
</file>

<file name="apps/mesh/src/ai-providers/factory.ts">

<violation number="1" location="apps/mesh/src/ai-providers/factory.ts:8">
P2: Keep the Claude Code model variants in one shared source of truth; this duplicate list can drift from the runtime SDK mapping.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

organization.id,
ctx.auth.user?.role,
);
const isClaudeCode = models.thinking.provider === "claude-code";
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 12, 2026

Choose a reason for hiding this comment

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

P1: Don't trust models.thinking.provider to decide whether to skip model-permission checks.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/api/routes/decopilot/routes.ts, line 158:

<comment>Don't trust `models.thinking.provider` to decide whether to skip model-permission checks.</comment>

<file context>
@@ -155,7 +155,7 @@ export function createDecopilotRoutes(deps: DecopilotDeps) {
       }
 
-      const isClaudeCode = models.connectionId === "claude-code";
+      const isClaudeCode = models.thinking.provider === "claude-code";
 
       // 2. Check model permissions (skip for Claude Code — uses local auth)
</file context>
Fix with Cubic

if (isActive || isClaudeCodePending) return;
setIsClaudeCodePending(true);
try {
await client.callTool({
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 12, 2026

Choose a reason for hiding this comment

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

P2: Gate the Claude Code connect path on actual CLI availability; right now it can create a unusable "connected" provider on servers where Claude Code is unavailable.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/settings-modal/pages/org-ai-providers.tsx, line 334:

<comment>Gate the Claude Code connect path on actual CLI availability; right now it can create a unusable "connected" provider on servers where Claude Code is unavailable.</comment>

<file context>
@@ -322,12 +322,42 @@ export function ProviderCard({
+    if (isActive || isClaudeCodePending) return;
+    setIsClaudeCodePending(true);
+    try {
+      await client.callTool({
+        name: "AI_PROVIDER_KEY_CREATE",
+        arguments: {
</file context>
Fix with Cubic

import { PROVIDERS } from "./registry";

/** Static model list for the Claude Code local provider. */
const CLAUDE_CODE_MODEL_LIST: ModelInfo[] = [
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 12, 2026

Choose a reason for hiding this comment

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

P2: Keep the Claude Code model variants in one shared source of truth; this duplicate list can drift from the runtime SDK mapping.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/ai-providers/factory.ts, line 8:

<comment>Keep the Claude Code model variants in one shared source of truth; this duplicate list can drift from the runtime SDK mapping.</comment>

<file context>
@@ -4,6 +4,40 @@ import type { ModelListCache } from "./model-list-cache";
 import { PROVIDERS } from "./registry";
 
+/** Static model list for the Claude Code local provider. */
+const CLAUDE_CODE_MODEL_LIST: ModelInfo[] = [
+  {
+    providerId: "claude-code",
</file context>
Fix with Cubic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/mesh/src/api/routes/decopilot/routes.ts">

<violation number="1" location="apps/mesh/src/api/routes/decopilot/routes.ts:875">
P2: Use `getUserId(ctx)` here instead of reading `ctx.auth.user` directly; otherwise API-key-authenticated requests are rejected by the new Connect Studio endpoints.

(Based on your team's feedback about using `getUserId` for mixed user/API-key auth.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/mesh/src/web/components/connect-studio-modal.tsx">

<violation number="1" location="apps/mesh/src/web/components/connect-studio-modal.tsx:83">
P1: This disconnect flow reports success without revoking the generated full-access API key, so Claude Code access persists after “Disconnect”.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

setDisconnecting(true);
try {
const res = await fetch(`/api/${org.slug}/decopilot/connect-studio`, {
method: "DELETE",
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 12, 2026

Choose a reason for hiding this comment

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

P1: This disconnect flow reports success without revoking the generated full-access API key, so Claude Code access persists after “Disconnect”.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/connect-studio-modal.tsx, line 83:

<comment>This disconnect flow reports success without revoking the generated full-access API key, so Claude Code access persists after “Disconnect”.</comment>

<file context>
@@ -29,101 +35,70 @@ function useConnectStatus(org: { slug: string }) {
+    setDisconnecting(true);
+    try {
+      const res = await fetch(`/api/${org.slug}/decopilot/connect-studio`, {
+        method: "DELETE",
+      });
+      if (!res.ok) {
</file context>
Fix with Cubic


app.delete("/:org/decopilot/connect-studio", async (c) => {
const ctx = c.get("meshContext");
if (!ctx.auth?.user?.id) {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 12, 2026

Choose a reason for hiding this comment

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

P2: Use getUserId(ctx) here instead of reading ctx.auth.user directly; otherwise API-key-authenticated requests are rejected by the new Connect Studio endpoints.

(Based on your team's feedback about using getUserId for mixed user/API-key auth.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/api/routes/decopilot/routes.ts, line 875:

<comment>Use `getUserId(ctx)` here instead of reading `ctx.auth.user` directly; otherwise API-key-authenticated requests are rejected by the new Connect Studio endpoints.

(Based on your team's feedback about using `getUserId` for mixed user/API-key auth.) </comment>

<file context>
@@ -799,61 +830,80 @@ export function createDecopilotRoutes(deps: DecopilotDeps) {
+
+  app.delete("/:org/decopilot/connect-studio", async (c) => {
+    const ctx = c.get("meshContext");
+    if (!ctx.auth?.user?.id) {
+      throw new HTTPException(401, { message: "Authentication required" });
+    }
</file context>
Fix with Cubic

vibegui and others added 3 commits March 12, 2026 19:38
Handle thinking_delta events from the Claude Agent SDK to stream
reasoning content in real-time. Track content block types to route
thinking vs text deltas correctly. Prevent duplicate text from
assistant message fallback when stream events are available.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Refactor Connect Studio modal to show each connection as a self-contained
card with its own connect/disconnect buttons. Add GitHub connection that
uses the local `gh` CLI token to register GitHub's MCP in Claude Code.

Also enable `includePartialMessages` in the Claude Agent SDK to get
real-time thinking/text streaming events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/mesh/src/api/routes/decopilot/claude-code-provider.ts">

<violation number="1" location="apps/mesh/src/api/routes/decopilot/claude-code-provider.ts:372">
P2: This replays the full `thinking` content even after `thinking_delta` events were already streamed, so Claude Code reasoning can show up duplicated in the chat UI.</violation>
</file>

<file name="apps/mesh/src/api/routes/decopilot/routes.ts">

<violation number="1" location="apps/mesh/src/api/routes/decopilot/routes.ts:794">
P2: `gh auth status --json` is missing the required field list, so GitHub status detection will always fall back to disconnected.</violation>

<violation number="2" location="apps/mesh/src/api/routes/decopilot/routes.ts:843">
P1: This creates a permanent wildcard API key but the disconnect/failure paths never revoke it, leaving active internal credentials behind.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


if (target === "claude-code") {
// Create API key for the MCP endpoint
const apiKey = await ctx.boundAuth.apiKey.create({
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 12, 2026

Choose a reason for hiding this comment

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

P1: This creates a permanent wildcard API key but the disconnect/failure paths never revoke it, leaving active internal credentials behind.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/api/routes/decopilot/routes.ts, line 843:

<comment>This creates a permanent wildcard API key but the disconnect/failure paths never revoke it, leaving active internal credentials behind.</comment>

<file context>
@@ -811,63 +835,78 @@ export function createDecopilotRoutes(deps: DecopilotDeps) {
+
+    if (target === "claude-code") {
+      // Create API key for the MCP endpoint
+      const apiKey = await ctx.boundAuth.apiKey.create({
+        name: "studio-connect-claude-code",
+        permissions: { "*": ["*"] },
</file context>
Fix with Cubic


for (const block of content) {
// Stream thinking content as reasoning
if (block.type === "thinking" && block.thinking) {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 12, 2026

Choose a reason for hiding this comment

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

P2: This replays the full thinking content even after thinking_delta events were already streamed, so Claude Code reasoning can show up duplicated in the chat UI.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/api/routes/decopilot/claude-code-provider.ts, line 372:

<comment>This replays the full `thinking` content even after `thinking_delta` events were already streamed, so Claude Code reasoning can show up duplicated in the chat UI.</comment>

<file context>
@@ -321,26 +353,42 @@ export async function streamClaudeCode(
+
+          for (const block of content) {
+            // Stream thinking content as reasoning
+            if (block.type === "thinking" && block.thinking) {
+              if (!reasoningPartId) {
+                reasoningPartId = generateMessageId();
</file context>
Fix with Cubic

GitHub status now uses `gh auth status` (plain) + `gh api user --jq .login`
instead of `gh auth status --json` which requires explicit field names.
Simplify ConnectionCard to single-row layout with inline toggle button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/mesh/src/api/routes/decopilot/routes.ts">

<violation number="1" location="apps/mesh/src/api/routes/decopilot/routes.ts:796">
P2: Don't return early on missing `gh` auth here; it hides an already-registered GitHub MCP and flips the modal back to `Connect`.

(Based on your team's feedback about checking MCP authentication state first.) [FEEDBACK_USED]</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment on lines +796 to +822
if (!ghOk) return { connected: false, auth: null };

// Get username via API
let user: string | undefined;
try {
const { ok, stdout } = await runCli("gh", [
"api",
"user",
"--jq",
".login",
]);
if (ok) user = stdout.trim();
} catch {
// Username not available
}

// Check if the MCP is registered in Claude Code
const { ok: mcpRegistered } = await runCli("claude", [
"mcp",
"get",
"github",
]);

return {
connected: mcpRegistered,
auth: user ? { user } : null,
};
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 13, 2026

Choose a reason for hiding this comment

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

P2: Don't return early on missing gh auth here; it hides an already-registered GitHub MCP and flips the modal back to Connect.

(Based on your team's feedback about checking MCP authentication state first.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/api/routes/decopilot/routes.ts, line 796:

<comment>Don't return early on missing `gh` auth here; it hides an already-registered GitHub MCP and flips the modal back to `Connect`.

(Based on your team's feedback about checking MCP authentication state first.) </comment>

<file context>
@@ -791,26 +791,35 @@ export function createDecopilotRoutes(deps: DecopilotDeps) {
-    if (!ok) return { connected: false, auth: null };
+    // Check if gh CLI is authenticated
+    const { ok: ghOk } = await runCli("gh", ["auth", "status"]);
+    if (!ghOk) return { connected: false, auth: null };
+
+    // Get username via API
</file context>
Suggested change
if (!ghOk) return { connected: false, auth: null };
// Get username via API
let user: string | undefined;
try {
const { ok, stdout } = await runCli("gh", [
"api",
"user",
"--jq",
".login",
]);
if (ok) user = stdout.trim();
} catch {
// Username not available
}
// Check if the MCP is registered in Claude Code
const { ok: mcpRegistered } = await runCli("claude", [
"mcp",
"get",
"github",
]);
return {
connected: mcpRegistered,
auth: user ? { user } : null,
};
const { ok: mcpRegistered } = await runCli("claude", [
"mcp",
"get",
"github",
]);
// Get username via API when gh CLI is authenticated
let user: string | undefined;
if (ghOk) {
const { ok, stdout } = await runCli("gh", [
"api",
"user",
"--jq",
".login",
]);
if (ok) user = stdout.trim();
}
return {
connected: mcpRegistered,
auth: user ? { user } : null,
};
Fix with Cubic

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.

1 participant