DeepSeek Harness · 오케스트레이션과 서브 Agent

Skill, Preset, 그리고 자기 수정

cordis_define은 Agent가 런타임에 자기 런타임을 고쳐 쓰게 해요. 핵심 디렉터리: packages/extensions/tool-cordis/apps/cli/config/agent-presets/.

강의 목표읽고 나면 세 가지를 말할 수 있어요. 발표문에 나온 “표준 / 코드 / 미니멀 / 크리에이티브” 네 모드가 왜 YAML 네 개뿐인지; 크리에이티브 모드에서 Agent가 cordis_definecordis_run으로 런타임에 스스로 새 도구를 키우는 방식과, 이 자기 수정의 신뢰 경계가 어디에 그려지는지; skill 계층 레지스트리에서 preset 층이 전역 층을 어떻게 가리는지.
인터랙티브 데모 · 자기 수정 한 바퀴

장면: 크리에이티브 모드(cordis preset) 세션에서 사용자가 “코드 줄 수를 세는 도구 하나 만들어 줘”라고 해요. 왼쪽은 런타임 실시간 상태, 오른쪽은 Agent 동작 — 자막을 따라 한 바퀴 돌아요.

0 / 8

플러그인 등록부 (Plugin / Package)

loc · Package v1미정의
loc · Package v2미정의

도구 목록

bashstr_replacesubagentcordis_inspect_querycordis_definecordis_runloc_count

Agent의 동작

cordis_inspect_query → Service와 Builtin의 정확한 시그니처를 읽어요
cordis_define kind:"new" → pluginId=loc / packageId=v1을 돌려줘요
cordis_run mode:"run" → v1이 활성화되고 loc_count가 목록에 들어가요
도구 세트가 바뀜 → 로그가 변경 후 전체 요청 헤더를 기록해요
loc_count → 결과가 빈 줄까지 세어 버렸어요, 고쳐야 해요
cordis_define kind:"existing" → v2를 추가하고 v1은 그대로 남겨요
cordis_run mode:"update" → v2로 전환, 실패하면 v1으로 롤백할 수 있어요
플러그인 줄을 ~/.dsh/.agent-presets/my-mode/에 써 넣어요 → 다섯 번째 모드
“재생”을 눌러 Agent가 런타임에 스스로 새 도구를 키우는 모습을 보세요.
데모는 수업용 시뮬레이션이에요. 흐름은 packages/extensions/tool-cordis/src/index.ts의 cordis_define·cordis_run 도구 설명 원문(148–259행)을 바탕으로 정리했고, 확인일 2026-08-13.
로직 분해 · 모드는 그저 YAML 한 장

먼저 발표문의 그 궁금증부터 풀어요. 표준·코드·미니멀·크리에이티브 네 모드인데, 소스에는 모드 분기 한 줄도 없어요. apps/cli/config/agent-presets/ 아래가 디렉터리 네 개이고, 각 디렉터리에 agent.cordis.yml 한 장 — 파일이 플러그인 조합 하나를 말해 세션 하나에 마운트돼요. 미니멀 모드는 전부 62행: persona 한 줄 “You are a helpful software engineer assistant.”에 complete: true(이후 조립이 프롬프트에 더 넣는 걸 거절), 도구는 지속 bash와 편집기뿐, 압축조차 없어요 — 벤치마크용 설정이에요. 크리에이티브 모드는 표준 모드를 그대로 두고 셋만 더 걸어요: 자기 지시 도구 세트 tool-cordis, 조합 작성을 가르치는 skill, 두 평면을 가르는 persona.

두 평면이 이 체계의 좌표계예요. HOST 조합은 세션을 넘어 공유하는 것: 영속화, 샌드박스와 승인, 모델 라우팅, subagent 레지스트리. AGENT PRESET은 한 세션이 그 레지스트리에 보태는 것: 도구, persona, 프롬프트 단락. 경계가 얼마나 가느냐는 디테일에서 보여요. preset에서 서비스를 게시하는 줄은 host에 속하거나 isolate realm에 싸여야 해요. 미니멀 모드가 샌드박스 없는 로컬 파일시스템을 쓰려면 fs-local을 자기 realm에 넣고, 그 세션의 fs만 가려요 — 다른 세션은 그대로 샌드박스를 타요(minimal/agent.cordis.yml 46–57행).

skill도 계층이에요. 전역 층은 배포 단위로 등록된 것(저장소 플러그인), preset 층은 preset을 따라다니는 것. 읽을 때 가까운 층의 동명이 그냥 이기고, 정렬 가중치는 같은 층 안에서만 먹혀요. 크리에이티브 모드의 editing-cordis-compositions skill은 preset 디렉터리에 살며 preset과 함께 복사·편집돼요. 이유는 yml 주석에 있어요: 이 배포의 두 평면을 말하고, 복사 단위는 preset이에요(cordis/agent.cordis.yml 248–254행). 설계 기록은 계층 간 병합 정렬안을 일부러 기각했어요. 가림은 단호해야 하고, 아니면 모델이 동명 skill 둘을 보고 헷갈려요(.agents/notes/implemented/architecture/2026-08-09-layered-skill-registry.zh.md).

HOST 조합 · 세션 간 공유 영속화 · 샌드박스와 승인 · 모델 라우팅 · subagent 레지스트리 skill 레지스트리 · 전역 층 배포급 skill, 가까운 층 동명 항목에 가려짐 preset YAML 네 장 standard · code · minimal · cordis 각 장 = 한 세션의 플러그인 조합, 자기 skill 층과 isolate realm 포함 크리에이티브 모드의 자기 수정 루프 cordis_inspect_query가 런타임을 읽어요 cordis_define은 소스만 기록하고 실행하지 않아요 cordis_run이 불변 Package를 활성화해요 실패: currentPackageId는 그대로, 롤백 가능 만족하면: 새 preset 디렉터리로 저장 배포판 preset 디렉터리는 한 글자도 고치면 안 돼요 모드 전용 코드는 없어요. 모드 = 플러그인 조합; 자기 수정도 같은 걸 고쳐요: 조합에 줄을 더하거나 빼는 것
수업용 구조도: 노드와 연결은 소스 관계를 설명하며, 내용은 수업에 맞게 정리했습니다.
define은 실행하지 않아요

cordis_define은 인자·문법만 검사하고 소스를 불변 Package로 기록해요. 승인을 신청하지 않고, 실행하지 않고, currentPackageId도 안 움직여요. 돌리려면 cordis_run을 다시 호출해야 해요. 정의와 활성화를 나누니, 망가뜨려도 롤백할 대상이 남아요.

실패해도 포인터는 그대로

cordis_run은 완전 성공 후에만 currentPackageId를 바꿔요. 시작 실패면 옛 current는 그대로예요. 버전 변경은 kind:"existing"으로 새 Package를 추가하고, 옛 버전은 영원히 남겨요 — 롤백은 옛 ID를 run하는 것뿐이에요.

경계는 신뢰예요

크리에이티브 모드 파일 머리 원문: “Treat a session on this preset as shell access”. 모델이 쓴 JS가 살아 있는 런타임에 붙어 돌고, 샌드박스 안전망은 없어요. 방어선은 누가 이 preset을 쓸 수 있는지에 그려지고, 코드 자체는 울타리를 치지 않아요.

핵심 증거 · 파일 머리 경고와 가까운 층 가림

첫 증거는 크리에이티브 모드 YAML의 파일 머리예요. 앞 여덟 줄은 무엇인지: 표준 모드에 자기 지시 도구 세트. 뒤 네 줄은 신뢰 선언으로, “shell 권한으로 대하라”를 설정 파일 주석에 적어 두었어요:

apps/cli/config/agent-presets/cordis/agent.cordis.yml1–12행
# The `cordis` agent preset: the standard coding agent, plus the ability to
# read and write the runtime it is running in.
#
# It exists so a person can ask an agent to author another agent. Everything in
# `standard` is here unchanged; what is added is the self-referential Cordis
# toolset, a skill that teaches composition authoring, and a persona that says
# which of the two planes an edit belongs to.
#
# TRUST: `cordis_mount` evaluates model-written JavaScript against the live
# runtime, and a composition this agent writes becomes a preset other sessions
# mount. Treat a session on this preset as shell access — the toolset's own
# documentation makes the same statement.
소스 스냅샷 안내: 로컬 저장소 deepseek-harness-master 기준, 확인 파일 apps/cli/config/agent-presets/cordis/agent.cordis.yml, 확인일 2026-08-13. 코드 블록은 소스 원문을 유지합니다.

둘째 증거는 skill 레지스트리의 병합 읽기예요. 코드를 안 붙여도 말할 수 있어요. collectFresh는 모든 층을 한 줄로 세워요: 전역 층이 맨 앞, preset 스코프 체인은 먼 조상이 앞·본 층이 맨 뒤. 그다음 순서대로 각 층 항목을 같은 Map에 넣고, 키는 skill 이름이에요. Map은 나중에 쓴 값이 앞을 덮으니, 가까운 층 동명이 먼 층을 자동 교체해요. 가림은 Map.set 한 번이고, 계층 간 가중치 비교는 없어요. 함수 머리 주석은 이 규칙을 도구 레지스트리 가림 규칙과 맞추고, 정렬 가중치는 같은 층 안 동명에만 적용된다고 덧붙여요.

출처: packages/skill/skill/src/index.ts 552–566행의 collectFresh, 확인일 2026-08-13.

기억할 메커니즘이 둘 더 있어요. 출처는 여기. 첫째, 동적 플러그인이 도구 세트 모양을 중간에 바꾸면 세션 로그가 변경 후 전체 요청 헤더를 기록해 “모델이 보는 것 ⟺ 로그에 있는 것” 불변식을 지켜요(.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.zh.md). 둘째, persona는 Agent가 배포판 preset 디렉터리를 절대 편집하지 말라고 못 박아요. 업그레이드가 통째로 덮어쓰고, cordis preset을 망가뜨리면 자기가 서 있는 모드를 끄는 셈이에요 — 고치려면 복사본을 만들어 고치세요(cordis/agent.cordis.yml 27행).

가로 비교 · 설정 한 장으로 역할을 적기 vs 플러그인 조합 한 덩어리로 역할 만들기

Claude Code는 frontmatter 있는 markdown 한 장으로 역할을 정의해요: description, 사용 가능 도구, model을 적고, AgentTool 호출 인자로 frontmatter의 model 필드를 임시 덮을 수도 있어요(원고 study/chapters/05-multi-agent.md 32–38행이 AgentTool.tsx inputSchema를 인용). Skills도 같아요: 디렉터리 하나에 SKILL.md 한 장. 이 길은 “설정이 역할을 기술한다”예요. 역할이 달라질 수 있는 축은 프레임워크가 frontmatter에 열어 둔 필드에 달려 있어요.

DSH preset은 “플러그인 조합 한 덩어리가 역할”이에요. persona는 조합 속 평범한 플러그인 한 줄이고, 도구·압축 전략·subagent 백엔드와 동급이에요. 미니멀 모드는 파일시스템 구현 전체를 바꾸고 압축을 끌 수도 있어요 — frontmatter 필드로는 못 담는 깊이예요. 대가도 직설이에요. preset을 쓰려면 두 평면과 isolate realm을 알아야 해서 markdown보다 문턱이 훨씬 높아요. 그래서 크리에이티브 모드가 수업 skill을 들고 다니고, 런타임을 읽는 cordis_inspect_query를 붙여요. 한쪽은 낮은 문턱의 역할 카드, 한쪽은 풀파워 조합 언어 — 누가 역할을 쓰는지에 대해 두 집은 생각이 많이 달라요.

수업 실습
01

경계 시나리오 둘을 추론해 보세요

첫째: 크리에이티브 모드 Agent가 잠깐 헷갈려 배포판 cordis/agent.cordis.yml을 직접 고치다 망가뜨리면, 다음에 크리에이티브 모드를 쓰려는 세션에는 무슨 일이 생길까요? persona 27행이 왜 “복사본을 만들어 고치라”를 철칙으로 쓰나요? 둘째: 다섯 번째 모드를 직접 조립할 때, 두 preset이 모두 게시하고 싶은 동명 서비스 줄을 각 파일에 남겨 두고 둘 다 isolate realm에 안 싸면, 두 세션이 동시에 마운트되면 어떻게 될까요? 힌트: 미니멀 모드가 realm으로 fs를 가리는 방식을 다시 보세요.

Takeaway: 모드 = YAML 한 장이 적은 플러그인 조합, 자기 수정 = 런타임에 그 조합에 줄을 더하거나 빼는 것. define는 기록만, run이 활성화, 실패해도 포인터는 그대로 — 세 규율이 “Agent가 Agent를 쓰는” 일에 후회할 여지를 남겨요. 안전은 샌드박스가 아니라 신뢰 경계예요. 누구에게 크리에이티브 모드를 열어 주는지는 누구에게 shell을 열어 주는 것과 같아요.