feat(agent): add Jcode as a native persistent-server ACP runtime - #1
Open
coderberry wants to merge 1 commit into
Open
feat(agent): add Jcode as a native persistent-server ACP runtime#1coderberry wants to merge 1 commit into
coderberry wants to merge 1 commit into
Conversation
Implement the "Jcode Native Runtime Adapter" prototype spec: a first-party jcode provider that executes every Multica task as one session on a shared, Multica-scoped persistent `jcode serve` daemon, reached through the upstream `jcode acp` stdio shim over ACP v1. Gated behind MULTICA_EXPERIMENTAL_JCODE. Transport decision and the live-probe evidence are recorded in docs/adr/ADR-JCODE-TRANSPORT.md (Phase A spike deliverable). Every protocol claim was verified against a real jcode v0.80.2 binary and its source: the runtime-dir single-instance lock, SUN_LEN socket limits, spawn-lock-protected autostart, session/resume without history replay, the silent fresh-session resume of an unknown id (hence resumeRejectionUndetectable), ignored session-scoped mcpServers (MCP reported unsupported), set_model and the reasoning_effort config option, per-turn usage, and ~60ms session/cancel acknowledgment. Backend (pkg/agent/jcode.go, reusing the shared hermesClient transport): - Pins every task shim (and anything it autostarts) to a Multica-scoped server via JCODE_RUNTIME_DIR/JCODE_SOCKET (default ~/.multica/jcode), appended last so nothing re-routes task execution; socket paths are validated absolute and SUN_LEN-safe. - Graceful cancellation: a running turn survives shim death by design, so runCtx cancellation sends session/cancel and waits a bounded interrupt window (MULTICA_JCODE_INTERRUPT_TIMEOUT, 10s) for stopReason=cancelled before the group kill; unacknowledged interrupts log the session id as potentially orphaned and never touch the shared server. - Provider-level concurrency slots per server socket (MULTICA_JCODE_MAX_CONCURRENT, default 4), held for the whole execution, cancellation-aware while waiting. - External-server mode: MULTICA_JCODE_AUTOSTART=0 probes the socket and fails fast instead of starting anything. - session/resume for reattachment, capability-gated on initialize; set_model failures fail the task (never silently run the wrong model); ThinkingLevel flows through applyACPEffortOption (jcode's application is verified upstream, GH multica-ai#6720); usage attributed to the effective model. Wiring follows the ZeroClaw playbook: SupportedTypes/New/launchHeaders, blocked-args policy, MinVersions (0.80.0), ACP model discovery from session/new (pinned to the scoped server), acpCatalogThinkingProviders, feature-flag-gated daemon probe with MULTICA_JCODE_PATH/MODEL, AGENTS.md context delivery, metrics label, migration 433 widening the protocol_family whitelist, default-command-name registration, frontend provider union + MCP-unsupported flag + placeholder logo, and env-vars docs (en/ja/ko/zh). Tests mirror the ACP backend conventions (fresh session, resume-not-load with replay-leak guard, resume-unsupported rejection, graceful and orphaned cancellation, timeout classification, slot semantics, autostart preflight, socket validation, blocked args, env knob parsing) plus enrollment in the shared deliverable-boundary suite and a probe feature-flag gate test. Real-binary smoke tests behind the agentintegration tag prove the spec's demonstration scenario end-to-end: AGENTS.md + tool execution in the bound worktree, resume of the same session through the persistent server after the first shim exited (context recalled), and two concurrent sessions where cancelling one leaves the other to complete. docs/JCODE_PROVIDER.md covers install, the feature flag, managed vs external server, configuration, concurrency, cancellation, recovery limitations, troubleshooting, and uninstall. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Adds Jcode (1jehuang/jcode) as a first-party agent runtime, implementing the "Jcode Native Runtime Adapter" prototype spec (gist). Unlike process-per-task providers, every Multica task runs as one session on a shared persistent
jcode servedaemon: the per-task process (jcode acp) is a thin ACP v1 stdio shim, sessions survive daemon and shim restarts, and cancelling one task interrupts only its own session. The provider is gated behindMULTICA_EXPERIMENTAL_JCODE=1— with the flag unset, jcode is never detected, registered, or started.Why this approach: the spec forbids depending on jcode's private daemon protocol. The spike (recorded in
docs/adr/ADR-JCODE-TRANSPORT.md) found jcode already ships the stable bridge the spec sketches —jcode acp, an upstream-owned ACP adapter backed by the persistent daemon — and Multica already has ten ACP providers on a shared transport (hermesClient). The backend therefore reuses that infrastructure and pins execution to a Multica-scoped server (JCODE_RUNTIME_DIR/JCODE_SOCKET, default~/.multica/jcode) so tasks never collide with the user's interactive jcode.Related Issue
No tracked issue — built from the prototype specification linked above. The ADR (
docs/adr/ADR-JCODE-TRANSPORT.md) records the spec's required spike answers and the deliberate deviations.Type of Change
Changes Made
server/pkg/agent/jcode.go— the backend: Multica-scoped server pinning (env injected last so nothing re-routes it), SUN_LEN-safe socket validation, graceful cancellation (session/cancel+ boundedMULTICA_JCODE_INTERRUPT_TIMEOUTwait forstopReason:"cancelled"before group kill; orphaned sessions logged, shared server never killed), per-socket concurrency slots (MULTICA_JCODE_MAX_CONCURRENT, default 4), external-server mode (MULTICA_JCODE_AUTOSTART=0→ fail fast on dead socket),session/resumereattachment (capability-gated, no history replay),session/set_model(failure fails the task), reasoning effort viaapplyACPEffortOption, per-model usage attribution.server/pkg/agent/{agent,launch,version,models,thinking}.go— SupportedTypes/New/launchHeaders, blocked-args policy, MinVersions 0.80.0, ACP model discovery pinned to the scoped server,acpCatalogThinkingProvidersentry.server/internal/daemon/agents_probe.go(+config.go) — feature-flag-gated probe withMULTICA_JCODE_PATH/MULTICA_JCODE_MODEL.server/internal/daemon/execenv/runtime_config.go— AGENTS.md context delivery (jcode loads it as session bootstrap input).server/internal/metrics/labels.go,scripts/agent-cli-command-names.txt.server/migrations/433_runtime_profile_add_jcode.{up,down}.sql— protocol_family whitelist widening (NOT VALID, matching migration 403's pattern).packages/core/types/agent.ts,packages/core/agents/mcp-support.test.ts,packages/views/runtimes/components/provider-logo.tsx— provider union, MCP-unsupported flag (jcode validates and dropsmcpServers; MCP lives in~/.jcode/mcp.json), placeholder logo.server/pkg/agent/jcode_test.go(fake ACP server: fresh session, resume-not-load with replay-leak guard, resume-unsupported rejection, graceful + orphaned cancellation, timeout classification, slot semantics, autostart preflight, socket validation, blocked args, env knobs), enrollment in the shared deliverable-boundary suite,server/internal/daemon/agents_probe_jcode_test.go(flag gate),server/pkg/agent/jcode_integration_test.go(real-binary smoke behindagentintegration).docs/adr/ADR-JCODE-TRANSPORT.md,docs/JCODE_PROVIDER.md(operator guide),apps/docs/content/docs/environment-variables.{,ja.,ko.,zh.}mdx, creating-agents built-in skill + source map.How to Test
cd server && go test ./pkg/agent ./internal/daemon ./internal/daemon/execenv ./internal/metrics -count=1— unit + fake-server suites, no model credentials needed.pnpm typecheck && pnpm test— frontend union, MCP flag, logo.cd server && MULTICA_RUN_REAL_AGENT_SMOKE=1 MULTICA_JCODE_SMOKE_MODEL=<working-model> go test -tags=agentintegration ./pkg/agent -run 'TestJcodeReal' -count=1 -v— runs the spec's demonstration scenario (tool execution in the bound worktree, resume of the same session after shim death, two concurrent sessions with one cancelled). Uses the authenticated account and consumes quota.MULTICA_EXPERIMENTAL_JCODE=1 make dev, create an agent on the Jcode runtime, assign an issue, watch progress stream; cancel a second task mid-run and confirm the first continues.All of 1–3 were run locally and pass (real smoke against jcode v0.80.2-dev: both tests green — session resume recalled prior-turn context through the persistent server; concurrent cancel interrupted only its own session, ~60 ms ack). Not run: step 4's full web-UI flow against a live workspace; risk is limited to registration/UI wiring, which follows the ZeroClaw pattern exactly and is covered by the probe/display/union tests.
Checklist
docs/adr/ADR-JCODE-TRANSPORT.md(spike findings → transport decision → deviations), plus the backend's header comment mapping each design constraint to its verified causeapps/web/features/landing/i18n/) and relevant docs (apps/docs/content/docs/) — docs synced (env-vars ×4 languages + provider guide); landing copy deliberately not updated: the "supported coding tools" marketing list advertises out-of-the-box providers, and this one is experimental behindMULTICA_EXPERIMENTAL_JCODE. A landing/changelog entry belongs with the release that lifts the flag (same treatment as ZeroClaw/MiniMax Code, which entered landing copy via changelog entries at release time).apps/docs/content/docs/developers/conventions.zh.mdx(terminology, mixed-rule fortask/issue/skill)AI Disclosure
AI tool used: Claude Code (Fable 5)
Prompt / approach:
/goal Build out the following spec: <gist URL>. The session ran the spec's required Phase A spike first — driving the real installedjcodebinary over ACP stdio with a Python probe and reading the upstream Rust source — and recorded every finding in the ADR before writing Go. Implementation deliberately mirrored the most recent provider addition (ZeroClaw, multica-ai#7351) as a touchpoint checklist, including its "verify against the real binary, don't assume the handshake" lesson: resume-of-unknown-session, MCP no-op, cancel semantics, and the runtime-dir lock were all discovered empirically, not assumed. Real-agent smoke tests were run under the repo'sMULTICA_RUN_REAL_AGENT_SMOKE=1convention.Risks / notes for review
jcode server stop --forceincantation.session/resumefor an unknown id by creating an empty session under that id, so a refused resume is undetectable → jcode is inresumeRejectionUndetectable. Flagged as an upstream follow-up in the ADR.jcode.go(promptCtxoutlivingrunCtxby the interrupt window) and the slot table's fixed-size-per-socket semantics.🤖 Generated with Claude Code