Skip to content

Add gateway Code Mode contract#71

Merged
jmagar merged 3 commits into
mainfrom
feat/code-mode-contract
May 24, 2026
Merged

Add gateway Code Mode contract#71
jmagar merged 3 commits into
mainfrom
feat/code-mode-contract

Conversation

@jmagar
Copy link
Copy Markdown
Owner

@jmagar jmagar commented May 24, 2026

Summary

  • add canonical Code Mode ids for Lab actions and upstream tools
  • expose gateway code_search/code_schema MCP meta-tools alongside scout/invoke
  • document Code Mode discovery/schema semantics and invalid_code_mode_id

Verification

  • cargo fmt --all -- --check
  • cargo check --manifest-path crates/lab/Cargo.toml --all-features
  • cargo test --manifest-path crates/lab/Cargo.toml --lib dispatch::gateway::code_mode::tests --all-features
  • cargo test --manifest-path crates/lab/Cargo.toml --lib mcp::server::tests::code_search_expands_builtin_matches_to_action_candidates --all-features

Summary by cubic

Adds the gateway Code Mode contract with canonical tool IDs and a sandboxed JavaScript runner for constrained execution via code_execute, alongside code_search and code_schema, enabling stable ids, exact schemas, and safe host-brokered tool calls.

  • New Features

    • Canonical IDs: lab::<service>.<action> and upstream::<upstream>::<tool>.
    • MCP tools: code_search (candidates with id/name/upstream/description/score/schema_available), code_schema (exact contract with schema_format = lab_action_spec or json_schema), and code_execute (runs constrained snippets in a child process using boa_engine with timeout and max_tool_calls limits).
    • Config: [code_mode] adds enabled, timeout_ms, and max_tool_calls; execution is blocked when disabled.
    • Errors: invalid_code_mode_id, code_mode_disabled, code_execution_failed, tool_call_limit_exceeded, schema_unavailable.
    • Hidden CLI: labby internal code-mode-runner to run the sandboxed helper.
    • Includes built-in Lab actions and healthy upstream tools; results are ranked and truncated by top_k.
  • Migration

    • Use code_search to get a stable id, then code_schema before generating tool-call code.
    • To run Code Mode snippets, call code_execute when [code_mode].enabled; otherwise keep executing via invoke (with scout for search).
    • Tools are exposed when gateway tool-search mode is on; raw upstream tools remain hidden.

Written for commit 9afb378. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced Code Mode, a new feature enabling schema-first tool discovery and constrained code execution
    • Added three new gateway tools: code_search, code_schema, and code_execute (disabled by default)
    • Added Code Mode configuration with validation for execution timeout and tool call limits
  • Documentation

    • Updated gateway service documentation with Code Mode behavior, authorization rules, and error handling
    • Added Code Mode implementation plan and error documentation

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

📝 Walkthrough

Walkthrough

This PR introduces Code Mode, a gateway-owned MCP meta-tool surface that enables schema-first code discovery and constrained execution. It adds configuration validation, tool ID parsing, code snippet invocation extraction with TypeScript binding generation, and MCP server integration for code_search, code_schema, and code_execute tools with scope-based access control and per-request timeout enforcement.

Changes

Code Mode Gateway Meta-Tool Surface

Layer / File(s) Summary
Configuration contract and validation
crates/lab/src/config.rs
CodeModeConfig with default-disabled state, configurable timeout (1–60s) and max tool calls (1–50), validated at startup via LabConfig::validate(), with dedicated error variants for invalid ranges. Tests verify TOML parsing and range rejection.
Tool type and ID parsing
crates/lab/src/dispatch/gateway.rs, crates/lab/src/dispatch/gateway/code_mode.rs
CodeModeToolId parses lab::<service>.<action> and upstream::<upstream>::<tool> formats; CodeModeToolRef enum distinguishes sources. Serializable CodeModeSearchCandidate and CodeModeSchemaResponse types model discovery results and schema contracts with associated constructors.
Snippet parsing and schema utilities
crates/lab/src/dispatch/gateway/code_mode.rs
extract_code_mode_invocations validates code by rejecting unsupported keywords (if/for/while/etc) outside comments/strings, scans for callTool(id, params) calls, parses string-literal IDs and JSON params (defaulting to {}), and enforces max call limits. action_input_schema converts ActionSpec parameters to JSON Schema. typescript_binding converts JSON Schema to TypeScript type definitions with enum, union, and required-field support. Unit tests validate parsing, validation, and schema conversion end-to-end.
Gateway manager and catalog wiring
crates/lab/src/dispatch/gateway/manager.rs, crates/lab/src/mcp/catalog.rs
GatewayManager::code_mode_config() exposes current configuration. New tool-name constants (CODE_SEARCH_TOOL_NAME, etc.) and LabMcpServer::gateway_code_mode_enabled() check for code search availability. Synthetic tool snapshot includes Code Mode tools alongside scout/invoke.
MCP server Code Mode tool implementation
crates/lab/src/mcp/server.rs
list_tools() advertises three Code Mode meta-tools with JSON input schemas. call_tool() handles: code_search (query hash, candidate ranking from builtin and upstream); code_schema (stable ID resolution to lab action or upstream tool schema, with sanitization); code_execute (config validation, invocation extraction, per-request timeout, structured result or error envelope). Helper methods generate builtin candidates, resolve schemas with exposure checks, and route execution to lab or upstream with confirmation gating. Tests validate candidate expansion and stable-ID execution routing. Snapshot expectations updated.
Error kinds and implementation documentation
docs/dev/ERRORS.md, docs/services/GATEWAY.md, docs/superpowers/plans/2026-05-24-code-mode-contract.md
Documented error kinds (invalid_code_mode_id HTTP 422, code_mode_disabled HTTP 403, tool_call_limit_exceeded HTTP 429, schema_unavailable HTTP 422). Gateway docs expanded with Code Mode discovery/schema/execution flow, canonical ID formats, validation ranges, scope/permission rules, and read-only vs destructive execution constraints. Detailed implementation plan with Tasks 1–5 covers ID parsing, search integration, schema resolution, documentation, and verification.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 A rabbit hops through code so bright,
With snippets parsed and schemas right,
Code Mode arrives with tools to find,
TypeScript bindings, well-designed!
Hop forward, lab, with gateway glow,
The Code Mode contract steals the show! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add gateway Code Mode contract' directly and concisely summarizes the main change: introducing a new Code Mode contract feature for the gateway.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/code-mode-contract

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.

Copy link
Copy Markdown

@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: b96a9d33ab

ℹ️ 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".

Comment on lines +1437 to +1443
if self.gateway_manager.is_none() {
let envelope = build_error(
&service,
"call_tool",
"unknown_tool",
"code schema is not enabled",
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Enforce tool-search enablement before serving code_schema

This branch only checks whether gateway_manager exists, so code_schema can still return Lab/upstream schemas even when [tool_search].enabled is false (the mode where these tools are intentionally hidden from list_tools). In a deployment with gateway configured but tool-search disabled, callers who know the tool name can bypass the feature toggle and access schema data anyway; this should be gated on tool_search_enabled() the same way discovery exposure is gated.

Useful? React with 👍 / 👎.

Comment on lines +2911 to +2912
other => build_error(service, action, other.kind(), &other.to_string()),
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve ToolError payloads in code_schema error envelopes

For non-Sdk errors, this helper uses other.to_string() as the message, but ToolError::Display is JSON, so envelopes end up with a nested JSON string in message and lose structured fields like valid/hint. A reproducible case is code_schema with a valid service but unknown action: callers receive a degraded unknown_action response that is much harder to handle programmatically.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 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 `@crates/lab/src/dispatch/gateway/code_mode.rs`:
- Around line 393-424: balanced_parenthesized currently only treats '"' and '\''
as quotes so backtick template literals can prematurely close parentheses
parsing; update the function to treat '`' as a quote as well by including '`' in
the match that sets quote (e.g., match ch { '"' | '\'' | '`' => quote =
Some(ch), ... }) and ensure the quote-handling block correctly recognizes and
closes on a '`' while still honoring escapes (backslash) the same way as for
other quotes; this mirrors how first_unsupported_keyword/next_call_tool_offset
skip template literals and prevents ')' inside backtick strings from ending the
extraction prematurely.
- Around line 229-235: The current logic pushes a new CodeModeInvocation into
calls and then checks calls.len() > max_tool_calls, which allows one extra
invocation; update the enforcement in the function handling CodeModeInvocation
(where calls, max_tool_calls, and ToolError::Sdk are used) to prevent the
off-by-one by checking the limit before pushing or by using calls.len() >=
max_tool_calls for the post-push path so that attempting the
(max_tool_calls+1)th call returns the ToolError::Sdk with sdk_kind
"tool_call_limit_exceeded" and the same formatted message.

In `@crates/lab/src/mcp/catalog.rs`:
- Around line 203-205: The catalog currently inserts CODE_SEARCH_TOOL_NAME,
CODE_SCHEMA_TOOL_NAME, and CODE_EXECUTE_TOOL_NAME whenever
visibility.exposes_synthetic_tools() is true, making Code Mode tools
discoverable even if Code Mode is disabled; update the insertion logic in the
function that builds the tools set in mcp/catalog.rs so those three tool names
are only added when the runtime/config flag for Code Mode is enabled (mirror the
check used in mcp/server.rs, e.g. self.gateway_code_mode_enabled() or
config.code_mode.enabled), leaving visibility.exposes_synthetic_tools() to
control synthetic-tool exposure generally but adding an additional conditional
guard around the CODE_* inserts to consult the Code Mode enablement.

In `@crates/lab/src/mcp/server.rs`:
- Around line 3153-3167: The Some(Ok(result)) arm for pool.call_tool currently
treats any CallToolResult as success without checking result.is_error, and the
None case uses sdk_kind "not_found" which masks a disconnected upstream; update
the Some(Ok(result)) branch in server.rs to check CallToolResult.is_error and if
true return Err(DispatchToolError::Sdk { sdk_kind: "upstream_error", message:
<use the result's error text> }) otherwise serialize the successful result, and
change the None arm to return an SDK error indicating upstream disconnection
(e.g., sdk_kind "upstream_disconnected" with a message mentioning the upstream
and tool) so callers can retry; refer to pool.call_tool, CallToolResult, and
DispatchToolError to locate and implement these changes.

In `@docs/dev/ERRORS.md`:
- Around line 59-62: The HTTP Status Mapping section is missing the four Code
Mode error kinds listed earlier; add entries for invalid_code_mode_id (HTTP
422), code_mode_disabled (HTTP 403), tool_call_limit_exceeded (HTTP 429), and
schema_unavailable (HTTP 422) to the “HTTP Status Mapping” list in this document
so the mapping is complete and consistent with the earlier definitions; use the
exact kind strings (invalid_code_mode_id, code_mode_disabled,
tool_call_limit_exceeded, schema_unavailable) and their corresponding status
codes when inserting the lines.

In `@docs/superpowers/plans/2026-05-24-code-mode-contract.md`:
- Around line 41-46: Update the completed-plan examples to match the shipped
contract by removing the obsolete code_search.detail field from the JSON
examples and changing the error mapping for invalid_code_mode_id from HTTP 400
to HTTP 422; locate the JSON snippet that calls code_search (references to
code_search.detail and invalid_code_mode_id) and adjust the example responses
and any stated HTTP status codes (also update the other occurrences flagged at
lines 729-731) so the examples reflect no "detail" key and use 422 for
invalid_code_mode_id.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 03869d60-7cbf-4d2b-bf73-8905f0598612

📥 Commits

Reviewing files that changed from the base of the PR and between f0b9450 and 74e8390.

📒 Files selected for processing (9)
  • crates/lab/src/config.rs
  • crates/lab/src/dispatch/gateway.rs
  • crates/lab/src/dispatch/gateway/code_mode.rs
  • crates/lab/src/dispatch/gateway/manager.rs
  • crates/lab/src/mcp/catalog.rs
  • crates/lab/src/mcp/server.rs
  • docs/dev/ERRORS.md
  • docs/services/GATEWAY.md
  • docs/superpowers/plans/2026-05-24-code-mode-contract.md

Comment thread crates/lab/src/dispatch/gateway/code_mode.rs Outdated
Comment thread crates/lab/src/dispatch/gateway/code_mode.rs Outdated
Comment on lines +203 to +205
tools.insert(CODE_SEARCH_TOOL_NAME.to_string());
tools.insert(CODE_SCHEMA_TOOL_NAME.to_string());
tools.insert(CODE_EXECUTE_TOOL_NAME.to_string());
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if code_mode tools should be gated separately from tool_search

# Find CodeModeConfig to see if it has an enabled field
echo "=== CodeModeConfig structure ==="
ast-grep --pattern $'struct CodeModeConfig {
  $$$
}'

# Check MCP server implementation for code_search/code_schema/code_execute handling
echo -e "\n=== MCP server handling of code mode tools ==="
rg -n 'CODE_SEARCH_TOOL_NAME|CODE_SCHEMA_TOOL_NAME|CODE_EXECUTE_TOOL_NAME' --type rust -A 10

# Check if there's validation that code mode is enabled before handling these tools
echo -e "\n=== Code mode enablement checks in call_tool ==="
rg -n 'code_mode.*enabled|gateway_code_mode_enabled' crates/lab/src/mcp/server.rs -C 5

Repository: jmagar/lab

Length of output: 11746


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Find exposes_synthetic_tools() definition ==="
rg -n "exposes_synthetic_tools" crates/lab/src/mcp -S
rg -n "exposes_synthetic_tools" crates/lab/src -S

echo "=== Inspect catalog.rs around lines ~180-240 ==="
sed -n '150,260p' crates/lab/src/mcp/catalog.rs | cat -n

echo "=== Locate GatewayManager code_mode_config / gateway_code_mode_enabled ==="
rg -n "code_mode_config|gateway_code_mode_enabled|gateway_code_mode_config" crates/lab/src -S

Repository: jmagar/lab

Length of output: 6131


Gate Code Mode tool exposure on code_mode.enabled

mcp/server.rs only executes code_search/code_schema/code_execute behind self.gateway_code_mode_enabled() (and also checks config.enabled), but mcp/catalog.rs lists those tools whenever visibility.exposes_synthetic_tools() is true, which is derived from tool-search visibility—not Code Mode config. This can make Code Mode tools discoverable even when Code Mode is disabled.

🤖 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 `@crates/lab/src/mcp/catalog.rs` around lines 203 - 205, The catalog currently
inserts CODE_SEARCH_TOOL_NAME, CODE_SCHEMA_TOOL_NAME, and CODE_EXECUTE_TOOL_NAME
whenever visibility.exposes_synthetic_tools() is true, making Code Mode tools
discoverable even if Code Mode is disabled; update the insertion logic in the
function that builds the tools set in mcp/catalog.rs so those three tool names
are only added when the runtime/config flag for Code Mode is enabled (mirror the
check used in mcp/server.rs, e.g. self.gateway_code_mode_enabled() or
config.code_mode.enabled), leaving visibility.exposes_synthetic_tools() to
control synthetic-tool exposure generally but adding an additional conditional
guard around the CODE_* inserts to consult the Code Mode enablement.

Comment thread crates/lab/src/mcp/server.rs Outdated
Comment thread docs/dev/ERRORS.md
Comment on lines +59 to +62
- `invalid_code_mode_id` — Code Mode tool id parsing failed. Valid ids are `lab::<service>.<action>` and `upstream::<upstream-name>::<tool-name>`. HTTP 422.
- `code_mode_disabled` — Code Mode execution was requested while `[code_mode].enabled` is false. Discovery and schema lookup can remain enabled without allowing execution. HTTP 403.
- `tool_call_limit_exceeded` — a Code Mode snippet attempted more host-brokered tool calls than `max_tool_calls` allows. HTTP 429.
- `schema_unavailable` — Code Mode schema lookup found a tool, but its upstream schema was missing or exceeded the safe return size after sanitization. HTTP 422.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep the HTTP status mapping table in sync with the new Code Mode kinds.

These four kinds are documented here with status codes, but they’re missing from the “HTTP Status Mapping” list later in this file. Please add them there as well to keep this document canonical and internally consistent.

🤖 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 `@docs/dev/ERRORS.md` around lines 59 - 62, The HTTP Status Mapping section is
missing the four Code Mode error kinds listed earlier; add entries for
invalid_code_mode_id (HTTP 422), code_mode_disabled (HTTP 403),
tool_call_limit_exceeded (HTTP 429), and schema_unavailable (HTTP 422) to the
“HTTP Status Mapping” list in this document so the mapping is complete and
consistent with the earlier definitions; use the exact kind strings
(invalid_code_mode_id, code_mode_disabled, tool_call_limit_exceeded,
schema_unavailable) and their corresponding status codes when inserting the
lines.

Comment on lines +41 to +46
```json
code_search({
"query": "github issues",
"top_k": 10,
"detail": "brief"
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update completed-plan examples to match the shipped contract.

This plan is marked completed, but it still shows a code_search.detail field and invalid_code_mode_id as HTTP 400. Those differ from the implemented/documented contract in this PR (no detail; invalid_code_mode_id mapped to HTTP 422). Please align these examples to avoid future confusion.

Also applies to: 729-731

🤖 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 `@docs/superpowers/plans/2026-05-24-code-mode-contract.md` around lines 41 -
46, Update the completed-plan examples to match the shipped contract by removing
the obsolete code_search.detail field from the JSON examples and changing the
error mapping for invalid_code_mode_id from HTTP 400 to HTTP 422; locate the
JSON snippet that calls code_search (references to code_search.detail and
invalid_code_mode_id) and adjust the example responses and any stated HTTP
status codes (also update the other occurrences flagged at lines 729-731) so the
examples reflect no "detail" key and use 422 for invalid_code_mode_id.

@jmagar jmagar merged commit ddaab2b into main May 24, 2026
14 checks passed
@jmagar jmagar deleted the feat/code-mode-contract branch May 24, 2026 19:57
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