cuekit currently has tmux-pane adapters for Claude Code, OpenCode, and pi. We want to add jcode as another child runtime while preserving the key cuekit UX:
- parent agents can attach to the live child pane with tmux;
- parent agents can steer the running child with
steer_task; - child output is captured in the normal cuekit transcript path;
- child tasks still receive cuekit's child reporting contract.
The obvious command, jcode run <message>, is non-interactive: it streams one request and exits. That is useful for a simple submit/result adapter, but it does not match the Claude Code / OpenCode live-pane workflow because follow-up steering cannot reliably become additional input to the running agent.
Observed from local jcode --help:
jcode run [OPTIONS] <MESSAGE>
jcode repl [OPTIONS]
# global / subcommand options include:
-C, --cwd <CWD>
-m, --model <MODEL>
--provider-profile <PROVIDER_PROFILE>
--no-updatejcode run is documented as “Run a single message and exit”. jcode repl is documented as “Run in simple REPL mode (no TUI)”.
Implement the first jcode cuekit adapter using jcode repl, not jcode run.
The launch command should run inside cuekit's existing tmux pane backend and pipe the initial rendered task prompt into the REPL, then keep stdin connected for later steering:
(printf '%s\n' '<rendered task prompt>'; cat) | jcode repl --no-update [-m '<model>']The adapter should be a normal createPaneAdapter consumer.
Because jcode v0.11.x records active sessions in ~/.jcode/active_pids/<session_id>, the launch wrapper must also account for REPL lifecycle cleanup. jcode repl marks its session active when the agent is created, but the observed normal REPL exit path does not mark the session closed. If cuekit simply lets the REPL process exit or kills the tmux pane, the next plain jcode TUI launch can see a dead PID marker and auto-restore the REPL session as an unexpected shutdown.
The cuekit wrapper should therefore run jcode repl as a child process, keep its PID, wait for it to exit, and remove only the active_pids marker whose file contents equal that child PID. This cleanup is intentionally narrow so it does not affect unrelated live jcode sessions.
Proposed capabilities:
{
agent_kind: "jcode",
supports_steering: true,
supports_attach: true,
supports_model_selection: true,
supports_artifacts: true,
supports_live_progress: false,
}Model selection is enabled because jcode repl --help exposes -m, --model <MODEL>.
jcode run remains a possible future “batch” mode, but it should not be the default adapter mode because it is explicitly single-shot. In cuekit terms:
- attach would show a streaming command, but not a persistent interactive session;
steer_taskwould send keys to a pane whose process may ignore stdin or already be exiting;- the child would be less similar to Claude Code / OpenCode tasks, where the parent can observe and steer a live runtime.
jcode repl better matches cuekit's current adapter semantics.
A pure builder should live in packages/adapters/src/jcode-adapter.ts:
export function buildJcodeReplLaunchCommand(spec: TaskSpec, jcodeBin = "jcode"): string {
const parts = [jcodeBin, "repl", "--no-update"];
if (spec.model) parts.push("--model", shellQuote(spec.model));
return `(printf '%s\\n' ${shellQuote(renderTaskSpecPrompt(spec))}; cat) | ${parts.join(" ")}`;
}Implementation should ensure:
- the rendered prompt is shell-quoted;
- model values are shell-quoted;
- a prompt starting with
-is treated as text, not an option; catkeeps the pipeline alive for subsequenttmux send-keyssteering;- the wrapper removes only the stale
~/.jcode/active_pids/*marker owned by the exitedjcode replchild process, preventing ghost auto-restore on future plainjcodelaunches; - the command still runs under
wrapLaunchCommandWithExitCodefrom the shared pane adapter, so normal terminal status inference still works.
jcode does not expose an obvious equivalent to Claude Code / OpenCode --dangerously-skip-permissions in the observed help output. Therefore the first adapter should ignore adapter_options.dangerously_skip_permissions and should not advertise permission bypass behavior.
Project config may still select agent_kind: jcode as a safe adapter default. Permission-bypass docs should not imply jcode participates in bypass semantics unless a jcode-specific option is verified later.
Expected implementation files:
- Create
packages/adapters/src/jcode-adapter.ts. - Export it from
packages/adapters/src/index.ts. - Register it in the MCP adapter registry wiring alongside Claude Code, OpenCode, and pi.
- Add adapter tests in
packages/adapters/__tests__/stub-adapters.test.tsor a dedicatedjcode-adapter.test.ts. - Update MCP command / stdio tests that assert adapter list length or exact agent kinds.
- Update docs / README adapter lists.
Adapter-level tests:
createJcodeAdapter(...).capabilities()returnsagent_kind: "jcode",supports_attach: true,supports_steering: true,supports_model_selection: true.buildJcodeReplLaunchCommand({ agent_kind: "jcode", objective: "x" })usesjcode repl --no-updateand the(printf ...; cat) | ...shape.- Model names are shell-quoted.
- Rendered prompts are shell-quoted and include full
TaskSpecguidance. - Submit → status returns a running view with tmux
attach_hintunder the fake pane backend. steer()sends keys to the tmux pane when the task is running.
MCP-level tests:
list({ kind: "adapters" })includesjcode.submit_taskacceptsagent_kind: "jcode"in the fake-backed test harness.- Stdio integration adapter count / expected agent kinds are updated.
Validation:
bun test packages/adapters
bun test packages/mcp
bun run typecheck
bun run check
bun test- Should the adapter accept a
provider_profileadapter option and translate it to--provider-profile? This is useful, but can be added after the basic REPL adapter lands. - Should we support both modes later (
jcode= repl,jcode-run= one-shot batch)? Not needed for the first implementation. - Does
jcode replreliably consume stdin from a pipe on all supported platforms? The fake backend can test command shape; a real tmux integration smoke should be used before declaring the adapter production-ready.