Skip to content

Repository files navigation

agent-work-loop

npm version CI license

코딩 에이전트가 같은 실패를 두 번 하지 않게 하는 CLI입니다. 명령어는 awl입니다.

에이전트에게 큰 작업을 맡기면 대체로 이렇게 흘러갑니다. 완료 조건 없이 시작하고, 중간에 무엇을 확인했는지 남지 않고, 테스트를 고쳐서 통과시키고, 다음 세션은 지난번 실패를 모른 채 처음부터 다시 합니다.

awl은 그 사이사이에 멈춤과 기록을 넣습니다. 목표를 검증 가능한 조건으로 옮기고, 사람이 봐야 할 지점에서 실제로 멈추고, 있었던 일을 파일로 남깁니다. 남은 기록은 다음 작업의 입력이 됩니다.

awl은 판단하지 않습니다. LLM을 호출하지 않고 파일과 상태만 다룹니다. 무엇을 배울지, 어떤 규칙을 세울지는 Claude Code나 Codex가 스킬로 판단합니다. awl은 그 판단이 사라지지 않게 붙잡아 둡니다.

macOS와 Windows, Claude Code와 Codex를 모두 지원합니다. Windows는 아직 macOS만큼 검증되지 않았습니다.


설치

npm install -g agent-work-loop

pnpm으로 설치했는데 awl: command not found가 나오면 pnpm setup을 한 번 실행하고 터미널을 새로 엽니다. 전역 bin이 PATH에 없어서입니다.

업데이트는 한 줄입니다. 엔진은 사본을 두지 않아서 패키지가 곧 엔진입니다.

npm i -g agent-work-loop@latest

여러 프로젝트를 관리한다면 awl update --local로 등록된 프로젝트의 스킬까지 한 번에 맞춥니다.


시작하기

프로젝트에서 한 번만 실행합니다.

cd my-project
awl init

주 언어, 검증 명령, 프로젝트 성격을 묻고 설치할 에이전트를 고릅니다. 질문 없이 감지된 값으로 진행하려면 awl init --yes를 씁니다.

만들어지는 것은 넷입니다.

경로 무엇 커밋
.awl/config.json 검증 명령과 프로젝트 성격 합니다. 팀이 같이 씁니다
.awl/profile.json 단계별로 갈아 끼울 스킬 합니다
.awl/state.json 지금 어느 티켓의 어느 단계인지 안 합니다
.claude/skills/ 또는 .agents/skills/ 작업 루프 스킬 팀 컨벤션에 따라

이제 에이전트를 열고 목표를 문장으로 던집니다. Codex에서는 / 대신 $를 씁니다.

/awl  페이지 편집기에 여백 시스템을 넣고 싶어

한 세션이 스펙을 쓰고, 티켓을 도출하고, 게이트 넷을 지나며 구현과 검증까지 끝냅니다. 지금 어디까지 왔는지는 awl status로 봅니다.


어떻게 도는가

요청 하나가 지나는 길

목표(문장)
  ↓
[조사] → [설계] → [명료화] → [스파이크] → [완료 조건]
  ↓
[게이트 1] 이 티켓들로 요청이 만족되는가
  ↓
티켓마다 { [게이트 2] 착수 → 구현·검증·격리 커밋 → [게이트 3] 완료 }
  ↓
[게이트 4] 실제로 만족됐는가
  ↓
awl evolve — 있었던 일에서 교훈을 뽑는다

게이트는 산문이 아니라 도구 호출입니다. "승인을 기다립니다"라고 써놓고 다음 단락에서 구현을 시작하면 그건 멈춘 게 아닙니다. 게이트 1과 4는 요청 층에서 같은 질문을 앞뒤로 묻고, 2와 3은 티켓 층에서 그렇게 합니다.

게이트 사이는 자유입니다. 조사부터 하든 코드를 먼저 읽든 상관없고, 게이트에 도착했을 때 요구한 형식만 맞으면 됩니다.

얼마나 멈출지 고르기

모드는 실행할 때 정합니다. 팀이 공유하는 설정이 아니라 그때그때 개인이 고르는 값입니다.

awl run "레이어 패널을 키보드로 조작하고 싶다" --strict
모드 동작
--strict 네 게이트에서 다 멈춥니다. 처음 건드리는 영역
생략 semi-auto — 게이트 2·3을 자동 승인합니다. 기본값
--auto 전부 자동. 요청을 닫을 때 펼친 요약만 받습니다
--review 교차 검증을 켭니다. 게이트 모드와 다른 축입니다

기본이 semi-auto인 이유는 시뮬레이션에서 strict가 티켓 다섯 개에 열한 번 멈췄기 때문입니다. 부담이 게이트 2·3에 몰렸는데 둘 다 기계 판정이 끝난 뒤에 묻는 자리였습니다.

자동 승인은 어느 모드에서든 기록에 남습니다. 게이트를 없애는 게 아니라 사람 손을 빼는 것이라, 나중에 어디부터 사람이 안 봤는지 되짚을 수 있어야 합니다.

awl run은 요청과 모드를 상태에 적고 다음 단계를 안내할 뿐, 에이전트를 띄우지는 않습니다.

커밋이 섞이지 않게

awl commit <티켓> --start로 시작점을 잡고, 작업이 끝나면 awl commit <티켓> -m "..."으로 닫습니다. 그 사이에 생긴 내 변경만 커밋하고 남의 미커밋 변경은 워킹트리에 그대로 둡니다.

겹칠 가능성이 있으면 커밋하지 않고 알립니다. 확신할 수 없을 때 조용히 밀어붙이는 것보다 멈추는 쪽이 낫다는 판단입니다.

단계마다 다른 스킬이 붙는다

awl init이 만드는 .awl/profile.json은 단계마다 어떤 방식으로 할지를 가리킵니다. 일곱 자리가 있고 기본값이 채워져 나옵니다.

자리 기본 하는 일
spec grill-with-docs 스펙을 쓰며 도메인 용어를 세웁니다
investigation research 코드를 읽고 출처를 남깁니다
clarification grill-me 남은 결정을 캐묻습니다
spike prototype 모르는 걸 일회성 프로토타입으로 판정합니다
implement tdd 실패하는 테스트부터 씁니다
review code-review 표준과 스펙 두 축으로 봅니다
close explain-diff 무엇이 왜 바뀌었는지 사람이 읽을 형태로 남깁니다

가리키기만 합니다. 설치하지도, 강제하지도 않습니다. 못 읽으면 그 단계는 계약만 보고 진행합니다. 마음에 안 들면 profile.json에서 다른 걸 가리키거나 비우면 됩니다.

캐묻기와 마감 설명은 모드가 강도를 정합니다.

strict      미해결 질문이 0건이 될 때까지 캐묻습니다. 마감 설명에 이해 확인까지
semi-auto   한 번 캐묻고 남은 건 clarification 으로. 마감 설명은 남깁니다
auto        캐묻지 않습니다 — 사람 손을 뺀 모드에서 캐묻는 건 모순입니다

close 자리가 review와 따로 있는 이유는 하는 일이 달라서입니다. 리뷰는 다른 눈으로 결함을 찾는 자리고, 마감 설명은 사람이 "에이전트가 무얼 했나"를 따라잡는 자리입니다. 자율로 오래 돌수록 이 부채가 커집니다.

링크가 살아 있는지는 awl doctor --links로 봅니다.


명령어

전체 목록은 awl --help, 실행 예시는 awl --examples, 스킬 설명은 awl --skills로 봅니다.

awl run "<목표>"    # 요청을 엽니다 (--strict / --auto / --review)
awl next           # 지금 뭘 해야 하는지 (스킬이 매 단계 부릅니다)
awl stages         # 전체 흐름 (--short 면 다섯 줄)
awl status         # 지금 어디까지 왔는지
awl doctor         # 설치와 환경 점검 (아무것도 고치지 않습니다)
awl doctor --links # 스킬 링크가 실제로 열리는지까지 (네트워크를 씁니다)
awl version-check  # 버전이 어긋난 곳 확인

문서와 검증:

awl doc new spec "<제목>"   # 스펙 스켈레톤
awl doc lint               # EARS 문형·용어집·모순·빠뜨린 예외 검사
awl tickets derive <스펙>   # 스펙에서 티켓 도출
awl verify                 # config 에 적은 검증 명령 실행
awl review pack <티켓>      # 리뷰어에게 넘길 자료 조립

쌓인 것 보기:

awl records        # 있었던 일 전수
awl gotchas        # 아직 규칙이 안 된 교훈
awl rules          # 이 프로젝트에 적용되는 규칙
awl backlog        # 정리 신호
awl brief          # 오늘 진행분만
awl metrics        # 세대별 지표 추세
awl tokens <티켓>   # 그 티켓이 단계별로 쓴 토큰

설정

.awl/config.json에 검증 명령을 적습니다. awl verify가 이 명령들을 실제로 실행해 통과와 실패를 가릅니다. AI가 "다 했습니다"라고 말할 수 없게 만드는 자리입니다.

{
  "project": "my-project",
  "mainLanguage": ["typescript"],
  "character": "디자인 토큰 강제, 여백은 자유 px 금지",
  "verifications": [
    { "name": "typecheck", "cmd": "tsc --noEmit" },
    { "name": "lint", "cmd": "biome check ." },
    { "name": "test", "cmd": "vitest run", "scope": "changed" },
    { "name": "e2e", "cmd": "playwright test", "level": "request", "exclusive": true }
  ]
}
  • scope: "changed" — 이번에 바뀐 파일에서 나온 실패만 봅니다
  • level: "request" — 티켓마다가 아니라 요청을 닫을 때 한 번 돕니다
  • exclusive: true — 포트처럼 못 나누는 자원을 쓰는 검증을 직렬화합니다
  • skip: true — 이 검증을 끕니다. 끈 사실은 게이트에 표시됩니다

모노레포는 각 항목에 cwd를 지정합니다. 상대경로 실행 파일도 그 cwd 기준으로 풀립니다.

{ "name": "typecheck", "cmd": "tsc -p tsconfig.json", "cwd": "packages/app" }

awl init이 모노레포를 감지하면 어느 패키지를 검증할지 물어봅니다. 나중에 바꾸려면 awl config set 을 쓰고, 인자 없이 awl config를 실행하면 항목을 골라 고치는 화면이 뜹니다.

내 환경에서만 다르게 두고 싶으면 config.local.json을 만듭니다. base → local 순으로 병합되고 local이 이깁니다. 배열은 통째로 갈아 끼우지 않고 name 키로 합칩니다.


무엇이 어디에 쌓이나

~/.awl (사람 기준) <project>/.awl (프로젝트 기준)
담는 것 전역 기본값, 교훈, 규칙, 세대 지표, 개인 초안 설정, 프로파일, 지금 상태, 기록
누구 것인가 당신. 프로젝트를 옮겨도 따라옵니다 이 프로젝트. 저장소를 나가면 안 따라옵니다

학습은 사람 층에, 기록은 프로젝트 층에 둡니다. 교훈이 저장소에 묶여 있으면 다음 프로젝트에서 빈손으로 시작하게 됩니다. 반대로 기록은 커밋·티켓과 1:1로 붙고 양이 커서, 레인이 여럿일 때 주 워킹카피 하나를 가리켜 실시간으로 공유합니다.

교훈이 규칙이 되는 건 사람이 정합니다. 자동 승격은 없습니다.

awl rules promote G-003 \
  --applies "여백 값을 CSS/스타일에 쓸 때" \
  --counter "이미 디자인 토큰 시스템이 없는 프로젝트"

--counter(반증 조건)를 요구하는 이유는 그게 없으면 검증할 수 없는 신념이 되기 때문입니다.

도구 자체가 아팠던 점은 다른 종류라 따로 남깁니다. awl feedback으로 적으면 기록에 awl-feedback 타입으로 쌓이고, 이건 작업 코드의 교훈이 아니라서 규칙으로 승격되지 않습니다. awl feedback-log로 모아 봅니다.


작업 루프와 오케스트레이션

작업 루프는 요청 하나가 스펙에서 게이트 넷을 지나는 흐름입니다. 한 세션이 관통합니다.

오케스트레이션은 무관한 요청 여럿을 격리 레인에 나눠 나란히 돌리는 층입니다.

awl run --lanes "키보드 조작" "인증 리프레시" "번들 축소"

레인마다 워크트리와 브랜치, 포트 오프셋이 생기고 각 레인의 상태에 요청이 적힙니다. 그 다음은 사람이 터미널을 셋 열어 각각 /awl을 돕니다. 현황은 awl lanes, 정리는 awl lane rm <이름>으로 합니다. 병합 안 된 커밋이 있으면 거부합니다.

격리합니다    워크트리 · 상태 · 포트
공유합니다    설정 · 프로파일 · 기록 · 교훈   (읽기는 전부, 쓰기만 나눕니다)

격리해야 하는 건 코드지 학습이 아닙니다. 개인 저장소까지 격리하면 레인 A가 겪은 실패를 레인 B가 모른 채 같은 시행착오를 반복합니다.

오케스트레이터 에이전트를 두지 않습니다. 예전에는 plan 세션이 exec과 review를 띄우고 파일 큐로 일감을 넘기는 구조였는데, 세 세션이 동시에 사람에게 물어 정신없었고 오케스트레이터 자체가 토큰을 먹었습니다. 역할 이름이 다르다는 게 세션을 나눌 근거는 아니었습니다. 지금은 레인당 한 세션이고, 넘길 일이 없으니 큐도 없습니다.

세션을 더 띄우는 건 세 경우뿐입니다. 편향을 피해야 할 때(--review의 교차 검증), 동시에 해야 할 때(레인), 오염되면 안 될 때. 그중에서도 띄우는 주체는 awl이 아니라 그 세션입니다.


자주 막히는 곳

스킬 링크가 죽었다고 나온다 profile.json이 가리키는 외부 스킬이 사라졌거나 저장소가 경로를 바꾼 경우입니다. profile.json에서 그 자리를 고치거나 비우면 됩니다 — 비우면 그 단계는 계약만 보고 진행합니다. "확인 못 함"은 다릅니다. 네트워크가 없거나 느릴 때 나오고, 링크가 죽었다는 뜻이 아닙니다.

설치된 스킬이 낡았다고 경고한다 패키지를 올렸는데 프로젝트의 스킬이 예전 버전일 때 나옵니다. awl init --yesawl update --local로 재설치하면 맞춰집니다. 프로젝트 설정은 건드리지 않습니다. 어긋난 곳은 awl version-check로 직접 봅니다.

업그레이드하면 프로젝트 설정이 사라지나요 아니요. 팀이 정한 검증 명령 같은 설정 필드는 그대로 둡니다.

검증 명령을 못 찾는다고 한다 node_modules/.bin이 지금 셸의 PATH에 없을 수 있습니다. cwd를 지정했다면 그 디렉토리가 실제로 있는지도 확인하세요.

커밋이 "남의 변경과 겹칠 수 있다"며 거부된다 의도한 동작입니다. git statusgit diff로 무엇이 섞였는지 확인하세요. 편집을 시작하기 전에 awl commit <티켓> --start를 먼저 호출해야 합니다. 순서가 뒤집히면 그 편집이 시작점 스냅샷에 흡수돼 격리가 무의미해집니다.

git push가 막힌다 awl init --push-guard로 심은 훅 때문입니다. 기본은 설치되지 않습니다. 사람이 터미널에서 직접 치는 push는 통과하고, 막혔다면 비대화형으로 실행된 경우입니다. 그때는 AWL_ALLOW_PUSH=1 git push를 씁니다.

대형 저장소에서 레인 만들기가 실패한다 git worktree add가 기본 180초 안에 못 끝난 경우입니다. 디스크 문제가 아닙니다. AWL_GIT_WORKTREE_TIMEOUT_MS로 값을 늘려 다시 시도하세요.

게이트에서 안 멈추고 그냥 진행한다 스킬이 최신인지 확인하세요. awl doctor가 스킬 불일치를 경고하면 awl init --yes로 재설치합니다.

전부 지우고 싶다 awl remove를 실행합니다. 기본은 드라이런이라 무엇이 지워질지 먼저 보여주고, 실제로 지우려면 --yes를 붙입니다. ~/.awl까지 지우려면 --global을 명시해야 합니다.


기여

pnpm install
pnpm run build
pnpm test
pnpm run lint
pnpm run typecheck

PR을 올리면 Node 18과 22 두 버전에서 typecheck·lint·test·build가 돌아갑니다.

릴리스는 pnpm release:patch(또는 minor/major)로 합니다. 검증과 빌드, tarball 확인, 배포 리허설을 통과한 뒤에야 버전과 CHANGELOG를 올리고 커밋·태그·push까지 처리합니다.

npm에 awl 이름이 이미 있어서 패키지는 agent-work-loop으로 배포하고 명령어만 awl로 씁니다.

MIT 라이선스입니다.

About

단단하게, 최대한 신경 안쓰게, 그러면서 데이터는 쌓아보시죠.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages