글 목록으로
2026년 11월 6일
12분 소요

DeepSeek이 공개한 팀 채팅 상주 에이전트 Super-Agent: 사람에게 말 거는 규칙은 코드로, 셸과 머지는 프롬프트로 막았다

DeepSeek Harness 팀이 10월 31일 공개한 Super-Agent는 GitHub와 팀 채팅을 지켜보다가 허락된 사람이 시킨 일을 PR로 돌려주는 연구용 프로토타입이다. 설계 글은 사람이 동시에 따라갈 수 있는 세션이 3~5개뿐이라 병목이 사람의 주의력으로 옮겨 갔다고 진단하고, 위임하라는 프롬프트만으로는 단일 세션이 5번 중 4번만 위임했다는 실험으로 위임을 구조로 옮긴 이유를 보여 준다. 공개 커밋의 코드를 읽고 테스트 1,197개를 돌려 보니, 누가 일을 시킬 수 있는지와 사람에게 어떤 메시지를 보낼 수 있는지는 호스트 코드가 판정한다. 반면 워커가 쓰는 gh·lark-cli 셸 경로, 자동 머지 조건, 명령 차단은 프롬프트와 셸 래퍼에 맡겨져 있고 문서도 이를 보안 경계가 아니라고 적었다. 무엇이 어디서 집행되는지 정리하고, Claude Code나 Codex로 팀 봇을 만들 때 그대로 가져올 것과 직접 보강할 것, 효과를 재는 방법을 정리했다.

DeepSeek Harness 팀이 10월 31일 Super-Agent 프로토타입을 MIT 라이선스로 공개했다. GitHub 저장소 하나와, 선택적으로 Feishu(ByteDance의 업무용 메신저) 채팅방을 지켜보다가 허락된 사람이 일을 시키면 작업 항목을 열고, 별도 세션에서 처리한 뒤 원래 대화에 PR 링크로 답하는 에이전트다. #64에서 분석한 DeepSeek Harness(dsh) 위에 얹는 번들 형태이고, README 첫 줄에 “공식 제품이 아닌 참고용 연구 프로토타입”이라고 적혀 있다. 공개 엿새 만에 스타 1만 9,882개를 받았다(11월 6일 GitHub API 조회).

같은 날 올라온 설계 글 「Super-agent 설계 탐구: 더 자율적인 에이전트 시스템을 향해」(위챗 원문, X 영어판)의 진단은 이렇다. 모델이 작업 하나를 혼자 끝내는 능력은 좋아졌는데, 사람이 동시에 따라갈 수 있는 활성 세션은 보통 3~5개다. 세션을 오가며 각 세션이 무슨 일을 하고 있었는지 기억하는 일이 사람 몫으로 남아 있어서, 생산성의 상한이 사람의 주의력으로 정해진다는 것이다. 그래서 README는 원칙을 한 문장으로 적었다. “사람의 주의는 최대한 적게 쓰고, 가치는 최대한 많이 준다.”

국내 기사는 대부분 “Claude Code를 겨냥했다”(Bloomberg의 표현이고 DeepSeek 자료에는 없다)와 완료 시간 수치를 전했다. 영어권 분석 글들은 “팀의 주의력을 예산으로 본다”는 틀로 권한 모델을 설명했지만, 모두 문서를 읽고 쓴 글이다. 그 원칙이 코드로 강제되는지 프롬프트로 부탁하는 수준인지는 확인하지 않았다.

이 글은 그 부분을 확인한다. 공개 커밋(8c32a9d, 10월 31일)의 소스와 프롬프트를 읽고 테스트 스위트를 돌렸다(59개 파일, 1,197개 테스트 통과). 봇 계정과 DeepSeek API 키가 필요한 실제 설치와 운영은 하지 않았으므로, 아래 내용은 코드와 테스트, 문서, 설계 글을 근거로 한다.

Super-Agent가 일을 받고 끝내는 흐름

구성은 라우터(코드에서는 orchestrator) 세션 하나와, 작업마다 새로 뜨는 워커(worker) 세션으로 나뉜다. 메시지 하나가 들어와서 PR이 되기까지 누가 무엇을 하는지는 다음과 같다.

단계 하는 일 판단하는 주체
Source GitHub 알림·이슈·PR·CI, Feishu 메시지를 읽어 Trigger(이벤트)로 바꾼다. 봇 자신의 메시지는 여기서 버린다 코드
게이트 보낸 사람이 허용 목록에 있는지, 에이전트를 직접 불렀는지(멘션·DM), 어느 채팅방인지로 “명시적 요청 / 추정 후보 / 무시”를 가른다 코드
평가(Eval) 추정 후보가 팀이 써 둔 규칙에 해당하는지 판단한다 라우터 모델
Ticket과 Mandate 수락하면 작업 단위인 Ticket을 만들고, 왜 해도 되는지(정책 버전, 범위, 근거가 된 규칙, 요청자)를 Mandate로 고정한다 코드가 기록
실행 Ticket마다 워커 세션과 작업 디렉터리를 하나씩 만든다. 같은 스레드의 후속 메시지는 라우터를 거치지 않고 그 워커에게 바로 간다 워커 모델
답장 접수 확인, 결과, 질문을 원래 대화로 보낸다 라우터 모델이 쓰고 코드가 검사

라우터는 일을 직접 하지 않는다. 설계 글에 따르면 라우터는 Bash 도구 없이도 돌아가고, 사람과 대화하고 작업을 나눠 주는 일만 한다. 코드도 같은 방향이다. 라우터 세션에는 sleep, 30초가 넘는 셸 타임아웃, 5초가 넘는 작업 대기를 거부하는 장치가 있다. 라우터가 한 단계에서 막혀 있으면 새로 들어온 요청이 그만큼 늦어지기 때문이다.

새로운 기법은 많지 않다. 결정적인 조건을 코드로 먼저 걸러내고 의미 판단만 모델에 넘기는 방식은 설계 글 스스로 컴퓨터 시스템의 Fast Path/Slow Path에서 빌려 왔다고 밝혔다. 스레드 구독은 pub/sub이다. 세션 로그를 하네스 밖에 두는 설계는 Anthropic의 “Decoupling the brain from the hands”와 같은 접근이라고 직접 인용했다. 이 프로젝트에서 새로 볼 것은 기법보다 그 기법들을 “사람에게 언제 말을 거는가”라는 기준 하나로 묶은 방식이다.

위임하라는 프롬프트로는 부족했다는 실험

설계 글의 실험에서 이 구조를 택한 이유가 드러난다. 채팅 메시지와 CI 메시지를 섞은 약 300개 메시지(그중 작업 요청 약 20개)를 흘려보내고 네 가지 구성을 5번씩 돌렸다. 코딩 작업 자체는 시간만 소모하는 가짜 도구로 대신했으므로, 이 실험은 코딩 실력이 아니라 일을 나누고 조율하는 능력만 잰다.

  • Super-Agent는 요청부터 결과 메시지까지 p50 12.4분, p95 15.7분이 걸렸다.
  • 서브에이전트 도구를 가진 단일 세션에 중립 프롬프트(“적절하면 서브에이전트를 써라”)를 주자, 5번 모두 위임하지 않았다. 새 메시지가 올 때마다 하던 일이 끊겼고 p95는 29.5분이었다.
  • 위임 우선 프롬프트(“모든 메시지가 너에게 오니 직접 하면 계속 끊긴다, 일은 서브에이전트에게 넘겨라”)로 바꾸자 5번 중 4번 위임했다. 나머지 한 번은 모델이 일이 “작다”고 판단해 직접 했고, 그 회차에서 완료 시간이 길게 늘어졌다.

설계 글의 결론은 단일 세션이 위임 여부를 프롬프트와 모델의 즉석 판단에 맡길 수밖에 없다는 것이다. 그래서 라우터에서 실행 능력을 빼서 위임을 구조로 강제했다.

비용도 같이 봐야 한다. 세션을 여러 개 유지하므로 Super-Agent는 실행당 캐시 읽기 토큰을 단일 세션 구성보다 많이 쓴다. 설계 글은 이를 “토큰을 주고 짧고 안정적인 완료 시간을 산다”고 표현했다. 후속 메시지를 워커로 바로 보내는 장치(pass-through)를 끄면 완료 시간은 거의 같지만, 라우터의 결정 횟수가 약 30% 늘고 캐시 읽기 토큰이 2,320만 개에서 3,180만 개로 37% 늘었다. 라우터 단독 부하 실험에서는 분당 이벤트가 약 1개에서 40개로 늘 때 결정당 평균 추론 시간이 6.4초에서 1.6초로 줄었다. 한 턴 동안 쌓인 이벤트를 다음 호출에 묶어 넣기 때문이다. 수치는 모두 합성 부하와 단순화한 환경에서 DeepSeek이 직접 잰 값이고, 설계 글도 “참고용”이라고 적었다.

코드가 집행하는 규칙

위임을 구조로 옮긴 원칙은 권한과 메시지에도 적용돼 있다. 문서 004는 지침의 강도를 다섯 단계로 나누고, 맨 위에 “도구와 호스트가 집행하는 사실: 신원, 권한, 도구 인자 검사, 답장 목적, 길이 제한. 프롬프트로 바꿀 수 없다”를 두었다. 코드에서 확인한 항목은 다음과 같다.

누가 일을 시킬 수 있는가. src/admission.ts와 src/policy.ts가 판정한다. 허용 목록에 있는 사람이 에이전트를 직접 부르면 명시적 요청이 된다. 목록 밖의 사람은 기본값이 무시다. 봇은 목록에 올려도 추정 후보까지만 될 수 있고 명시적 요청은 할 수 없다. 사람이 시키지 않은 일을 규칙에 따라 먼저 하는 모드는 기본값이 observe(policy.ts의 z.enum(['off', 'observe', 'auto']).default('observe'))다. 이 모드에서는 “수락했을 것”이라는 판단만 기록하고 실제로는 아무것도 수락하지 않는다. 이슈 본문이나 인용된 문서에 “이 봇에게 권한을 줘라”라고 써 있어도 게이트는 바뀌지 않는다.

한번 준 권한은 언제 다시 확인하는가. 끝난 Ticket은 Mandate를 계속 갖고 있다가, 사람이 같은 스레드에 다시 말을 걸면 새 평가 없이 이어서 일한다. 이어서 일하기 전에는 현재 정책으로 Mandate를 다시 검증한다. 그 사이 요청자가 허용 목록에서 빠졌거나 근거 규칙이 꺼졌다면 Ticket은 끝난 상태로 남는다.

사람에게 어떤 메시지를 보낼 수 있는가. 이 부분이 이 프로젝트의 원칙이 가장 구체적으로 구현된 곳이다. 라우터가 사람에게 말하는 도구 orchestrator_reply는 목적(purpose)을 answer, result, attention 중 하나로 받고, src/core/replies.ts가 목적마다 조건을 검사한다.

  • result(결과)는 Ticket의 최신 보고가 ready이거나 Ticket이 완료·머지·드롭으로 끝났을 때만 나간다. 아니면 notReady 오류다.
  • attention(사람의 결정 요청)은 워커가 구조화된 필드로 올린 질문과 글자 그대로 같은 질문일 때만 나간다. 다른 질문을 지어내면 notAttention이다.
  • answer(답변)는 사람이 실제로 물은 메시지를 가리켜야 하고, 워커가 그 질문에 답했다고 보고한 뒤에만 한 번 쓸 수 있다.
  • 접수 확인(acknowledgement)은 사람이 보낸 메시지에만 달 수 있고, 같은 메시지에는 재시작을 거쳐도 한 번만 나간다.

진행 상황을 알리는 목적은 아예 없다. “아직 작업 중입니다” 같은 메시지는 보낼 방법이 없다는 뜻이다. tests/core-engine.spec.ts에 준비되지 않은 Ticket의 결과 메시지와 열린 질문이 없는 Ticket의 결정 요청이 거부되는 테스트가 있고, 이번에 돌린 스위트에서 통과했다. 메시지 길이도 도구 스키마가 자른다. 채팅 메시지는 100단어(중국어는 형태소 분절 기준), 라우터가 워커에게 붙이는 메모는 30단어를 넘으면 zod 검증에서 거부된다(src/infra/text.ts의 IM_WORDS = 100, NOTE_WORDS = 30).

프롬프트 캐시를 고려한 배치도 코드에 있다. 정책 섹션은 매 요청마다 설정에서 새로 만들어 시스템 프롬프트 맨 끝에 붙인다. 정책이 바뀌어도 앞부분은 그대로 남아 캐시가 깨지지 않게 하려는 배치다. 캐시 접두부를 지키는 설계는 #48에서 다뤘다.

프롬프트와 셸 래퍼에 맡긴 규칙

반대쪽 목록도 있다. 문서가 숨기지 않고 적어 둔 것들이다.

워커의 셸에서는 메시지를 직접 보낼 수 있다. 워커는 GitHub에 에이전트 계정의 gh로, Feishu에 봇의 lark-cli로 접근한다. src/infra/environment.ts를 보면 두 명령은 실제 CLI를 그대로 실행하는 얇은 셸 스크립트(shim)다. 하위 명령을 가리지 않는다. PR 리뷰 댓글에 답하는 일은 원래 워커가 gh api .../replies로 직접 하도록 GitHub 스킬에 적혀 있다. 그러니 앞에서 본 답장 목적 검사는 라우터의 답장 도구를 지날 때만 적용된다. 워커가 셸로 메시지를 보내지 못하게 하는 것은 프롬프트 문장이다. prompts/work.md의 “IM 전달은 orchestrator가 맡는다. 직접 두 번째 IM 메시지를 보내지 마라”, prompts/replies.md의 “진행 보고를 답변으로 바꿔 달거나, 질문을 지어내거나, 거부된 답장을 CLI로 우회하지 마라”가 그 역할을 한다. 우회 경로가 있다는 것을 알고 프롬프트로 막아 둔 셈이다.

명령 차단은 이름으로만 막는다. 운영자가 막을 명령을 지정하면 같은 이름의 shim이 오류를 낸다. 문서 003은 “이 래퍼와 디렉터리는 기본값을 정할 뿐 보안 경계가 아니다. 워커는 절대 경로로 프로그램을 실행할 수 있다”고 적었다. 워커 세션은 운영자의 OS 사용자 권한으로 승인 없이 명령을 실행한다. 따라서 운영자 계정이 읽을 수 있는 파일은 워커도 읽을 수 있다.

자동 머지 조건은 프롬프트에 있다. 기본 지침은 에이전트 계정으로는 자동 머지를 켜지 않게 한다. GitHub은 자동 머지를 켠 사람을 머지한 사람으로 기록하기 때문이다. 별도 계정의 CLI가 지정됐을 때만 PR이 준비됐고, 변경이 200줄 미만이고, 필요한 승인이 현재 head 커밋을 덮을 때 자동 머지를 켠다. 문서는 “호스트에는 머지 전용 판단 로직이 없다”고 밝히고, 승인을 강제하려면 GitHub branch protection에서 요구하라고 안내한다. GitHub 메시지 첫 줄의 “This is by an automated agent, not a human” 공개 문구도 기본 프롬프트에 들어 있는 문장이다.

정리하면 다음과 같다.

집행 방식 항목 근거
호스트 코드 일을 시킬 수 있는 사람 판정, observe 기본값, Mandate 기록과 재검증, 답장 목적 4종과 상태 조건, 메시지 100단어·메모 30단어, 라우터의 대기 금지 admission.ts, policy.ts, core/replies.ts, tools/main.ts, 테스트
프롬프트 워커가 셸로 메시지를 보내지 않기, 작업 중 침묵, 자동 머지 조건(200줄 미만), 공개 문구 prompts/work.md, prompts/replies.md, prompts/team/*.md
기본값일 뿐 강제 아님 명령 차단, Ticket별 디렉터리 분리 문서 003

이 배치에는 이유가 있다. 앞의 칸은 모두 호스트가 이미 갖고 있는 구조화된 사실(보낸 사람, Ticket 상태, 보고 필드)로 판정할 수 있다. 뒤의 칸은 셸을 가진 워커가 무엇을 하는지에 대한 문제라서 프로세스 수준의 격리가 필요하다. 설계 글도 보안과 프라이버시를 미해결 과제로 꼽았다. 이벤트 기반 구조는 신뢰할 수 없는 입력을 계속 받아들이므로, 클라우드의 에이전트 루프가 프롬프트 인젝션으로 장악되면 연결된 단말 전체가 위험해진다는 것이다. 자격 증명이 모델 컨텍스트에 들어갈 수 있는 한 정상 실행 중에도 새어 나갈 수 있으니, 에이전트가 자격 증명을 보지 않고 쓰는 방법이 필요하다고도 적었다.

#56의 Grok Bot은 계정당 컴퓨터 한 대를 모든 봇이 같이 쓰고, 문서도 봇을 보안 경계로 쓰지 말라고 했다. Super-Agent는 누가 시켰고 어디까지 해도 되는지를 도메인 개념(Mandate)으로 만들어 코드로 집행한다는 점에서 한 단계 더 나갔다. 다만 실행 격리에서는 같은 문제가 남아 있고, 문서가 그 사실을 먼저 밝혔다는 점이 다르다.

Claude Code나 Codex로 팀 봇을 만들 때

Slack이나 GitHub에서 Claude Code, Codex, 직접 만든 Agent SDK 봇을 팀 채널에 붙여 쓰고 있다면, 이 코드에서 가져올 것과 직접 보강할 것이 나뉜다. 아래는 Super-Agent 코드에서 확인한 방식을 바탕으로 한 제안이고, 이 글에서 직접 운영해 검증한 것은 아니다.

1. 사람에게 말하는 도구를 목적별로 나누고 상태로 검사한다. 지금 봇이 send_message(text) 같은 도구 하나로 채널에 글을 쓴다면, 메시지를 줄이라는 지시는 프롬프트에만 있다. 목적을 enum으로 받고 호스트가 가진 상태로 검사하면, 모델이 진행 보고를 보내고 싶어도 보낼 수단이 없어진다.

// 예시: 목적을 enum으로 받고, 목적마다 호스트 상태로 허용 여부를 정한다
const reply = z.object({
  purpose: z.enum(['ack', 'answer', 'result', 'attention']),
  ticketId: z.string(),
  text: z.string().refine(t => wordCount(t) <= 100, '100단어 이하'),
})

function allow(r: z.infer<typeof reply>, t: Ticket): boolean {
  switch (r.purpose) {
    case 'ack': return t.ackSent === false && t.trigger.fromHuman
    case 'result': return t.report?.state === 'ready' || t.ended
    case 'attention': return t.openQuestion !== undefined
    case 'answer': return t.pendingHumanQuestion !== undefined
  }
}

2. 워커 환경에서 채팅 자격 증명을 뺀다. Super-Agent가 프롬프트로 막은 우회 경로를 직접 만드는 봇이라면 처음부터 닫을 수 있다. 워커가 채팅 메시지를 보낼 필요가 없다면 Slack이나 Feishu 토큰을 워커 프로세스의 환경과 파일 시스템에 아예 두지 않는다. 메시지는 호스트의 답장 도구만 보낸다. GitHub은 PR을 만들고 리뷰에 답하려면 쓰기 권한이 필요해서 토큰 범위로 댓글만 따로 막기 어렵다. 그러니 GitHub 쪽은 차단보다 감사(아래 측정 방법)로 다루는 편이 현실적이다.

3. 머지 조건은 branch protection으로 옮긴다. “200줄 미만이면 자동 머지” 같은 조건을 프롬프트에 두고 있다면, 필수 리뷰어와 새 커밋이 올라오면 기존 승인을 무효로 하는 설정(dismiss stale approvals)을 GitHub에 건다. 에이전트 계정에는 머지 권한을 주지 않는다. Super-Agent 문서가 권하는 방식이기도 하다. 머지 전 판정을 무엇에 맡길지는 #81에서 다뤘다.

4. 워커는 격리된 환경에서 돌린다. 워커가 승인 없이 셸을 쓰는 구조라면 명령 이름 차단으로는 부족하다. 컨테이너나 VM에 작업 디렉터리만 마운트하고, 운영자의 SSH 키와 클라우드 자격 증명이 없는 환경에서 돌린다. 여러 워커가 같은 도구나 캐시를 공유할 때 생기는 문제는 #76에서 다뤘다.

5. 먼저 시키지 않은 일은 관찰 모드로 시작한다. 채널의 모든 메시지를 읽고 알아서 일을 시작하게 하려면, Super-Agent의 observe처럼 “수락했을 것” 판단만 기록하는 기간을 둔다. 그 기록을 사람이 보고 맞다고 판단한 비율이 충분할 때 자동 수락으로 바꾼다.

효과를 확인하는 방법

이 설계의 목표는 완료 시간보다 사람이 쓰는 주의를 줄이는 것이므로, 측정도 그쪽에 맞춘다. 바꾸기 전 구성으로 2주쯤 기준선을 잡고, 메시지 도구 변경과 워커 격리를 따로 적용해서 비교한다.

  • 완료된 작업 하나당 사람이 받은 메시지 수. 봇 계정이 채널과 GitHub에 남긴 메시지를 세고 완료된 작업 수로 나눈다. 이 비율이 줄었는데 완료 작업 수가 같다면 개선이다.
  • 답장 도구를 거치지 않은 메시지. GitHub API나 채팅 API로 봇 계정의 메시지를 가져와 호스트의 발신 기록과 대조한다. 기록에 없는 메시지는 워커가 셸로 보낸 것이다. 2번을 적용한 채팅 쪽은 0이어야 하고, GitHub 쪽은 리뷰 답글 외의 것이 있는지 본다.
  • 관찰 모드의 판단 정확도. “수락했을 것”으로 기록된 판단 중 사람이 동의한 비율과, 사람이 따로 요청한 일 중 봇이 놓친 비율을 같이 본다.
  • 토큰 비용. 설계 글의 실험처럼 세션을 나누면 캐시 읽기 토큰이 늘 수 있다. 작업당 토큰과 청구액을 기준선과 비교하고, 완료 시간이나 메시지 수가 나아지지 않았는데 비용만 늘었다면 이전 구성으로 되돌린다.

정리

Super-Agent는 팀 채팅에 상주하는 코딩 에이전트의 비용을 토큰보다 사람의 주의로 보고, 그 기준으로 구조를 짰다. 일을 시킬 수 있는 사람, 먼저 일을 시작하는 조건, 사람에게 보낼 수 있는 메시지의 종류와 길이는 호스트 코드가 판정하고, 테스트로 그 동작을 확인할 수 있다. 위임을 프롬프트에 맡겼을 때 생기는 문제를 실험으로 보이고 구조로 옮긴 판단이 메시지 규칙에도 그대로 이어졌다.

워커가 셸에서 쓰는 메시지 경로, 자동 머지 조건, 명령 차단은 아직 프롬프트와 셸 래퍼에 있다. 문서와 설계 글이 이 한계를 직접 적었다. 팀 봇을 만든다면 메시지 도구와 권한 판정 방식은 가져오고, 워커의 자격 증명 분리와 실행 격리, 머지 규칙은 GitHub 설정과 실행 환경에서 따로 갖춰야 한다.

이 글의 근거는 공개 커밋의 코드와 테스트, 문서, 설계 글이다. 실제 저장소에 설치해서 운영하지는 않았다. README가 밝혔듯 공개판은 DeepSeek 내부 버전과 다르고, 설계 글의 일부는 아직 구현되지 않았다. 완료 시간과 토큰 수치는 DeepSeek이 합성 부하에서 잰 값이며 외부에서 재현한 결과는 아직 없다.