
anki
Anki 카드 분할 스킬. 정보 밀도 높은 Anki 카드를 원자적 단위로 분할.사용 시점: (1) 사용자가 /anki 명령 실행, (2) Anki 카드 분할/분석 요청,(3) An
Awesome Anki
<img width="1719" height="983" alt="Awesome Anki 메인 화면" src="https://github.com/user-attachments/assets/6af494b7-0395-43d7-a41c-9a614c251047" />Awesome Anki는 **Anki 노트를 학습 효율이 높은 원자 카드(Atomic Card)**로 분할하고, 검증하고, 필요 시 복구(롤백)할 수 있는 로컬 우선 웹 애플리케이션입니다.
목차
- 1. 프로젝트 소개
- 2. 핵심 기능
- 3. 기술 스택
- 4. 모노레포 구조
- 5. 빠른 시작
- 6. 실행 방법
- 7. 환경 변수
- 8. 개발 DX 도구
- 9. API 레퍼런스
- 10. 품질 검증
- 11. 운영/트러블슈팅 체크
- 12. 자가 호스팅 (Self-Host)
- 13. 참고 링크
- 14. 라이선스
1. 프로젝트 소개
기존 Anki 카드에 정보가 과도하게 밀집되면 복습 효율이 떨어질 수 있습니다. Awesome Anki는 다음 흐름으로 이 문제를 해결합니다.
- 카드 구조를 분석해 분할 가능 여부를 판단합니다.
- AI(Gemini/OpenAI)로 카드를 의미 단위로 분리합니다.
- 분할 전 백업을 생성하고, 적용 실패 시 자동 롤백합니다.
- 팩트/최신성/유사성/문맥 검증으로 결과 품질을 점검합니다.
2. 핵심 기능
2.1 카드 분할
- AI Split: Gemini 또는 OpenAI를 사용해 비정형 텍스트를 의미 단위로 분할
- 멀티 프로바이더: 웹 UI에서 프로바이더/모델 선택, 모델별 결과 비교 가능
- 비용 가시화: 분석 전 비용 추정, 분석 후 실측 비용 + 토큰 사용량 표시
- 예산 가드레일: 서버 사이드 예산 상한으로 과도한 비용 방지
- Preview / Apply 분리: 적용 전 미리보기로 결과 확인 가능
- 학습 데이터 복제: 분할 후 카드에 스케줄링 정보 복제 시도
2.2 검증
- Fact Check: 카드 내용의 사실성 점검
- Freshness: 최신성 점검(기준 날짜 기반)
- Similarity: Jaccard + 임베딩 기반 유사 카드 탐지
- Context: nid 링크 기반 문맥 일관성 점검
- All-in-one 검증: 단일 요청으로 통합 검증 실행
2.3 안정성
- 분할 전 백업(
preBackup) 필수 생성 - 적용 실패 시 자동 롤백
- 손상 백업 파일 자동 격리(
.corrupt-*) - 원클릭 수동 롤백 API 제공
2.4 프롬프트 운영
- 프롬프트 버전 생성/수정/활성화/삭제
- 시스템 프롬프트 원격 SoT 저장 (
awesomeAnki.prompts.system) expectedRevision기반 CAS 충돌 제어 (409반환)- systemPrompt 저장 성공 시 즉시 Anki
sync()실행 - 분할 히스토리 저장/조회
- 실패 패턴 분석
- A/B 실험(Experiment) 생성 및 완료 처리
2.5 보안
/api/health를 제외한 API는ANKI_SPLITTER_API_KEY인증 필요
3. 기술 스택
| 영역 | 기술 |
|---|---|
| 런타임 | Bun |
| 언어 | TypeScript |
| 서버 | Hono |
| 웹 | React 19 + Vite |
| 상태 관리 | TanStack Query |
| 스타일링 | Tailwind CSS v4 |
| 렌더링 | markdown-it + KaTeX |
| LLM | Google Gemini + OpenAI |
| 연동 | AnkiConnect |
4. 모노레포 구조
awesome-anki/
├── src/ # 루트 CLI 엔트리
├── packages/
│ ├── core/ # 도메인 로직(분할/검증/백업)
│ ├── server/ # Hono REST API
│ └── web/ # React + Vite 웹 UI
├── output/ # 런타임 산출물(백업, 임베딩 캐시, 프롬프트 버전/legacy 기록)
├── docs/ # 아키텍처/기능/트러블슈팅 문서
└── templates/ # 카드 템플릿 리소스
5. 빠른 시작
5.1 사전 요구사항
5.2 설치
git clone https://github.com/greenheadHQ/awesome-anki.git
cd awesome-anki
bun install
5.3 환경 설정
cp .env.example .env
실제 운영값은 이 저장소 기준으로 .envrc에서 export 관리하며, 비밀값은 secrets/*.age로 암호화 관리합니다.
6. 실행 방법
6.1 웹 GUI (권장)
# 서버 + 웹 동시 실행
bun run dev
# 서버만 실행 (기본: 3000)
bun run dev:server
# 웹만 실행 (기본: 5173)
bun run dev:web
6.2 CLI
# 연결 상태 확인
bun run cli:status
# 덱 분할 미리보기
bun run cli:split
# 덱 분할 적용
bun run cli:split -- --apply
# 특정 노트 분할
bun run cli split --note <noteId>
# 분석 명령 (내부용)
bun run cli analyze <deckName> [noteId]
# 백업 목록/롤백
bun run cli backups
bun run cli rollback <backupId>
7. 환경 변수
7.1 핵심 서버/도메인 변수
| 변수 | 설명 |
|---|---|
GEMINI_API_KEY | Gemini API 키 (split/validation에서 Gemini 사용 시 필요) |
OPENAI_API_KEY | OpenAI API 키 (임베딩 필수, split/validation에서 OpenAI 사용 시 필요) |
ANKI_SPLITTER_API_KEY | 서버 API 인증 키 |
ANKI_CONNECT_URL | AnkiConnect URL |
ANKI_CONNECT_VERSION | AnkiConnect 버전(기본 6) |
TARGET_DECK | 기본 대상 덱 |
SPLIT_HISTORY_DB_PATH | 분할 이력 SQLite 파일 경로 (기본 data/split-history.db) |
HISTORY_SYNC_MODE | 히스토리 동기화 모드 (local / remote) |
ANKI_SPLITTER_DEFAULT_LLM_PROVIDER | 기본 LLM 프로바이더 (gemini / openai, 기본 gemini) |
ANKI_SPLITTER_DEFAULT_LLM_MODEL | 기본 LLM 모델 (기본 gemini-3-flash-preview) |
ANKI_SPLITTER_BUDGET_CAP_USD | 서버 사이드 예산 상한 USD (기본 1.0) |
7.2 웹/개발 변수
| 변수 | 설명 |
|---|---|
VITE_API_URL | 웹에서 직접 호출할 API 베이스 URL |
VITE_API_PROXY_TARGET | Vite dev 프록시 타깃(기본 http://localhost:3000) |
VITE_LOCATOR_TARGET | Locator 에디터 타깃 (cursor/vscode) |
VITE_DISABLE_LOCATOR | Locator 강제 비활성화 |
8. 개발 DX 도구
이 섹션은 LocatorJS를 실제로 어떻게 켜고 끄는지, 어떤 설정값이 영향을 주는지를 정리합니다.
8.1 공통 동작 원칙
- LocatorJS는
packages/web/src/main.tsx에서import.meta.env.DEV조건으로만 초기화됩니다. - 즉,
bun run dev일 때만 동작하고bun run build산출물에서는 실행되지 않습니다. - 비활성화는 아래 환경변수로 즉시 제어할 수 있습니다.
VITE_DISABLE_LOCATOR=true
8.2 LocatorJS (브라우저 → 에디터 점프)
설정 방법
- 런타임 패키지 설치
@locator/runtime
- Vite Babel 체인에 data-id 플러그인 연결
@locator/babel-jsx/dist- 개발 모드에서만 적용 (
mode === "development")
- 런타임 초기화
setupLocatorUI({ targets, showIntro: false })showIntro: false로 온보딩 팝업 비활성화
- 에디터 타깃 선택
- 기본:
VITE_LOCATOR_TARGET=cursor - 전환:
VITE_LOCATOR_TARGET=vscode
- 기본:
사용 방법
bun run dev실행- 브라우저에서 점프하려는 컴포넌트 위에 마우스를 올림
- macOS 기준
Option + Click실행 - 설정된 에디터(Cursor/VS Code)에서 해당 파일+라인으로 이동
점검 포인트
- 점프가 안 되면 먼저
VITE_DISABLE_LOCATOR가true인지 확인 - 반드시 Vite 개발 서버(
bun run dev또는bun run dev:web)에서 테스트 - 소스 메타가 누락되면
packages/web/vite.config.ts의 Babel 플러그인 설정 확인
8.3 권장 운영 시나리오
- 평소: Locator 활용 (기본 활성)
- 불필요 시:
VITE_DISABLE_LOCATOR=true로 비활성화
9. API 레퍼런스
9.1 인증
/api/health를 제외한 API는 인증 필요- 인증 방법:
X-API-Key: <ANKI_SPLITTER_API_KEY>Authorization: Bearer <ANKI_SPLITTER_API_KEY>
9.2 공통
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/health | 서버 헬스 체크 |
9.3 Deck / Card
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/decks | 덱 목록 |
| GET | /api/decks/:name/stats | 덱 통계 |
| GET | /api/cards/deck/:name | 덱 카드 목록 |
| GET | /api/cards/deck/:name/difficult | 어려운 카드 목록 |
| GET | /api/cards/:noteId | 단일 카드 상세 |
9.4 Split / History / Backup / Media
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/llm/models | 사용 가능 LLM 모델/가격 조회 |
| POST | /api/split/preview | 분할 미리보기 (provider/model/budgetUsdCap 선택 가능, 예산 초과 시 HTTP 402) |
| POST | /api/split/apply | 분할 적용 |
| POST | /api/split/reject | 분할 반려 처리 |
| GET | /api/history | 분할 이력 목록 조회 |
| GET | /api/history/:sessionId | 분할 이력 상세 조회 |
| GET | /api/history/sync/health | 히스토리 동기화 상태 |
| GET | /api/backup | 백업 목록 |
| GET | /api/backup/latest | 최신 백업 ID |
| POST | /api/backup/:id/rollback | 롤백 실행 |
| GET | /api/media/:filename | Anki 미디어 프록시 |
9.5 Clinic
| 메서드 | 경로 | 설명 |
|---|---|---|
| POST | /api/clinic/fact-check | 팩트 체크 |
| POST | /api/clinic/freshness | 최신성 검사 |
| POST | /api/clinic/similarity | 유사성 검사 |
| POST | /api/clinic/context | 문맥 검사 |
| POST | /api/clinic/yagni | YAGNI 검사 |
| POST | /api/clinic/all | 통합 검증 |
| POST | /api/clinic/fix/apply | 검증 결과 수정 적용 |
9.6 Embedding
| 메서드 | 경로 | 설명 |
|---|---|---|
| POST | /api/embedding/generate | 덱 임베딩 생성/갱신 |
| GET | /api/embedding/status/:deckName | 임베딩 캐시 상태 |
| DELETE | /api/embedding/cache/:deckName | 캐시 삭제 |
| POST | /api/embedding/single | 단일 텍스트 임베딩(디버그용) |
임베딩 API 응답은 공통 envelope를 사용합니다:
- 성공:
ok=true,schemaVersion,requestId,timestamp(ISO 8601),data - 실패:
ok=false,schemaVersion,requestId,timestamp(ISO 8601),error.code/message/retryable POST /api/embedding/generate는 부분 실패 시에도 HTTP 200을 유지하고data.status=completed_with_errors와data.failures[]로 상세를 반환합니다.
9.7 Prompt Ops
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /api/prompts/system | 원격 systemPrompt + revision 조회 |
| POST | /api/prompts/system | CAS 기반 systemPrompt 저장 + sync |
| GET | /api/prompts/versions | 프롬프트 버전 목록 |
| GET | /api/prompts/versions/:id | 버전 상세 |
| POST | /api/prompts/versions | 버전 생성 |
| PUT | /api/prompts/versions/:id | 버전 수정 (systemPrompt 수정 불가) |
| DELETE | /api/prompts/versions/:id | 버전 삭제 |
| POST | /api/prompts/versions/:id/activate | 버전 활성화 |
| GET | /api/prompts/active | 현재 활성 버전 조회 |
| GET | /api/prompts/versions/:id/failure-patterns | 실패 패턴 분석 |
| GET | /api/prompts/experiments | 실험 목록 |
| GET | /api/prompts/experiments/:id | 실험 상세 |
| POST | /api/prompts/experiments | 실험 생성 |
| POST | /api/prompts/experiments/:id/complete | 실험 완료 |
추가 정책:
- systemPrompt SoT는 Git tracked file이 아닌 miniPC AnkiConnect config다.
- 로컬 파일 fallback 저장은 금지되며, sync 실패 시 저장 요청은 실패 처리된다.
10. 품질 검증
루트 디렉터리에서 실행합니다.
# 빠른 검증 (PR 최소 기준)
bun run check:quick
# 전체 검증 (권장)
bun run check
세부 검증:
bun run lint
bun run typecheck
bun run test
bun run build
CI에서는 .github/workflows/ci.yml의 quality-gate가 bun run check를 실행합니다.
11. 운영/트러블슈팅 체크
문제 발생 시 아래 순서 권장:
bun run check:quickbun run checkANKI_SPLITTER_API_KEY및 API 헤더 확인ANKI_CONNECT_URL연결 확인
상세 트러블슈팅 문서: docs/TROUBLESHOOTING.md
12. 자가 호스팅 (Self-Host)
12.1 사전 작업
# 호스트에 데이터 디렉토리 생성 및 권한 설정 (UID 1001 = 컨테이너 내부 anki 사용자)
sudo mkdir -p /srv/awesome-anki/{data,output}
sudo chown -R 1001:1001 /srv/awesome-anki
12.2 최소 실행
podman run -d --name awesome-anki \
--network=host \
-e GEMINI_API_KEY=<your-key> \
-e ANKI_CONNECT_URL=http://100.79.80.95:8765 \
-e ANKI_SPLITTER_REQUIRE_API_KEY=false \
-v /srv/awesome-anki/data:/app/data \
-v /srv/awesome-anki/output:/app/output \
ghcr.io/greenheadhq/awesome-anki:latest
ANKI_SPLITTER_REQUIRE_API_KEY=false: Tailscale/VPN 등 네트워크 격리 환경에서만 사용하세요. 공개 네트워크에 노출되는 경우 reverse proxy 단에서 인증(basic auth 등)을 반드시 설정해야 합니다.
12.3 환경변수 파일 사용
# /etc/awesome-anki/env 예시
GEMINI_API_KEY=...
OPENAI_API_KEY=...
ANKI_CONNECT_URL=http://100.79.80.95:8765
ANKI_SPLITTER_REQUIRE_API_KEY=false
PORT=3100
podman run -d --name awesome-anki \
--network=host \
--env-file /etc/awesome-anki/env \
-v /srv/awesome-anki/data:/app/data \
-v /srv/awesome-anki/output:/app/output \
ghcr.io/greenheadhq/awesome-anki:latest
12.4 Caddy reverse proxy 연계
Caddy 사이트블록 예시 (NixOS 등에서 관리):
anki.greenhead.dev {
reverse_proxy localhost:3100
}
상세 인프라 구성은 greenheadHQ/nixos-config#75를 참고하세요.
13. 참고 링크
13.1 내부 문서
- 아키텍처:
docs/ARCHITECTURE.md - 기능 상세:
docs/FEATURES.md - 트러블슈팅:
docs/TROUBLESHOOTING.md - 작업 로드맵:
docs/TODO.md
13.2 외부 레퍼런스
- Bun: https://bun.sh/
- Hono: https://hono.dev/
- React: https://react.dev/
- Vite: https://vite.dev/
- Tailwind CSS: https://tailwindcss.com/
- TanStack Query: https://tanstack.com/query
- Google Gemini API: https://ai.google.dev/
- OpenAI API: https://platform.openai.com/
- Anki: https://apps.ankiweb.net/
- AnkiConnect: https://ankiweb.net/shared/info/2055492159
- LocatorJS: https://github.com/infi-pc/locatorjs
- LocatorJS React data-id 설치 가이드: https://www.locatorjs.com/install/react-data-id?stack=Vite
14. 라이선스
MIT