CLI AI 에이전트를 위한 WebSocket 브릿지 (agent-ws)
요약
agent-ws는 CLI AI 에이전트(Claude Code, Codex)의 응답을 WebSocket으로 스트리밍하는 브릿지 도구입니다. 프롬프트 엔지니어링 없이 전송만 담당하며, Node.js 백엔드에 임베딩하여 사용할 수 있습니다. --mode 플래그를 통해 텍스트 생성부터 파일 작업(agentic), 전체 시스템 접근(unrestricted)까지 에이전트의 권한 수준을 세밀하게 제어할 수 있습니다.
핵심 포인트
- WebSocket 스트리밍으로 AI 에이전트 응답 전송
- Claude Code와 Codex CLI를 지원하는 브릿지 역할 수행
- safe, agentic, unrestricted 모드로 권한 레벨 제어 가능
- Node.js 백엔드에 임베딩하여 활용 가능
WebSocket bridge for CLI AI agents.
Claude Code와 Codex CLI로부터의 응답을 WebSocket으로 스트리밍합니다. 단순한 파이프(dumb pipe)입니다: 프롬프트 엔지니어링도, 자격 증명 처리도 없이 전송만 담당합니다.
-
Node.js 20+
-
지원되는 CLI 에이전트가 최소 하나 설치되어 있어야 합니다:
-
Claude Code (
npm install -g @anthropic-ai/claude-code
) -
Codex (
npm install -g @openai/codex
) -
Claude Code (
# npm에서
npm install -g agent-ws
# 또는 직접 실행
...
# WebSocket 브릿지 시작
agent-ws
# 서버가 시작 시 일회성 인증 토큰을 출력합니다:
...
만약 CLI를 실행하는 대신 자체 Node.js 백엔드(예: Express, Fastify 또는 Next.js API route)에 WebSocket 서버를 임베드하려는 경우:
import { AgentWS } from "agent-ws";
import { randomBytes } from "node:crypto";
const agent = new AgentWS({
...
참고: 이것은 서버 측 전용입니다. 브라우저/React 클라이언트는 실행 중인 agent-ws 서버에 WebSocket 클라이언트로서 연결해야 합니다 (프로토콜 참조).
-p, --port <포트> WebSocket 서버 포트 (기본값: 9999)
-H, --host <호스트> WebSocket 서버 호스트 (기본값: localhost)
-m, --mode <모드> 권한 모드: safe, agentic, unrestricted (기본값: safe)
...
--mode로 CLI 에이전트가 수행할 수 있는 작업을 제어합니다.
:
agent-ws --mode safe # 기본값 — 텍스트 생성만 가능
agent-ws --mode agentic # 파일 작업 (읽기/쓰기/편집)
agent-ws --mode unrestricted # 전체 시스템 접근 — 셸, 네트워크, 모든 것
| 모드 | Claude CLI 플래그 | Codex CLI 플래그 | 기능 | :---: |
|---|---|---|---|
|safe|--max-turns 1 --tools ""|--sandbox read-only --ask-for-approval never|텍스트만 가능, 도구 없음|
|agentic|--permission-mode dontAsk --allowedTools "Read(**),Write(**),Edit(**),Glob(**),Grep(**)"|--sandbox workspace-write --ask-for-approval never|파일 작업만 가능, 셸/네트워크 불가|
|unrestricted|--dangerously-skip-permissions|--sandbox danger-full-access --ask-for-approval never|모든 것|
모드 선택:
safe사용
텍스트 응답만 필요할 때(Q&A, 파일 접근 없는 코드 생성)는 agentic 사용
CLI가 프로젝트 파일을 읽거나 쓸 필요는 있지만 임의의 명령을 실행해서는 안 될 때는 unrestricted 사용
전체 시스템 접근이 허용되는 신뢰할 수 있고 격리된 환경에서만
agentic와 unrestricted 모드에서는 두 러너 모두 모든 파일 작업에 상대 경로를 사용하도록 요구하는 샌드박스 지침을 주입합니다. Claude는 또한 세션 디렉터리에 CLAUDE.md 파일을 작성하여 이 제약을 강화합니다.
--mode는 CLI 에이전트가 요청받는 작업을 제어하고, --sandbox는 생성된 프로세스가 OS 수준에서 실제로 할 수 있는 것을 제어합니다. 두 가지를 안전벨트와 보조 벨트로 취급하세요. 플래그는 무시되거나 우회될 수 있으며, OS 샌드박스는 커널 수준에서 경계를 강제합니다.
agent-ws --sandbox none # 기본값. OS 격리 없음; CLI 자체 플래그를 신뢰함.
agent-ws --sandbox os # 이 플랫폼에 가장 적합한 네이티브 OS 샌드박스를 선택합니다.
agent-ws --sandbox auto # os와 동일하지만, 오류를 발생시키는 대신 경고와 함께 none으로 폴백합니다.
...
| 백엔드 | 플랫폼 | 메커니즘 | 참고 사항 |
|---|---|---|---|
none | 모든 환경 | no-op | 이 플래그가 존재하기 전과 동일한 동작 방식 |
seatbelt | macOS | /usr/bin/sandbox-exec와 선별된 SBPL 프로파일 사용 | Apple에서 폐기되었지만 여전히 기능함. Claude Code, Gemini CLI 및 오늘날 게시된 대부분의 에이전트 설정에서 사용됨. |
bwrap | Linux | bubblewrap 마운트 네임스페이스 + --unshare-all --share-net | 특권 없는 사용자 네임스페이스가 필요합니다. Ubuntu 24.04 이상은 이것을 제한적으로 제공하므로, 문제 해결 섹션을 참조하세요. |
샌드박스가 제한하는 것:
- 쓰기는 프로젝트별 세션 디렉터리에만 한정됩니다 (
safe모드는 세션 디렉터리 쓰기도 차단합니다) - 자격 증명 디렉터리 (~/.claude,~/.codex및 해당~/.config/...등가물)는 읽기 전용으로 마운트되어 CLI가 인증할 수는 있지만 유출(exfiltrate)할 수는 없습니다 -safe모드에서는 프로세스 실행이 거부됩니다.
모드(tiny shell 화이트리스트를 제외하고는 CLI가 자체 헬퍼를 포크해야 함) - macOS: 아웃바운드 TCP는 고정된 에이전트 API 엔드포인트로만 허용됩니다. Linux: 아웃바운드 네트워크는 현재 제한되지 않습니다 — 아래 Honest 주의사항을 참조하십시오.
솔직한 주의사항(Honest caveats):
seatbelt
프로필은 macOS 마이너 릴리스마다 유지보수가 필요하며, Apple은 sandbox-exec를 완전히 제거할 수 있습니다 (공지된 날짜 없음).bwrap
호스트 이름으로 아웃바운드 네트워크를 제한할 수 없습니다 (포트로만 가능). Linux bwrap 프로필은 v1에서 모든 아웃바운드 트래픽을 허용합니다. 호스트 이름 화이트리스트가 필요하면 외부 이그레스 프록시와 함께 사용하십시오.- Windows는 이 버전에서 네이티브 샌드박스를 제공하지 않습니다. 대신 WSL2와 Linux bwrap 백엔드를 사용하십시오. - 기본값은 none이므로 기존 설정은 계속 작동합니다. --sandbox os로 명시적으로 옵트인하고 문제가 발생하면 보고하십시오.
클라이언트는 서버에서 실제로 무엇이 사용 가능한지 런타임에 조회할 수 있습니다:
// 클라이언트 → 에이전트
{ "type": "capabilities" }
// 에이전트 → 클라이언트
...
응답은 서버의 생명 주기 동안 캐시되므로, 시작 후 CLI를 설치할 경우 agent-ws 재시작을 해야 반영됩니다.
┌───────────────┐ WebSocket ┌─────────────┐ stdio ┌─────────────┐
│ 귀하의 앱 │ <=================> │ agent-ws │ <===============> │ Claude Code │
│ (모든 클라이언트) │ localhost:9999 │ (Node.js) │ stdio │ / Codex │
...
어떤 WebSocket 클라이언트라도 연결할 수 있습니다 — 브라우저 프론트엔드, 백엔드 서비스, 스크립트, 다른 CLI 도구 등. 각 연결은 자체 CLI 프로세스를 얻습니다. 에이전트는:
- localhost에서 WebSocket 연결을 수락합니다
- 클라이언트로부터 프롬프트 메시지를 받습니다
- 적절한 CLI 에이전트(Claude Code 또는 Codex)를 실행합니다
- 출력을 실시간으로 스트리밍합니다
- 프로세스 생명 주기(타임아웃, 취소, 정리)를 관리합니다.
| 에이전트 | Provider 필드 | CLI |
|---|---|---|
| Claude Code | ` |
{ "type": "prompt", "prompt": "로그인 폼을 만들어줘", "requestId": "uuid", "model": "opus", "provider": "claude" }
{ "type": "prompt", "prompt": "...", "requestId": "uuid", "projectId": "my-app", "systemPrompt": "...", "thinkingTokens": 2048 }
{ "type": "prompt", "prompt": "이 이미지를 설명해줘", "requestId": "uuid", "images": [{ "media_type": "image/png", "data": "<base64>" }] }
...
| 필드 | 필수 여부 | 설명 |
|---|---|---|
prompt | 예 | 프롬프트 텍스트 (최대 512KB) |
requestId | 예 | 고유 요청 식별자 (최대 256자) |
model | 아니요 | 모델 이름 (예: "sonnet" , "opus" ) |
provider | 아니요 | "claude" (기본값) 또는 "codex" . 알 수 없는 값은 거부됩니다. |
projectId | 아니요 | 디렉터리로 CLI 세션을 범위 지정합니다. 다중 턴에 대해 --continue를 활성화합니다. 영숫자, 하이픈, 밑줄, 점만 가능합니다. |
systemPrompt | 아니요 | 시스템 프롬프트로 추가됩니다 (최대 64KB). 연결별 캐시: 후속 메시지에서 생략되면 마지막 값이 재사용됩니다. |
thinkingTokens | 아니요 | 최대 사고 토큰 수. 0은 사고 기능을 비활성화합니다. Claude가 결정하도록 하려면 생략합니다. Codex는 이 필드를 무시합니다. |
images | 아니요 | { media_type, data } 객체 배열. 최대 4개의 이미지, 각 10MB의 base64를 지원합니다. 지원되는 유형: image/png , image/jpeg , image/gif , image/webp . |
files | 아니요 | { path, content } 객체 배열. 최대 100개의 파일, 총 50MB까지 가능합니다. Claude가 읽거나 편집할 수 있도록 세션 디렉터리에 작성됩니다. |
{ "type": "connected", "version": "1.1", "agent": "agent-ws", "mode": "safe" }
{ "type": "capabilities", "agent": "agent-ws", "version": "1.1", "mode": "safe", "sandbox": { "active": "none", "available": ["none"] }, "providers": [{ "id": "claude", "available": true, "version": "2.1.141" }, { "id": "codex", "available": false }] }
{ "type": "chunk", "content": "여기에 로그인 폼이 있습니다...", "requestId": "uuid" }
...
thinking: true를 포함하는 청크는 Claude의 추론을 담고 있습니다. 클라이언트는 이를 사고 표시기로 보여주거나 무시할 수 있습니다.
tool_event와 file_change
파일을 수정하는 도구를 호출할 때 agentic 및 unrestricted 모드에서 발생합니다. 실시간 도구 활동에 신경 쓰지 않는 클라이언트는 이를 무시해도 됩니다. 편집(Edit) 도구는 두 개의 file_change 이벤트를 발생시킵니다. 첫 번째는 편집이 시작될 때 발생하는 동기적 이벤트(콘텐츠 없음)이며, 두 번째는 편집 후 디스크에서 읽은 콘텐츠를 포함하는 비동기적 이벤트입니다.
일반적인 오류 메시지:
| 메시지 | 발생 시점 |
|---|---|
Invalid JSON | 잘못된 형식의 메시지 |
Request already in progress | 다른 요청이 실행 중일 때 프롬프트 전송 |
Process timed out | CLI가 --timeout을 초과했을 때 |
Runner has been disposed | 연결이 정리되었을 때 |
<Agent> CLI exited with code N | CLI 프로세스가 실패했을 때 |
Request cancelled | 취소 메시지를 수신했을 때 |
Server is shutting down | 정상적인 종료 절차가 진행 중일 때 |
agent-ws는 시작할 때마다 무작위 인증 토큰(auth token)을 생성합니다. 클라이언트는 이를 쿼리 매개변수(query parameter)로 포함해야 합니다:
ws://localhost:9999?token=<token>
이것은 다른 웹사이트나 애플리케이션이 로컬 agent-ws 인스턴스에 연결하는 것을 방지합니다. 이것이 없으면 방문하는 모든 페이지가 localhost:9999로 WebSocket을 열고 사용자의 장치에서 명령을 실행할 수 있습니다(브라우저는 WebSocket 연결에 대해 CORS를 강제하지 않습니다).
인증 기능을 비활성화하려면 (예: 로컬 개발/테스트용):
agent-ws --no-auth
라이브러리 API를 사용할 때는 옵션에 authToken을 전달합니다:
import { AgentWS } from "agent-ws";
import { randomBytes } from "node:crypto";
const token = randomBytes(32).toString("hex");
...
인증 토큰 (Auth token): 시작 시 생성되는 무작위 토큰으로, 모든 연결에 필수적입니다 (--no-auth로 비활성화 가능)
기본적으로 안전함 (Safe by default): --mode safe는 도구 접근 없이 텍스트 전용 응답으로 제한합니다
OS 샌드박스 (opt-in): --sandbox os는 스폰되는 모든 CLI를 Seatbelt(macOS) 또는 bubblewrap(Linux)으로 감쌉니다. 보장 사항 및 주의사항은 Sandboxing을 참조하십시오.
로컬 전용 (Local only): 기본적으로 localhost에 바인딩됩니다
Origin 검증: 선택적 --origins
플래그 제한: 허용되는 Origin을 제한합니다. 자격 증명 없음 (No credentials): API 키를 저장하거나 전송하지 않습니다. **프로세스 격리 (Process isolation)****: 연결당 하나의 CLI 프로세스를 사용합니다. 메시지 제한 (Message limits): 최대 WebSocket 페이로드 50MB, 최대 프롬프트 512KB, 이미지당 10MB(최대 4개), 총 100개 파일(총 50MB)입니다. 하트비트 (Heartbeat): 연결된 세션은 30초마다 정리됩니다. 속도 제한 (Rate limiting): IP당 최대 동시 연결 수 10개입니다. 안전 종료 (Graceful shutdown): SIGINT/SIGTERM 시 진행 중인 요청에 대해 5초의 배수 기간을 가집니다. 경로 순회 방지 (Path traversal protection): 파일 경로는 세션 디렉토리 내에 머무르도록 검증됩니다.
npm install # 의존성 설치
npm run build # TypeScript 빌드
npm test # 테스트 실행
...
src/
├── index.ts # 배럴 익스포트 (라이브러리 진입점)
├── cli.ts # CLI 진입점 (Commander)
...
Claude Code가 설치되었는지 확인하세요:
npm install -g @anthropic-ai/claude-code
claude --version
agent-ws는 더 이상 Claude를 필수로 요구하지 않습니다. Codex만으로 시작하거나 그 반대도 가능합니다. 기능 핸드셰이크(capabilities handshake)를 통해 실제로 사용 가능한 Provider가 무엇인지 보고합니다.
다른 인스턴스가 실행 중일 수 있습니다. 해당 프로세스를 종료하거나 다른 포트를 사용하세요:
agent-ws --port 9998
Ubuntu 24.04 이상 버전은 기본적으로 특권 없는 사용자 네임스페이스(unprivileged user namespaces)를 비활성화합니다. 다음 중 하나를 수행해야 합니다:
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 # 임시적
# 또는 영구 적용:
echo
AI 자동 생성 콘텐츠
본 콘텐츠는 GitHub AI Tools의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기