ACP Thread Bound Agents: 안정적인 코딩 에이전트 워크플로우 구축하기
코딩 에이전트를 실제 업무에 쓰다 보면 세션 관리가 가장 큰 고민거리가 됩니다. 긴 작업을 수행하던 에이전트가 갑자기 응답을 멈추거나, 여러 채널에서 메시지가 섞여 맥락을 놓치는 일이 빈번하죠. 특히 협업 툴 안에서 에이전트의 상태를 추적하고 안정적으로 출력을 받아보는 일은 생각보다 복잡합니다.
이런 문제를 해결하기 위해 OpenClaw는 ACP(Agent Control Plane) 세션을 스레드에 바인딩하는 방식을 제안합니다. 복잡한 설정 없이도 에이전트의 생명 주기를 관리하고, 작업 중단 시에도 안전하게 복구할 수 있는 환경을 만드는 것이 핵심입니다.
What You’ll Need
섹션 제목: “What You’ll Need”- OpenClaw core (Control Plane 관리용)
acpx기반의 plugin service (첫 번째 런타임 백엔드)- Discord 등 Thread 기능을 지원하는 채널
- SQLite (제어 평면 상태 저장용, WAL 모드 권장)
Quick Start
섹션 제목: “Quick Start”5분 안에 ACP 세션을 스레드에 바인딩하고 에이전트를 실행하는 방법입니다.
-
세션 바인딩 및 포커스
/focus커맨드를 사용하여 ACP 타겟을 특정 스레드에 바인딩하세요. OpenClaw가 자동으로 세션 ID와 메타데이터를 연결합니다. -
메시지 라우팅 바인딩된 스레드에서 메시지를 보내세요. 해당 메시지는 core dispatch를 거쳐 연결된 ACP 세션으로 즉시 전달됩니다.
-
상태 모니터링 및 스트리밍 에이전트의 실행 상태(
running,completed등)를 확인하세요. 모든 출력은 Webhook을 통해 동일한 스레드 persona로 실시간 스트리밍됩니다. -
세션 종료 및 정리 작업이 끝나면
/unfocus를 하거나 스레드를 보관(Archive)하세요. OpenClaw가 자동으로 lifecycle cleanup을 수행합니다.
Architecture Recommendation
섹션 제목: “Architecture Recommendation”OpenClaw는 하이브리드 구조를 추천합니다. Core는 세션 식별, 라우팅 결정, 중복 방지 같은 Control Plane 역할을 맡고, 실제 실행은 플러그형 Runtime(예: acpx)이 담당하는 방식입니다.
- AcpSessionManager: Gateway 프로세스에서 동작하며, 모든 ACP 쓰기 및 오케스트레이션을 관리합니다.
- 이벤트 기반 프로젝션: 스레드 출력은 단순한 부수 효과가 아니라, ACP 실행 이벤트의 결과물로 처리되어 일관성을 유지합니다.
- 상태 관리: 모든 ACP 세션은
creating,idle,running,cancelling,closed,error중 하나의 명확한 생명 주기 상태를 가집니다. - 데이터 저장: ACP 제어 평면 상태는 OpenClaw 상태 디렉토리 아래의 전용 SQLite 저장소에 보관하여 장애 복구를 지원합니다.
Troubleshooting
섹션 제목: “Troubleshooting”- 중복 출력 문제: 네트워크 재시도 시 동일한 출력이 Discord에 중복으로 나타날 수 있습니다. 이 경우 OpenClaw의 idempotency key가 제대로 설정되었는지 확인하세요.
- 라우팅 실패: 스레드 메시지가 ACP 세션으로 전달되지 않는다면, core dispatch 경로에 ACP 브랜치가 포함되어 있는지 점검해야 합니다. 순수 plugin만으로는 라우팅을 완전히 가로챌 수 없기 때문입니다.
더 자세한 설정 방법이 궁금하다면 AI Setup Assistant에게 물어보세요.
What’s Next
섹션 제목: “What’s Next”에이전트를 개발하다 보면 세션이 갑자기 끊기거나, 메시지가 중복으로 처리되어 곤란했던 적이 있으시죠? 특히 LLM 응답을 기다리는 동안 프로세스가 죽어버리면 상태를 복구하기가 정말 까다로워요. OpenClaw는 이런 문제를 해결하기 위해 ACP(Agent Control Protocol) 아키텍처를 설계했어요. 실행 상태를 안전하게 유지하고, 복잡한 에이전트 상호작용을 깔끔하게 관리하는 방법을 알려드릴게요.
What You’ll Need
섹션 제목: “What You’ll Need”- OpenClaw Core
- Plugin backend (acpx 구현체)
- SQLite (WAL mode 지원 환경)
Quick Start
섹션 제목: “Quick Start”5분 만에 ACP 런타임의 핵심 흐름을 파악하는 방법이에요.
- 세션 확보:
ensureSession을 호출해 에이전트 세션을 준비하세요. - 명령 제출:
submitAPI로 프롬프트나 조종(steer) 명령을 보냅니다. - 이벤트 스트리밍:
stream을 통해 실시간으로 텍스트 델타나 도구 호출 이벤트를 받으세요. - 세션 종료: 작업이 끝나면
close를 호출해 리소스를 정리합니다.
Boundary model (경계 모델)
섹션 제목: “Boundary model (경계 모델)”OpenClaw는 시스템의 안정성을 위해 역할을 명확히 나누었어요.
Core (OpenClaw 핵심 기능):
- 응답 파이프라인 내 ACP 세션 모드 디스패치 분기 처리
- 부모 및 스레드 중복 방지를 위한 전달 중재(Arbitration)
- ACP 컨트롤 플레인 영속성 관리 (마이그레이션 시
SessionEntry.acp호환성 투영 포함) - 세션 리셋/삭제와 연동된 수명 주기 unbind 및 런타임 detach 의미론
Plugin backend (acpx 구현체):
- ACP 런타임 워커(Worker) 감시
- acpx 프로세스 실행 및 이벤트 파싱
- ACP 커맨드 핸들러(
/acp ...) 및 운영자 UX - 백엔드 전용 설정 기본값 및 진단 기능
Runtime ownership model
섹션 제목: “Runtime ownership model”- 하나의 Gateway 프로세스가 ACP 오케스트레이션 상태를 소유해요.
- ACP 실행은 acpx 백엔드를 통해 감시되는 자식 프로세스에서 수행됩니다.
- 프로세스 전략은 메시지 단위가 아니라, 활성화된 ACP 세션 키당 하나씩 길게 유지(Long-lived)되는 방식이에요.
이렇게 하면 프롬프트를 보낼 때마다 프로세스를 새로 띄우는 비용을 줄일 수 있고, 취소나 재연결 동작을 훨씬 안정적으로 만들 수 있어요.
Core runtime contract
섹션 제목: “Core runtime contract”라우팅 코드가 CLI 세부 사항에 의존하지 않도록 공통 계약(Contract)을 정의했어요. 덕분에 디스패치 로직을 바꾸지 않고도 백엔드를 교체할 수 있습니다.
export type AcpRuntimePromptMode = "prompt" | "steer";
export type AcpRuntimeHandle = { sessionKey: string; backend: string; runtimeSessionName: string;};
export type AcpRuntimeEvent = | { type: "text_delta"; stream: "output" | "thought"; text: string } | { type: "tool_call"; name: string; argumentsText: string } | { type: "done"; usage?: Record<string, number> } | { type: "error"; code: string; message: string; retryable?: boolean };
export interface AcpRuntime { ensureSession(input: { sessionKey: string; agent: string; mode: "persistent" | "oneshot"; cwd?: string; env?: Record<string, string>; idempotencyKey: string; }): Promise<AcpRuntimeHandle>;
submit(input: { handle: AcpRuntimeHandle; text: string; mode: AcpRuntimePromptMode; idempotencyKey: string; }): Promise<{ runtimeRunId: string }>;
stream(input: { handle: AcpRuntimeHandle; runtimeRunId: string; onEvent: (event: AcpRuntimeEvent) => Promise<void> | void; signal?: AbortSignal; }): Promise<void>;
cancel(input: { handle: AcpRuntimeHandle; runtimeRunId?: string; reason?: string; idempotencyKey: string; }): Promise<void>;
close(input: { handle: AcpRuntimeHandle; reason: string; idempotencyKey: string }): Promise<void>;
health?(): Promise<{ ok: boolean; details?: string }>;}첫 번째 백엔드인 AcpxRuntime은 플러그인 서비스로 제공돼요. Core는 레지스트리를 통해 런타임을 찾고, 사용 가능한 백엔드가 없으면 명확한 에러를 발생시킵니다.
Control-plane data model and persistence
섹션 제목: “Control-plane data model and persistence”안전한 데이터 보관을 위해 전용 ACP SQLite 데이터베이스(WAL 모드)를 사용해요. 트랜잭션 업데이트와 크래시 복구를 보장합니다.
주요 테이블 구조:
acp_sessions: 세션 상태, 백엔드 정보, 생성/수정 시간 관리acp_runs: 각 실행(Run)의 상태, 멱등성 키, 에러 메시지 기록acp_bindings: 스레드, 채널, 계정과 세션 키 간의 연결 정보acp_events: 실행 중 발생하는 이벤트 시퀀스와 페이로드 저장acp_delivery_checkpoint: Discord 메시지 전달 상태 추적acp_idempotency: 중복 요청 방지를 위한 결과 저장소
export type AcpSessionMeta = { backend: string; agent: string; runtimeSessionName: string; mode: "persistent" | "oneshot"; cwd?: string; state: "idle" | "running" | "error"; lastActivityAt: number; lastError?: string;};저장 규칙은 엄격해요. 프로세스 ID나 소켓 정보는 메모리에만 두고, 세션의 생명주기와 실행 상태는 반드시 ACP DB에 기록합니다. Gateway가 죽더라도 DB의 체크포인트를 보고 다시 시작할 수 있어요.
Routing and delivery
섹션 제목: “Routing and delivery”Inbound (들어오는 요청):
- 현재 스레드 바인딩을 먼저 확인해요.
- 대상이 ACP 세션이면 일반적인 LLM 응답 대신 ACP 런타임 분기로 라우팅합니다.
/acp steer명령을 쓰면 명시적으로mode: "steer"가 적용돼요.
Outbound (나가는 응답):
- ACP 이벤트 스트림은 OpenClaw 응답 청크로 정규화됩니다.
- Discord 전송 시 속도 제한을 넘지 않도록 최소 간격과 최대 청크 크기를 조절해요.
- 작업이 끝나거나 실패하면 최종 메시지가 반드시 전송됩니다.
State machines and transaction boundaries
섹션 제목: “State machines and transaction boundaries”세션과 실행(Run)은 각각 정해진 상태를 따라 움직여요.
- Session:
creating -> idle -> running -> idle(또는error,closed) - Run:
queued -> running -> completed(또는failed,cancelled)
이 과정에서 트랜잭션 경계가 매우 중요해요. 세션을 생성하거나, 실행을 취소하거나, 종료할 때 부분적인 성공이 허용되지 않도록 설계되었어요. 모든 상태 변화는 원자적으로 처리됩니다.
Per-session actor model
섹션 제목: “Per-session actor model”AcpSessionManager는 각 ACP 세션 키마다 하나의 Actor를 실행해요.
- Actor는
submit,cancel,close,stream요청을 순차적으로 처리해요. - 런타임 프로세스의 생명주기를 직접 관리합니다.
- 이벤트 순서(
seq)를 보장하며, Discord에 보내기 전에 먼저 DB에 기록해요. - 메시지 전송이 성공한 후에만 체크포인트를 업데이트합니다.
이 모델 덕분에 여러 턴이 겹칠 때 발생하는 레이스 컨디션이나 메시지 순서가 뒤섞이는 문제를 방지할 수 있어요.
Idempotency and recovery
섹션 제목: “Idempotency and recovery”모든 외부 ACP 액션(생성, 제출, 취소, 종료)은 **멱등성 키(Idempotency Key)**를 가져야 해요. 네트워크 문제로 같은 요청이 두 번 들어와도 중복 실행되지 않도록 보장합니다.
Gateway가 다시 시작될 때의 복구 로직도 튼튼해요.
- 종료되지 않은 세션을 DB에서 불러와 Actor를 다시 생성합니다.
- 하트비트가 없는 실행(Run)은 실패로 처리하거나 어댑터를 통해 복구해요.
- 스레드 바인딩은 있는데 세션이 사라진 경우, 엉뚱한 LLM 응답이 나가지 않도록 안전하게 차단합니다.
Lifecycle and safety
섹션 제목: “Lifecycle and safety”안전한 운영을 위해 다음과 같은 제어 장치를 제공해요.
- 지원 작업:
/acp cancel(실행 취소),/unfocus(스레드 해제),/acp close(세션 종료) - TTL 정책: 글로벌 설정, 스레드 바인딩 만료 시간, 런타임 소유자 TTL 중 가장 짧은 것을 기준으로 세션을 자동 종료합니다.
- 안전 제어: 허용된 에러 에이전트 목록 관리, 작업 디렉토리 제한, 환경 변수 화이트리스트, 계정당 최대 세션 수 제한 등이 포함돼요.
Troubleshooting
섹션 제목: “Troubleshooting”- Gateway 재시작 후 세션이 멈췄나요? Gateway는 시작 시 DB에서 비정상 종료된 세션을 자동으로 감지하고 복구 프로세스를 시작해요. 잠시 기다리면 다시 활성화됩니다.
- 바인딩 에러 메시지가 나오나요?
스레드 바인딩은 남아있지만 세션 데이터가 유실된 경우예요. 이럴 때는
/unfocus를 사용해 바인딩을 정리하고 새로 시작하는 것이 좋습니다.
What’s Next
섹션 제목: “What’s Next”궁금한 점이 더 있다면 AI Setup Assistant에게 물어보세요!
개발을 하다 보면 설정 파일의 끝없는 리스트를 마주하고 막막해질 때가 있죠. 특히 세션 관리나 백엔드 라우팅처럼 세밀한 제어가 필요한 부분을 설정할 때는 어떤 키가 어떤 역할을 하는지 정확히 아는 것이 중요해요.
복잡한 설정 항목들 사이에서 길을 잃지 않도록, 여러분의 프로젝트에 바로 적용할 수 있는 주요 설정값들을 정리해 드릴게요.
What You’ll Need
섹션 제목: “What You’ll Need”- SQLite (기본
store사용 시 필요) - Discord 채널 연동 (
threadBindings설정 시 필요)
Quick Start
섹션 제목: “Quick Start”가장 먼저 확인해야 할 핵심 설정입니다. 이 단계만 완료해도 기본적인 ACP 기능을 시작할 수 있어요.
acp.enabled를true로 설정하여 기능을 활성화하세요.acp.backend를 설정하세요. 별도 설정이 없으면 기본값인acpx가 사용됩니다.acp.controlPlane.store에서 데이터 저장 방식을 선택하세요. 기본값은sqlite입니다.
Config surface 상세
섹션 제목: “Config surface 상세”Core keys
섹션 제목: “Core keys”시스템의 뼈대를 구성하는 핵심 설정 키들입니다.
acp.enabled: ACP 활성화 여부를 결정해요.acp.dispatch.enabled: 독립적인 ACP 라우팅 기능을 즉시 중단할 수 있는 킬 스위치예요.acp.backend: 사용할 백엔드를 지정하며 기본값은acpx입니다.acp.defaultAgent: 기본으로 사용할 에이전트를 설정해요.acp.allowedAgents[]: 허용된 에이전트 리스트를 관리합니다.acp.maxConcurrentSessions: 동시에 실행 가능한 최대 세션 수를 제한해요.acp.stream.coalesceIdleMs: 스트림 병합 시 대기할 유휴 시간을 밀리초 단위로 설정합니다.acp.stream.maxChunkChars: 스트림의 최대 청크 문자 수를 지정해요.acp.runtime.ttlMinutes: 런타임이 유지될 시간을 분 단위로 설정합니다.acp.controlPlane.store: 컨트롤 플레인의 저장소 타입을 결정하며 기본값은sqlite예요.acp.controlPlane.storePath: 저장소 파일이 위치할 경로를 지정합니다.acp.controlPlane.recovery.eagerActors: 복구 시 즉시 활성화할 액터를 설정해요.acp.controlPlane.recovery.reconcileRunningAfterMs: 실행 중인 상태를 재조정하기 전 대기 시간을 설정합니다.acp.controlPlane.checkpoint.flushEveryEvents: 체크포인트를 저장할 이벤트 주기를 설정해요.acp.controlPlane.checkpoint.flushEveryMs: 체크포인트를 저장할 시간 주기를 밀리초 단위로 설정합니다.acp.idempotency.ttlHours: 멱등성 유지를 위한 데이터의 유효 시간을 시간 단위로 지정해요.channels.discord.threadBindings.spawnAcpSessions: Discord 스레드 바인딩 시 ACP 세션을 생성할지 여부를 결정합니다.
Plugin/backend keys (acpx plugin section)
섹션 제목: “Plugin/backend keys (acpx plugin section)”acpx 플러그인과 관련된 백엔드 상세 설정입니다.
- backend command/path overrides: 백엔드 실행 명령어 및 경로를 덮어씁니다.
- backend env allowlist: 백엔드에서 사용할 환경 변수 허용 리스트를 관리해요.
- backend per-agent presets: 에이전트별 프리셋 설정을 적용합니다.
- backend startup/stop timeouts: 백엔드 시작 및 종료 시의 타임아웃 시간을 제어해요.
- backend max inflight runs per session: 세션당 동시에 처리할 수 있는 최대 실행 수를 제한합니다.
Troubleshooting
섹션 제목: “Troubleshooting”설정 과정에서 발생할 수 있는 일반적인 상황과 해결 방법이에요.
- 서비스 중단 후 복구 설정이 필요한 경우:
acp.controlPlane.recovery.eagerActors설정을 통해 필요한 액터를 즉시 복구하고,acp.controlPlane.recovery.reconcileRunningAfterMs값을 조정하여 재조정 타이밍을 최적화하세요. - 데이터 저장 문제 발생 시:
acp.controlPlane.storePath가 올바른 경로를 가리키고 있는지,sqlite권한이 적절한지 확인해 보세요.
설정 중에 궁금한 점이 생기면 언제든 도움을 받을 수 있어요. AI Setup Assistant
What’s Next
섹션 제목: “What’s Next”에이전트 세션을 관리하다 보면 상태가 꼬이거나 메시지 전달이 누락되는 경험, 다들 한 번쯤 있으시죠? 특히 복잡한 워크플로우에서 상태 일관성을 유지하고 안정적인 메시지 전달을 보장하는 시스템을 구축하는 건 정말 까다로운 작업이에요. 이런 개발자의 고민을 해결하기 위해 설계된 ACP 구현 사양을 공유해 드릴게요.
What You’ll Need
섹션 제목: “What You’ll Need”이 가이드를 따라가려면 다음 항목들에 대한 이해가 필요해요.
- Node.js 및 TypeScript 개발 환경
- SQLite 데이터베이스 및 트랜잭션 관리
- Discord 모니터링 및 스레드 바인딩 개념
acpx런타임 플러그인 구조
Quick Start
섹션 제목: “Quick Start”ACP를 빠르게 적용하기 위한 핵심 단계는 다음과 같아요.
- Core 모듈 추가:
src/acp/control-plane/경로에 매니저, 스토어, 이벤트, 체크포인트 모듈을 생성하세요. - Registry 등록:
src/acp/runtime/registry.ts를 통해 ACP 백엔드를 등록할 수 있는 API를 준비하세요. - Core 변경:
dispatch-from-config.ts등 주요 터치포인트에서 ACP 매니저를 호출하도록 수정하세요. - Schema 업데이트:
SessionEntry에SessionAcpMeta필드를 추가하고 단계별 마이그레이션을 진행하세요.
상세 구현 사양
섹션 제목: “상세 구현 사양”Control-plane modules (신규)
섹션 제목: “Control-plane modules (신규)”Core에 전용 ACP 컨트롤 플레인 모듈을 추가해야 해요.
src/acp/control-plane/manager.ts- ACP actor 소유, 라이프사이클 전환, 커맨드 직렬화 담당
src/acp/control-plane/store.ts- SQLite 스키마 관리, 트랜잭션, 쿼리 헬퍼
src/acp/control-plane/events.ts- 타입이 지정된 ACP 이벤트 정의 및 직렬화
src/acp/control-plane/checkpoint.ts- 지속 가능한 전달 체크포인트 및 재생 커서
src/acp/control-plane/idempotency.ts- 멱등성 키 예약 및 응답 재생
src/acp/control-plane/recovery.ts- 부팅 시 조정(reconciliation) 및 actor 재수화(rehydrate) 계획
호환성을 위한 브릿지 모듈도 필요해요.
src/acp/runtime/session-meta.tsSessionEntry.acp투영을 위해 일시적으로 유지하며, 마이그레이션 완료 후에는 더 이상 Source-of-truth가 아니어야 해요.
필수 불변 조건 (Required invariants)
섹션 제목: “필수 불변 조건 (Required invariants)”코드에서 반드시 강제해야 하는 규칙들이에요.
- ACP 세션 생성과 스레드 바인딩은 원자적이어야 해요 (단일 트랜잭션).
- ACP 세션 actor당 한 번에 최대 하나의 활성 실행(run)만 존재할 수 있어요.
- 실행당 이벤트
seq는 엄격하게 증가해야 해요. - 전달 체크포인트는 마지막으로 커밋된 이벤트를 넘어서 진행될 수 없어요.
- 중복 커맨드 키에 대한 멱등성 재생은 이전의 성공 페이로드를 반환해야 해요.
- 유효하지 않거나 누락된 ACP 메타데이터는 일반 LLM 응답 경로로 라우팅될 수 없어요.
Core 주요 변경 사항 (Touchpoints)
섹션 제목: “Core 주요 변경 사항 (Touchpoints)”수정이 필요한 파일 목록이에요.
src/auto-reply/reply/dispatch-from-config.ts- ACP 브랜치에서
AcpSessionManager.submit및 이벤트 투영 전달을 호출하세요. - 컨트롤 플레인 불변 조건을 우회하는 직접적인 ACP 폴백을 제거하세요.
- ACP 브랜치에서
src/auto-reply/reply/inbound-context.ts- ACP 컨트롤 플레인을 위해 정규화된 라우팅 키와 멱등성 시드(seed)를 노출하세요.
src/config/sessions/types.tsSessionEntry.acp를 투영 전용 호환성 필드로 유지하세요.
src/gateway/server-methods/sessions.ts- reset/delete/archive 시 ACP 매니저의 close/unbind 트랜잭션 경로를 호출해야 해요.
src/infra/outbound/bound-delivery-router.ts- ACP 바인딩 세션 턴에 대해 fail-closed 데스티네이션 동작을 강제하세요.
src/discord/monitor/thread-bindings.ts- 컨트롤 플레인 조회와 연결된 ACP 상태 유효성 검사 헬퍼를 추가하세요.
src/auto-reply/reply/commands-acp.ts- spawn/cancel/close/steer를 ACP 매니저 API를 통해 라우팅하세요.
src/agents/acp-spawn.ts- 임시 메타데이터 쓰기를 중단하고 ACP 매니저 spawn 트랜잭션을 호출하세요.
src/plugin-sdk/**및 플러그인 런타임 브릿지- ACP 백엔드 등록 및 헬스 체크 시맨틱을 깔끔하게 노출하세요.
수정하지 않는 파일:
src/discord/monitor/message-handler.preflight.ts- 스레드 바인딩 오버라이드 동작을 표준 세션 키 리졸버로 유지하세요.
ACP 런타임 레지스트리 API
섹션 제목: “ACP 런타임 레지스트리 API”src/acp/runtime/registry.ts 모듈에 다음 API를 구현하세요.
export type AcpRuntimeBackend = { id: string; runtime: AcpRuntime; healthy?: () => boolean;};
export function registerAcpRuntimeBackend(backend: AcpRuntimeBackend): void;export function unregisterAcpRuntimeBackend(id: string): void;export function getAcpRuntimeBackend(id?: string): AcpRuntimeBackend | null;export function requireAcpRuntimeBackend(id?: string): AcpRuntimeBackend;requireAcpRuntimeBackend는 백엔드를 사용할 수 없을 때 타입이 지정된 에러를 던져요.- 플러그인 서비스는
start시 백엔드를 등록하고stop시 등록을 해제해요.
acpx 런타임 플러그인 계약
섹션 제목: “acpx 런타임 플러그인 계약”첫 번째 프로덕션 백엔드인 extensions/acpx와 OpenClaw는 다음 커맨드 계약으로 연결돼요.
- Backend ID:
acpx - Plugin Service ID:
acpx-runtime - Encoding:
runtimeSessionName = acpx:v1:<base64url(json)> - Payload Fields:
name,agent,cwd,mode(persistent | oneshot)
커맨드 매핑:
- 세션 보장:
acpx --format json --json-strict --cwd <cwd> <agent> sessions ensure --name <name> - 프롬프트 턴:
acpx --format json --json-strict --cwd <cwd> <agent> prompt --session <name> --file - - 취소:
acpx --format json --json-strict --cwd <cwd> <agent> cancel --session <name> - 종료:
acpx --format json --json-strict --cwd <cwd> <agent> sessions close <name>
스트리밍 이벤트:
text=>text_delta/outputthought=>text_delta/thoughttool_call=>tool_calldone=>doneerror=>error
세션 스키마 패치
섹션 제목: “세션 스키마 패치”src/config/sessions/types.ts의 SessionEntry를 다음과 같이 수정하세요.
type SessionAcpMeta = { backend: string; agent: string; runtimeSessionName: string; mode: "persistent" | "oneshot"; cwd?: string; state: "idle" | "running" | "error"; lastActivityAt: number; lastError?: string;};마이그레이션 규칙:
- Phase A: 이중 쓰기 (
acp투영 + ACP SQLite) - Phase B: ACP SQLite 우선 읽기, 기존 필드 폴백
- Phase C: 기존 항목에서 누락된 ACP 행을 채우는 마이그레이션 커맨드 실행
- Phase D: 폴백 읽기 제거 및 UX용 투영만 유지
에러 계약 (Error contract)
섹션 제목: “에러 계약 (Error contract)”사용자에게 보여줄 안정적인 에러 코드를 정의하세요.
ACP_BACKEND_MISSING: 백엔드 미설정. 플러그인 활성화 필요 메시지.ACP_BACKEND_UNAVAILABLE: 백엔드 일시적 사용 불가. 재시도 안내.ACP_SESSION_INIT_FAILED: 세션 런타임 초기화 실패.ACP_TURN_FAILED: 완료 전 ACP 턴 실패.
중복 전달 중재 (Duplicate delivery arbitration)
섹션 제목: “중복 전달 중재 (Duplicate delivery arbitration)”- 활성 스레드 바인딩이 있다면 해당 스레드에만 전달하세요.
- 동일한 턴에 대해 부모 채널에 중복 전송하지 마세요.
- 대상 선택이 모호한 경우, 부모 채널로 폴백하지 말고 명시적인 에러와 함께 실패 처리하세요.
관측 가능성 (Observability)
섹션 제목: “관측 가능성 (Observability)”다음 메트릭과 로그를 반드시 포함해야 해요.
- Metrics: 백엔드별 spawn 성공/실패 횟수, 실행 지연 시간(큐 대기, 런타임 턴 시간 등), actor 재시작 횟수, 멱등성 히트율.
- Logs:
sessionKey,runId,idempotencyKey등을 포함한 구조화된 로그. 세션 및 실행 상태 머신의 전환 로그. - Diagnostics:
/acp sessions(상태 및 바인딩 확인),/acp doctor(백엔드 및 저장소 상태 점검).
테스트 맵
섹션 제목: “테스트 맵”- Unit tests:
registry.test.ts,dispatch-from-config.acp.test.ts,bound-delivery-router.test.ts(fail-closed 케이스 확장). - Integration tests:
reply-delivery.test.ts(전달 대상 동작), acpx 플러그인 런타임 테스트. - E2E tests: 세션 라이프사이클(reset/delete) 커버리지 확장 및 spawn부터 복구까지의 전체 라운드트립 테스트.
롤아웃 가드 (Rollout guard)
섹션 제목: “롤아웃 가드 (Rollout guard)”첫 릴리스에서는 독립적인 킬 스위치를 사용하세요.
acp.dispatch.enabled기본값은false예요.- 비활성화 시 사용자는 정책에 의해 ACP 디스패치가 비활성화되었다는 메시지를 받게 돼요.
- 카나리 검증 후 다음 릴리스에서
true로 변경할 수 있어요.
Troubleshooting
섹션 제목: “Troubleshooting”- ACP 백엔드 누락:
acpx플러그인이 설치되고 활성화되어 있는지 확인하세요. - 세션 초기화 실패: SQLite 트랜잭션 로그를 확인하여 원자적 세션 생성 단계를 점검하세요.
- 전달 오류:
bound-delivery-router에서 fail-closed 동작이 의도치 않게 발생하지 않았는지 확인하세요.
구현 중 궁금한 점이 있다면 AI Setup Assistant에게 언제든 물어보세요!
What’s Next
섹션 제목: “What’s Next”에이전트를 개발하다 보면 세션 상태가 꼬이거나 명령어가 제대로 전달되지 않아 답답할 때가 있죠. 특히 여러 스레드에서 복잡한 워크플로우를 관리해야 할 때는 더욱 그렇습니다. 이런 문제를 해결하기 위해 에이전트 제어 평면(ACP)의 새로운 명령어와 사용자 경험(UX) 계획을 준비했어요.
What You’ll Need
섹션 제목: “What You’ll Need”이 가이드는 소스 문서에 언급된 다음 구성 요소를 기준으로 합니다.
- Discord: 첫 번째로 지원되는 채널 어댑터
- SQLite: ACP 제어 평면 저장소 및 트랜잭션 관리
- acpx backend adapter: 런타임 계약을 구현하는 어댑터
- Node.js 기반 환경:
src/acp/및 관련 경로의 소스 코드 실행 환경
Quick Start
섹션 제목: “Quick Start”새로운 ACP 명령어를 사용하여 5분 안에 에이전트 세션을 시작하고 제어할 수 있습니다.
- 에이전트 생성:
Terminal window /acp spawn <agent-id> [--mode persistent|oneshot] [--thread auto|here|off] - 명령 전달:
Terminal window /acp steer <instruction> - 세션 확인:
Terminal window /acp sessions - 세션 종료:
Terminal window /acp close [session]
기존의 /focus <sessionKey>와 /unfocus 명령어도 ACP 타겟을 지원하도록 유지되니 익숙한 방식 그대로 사용할 수 있어요.
단계별 배포 로드맵
섹션 제목: “단계별 배포 로드맵”ACP 구현은 총 7단계로 진행됩니다. 각 단계는 시스템의 안정성과 데이터 무결성을 보장하도록 설계되었습니다.
Phase 0: ADR 및 스키마 확정
섹션 제목: “Phase 0: ADR 및 스키마 확정”- ACP 제어 평면 소유권 및 어댑터 경계에 대한 ADR(Architecture Decision Record)을 확정합니다.
- DB 스키마를 고정합니다:
acp_sessions,acp_runs,acp_bindings,acp_events,acp_delivery_checkpoint,acp_idempotency. - 안정적인 ACP 에러 코드, 이벤트 규약, 상태 전환 가드를 정의합니다.
Phase 1: Core의 제어 평면 기반 구축
섹션 제목: “Phase 1: Core의 제어 평면 기반 구축”AcpSessionManager및 세션별 actor 런타임을 구현합니다.- ACP SQLite 저장소와 트랜잭션 헬퍼를 구축합니다.
- 멱등성(Idempotency) 저장소와 재생(Replay) 헬퍼를 구현합니다.
- spawn/cancel/close API를 트랜잭션 보장과 함께 매니저에 연결합니다.
Phase 2: Core 라우팅 및 생명주기 통합
섹션 제목: “Phase 2: Core 라우팅 및 생명주기 통합”- dispatch 파이프라인에서 스레드에 바인딩된 ACP turn을 ACP 매니저로 라우팅합니다.
- ACP 바인딩/세션 불변성이 실패할 경우 fail-closed 라우팅을 강제합니다.
- reset/delete/archive/unfocus 생명주기를 ACP close/unbind 트랜잭션과 통합합니다.
Phase 3: acpx 백엔드 어댑터/플러그인
섹션 제목: “Phase 3: acpx 백엔드 어댑터/플러그인”- 런타임 계약(
ensureSession,submit,stream,cancel,close)에 따라acpx어댑터를 구현합니다. - 백엔드 상태 확인(Health checks) 및 시작/종료 등록 기능을 추가합니다.
- acpx ndjson 이벤트를 ACP 런타임 이벤트로 정규화합니다.
Phase 4: 전송 프로젝션 및 채널 UX (Discord 우선)
섹션 제목: “Phase 4: 전송 프로젝션 및 채널 UX (Discord 우선)”- 체크포인트 재개 기능이 포함된 이벤트 기반 채널 프로젝션을 구현합니다.
- 속도 제한(Rate-limit)을 고려한 플러시 정책으로 스트리밍 청크를 병합합니다.
- 실행당 정확히 한 번(Exactly-once)의 최종 완료 메시지 전송을 보장합니다.
Phase 5: 마이그레이션 및 전환
섹션 제목: “Phase 5: 마이그레이션 및 전환”SessionEntry.acp프로젝션과 ACP SQLite 소스 간의 이중 쓰기(Dual-write)를 도입합니다.- 레거시 ACP 메타데이터 행을 위한 마이그레이션 유틸리티를 추가합니다.
- 읽기 경로를 ACP SQLite 기본으로 전환합니다.
Phase 6: 안정화 및 확장 제한
섹션 제목: “Phase 6: 안정화 및 확장 제한”- 동시성 제한(전역/계정/세션), 큐 정책, 타임아웃 예산을 적용합니다.
- 전체 텔레메트리, 대시보드, 알림 임계값을 추가합니다.
- 카오스 테스트를 통해 충돌 복구 및 중복 전송 억제 기능을 검증합니다.
Troubleshooting
섹션 제목: “Troubleshooting”문제가 발생했을 때 참고할 수 있는 일반적인 상황과 해결 방법입니다.
- 중복 전송 문제: 단일 목적지 리졸버(Destination resolver)와 멱등성 이벤트 체크포인트를 통해 해결합니다.
- 부하로 인한 프로세스 불안정: 세션별 소유자 유지, 동시성 캡(Concurrency caps), 백오프(Backoff) 정책을 확인하세요.
- 플러그인 미설정: ACP 라우팅은 암시적인 폴백 없이 명시적인 에러를 발생시키는 fail-closed 방식을 따릅니다. 설정 키를 다시 확인해 주세요.
- DB 손상 또는 마이그레이션 오류: WAL 모드와 백업/복구 후크를 사용하며, 읽기 전용 폴백 진단 도구를 활용하세요.
구현 및 테스트 체크리스트
섹션 제목: “구현 및 테스트 체크리스트”모든 기능이 정상 작동하는지 확인하기 위해 다음 항목들을 체크해 보세요.
- ACP 세션 spawn이 지원되는 채널(Discord)에서 스레드를 생성하거나 바인딩할 수 있는가?
- 모든 스레드 메시지가 바인딩된 ACP 세션으로만 라우팅되는가?
- spawn+bind+initial enqueue 작업이 저장소에서 원자적(Atomic)으로 처리되는가?
- 동일한 멱등성 키를 가진 명령 재시도가 중복 실행을 생성하지 않는가?
- 크래시 후 재시작 시 매핑이 보존되고 세션 연속성이 유지되는가?
더 자세한 도움이 필요하시면 AI Setup Assistant에게 물어보세요!
What’s Next
섹션 제목: “What’s Next”OpenClaw Expert
아직 막혀 있나요?
이 문서에서 답을 못 찾았다면 OpenClaw Expert에게 바로 물어보세요.