Skip to content

Add Claude Code delegation to Maple Agent - #976

Open
benthecarman wants to merge 5 commits into
MaplePrivacyLabs:masterfrom
benthecarman:claude-code-support
Open

benthecarman wants to merge 5 commits into
MaplePrivacyLabs:masterfrom
benthecarman:claude-code-support

Conversation

@benthecarman

@benthecarman benthecarman commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Adds Claude Code delegation alongside Codex in Maple Agent. Tasks can stream activity, answer approval and question cards, resume delegated sessions, and stop their child processes. The native Rust transport is adapted from the pinned Goose provider and requires only the installed Claude CLI.

The Claude card uses its logo and checks claude auth status --json to show signed-in, signed-out, or unknown status. Status probes are bounded and account details are not retained. Failed launches before session confirmation retry with a fresh session instead of trying to resume an unsaved UUID. Claude's multiSelect questions support multiple choices and optional notes in Maple's question card.

For both providers, Settings controls availability in the composer. Each task must explicitly select a provider; disabling it in Settings hides it and blocks saved selections on the next run. Task choices persist across restarts.

Validation:

  • The component's full just ci recipe passed on NixOS using installed host tools: formatting, four Clippy configurations, warning-denied workspace builds, 809 workspace tests, and 35 headless tests. This was not a pinned nix develop run.
  • Native Rust CLI fixtures cover streaming, confirmed-session resumption and failed-start recovery, provider isolation, approvals, multiple-choice answers, cancellation, malformed output, process cleanup, and authentication probe failures/timeouts. The cancellation fixture re-executes itself as a sleeping child and needs no host sleep executable.
  • Settings gates and session tool refresh tested with warm and cold runtimes and ACP exclusion.
  • The native question-card fixture passed interactive Linux checks in light/dark themes: multiple selection and deselection, numbered shortcuts, notes, advancing to a single-choice question, and Vim cursor movement/Enter toggling. Runtime broker tests cover answer delivery; the visual fixture runs without authentication or inference.
  • Earlier Linux debug-app checks verified the Claude logo, live sign-in status in light/dark themes, and the Settings toggle. Authenticated composer interaction was not exercised in the isolated offline UI profile.
  • An earlier non-Nix Linux release build passed, and the user tested the uploaded delegation build.

Native GUI checks ran on Linux only.

Let Maple tasks delegate to an installed Claude Code CLI through a Rust
transport adapted from Goose. Share Codex's activity, approval,
question, and cancellation controls while keeping process ownership in
Maple.

Cover streaming, resumption, provider isolation, permissions, failures,
and process cleanup with native CLI fixtures.
Show Codex and Claude in the composer only when enabled in Settings.
Require each task to opt in, and block saved selections while Settings
is disabled. Preserve task choices across restarts and re-enablement.

Exercise admission, composer visibility, and cached tool refresh for
both providers, including rejection of direct requests when disabled.
Explain Claude CLI setup, native transport provenance, and the separate
Settings and task controls. Record the fixture validation workflow so
future provider changes preserve the shared lifecycle contract.

@AnthonyRonning AnthonyRonning 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.

Two non-blocking findings from a local review against claude 2.1.258 (stream-json protocol, interrupt, resume, and AskUserQuestion all verified outside the GUI). Details inline.

let existing_thread = self.state.lock().await.thread_id.clone();
let claude_thread = existing_thread
.clone()
.unwrap_or_else(claude::new_session_id);

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.

A failed first Claude launch strands the agent. For Claude, ThreadStart echoes this locally generated UUID, so state.thread_id is committed (below, after the handshake) before the CLI has persisted anything. If the first turn dies at startup (not signed in, an --effort/--model value the CLI rejects, any usage error), every later agent_send on that agent runs --resume <uuid>. On 2.1.258 that returns result subtype=error_during_execution with stderr No conversation found with session ID: ..., which Maple renders as the same generic "could not complete this request" text, so the user cannot tell the agent is permanently broken. Codex only records a thread after thread/start succeeds.

Suggestion: commit the Claude session ID only once the child has emitted system/init (or the first successful result), or fall back to --session-id with the same UUID when a resume fails immediately with no turns.

.filter(|(_, question)| question.is_object())
.map(|(i, question)| {
let mut question = question.clone();
question["id"] = format!("q{i}").into();

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.

Multi-select questions become single-select. AskUserQuestion sends multiSelect: true per question (verified on 2.1.258), but parse_user_questions in developer_tools.rs only keeps id/header/question/options, so the question card lets the user pick one option. The answer path in respond already joins several values with , , so only the card side is missing. Not blocking, but worth carrying multiSelect through the projection here so the card can allow multiple picks.

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