이 글은 Claude Opus 4.7 을 이용해 초안이 작성되었으며, 이후 퇴고를 거쳤습니다.


Part 1 에서는 2026년 5월 기준 de-facto 가 된 spec 문서들의 지형도와 best practices 를 정리했습니다. 2편에서는 가상의 Go + Templ + HTMX 기반 To-Do 앱 gotodo 를 새로 부트스트래핑한다고 가정하고, 각 문서를 실제로 어떻게 채우는지 발췌 형태로 따라갑니다.


가상 프로젝트: gotodo#

스택은 다음과 같습니다.

  • Go 1.23 — 표준 라이브러리 중심
  • templ — Go 네이티브 SSR 템플릿 (type-safe)
  • HTMX 2.0 — 클라이언트 JS 최소화
  • SQLite + modernc.org/sqlite — CGO 없는 순수 Go 드라이버

목표는 단순합니다. 할 일 추가/완료/삭제만 되는 SSR 미니멀 앱. 1인 로컬 사용을 가정합니다.


Step 0: git init 직후의 1차 골격#

git init 직후 가장 먼저 만드는 건 파일이 아니라 디렉터리 구조의 합의 입니다. Vertical Slice Architecture(VSA) 를 따른다는 가정으로 다음과 같이 잡습니다.

gotodo/
├── AGENTS.md
├── CLAUDE.md          # -> AGENTS.md (symlink)
├── GEMINI.md          # -> AGENTS.md (symlink)
├── README.md
├── ARCHITECTURE.md
├── DESIGN.md
├── DEVELOPMENT.md
├── Makefile
├── go.mod
├── cmd/server/main.go
├── features/
│   └── task/                # feature slice: 한 폴더에 핸들러+스토어+뷰+테스트
│       ├── handler.go
│       ├── handler_test.go
│       ├── store.go
│       ├── store_test.go
│       └── views.templ
├── internal/
│   ├── db/db.go
│   └── server/server.go
├── migrations/
│   └── 001_create_tasks.sql
├── static/
│   └── htmx.min.js
└── docs/
    ├── adr/0001-htmx-over-spa.md
    └── specs/001-task-crud.md

VSA 채택 이유는 Part 1 에서 가볍게 언급했고, 곧 ADR-0001 로 다시 적습니다. 핵심만 짚으면, 한 변경을 위해 에이전트가 들고 다녀야 할 컨텍스트가 한 폴더 안에 닫혀 있다는 점입니다.


Step 1: README.md — agent-friendly 진입점#

README 는 사람과 에이전트가 동시에 보는 진입점입니다. 3줄 quick start + 무엇/무엇이 아닌지 + 다음에 볼 문서들, 이 세 블록이면 충분합니다.

# gotodo

A minimal SSR-based To-Do app. Go + Templ + HTMX + SQLite.
Single-user, local-first. No JS framework, no build step.

## Quick start

```bash
git clone https://github.com/example/gotodo
cd gotodo
make dev          # http://localhost:8080

What it is / What it isn’t#

  • It is: 학습 목적의 미니멀 SSR 앱. HTMX 의 hypermedia 패턴을 실험합니다.
  • It isn’t: 멀티 유저 SaaS, 모바일 앱, 오프라인 동기화 기능.

Where to go next#

  • AGENTS.md — 에이전트가 따라야 할 규칙 (사람도 읽으세요)
  • ARCHITECTURE.md — 시스템 구조와 도메인 모델
  • DESIGN.md — 시각 디자인 시스템 (컬러, 타이포, 컴포넌트)
  • DEVELOPMENT.md — 매일 쓰는 명령어
  • docs/specs/ — 진행 중인 feature spec
  • docs/adr/ — 큰 의사결정의 기록

README 가 1500줄이 되는 가장 흔한 이유는, "혹시 누가 못 찾을까 봐" 모든 걸 여기에 적기 때문입니다. **다른 문서로 위임하는 1줄 포인터** 가 더 친절합니다.

---

## Step 2: `AGENTS.md` + symlink 설정

`AGENTS.md` 는 단일 진실 원본입니다. 다음은 `gotodo` 의 발췌입니다.

```markdown
# AGENTS.md

이 문서는 사람과 에이전트(Claude Code, Codex CLI, Cursor 등)가
이 repo 에서 일할 때 공통으로 따르는 규칙입니다.

## 1. 프로젝트 한 줄 요약

Go + Templ + HTMX + SQLite 로 만든 SSR 기반 미니멀 To-Do 앱.
싱글 유저, 로컬 우선.

## 2. 자주 쓰는 명령어

| Task         | Command          |
|--------------|------------------|
| 개발 서버    | `make dev`       |
| 테스트       | `make test`      |
| 린트         | `make lint`      |
| 빌드         | `make build`     |
| DB 마이그레이션 | `make migrate` |

세부는 `DEVELOPMENT.md` 참조.

## 3. 디렉터리 한 줄 안내

- `cmd/server/` — main 진입점
- `features/<name>/` — feature slice (handler + store + view + test)
- `internal/db/` — DB 초기화
- `internal/server/` — HTTP 서버, 라우팅
- `migrations/` — SQL 마이그레이션
- `docs/` — ADR 와 spec

자세한 구조와 의도는 `ARCHITECTURE.md` 참조.

## 4. 작업 규칙

### 4-1. Vertical Slice 안에서 일하라

새 feature 는 `features/<name>/` 폴더 안에 닫아야 합니다.
다른 feature 의 코드를 import 하지 마세요. 공통 로직이 필요해지면
먼저 issue 를 열고 논의하세요.

### 4-2. 테스트가 먼저

핸들러와 스토어 변경은 항상 실패하는 테스트 → 통과로 갑니다.
Templ 뷰의 텍스트 변경처럼 명백한 케이스는 예외입니다.

### 4-3. SQL 은 인라인으로, ORM 금지

`database/sql` 표준 라이브러리만 사용합니다. ORM/쿼리빌더는
이 프로젝트의 범위에서 과합니다 (ADR-0002 참조).

### 4-4. 클라이언트 JS 는 HTMX 외에 추가 금지

ADR-0001 의 결정. 새 JS 라이브러리를 추가하고 싶다면 먼저 ADR 로 제안하세요.

## 5. 작업 완료 전 체크리스트

- [ ] `make test` 통과
- [ ] `make lint` 통과 (exit code 0)
- [ ] 변경된 feature 의 `*.templ` 가 `templ generate` 로 재생성됨
- [ ] `docs/specs/` 에 해당하는 spec 이 있고 acceptance criteria 가 만족됨

## 6. 보안/시크릿

- `.env` 와 `*.db` 파일은 절대 커밋하지 않습니다.
- DB 파일 경로는 `GOTODO_DB_PATH` 환경변수로만 받습니다.

## 7. 도구별 보강

### Claude Code
- `~/.claude/commands/release.md` 에 `/release` 가 정의되어 있습니다.
- 릴리스 전 항상 `/release dry-run` 을 먼저 실행하세요.

### Cursor
- `.cursor/rules/templ.mdc` 가 `*.templ` 파일 편집 시 자동 적용됩니다.
- `templ generate` 를 빠뜨리지 않도록 강제합니다.

symlink 설정은 다음 한 번이면 끝입니다.

ln -s AGENTS.md CLAUDE.md
ln -s AGENTS.md GEMINI.md
git add AGENTS.md CLAUDE.md GEMINI.md

이렇게 두면 Claude Code 든 Codex CLI 든 Gemini CLI 든 동일한 규칙을 읽습니다.

Claude Code 의 글로벌 CLAUDE.md 와의 관계#

~/.claude/CLAUDE.md 에 사용자별 글로벌 규칙(예: “한국어 경어체로 답변하라”, “git 커밋 메시지는 Conventional Commits 로”) 이 있다면, 그것은 그대로 둡니다. 프로젝트의 ./CLAUDE.md(→ AGENTS.md) 는 그 위에 쌓이므로, 프로젝트 규칙이 글로벌 규칙을 덮어쓰거나 보완합니다.


Step 3: ARCHITECTURE.md — 도메인 모델과 Templ 컴포넌트 구조#

ARCHITECTURE 는 “조립도” 입니다. 다음은 발췌입니다.

# ARCHITECTURE

## 시스템 다이어그램

```mermaid
flowchart LR
    Browser["Browser<br/>(HTMX)"] -- HTTP --> Server["Go HTTP Server<br/>(net/http)"]
    Server --> Feature["features/task<br/>handler+store+view"]
    Feature --> DB[("SQLite<br/>tasks.db")]
    style Browser fill:#87CEEB,color:#000000
    style Server fill:#90EE90,color:#000000
    style Feature fill:#FFD700,color:#000000
    style DB fill:#FFB6C1,color:#000000
```

## 도메인 모델

가장 중요한 엔티티는 `Task` 하나입니다.

```go
type Task struct {
    ID        int64
    Title     string    // 1..200 chars, trim
    Done      bool
    CreatedAt time.Time // UTC
}
```

제약사항:

- `Title` 은 trim 후 빈 문자열이면 400 응답.
- `Title` 길이는 200자 초과 시 400.
- `Done` 토글은 idempotent.

## HTTP 라우트

| Method | Path                  | 응답                          |
|--------|-----------------------|-------------------------------|
| GET    | `/`                   | 전체 페이지 (full page)        |
| POST   | `/tasks`              | 새 row partial (`<li>`)        |
| POST   | `/tasks/{id}/toggle`  | 갱신된 row partial             |
| DELETE | `/tasks/{id}`         | 빈 응답 (HTMX 가 row 제거)     |

HTMX 의 부분 응답 패턴(out-of-band swap)을 사용합니다. JSON 은 쓰지 않습니다.

## Templ 컴포넌트 구조

- `views.Layout(title)` — 전체 페이지 셸
- `views.TaskList(tasks)``<ul>` 컨테이너
- `views.TaskRow(t)` — 하나의 `<li>` (POST/toggle/delete 의 응답이 곧 이 컴포넌트)
- `views.NewTaskForm()` — 상단 입력 폼

핵심 원칙: **HTTP 핸들러는 한 컴포넌트만 렌더링** 한다. 페이지 한 덩어리를 통째로 반환하는 경로는 `GET /` 뿐.

## 의존성 흐름

```
cmd/server/main.go
  └─ internal/server.New(db)
       └─ features/task.NewHandler(store)
            └─ features/task.NewStore(db)
                 └─ internal/db.Open()
```

각 feature 패키지는 자기 `Store``Handler` 의 인터페이스를 자기 폴더 안에서 정의합니다.
다른 feature 의 internal 패키지를 import 하지 않습니다.

Tip: Mermaid 다이어그램의 배경색을 밝게 쓸 때는 color:#000000 을 함께 지정해야 다크 테마에서도 글자가 보입니다. 이 블로그의 CLAUDE.md 에도 같은 규칙이 적혀 있습니다.


Step 4: DESIGN.md — 시각 디자인 시스템#

DESIGN.md 는 비교적 새 컨벤션입니다. 2025년 후반 Google Stitch 가 표준 포맷 을 제안했고, VoltAgent 의 awesome-design-md 가 Linear, Vercel, Stripe, Notion 등 73개 사이트의 실제 DESIGN.md 를 모아 사실상 보급의 허브 역할을 하고 있습니다.

역할은 한 문장으로 정리됩니다. AGENTS.md 는 “어떻게 빌드하는가”, DESIGN.md 는 “어떤 모양인가” 입니다. 새 화면이나 컴포넌트를 추가할 때 에이전트가 매번 “버튼 색은 뭘로 할까”, “간격은 얼마로 할까” 를 새로 결정하지 않고, 이 파일을 단일 진실 원본으로 참조하게 만드는 게 목표입니다.

다음은 gotodo 의 발췌입니다. 1인 로컬 앱이라 의도적으로 작게 잡았습니다.

# DESIGN

## 1. Visual Theme & Atmosphere

**Terminal-minimal**. CLI 도구를 GUI 로 옮긴 듯한 인상.
이미지 없음, 그라데이션 없음, 애니메이션 최소. 정보 밀도와 빠른 조작감이 미관보다 우선.

## 2. Color Palette & Roles

| Token         | Hex       | Role                                |
|---------------|-----------|--------------------------------------|
| `--bg`        | `#0E1116` | 페이지 배경                          |
| `--surface`   | `#161B22` | 카드/리스트 항목 배경                |
| `--fg`        | `#E6EDF3` | 기본 텍스트                          |
| `--muted`     | `#8B949E` | 보조 텍스트, 완료된 task             |
| `--accent`    | `#3FB950` | 활성 상태, primary button            |
| `--danger`    | `#F85149` | 삭제, 에러 상태                      |
| `--border`    | `#30363D` | 1px 분할선                           |

다크 테마만 지원합니다. 라이트 테마는 v2 에서 검토 예정.

## 3. Typography Rules

전부 시스템 모노스페이스 스택. 별도 웹폰트를 다운로드하지 않습니다.

```css
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo,
             Consolas, "Liberation Mono", monospace;
```

| Element     | Size | Weight | Line-height |
|-------------|------|--------|--------------|
| `<h1>`      | 24px | 600    | 1.3          |
| 본문        | 16px | 400    | 1.5          |
| Task title  | 16px | 400    | 1.4          |
| Hint/meta   | 13px | 400    | 1.4          |

## 4. Component Stylings

### Button — Primary (`+ Add`)
- bg: `--accent`, fg: `--bg`, padding: `8px 16px`, radius: `4px`
- Hover: opacity 0.9
- Disabled: opacity 0.4, cursor not-allowed

### Button — Danger (`✕`)
- bg: transparent, fg: `--danger`, radius: `4px`
- Hover: bg `rgba(248, 81, 73, 0.1)`

### Text Input
- bg: `--surface`, fg: `--fg`, border: 1px solid `--border`, radius: `4px`
- Focus: border-color `--accent`, outline 없음
- Placeholder: `--muted`

### Task Row (`<li>`)
- 가로 layout: `[checkbox] [title] ........ [delete]`
- padding: `12px 16px`, border-bottom: 1px solid `--border`
- 완료된 task: title 에 `text-decoration: line-through`, color `--muted`

## 5. Layout Principles

- **Spacing scale**: 4 / 8 / 12 / 16 / 24 / 32 (8px base, 4 와 12 만 예외)
- **Container**: max-width 640px, 가운데 정렬 (1인 앱은 좁은 폭이 자연스럽다)
- **Whitespace**: 항목 사이 0, 섹션 사이 24px. 빽빽함을 두려워하지 않는다.

## 6. Depth & Elevation

평면적 디자인을 유지합니다. shadow 는 다음 두 경우만 허용합니다.

- focus 가 들어간 input: `0 0 0 2px rgba(63, 185, 80, 0.3)`
- 에러 토스트(있다면): `0 4px 12px rgba(0, 0, 0, 0.4)`

## 7. Do's and Don'ts

**Do**
- 모노스페이스 폰트로 일관된 그리드 정렬을 유지한다.
- 상태 변화는 색으로 표현한다 (애니메이션 대신).
- 모든 상호작용은 키보드로도 가능해야 한다 (Tab/Enter/Space).

**Don't**
- 그라데이션, 이미지, 아이콘 폰트를 추가하지 않는다 (절대).
- 라이트 테마용 색을 임의로 도입하지 않는다 (ADR 로 제안 후).
- transition 시간을 200ms 보다 길게 두지 않는다.

## 8. Responsive Behavior

단일 컬럼 레이아웃이라 별도 breakpoint 가 거의 필요 없습니다.

- `< 480px`: container padding 16px → 8px
- 터치 타깃 최소 44×44px (delete 버튼 포함)

## 9. Agent Prompt Guide

새 UI 컴포넌트를 만들 때 에이전트에 던질 짧은 프롬프트 템플릿:

> Style this component using the tokens in `DESIGN.md`.
> Use `--accent` only for the primary action. Match the existing
> `TaskRow` density. Mono font, no images, no gradients.

색만 빨리 참조하고 싶을 때:

> Primary action → `--accent` (#3FB950). Destructive → `--danger` (#F85149).
> Surfaces → `--bg` / `--surface`. Text → `--fg` / `--muted`.

왜 이 9개 섹션인가#

awesome-design-md 의 모든 예제가 같은 9개 섹션을 가집니다. 처음에는 “한 페이지짜리 앱에 9개나?” 싶지만, 막상 적어 보면 각 섹션이 매우 짧아도 충분합니다(gotodo 의 위 예제는 전체가 100줄 이하). 중요한 건 에이전트가 헤매지 않도록 미리 결정해 두는 것 이지, 결정의 양이 아닙니다.

Templ 컴포넌트가 토큰을 참조하게 만들기#

DESIGN.md 만 두면 잊혀집니다. 토큰을 실제 CSS 로 옮기고, Templ 컴포넌트가 그 토큰만 사용하게 강제해야 살아 있는 문서가 됩니다.

<!-- static/tokens.css : DESIGN.md 의 토큰을 그대로 옮긴 단일 파일 -->
:root {
  --bg: #0E1116;
  --surface: #161B22;
  --fg: #E6EDF3;
  --muted: #8B949E;
  --accent: #3FB950;
  --danger: #F85149;
  --border: #30363D;
}
// features/task/views.templ (발췌)
templ TaskRow(t Task) {
  <li class="task-row">
    <button class="btn-toggle"
            hx-post={ fmt.Sprintf("/tasks/%d/toggle", t.ID) }
            hx-target="closest li" hx-swap="outerHTML">
      if t.Done {  } else {  }
    </button>
    <span class={ "title", templ.KV("done", t.Done) }>{ t.Title }</span>
    <button class="btn-danger"
            hx-delete={ fmt.Sprintf("/tasks/%d", t.ID) }
            hx-target="closest li" hx-swap="delete"></button>
  </li>
}

이러면 새 컴포넌트를 만들 때도 에이전트가 tokens.css 의 변수만 쓰게 됩니다.

awesome-design-md 활용 팁#

처음 DESIGN.md 를 쓰는 사람에게 가장 막막한 부분은 “톤” 입니다. 그럴 때는 awesome-design-md 에서 자기 프로젝트의 톤과 가까운 사이트를 골라 그 DESIGN.md 를 그대로 복사한 뒤 토큰만 바꿔 시작 하는 게 빠릅니다. 예를 들어 gotodo 처럼 미니멀/모노스페이스 톤이라면 Vercel 이나 Ollama 의 DESIGN.md 가 좋은 출발점입니다.

한 가지 주의. awesome-design-md 의 DESIGN.md 들은 마케팅 사이트 기준이라 섹션이 풍부합니다. 1인 앱이나 내부 도구에는 그대로 가져오면 과합니다. 자기 프로젝트 규모에 맞춰 5~10% 까지 줄이는 것을 두려워하지 마세요.


Step 5: 첫 ADR — docs/adr/0001-htmx-over-spa.md#

ADR 은 짧을수록 좋습니다. Michael Nygard 포맷을 거의 그대로 씁니다.

# ADR-0001: HTMX over SPA

## Status

Accepted (2026-05-28)

## Context

`gotodo` 는 1인 로컬 사용을 가정한 학습 프로젝트입니다.
SPA 를 채택하면 다음이 따라옵니다.

- Node.js 빌드 파이프라인 (vite/esbuild)
- 클라이언트 라우팅
- JSON API 와 SSR 의 이원화

이 모든 비용이 학습 목적과 1인 사용 가정에 비추어 과합니다.

## Decision

다음을 채택합니다.

- 모든 페이지/부분 응답은 서버에서 HTML 로 렌더링한다 (templ).
- 인터랙션은 HTMX 의 attribute 만으로 작성한다 (`hx-post`, `hx-target`, `hx-swap`).
- 추가 클라이언트 JS 라이브러리는 금지한다.

## Consequences

### Positive
- 빌드 파이프라인이 `make build` 한 줄로 끝난다.
- 핸들러가 반환하는 응답이 곧 사용자에게 보이는 화면이라 디버깅이 쉽다.
- 에이전트가 "JSON 응답을 SPA 가 어떻게 그릴까" 를 추측할 필요가 없다.

### Negative
- 복잡한 클라이언트 상태가 필요한 화면(드래그앤드롭, 오프라인 큐 등)이 생기면 재검토 필요.
- HTMX 의 OOB swap 패턴에 익숙해지는 학습 비용.

## Alternatives considered

- **Next.js (App Router)** — 빌드 파이프라인 비용 과다.
- **Alpine.js + plain JSON API** — 응답 형태 이원화로 핸들러가 두 가지 모드를 가져야 함.
- **Vanilla JS + fetch** — 작성 비용은 낮지만 일관된 패턴을 강제하기 어려움.

ADR 을 적어 두면, 6개월 뒤 에이전트에게 “React 로 바꿔 줘” 라는 요청이 들어왔을 때 “이 결정은 ADR-0001 에 의해 이미 거부된 옵션입니다” 라고 답할 근거가 생깁니다.


Step 6: DEVELOPMENT.md — 매일 쓰는 명령어#

AGENTS.md 의 명령어 표는 매우 짧게, 자세한 흐름은 DEVELOPMENT.md 에 둡니다.

# DEVELOPMENT

## 사전 요구사항

- Go 1.23+
- `templ` CLI (`go install github.com/a-h/templ/cmd/templ@latest`)
- `golangci-lint` (`brew install golangci-lint`)

## 자주 쓰는 명령어

```bash
make dev          # templ generate --watch + air (http://localhost:8080)
make test         # go test ./...
make lint         # golangci-lint run
make build        # CGO_DISABLED=1 go build -o bin/gotodo ./cmd/server
make migrate      # 누적된 migrations/*.sql 을 순서대로 적용
make clean        # bin/, *.db, templ 생성물 제거
```

## 환경변수

| 변수                | 기본값         | 설명                |
|---------------------|----------------|---------------------|
| `GOTODO_DB_PATH`    | `./gotodo.db`  | SQLite 파일 경로     |
| `GOTODO_LISTEN_ADDR`| `:8080`        | 서버 바인딩 주소     |

`.env.example` 를 복사해서 `.env` 를 만들면 `make dev` 가 자동으로 로드합니다.

## 테스트 작성 규칙

- 핸들러 테스트는 `httptest.NewServer` 로 실제 라우터에 붙입니다 (mock 금지).
- 스토어 테스트는 임시 SQLite 파일로 돌립니다 (`t.TempDir()`).
- 통합 테스트가 5\~10초 안에 끝나는 한, 모킹보다 실제 의존성을 선호합니다.

## 커밋 컨벤션

[Conventional Commits](https://www.conventionalcommits.org/).
PR 제목도 같은 규칙을 따릅니다. `commitlint` 가 CI 에서 검증합니다.

```
feat(task): add toggle endpoint
fix(store): handle empty title after trim
docs(adr): record HTMX-over-SPA decision
```

Step 7: 첫 feature spec — docs/specs/001-task-crud.md#

feature 단위 spec 은 짧고 검증 가능해야 합니다. 다음은 발췌입니다.

# SPEC-001: Task CRUD

## Background

`gotodo` 의 최소 기능 단위. 사용자가 할 일을 추가/완료/삭제할 수 있어야 한다.

## Goals

- 한 페이지에서 할 일을 입력하고 즉시 목록에 추가한다 (페이지 새로고침 없이).
- 각 항목을 클릭/체크하면 완료 상태가 토글된다.
- 삭제 버튼으로 항목을 제거한다.
- 모든 변경은 SQLite 에 즉시 반영된다.

## Non-goals

- 사용자 인증
- 마감일/우선순위
- 다중 사용자, 다중 디바이스 동기화

## Acceptance criteria

- [ ] `GET /` 가 현재 할 일 목록과 새 항목 입력 폼을 렌더링한다.
- [ ] `POST /tasks``title` 폼 값을 받아 새 항목을 저장하고, `TaskRow` 부분 응답을 반환한다.
- [ ] `title` 이 trim 후 빈 문자열이면 400 을 반환한다.
- [ ] `title` 길이가 200자 초과면 400 을 반환한다.
- [ ] `POST /tasks/{id}/toggle``Done` 을 뒤집고 갱신된 `TaskRow` 를 반환한다.
- [ ] `DELETE /tasks/{id}` 가 항목을 제거하고 빈 응답을 반환한다 (HTMX 가 DOM 에서 제거).
- [ ] 위 모든 동작에 대한 핸들러/스토어 테스트가 있다.

## Open questions

- 동일한 title 을 가진 항목을 허용할 것인가? → **허용**. 사용자가 일부러 둘 수 있음.
- 정렬 기준은? → `CreatedAt DESC` 로 시작. 나중에 spec 으로 분리 가능.

이 spec 1장이 있으면, 에이전트가 첫 작업을 시작할 때 어디까지가 범위이고 어디부터가 다른 spec 인지 명확해집니다.


검증: Claude Code 에 작업을 시켜 보기#

여기까지 부트스트래핑이 끝났습니다. 진짜 가치가 나오는 건 다음 순간입니다. 빈 features/task/ 폴더로 가서, 에이전트에게 이렇게만 던집니다.

docs/specs/001-task-crud.md 를 보고 task feature 를 구현해 주세요.

부트스트래핑이 잘 되어 있는 repo 에서 에이전트가 보이는 행동은 대략 다음과 같습니다.

  1. AGENTS.md 부터 읽고, “VSA 안에서 일하라”, “테스트 먼저”, “ORM 금지”, “HTMX 외 JS 금지” 같은 규칙을 컨텍스트에 적재합니다.
  2. ARCHITECTURE.md 의 라우트 표와 Templ 컴포넌트 구조를 확인, 어떤 핸들러가 어떤 컴포넌트를 반환해야 하는지 파악합니다.
  3. DESIGN.md 의 토큰과 컴포넌트 스타일을 확인, 새 마크업에 임의의 색이나 폰트를 도입하지 않고 tokens.css 의 변수만 참조합니다.
  4. docs/specs/001-task-crud.md 의 acceptance criteria 를 그대로 테스트 케이스로 풀어 먼저 작성합니다.
  5. 빨간 테스트를 통과시키는 최소 구현을 features/task/ 안에서 작성합니다.
  6. make testmake lint 를 직접 돌려 보고 결과를 확인합니다.
  7. ADR-0001 을 근거로, 도중에 “여기서 Alpine.js 를 추가하면 편할 것 같은데” 같은 일탈을 스스로 거부합니다.

부트스트래핑이 부실하면 위 흐름의 절반 이상이 사용자와의 핑퐁(“테스트 먼저 작성해 주세요”, “ORM 쓰지 마세요”, “이 폴더 안에서만 작업해 주세요”) 으로 채워집니다. 매번 같은 말을 반복하는 대신, 문서에 한 번 적어 두는 편이 훨씬 쌉니다.


부트스트래핑 체크리스트#

여러분의 다음 신규 프로젝트에 가져다 쓸 수 있는 한 장 짜리 체크리스트로 정리합니다.

Day 1 (git init 직후)#

  • README.md — 3줄 quick start + 무엇/무엇이 아닌지 + 다음 문서 포인터
  • AGENTS.md — 200~400줄 이내, 자주 쓰는 명령 표, 디렉터리 한 줄 안내, 작업 규칙, 완료 체크리스트
  • CLAUDE.md / GEMINI.mdAGENTS.md 로의 symlink (또는 짧은 보강 파일)
  • ARCHITECTURE.md — 시스템 다이어그램(Mermaid), 도메인 모델, 의존성 흐름
  • DESIGN.md — UI 가 있는 프로젝트라면 Stitch 9개 섹션. awesome-design-md 의 유사 톤 사이트에서 출발해도 좋음
  • DEVELOPMENT.md — 빌드/테스트/실행 명령, 환경변수, 커밋 컨벤션
  • Makefiledev / test / lint / build 최소 4개 타깃
  • .gitignore — 시크릿/빌드 결과물/DB 파일 제외

첫 feature 시작 전#

  • docs/adr/0001-*.md — 가장 큰 첫 의사결정(스택 선택, 아키텍처 패턴) 기록
  • docs/specs/001-*.md — 첫 feature 의 Background/Goals/Non-goals/Acceptance criteria

자동 검증 장치 (있으면 좋음)#

  • CI 에서 README.md 의 quick start 명령이 실제로 동작하는지 검증
  • CI 에서 make test / make lint 강제
  • commitlint 또는 PR title lint 로 커밋 메시지 컨벤션 강제
  • templ generate 같은 코드젠 출력물의 dirty diff 검출

1~2개월 뒤 주기적으로 점검#

  • AGENTS.md 가 600줄을 넘기지 않았는가? → 넘었다면 분리
  • 같은 정보가 두 문서에 중복되어 있지 않은가?
  • 완료된 spec 은 docs/specs/archive/ 로 이동했는가?
  • ADR 이 6개월 이상 새 항목 없이 멈춰 있지는 않은가? (의사결정 자체가 멈췄는지 점검)

마무리#

2년 전이라면 신규 git repo 의 1일 차 작업은 “README 작성 + go mod init” 두 줄로 끝났습니다. 지금은 AGENTS.md 를 시작으로 한 spec 문서 셋이 그만큼의 자리를 차지합니다. 부담스럽게 들릴 수 있지만, 실제로는 정반대입니다. 매 세션마다 같은 규칙을 사람이 반복해서 말하지 않게 만드는 일회성 비용입니다.

핵심은 다음 세 가지로 요약됩니다.

  1. AGENTS.md 를 단일 진실 원본으로 두고 도구별 파일은 symlink 또는 짧은 보강으로.
  2. 정보 유형별로 1차 거주지 1곳 — 같은 문장을 두 문서에 적지 말기.
  3. 검증 가능한 명령어와 acceptance criteria — 에이전트는 실행해서 결과를 보는 쪽으로 자연스럽게 흐릅니다.

이 정도만 지키면, 에이전트가 만드는 결과물의 품질이 운에서 규율로 옮겨갑니다. 여러분의 다음 신규 프로젝트에서 시도해 보시면, 첫 PR 의 모양이 꽤 달라질 겁니다.

다음 새 repo 만들 때 위 체크리스트를 한 번 꺼내 보시기 바랍니다.