Skip to content

fix(runner): make integrations behave more consistently in session#1686

Merged
markturansky merged 11 commits into
ambient-code:mainfrom
squizzi:fix/intermittent-integration-failures
Jun 16, 2026
Merged

fix(runner): make integrations behave more consistently in session#1686
markturansky merged 11 commits into
ambient-code:mainfrom
squizzi:fix/intermittent-integration-failures

Conversation

@squizzi

@squizzi squizzi commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

This PR fixes issues with Integrations not being loaded into session consistently. In prior test runs against main, a configured Jira integration would rarely work often resulting in this type of behavior.

Screenshot 2026-06-15 at 1 14 21 PM

Following up to tell the agent that Jira MCP is indeed available and the integration is configured often resulted in it not knowing the integration was even available to it within session:

Screenshot 2026-06-15 at 1 14 35 PM

Following this change Jira (and other integrations) work on the first invocation of the prompt:

Screenshot 2026-06-15 at 1 13 51 PM

Relates to: #1506

Summary by CodeRabbit

  • New Features
    • Added Jira auto-configuration for MCP when credentials are provided via environment variables.
    • System prompts now generate integration-specific guidance dynamically, including conditional integration status.
  • Improvements
    • Enhanced Claude first-run initialization to rebuild MCP servers and the Claude system prompt, ensuring the updated prompt is applied.
    • Git push instructions now adapt based on detected GitHub mode and credential/MCP configuration.
  • Tests
    • Added unit tests covering Claude run initialization and integration prompt generation across supported providers.

`build_credential_mcp_servers()` only registers the Jira MCP subprocess
when `jira` is present in `CREDENTIAL_IDS` (set via RoleBinding resolution).
However, `populate_runtime_credentials()` fetches Jira credentials via the
session-scoped fallback endpoint and sets JIRA_URL/JIRA_API_TOKEN in the
environment regardless of binding state.

Add an env-var fallback in `build_mcp_servers()`: if JIRA_URL and
JIRA_API_TOKEN are set but no Jira MCP server was added by the credential
binding path, register mcp-atlassian from the registry (same pattern Gerrit
already uses via GERRIT_CONFIG_PATH).

Previously the system prompt always told Claude to ask users to configure
Jira/Google when those integrations were needed, even when MCP servers were
already loaded and credentials were present in the environment. Claude followed
the static instruction and reported integrations as unavailable, requiring a
user follow-up to remind it the MCP was loaded.

Root cause: MCP_INTEGRATIONS_PROMPT was a static string evaluated at import
time, and the system prompt was not rebuilt after the first-run credential
refresh that populates env vars like JIRA_URL and JIRA_API_TOKEN.

Fixes:
- Replace static MCP_INTEGRATIONS_PROMPT with a data-driven _INTEGRATION_REGISTRY
  covering GitHub, GitLab, Jira, and Google Workspace. Each entry has a detect()
  callable and mode-keyed prompts. When an integration is configured, Claude is
  told to use its MCP server/tools; when not, it's told to ask the user to set
  it up. New integrations can be added by appending a single _Integration entry.
- Add _rebuild_system_prompt() to ClaudeBridge and call it alongside
  _rebuild_mcp_servers() on first run, after credential refresh, so the prompt
  accurately reflects actual integration state even when the backend was slow on
  the initial _setup_platform() credential fetch.
- Update the Gemini CLI bridge to use _build_integrations_prompt() for the same
  conditional behavior instead of the old static constant + separate blocks.
- Add TestBuildIntegrationsPrompt with parameterized tests for all 4 integrations
  covering configured/not-configured states and both sidecar and token modes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Kyle Squizzato <kysquizz@redhat.com>
@netlify

netlify Bot commented Jun 15, 2026

Copy link
Copy Markdown

Deploy Preview for cheerful-kitten-f556a0 canceled.

Name Link
🔨 Latest commit 0e3c499
🔍 Latest deploy log https://app.netlify.com/projects/cheerful-kitten-f556a0/deploys/6a309eb04260a600083801b2

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 63fb8d12-ee9d-4806-a428-496d0f6d46db

📥 Commits

Reviewing files that changed from the base of the PR and between c98b3f3 and 1d53202.

📒 Files selected for processing (4)
  • components/runners/ambient-runner/ambient_runner/bridges/claude/mcp.py
  • components/runners/ambient-runner/ambient_runner/bridges/gemini_cli/system_prompt.py
  • components/runners/ambient-runner/ambient_runner/platform/prompts.py
  • components/runners/ambient-runner/tests/test_bridge_claude.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • components/runners/ambient-runner/tests/test_bridge_claude.py
  • components/runners/ambient-runner/ambient_runner/bridges/claude/mcp.py
  • components/runners/ambient-runner/ambient_runner/platform/prompts.py

📝 Walkthrough

Walkthrough

Replaces static per-provider MCP/token prompt constants with a registry-driven _build_integrations_prompt() that parses CREDENTIAL_MCP_URLS and selects the correct fragment per provider. Adds Jira MCP env-based fallback in build_mcp_servers, wires Claude's first-run path to rebuild the system prompt and clear the adapter cache, migrates Gemini prompt assembly to the new builder, and adds corresponding unit tests.

Changes

Dynamic integration prompts, Jira MCP fallback, and Claude first-run rebuild

Layer / File(s) Summary
Integration prompt registry and builder
ambient_runner/platform/prompts.py
Introduces _Integration dataclass registry with detect functions and per-provider mcp/token/missing prompt fragments. _build_integrations_prompt() parses CREDENTIAL_MCP_URLS JSON and selects the right fragment per provider. build_workspace_context_prompt replaces static branching with a single call to it. MCP_INTEGRATIONS_PROMPT kept as a legacy alias.
Jira MCP env fallback
ambient_runner/bridges/claude/mcp.py
build_mcp_servers conditionally registers the Jira MCP server from _CREDENTIAL_MCP_REGISTRY when JIRA_URL/JIRA_API_TOKEN are present; expands ${...} placeholders in env config before adding the server.
Claude first-run system-prompt rebuild
ambient_runner/bridges/claude/bridge.py
_initialize_run first-run branch calls new _rebuild_system_prompt() and clears _adapter cache. _rebuild_system_prompt() regenerates _system_prompt via build_sdk_system_prompt with current workspace and resolved cwd paths.
Gemini prompt assembly migration
ambient_runner/bridges/gemini_cli/system_prompt.py
Drops GITHUB_TOKEN_PROMPT, GITLAB_TOKEN_PROMPT, MCP_INTEGRATIONS_PROMPT imports; imports _build_integrations_prompt. Adds GitHub-mode detection from CREDENTIAL_MCP_URLS JSON to select GIT_PUSH_MCP_STEPS vs GIT_PUSH_STEPS. Replaces per-token conditionals with a single integration prompt call.
Logger message formatting
ambient_runner/bridges/claude/mcp.py
Reformats multi-line logger.warning and logger.info calls in _build_sidecar_mcp_servers and _wait_for_sidecar_readiness for consistent line length; no behavioral changes.
Unit tests
tests/test_bridge_claude.py
TestClaudeBridgeFirstRunMCPRebuild verifies MCP+prompt rebuild on first run and no-op on subsequent same-user runs; TestBuildIntegrationsPrompt covers all four providers across missing/token/sidecar modes with monkeypatch env isolation.

Possibly related PRs

  • ambient-code/platform#1593: Modifies mcp.py around credential-driven MCP server construction; the Jira env-based fallback in this PR uses the registry mechanism introduced there.
  • ambient-code/platform#1599: Implements the credential sidecar model by parsing CREDENTIAL_MCP_URLS to build Claude credential MCP servers and routing GitHub operations through MCP—directly aligned with the CREDENTIAL_MCP_URLS parsing logic in this PR.
🚥 Pre-merge checks | ✅ 8
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title follows Conventional Commits format with type 'fix', scope 'runner', and clearly describes the main changeset: making integrations (particularly Jira) load consistently in sessions on first invocation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Performance And Algorithmic Complexity ✅ Passed No meaningful performance regressions detected. Minor JSON parsing redundancy (twice per prompt build on first run) is negligible in impact; no O(n²) algorithms, N+1 patterns, loops with expensive...
Security And Secret Handling ✅ Passed PR implements safe credential handling with no plaintext logging. Environment variables (JIRA_API_TOKEN, JIRA_URL, etc.) are expanded only into MCP subprocess env, never logged/serialed. JSON parsi...
Kubernetes Resource Safety ✅ Passed No Kubernetes resources, manifests, RBAC, or container configs present in PR. All changes are Python source code for integration bridges and system prompts.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/runners/ambient-runner/ambient_runner/bridges/claude/bridge.py (1)

230-238: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

User-change rebuild is incorrectly gated by per-thread worker existence (credential leakage risk).

At Line 230, rebuild happens only if get_existing(thread_id) is true. The adapter/MCP config is shared across threads, so a user switch on a new thread can still reuse the previous user’s adapter/mcp env-expanded credentials and stale system prompt.

Suggested fix
-        elif user_changed and self._session_manager.get_existing(thread_id):
-            logger.info(
-                f"User changed for thread={thread_id}, "
-                "rebuilding MCP servers and adapter with new credentials"
-            )
-            await self._session_manager.destroy(thread_id)
-            self._rebuild_mcp_servers()
-            # Force adapter rebuild so ClaudeAgentOptions uses new mcp_servers
-            self._adapter = None
+        elif user_changed:
+            logger.info(
+                f"User changed for thread={thread_id}, "
+                "rebuilding MCP servers, prompt, and adapter with new credentials"
+            )
+            if self._session_manager.get_existing(thread_id):
+                await self._session_manager.destroy(thread_id)
+            self._rebuild_mcp_servers()
+            self._rebuild_system_prompt()
+            # Force adapter rebuild so ClaudeAgentOptions uses updated config
+            self._adapter = None
🤖 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 `@components/runners/ambient-runner/ambient_runner/bridges/claude/bridge.py`
around lines 230 - 238, The user-change rebuild logic at the condition checking
user_changed and self._session_manager.get_existing(thread_id) is incorrectly
gated by per-thread worker existence. Since the adapter and MCP servers are
shared across all threads (not per-thread), removing the specific thread_id from
an existing session check will ensure the rebuild happens whenever a user
changes, regardless of whether that particular thread_id already has a worker.
This prevents the risk of new threads reusing the previous user's stale adapter
and environment-expanded credentials. Restructure the condition so that
rebuilding the MCP servers and setting self._adapter to None occurs whenever
user_changed is true, independent of the per-thread worker existence check.
🤖 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
`@components/runners/ambient-runner/ambient_runner/bridges/gemini_cli/system_prompt.py`:
- Around line 201-203: The prompt builder unconditionally includes
GIT_PUSH_STEPS even when GitHub MCP mode is active, creating conflicting
instructions (MCP mode says use GitHub MCP tools/don't use git push, while
GIT_PUSH_STEPS instructs git/gh flow). Identify where GIT_PUSH_STEPS is being
appended to the sections list and make it conditional: only add GIT_PUSH_STEPS
when GitHub sidecar/MCP mode is not active. Ensure the mode detection uses the
same logic as _build_integrations_prompt() uses to determine whether to emit
MCP-related instructions, so the prompt remains coherent.

In `@components/runners/ambient-runner/ambient_runner/platform/prompts.py`:
- Around line 151-154: The _detect_jira function currently only checks for
JIRA_URL and JIRA_API_TOKEN environment variables, but it should also detect
when Jira is configured via CREDENTIAL_MCP_URLS provider keys. Update the
function to check both the environment variables and the CREDENTIAL_MCP_URLS
configuration (checking for Jira-related provider keys). Return "mcp" if either
configuration method is detected, so that Jira MCP is properly recognized
regardless of how it was configured.

---

Outside diff comments:
In `@components/runners/ambient-runner/ambient_runner/bridges/claude/bridge.py`:
- Around line 230-238: The user-change rebuild logic at the condition checking
user_changed and self._session_manager.get_existing(thread_id) is incorrectly
gated by per-thread worker existence. Since the adapter and MCP servers are
shared across all threads (not per-thread), removing the specific thread_id from
an existing session check will ensure the rebuild happens whenever a user
changes, regardless of whether that particular thread_id already has a worker.
This prevents the risk of new threads reusing the previous user's stale adapter
and environment-expanded credentials. Restructure the condition so that
rebuilding the MCP servers and setting self._adapter to None occurs whenever
user_changed is true, independent of the per-thread worker existence check.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7d15312c-1630-40b8-9be7-8c8a330c906a

📥 Commits

Reviewing files that changed from the base of the PR and between d3ee37a and c98b3f3.

📒 Files selected for processing (5)
  • components/runners/ambient-runner/ambient_runner/bridges/claude/bridge.py
  • components/runners/ambient-runner/ambient_runner/bridges/claude/mcp.py
  • components/runners/ambient-runner/ambient_runner/bridges/gemini_cli/system_prompt.py
  • components/runners/ambient-runner/ambient_runner/platform/prompts.py
  • components/runners/ambient-runner/tests/test_bridge_claude.py

@markturansky markturansky merged commit 1bd2057 into ambient-code:main Jun 16, 2026
20 checks passed
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.

2 participants