Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ npm install -g @orgloop/agentctl

Requires Node.js >= 20.

Public adapters currently shipped in the CLI: `claude-code`, `codex`, `opencode`, `pi`, `pi-rust`, and `openclaw`.
ACP-backed adapter work is in progress internally, but adapters such as `codex-acp` are not user-visible until packaging and discover-first session reattachment are ready.

## Quick Start

```bash
Expand Down
10 changes: 10 additions & 0 deletions docs/adr/adr-001-agentctl-adopts-acp.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ Research ([acpx-vs-agentctl analysis](obsidian://open?vault=My%20Notes&file=Proj

**agentctl will adopt ACP as its primary agent interface strategy.**

### Rollout boundary

This ADR describes the architectural direction, not a claim that ACP-backed adapters are already production-ready in the public CLI.

Until an ACP adapter has:
- a packaged/distributed bridge story (or explicit documented prerequisite), and
- discover-first rediscovery / reattach semantics that survive a fresh CLI process or daemon restart,

it should remain experimental and not be registered as a public adapter.

### Principles

1. **Ride on ACP, don't fight it.** agentctl's CLI and internal APIs should align with ACP primitives (sessions, prompts, cancel, permissions). Where ACP provides a clean abstraction, use it rather than reinventing.
Expand Down
12 changes: 12 additions & 0 deletions src/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ describe("launch --adapter flag (#74)", () => {
// Should reference the requested adapter in the error, not silently use claude-code
expect(stderr).not.toContain("Launched session");
});

it("rejects codex-acp with a targeted experimental message", async () => {
const { stderr } = await run([
"launch",
"--adapter",
"codex-acp",
"-p",
"test",
]);
expect(stderr).toContain("not publicly shipped yet");
expect(stderr).toContain("use 'codex' for now");
});
});

describe("shortId (#71)", () => {
Expand Down
10 changes: 8 additions & 2 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { fileURLToPath } from "node:url";
import { Command } from "commander";
import { ClaudeCodeAdapter } from "./adapters/claude-code.js";
import { CodexAdapter } from "./adapters/codex.js";
import { createCodexAcpAdapter } from "./adapters/codex-acp.js";
import { OpenClawAdapter } from "./adapters/openclaw.js";
import { OpenCodeAdapter } from "./adapters/opencode.js";
import { PiAdapter } from "./adapters/pi.js";
Expand Down Expand Up @@ -47,7 +46,6 @@ import { createWorktree, type WorktreeInfo } from "./worktree.js";
const adapters: Record<string, AgentAdapter> = {
"claude-code": new ClaudeCodeAdapter(),
codex: new CodexAdapter(),
"codex-acp": createCodexAcpAdapter(),
openclaw: new OpenClawAdapter(),
opencode: new OpenCodeAdapter(),
pi: new PiAdapter(),
Expand Down Expand Up @@ -101,6 +99,14 @@ function getAdapter(name?: string): AgentAdapter {
if (!name) {
return adapters["claude-code"];
}

if (name === "codex-acp") {
console.error(
"Adapter 'codex-acp' is not publicly shipped yet. The ACP bridge packaging and discover-first rediscovery story are still incomplete, so use 'codex' for now.",
);
process.exit(1);
}

const adapter = adapters[name];
if (!adapter) {
console.error(`Unknown adapter: ${name}`);
Expand Down
Loading