graph-engineering
by sciencemj
README.md
**한국어** · [English](README.en.md)
# Graph Engineering
[](https://github.com/sciencemj/graph-engineering/actions/workflows/ci.yml)
코딩 작업을 자연어 대화가 아니라 **명시적 실행 그래프(DAG)** 로 돌리는 Claude Code 플러그인.
Claude 는 그래프를 설계하지 않는다. **커서를 한 칸 미는 펌프**일 뿐이고, 무엇을 실행할지는 서버가 정한다.
`bun test` 같은 결정적 작업은 서버가 셸로 직접 돌린다 — **LLM 호출 0회**. 그래서 "테스트 돌렸다고 하고 안 돌린"
일이 구조적으로 일어나지 않는다.

---
## 왜
LLM 에게 긴 작업을 시키면 네 가지가 반복된다.
| 안티패턴 | 이 플러그인의 대답 |
|---|---|
| 컨텍스트가 넘치면 앞의 결정을 잊는다 | 상태는 대화가 아니라 **서버(SQLite)** 가 소유한다 |
| "테스트 통과했습니다" — 실제로는 안 돌림 | 결정적 작업은 **서버가 실행**한다. 종료 코드가 판정한다 |
| 실패하면 조용히 우회한다 | 실패는 **엣지**다. `on_failure`·재시도·루프가 그래프에 적혀 있다 |
| 사람이 언제 봐야 하는지 모른다 | `user_input`·`checkpoint` 가 **1급 노드**다. AI 는 그 응답을 대신 못 채운다 |
## 설치
```bash
# Claude Code 안에서
/plugin marketplace add sciencemj/graph-engineering
/plugin install graph-engineering@graph-engineering-dev
```
[Bun](https://bun.sh) 이 필요하다 (`curl -fsSL https://bun.sh/install | bash`). MCP 서버가 Bun 으로 돈다.
설치하면 Claude Code 를 띄울 때 stderr 에 UI 주소 한 줄이 찍힌다.
```
[graph-engineering] UI: http://localhost:7788/#t=<ui_token>
```
**그 토큰은 어떤 파일에도 저장되지 않는다.** 사람만 가지는 전권 토큰이고, AI 는 읽을 수 없다.
## 5분 사용법
```
/graph-engineering:graph-new 만료 토큰 버그를 고치고 테스트가 통과할 때까지 반복
```
Claude 가 요구사항을 노드로 분해해 `.claude/graphs/<이름>.graph.json` 에 등록한다. **자동으로 실행하지 않는다.**
```
/graph-engineering:graph-open # 브라우저에서 그래프를 열어 직접 고친다
/graph-engineering:graph-lock # 구조를 확정한다 — 이제 AI 는 제안만 할 수 있다
/graph-engineering:graph-run <이름>
/graph-engineering:graph-status
```
락은 **AI 에게만** 걸린다. 사람은 락된 그래프도 UI 에서 계속 편집한다.
## 화면
### 사람 차례는 화면을 점유한다

`user_input` 과 `checkpoint` 에 도달하면 런이 멈춘다. 이 모달의 버튼은 `ui_token` 을 요구하는
**사람 전용 툴**을 부른다 — MCP 에는 그 툴 이름조차 노출되지 않는다. "대신 눌러드릴까요" 가 불가능하다.
### 작업일지 — 노드를 따라 흐르는 상태 객체

흩어진 임시 파일 대신 모든 노드가 이 객체 하나만 읽고 쓴다. 화면에 보이는 값은 요약이 아니라
`.claude/graph.db` 에 실제로 들어 있는 그대로다. 실행 이력은 **append-only** 다 — DB 트리거가
`UPDATE`/`DELETE` 를 거부하므로 서버 코드조차 지난 기록을 고칠 수 없다.
엣지 상태는 세 가지다: `pending`(아직 판정 전) · `taken`(감) · `not_taken`(안 감). "아직 안 봤다" 와
"보고 안 갔다" 를 같은 색으로 칠하면 분기 버그를 못 찾는다.
### 흐름 방향은 한 번에 뒤집힌다

세로↔가로 전환은 배치를 다시 계산한다. `loop` 엣지는 배치에서 빠진다 — 되돌아가는 흐름이
레이아웃을 왜곡하지 않게.
## 노드 8종
| 타입 | 누가 실행하나 | 하는 일 |
|---|---|---|
| `command` | 서버 (LLM 0회) | argv 로 직접 exec. 셸을 안 거치므로 명령 주입이 없다 |
| `condition` | 서버 (LLM 0회) | 화이트리스트된 연산자만. 임의 코드 평가 없음 |
| `join` / `parallel` | 서버 (LLM 0회) | 합류(`all`/`any`/`n_of_m`) 와 분기 |
| `subgraph` | 서버 | 런 시작 시점에 인라인 전개된다 |
| `ai_task` | Claude | 지시를 받아 수행하고 결과를 보고. **판정은 다음 `run_advance`** 가 한다 |
| `user_input` | 사람 | 폼 응답. AI 가 못 채운다 |
| `checkpoint` | 사람 | 승인/거부. AI 가 못 누른다 |
## 안전 장치
- **두 토큰** — `agent_token` 은 파일에 있고 MCP 가 쓴다. `ui_token` 은 stderr 로만 나가고
사람만 가진다. 사람 전용 툴은 `ui_token` 없이는 HTTP 로도 못 부른다.
- **명령 허용 목록** — 기본은 거부다. 매칭은 **보간이 끝난 최종 argv** 로 한다.
`bun test ${vars.target}` 을 미리 통과시켜 놓고 뒤에 아무 값이나 밀어 넣는 경로를 막는다.
- **락 + 구조 해시** — 락된 그래프를 서버 밖에서 고치면 UI 가 "외부 변조 감지" 를 띄운다.
사람이 내용을 확인하고 승인해야 정본이 된다.
- **훅** — Claude 가 `.claude/graphs/**`, `.claude/graph.db`, `.claude/graph-config.json` 을
직접 쓰려 하면 `PreToolUse` 훅이 막는다. 파일 편집으로 락을 우회할 수 없다.
- **방문 상한** — 노드당 기본 5회. 무한 루프는 런을 실패시킨다.
설정은 `.claude/graph-config.json`:
```json
{
"port": 7788,
"commands": {
"allowlist": ["bun test*", "bun run lint", "uv run pytest*"],
"env_deny": ["ANTHROPIC_API_KEY"],
"inline_wait_ms": 40000
}
}
```
## 언어
UI 는 브라우저 언어를 따른다 — 선호 목록에 한국어가 있으면 한국어, 아니면 영어다.
강제하려면 주소에 `?lang=ko` 또는 `?lang=en` 을 붙인다.
```
http://localhost:7788/?lang=en#t=<ui_token>
```
Claude 가 읽는 것(스킬 프롬프트·슬래시 커맨드·MCP 툴 설명)은 영어다.
## 어디에 저장되나
| 무엇 | 어디 |
|---|---|
| 그래프 정의 | `<프로젝트>/.claude/graphs/<이름>.graph.json` — 코드처럼 커밋한다 |
| 런 · 이력 · 제안 · 감사 | `<프로젝트>/.claude/graph.db` (SQLite) |
| 명령 출력 | `<프로젝트>/.claude/graph-runs/<run_id>/logs/<노드>.v<N>.a<N>.<stream>.log` |
`<프로젝트>` 는 `GRAPH_PROJECT_ROOT`(`${CLAUDE_PROJECT_DIR}`) — 플러그인 폴더가 아니라 작업 중인 프로젝트 루트다.
## 검증
소스를 읽는 것은 검증이 아니다. 이 저장소가 실제로 도는지 보는 방법:
```bash
bun test # 413개 · 단위·통합
bun run typecheck # server · web · scripts 세 설정
bun run smoke # happy-dom 으로 실제 렌더 (빈 화면 회귀 방지)
bun run ui # 헤드리스 Chrome → UI 조작 → 파일이 진짜 바뀌는지
bun run livelog # 명령이 도는 중에 출력이 화면까지 흐르는지
bun run perf # 100 노드에서 팬·줌 프레임 예산 (로컬 측정, CI 제외)
bun run shots # README 스크린샷을 실제 런에서 다시 찍는다 (ko · en 둘 다)
```
`bun run shots` 로 만든 이미지가 이 README 에 박혀 있다. 목업이 아니라 진짜 런의 화면이고,
UI 가 깨지면 스크린샷도 같이 깨진다.
## 문서
- [`docs/spec.ko.md`](docs/spec.ko.md) — 제품 계약. 무엇을 만들 것인가
- [`docs/architecture.md`](docs/architecture.md) — 설계와 13개 불변식. 왜 그렇게 만들었나
- [`docs/decisions.md`](docs/decisions.md) — D-01~D-25. 갈림길마다 무엇을 버렸나
## 개발
```bash
bun install
bun run build # server/web/dist — 커밋한다. 플러그인 설치에는 빌드 단계가 없다
bun run dev # UI 만 따로 (vite)
bun run cli # 서버를 직접 띄운다
```
## 라이선스
MIT — [LICENSE](LICENSE)
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues