essai = essay + AI. 글쓰기에 AI를 더하다.
AI 소설 작성 프레임워크. 작가가 통제하는 글쓰기 — 모델 독립적, 언어 독립적, 장르 독립적.
# 프로젝트 생성
essai init my-novel
cd my-novel
# 글로벌 기본값 설정 (모든 신규 프로젝트에 상속)
essai config set -g defaultBaseUrl https://api.z.ai/api/coding/paas/v4
essai config set -g defaultApiKey sk-...
essai config set -g defaultModel glm-5.1
essai config set -g defaultLanguage ko
# 또는 프로젝트별 설정 (essai.json에 직접 기록)
essai config set llm.model glm-5.1
essai config set llm.apiKey sk-...
# 성경(bible) 초기화 후 1장 작성
essai bible init romance
essai write next
# 웹 UI 실행 — http://localhost:7331
essai serve
# 또는 터미널 UI
essai tui- 언어: TypeScript (엄격 모드)
- AI: Vercel AI SDK (ai + @ai-sdk/openai-compatible)
- CLI/TUI: Commander.js + Ink 7 (React 19)
- Web: Next.js 15 (localhost:7331 via
essai serve) - Validator: 정적 일관성 검사 (
bible/world.md기반, LLM 없음) - 모노레포: pnpm workspaces + Turborepo
- 린트/타입: Biome, TypeScript strict, Zod
- CI: GitHub Actions (build · typecheck · lint · test)
essai/
├── packages/
│ ├── core/ # 코어 로직 (순수 TS, UI 의존성 제로)
│ ├── cli/ # CLI (Commander.js + Ink)
│ ├── tui/ # TUI (Ink, Phase 5)
│ └── web/ # Web (Next.js)
├── templates/ # Bible 템플릿
└── docs/ # 설계 문서
| 명령 | 설명 |
|---|---|
init [name] |
새 essai 프로젝트 생성 |
config set <key> <value> |
설정값 쓰기 (-g로 글로벌) |
config get <key> |
설정값 읽기 |
config show |
전체 essai.json 출력 |
config export [--redact] |
글로벌 설정 JSON 덤프 (--redact: apiKey 마스킹) |
config import [file] [--merge] [--skip-api-key] |
글로벌 설정 JSON 교체/병합 (파일 또는 stdin) |
write <chapter> |
챕터 작성 (숫자 또는 next) |
read <chapter> |
챕터 출력 |
list |
작성된 챕터 목록 + 글자 수 |
status |
프로젝트 진행 상황 |
context <chapter> |
챕터 작성 시 주입될 컨텍스트 미리보기 |
rewrite <chapter> |
챕터 처음부터 다시 생성 (덮어쓰기, -i 지시문, 자동 .bak 백업) |
review <chapter> |
챕터 품질 피드백 (-r 커스텀 룰) |
validate <chapter> |
정적 일관성 검사 (--disable <rule>, 언어별 룰: korean-register, english-em-dash, mixed-script-punctuation) |
audit <chapter> |
LLM 8차원 연속성 감사 (--only dim1,dim2) |
export |
모든 챕터를 단일 파일로 (-f md|txt) |
serve |
웹 UI 시작 (-p, --start) |
tui |
터미널 UI (Ink) 시작 |
bible init/show/edit/validate/add/agent |
bible/ 폴더 관리 (bible init <template> --agent / bible agent로 AI 대화형 생성) |
-i, --instruction <text>— 작가 지시문 추가--raw— 파이프라인 건너뛰고 글만 작성 (review/fix 생략)--no-fix— review는 수행하되 자동 수정은 생략
Next.js 웹 UI를 실행한다. 기본 포트 7331 — http://localhost:7331
-p, --port <port>— 포트 지정--start— dev 대신 프로덕션 서버 (next build선행 필요)
각 프로젝트는 essai.json을 가진다. 공통 기본값은 글로벌 설정에서 가져온다.
LLM 기본값, 언어, 그리고 생성된 프로젝트 목록을 보관한다. config set -g로 편집하거나 직접 수정할 수 있다.
| 키 | 설명 |
|---|---|
defaultBaseUrl |
LLM API 엔드포인트 |
defaultApiKey |
LLM API 키 |
defaultModel |
모델 이름 |
defaultLanguage |
기본 출력 언어 (ko, en, ja, zh 등 — 코드에서 언어 목록 고정하지 않음) |
defaultChapterWords |
챕터당 목표 글자 수 |
defaultTemperature |
샘플링 온도 |
| 키 | 설명 |
|---|---|
llm.baseUrl / llm.apiKey / llm.model |
LLM 설정 (글로벌보다 우선) |
llm.temperature / llm.maxTokens / llm.thinkingEnabled |
생성 파라미터 |
language |
출력 언어 |
chapterWords |
챕터당 목표 글자 수 |
프로젝트별 essai.json이 글로벌 기본값보다 우선한다.
전체 설계는 docs/design.md를 참고.
bible/world.md에 작가가 정의한 세계관을 두면 essai validate <chapter>가 정적(비-LLM) 검사를 수행한다. docs/validation-future-work.md의 제안 구현.
# world.md 예시
## 공간
- 분식집: 1층 (101호)
- 도윤: 302호 (3층)
- 산링: 203호 (2층)
## 소품 규칙
- 출입: 도어락. 열쇠 ❌
- 통신: 카톡
## 타임라인
- 입국: 9월 / 귀국: 3월 / 총 6개월검사 항목 (언어 무관):
- floor-consistency — "벽 하나 사이" 인물이 다른 층에 살 때
- forbidden-props —
world.md가 금지한 소품이 본문에 등장할 때 - visa-duration — 비자 종류 vs 체류 기간 불일치
- mixed-script-punctuation — 한글 문단이 ASCII 직견따옴표(
"…")를 쓸 때
검사 항목 (언어별):
- korean-register (ko) — 한 챕터 안에서
-습니다(격식체)와반가워/좋아/그래(해요체/반말)가 혼용될 때 - english-em-dash (en) — 한 문단에 em-dash(
—) 3개 이상 (AI 텔)
$ essai validate 1
✗ [floor-consistency] Adjacency claim between "도윤" (floor 3) and "산링" (floor 2)
⚠ [forbidden-props] Text mixes "도어락" (keyless) with "열쇠" (key)
⚠ [visa-duration] Visa type matched (H-?1...) typically allows ~6 months, but text mentions 12 months정적 validator가 잡지 못하는 의미적 일관성 문제를 LLM이 검사합니다. 8개 차원을 순회하며 각각 한 줄 JSON 평결을 반환합니다.
$ essai audit 3 # 8개 차원 전부
$ essai audit 3 --only pacing,craft-rule-violations차원:
- character-consistency — 캐릭터 말투/성격/애착 유형이 bible과 다른지
- timeline — 시간 역행, 동일 일 불가능 사건, 계절 불일치
- setting-conflict — 공간 레이아웃, 거리, 소품의 이전 설정 충돌
- emotion-continuity — 감정선이 자연스럽게 이어지는지
- language-progression — 언어 능력 진행 (외국인 한국어 학습자 등)
- pacing — 로맨스 아크의 한 비트라도 전진하는지, padding 아닌지
- information-barrier — 캐릭터가 알 수 없는 정보에 기반해 행동하는 "작가 누출"
- craft-rule-violations — show/tell 위반, 비유 과다, padding
웹 UI에서도 같은 결과를 "정적 검증"/"LLM 감사" 탭으로 볼 수 있고 "결과 복사" 버튼으로 클립보드에 마크다운 요약이 복사됩니다.
{ "llm": { "model": "glm-5.1", "baseUrl": "https://api.example.com/v4", "apiKey": "sk-..." }, "language": "ko", "chapterWords": 3000, "projects": [ { "name": "my-novel", "path": "/path/to/my-novel", "id": "my-novel-abc123" } ] }