코딩 에이전트를 밤새 돌려놓고 아침에 보면 작업이 끝난 것이 아니라 권한 요청 화면에서 멈춰 있는 경우가 있습니다. 더 나쁜 경우에는 분명히 중단했다고 생각한 빌드가 백그라운드에서 계속 돌아 시스템을 느리게 만듭니다. 모델 품질과 별개로, 하네스가 언제 멈추고 무엇을 함께 종료하는지가 실제 사용성을 좌우합니다.

Chris Wellons는 10월 31일 Prospero를 공개했습니다. C++로 작성한 단일 실행 파일에 Dear ImGui 인터페이스를 붙인 코딩 하네스입니다. GitHub 저장소는 Unlicense로 공개돼 있고, Windows·macOS·Linux를 지원합니다. 이 글은 원문과 저장소 문서를 읽은 뒤, 하네스 설계에서 재사용할 수 있는 부분을 CodeBridge의 로컬 실험으로 확인한 기록입니다. Prospero 자체를 빌드하거나 모델을 연결해 실행하지는 않았습니다.

“100배 적은 메모리”는 저자의 주장이고, 구조는 따로 확인할 수 있다

원문은 다른 하네스보다 “약 두 자릿수 적은 자원”을 쓴다고 설명합니다. 이 수치는 저자의 표현이며, 비교 대상·측정 조건·측정 방법·독립 재현이 공개되지 않았습니다. 이 글에서 100배라는 숫자를 사실로 취급하지 않습니다.

대신 구조적으로 확인 가능한 차이는 있습니다. Prospero는 웹 스택이나 별도 데몬 없이 하나의 실행 파일로 동작합니다. 창이 없을 때는 렌더링을 하지 않는 수동 렌더링을 쓰고, 같은 실행 파일을 SSH 너머의 헤드리스 엔진으로 띄울 수 있습니다. 이 세 가지는 메모리 사용량 자체를 증명하지는 않지만, 상주 프로세스와 유휴 렌더링을 줄이는 방향의 설계라는 점은 문서에서 확인됩니다.

Prospero 공식 저장소의 macOS 실행 화면. 왼쪽 세션·서브에이전트, 가운데 대화 기록, 오른쪽 백그라운드 작업과 계획 패널이 보인다.

이미지: skeeto/prospero 공식 저장소 스크린샷. 저장소는 Unlicense(퍼블릭 도메인)로 공개돼 있습니다.

핵심 원칙은 “영원히 기다리지 않는다”

원문에서 가장 실무적인 문장은 성능 주장이 아니라 이 원칙입니다. Prospero는 모든 작업에 데드라인을 둡니다. 사용자가 자리에 없어 권한 요청에 응답하지 않으면, 일정 시간 뒤 요청은 거부로 처리되고 에이전트는 그 전제로 계속 진행해야 합니다.

여기에 몇 가지 규칙이 붙습니다.

  • 모든 네트워크 요청에 타임아웃이 있습니다.
  • 워치독이 무한 대기를 막습니다.
  • 에이전트 간 메일박스 크기가 제한됩니다.
  • 셸 명령이 타임아웃되면 동기 실행을 포기하고 비동기 백그라운드 작업으로 전환합니다.
  • 예외는 Plan 모드의 사용자 응답 대기처럼 사람이 실제로 지켜보는 상황입니다.

이 설계는 “실패하지 않는 에이전트”가 아니라 “실패해도 통제 가능한 에이전트”를 만드는 쪽에 가깝습니다. 모델이 느리거나 도구가 응답하지 않을 때 하네스 전체가 멈추지 않고, 다음 판단으로 넘어갈 수 있게 합니다.

중단 버튼이 실제로는 셸만 죽일 때

프로세스 정리 이야기는 추상적으로 들리기 쉽습니다. 그래서 CodeBridge가 Node.js로 작은 실험을 만들었습니다. 셸이 sleep 자식 프로세스를 하나 띄우고 기다리는 상황에서, 셸만 종료하는 경우와 프로세스 그룹 전체를 종료하는 경우를 비교합니다.

import { spawn } from "node:child_process";
import fs from "node:fs";
import { setTimeout as sleep } from "node:timers/promises";

const alive = (pid) => {
  try { process.kill(pid, 0); return true; } catch { return false; }
};

async function run(mode) {
  const pidFile = `/tmp/grandchild-${mode}.pid`;
  fs.rmSync(pidFile, { force: true });
  const shell = spawn("/bin/sh", ["-c", `sleep 30 & echo $! > '${pidFile}'; wait`], {
    detached: mode === "group",
    stdio: "ignore"
  });
  for (let i = 0; i < 50 && !fs.existsSync(pidFile); i++) await sleep(20);
  const grandchild = Number(fs.readFileSync(pidFile, "utf8").trim());

  process.kill(mode === "group" ? -shell.pid : shell.pid, "SIGTERM");
  await sleep(400);
  const result = { mode, shellAlive: alive(shell.pid), grandchildAlive: alive(grandchild) };
  if (result.grandchildAlive) process.kill(grandchild, "SIGKILL");
  return result;
}

console.log(JSON.stringify(await run("naive")));
console.log(JSON.stringify(await run("group")));

macOS에서 Node.js 24로 실행한 실제 출력입니다.

{"mode":"naive","shellAlive":false,"grandchildAlive":true,"grandchildPid":3700}
{"mode":"group","shellAlive":false,"grandchildAlive":false,"grandchildPid":3702}

첫 줄이 문제의 핵심입니다. 셸은 죽었지만 손자 프로세스는 살아 있습니다. 빌드 시스템이 실제 컴파일러나 테스트 러너를 손자로 띄웠다면, 하네스는 “중단됨”이라고 보고해도 작업은 계속됩니다. 두 번째 줄은 새 프로세스 그룹을 만들고 그룹 전체에 신호를 보냈을 때 둘 다 종료된 결과입니다.

이 실험은 Prospero의 구현을 재현한 것이 아닙니다. 하네스가 프로세스 그룹, job object, cgroup 같은 경계를 어떻게 잡는지에 따라 같은 문제가 달라진다는 점만 보여주는 합성 예제입니다. Windows에서는 job object, Linux에서는 cgroup이나 프로세스 그룹, macOS에서는 프로세스 그룹과 세션 관리가 관련됩니다. “자식 프로세스를 kill했다”는 한 줄로는 어느 계층까지 정리됐는지 알 수 없습니다.

하네스를 고를 때 확인할 질문

Prospero의 문서를 읽고 바로 적용할 수 있는 점검 항목을 정리하면 다음과 같습니다. 제품의 기능 목록보다 장애 상황에서의 계약을 먼저 보는 편이 낫습니다.

질문 확인할 증거 흔한 오해
도구 호출마다 데드라인이 있는가 설정 문서, 타임아웃 로그, 취소 테스트 모델의 응답이 끝나면 작업도 끝난다
권한 요청이 방치되면 어떻게 되는가 기본 허용/거부 정책, 만료 시간 무응답은 안전한 대기다
중단 시 프로세스 트리가 함께 죽는가 손자 프로세스 PID 확인, 그룹 종료 테스트 셸 종료는 빌드 종료다
유휴 상태에서 자원을 쓰는가 렌더링 방식, 상주 프로세스, 측정값 기능이 많으면 메모리도 당연히 많다
창을 닫아도 작업이 이어지는가 헤드리스 엔진, 재접속 절차 데스크톱 앱이 꺼지면 세션도 끝난다
권한 시스템을 보안 경계로 쓸 수 있는가 컨테이너·VM 격리 문서 승인 프롬프트가 악성 코드를 막는다

마지막 항목은 원문도 분명히 말합니다. 권한 시스템은 악의적인 에이전트를 막는 보안 경계가 아니라 실수를 줄이는 장치입니다. 에이전트가 하네스와 같은 권한으로 프로그램을 실행할 수 있다면, 결국 하네스 자체를 컨테이너나 별도 기기에 가둬야 합니다. 이 주제는 에이전트 샌드박스 설계 글에서 더 다룹니다.

도입 전에 남는 제약

Prospero에는 모델 제공자가 기본으로 들어 있지 않습니다. 사용자가 llama.cpp, vLLM, LiteLLM, OpenRouter, Anthropic API, OpenAI API 같은 엔드포인트를 직접 설정해야 합니다. 원문은 Claude 구독으로는 사용할 수 없다고 명시합니다. 헤드리스 엔진을 포함한 Professional Edition은 유료이며, GitHub의 Community Edition은 원격 배포 기능이 제한됩니다.

설정은 ~/.config/prospero/prospero.ini에 두고, URL로 다른 설정을 include할 수 있습니다. 편리하지만 원문은 URL include가 셸 명령에 들어갈 수 있는 값을 제한하는 대신, API 키로 환경 변수를 추출해 공격자 엔드포인트로 보내는 경로는 남아 있다고 설명합니다. 공유 설정을 쓸 때는 출처를 신뢰해야 합니다.

메모리 절감 폭, 장시간 운전 안정성, 실제 모델과의 호환성은 이 글에서 측정하지 않았습니다. 특히 “두 자릿수 적은 자원”은 독립 벤치마크가 나오기 전까지는 설계 방향을 설명하는 주장으로 읽는 편이 안전합니다.

Prospero에서 배울 점은 C++이나 ImGui가 아닙니다. 작업마다 끝나는 조건을 두고, 사람이 없을 때의 기본값을 정하고, 중단이 실제 프로세스 트리까지 닿게 만드는 것입니다. 다음에 하네스 설정을 바꿀 때는 모델 목록보다 타임아웃·취소·자식 프로세스 정리 항목을 먼저 확인해 보시길 권합니다.

아래 유료 강의는 Claude Code를 포함한 AI 코딩 하네스의 검증과 제약 설계를 다룹니다. Prospero 자체의 사용법이나 이 실험의 재현을 제공하는 강의는 아니며, 링크는 홍보 링크입니다.