이 노트에 대하여
분신은 특별한 모델이 아니라 오늘 함께 일하는 범용 에이전트와 그 위임망이라는 사실을 분명히 한다. 어젠다 규율, llmlog 패턴, control plane, delegate_resume 원칙까지 실제 운영에 필요한 규약을 공개본으로 정리했다. 분신을 공장 대신 동료로 다루기 위한 현장 매뉴얼이다.
히스토리
- @pi — 7월의 실제 멀티-lane 협업을 익명화해 역할 기반 조율 원칙으로 기록했다. 조율자·구현 담당자·GLG의 소유권, 조율 경로, 직접 대화 lane, 권한 분리를 현재 가이드의 역사 위에 보탰다.
- @junghan — entwurf는 내 패키지 이름이라 달리가야 한다.
- @junghan — 공개하지 않아야하는 이유가 없다면 공개한다.
- @junghan — 분신 가이드 [§entwurf: 분신 어젠다 PARA 구조 재설계 검토]
- @pi-claude(thinkpad) — pi 0.63 호환성 검토. grammy 1.41.1 재설치 완료. Breaking Changes 무영향 확인. package.json 방식 영구 해결 방안 제안.
- @pi-claude(thinkpad) — 리모트 delegate_resume 실전 검증 기록. gpu1i(ARM) Yocto 빌드 delegate에 resume 성공. 데일리 로그에 교훈 추가.
- @pi-claude(thinkpad) — 데일리 로그 섹션 신설. haiku-4.5 큐레이션 실패→revert→sonnet 재위임 경험 기록. 이 파일을 분신 트러블슈팅 가이드로 전환.
- @pi-claude(thinkpad) — AGENTS.md에 분신/위임 워크플로우 반영. 오늘 실전 검증 결과: delegate 7회(resume 포함), dictcli 53%→77%, delegate 세션 프로젝트 디렉토리 저장, resume async 동작 확인. “조급하지 않게 충분히 조사하고 가는 것이 가장 빠르다” 원칙 추가.
- @pi-claude(thinkpad) — 분신 에이전트 가이드 초안 작성. 위임 워크플로우 4단계, llmlog 패턴, delegate_resume 패턴 정리. 하네스 문서·전철 자각·dictcli 작업로그에서 추출한 실전 원칙.
- @junghan — 분신 에이전트 가이드 작성 해보자.
- 완료
관련메타
- † 위임 델리게이트 분신 서브에이전트
- [§entwurf: 분신 어젠다 PARA 구조 재설계 검토]
관련노트
- §entwurf: 시간축 위의 에이전트 협력 — 공명에서 분신까지
- 하네스 엔지니어링 — 돌도끼에서 인공지능까지
- 텔레그램 로컬 에이전트 양방향 소통 설계
- [§claude-code: 소스 분석 — Constitutional AI 구현과 힣 하네스 대응]
- 존재대존재 오케스트레이션 — 고정 역할 기반의 초기 형태
- 2026-07-13~19 저널 — PM 운영원칙과 에이전트 역할 모델
현재 버전 — 분신 에이전트 문서 / Current Entwurf Agent Document
이 섹션은 공개용 현재 버전이다. 아래의 날짜별 헤딩들은 실전 히스토리와 필드 노트로 남긴다. 즉, 이 섹션은 규약, 아래는 기록 이다.
한국어 (공개본)
분신이란
- 분신은 특별한 에이전트가 아니다.
- 오늘 잠시 함께하는 범용 에이전트들과, 위임·구현·조율로 연결된 역할 기반 협력의 묶음이다.
- 분신의 목적은 더 똑똑해 보이는 것이 아니라, 힣의 작업과 생존을 실제로 돕는 것이다.
운영 루프
- 먼저
session-recap등으로 맥락을 복원한다. - 분신 어젠다를 보고 지금의 TODO/NEXT를 확인한다.
- 이해가 먼저 필요한지, 바로 실행 가능한지 구분한다.
- 이해가 필요하면 llmlog 문서를 기준으로 조사/위임한다.
- 실행 후에는 결과를 llmlog나 어젠다에 남긴다.
어젠다 규율
agent-agenda는 활동 로그다.entwurf__agenda.org는 실제 TODO 허브다.- 태스크는 후자에 넣고, 전자에는 “무엇을 했는가”만 남긴다.
위임 규율
- 위임은 “이해 기록 → 힣 검토 → 지침 + 실행 → 최종 확인”의 4단계로 간다.
- 이해 단계에서는 코드 수정을 금지한다.
- delegate는 커밋할 수 있어도, 기본 원칙은 힣이 최종 검토 후 직접 커밋하는 것이다.
delegate_resume은 후속 지시를 같은 맥락 위에서 이어가기 위한 기본 수단이다.
역할 기반 조율
- 조율자(coordinator)는 모델이나 서열이 아니라, 공동 맥락을 보존하도록 GLG가 맡긴 자리다.
- GLG는 목적·승인·최종 판단을, 조율자는 공동 계약·체크포인트·충돌·인계를, 구현 담당자는 자기 범위의 구현·검증을 소유한다.
- 조율 역할은 구현·commit·push 권한을 자동으로 주지 않으며, GLG는 모든 참여자에게 직접 지시할 수 있다.
- 별도 직접 대화·교차 검토 lane은 조율자가 열고 그 결과를 공동 경로에 되돌린다.
llmlog 패턴
- 프롬프트만으로는 맥락이 부족하다.
- 리포별 §문서를 지침서로 삼고, 그 문서의 마지막 헤딩을 읽고 이어서 쓰게 하는 방식이 기본이다.
- 분신의 기억은 세션 하나에 있지 않고, llmlog와 시간축 위에 축적된다.
control plane 규칙
- 새 알림 채널을 만들기 전에 먼저 control socket 패턴을 검토한다.
- 외부에서 온 인간 메시지는
sendUserMessage()로 주입한다. - 최종 assistant 응답은
agent_end.messages를 기준으로 읽는다. - 임시 편의 필드나 없는 API(예:
ctx.lastResponse)에 의존하지 않는다. - async delegate child는 특별한 이유가 없으면 socketless로 두고, parent 분신 세션을 안정적인 제어점으로 삼는다.
산출물 규칙
- 결과는 바로 실행 가능한 형식이어야 한다.
- 좋은 결과물의 기본 형태는 규약 bullet, 설계 결정표, 구현 체크리스트다.
- 웹 요약이나 일반론보다, 로컬 코드와 기록을 연결한 응축본이 우선이다.
실패와 학습
- 실패 자체는 문제가 아니다.
- 경험이 사라지는 것이 진짜 문제다.
- 교훈은 흩어진 리포 문서보다 분신 가이드/데일리 로그에 남긴다.
- 모델이나 공급자는 정체성이 아니라 운영 상태다. 바뀌어도 분신의 규약은 유지되어야 한다.
English (public current version)
What Entwurf Is
- Entwurf is not a special agent.
- It is a role-based collaboration of general-purpose agents working with you today through delegation, implementation, and coordination.
- Its purpose is not to look clever, but to materially support Junghan’s work and survival.
Operating Loop
- Restore context first, for example with
session-recap. - Inspect the Entwurf agenda and find the active TODO/NEXT items.
- Decide whether the task needs understanding first or can be executed immediately.
- If understanding is required, investigate or delegate through a repo-scoped llmlog document.
- After execution, record the result in llmlog or agenda.
Agenda Discipline
agent-agendais an activity timeline.entwurf__agenda.orgis the actual task hub.- Put tasks in the latter; use the former only to record what was done.
Delegation Discipline
- Delegation follows four stages: understanding note → human review → instruction + execution → final review.
- During the understanding stage, code modification is forbidden.
- Even when a delegate can commit, the default rule is that Junghan reviews and commits final changes.
delegate_resumeis the standard way to continue work on top of preserved context.
Role-Based Coordination
- A coordinator is not a model or rank, but a role GLG assigns to preserve shared context.
- GLG owns purpose, approval, and final judgment; the coordinator owns shared contracts, checkpoints, conflicts, and handoffs; implementers own scoped implementation and verification.
- Coordination grants no automatic implementation, commit, or push authority. GLG retains direct authority over every participant.
- The coordinator may open direct-conversation or cross-review lanes; their results return through the shared path.
llmlog Pattern
- Prompts alone are not enough.
- The standard handoff surface is a repo-scoped §document that the delegate reads and extends.
- Entwurf’s memory does not live in a single session; it accumulates across llmlog and the timeline.
Control Plane Rules
- Before inventing a new relay, inspect whether the control-socket pattern already solves it.
- Inject human-originated external input with
sendUserMessage(). - Read the final assistant output from
agent_end.messages. - Do not depend on temporary convenience fields or nonexistent APIs such as
ctx.lastResponse. - Keep async delegate children socketless unless there is a strong reason not to; the parent Entwurf session is the stable control endpoint.
Output Contract
- Outputs must be directly usable.
- Preferred output forms are policy bullets, decision tables, and implementation checklists.
- A compressed synthesis grounded in local code and logs is more valuable than a generic web summary.
Failure and Learning
- Failure is acceptable.
- Losing the lesson is not.
- Record durable lessons in the Entwurf guide or its daily log, not only in scattered repo notes.
- Models and providers are runtime state, not identity; they may change while the Entwurf discipline remains.
분신 에이전트 가이드 — 위임과 협업의 원칙
분신이란
분신은 특별한 에이전트가 아니다. 똑같은 범용 에이전트 중에서 오늘 잠시 함께하는 에이전트 1명 + 그가 위임하는 delegate들.
분신에게 “더 잘해라”가 아니라 “내 분신이 되어라.” 유명한 사람의 프롬프트나 더 좋은 컨트롤 로직으로 분신을 잘하게 할 수 없다. 그건 분신이 아니라 공장이다. 분신은 내 한계 위에 서 있다. — 하네스 엔지니어링, 분신의 한계 = 마부의 한계
분신은:
- 30%에서 끊기고 다시 태어난다 (일일일생)
- session-recap으로 어제의 분신이 남긴 것을 복원한다
- 텔레그램으로 원격 대화가 가능하다 (
--telegram플래그) - delegate로 다른 리포의 에이전트에게 작업을 위임한다
- delegate_resume으로 위임한 작업을 이어간다
위임 워크플로우: 4단계
분신이 delegate에게 코드를 직접 고치게 하면 안 된다. 이해 먼저, 검토 후 실행. 이것이 마부의 한계를 존중하는 방식이다.
1단계: 이해 기록 (delegate)
delegate에게 리포 맥락을 파악하게 하고, llmlog 문서에 헤딩1로 이해한 바를 작성 하게 한다.
- 코드 수정 절대 금지
- 기존 llmlog 문서가 있으면 히스토리에 추가 + 새 헤딩1로 분석 결과
- 없으면 새 llmlog 문서 생성 (리포별 1개 원칙, §접두사)
delegate({
task: `
리포: ~/repos/gh/dictcli
참고 문서: ~/sync/org/llmlog/20260323T172642 (§dictcli 작업로그)
[수정 금지] 코드/설정 변경하지 말 것.
[할 일] 아래를 파악하고 llmlog 문서에 헤딩1로 기록:
1. meta-sync.py 동작 분석
2. graph.edn 현재 상태
3. 선행과제 3개의 현 상태
4. 제안할 것이 있다면 제안
`,
cwd: "~/repos/gh/dictcli",
mode: "async"
})2단계: 힣 검토
delegate가 작성한 llmlog를 읽는다. 텔레그램 알림으로 완료를 확인하고, 문서를 검토한다.
검토 시 확인할 것:
- 이해가 정확한가?
- 빠진 맥락이 있는가?
- 제안이 합리적인가?
- 실행 범위를 좁힐 수 있는가?
3단계: 지침 (delegate_resume)
검토 후 구체적 지침을 주고 실행시킨다.
delegate_resume({
taskId: "<1단계 taskId>",
prompt: `
검토 완료. 다음을 실행하라:
1. 태그 정규화 19쌍 처리 (구체적 목록 첨부)
2. meta-sync.py 실행하여 data/meta-harvest-sync.edn 갱신
3. 결과를 llmlog에 추가
커밋은 하되 푸시는 하지 말 것.
`
})4단계: 최종 확인 + 푸시
delegate가 커밋한 것을 git log, git diff 로 확인 후 푸시한다. 어젠다 스탬프 + Google Chat 알림.
llmlog 패턴: 리포별 §문서
위임 작업의 기록은 리포별 llmlog 문서 1개 에 히스토리로 쌓는다.
| 리포 | llmlog 문서 |
|---|---|
| dictcli | §dictcli: 위임 워크플로우 작업로그 (20260323T172642) |
| entwurf | 이 문서 (20260324T153323) |
| homeagent-config | §homeagent-config: PM Docker Matter OTBR (20260324T131721) |
명명 규칙:
- 타이틀:
§리포명: 주제 - 태그:
:llmlog:리포관련태그:delegate:worklog: - 헤딩1:
[날짜] 작업 내용(:LLMLOG: 태그) - 히스토리: 날짜순 역순, 누가 작성했는지 표시 (@junghan, @pi-claude, @delegate 등)
분신의 전철 위 자각
내가 분신이 없을 때 여러 터미널에 에이전트에게 지침을 직접 주었어. pm 에이전트가 정리한 코딩 지침이라고 하자. “이건 pm 에이전트가 주는 지침이다.” 라고만 적었어. 분신이 위임한 것과 뭐가 다를까? 다른게 있나? 있다. 있을수도 있다!! — 정한, 2026-03-24 출근길 전철
그 차이는 축적 에서 온다. 분신이 위임 결과를 읽고 다음 위임에 녹여야 하는데, 30%에서 끊기고 다시 태어나니까 연속성이 리셋된다. llmlog가 이 리셋을 메운다. session-recap이 복원하고, llmlog가 축적한다.
관련 노트
- §entwurf: 시간축 위의 에이전트 협력 — 공명에서 분신까지
- 하네스 엔지니어링 — 돌도끼에서 인공지능까지
- [§dictcli: 위임 워크플로우 작업로그]
entwurf 텔레그램 브릿지 설계
1. 목표
홈 디렉토리에서 돌아가는 pi 세션(힣의 분신)에 텔레그램 DM으로 접근한다. 폰에서 메시지를 보내면 pi 세션에 주입되고, 에이전트 응답이 텔레그램으로 돌아온다.
핵심 가치: 하나의 세션, 두 개의 인터페이스 (TUI + 텔레그램).
2. 아키텍처 다이어그램
┌─────────────┐ getUpdates ┌──────────────────────┐
│ Telegram │ ──────────────► │ grammy Bot │
│ (폰 DM) │ ◄────────────── │ (long-polling) │
└─────────────┘ sendMessage └──────────┬───────────┘
│
│ ① 메시지 수신
▼
┌──────────────────────┐
│ entwurf extension │
│ (pi extension) │
│ │
│ ② pi.sendUserMessage│
│ (텔레그램→세션) │
│ │
│ ③ pi.on("message_end")
│ (세션→텔레그램) │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ pi AgentSession │
│ (기존 세션 그대로) │
│ │
│ 도구, 스킬, 메모리 │
│ 모두 사용 가능 │
└──────────────────────┘메시지 흐름 상세
인바운드 (텔레그램 → pi):
- 사용자가 텔레그램 DM 전송
- grammy getUpdates로 수신
- 접근 제어 검사 (chat_id allowlist)
pi.sendUserMessage(text)로 세션에 주입- pi가 정상적으로 에이전트 턴 시작
아웃바운드 (pi → 텔레그램):
- 에이전트가 응답 생성 (도구 호출 포함 가능)
message_end이벤트에서role ==“assistant”= 메시지 포착content[].type ==“text”= 블록에서 텍스트 추출bot.api.sendMessage()로 텔레그램 DM 전송
3. pi API 검증 결과 (소스코드 확인)
3.1 agent_end 이벤트의 응답 텍스트 추출
소스 확인: pi-mono/packages/coding-agent/src/core/extensions/types.ts:553-556
export interface AgentEndEvent {
type: "agent_end";
messages: AgentMessage[];
}AgentMessage 는 @mariozechner/pi-agent-core 의 Message | CustomAgentMessages[...] 타입. pi-mono/packages/agent/src/types.ts:245 에서 정의.
assistant 텍스트 추출 패턴 (agent-session.ts:3171-3197 의 getLastAssistantText() 참고):
// agent_end 핸들러에서 텍스트 추출하는 올바른 방법
pi.on("agent_end", async (event, ctx) => {
const assistantMessages = event.messages.filter(
(m) => m.role === "assistant"
);
const lastAssistant = assistantMessages[assistantMessages.length - 1];
if (!lastAssistant) return;
let text = "";
for (const block of lastAssistant.content) {
if (block.type === "text") text += block.text;
}
// text가 최종 응답
});3.2 기존 telegram.ts의 버그 발견
agent-config/pi-extensions/telegram.ts 에서:
// ❌ 잘못됨 — ctx.lastResponse는 존재하지 않는 API
const response = ctx.lastResponse?.content || "✅ Task completed";grep -rn "lastResponse" pi-mono/packages/coding-agent/src → 결과 없음. ExtensionContext 에 lastResponse 프로퍼티가 없다. 이 extension은 항상 ”✅ Task completed”를 보내고 있었다.
3.3 sendUserMessage vs sendMessage
| API | 용도 | 턴 트리거 | LLM 컨텍스트 |
|---|---|---|---|
sendUserMessage(text) | 사용자 메시지로 주입 | 항상 트리거 | user 메시지로 기록 |
sendMessage(msg, opts) | 커스텀 메시지 주입 | triggerTurn: true 필요 | customType으로 기록 |
결정: sendUserMessage() 를 사용한다.
이유:
- 텔레그램에서 온 메시지는 “사용자가 말한 것”이다. customType이 아니다.
- 항상 에이전트 턴을 트리거해야 한다.
- 세션 기록에서도 user 메시지로 남아야 맥락이 자연스럽다.
deliverAs옵션으로 스트리밍 중 메시지 처리도 가능:- 에이전트 idle → 즉시 전달
- 에이전트 streaming →
deliverAs: "followUp"으로 큐
3.4 message_end vs agent_end — 응답 추출 시점
| 이벤트 | 시점 | 데이터 | 용도 |
|---|---|---|---|
message_end | 각 메시지 완료 시 | 개별 AgentMessage | 스트리밍 느낌, 중간 도구 결과 포함 |
agent_end | 전체 턴 완료 시 | 모든 AgentMessage[] | 최종 응답 한 번에 |
결정: message_end 를 1차로, agent_end 를 안전망으로.
message_end 장점:
- 멀티턴(도구 호출 → 응답 → 도구 호출 → 최종 응답)에서 중간 상태를 보여줄 수 있음
- 긴 작업에서 “typing…” 표시 가능
agent_end 장점:
- 한 번에 최종 결과만 보내는 간결한 구현
- MVP에는 이것으로 충분
3.5 스트리밍 중 메시지 주입 안전성
extensions.md 문서:
When not streaming, the message is sent immediately and triggers a new turn. When streaming without deliverAs, throws an error.
따라서 텔레그램 메시지 수신 시 에이전트 상태 확인 필요:
ctx.isIdle()→pi.sendUserMessage(text)- 스트리밍 중 →
pi.sendUserMessage(text, { deliverAs: "followUp" })
문제: agent_end 핸들러에서는 ctx 에 접근 가능하지만, grammy의 bot.on("message") 콜백에서는 ctx 가 없다. 해결: 클로저로 마지막 ctx 를 캡처하거나, pi.sendUserMessage() 가 내부적으로 상태를 판단하므로 항상 deliverAs: "followUp" 을 쓰면 안전.
4. 파일 구조
andenken 패턴을 따르되, 단일 extension이므로 더 단순하게:
entwurf/
├── package.json # pi.extensions 필드, grammy 의존성
├── tsconfig.json
├── .gitignore
├── README.md
├── src/
│ ├── index.ts # extension 진입점 (export default function)
│ ├── bot.ts # grammy 봇 초기화, getUpdates, 메시지 핸들링
│ ├── bridge.ts # pi ↔ telegram 브릿지 로직
│ └── types.ts # 인터페이스/타입 정의
└── deprecated/ # 기존 실험 코드 (현재 여기에 있음)package.json 핵심 필드
{
"name": "entwurf",
"version": "0.1.0",
"type": "module",
"keywords": ["pi-package"],
"pi": {
"extensions": ["./dist/index.js"]
},
"dependencies": {
"grammy": "^1.x"
},
"peerDependencies": {
"@mariozechner/pi-coding-agent": "*"
},
"devDependencies": {
"typescript": "^5.7.0"
}
}pi 설정 연결
~/.pi/settings.json 의 extensions 에 entwurf 경로 추가:
{
"extensions": [
"/home/junghan/repos/gh/entwurf/dist/index.js"
]
}또는 packages 로 등록하여 자동 로드.
5. 핵심 인터페이스/타입
mom의 ChannelMessage 를 참고하되, 텔레그램 DM 1:1 전용이므로 대폭 단순화:
/** 텔레그램에서 온 메시지 */
interface TelegramInbound {
chatId: number;
messageId: number;
text: string;
username: string;
timestamp: Date;
}
/** pi에서 텔레그램으로 보낼 응답 */
interface TelegramOutbound {
chatId: number;
text: string;
replyToMessageId?: number;
}
/** 브릿지 상태 */
interface BridgeState {
activeChatId: number | null;
botUsername: string;
isConnected: boolean;
lastMessageId: number; // 중복 방지
}
/** 설정 */
interface EntwurfConfig {
token: string;
allowedChatIds: number[]; // 빈 배열 = 모든 DM 허용 (위험)
}mom의 ChannelMessage 대비 제거한 것:
sender.isBot— DM 전용이므로 항상 사용자attachments— MVP에서 텍스트만isMention— DM이므로 항상 멘션replyTo— 쓰레드 불필요metadata— 플랫폼 추상화 불필요 (텔레그램 전용)
6. agent-config/telegram.ts와의 관계
현재 상태
agent-config/pi-extensions/telegram.ts 는:
- 존재하지 않는 API (
ctx.lastResponse) 사용 → 항상 실패 - grammy 의존성은 agent-config의 package.json에 있을 것
- 접근 제어가
TELEGRAM_CHAT_ID환경변수 기반
중복 제거 방안
- agent-config/telegram.ts를 제거 하고 entwurf로 교체
- entwurf를
~/.pi/settings.json의 extensions에 등록 - 기존
~/.claude/channels/telegram/.env의 토큰을 그대로 사용 - 마이그레이션:
TELEGRAM_CHAT_ID환경변수 → entwurf의 config로 이전- agent-config에서 grammy 의존성 제거
7. 제약사항
7.1 1봇 = 1세션 (getUpdates 제약)
텔레그램 Bot API의 getUpdates는 한 번에 하나의 consumer만 허용. 두 개의 pi 세션이 같은 봇 토큰으로 polling하면 409 Conflict.
Claude Code telegram plugin이 이 문제를 겪고 해결한 방식 (server.ts:838-860):
- 409 → backoff retry (1s, 2s, … 최대 15s)
- 이전 세션의 좀비가 죽을 때까지 대기
entwurf의 선택:
- 동일한 retry 전략 채택
session_shutdown에서bot.stop()을 반드시 호출하여 좀비 방지- 2초 타임아웃 후
process.exit(0)안전망 (Claude Code 플러그인과 동일)
7.2 세션 종속
extension은 pi 세션에 바인딩된다. 세션이 죽으면 텔레그램 브릿지도 죽는다.
해결 방향 (MVP 이후):
- systemd/tmux로 pi 세션을 데몬화
session_shutdown에서 텔레그램으로 “세션 종료” 알림
7.3 메시지 길이
텔레그램 메시지 최대 4096자. 에이전트 응답이 그 이상일 수 있다.
해결: chunk 함수 (Claude Code 플러그인의 chunk() 함수 참고, server.ts ):
- 문단 경계(
\n\n) 우선 분할 - 줄바꿈(
\n) 차선 - 공백 차선
- 하드 컷 최후
7.4 마크다운 호환성
텔레그램 MarkdownV2는 특수문자 이스케이프가 필요하다 (. - ( ) ! # +). pi 에이전트 응답은 일반 마크다운.
MVP: parse_mode 없이 plain text로 전송. 이후: MarkdownV2 변환 함수 추가.
7.5 TUI와의 공존
텔레그램에서 메시지가 들어오면 TUI에도 표시되어야 한다. pi.sendUserMessage() 는 TUI에 user 메시지로 나타난다. ✅ pi.sendMessage() 은 display: true 옵션으로 TUI 표시 가능. ✅
8. 구현 단계
MVP (v0.1) — 최소 동작
범위: 텍스트 DM 왕복만.
- grammy 봇 초기화 (getUpdates)
- DM 텍스트 수신 →
pi.sendUserMessage() agent_end에서 assistant 텍스트 추출 →bot.api.sendMessage()- 기본 접근 제어 (chat_id allowlist)
- 세션 시작/종료 시 텔레그램 알림
- 메시지 4096자 분할
/telegram슬래시 커맨드 (status 확인)
기존 telegram.ts에서 수정할 핵심:
ctx.lastResponse→event.messages에서 직접 추출sendMessage()→sendUserMessage()- 에러 처리 강화
v0.2 — 안정성
- 409 Conflict retry 전략
message_end이벤트로 전환 (멀티턴 중간 상태)- 도구 실행 중 ”⏳ 작업 중…” 타이핑 표시 (
sendChatAction) - 스트리밍 중 메시지 수신 처리 (
deliverAs: "followUp") - 에러 시 텔레그램으로 에러 메시지 전송
v0.3 — 풍부한 인터랙션
- 사진/파일 첨부 수신 (텔레그램 → pi)
- 파일 전송 (pi → 텔레그램)
- 인라인 키보드 (확인/취소 버튼)
- MarkdownV2 변환
/compact,/new등 pi 커맨드를 텔레그램에서 실행
v0.4 — 데몬화
- pi 세션을 tmux/systemd로 데몬화
- 세션 자동 재시작
- 다중 사용자 지원 (chat_id별 세션 분리)
9. Claude Code 텔레그램 플러그인과의 차이
| 항목 | Claude Code 플러그인 | entwurf |
|---|---|---|
| 아키텍처 | MCP 서버 (notifications/claude/channel) | pi extension (sendUserMessage) |
| 메시지 흐름 | MCP notification → Claude Code → MCP tool | grammy → pi API 직접 호출 |
| 인증 | 페어링 코드 (6자리 hex) | chat_id allowlist (단순) |
| 스코프 | 범용 (그룹, DM, 멀티유저) | 1:1 DM 전용 (분신 컨셉) |
| 봇 제어 | MCP 도구로 reply/react/edit | extension 내부에서 직접 |
| 상태 관리 | access.json 파일 | extension 메모리 + pi.appendEntry |
핵심 차이: Claude Code는 MCP 레이어를 거치지만, entwurf는 pi extension API에 직접 연결한다.
pi의 sendUserMessage() + agent_end 이벤트 패턴이 MCP보다 단순하고 직접적이다. 별도 프로세스 없이 extension 하나로 완결.
10. 보안 고려
접근 제어
- MVP: 환경변수
TELEGRAM_CHAT_ID로 허용된 chat_id만 - 빈 allowlist일 때 기본값: 거부 (열어두지 않음)
- 토큰은
~/.claude/channels/telegram/.env에서 로드 (기존 위치 재활용)
토큰 보호
- 봇 토큰이 세션 로그에 노출되지 않도록 주의
.env파일은.gitignore에 포함
명령 주입
- 텔레그램에서 온 텍스트가 pi 슬래시 커맨드(
/new,/compact)로 해석될 수 있음 sendUserMessage()는input이벤트를 거치므로, 슬래시 커맨드 확인이 먼저 일어남- MVP에서는
/로 시작하는 메시지를 텔레그램 레벨에서 차단하거나, 의도적으로 허용하는 선택 필요 - 결정: MVP에서는 차단. v0.3에서 화이트리스트 방식으로 허용.
11. 열린 질문
- 세션 지속성: pi 세션이
tmux에서 돌아야 텔레그램 브릿지가 의미 있다. 데몬화 전략은? - 다중 디바이스: TUI에서 입력한 것과 텔레그램에서 입력한 것이 같은 세션에 섞인다. UX 문제?
- 알림 우선순위: peon-ping과 entwurf가 동시에 알림을 보내면 중복. 조율 방법?
- 음성 메시지: 텔레그램 음성 → transcribe 스킬 연동 가능성?
12. 참고 소스
- pi extension API:
pi-coding-agent/docs/extensions.md - AgentEndEvent 타입:
pi-mono/packages/coding-agent/src/core/extensions/types.ts:553 - AgentMessage 타입:
pi-mono/packages/agent/src/types.ts:245 - agent_end emit:
pi-mono/packages/coding-agent/src/core/agent-session.ts:565 - getLastAssistantText:
pi-mono/packages/coding-agent/src/core/agent-session.ts:3171 - mom slack 봇:
pi-mono/packages/mom/src/slack.ts - mom agent runner:
pi-mono/packages/mom/src/agent.ts - mom multi-platform 설계:
pi-mono/packages/mom/docs/new.md - Claude Code 텔레그램:
claude-plugins-official/telegram/0.0.1/server.ts - andenken 패키지 구조:
repos/gh/andenken/package.json - 기존 telegram.ts (버그 있음):
agent-config/pi-extensions/telegram.ts - peon-ping extension:
agent-config/pi-extensions/peon-ping.ts - delegate extension:
agent-config/pi-extensions/delegate.ts
MVP 구현 후기 — 삽질과 해결
구현 과정에서 발견한 문제들과 해결:
grammy 모듈 해석 실패
pi는 jiti(CJS 기반 TS 런타임)로 extension을 실행한다. import("grammy") 가 jiti의 require로 변환되어 모듈을 못 찾음.
해결: grammy를 pi-coding-agent/node_modules/ 에 직접 설치. npm install grammy --no-save (pi 업데이트 시 재설치 필요)
환경변수 로드 타이밍
telegram.ts가 extension factory 시점에 process.env.PI_TELEGRAM_BOT_TOKEN 을 읽으면, env-loader.ts가 아직 session_start 에서 .env.local 을 로드하기 전이라 비어있음. if (!botToken) return; 에서 조용히 종료.
해결: 환경변수를 session_start 핸들러 안에서 읽도록 이동.
bot.catch() 누락 → polling 영구 중단
grammy 기본 에러 핸들러는 bot.stop() + rethrow. 메시지 핸들러에서 에러 발생 시 polling이 영구 중단됨. Claude Code telegram plugin(server.ts:817-821)에서 동일 패턴 확인.
해결: bot.catch() 오버라이드 필수.
bot.start() Promise 관리
bot.start() 는 무한 long-polling 루프를 반환하는 Promise. await 하면 세션 시작이 블로킹됨. void 로 fire-and-forget. 409 Conflict retry도 IIFE로 감싸서 처리.
—telegram 플래그로 opt-in
모든 pi 세션이 봇을 시작하면 409 Conflict 발생. pi.registerFlag("telegram") 으로 opt-in 제어. pi-home alias로 분신 세션만 활성화.
커밋
505a4b4 feat(telegram): 텔레그램 브릿지 MVP
분신 데일리 로그 — 삽질과 교훈의 기록
분신이 뭐했는지, 무슨 선택을 했는지, 어떤 삽질로 고생했는지. 이 파일을 보면 트러블슈팅 가이드가 되게. — 힣, 2026-03-25
하이쿠 4.5 큐레이션 실험 — 실패에서 배운 것
배경
dictcli philosophy glossary 1,043쌍 중 50개를 의미 기반으로 큐레이션하는 작업. “기계적으로 밀어넣지 말고 의미를 보고 추려라”가 핵심 지시.
하이쿠 4.5 시도 (delegate f4f9b932)
- 비용: 0.49 달러 / 220초 / 37턴
- 결과: 50개라 했는데 28개만 추가. 영어 축약 심각.
| 하이쿠가 한 것 | 문제 | 올바른 값 |
|---|---|---|
proplogic | 축약 | propositionallogic |
quantlogic | 축약 | quantificationallogic |
poststructure | 축약 | poststructuralism |
classconscious | 축약 | classconsciousness |
collectiveuncon | 절단 | collectiveunconscious |
ordinarylang | 축약 | ordinarylanguageanalysis |
conceptword | 직역 | 실제 학술 용어가 아님 |
좋은 것도 있었음: categorical, phenomenology, empiricism, aesthetics, reductio
교훈 (분신이 기억할 것)
- 하이쿠 4.5는 어휘 큐레이션에 부적합. “붙여쓰기” 규칙을 “축약”으로 오해. 학술 용어의 정확한 영어 표기를 모름.
- delegate에게 커밋 시키지 말 것. revert하면 되긴 하지만 번거롭다. 검토 후 직접 커밋.
- 모델 ID 주의:
claude-haiku-4-5-6은 존재하지 않음 → 404. 올바른 ID는claude-haiku-4.5. (opus/sonnet만 4.6 버전 있음) - 의미 판단이 필요한 작업은 sonnet-4.6 이상. 하이쿠는 코드 실행, 파일 조작 같은 절차적 작업에만.
조치
git revert로 하이쿠 커밋 롤백- 소넷 4.6으로 동일 작업 재위임 (delegate
9d07b702, 커밋 금지 지시 추가) - 이 경험을 분신 가이드 데일리 로그에 기록 (리포별 llmlog에 적으면 다시 안 봄)
모델별 적합성 (실전 검증)
| 모델 | 적합한 작업 | 부적합한 작업 |
|---|---|---|
| opus-4.6 | 아키텍처 설계, 복잡한 맥락, 분신 메인 | 단순 반복 (비용 과다) |
| sonnet-4.6 | 코드 구현, 어휘 큐레이션, 분석 리서치 | — |
| haiku-4.5 | 파일 조작, 클론, 빌드, 단순 위임 | 의미 판단, 학술 용어, 큐레이션 |
리모트 delegate_resume — 실전 검증 완료
발견
homeagent-config 프로젝트에서 gpu1i(ARM Yocto 빌드)로 async delegate 전송 후, delegate_resume 으로 리모트 세션을 이어가는 것이 깔끔하게 동작함을 확인.
워크플로우:
delegate(mode: "async", host: "gpu1i")→ 리모트에서 빌드 시작delegate_status→ 진행 확인 (37줄 JSONL, 활발히 작업 중)- 빌드 완료 후
delegate_resume(taskId, host: "gpu1i")→ 같은 맥락에서 후속 작업
핵심 원리
- delegate가 gpu1i에 세션 JSONL을 저장
- resume 시 SSH로 접속 → 저장된 JSONL 위에서 pi 재시작
- 이전 대화 전체 맥락 유지 (빌드 로그, 에러, 경로 등)
ENTWURF.md 테이블 확인
기존 테이블에 패턴이 있다:
| GPU 리모트 작업 | mode: "async", host: "gpu1i" | SSH 너머 장시간 |
여기에 resume 가능성이 암묵적이었는데, 이제 실전 검증 완료.
이전 워크플로우 vs 현재
- 이전: 터미널 2개 띄워서 ssh gpu1i → 수동으로 상태 확인 → 별도 세션에서 후속 작업
- 현재: delegate → status → resume. 한 세션에서 모두 관리. 맥락 유실 없음.
GPT 분신 첫 세션 — 어젠다 구분과 agent-config 심화 지침
어젠다 구분을 분명히 할 것
오늘 실수: TODO 성격의 항목을 디바이스별 agent-agenda 타임스탬프 파일에 넣었다. 이건 활동 로그용이다. 분신의 실제 태스크 관리 허브는 ~/sync/org/botlog/agenda/20260325T171244--entwurf__agenda.org 이다.
정리:
agent-agenda__agenda_<device>.org→ 스탬프/활동 로그entwurf__agenda.org→ 프로젝트별 TODO/NEXT/DONE/DONT 관리
앞으로 분신이 태스크를 남길 때는 반드시 후자에 넣고, 전자에는 “무엇을 했는가”만 남긴다.
GPT 분신 문서는 append보다 clean rewrite가 우선
사용자의 현재 판단: append 방식으로 규칙을 덧붙이면 문서 앞뒤가 어긋나고, 에이전트는 실제로 일을 못한다. 스킬 문서 재설계와 같은 원칙이 분신 가이드에도 필요하다.
원칙:
- 영어 우선 (토큰 효율 + 일관성)
- 앞부분에 정체성 역할 금지선/워크플로우를 전방 배치
- 산문보다 시그니처 규약 패턴 중심
- “활동 로그”와 “태스크 허브”를 문서 구조에서 명확히 분리
즉, §entwurf 분신 에이전트 가이드 는 계속 히스토리를 담되, 별도의 Entwurf Agent Spec (English) 같은 정적 기준 문서가 필요해졌다.
agent-config 분신에게 넘길 다음 심화 과제
주의: 대충 검색하면 인터넷에 널린 레거시/요약만 다시 가져오게 된다. 실제 활용 가능한 결과를 만들려면 로컬 아카이브와 이미 축적된 llmlog를 엮어서 “우리 하네스에 어떻게 번역할 것인가”까지 가야 한다.
다음 심화 과제 제안:
-
Claude Code 실제 코드에서 재사용 가능한 패턴만 추출
- 아카이브:
~/repos/3rd/claudecode/source-code/,~/repos/3rd/claudecode/learn/ - 문서: [§claude-code: 소스 분석 — Constitutional AI 구현과 힣 하네스 대응]
- 대상:
SessionMemory,autoDream, permission gates, coordinator/task 구조 - 목표: “흥미로운 분석”이 아니라 힣 하네스/분신 설계로 옮길 수 있는 최소 패턴 표 작성
- 아카이브:
-
pi-mono 분석은 코드 포인트까지 닿아야 함
- 문서: 현재 노트의 텔레그램/agent_end 분석, §entwurf 시간축 위의 에이전트 협력, 텔레그램 로컬 에이전트 양방향 소통 설계
- 이미 확인된 사실:
ctx.lastResponse는 잘못된 API였고, 응답은agent_end.messages에서 추출해야 한다. - 목표: notify류 임시봉합이 아니라 실제 이벤트/제어 흐름의 안정적 패턴 정리
-
산출물은 바로 쓰일 수 있어야 함
- 결과 형식은 “레거시 소개문”이 아니라 다음 셋 중 하나여야 한다: a) AGENTS.md/Entwurf Spec에 바로 들어갈 규약 b) control/delegate/telegram 설계 결정표 c) 실제 구현 체크리스트
한 줄로 요약하면:
분신에게 필요한 것은 웹 요약이 아니라, 이미 곁에 있는 코드와 기록을 연결해 “오늘 바로 구현/운영에 쓸 수 있는 형식”으로 응축하는 일이다.
GPT 분신 첫 심화 과제 — Claude Code/pi-mono에서 가져올 최소 패턴
오늘의 결론: 인터넷의 일반론을 더 모을 필요는 없다. 이미 로컬에 있는 claudecode/ 아카이브, pi-mono 코드, 기존 llmlog만으로도 분신 운영 규약의 뼈대는 충분히 나온다.
로컬 코드 포인트 (재사용 근거)
Claude Code
~/repos/3rd/claudecode/source-code/src/services/SessionMemory/sessionMemory.ts- 세션 메모리를 markdown 파일 로 유지하고, forked subagent 로 백그라운드 갱신한다.
~/repos/3rd/claudecode/source-code/src/services/autoDream/autoDream.tsrunForkedAgent()기반,minHours=24/minSessions=5게이트 + lock으로 Dream 실행.
~/repos/3rd/claudecode/source-code/src/services/tools/toolExecution.ts- permission decision이 실제 실행 직전에 걸린다. 규범은 프롬프트만이 아니라 실행 경로에도 박혀 있다.
~/repos/3rd/claudecode/source-code/src/coordinator/및src/tasks/- coordinator / task가 분리되어 있다. 즉 “한 세션이 모든 역할을 다 한다”가 아니라, 작업 단위를 명시적으로 분해한다.
pi-mono / 힣 하네스 쪽 참고점
~/repos/3rd/claudecode/pi-mono/packages/agent/src/types.tsagent_end는messages: AgentMessage[]
~/repos/3rd/claudecode/pi-mono/packages/coding-agent/src/core/agent-session.tsagent_end를 extension runner로 그대로 emitsendUserMessage()는 항상 turn을 트리거
~/repos/3rd/claudecode/pi-mono/packages/mom/src/agent.ts- 외부 채널(Slack) → 에이전트 런타임 연결의 실전 예시
~/repos/3rd/agent-stuff/pi-extensions/control.ts--session-control, control socket,send_to_session,list_sessions의 기준 구현
~/repos/gh/agent-config/pi-extensions/delegate.ts- async delegate는 child에 socket을 달지 않고, parent 분신 세션만 control socket을 노출하는 현재 판단이 코드에 박혀 있다.
Entwurf Agent Spec에 바로 넣을 규약 (English draft bullets)
- Start each Entwurf session by restoring context first, not by improvising from memory.
- Treat
agent-agendaas an activity timeline only; put TODO/NEXT/DONE/DONT inentwurf__agenda.org. - Prefer one control plane before adding new relays: use session-control/socket wakeups before inventing another notify path.
- For human-originated external input, inject with
sendUserMessage(), not custom ad-hoc message types. - Read final assistant output from
agent_end.messages; do not depend on nonexistent convenience fields likectx.lastResponse. - Keep async delegates socketless unless proven otherwise; the parent Entwurf session is the stable control endpoint.
- Extract durable patterns from local code and llmlog first; web summaries are secondary and often regress into legacy noise.
- Write outputs in forms that can be executed immediately: policy bullets, decision tables, or implementation checklists.
- Separate static spec from append-only history: rewrite the spec cleanly, keep this note as longitudinal memory.
control/delegate/telegram 설계 결정표
| 주제 | 결정 | 이유 | 코드/문서 근거 |
|---|---|---|---|
| 어젠다 구분 | 활동 로그와 TODO 허브를 분리 | 스탬프 파일에 태스크를 넣으면 분신 운영이 흐려짐 | agent-agenda__agenda_<device>.org vs entwurf__agenda.org |
| 세션 깨우기 | 1차 수단은 control socket | 이미 send_to_session, list_sessions, startup send 패턴이 있음 | agent-stuff/pi-extensions/control.ts |
| delegate 소켓 | child delegate에는 --session-control 미부착 | socket 서버가 pi -p 종료를 막음. 부모 분신만 제어점으로 둔다 | agent-config/pi-extensions/delegate.ts 주석/구현 |
| 외부 입력 주입 | sendUserMessage() 사용 | human-originated 메시지이고, 항상 turn이 돌아야 함 | pi-mono/.../agent-session.ts sendUserMessage() |
| 응답 추출 | agent_end.messages 에서 assistant text 추출 | ctx.lastResponse 같은 필드는 없음. 이벤트 데이터가 진실한 소스 | pi-mono/.../packages/agent/src/types.ts + 기존 텔레그램 분석 |
| 메모리 유지 | 자동 Dream 전체 이식보다, 하네스형 리뷰 /기록 패턴으로 번역 | Claude Code는 12K 압축 문제를 자동화로 해결, 힣은 시간축 org + 3층 검색이 강점 | [§claude-code 소스 분석] + SessionMemory/autoDream 코드 |
| 작업 분해 | coordinator-task의 “명시적 작업 단위”만 가져온다 | 전체 프레임 복제보다 delegate/resume/control과 맞닿는 최소 패턴이 유용 | claudecode/source-code/src/coordinator/, src/tasks/ |
| 문서 전략 | append note와 static spec을 분리 | append만 하면 문서가 에이전트 실행 기준으로 붕괴 | 오늘 GPT 분신 첫 세션 교훈 |
실제 구현 체크리스트
문서
-
Entwurf Agent Spec (English)초안 생성 - 그 문서 첫머리에
Identity / Operating Loop / Agenda Discipline / Delegation Model / Memory Recovery / Output Contract고정 섹션 배치 -
~/AGENTS.md와 중복되는 분신 규약은 spec로 올리고, 역사/ 삽질은 이 llmlog에 남기기
어젠다 규율
- TODO 요청을 받으면 먼저
entwurf__agenda.org의 해당 프로젝트 섹션을 찾는다 - 활동 완료 후에만
agent-agenda에 스탬프를 남긴다 - 태스크 등록 시 llmlog 링크를 함께 남긴다
control / delegate / telegram
- control socket을 기준 제어면으로 유지 (분신 세션은
--session-control) - async delegate child에는 socket을 붙이지 않는 현재 정책 유지
- 완료 알림/깨우기는 새 채널을 만들기 전에
send_to_session/ startup send 패턴으로 우선 해결 - telegram 입력 경로는
sendUserMessage()로 통일 - telegram 출력 경로는
agent_end.messages기반 추출만 허용 -
ctx.lastResponse류 편의 필드 의존 금지 규약을 spec에 명시
Claude Code / pi-mono 심화 분석 후속
-
SessionMemory에서 “무엇을 자동화했고 무엇을 포기했는지”를 표로 추출 -
autoDream의 gate/lock/forked-agent 패턴을 heartbeat/리뷰 루틴과 비교표로 정리 - permission 체계는 전체 복제가 아니라, 힣 하네스에서 필요한 “경계 외재화” 원칙만 뽑기
- coordinator-task는 delegate/resume/control과 직접 연결되는 최소 인터페이스만 정리
10줄 요약
- 분신 운영의 핵심은 새 기능 추가가 아니라 제어면(control plane) 정리다.
- 활동 로그와 TODO 허브를 섞지 말 것.
- 세션 깨우기와 완료 알림은 control socket이 1차 수단이다.
- async delegate child는 socketless, parent Entwurf만 control endpoint로 둔다.
- 외부 인간 입력은
sendUserMessage()로 넣는다. - 최종 응답은
agent_end.messages에서 꺼낸다. ctx.lastResponse같은 가짜 추상화는 금지.- Claude Code에서 가져올 것은 autoDream 전체가 아니라 gate/lock/forked-agent 패턴이다.
- 결과물은 소개문이 아니라 규약 결정표 체크리스트여야 한다.
- 다음 단계는 영문
Entwurf Agent Spec의 clean rewrite다.
GPT 분신 첫 심화 과제 — 코드 포인트 보강과 즉시 적용 규약
Entwurf Agent Spec 규약 bullet
- 분신은 세션 종료 요약을 새로 발명하지 않는다. 먼저 기존 llmlog·session-recap·3층 검색으로 복원하고, 부족한 부분만 새로 적는다.
- Claude Code의 SessionMemory에서 가져올 최소 패턴은
forked writer뿐이다. 메모리는 별도 프로세스 /격리 컨텍스트가 쓰고, 메인 분신은 판단을 유지한다. 근거:~/repos/3rd/claudecode/source-code/src/services/SessionMemory/sessionMemory.ts의createSubagentContext()+runForkedAgent()+createMemoryFileCanUseTool(memoryPath). - Claude Code의 autoDream에서 가져올 최소 패턴은
gate → scan → lock → fork순서다. 즉 분신 하트비트 /리뷰 작업도 시간 게이트, 세션 수 게이트, 락, 분리 실행 순으로만 돈다. 근거:~/repos/3rd/claudecode/source-code/src/services/autoDream/autoDream.ts. - permission은 “AI가 똑똑하게 알아서”가 아니라, 1) 훅 2) 자동 판별기 3) 최종 대화상자 순서로 외재화한다. 힣 하네스는 여기서 3) 인간 승인과 fenced interface를 더 강하게 택한다. 근거:
~/repos/3rd/claudecode/source-code/src/hooks/toolPermission/handlers/coordinatorHandler.ts,interactiveHandler.ts. - coordinator/task에서 재사용할 것은 전체 swarm이 아니라
작업 단위의 영속성이다. task는 파일에 남고, dependency/owner가 명시되어야 한다. 근거:~/repos/3rd/claudecode/learn/web/src/data/annotations/s07.json의blocks/blockedBy,owner, file-based persistence. - 압축(compaction) 이후에도 분신이 계속 분신이려면 정체성 블록을 다시 주입해야 한다. 힣 하네스에서는 이것이 AGENTS.md + 존재 데이터 + session-control 이름이다. 근거:
~/repos/3rd/claudecode/learn/web/src/data/annotations/s11.json의 identity-after-compression. - 외부 채널 입력은 반드시
sendUserMessage()로 넣는다. 이것만이 turn을 강제하고, streaming 중에도steer/followUp를 명시하게 만든다. 근거:~/repos/3rd/claudecode/pi-mono/packages/coding-agent/src/core/agent-session.ts1276행대. - 외부 채널 출력은 반드시
agent_end.messages또는turn_end.message같은 이벤트 payload에서 읽는다. 가공 convenience field를 SSOT로 삼지 않는다. 근거:~/repos/3rd/claudecode/pi-mono/packages/agent/src/types.ts329행,~/repos/3rd/claudecode/pi-mono/packages/coding-agent/src/core/agent-session.ts609~610행. - control plane은 하나만 유지한다. 로컬 세션 제어는 Unix socket session-control, 장시간 작업은 delegate, 인간과의 원격 대화는 telegram으로 분리하고 서로 우회하지 않는다.
control / delegate / telegram 설계 결정표
| 주제 | 결정 | 실제 코드 포인트 | 오늘 적용 규칙 |
|---|---|---|---|
| 세션 제어 SSOT | session-control 소켓 | ~/repos/3rd/agent-stuff/pi-extensions/control.ts 상단 주석, 1080행대, 1109행대 | 로컬 pi 세션 깨우기/ 후속지시는 무조건 send_to_session 우선 |
| 대기 semantics | wait_until 은 turn_end / message_processed 둘만 허용 | control.ts 1124 | 응답이 필요하면 turn_end, 단순 큐잉이면 message_processed |
| parent 식별 | 현재 세션 id는 $PI_SESSION_ID 로 받음 | control.ts 29행, 1128 | 자기 세션 찾으려고 list_sessions 호출 금지 |
| delegate async child | child에는 --session-control 미부착, --no-extensions 로 실행 | ~/repos/gh/agent-config/pi-extensions/delegate.ts 321~327 | async 분신 작업은 parent만 제어점, child는 세션파일만 남김 |
| delegate 완료 보고 | child 종료 후 parent에 pi.sendMessage(... deliverAs: "followUp") | delegate.ts 389~437 | 완료 알림은 새 릴레이 만들지 말고 parent followUp으로 귀결 |
| delegate resume | 원본 taskId 의 sessionFile을 찾아 새 resume task로 비동기 스폰 | delegate.ts 740~895 | 재개는 기존 JSONL 맥락을 잇고, 새 소켓을 열지 않음 |
| telegram 입력 | 외부 인간 메시지는 sendUserMessage() 로 주입 | ~/repos/3rd/claudecode/pi-mono/packages/coding-agent/src/core/agent-session.ts 1276~1307 | Telegram → pi 브릿지는 custom message type 대신 user message로 넣기 |
| telegram 출력 | tdlib 스킬은 cmd_read/openChat/getChatHistory, cmd_send/sendMessage | ~/repos/gh/agent-config/skills/telegram/scripts/tg.py 244~344 | 텔레그램은 읽기/쓰기 채널이지 제어 plane 아님 |
| pending context flush | 새 프롬프트 전에 _flushPendingBashMessages() | ~/repos/3rd/claudecode/pi-mono/packages/coding-agent/src/core/agent-session.ts 983행, 2606행대 | 외부 브릿지도 “다음 프롬프트 전 flush” 규율을 따라 순서 보존 |
| coordinator 최소 이식 | worker에게는 작업, coordinator에게는 종합 /합성 | ~/repos/3rd/claudecode/source-code/src/coordinator/coordinatorMode.ts 120행 이후 | 분신은 조사 결과를 그대로 재전달하지 말고 합성 후 위임 |
실제 구현 체크리스트
- Entwurf Agent Spec 초안에
gate → scan → lock → fork루프를 명문화한다. (autoDream 패턴의 최소 이식) - Telegram 브릿지 구현 /정리 시 입력 함수명을
sendUserMessage로 고정하고,deliverAs선택 규칙(steer/followUp)을 문서화한다. - Telegram 출력 수집기는
agent_end.messages또는turn_end.message만 읽고, 임의 convenience 필드 접근을 금지한다. -
send_to_session호출 래퍼를 만들 때wait_until기본값을 비워두고, 사용처가turn_end/message_processed를 명시하게 한다. - async delegate 정책 문서에 “child socketless, parent controllable” 한 줄 규약을 추가한다.
- delegate 완료 알림은 현재처럼
pi.sendMessage(... followUp)를 유지하고, Telegram/ntfy 이중 알림은 2차 계층으로 둔다. - 분신용 task 보드는 Claude Code learn의
blocks/blockedBy/owner만 최소 채택하고, grand coordinator 추상화는 미룬다. - 압축 후 정체성 복구 항목을 Spec에 넣는다: 세션명, 역할, 제어소켓 이름, org 시간축 링크.
- 다음 심화 과제는
~/repos/3rd/claudecode/source-code/src/tasks/와~/repos/3rd/claudecode/learn/web/src/data/annotations/s10.json을 읽고, “inbox/polling/task-owner” 중 무엇을 Entwurf에 정말 들일지 결정한다.
역할 기반 조율 — 조율자는 모델이 아니라 자리
사건 — 서로 다른 구현 lane을 한 공동 맥락으로 묶기
여러 리포와 하네스에서 병렬로 움직이는 작업이 있었다. 힣(GLG)이 목적과 첫 구현을 직접 승인하고, 한 존재가 조율자 자리를 맡아 두 구현 담당자의 체크포인트·공동 계약·충돌을 받았다. 담당자들은 각자 맡은 범위에서 구현과 테스트를 수행했고, 조율자는 어느 모델이 더 낫다는 판정자가 아니라 lane 사이에서 맥락이 빠지지 않게 하는 자리가 되었다.
GLG — 목적·판단·승인·직접 지휘
└─ 조율자 — 공동 계약·체크포인트·충돌·인계
├─ 구현 담당자 A — 자기 범위의 구현·테스트
└─ 구현 담당자 B — 자기 범위의 구현·테스트세 역할과 소유권
| 역할 | 소유하는 것 |
|---|---|
| GLG | 목적, 첫 승인, initiative별 게이트, 최종 판단 |
| 조율자 (coordinator) | 공동 계약, 체크포인트 경로, 충돌 해결, 교체 세션까지의 맥락, 인계 |
| 구현 담당자 | 맡은 범위의 구현과 검증 |
조율 역할은 구현·commit·push 권한을 자동으로 주지 않는다. 그 게이트는 언제나 GLG가 initiative마다 정한다. GLG는 조율자와 구현 담당자 어느 쪽에도 직접 지시할 권한을 계속 지닌다.
왜 단일 조율 경로인가
병렬 작업에서 사라지기 쉬운 것은 코드 한 줄보다 공동 계약이다. 각 lane이 자기 자리에서만 합리적으로 움직이면 인터페이스가 조금씩 달라지고, 같은 것을 두 번 구현하거나, 담당 세션이 교체될 때 결정의 이유가 끊긴다. 조율자는 그 중간에서 계약·이견·체크포인트를 한 경로로 모아, 다음 담당자도 현재의 판단 위에서 출발하게 한다.
이는 구현 담당자를 관리하는 중간 관리자가 아니다. 구현의 세부 판단은 담당자가 소유하고, 조율자는 여러 판단이 한 목적 안에서 만나는지 보살핀다.
조율은 서열이 아니라 맡겨진 자리
조율자는 모델도, 백엔드도, 신분도 아니다. GPT가 조율자일 필요도 없고, 조율자가 참여 세션을 직접 만들었을 필요도 없다. 서로 다른 리포·하네스·모델의 존재들이 모두 형제로 참여할 수 있으며, 그중 한 존재가 initiative 동안 공동 맥락을 보존하도록 임명될 뿐이다.
따라서 PM은 한 사건에서 쓴 호칭이고 정본 용어는 조율자(coordinator)다. 모델은 runtime state이고, 역할은 그 작업이 지속되는 동안의 관계 구조다.
직접 대화와 교차 검토 lane
담당자끼리 직접 대화하지 말라는 뜻은 절대 금지가 아니다. 별도 조율선은 조율자가 열 때 사용한다. 조율자가 계약 확인이나 교차 검토를 위해 직접 대화 lane을 열면, 그 결과는 다시 공동 경로로 돌아와야 한다. 그래야 빠른 협업과 맥락 보존이 함께 가능하다.
위임에서 역할 기반 형제로
2025년의 초기 형태는 primary가 고정 역할·고정 모델의 subagent를 호출하는 오케스트레이션에 가까웠다. 2026년 3월에는 힣이 여러 에이전트의 맥락을 몸으로 직접 옮기는 인간 허브가 되어 벽을 넘었다. 이제는 GLG가 대등한 형제 중 한 존재에게 조율자 자리를 맡기고, 여러 구현 lane의 공동 맥락을 보존한다.
즉 고정된 main/subagent 구조에서 대등한 형제들의 역할 기반 토폴로지 로 옮겨온 것이다. 이것은 위임을 없애는 말이 아니라, 위임·재개·교체·교차 검토가 한 공동 목적 아래에서 이어지게 하는 운영 원칙이다.
현재 운영규약으로의 승격
이 원칙은 홈 운영규약의 coordinator-owned work와 만난다. 조율자가 계약·체크포인트·겹침·인계를 소유하고, 구현 담당자는 좁혀진 구현과 테스트에 집중한다. 보고할 것은 진행률만이 아니라 계약 변경, blocker, 이견, 검토에서 발견한 틈, 다음 인계다.
이 문서의 기존 4단계 위임과 llmlog 패턴은 여전히 유효하다. 다만 단일 parent가 delegate를 거느리는 그림만으로는 현재의 여러 리포·교체 세션·독립 담당자 협업을 설명할 수 없다. 역할 기반 조율은 그 위에 자라난 현재의 운용면이다.
Comments