Skip to content

feat(claude-code): Claude Code CLI provider — Phases 1–5#2472

Merged
senamakel merged 16 commits into
tinyhumansai:mainfrom
finedesignz:feat/claude-code-provider
Jun 3, 2026
Merged

feat(claude-code): Claude Code CLI provider — Phases 1–5#2472
senamakel merged 16 commits into
tinyhumansai:mainfrom
finedesignz:feat/claude-code-provider

Conversation

@finedesignz
Copy link
Copy Markdown
Contributor

@finedesignz finedesignz commented May 22, 2026

Summary

Adds Claude Code CLI as a selectable inference provider on equal footing with openhuman, ollama:*, and <slug>:*. Routes any chat workload through Anthropic's claude CLI (-p --output-format stream-json --verbose --include-partial-messages --resume <uuid>) instead of calling the Anthropic HTTP API directly. Native OpenHuman tools stay in Rust and are exposed back to the CLI over MCP via the existing openhuman-core mcp stdio server, so the CLI's model can call mcp__openhuman__* to reach OpenHuman memory, threads, channels, and people without leaving the workspace.

Plan, locked decisions, and per-phase checkpoints live in .planning/claude-code-provider/PLAN.md.

Locked decisions:

  1. MIN_CLI_VERSION = 2.0.0 (enforced by version_check::probe)
  2. Read-only MCP tool subset surfaced as mcp__openhuman__* (PLAN §13.2)
  3. Per-role provider selection — chat_provider / agentic_provider / reasoning_provider each accept claude-code:<model>[@<temp>]
  4. UI branding: "Claude Code CLI" in all settings copy
  5. Subscription detection (v1.1) — separate claude_code_auth_status RPC, pure FS, never round-trips token

What's in this PR

Phase 1 — Scaffold

  • New module src/openhuman/inference/provider/claude_code/{mod,types,version_check,auth}.rs
  • Factory grammar: recognize claude-code:<model>[@<temp>] provider strings
  • New RPC method openhuman.inference_claude_code_status returns CliStatus { ok | not_installed | outdated | unusable }

Phase 2 — Driver + stream parsing

  • stream_parser.rs, event_mapper.rs, session_store.rs, input_builder.rs, driver.rs
  • Concurrency cap: Semaphore(MAX_CONCURRENT_TURNS=4) per provider instance

Phase 3 — MCP wiring

  • Driver writes per-turn mcp-config.json (tempdir) pointing the CLI at openhuman-core mcp over stdio
  • CC flags: --mcp-config <tmp> --strict-mcp-config --disallowedTools Bash,Read,Write,Edit,Glob,Grep,WebFetch,WebSearch,TodoWrite,Task,BashOutput,KillShell

Phase 4 — Frontend + docs

  • aiSettingsApi.ts: ProviderRef extended with claude-code kind
  • ClaudeCodeStatusCard.tsx embedded in AIPanel.tsx
  • Gitbook page gitbooks/developing/providers/claude-code.md

Phase 5 — Tests + ship

  • Integration test tests/claude_code_stream_e2e.rs

Phase 6 (v1.1) — Subscription auth + cost + UX polish (new in this iteration)

  • auth_status.rs — tolerant parse of ~/.claude/.credentials.json; returns subscription | api_key_env | none with optional account_email + expires_at. Token never round-trips.
  • New RPC openhuman.inference_claude_code_auth_status — pure FS, independent of slow version probe. UI refreshes auth independently after claude login.
  • Settings card auth section: badge + Recheck + "Sign in with Claude" button.
  • New Tauri command claude_code_login_launch — opens the user's native terminal running claude login (Windows cmd /k, macOS osascript → Terminal.app, Linux tries x-terminal-emulatorgnome-terminalkonsolexfce4-terminalxterm). The OAuth flow stays in the terminal because the interactive paste-the-code step can't be hosted in-app.
  • Cost wiring: event_mapper plumbs result.total_cost_usd into UsageInfo.charged_amount_usd so cost.rs records per-turn spend without re-pricing tokens × rates.
  • Provider picker: CustomRoutingDialog exposes "Claude Code CLI" as a 3rd source option alongside cloud and local Ollama. Model is a free-text input (default sonnet-4-5).
  • .planning/claude-code-provider/WRITE-TOOLS-THREAT-MODEL.md — design doc for the v1.2 write-tool surface (5 attack scenarios + 8 required controls). Recommendation: defer write tools until approval/audit infra exists.

Test plan

  • cargo check (core + tauri shell) — clean
  • cargo test --lib claude_code27/27 unit tests pass (incl. new auth_status + cost wiring)
  • cargo test --test claude_code_stream_e2e1/1 integration test passes
  • pnpm --filter openhuman-app test claude_code + AIPanel — 25/25 tests pass
  • pnpm typecheck — clean
  • pnpm lint — 0 errors
  • N/A: Manual smoke test against a real claude 2.0.x install with both subscription and API-key auth — deferred, gated on reviewer's local CLI

Notes for review

  • --no-verify push. The pre-push hook is reformatting ~940 unrelated files (line-ending CRLF/LF, lottie JSON, etc.) that have nothing to do with this change. Per CLAUDE.md's rule for "pre-existing breakage on main in code you didn't touch", I'm pushing past it. Happy to rebase if you'd like the hook output preserved.
  • Auth scope. Subscription users (Pro/Max via claude login) are now fully supported in v1.1 — detection, UI, and a one-click "Sign in with Claude" terminal launcher. API key path also intact (ANTHROPIC_API_KEY env or per-config override).
  • Write tools deferred to v1.2. Threat model captured in .planning/claude-code-provider/WRITE-TOOLS-THREAT-MODEL.md. v1.1 surface stays strictly read-only.
  • MCP server reuse. We reuse the existing stdio MCP server at src/openhuman/mcp_server/ rather than building a new HTTP MCP transport.
  • Submodule. app/src-tauri/vendor/tauri-cef had a working-tree drift on my machine; excluded from every commit on this branch.

Summary by CodeRabbit

  • New Features

    • Added support for using Claude Code CLI as an AI routing option in Custom routing, including model selection and optional temperature overrides.
    • Added a new Claude Code status card in Settings to check CLI availability, version compatibility, and authentication state.
    • Added a guided “Sign in with Claude” flow that can launch login in your native terminal.
  • Documentation

    • Added setup and usage documentation for Claude Code CLI integration.

Adds the module skeleton, version probe, auth resolution, factory
dispatch grammar, and JSON-RPC status endpoint for the Claude Code CLI
provider. The Provider impl is a stub that returns NotImplemented —
Phase 2 lands the driver + stream parser.

- new: src/openhuman/inference/provider/claude_code/{mod,types,version_check,auth}.rs
- factory: recognize `claude-code:<model>[@<temp>]` provider strings
- rpc: openhuman.inference_claude_code_status (probes `claude --version`,
  enforces MIN_CLI_VERSION=2.0.0)
- plan: lock decisions per user — v2.0.0 pin, read-only MCP subset,
  per-role provider selection, "Claude Code CLI" branding

5 unit tests pass on version parsing and auth resolution.
End-to-end CLI driver for the Claude Code provider. Spawns `claude -p
--output-format stream-json` per chat turn, parses JSONL stdout into
ProviderDelta events, persists per-thread session UUIDs for --resume,
and caps concurrent processes via Semaphore(4).

- stream_parser.rs — line-buffered JSONL → ClaudeCodeEvent
- event_mapper.rs — ClaudeCodeEvent → ProviderDelta + aggregated
  ChatResponse with usage; handles content_block_start/delta/stop for
  text, thinking, and tool_use blocks
- session_store.rs — disk-backed thread_id → CC UUIDv4 map with v4
  validation (CC rejects non-v4 ids on --resume)
- input_builder.rs — stream-json stdin payload (full history on new
  session, last user turn on --resume)
- driver.rs — tokio Command spawn, stdin/stdout/stderr plumbing,
  graceful end-of-stream drain
- mod.rs — real Provider impl with Semaphore(4) concurrency cap and
  thread-key fallback hash until ChatRequest carries thread_id (Phase 4)
- factory.rs — pass workspace dir into from_env() so SessionStore lands
  next to the live config

22 unit tests pass (parser, mapper, session store, input builder,
version check, auth).

MCP server wiring + write-tool exposure stays in Phase 3.
Phase 3 of the Claude Code CLI provider plan. Instead of building a new
HTTP MCP server, we reuse the existing stdio MCP server that's already
in src/openhuman/mcp_server/ — CC spawns `openhuman-core mcp` as a
child stdio MCP server, exposing read-only OpenHuman tools as
`mcp__openhuman__*` inside the model's tool surface.

Per-turn the driver now:
- Writes a tempfile mcp-config.json pointing the CLI at
  `openhuman-core mcp` over stdio
- Passes --mcp-config <tmp> --strict-mcp-config
- Passes --disallowedTools Bash,Read,Write,Edit,... so OpenHuman's tool
  surface stays authoritative (CC builtins kept off in v1)

Falls back gracefully when openhuman-core binary can't be located
(std::env::current_exe failure) — CC runs without OpenHuman MCP tools
instead of erroring the turn.

Drops the "MCP wiring stays in Phase 3" TODO from the driver module
header.

22 unit tests still pass.
Frontend surface for the Claude Code CLI provider plus the docs page.

- aiSettingsApi: extend ProviderRef union with `claude-code` kind;
  parse + serialize `claude-code:<model>[@<temp>]` provider strings via
  the same grammar as `ollama:` and `<slug>:<model>`
- config tauri command: new `openhumanClaudeCodeStatus()` + typed
  `ClaudeCodeStatus` union (ok | not_installed | outdated | unusable)
  hitting the openhuman.inference_claude_code_status RPC
- ClaudeCodeStatusCard: new settings card that probes the CLI on mount
  and on manual refresh; surfaces install / outdated / unusable states
  with appropriate copy + dark-mode styling
- AIPanel: extend the local ProviderRef union to mirror the API type;
  describeProvider() renders "Claude Code CLI <model>"; status card
  embedded at the top of the AI settings panel
- gitbook: new providers/claude-code.md covering install requirements,
  factory grammar, status RPC, per-turn behavior, auth resolution
  order, exposed MCP tools, and v1 limitations

5 new Vitest tests pass; pnpm compile and pnpm lint clean.
Feeds a representative CC 2.x stream-json transcript through the
StreamJsonParser → EventMapper pipeline and asserts:
- text deltas arrive in order and aggregate into final_text
- tool_use block emits ToolCallStart + ToolCallArgsDelta + final ToolCall
  with parsed JSON arguments
- the `result` event finalizes usage tokens (incl. cache_read_input_tokens)
- session_id captured from the first `system` event
- chunk-boundary buffering survives splitting the transcript mid-line

Closes Phase 5 of the claude-code-provider plan. 22 unit tests + 1 E2E
integration test pass.
@finedesignz finedesignz requested a review from a team May 22, 2026 01:32
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces the Claude Code CLI provider, enabling OpenHuman to route inference through Anthropic's locally-installed claude CLI. Changes span frontend routing types, Tauri RPC bindings, a React status panel, and comprehensive Rust backend infrastructure for stream parsing, session management, CLI spawning, and provider integration.

Changes

Claude Code CLI Provider Integration

Layer / File(s) Summary
Frontend Provider Routing Types and Parsing
app/src/services/api/aiSettingsApi.ts, app/src/components/settings/panels/AIPanel.tsx
Extended ProviderRef discriminated union adds claude-code variant. Parsing (parseProviderString) and serialization (serializeProviderRef) support claude-code:<model>[@<temperature>] grammar. describeProvider displays "Claude Code CLI" labels in UI routing descriptions.
Status Probe RPC: Tauri Commands and Backend Handlers
app/src/utils/tauriCommands/config.ts, src/openhuman/inference/schemas.rs, app/src-tauri/src/claude_code.rs, app/src-tauri/src/lib.rs
Client-side Tauri command wrappers invoke openhuman.inference_claude_code_status and openhuman.inference_claude_code_auth_status RPC methods. Backend schema registers these endpoints with blocking handlers that run CLI/auth probes and return JSON outcomes. Tauri claude_code_login_launch command spawns native terminal (OS-specific: Windows cmd, macOS Terminal.app, Linux emulator list) to run claude login.
Status Card React Component and Tests
app/src/components/settings/panels/ai/ClaudeCodeStatusCard.tsx, app/src/components/settings/panels/ai/__tests__/ClaudeCodeStatusCard.test.tsx
New ClaudeCodeStatusCard component probes CLI installation and authentication state on mount and button clicks. Conditional UI renders version/path for ok, install guidance for not_installed, outdated details with min_required, or unusable reason. Auth section displays subscription email, API-key-env notice, or sign-out flow with "Sign in with Claude" button. Comprehensive test suite validates all probe outcomes, button interactions, and auth state transitions.
Backend Infrastructure: Types, Auth, Version Check, Sessions
src/openhuman/inference/provider/claude_code/types.rs, auth.rs, auth_status.rs, version_check.rs, session_store.rs
Defines CliStatus enum (ok/not_installed/outdated/unusable) and version constraints. Resolves Anthropic API authentication from ANTHROPIC_API_KEY env var or ~/.claude/.credentials.json with tolerant OAuth JSON parsing. Binary discovery via PATH or OPENHUMAN_CLAUDE_CLI override; version validation with semver comparison. Session store persists RFC-4122 v4 UUIDs per thread in claude-code-sessions.json with UUID generation/validation.
Stream Parsing and Event Mapping
src/openhuman/inference/provider/claude_code/stream_parser.rs, event_mapper.rs
StreamJsonParser buffers incoming bytes, splits on newlines, decodes typed Claude CLI events, tolerates schema drift, and captures schema_version. EventMapper aggregates events into ProviderDeltas (text, thinking, tool calls) with per-block state tracking, tool-call JSON argument assembly, and final ChatResponse construction including usage finalization from terminal result events.
Input Building and CLI Turn Driver
src/openhuman/inference/provider/claude_code/input_builder.rs, driver.rs
build_stdin constructs newline-delimited JSON payload, filtering message roles and switching between new-session full-history and resume-session last-message modes. run_turn orchestrates a single CLI turn: selects/persists session UUID, optionally writes MCP config, builds full CLI argument vector (tool restrictions, session/model/system-prompt flags), spawns child with piped I/O, streams stdout through parser and mapper into ProviderDeltas, drains stderr concurrently, waits for exit, and returns aggregated response.
Provider Implementation and Factory Integration
src/openhuman/inference/provider/claude_code/mod.rs, factory.rs, src/openhuman/inference/provider/mod.rs
ClaudeCodeProvider struct stores model, CLI path, workspace, optional API key, semaphore-capped concurrency (max 4 turns), and session store. from_env probes CLI version, resolves credentials, returns errors for missing/outdated/unusable states. run_chat acquires permit, derives deterministic thread key from first user message, and delegates to driver. Provider trait reports tool-calling enabled, vision disabled; wires chat_with_system, chat_with_history, and chat to construct ChatRequests and extract text. Factory recognizes claude-code:<model>[@<temp>] prefix, parses model/temperature, resolves workspace, and instantiates provider. Module exports aggregated submodules.
Documentation and End-to-End Testing
gitbooks/developing/providers/claude-code.md, tests/claude_code_stream_e2e.rs
User docs describe prerequisites (CLI 2.0.0+, API key/credentials, openhuman-core MCP), routing grammar, RPC interfaces, per-turn execution (session UUIDs, MCP config, tool restrictions, streaming), auth resolution order, MCP tool exposure (read-only vs destructive), and limitations (no vision, semaphore queueing, cost not yet wired to billing). E2E test validates stream parser and event mapper pipeline against captured Claude transcript, asserting schema version, session ID, text/thinking delta ordering, tool-call lifecycle with JSON argument assembly, and usage finalization.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • tinyhumansai/openhuman#1858: The main PR extends unified per-workload provider routing and factory grammar by adding claude-code:<model>[@<temp>] support in ProviderRef parsing/serialization and create_chat_provider_from_string, building on the same routing/factory code introduced in that PR.

  • tinyhumansai/openhuman#1888: Both PRs modify shared AI settings routing model—ProviderRef parsing/serialization and AIPanel custom routing UI—so the main PR's claude-code provider variant is an extension of the slug-keyed provider/routing refactor from that PR.

  • tinyhumansai/openhuman#2580: Both PRs expand shared ProviderRef union and update AIPanel.tsx/aiSettingsApi.ts parsing/serialization and routing UI logic; main PR adds claude-code kind while that PR introduces default kind, making them code-adjacent with likely overlap.

Suggested labels

rust-core

Poem

🐰 A CLI whispers its secrets through JSON lines,
Sessions bloom in folders, UUIDs entwine,
Text deltas stream past, tools call and reply,
Claude's wisdom flows local—no clouds in the sky.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(claude-code): Claude Code CLI provider — Phases 1–5' accurately and directly summarizes the main change: introducing a Claude Code CLI inference provider with multiple implementation phases.
Docstring Coverage ✅ Passed Docstring coverage is 94.85% which is sufficient. The required threshold is 80.00%.
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.


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 added the feature Net-new user-facing capability or product behavior. label May 22, 2026
Copy link
Copy Markdown
Contributor

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

🧹 Nitpick comments (3)
gitbooks/developing/providers/claude-code.md (1)

88-88: 💤 Low value

Clarify concurrency cap scope.

"agentic runs share the same Semaphore(4)" could be read as role-specific, but the plan (line 151) specifies a global Semaphore(4) in driver.rs shared by all CC turns regardless of role.

✍️ Suggested clarification
-- `agentic` runs share the same `Semaphore(4)`; under load a CC turn waits in queue rather than failing fast.
+- All CC turns (across `chat`, `reasoning`, and `agentic` roles) share a global `Semaphore(4)`; under load a turn waits in queue rather than failing fast.
🤖 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 `@gitbooks/developing/providers/claude-code.md` at line 88, Update the wording
to explicitly state that the Semaphore(4) is a single global concurrency cap
shared by all CC turns (not role-specific); mention the global Semaphore(4)
defined in driver.rs and that all agentic runs/CC turns compete for the same
permit, causing queued waits under load instead of role-scoped limits or fast
failures. Adjust the sentence referencing "agentic runs share the same
Semaphore(4)" to clarify it is a global semaphore in driver.rs used by all CC
turns regardless of role.
.planning/claude-code-provider/PLAN.md (1)

21-21: 💤 Low value

Consider adding language specifiers to fenced code blocks.

Static analysis flagged these fenced code blocks as missing language identifiers. While they contain ASCII diagrams and file trees rather than code, adding ```text would satisfy the linter and improve consistency.

📝 Proposed fix
-```
+```text
 Frontend  ──invoke──>  Tauri shell  ──HTTP+bearer──>  openhuman-core (Axum :7788)
 ...
-```
+```text

Apply similarly to lines 56 and 80.

Also applies to: 56-56, 80-80

🤖 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 @.planning/claude-code-provider/PLAN.md at line 21, Add a language specifier
to the three fenced code blocks that contain ASCII diagrams/file trees (the
blocks starting with the diagram line "Frontend  ──invoke──>  Tauri shell 
──HTTP+bearer──>  openhuman-core (Axum :7788)" and the other two similar
ASCII/file-tree blocks) by changing their opening fences from ``` to ```text so
the linter recognizes them; update all three occurrences (including the blocks
referenced in the comment) to use ```text as the opening fence and leave the
closing fences unchanged.
src/openhuman/inference/schemas.rs (1)

828-837: ⚡ Quick win

Add debug/trace logging to the new RPC handler.

This new endpoint has no entry/exit/error logs, which makes CLI probe failures harder to trace in production diagnostics.

🛠️ Minimal logging patch
 fn handle_inference_claude_code_status(_params: Map<String, Value>) -> ControllerFuture {
     Box::pin(async move {
+        tracing::debug!("[rpc][inference] claude_code_status: start");
         let status = tokio::task::spawn_blocking(
             crate::openhuman::inference::provider::claude_code::version_check::probe,
         )
         .await
-        .map_err(|e| format!("claude_code_status join error: {e}"))?;
+        .map_err(|e| {
+            tracing::debug!("[rpc][inference] claude_code_status: join_error={e}");
+            format!("claude_code_status join error: {e}")
+        })?;
+        tracing::debug!("[rpc][inference] claude_code_status: success");
         to_json(RpcOutcome::new(status, vec![]))
     })
 }

As per coding guidelines: Use log / tracing at debug or trace level on RPC entry and exit, error paths, state transitions, and hard-to-infer branches.

🤖 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 `@src/openhuman/inference/schemas.rs` around lines 828 - 837, The new RPC
handler handle_inference_claude_code_status lacks any telemetry; add tracing/log
statements at function entry and exit and on error paths so CLI probe failures
are diagnosable: emit a debug/trace log when the handler is invoked (include any
incoming _params context), trace before/after calling
crate::openhuman::inference::provider::claude_code::version_check::probe, and
log failures from the spawned task with the mapped error string (include the
original error details) before returning the RpcOutcome; use the project's
tracing/log macros (trace! or debug! and error!) consistently for entry,
success, and error branches.
🤖 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 `@app/src-tauri/vendor/tauri-cef`:
- Line 1: The CI guard failed because the pinned SHA for the tauri-cef vendor
was changed to e22ec719034fdac3994c42a3c040fafa10672219 in the tauri-cef vendor
update but .github/tauri-cef-expected-sha was not updated; fix by updating the
contents of .github/tauri-cef-expected-sha to the new SHA
(e22ec719034fdac3994c42a3c040fafa10672219) to match the change in
vendor/tauri-cef, or revert the vendor/tauri-cef bump so both pins remain in
sync in the same PR.

In `@app/src/components/settings/panels/AIPanel.tsx`:
- Around line 87-89: WorkloadRow and the save-bar diffSummary are falling
through to the local branch for the new union variant { kind: 'claude-code'; ...
}; update both to handle the 'claude-code' discriminant exhaustively by adding
an explicit branch/case for kind === 'claude-code' (or pattern-match on kind)
that returns the intended display string (e.g., "Claude Code" and the specific
model name/route) instead of treating it as local/Ollama; modify the logic in
the WorkloadRow component and the diffSummary generation to include that case so
all route display paths correctly represent claude-code routes.

In `@gitbooks/developing/providers/claude-code.md`:
- Around line 77-81: The tool list in the Claude Code provider docs is out of
sync with the locked v1 read-only plan. Update the documented surface in this
section to match the approved symbols from
.planning/claude-code-provider/PLAN.md, including the `memory_search`,
`memory_get`, `threads_list`, `threads_get`, `threads_messages`,
`channels_list`, `channels_messages_read`, `people_search`, `people_get`, and
`webhooks_list` set, and remove the mismatched `core.*`, `tree.*`, `agent.*`,
and `searxng_search` entries unless the plan is updated first. Also ensure
`agent.run_subagent` is not documented as part of v1 since write tools are
deferred; keep the naming consistent with the plan across the docs.
- Around line 66-71: The Auth resolution order section is missing the
per-request/config override and the fallback error state; update the "Auth
resolution order" block to list four steps: first check an explicit key provided
on ChatRequest or in agent/config (per-thread/per-agent override), then
ANTHROPIC_API_KEY env var, then the CLI credentials file
(~/.claude/.credentials.json), and finally the None case which should set
auth_state = "missing" and cause chat() to error; mention that
Subscription/OAuth v2 and OpenHuman's AuthService integration are separate and
won't change this resolution order.

In `@src/openhuman/inference/provider/claude_code/auth.rs`:
- Around line 40-47: The test defaults_to_cli_credentials_without_env currently
skips assertions when the ANTROPIC_API_KEY env var exists; make it deterministic
by ensuring the environment is controlled inside the test: save the original
ANTROPIC_API_KEY, remove or unset it before calling resolve(), run the
assertions that src == AuthSource::CliCredentials and key.is_none(), and finally
restore the original environment variable to avoid side effects; refer to the
test function defaults_to_cli_credentials_without_env and the resolve() call and
AuthSource::CliCredentials to locate where to add the env removal/restoration.

In `@src/openhuman/inference/provider/claude_code/driver.rs`:
- Around line 183-191: Check the input bytes returned by
build_stdin(ctx.messages, is_new) before calling cmd.spawn(): call build_stdin
first, bail with the existing error message if it is empty, and only then spawn
the process (so you don't launch `claude` unnecessarily); update the code paths
around build_stdin, cmd.spawn(), and the child variable (in driver.rs) so the
empty-input validation happens prior to spawning and error handling remains
consistent.

In `@src/openhuman/inference/provider/claude_code/event_mapper.rs`:
- Around line 147-169: The "tool_use" match arm currently uses unwrap_or("") to
build call_id and tool_name and emits ProviderDelta::ToolCallStart and inserts
BlockState even when those values are empty; change the logic in the event
mapping (the "tool_use" arm handling BlockKind::Tool, the BlockState insertion
code and emission of ProviderDelta::ToolCallStart) to validate that both call_id
and tool_name are non-empty strings before inserting into self.blocks or
returning the ToolCallStart delta—if either is empty, skip the
insertion/emission (optionally log or emit a no-op delta) and ensure the same
non-empty validation is applied to the other similar sections referenced (the
other "tool" handling arms that construct call_id/call_name and emit
ToolCallArgsDelta/ToolCallStart).

In `@src/openhuman/inference/provider/claude_code/mod.rs`:
- Around line 11-18: mod.rs currently mixes exports with operational runtime,
hashing/session logic, and tests; split those concerns by moving the
runtime/provider behavior into a new sibling module (e.g., provider.rs), move
thread-hash/session key logic into a thread_key.rs or session_key.rs, and move
tests into a companion tests module/file, then update mod.rs to only re-export
public items (retain pub mod auth; driver; event_mapper; input_builder;
session_store; stream_parser; types; version_check;) and add pub use statements
as needed to expose the new modules' public APIs; ensure function/type names
referenced by other modules (e.g., any provider init functions, session hashing
functions, or thread key types) are kept public in their new files and that mod
declarations are added so compilation continues.
- Around line 119-123: The thread key currently derived only from the first user
message (thread_key_from_messages) can collide across distinct conversations;
change the key derivation to incorporate more stable and unique identifiers
(e.g., include request.user_id or request.session_id if available, or hash the
concatenation of multiple message texts and the message timestamps/indices) so
that thread_id is unique per user-conversation; update the code paths that call
thread_key_from_messages (including the other occurrence around the 146-155
region) to use the new multi-field hash function or helper and ensure thread_id
generation remains deterministic but now includes user and/or timestamp/context
data to avoid cross-chat leakage.

In `@src/openhuman/inference/provider/claude_code/stream_parser.rs`:
- Around line 64-66: The current feed_bytes method pushes a lossy UTF-8 string
per chunk which can corrupt multibyte characters; change the internal buffer
from String to a raw byte buffer (e.g., Vec<u8>), have feed_bytes append chunk
bytes, split on b'\n' to extract complete line bytes, decode each complete line
with String::from_utf8 (returning an error/event on invalid UTF-8 if desired)
and pass decoded lines into the existing feed() logic, leaving any trailing
partial line bytes in the buffer; also update end() to decode and process any
remaining bytes as a final line (using strict from_utf8) before closing.

In `@src/openhuman/inference/provider/factory.rs`:
- Around line 180-181: split_model_and_temperature(model_with_temp) currently
returns a temperature override in _temperature_override which is ignored; update
the surrounding logic so that if _temperature_override is Some(...) you either
propagate an error or reject the input rather than silently dropping it.
Concretely, replace the silent discard of _temperature_override with a check
after let (model, _temperature_override) =
split_model_and_temperature(model_with_temp); and if the override is present
return a clear Err or panic with a message referencing the original
model_with_temp (or otherwise propagate the temperature through the provider
construction path) so callers cannot be misled by an ignored @<temp> suffix.

---

Nitpick comments:
In @.planning/claude-code-provider/PLAN.md:
- Line 21: Add a language specifier to the three fenced code blocks that contain
ASCII diagrams/file trees (the blocks starting with the diagram line "Frontend 
──invoke──>  Tauri shell  ──HTTP+bearer──>  openhuman-core (Axum :7788)" and the
other two similar ASCII/file-tree blocks) by changing their opening fences from
``` to ```text so the linter recognizes them; update all three occurrences
(including the blocks referenced in the comment) to use ```text as the opening
fence and leave the closing fences unchanged.

In `@gitbooks/developing/providers/claude-code.md`:
- Line 88: Update the wording to explicitly state that the Semaphore(4) is a
single global concurrency cap shared by all CC turns (not role-specific);
mention the global Semaphore(4) defined in driver.rs and that all agentic
runs/CC turns compete for the same permit, causing queued waits under load
instead of role-scoped limits or fast failures. Adjust the sentence referencing
"agentic runs share the same Semaphore(4)" to clarify it is a global semaphore
in driver.rs used by all CC turns regardless of role.

In `@src/openhuman/inference/schemas.rs`:
- Around line 828-837: The new RPC handler handle_inference_claude_code_status
lacks any telemetry; add tracing/log statements at function entry and exit and
on error paths so CLI probe failures are diagnosable: emit a debug/trace log
when the handler is invoked (include any incoming _params context), trace
before/after calling
crate::openhuman::inference::provider::claude_code::version_check::probe, and
log failures from the spawned task with the mapped error string (include the
original error details) before returning the RpcOutcome; use the project's
tracing/log macros (trace! or debug! and error!) consistently for entry,
success, and error branches.
🪄 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: 584f8968-43b5-4224-8b59-54b5cd11f565

📥 Commits

Reviewing files that changed from the base of the PR and between 7fe3dd0 and 7c33199.

📒 Files selected for processing (21)
  • .planning/claude-code-provider/PLAN.md
  • app/src-tauri/vendor/tauri-cef
  • app/src/components/settings/panels/AIPanel.tsx
  • app/src/components/settings/panels/ai/ClaudeCodeStatusCard.tsx
  • app/src/components/settings/panels/ai/__tests__/ClaudeCodeStatusCard.test.tsx
  • app/src/services/api/aiSettingsApi.ts
  • app/src/utils/tauriCommands/config.ts
  • gitbooks/developing/providers/claude-code.md
  • src/openhuman/inference/provider/claude_code/auth.rs
  • src/openhuman/inference/provider/claude_code/driver.rs
  • src/openhuman/inference/provider/claude_code/event_mapper.rs
  • src/openhuman/inference/provider/claude_code/input_builder.rs
  • src/openhuman/inference/provider/claude_code/mod.rs
  • src/openhuman/inference/provider/claude_code/session_store.rs
  • src/openhuman/inference/provider/claude_code/stream_parser.rs
  • src/openhuman/inference/provider/claude_code/types.rs
  • src/openhuman/inference/provider/claude_code/version_check.rs
  • src/openhuman/inference/provider/factory.rs
  • src/openhuman/inference/provider/mod.rs
  • src/openhuman/inference/schemas.rs
  • tests/claude_code_stream_e2e.rs

Comment thread app/src-tauri/vendor/tauri-cef Outdated
Comment thread app/src/components/settings/panels/AIPanel.tsx
Comment thread gitbooks/developing/providers/claude-code.md Outdated
Comment thread gitbooks/developing/providers/claude-code.md
Comment thread src/openhuman/inference/provider/claude_code/auth.rs
Comment thread src/openhuman/inference/provider/claude_code/event_mapper.rs
Comment thread src/openhuman/inference/provider/claude_code/mod.rs
Comment thread src/openhuman/inference/provider/claude_code/mod.rs
Comment thread src/openhuman/inference/provider/claude_code/stream_parser.rs
Comment thread src/openhuman/inference/provider/factory.rs Outdated
Adds a separate `openhuman.claude_code_auth_status` RPC and surfaces the
result in the settings card so Claude Pro/Max users can see they're
signed in without staring at "Not installed/configured" badges.

- New `auth_status.rs` module: tolerant parse of
  `~/.claude/.credentials.json` (overridable via
  `OPENHUMAN_CLAUDE_CREDENTIALS` for tests). Returns
  `subscription | api_key_env | none` with optional account_email +
  expires_at. Token never leaves the file — only metadata round-trips.
- Tolerant to schema drift: any parse failure still returns
  `Subscription { account_email: None, expires_at: None }` since the
  file existing is strong evidence of login.
- Auth probe is independent of version probe: pure FS, no spawn. UI
  refreshes them separately so a user who just ran `claude login` can
  recheck auth without re-spawning the binary.
- Settings card: badge + Recheck button + sign-in/out hints
  (delegates to `claude login` / `claude logout` — no in-app file
  mutation to avoid half-state with the CLI).
- PLAN.md §2 + §13 updated: subscription detection moved from v2
  non-goals to v1.1.

Tests: 4 Rust unit tests (parse shapes incl. drift fallback) + 4 new
RTL tests (subscription/api-key/none/independent-recheck).
Three independent v1.1 features, plus a write-tools threat model.

**Cost wiring** — `event_mapper` now plumbs `result.total_cost_usd`
from CC's stream into `UsageInfo.charged_amount_usd`, so downstream
`cost.rs` can record per-turn spend without re-pricing tokens × model
rates. Synthesizes an empty `UsageInfo` for cost-only result frames.

**In-app `claude login`** — new `claude_code_login_launch` Tauri
command spawns the user's native terminal running `claude login`
(Windows: `cmd /k`, macOS: `osascript` → Terminal.app, Linux: tries
`x-terminal-emulator` → `gnome-terminal` → `konsole` → `xfce4-terminal`
→ `xterm`). The OAuth flow itself stays in the terminal — we can't
host the interactive paste-the-code step in-app. Settings card grew
a "Sign in with Claude" button that triggers this and an explainer.

**Provider picker UI** — `CustomRoutingDialog` now exposes
`Claude Code CLI` as a 3rd source option (alongside cloud providers
and local Ollama). Model is a free-text input (`sonnet-4-5` default)
because CC accepts arbitrary model strings — passed verbatim to
`claude --model`. ProviderRef discriminator `claude-code` is round-
tripped through serialize/parse and the diff summary.

**Write-tools threat model**
`.planning/claude-code-provider/WRITE-TOOLS-THREAT-MODEL.md`
documents 5 attack scenarios (injected exfiltration, persistent
memory poison, webhook hijack, cross-thread leakage, people graph
corruption) and the 8 controls needed before any write tool ships
to the MCP surface. Recommends deferring to v1.2 — approval/audit
infra is its own project.

Tests: 27/27 Rust + 25/25 frontend (incl. 4 new auth tests and the
AIPanel naming-collision fix — renamed card's "Refresh" button to
"Probe" to disambiguate from heartbeat's Refresh).
Copy link
Copy Markdown
Contributor

@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

♻️ Duplicate comments (1)
app/src/components/settings/panels/AIPanel.tsx (1)

1531-1539: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle claude-code explicitly in route/summarization display paths.

Line 1537 and Line 2063 still fall through to local formatting for the claude-code variant, so UI labels and save summaries can be misleading (Ollama / local:*).

Also applies to: 2059-2064

🤖 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 `@app/src/components/settings/panels/AIPanel.tsx` around lines 1531 - 1539, The
current branch that sets the human-readable label for models treats any
non-'openhuman' and non-'cloud' ref_.kind as Ollama, which causes 'claude-code'
to be mis-labeled; update the label/resolution logic where resolved is computed
(the block referencing ref_.kind, selectedCloud and ref_.model) to explicitly
check for ref_.kind === 'claude-code' and format it with the correct provider
string (e.g., 'Claude Code · {ref_.model}' or another appropriate label) instead
of falling back to the Ollama/local path; apply the same explicit handling to
the other display/summarization formatting code paths that use the same pattern
(the nearby save/summary formatter that composes provider/model strings using
selectedCloud and ref_.model) so 'claude-code' no longer gets misrepresented as
Ollama/local.
🧹 Nitpick comments (1)
app/src/utils/tauriCommands/config.ts (1)

267-313: 🏗️ Heavy lift

Consider extracting Claude Code RPC types/commands into a dedicated module.

config.ts has grown past the preferred source-file size, and these additions are a clean split point (e.g., tauriCommands/claudeCode.ts).

As per coding guidelines **/*.{js,ts,tsx,jsx}: Prefer files ≤ ~500 lines per source file; split modules when growing to maintain readability and single responsibility.

🤖 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 `@app/src/utils/tauriCommands/config.ts` around lines 267 - 313, This file is
hitting the size guideline — extract the Claude Code RPC types and functions
into a dedicated module: create a new module (e.g., tauriCommands/claudeCode.ts)
and move the ClaudeCodeAuthStatus type plus the openhumanClaudeCodeAuthStatus
and openhumanClaudeCodeLoginLaunch functions there, keeping their signatures and
Tauri checks intact; export them from the new module and update any imports that
previously referenced these symbols from config.ts to import from the new
tauriCommands/claudeCode module so existing call sites keep working.
🤖 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 @.planning/codebase/CONCERNS.md:
- Line 67: Update the CONCERNS.md sentence that currently claims "v1 calls
Anthropic HTTP API directly" to reflect that this provider is CLI-driven: change
the note to state v1 uses the Anthropic CLI (not the HTTP API) and that v2 will
migrate to OpenHuman's native streaming surface; target the note referencing the
claude_code module (claude_code::mod.rs) so future work doesn't assume an
HTTP-based transport.

In @.planning/codebase/INTEGRATIONS.md:
- Around line 8-10: Update the maturity note for the "Anthropic Claude Code CLI"
provider that currently says "Phase 1" to reflect the actual implemented scope:
replace the Phase 1 scaffold tag with a concise status like "Implemented
(includes streaming, auth, session store, types, and version checks)" and/or
list the implemented modules (mod.rs, driver.rs, stream_parser.rs,
event_mapper.rs, input_builder.rs, session_store.rs, auth.rs, types.rs,
version_check.rs) so the doc accurately reflects the shipped functionality.

In @.planning/codebase/STRUCTURE.md:
- Line 7: The fenced code block starting with triple backticks in the
STRUCTURE.md doc lacks a language identifier; update that opening fence (```) to
include a language token (e.g., ```text) so the snippet renders and lints
correctly, ensuring the block that lists the project tree (starting with
"openhuman/") is updated to use the language-specified fence.

In `@app/src-tauri/src/claude_code.rs`:
- Around line 58-61: The Linux branch constructs the terminal args incorrectly
by passing "claude login" as one argument; update the Command invocation that
currently uses Command::new(term).args(["-e", "claude login"]).spawn() to pass
the command and its argument as separate argv entries (e.g., "-e", "claude",
"login") so the terminal treats "claude" as the executable and "login" as its
argument; modify the args call in the same function/closure where
Command::new(term) is used to supply multiple &str entries instead of a single
space-containing string.

In `@app/src/components/settings/panels/AIPanel.tsx`:
- Around line 1728-1734: The computed noProviders flag in AIPanel.tsx currently
uses only customCloud and localAvailable and thus hides the Claude Code option;
update the condition that defines noProviders to also consider the
always-available Claude Code source (e.g., include a boolean like
claudeCodeAvailable or reference the existing
ClaudeCodeStatusCard/claudeCodeEnabled flag) so that noProviders is false when
Claude Code is present; make the same change for the equivalent check around
lines 1765-1769 so the dialog and picker both show the Claude Code option when
cloud/local providers are absent.

In `@src/openhuman/inference/provider/claude_code/auth_status.rs`:
- Around line 213-236: The test probe_returns_none_when_no_env_and_no_file
mutates global environment variables and can race with other tests; wrap the env
setup/teardown in a process-global test lock to serialize access (e.g., acquire
a global ENV_LOCK mutex at the start of
probe_returns_none_when_no_env_and_no_file and release it after restoring vars)
so probe() and assertions about AuthSource::None run with exclusive access;
ensure the lock is a static/global (OnceCell/lazy_static) so all tests use the
same mutex.

---

Duplicate comments:
In `@app/src/components/settings/panels/AIPanel.tsx`:
- Around line 1531-1539: The current branch that sets the human-readable label
for models treats any non-'openhuman' and non-'cloud' ref_.kind as Ollama, which
causes 'claude-code' to be mis-labeled; update the label/resolution logic where
resolved is computed (the block referencing ref_.kind, selectedCloud and
ref_.model) to explicitly check for ref_.kind === 'claude-code' and format it
with the correct provider string (e.g., 'Claude Code · {ref_.model}' or another
appropriate label) instead of falling back to the Ollama/local path; apply the
same explicit handling to the other display/summarization formatting code paths
that use the same pattern (the nearby save/summary formatter that composes
provider/model strings using selectedCloud and ref_.model) so 'claude-code' no
longer gets misrepresented as Ollama/local.

---

Nitpick comments:
In `@app/src/utils/tauriCommands/config.ts`:
- Around line 267-313: This file is hitting the size guideline — extract the
Claude Code RPC types and functions into a dedicated module: create a new module
(e.g., tauriCommands/claudeCode.ts) and move the ClaudeCodeAuthStatus type plus
the openhumanClaudeCodeAuthStatus and openhumanClaudeCodeLoginLaunch functions
there, keeping their signatures and Tauri checks intact; export them from the
new module and update any imports that previously referenced these symbols from
config.ts to import from the new tauriCommands/claudeCode module so existing
call sites keep working.
🪄 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: fbc80122-4ac7-4c60-8db2-968fab23844b

📥 Commits

Reviewing files that changed from the base of the PR and between 7c33199 and 43a5a02.

📒 Files selected for processing (19)
  • .planning/claude-code-provider/PLAN.md
  • .planning/claude-code-provider/WRITE-TOOLS-THREAT-MODEL.md
  • .planning/codebase/ARCHITECTURE.md
  • .planning/codebase/CONCERNS.md
  • .planning/codebase/CONVENTIONS.md
  • .planning/codebase/INTEGRATIONS.md
  • .planning/codebase/STACK.md
  • .planning/codebase/STRUCTURE.md
  • .planning/codebase/TESTING.md
  • app/src-tauri/src/claude_code.rs
  • app/src-tauri/src/lib.rs
  • app/src/components/settings/panels/AIPanel.tsx
  • app/src/components/settings/panels/ai/ClaudeCodeStatusCard.tsx
  • app/src/components/settings/panels/ai/__tests__/ClaudeCodeStatusCard.test.tsx
  • app/src/utils/tauriCommands/config.ts
  • src/openhuman/inference/provider/claude_code/auth_status.rs
  • src/openhuman/inference/provider/claude_code/event_mapper.rs
  • src/openhuman/inference/provider/claude_code/mod.rs
  • src/openhuman/inference/schemas.rs
✅ Files skipped from review due to trivial changes (3)
  • .planning/claude-code-provider/WRITE-TOOLS-THREAT-MODEL.md
  • .planning/codebase/TESTING.md
  • .planning/claude-code-provider/PLAN.md

Comment thread .planning/codebase/CONCERNS.md Outdated
Comment thread .planning/codebase/INTEGRATIONS.md Outdated
Comment thread .planning/codebase/STRUCTURE.md Outdated
Comment thread app/src-tauri/src/claude_code.rs Outdated
Comment thread app/src/components/settings/panels/AIPanel.tsx Outdated
Comment thread src/openhuman/inference/provider/claude_code/auth_status.rs
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

Review — Claude Code CLI Provider (Phases 1–5 + v1.1)

Solid feature implementation. The architecture is well thought out — clean module boundaries, proper use of the Provider trait, good streaming pipeline. The threat model doc is especially appreciated.

I have three findings that CodeRabbit did not catch — two are safety-critical for production use:

Severity File Issue
critical driver.rs No turn timeout — stuck CLI hangs forever
major driver.rs No kill_on_drop(true) — orphaned processes on cancellation
major mod.rs DefaultHasher not stable across Rust versions — sessions break on rebuild

CodeRabbit already flagged the submodule pin, lossy UTF-8 in the parser, Linux terminal arg construction, empty tool-call ids, and the pre-spawn validation ordering — I'm not repeating those. Please address their findings alongside mine.

Overall the code quality is high, tests are comprehensive (27 unit + 1 integration + 25 frontend), and the phased rollout plan is sound. Fix the timeout + kill-on-drop gap and this is close to shippable.

Comment thread src/openhuman/inference/provider/claude_code/driver.rs
Comment thread src/openhuman/inference/provider/claude_code/driver.rs
Comment thread src/openhuman/inference/provider/claude_code/mod.rs
@oxoxDev oxoxDev assigned oxoxDev and unassigned oxoxDev May 28, 2026
@senamakel senamakel self-assigned this Jun 3, 2026
senamakel added 7 commits June 2, 2026 20:22
# Conflicts:
#	app/src-tauri/src/lib.rs
#	app/src/components/settings/panels/AIPanel.tsx
#	src/openhuman/inference/provider/mod.rs
Addresses @graycyrus review:
- Add 5-minute TURN_TIMEOUT around the streaming + wait loop so a
  stuck CLI process doesn't block the task forever (PLAN §8).
- Set kill_on_drop(true) on the Command so cancelled Tokio tasks
  clean up the child process.
- Validate input (build_stdin) before spawning the child to avoid
  launching a process we can't feed.
Replace DefaultHasher (not guaranteed stable across Rust compiler
versions) with SHA-256 for deriving thread session keys. Prevents
persisted session lookups from breaking on toolchain updates.

Addresses @graycyrus review on mod.rs:148.
Don't emit ToolCallStart/ToolCallArgsDelta with empty identifiers —
downstream tool-call matching becomes ambiguous. Also add missing
reasoning_content field to ChatResponse construction.

Addresses CodeRabbit on event_mapper.rs:169.
- Add claude-code case to providerRefSignature (fixes TS2366)
- Handle claude-code in selectedRef + applySelection (fixes TS2339)
- Fix noProviders gate: Claude Code CLI is always available as a
  source, so the empty-state should never block the dialog.

Addresses CodeRabbit on AIPanel.tsx:89,1734.
- Log warning when @<temp> suffix is parsed but ignored in factory.
- Fix auth test to always assert (not skip when env var is set).
- Fix Linux terminal emulator args: gnome-terminal uses `--`,
  xfce4-terminal gets the command as a single arg, others split.
- Update auth resolution docs to match v1.1 implementation.

Addresses CodeRabbit on factory.rs:181, auth.rs:47, claude_code.rs:61,
claude-code.md:71.
Remove .planning/ directory and PR_DESCRIPTION.md (internal planning
artifacts that don't belong in the repo). Reset tauri-cef submodule
pointer to match main. Apply formatter to ClaudeCodeStatusCard.
@coderabbitai coderabbitai Bot added the rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. label Jun 3, 2026
@senamakel senamakel merged commit 9d28a72 into tinyhumansai:main Jun 3, 2026
24 of 32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants