콘텐츠로 이동

용어집

이 페이지는 flower 문서의 용어 기준이다. 같은 것은 문서 전체에서 하나의 이름만 쓴다. 한국어–영어 대응은 여기서 확정한다 —— 번역판도 이 표를 따른다.

각 항목은 세 가지를 준다: 이 단어가 무엇을 가리키는가, 코드에서는 무엇인가, 무엇이 아닌가. 세 번째가 대개 가장 쓸모 있다. 대부분의 오해는 한 단어를 다른 단어로 착각하는 데서 나오기 때문이다.


프레임워크와 실행

long-horizon

long-horizon

한 번의 실행이 수 시간에서 수일에 걸치고, 여러 세션에 걸치고, 프로세스 재시작에 걸친다. 한 번 묻고 한 번 답하는 것이 아니다. flower의 모든 메커니즘은 이런 실행이 중간에 무너지지 않게 하기 위한 것이다.

실측 참조: HT001은 10.4시간 연속으로 돌았다.

실행

run

Runtime이 시작해서 끝날 때까지의 전 과정. 한 번의 실행 안에는 여러 스텝, 여러 세션이 있을 수 있고, 중단된 뒤 연속성으로 이어붙일 수 있다. 실행 기록은 runs/manifest.jsonruns/sessions.db에 남는다.

아니다: API 호출 한 번도 아니고, 세션 하나도 아니다.

세션

session

모델 쪽의 컨텍스트 한 줄기. 자기 session_id를 가지며 resume할 수 있고 fork할 수 있다. 한 번의 실행은 세션 여러 개를 태워 없앨 수 있다 —— 핸드오프할 때마다 새 세션으로 바뀐다.

스텝

step · Step

워크플로우 안의 실행 단위 하나. 컨텍스트 딕셔너리를 받아 agent를 한 번 돌리고 결과를 딕셔너리에 되쓴다. Step은 클래스다. Python API를 보라.

워크플로우

workflow · Workflow

순서대로 엮인 스텝들, 그리고 스텝 사이에 상태를 어떻게 넘길지와 언제 조기 종료할지.

프레임워크는 완성된 워크플로우를 제공하지 않는다

flower는 메커니즘만 제공한다. 워크플로우는 당신이 쓴다. 워크플로우 설계를 보라.


역할

역할은 flower가 agent에게 부여하는 분업이다. 각 역할 = 주입되는 규칙 텍스트 한 덩어리 + 도구 한 묶음 + hook 한 묶음. 다섯 역할 모두 팩토리 함수다. Python API를 보라.

코디네이터

coordinator · coordinator()

메인 스레드 위의 그 agent. 작업을 쪼개고, 일을 맡기고, 보고를 읽고, 결정을 내린다. 하지만 직접 손대지 않는다 —— Write / Edit를 받지 못한다. 기본 도구는 Agent, TodoWrite, Read(roles.py:27)이지만 그게 최종 목록은 아니다. 인자에 따라 세 종류가 더 붙는다: glance=True(기본값)면 제한된 Bash가 하나 붙고(git status / ls처럼 한 번 보고 끝나는 명령까지만, delegate_guard가 지킨다), 질문 채널을 주면 inboxask가 붙고, 부하 워커WebFetch / WebSearch를 들고 있으면 그 둘도 합쳐진다 —— allowed_tools세션 단위라서, 합치지 않으면 subagent가 직접 호출할 때 아무도 응답하지 않는 권한 승인에서 멈춘다(roles.py:513-526).

역할 설정은 "Claude Code를 쓸 줄 아는 사람"이지, 실행자가 아니다.

아니다: 더 똑똑한 agent가 아니다. 워커와 기본적으로 같은 모델 등급을 쓴다. 아끼는 것은 컨텍스트지 모델이 아니다.

워커

worker · worker()

실제로 일하는 subagent: 코드를 쓰고, 테스트를 돌리고, 자료를 찾는다. 도구는 Read Write Edit Bash Glob Grep WebFetch WebSearch.

응답 형식은 규칙 텍스트로 네 단락에 묶여 있다 —— 결론 / 근거 / 산출물 / 미검증, 30줄을 넘지 않으며, 파일 내용·명령 출력·로그·diff 원문을 붙여 넣는 것은 금지다.

클래리파이어

clarifier · clarify()

손대기 전에 요구를 분명히 묻는 역할. 일을 하지 않고 질문만 한다. 분명해질 때까지 묻는다(라운드 상한 없음). 마지막에 요구 확인서 한 부를 낸다. 사전 확인을 보라.

판정자

judge · judge()

"끝났는가 아닌가"를 판정하는 역할. 둘 중 하나를 한다: 시작 전에 목표를 설정하거나(목표 + 판정 체크리스트 산출), 매 라운드가 끝난 뒤 그 라운드를 판정한다(판정 산출). 목표 가드를 보라.

핵심: 판정자가 판정하는 것은 산출물이지 소스코드가 아니다.

HT001에서 한 번 넘어졌다: 검수 기준은 "macOS 터미널에서 바로 실행"이라고 적혀 있었는데, 인도된 산출물에 file을 돌리니 ELF 64-bit LSB pie executable, ARM aarch64, GNU/Linux였고, 판정은 통과였다.

두 가지를 분명히 해둬야 한다. 그러지 않으면 이 예시는 오독된다:

  1. 그때 잘못 판정한 것은 목표 가드가 아니다 —— HT001에는 아직 이 메커니즘이 없었다. 잘못 판정한 것은 코디네이터가 자발적으로 파견한 감사자였다.
  2. 기본 설정의 판정자도 십중팔구 이걸 놓친다. judge()의 기본값은 can_run=False이고 도구는 Read/Glob/Grep뿐이다 —— file을 돌릴 수 없다. Makefile을 읽고 Darwin 분기가 실제로 있는 것을 보고는 달성으로 판정할 뿐이다.

진짜로 통한 것은 HT002다: 판정자가 judge_can_run을 켜서 직접 filelsof를 돌려 현장을 봤고, 이 함정을 명확히 피했다. 그러니 "산출물을 판정한다"는 말은 can_run=True가 있어야 땅에 발을 붙인다.

오라클

oracle · oracle()

읽기 전용 우회로 하나. 실행이 아직 돌고 있는 동안 "지금 어디까지 왔나"를 물으면, 최근 이벤트와 워크벤치를 한 번 보고 답한다. 그 답은 그 실행의 컨텍스트로 들어가지 않는다 —— 물어도 실행에 영향이 없고, 답하면 버려진다.

subagent

Claude Agent SDK의 개념: 메인 agent가 Agent 도구로 파견하는 하위 agent. 자기 transcript를 따로 가지며, 도구 호출과 시행착오는 그쪽에 기록되고 메인 스레드는 최종 보고만 받는다.

flower가 컨텍스트를 아끼는 첫 번째 층이자, 가장 많이 아끼는 층이다. 컨텍스트 경제학을 보라.


네 가지 메커니즘

사전 확인

clarify

손대기 전에 요구를 분명히 물어서 요구 확인서 한 부로 얼린 다음, 실행을 시작한다. 막는 것은 "만들어 놨는데 원하던 게 아니다"이다. 사전 확인을 보라.

요구 확인서

brief · Brief

클래리파이어가 다 묻고 나서 내는 문서. 정확히 네 단락. 이후 스텝들은 이것을 읽고, 요구를 다시 추측하지 않는다.

작업 지시서혼동하지 말 것. 요구 확인서는 "사람이 무엇을 원하는가"이고, 작업 지시서는 "이 subagent가 이번에 무엇을 하는가"이다.

작업 지시서

task brief

코디네이터가 일을 맡길 때 워커에게 써 주는 그 글. 이번 작업에만 해당하는 것만 쓴다 —— 상대가 이미 아는 규율은 되풀이하지 않는다.

실측: 8/8건의 작업 지시서 전부가 상대가 이미 아는 규율을 되풀이했고, 가장 짧은 521자짜리에서 작업 고유 내용은 약 120자뿐이었다. 한 라운드에 약 4.8k의 영구 컨텍스트를 헛되이 차지했다.

목표 가드

goal guard

판정자가 매 라운드가 끝난 뒤 목표 달성 여부를 독립적으로 판정하고, 달성되지 않았으면 되돌려 계속 시킨다. 막는 것은 "끝났다고 했는데 사실 안 끝났다"이다. 목표 가드를 보라.

판정

verdict · Verdict

판정자가 한 라운드를 판정한 결과. 정확히 세 단락: 결론 / 이유 / 미통과.

결론은 세 가지다. ACHIEVED(달성), NOT_YET(아직), UNREACHABLE(이 환경에서는 검증 불가). 뒤의 둘은 서로 다른 결론이다 —— "여기서는 검증할 수 없다"는 절대 통과로 판정하지 않는다.

연속성

continuity

같은 디렉터리에서 한 번 더 돌리면 지난번 진척에 자동으로 이어붙는다 —— 프로세스가 죽었거나 머신이 재시작되어도 마찬가지다. 막는 것은 "몇 시간 돌다 죽어서 처음부터 다시"이다. 연속성을 보라.

핸드오프혼동하지 말 것: 연속성은 프로세스를 넘어 지난 실행에 이어붙이는 것이고, 핸드오프는 같은 실행 내부에서 새 세션으로 바꾸는 것이다.

핸드오프

handoff

컨텍스트가 거의 찼을 때, 현재 세션이 사람이 읽고 고칠 수 있는 핸드오프 문서를 쓰게 하고, 그다음 새 세션이 이어받는다. 막는 것은 "컨텍스트가 차서 요약 한 덩어리로 압축되는 것"이다. 핸드오프를 보라.

compact가 아니다. compact를 보라.

핸드오프 문서

handoff document · Handoff

핸드오프 때 쓰는 문서. 다섯 단락: doing(무엇을 하고 있는가), decided(무엇을 정했는가), deadends(막힌 길), next(다음 단계), scene(현장).

필수는 doingnext뿐이다 —— "막힌 길"을 비워둘 수 없게 강제하면 모델이 지어내게 된다.

compact

compact

Claude Code의 기본 방식: 컨텍스트가 차면 앞의 대화를 요약 한 덩어리로 만든다.

flower는 이걸 쓰지 않고 핸드오프로 대체한다. 차이는 이렇다. 요약은 모델이 생성한 것이라 읽을 수도 고칠 수도 없고, 무엇이 버려졌는지 알 수 없다. 핸드오프 문서는 구조화되어 있고, 디스크에 남고, 열어서 한 줄 고친 다음 이어서 돌리게 할 수 있다.


컨텍스트 관리

메인 스레드

main thread

코디네이터가 있는 그 세션 컨텍스트. 실행 전체를 관통하는 유일한 컨텍스트이므로, 가장 아껴야 한다.

코드에서 메인 스레드를 판정하는 방법: hook 데이터에 agent_id없다. subagent의 hook에는 agent_id가 있다.

워크벤치

workbench · Workbench

디스크에 남는 작업 디렉터리. 하위 디렉터리 셋:

디렉터리 무엇을 두나
scripts/ 두 번째로 다시 돌릴 스크립트, 첫 줄에 # desc: 한 줄 설명
artifacts/ 2000자를 넘는 긴 산출물
notes/ 핵심 결정, 결정 하나에 파일 하나

INDEX.md는 이 세 디렉터리의 색인이며, system prompt에 주입된다. 그래서 agent는 매 라운드 손에 무엇이 있는지 안다.

입구가 둘, 기본 위치가 둘

워크벤치가 어디에 놓이는지는 어떻게 만들었느냐에 달렸다. 여기서 자주 밟는다:

생성 방식 워크벤치 루트 디렉터리
Workbench(workspace) —— starter_flow() / wake_state()가 가는 길이기도 하다 <워크스페이스>/.flower
Runtime(workbench=True) <run_dir>/workbench(기본값 runs/workbench)

커맨드라인은 전자를 간다. 그래서 flower로 돌리면 .flower/가 나온다. 하지만 Python에서 직접 Runtime(workbench=True)를 쓰면 runs/workbench를 받는다. 위치를 지정하려면 만들어 둔 Workbench 인스턴스를 넘겨라. 기본값에 기대지 마라.

색인은 subagent가 상속받지 못한다

색인은 세션 단위의 system_prompt.append를 탄다. subagent는 받지 못한다. 그래서 "긴 산출물은 artifacts/에 쓴다"는 이 규칙은 코디네이터작업 지시서에 옮겨 적어야만 한다 —— 그게 유일한 통로다.

스필

spill

도구 결과가 임계값(기본 4000자)을 넘으면, PostToolUse hook이 그것을 <워크벤치 루트>/spill/에 쓰고 컨텍스트에는 경로 한 줄만 남긴다.

경로는 워크벤치를 따라간다. 하드코딩이 아니다 —— 워크벤치가 기본 위치인 <워크스페이스>/.flower에 있을 때만 그게 정확히 .flower/spill/이 된다. 격리를 켜서 워크벤치가 home=으로 저장소 바깥을 가리키면, 스필도 따라 나간다.

그 자리에서 자른다. 컨텍스트가 찬 뒤에 되돌아가 compact하는 게 아니다.

일회성 명령

ephemeral command

결과가 곧 낡아버리고 남겨둘 가치가 없는 명령 —— ls, git status, ps 같은 것들. 이 결과들은 영속화되는 세션 기록에 들어가지 않는다. "메인 스레드가 한 번 봐도 되는가"와 "결과가 잘려나가는가"를 판단할 때 같은 함수를 쓴다. 그래서 두 집합은 항상 같다.

트리밍

trim · TrimmingSessionStore

resume 직전에 모델에 다시 먹일 메시지 사본을 다시 쓴다(일회성 명령의 결과, 지나치게 긴 도구 출력).

load()만 덮어쓴다: SQLite 안의 원문은 언제나 그대로다. 잘려나가는 것은 이번 resume에서 컨텍스트로 들어가는 그 사본뿐이다. 그래서 트리밍은 되돌릴 수 있다 —— 전략을 바꿔 다시 resume하면 다시 완전한 기록을 얻는다.

프루닝

prune · PruningSessionStore

에러 메시지를 컨텍스트 바깥에 막아둔다. 네트워크가 끊겨 재시도하는 동안 쏟아진 에러 더미가 resume 이후의 컨텍스트를 차지할 이유는 없다.

트리밍혼동하지 말 것: 트리밍은 부피와 가치로 버리고, 프루닝은 "에러인가 아닌가"로 버린다.


런타임

격리

isolation

표시된 역할은 자동으로 독립된 git worktree에 배치된다. hook이 강제하며, 프롬프트에 기대지 않는다. 같은 저장소를 병렬로 고칠 때 충돌하지 않는다.

격리를 켜면 워크벤치를 저장소 밖으로 옮겨야 한다

worktree 격리를 켤 때 워크벤치는 반드시 home=으로 저장소 바깥을 가리켜야 한다. 그러지 않으면 격리된 agent가 공유 checkout에 쓰지 못한다.

리질리언스

resilience · Resilience

네트워크가 끊기면 실패로 빠져나가지 않고 매달려 기다린다: DNS + TCP 프로브가 지켜보다가, 네트워크가 돌아오면 resume해서 이어 간다. 대기 중에 생긴 에러 메시지는 프루닝이 컨텍스트 바깥에 막아둔다.

리니지

lineage · Lineage

"이번 실행이 어느 세션에서 fork되었는가"를 프로세스를 넘어 기록하며, lineage.json에 남는다. 연속성은 이것으로 지난번에 어디까지 갔는지 찾는다.

실행 매니페스트혼동하지 말 것 —— 그건 runs/manifest.json이고, 매 실행의 장부를 기록한다.

실행 매니페스트

run manifest · runs/manifest.json

실행의 장부 기록: 얼마를 썼는지, 얼마나 돌았는지, 컨텍스트가 얼마나 컸는지. 사례 페이지의 숫자는 전부 여기서 다시 계산해 볼 수 있다.

웨이크

wake · wake_state()

출발 전의 읽기 전용 탐지: 이 워크스페이스에 이미 요구 확인서와 목표가 있는지 보고, 이번이 완전히 새로 시작하는 것인지 연속성인지 결정한다. 한 바이트도 쓰지 않는다.

wake_state()는 워크벤치 위치의 유일한 정의처다 —— 드라이버 프로그램도 확인서가 어디 있는지 알려면 이걸 거쳐야 한다. 직접 경로를 이어 붙였다가 틀려도 에러가 나지 않고, 조용히 무효가 될 뿐이다.

이벤트

event · Event

SDK의 메시지 스트림을 평탄화한 안정적인 구조. 상호작용 레이어Event만 알고, 어떤 SDK 타입도 import하지 않는다 —— UI를 바꿔도 코어를 고치지 않아도 되는 경계다.

상호작용 레이어

interaction layer

사람과 실행 사이의 UI 층. 기본은 터미널이고, Web·TUI·HTTP로 바꾸거나 완전 무인 자동으로 갈 수 있다. 상호작용 레이어 교체를 보라.

세션 스토어

session store · SessionStore

세션 메시지의 영속화 백엔드. 기본값인 SqliteSessionStoreruns/sessions.db에 쓰며, 트리밍프루닝 두 층의 래퍼를 씌울 수 있다.

예산

budget · max_budget_usd

한 번의 실행에 대한 지출 상한. 넘으면 멈춘다. long-horizon 실행은 이게 없으면 아주 비싸진다 —— HT001은 $171.62를 썼다.


이식성

이식 가능

portable

머신을 바꿔도 동작이 같다. 방법은 setting_sources=[] —— 호스트의 ~/.claude/도 읽지 않고, 프로젝트의 .claude/도 읽지 않는다. 도메인 능력은 plugin으로 저장소를 따라다니고, 자격 증명은 .env로 직접 들고 다닌다.

대가: 자격 증명을 직접 들고 다녀야 한다. 호스트 설정을 자동으로 상속하지 않는다.

덧붙이기

append

도메인 지시는 Claude Code의 기본 시스템 프롬프트 뒤에 덧붙는다. 대체하지 않는다:

system_prompt = {"type": "preset", "preset": "claude_code", "append": spec.instructions}

그래서 전문화가 범용 능력을 잃는 대가로 이뤄지지 않는다.

plugin

저장소를 따라다니는 도메인 능력 꾸러미. plugins=[local]로 로드하며, 디렉터리 안에 skills/, agents/, hooks/, .mcp.json을 둘 수 있다. 배포를 보라.