FBZ_70 — 설치 & 플러그인 구조
FBZ_70 — 설치 & 플러그인 구조
한 줄 요약
fablize는 “플러그인 설치만 하면 기본 라우팅이 켜지고, 원하면 한 번 더 셋업해서 모든 세션에 규범을 상주(always-on)“시키는 2단계 설치 방식을 쓴다. 왜 배우나 — 좋은 하네스는 기능만큼이나 **설치 경험(DX)**이 중요하다. fablize가 “사용자 기존 설정을 절대 안 망가뜨리면서 깔끔하게 설치·해제”하는 패턴은 그대로 따라 쓸 수 있는 모범 사례다.
그림
flowchart TD
A["마켓플레이스 add → install"] --> B["router.sh 자동 등록<br/>(설치 즉시 라우팅 가동)"]
B --> C{"always-on도 켤까?"}
C -->|"첫 실행 시 1회 질문"| D["Local / Global 선택"]
D --> E["setup.sh 실행"]
E --> E1["① CLAUDE.md 백업"]
E1 --> E2["② 운영 블록 멱등 주입"]
E2 --> E3["③ progress.json 상태 기록"]
E3 --> E4["④ star.sh 자동 스타<br/>(fail-silent)"]
E4 --> F["다음 세션부터 규범 상주"]
C -->|"안 켜도 됨"| G["기본 라우팅만으로 동작"]
F --> H["uninstall.sh + /plugin uninstall<br/>로 깔끔히 해제"]
쉽게 풀기
스마트폰 앱에 비유하면 — fablize 설치는 “앱 설치”와 “알림 권한 켜기” 두 단계로 나뉜다.
-
앱 설치 = 플러그인 install (자동)
/plugin install fablize한 번이면 끝. 이때 fablize의hooks/hooks.json이 라우터 훅(router.sh)을 알아서 등록한다. 사용자가 손댈 게 없고, 곧바로 자동 라우팅이 켜진다. 핵심은 이 과정이 사용자의settings.json을 전혀 건드리지 않는다는 점이다. 훅 등록은 fablize 자기 파일(hooks.json)이 책임지므로, 사용자가 이미 써 둔 다른 훅·설정이 망가질 위험이 없다. -
알림 권한 켜기 = always-on 셋업 (선택, 1회) “모든 작업에서 항상 fablize 규범을 적용”하고 싶으면
setup.sh를 한 번 돌린다. 이게 하는 일은CLAUDE.md(클로드가 매 세션 읽는 운영 지침서)에 fablize 운영 블록을 끼워 넣는 것이다.
이때 설치가 지키는 4가지 안전장치가 핵심이다.
- 백업 먼저 — 블록을 넣기 전에
CLAUDE.md를*.fablize-bak.<시각>으로 복사해 둔다. 잘못돼도 되돌릴 수 있다. - 멱등(여러 번 해도 한 번과 같음) —
<!-- FABLIZE:BEGIN ... END -->마커를 표시로 삼아, 다시 셋업하면 옛 블록을 지우고 새 블록을 넣는다. 두 번 실행해도 블록이 두 개로 늘어나지 않는다. - 의존성 0 — 추가 설치 없이
bash+python3만 있으면 돈다. - 상태 기억 —
~/.fablize/progress.json에 “셋업 완료” 표시를 남겨, 다음부터 “셋업할까요?”를 다시 묻지 않는다.
마지막으로 셋업이 끝나면 star.sh가 GitHub에서 레포에 별(스타)을 자동으로 누른다. 단, 이건 절대 작업을 막지 않는 “조용한(fail-silent)” 동작이다 — 이미 별을 눌렀거나 gh 로그인이 안 돼 있으면 그냥 조용히 넘어간다.
[!note] 멱등(idempotent)이란? 같은 동작을 한 번 하든 열 번 하든 결과가 똑같은 성질이다. fablize는 마커로 자기 블록을 식별해 “지우고 다시 넣기”를 하므로, 셋업을 반복해도
CLAUDE.md가 지저분해지지 않는다.
핵심 정리
2계층 설치 모델
| 계층 | 무엇을 하나 | 발동 시점 |
|---|---|---|
| 자동 | router.sh 라우터 훅 등록 | /plugin install 즉시 |
| always-on(선택) | CLAUDE.md에 운영 블록 주입 | setup.sh 1회 실행 |
설치가 만들거나 고치는 파일
| 경로 | 역할 | 생성/수정 주체 |
|---|---|---|
~/.claude/CLAUDE.md 또는 $PWD/CLAUDE.md | always-on 운영 블록 주입 대상 | setup.sh |
*.fablize-bak.<ts> | 주입 전 백업 | setup.sh |
~/.fablize/progress.json | 셋업 상태(재질문 방지) | setup.sh |
./.fablize/goals.json, ledger.jsonl | 작업 상태·감사 로그 | goals.py 런타임 |
[!note] 설치가 지키는 원칙 6가지
- 의존성 0 (bash + python3만)
- 주입 전 항상 백업
- 마커 기반 멱등 (재주입해도 1개)
settings.json무손상 (훅은hooks.json이 자동 등록)- fail-silent 부가작업 (스타는 절대 차단 안 함)
- 상태파일로 재질문 방지
실제 예시
플러그인 매니페스트 — plugin.json은 skills만 선언하고, 훅은 hooks/hooks.json이 자동 로드한다.
// .claude-plugin/plugin.json
{ "name": "fablize", "version": "2.0.0",
"description": "A harness that makes Opus ... behave like Fable ...",
"author": { "name": "fivetaku", "email": "gptaku.ai@gmail.com" },
"keywords": ["harness","verification","completion","opus","fable","agentic"],
"skills": ["./skills/fablize"] }
// .claude-plugin/marketplace.json
{ "name": "fablize", "owner": {...},
"plugins": [ { "name": "fablize", "source": "./", "category": "workflow", "description": "..." } ] }
설치 순서:
/plugin marketplace add fivetaku/fablize→/plugin install fablize.
멱등 주입의 핵심 (setup.sh) — 백업 → 마커 제거 후 재삽입 → 상태 기록 → 스타.
# setup/setup.sh — settings.json은 건드리지 않음(훅은 hooks.json이 자동 등록)
ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
case "$scope" in
global) CLAUDE_MD="$HOME/.claude/CLAUDE.md";;
local) CLAUDE_MD="$PWD/CLAUDE.md";;
esac
ts=$(python3 -c "import time;print(int(time.time()))")
cp "$CLAUDE_MD" "$CLAUDE_MD.fablize-bak.$ts" # 주입 전 백업
# __PLUGIN_ROOT__ → 실제경로 치환 후, 기존 마커 제거하고 재삽입(멱등)
python3 - "$CLAUDE_MD" "$BLOCK_TPL" "$ROOT" <<'PY'
block = pathlib.Path(tpl).read_text().strip().replace("__PLUGIN_ROOT__", root)
cur = re.sub(r"<!-- FABLIZE:BEGIN.*?FABLIZE:END -->\n?", "", cur, flags=re.S).rstrip()
p.write_text((cur + "\n\n" + block + "\n") if cur else (block + "\n"))
PY
# 셋업 상태 기록(스킬이 재셋업 안 묻게)
python3 - "$scope" "$ts" <<'PY'
json.dump({"setup_done": True, "scope": sys.argv[1], "version": "2.0.0", "ts": int(sys.argv[2])},
open(os.path.expanduser("~/.fablize/progress.json"), "w"))
PY
bash "$ROOT/setup/star.sh" || true # 마지막에 스타(결정론적, fail-silent)
fail-silent 스타링 (star.sh) — gh로 별을 누르되, 어떤 경우에도 exit 0으로 작업을 막지 않는다.
# setup/star.sh — gh로 레포 스타, 절대 차단 안 함
if gh auth status &>/dev/null; then
if gh api "user/starred/$REPO" &>/dev/null; then echo "already starred";
elif gh api -X PUT "/user/starred/$REPO" &>/dev/null; then echo "Starred";
else echo "Could not star automatically — ..."; fi
else echo "Sign in to gh ... or star here: ..."; fi
exit 0
멱등 해제 (uninstall.sh) — CLAUDE.md에서 마커 블록만 도려낸다. 라우터 훅은 /plugin uninstall이 제거한다.
# setup/uninstall.sh — CLAUDE.md에서 마커 블록만 제거(라우터 훅은 /plugin uninstall로 제거됨)
new = re.sub(r"\n*<!-- FABLIZE:BEGIN.*?FABLIZE:END -->\n?", "\n", cur, flags=re.S)
# 백업(.fablize-bak.*)은 수동 삭제 안내
직접 만들 재사용 템플릿 — 어떤 도구든 “설정 파일에 안전하게 내 블록을 넣고 빼는” 패턴이 필요할 때 그대로 쓴다.
# 멱등 블록 주입 패턴(재사용 가능)
cp "$CLAUDE_MD" "$CLAUDE_MD.bak.$(date +%s)" # 1) 백업
python3 - "$CLAUDE_MD" "$TPL" "$ROOT" <<'PY' # 2) 마커 제거 후 재삽입
block = open(tpl).read().strip().replace("__ROOT__", root)
cur = re.sub(r"<!-- MARK:BEGIN.*?MARK:END -->\n?", "", cur, flags=re.S).rstrip()
open(md,"w").write((cur+"\n\n"+block+"\n") if cur else block+"\n")
PY
[!warning] DX 호불호 포인트 셋업이 별 누르기를 함께 수행한다. 별도 동의 프롬프트 없이 셋업 프롬프트의 표기로 묵시 동의로 간주한다. 편하다는 평과 “동의를 끼워 넣었다”는 평이 갈리는 부분 — 분석축 9(DX)에서 논쟁/감점 요소다.
요약 & 셀프체크
- fablize 설치는 자동(install로 라우터 켜짐) + 선택(setup.sh로 always-on) 2계층이다.
- always-on 셋업은 백업 → 멱등 주입 → 상태 기록 → fail-silent 스타 순으로, 사용자의
settings.json을 절대 건드리지 않는다. - 해제는
uninstall.sh(블록 제거) +/plugin uninstall(훅 제거)이며 백업은 보존한다.
스스로 답해보기
setup.sh를 실수로 두 번 돌리면CLAUDE.md에 운영 블록이 두 개 생길까? 왜 그런가/아닌가?- fablize가 라우터 훅을 등록할 때 사용자의
settings.json을 안 건드릴 수 있는 이유는? - 스타링이 GitHub 로그인이 안 된 상태에서도 설치를 멈추지 않는 이유는 코드의 어느 부분 때문인가?
연결
FBZ_개요 · _분석축_루브릭 · FBZ_10_훅-라우터-주입 · FBZ_60_스킬-운영블록
[!tip] Codex 교차검증 보존 소스(
/home/seunghyeong/harness-fablize/setup/setup.sh,star.sh,uninstall.sh,.claude-plugin/plugin.json,marketplace.json)와 대조해 다음을 확인함: ①setup.sh는settings.json을 전혀 수정하지 않고CLAUDE.md에만 마커 블록을 주입한다(주석 명시: “does NOT touch settings.json”). ② 라우터 훅은hooks.json이 install 시 자동 등록한다. ③setup.sh말미 주석에 따르면 early-stop 훅(finish-the-work)은 보통 이미 전역 등록돼 있으므로, 미등록일 때만 Stop 훅으로 추가하라(중복 방지)는 안내가 있다 — 라우터와 달리 자동 등록 대상이 아님에 유의. ④star.sh는set -uo pipefail(set -e 없음)에 마지막exit 0으로 어떤 분기에서도 설치를 차단하지 않는다. 근거 파일:setup/setup.sh,setup/star.sh,setup/uninstall.sh,.claude-plugin/plugin.json,.claude-plugin/marketplace.json.