Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,6 @@ coverage/
# matters: in .gitignore the *last* matching pattern wins.
!runs/r-clean-*/
!runs/r-clean-*/**

# Claude Code session locks (per-process state, not source)
.claude/scheduled_tasks.lock
2 changes: 1 addition & 1 deletion plugins/preview-forge/agents/ideation/ideation-lead.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ IDEA_SPEC: <not provided — fallback v1.5.4 path>
먼저 **active profile을 resolve**:
1. `runs/<id>/.profile` 파일 (M1이 /pf:new --profile 파싱 후 기록)
2. env `PF_PROFILE`
3. plugin `settings.json` → `pf.defaultProfile` (기본 `pro`)
3. plugin `settings.json` → `pf.defaultProfile` (현재 `"standard"`; v1.3.0에서는 `"pro"`였으나 v1.4.0에서 데모-퍼스트 정책으로 flip — LESSON 0.10 참조). 최종 fallback도 `"standard"`.

그리고 profile의 `previews.count`만큼 Advocate 선정:
- **standard** (9): P01, P02, P05, P07, P10, P14, P17, P20, P24 — 가장 다양한 페르소나 스펙트럼
Expand Down
17 changes: 9 additions & 8 deletions plugins/preview-forge/commands/new.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ description: Start a new Preview Forge run (PreviewDD cycle begins)
```

예시:
- `/pf:new "공방 운영자가 수업·재고·정산을 한 곳에서"` (pro profile 기본값)
- `/pf:new "todo app with auth" --profile=standard` (빠른 프로토타입)
- `/pf:new "production SaaS 런칭용 앱" --profile=max` (풀 143-agent 검증)
- `/pf:new "idea" --profile=pro --previews=26 --no-cache` (pro 기본에 previews 확장 + 캐시 스킵)
- `/pf:new "공방 운영자가 수업·재고·정산을 한 곳에서"` (**standard** profile 기본값 — v1.4+, 9 previews · 2×5 eng · ~25분)
- `/pf:new "production SaaS launch" --profile=pro` (실제 프로젝트, 18 previews · 3×5 eng · ~70분)
- `/pf:new "regulated enterprise rollout" --profile=max` (풀 143-agent · 26 previews · ~160분)
- `/pf:new "idea" --profile=pro --previews=26 --no-cache` (pro에 previews 확장 + 캐시 스킵)
- `PF_PROFILE=max /pf:new "..."` (환경변수로 default 오버라이드 — 1회용)

## 인자

Expand All @@ -27,16 +28,16 @@ description: Start a new Preview Forge run (PreviewDD cycle begins)

| 플래그 | 기본값 | 설명 |
|---|---|---|
| `--profile` | `pro` (`settings.json` defaultProfile) | 프로파일 이름: `standard` · `pro` · `max` |
| `--profile` | **`standard`** (v1.4+, was `pro` in v1.3.0; lives in `settings.json` `pf.defaultProfile`) | 프로파일 이름: `standard` · `pro` · `max`. 처음부터 더 깊은 검증을 원하면 `--profile=pro` 또는 `--profile=max` 명시. 환경변수 `PF_PROFILE=pro` 도 동일 효과 (해당 셸 세션에 영향). |
| `--previews=N` | profile에 종속 (9/18/26) | Advocate 수 오버라이드. profile의 `max_user_expand` (26) 이내 |
| `--no-cache` | false | PreviewDD-level 캐시 스킵. 동일 아이디어 재실행 시 강제 재생성 |

### 프로파일 빠른 비교

| Profile | Previews | Eng teams | Panels | SCC iter | P95 ceiling | 권장 용도 |
|---|---|---|---|---|---|---|
| **standard** | 9 | 2×5 (BE+FE) | keyword-trigger | 3 | ~60k tok / 25min | 데모 · 프로토타입 |
| **pro** *(기본)* | 18 | 3×5 (+DB) | keyword-trigger + escalation | 4 | ~250k tok / 70min | 실제 프로젝트 |
| **standard** *(기본 — v1.4+)* | 9 | 2×5 (BE+FE) | keyword-trigger | 3 | ~60k tok / 25min | 데모 · 프로토타입 · 첫 시도 |
| **pro** | 18 | 3×5 (+DB) | keyword-trigger + escalation | 4 | ~250k tok / 70min | 실제 프로젝트 |
| **max** | 26 | 5×5 (all) | always-on | 5 | ~600k tok / 160min | 프로덕션 런칭 · 베이스라인 |

상세: `plugins/preview-forge/profiles/{standard,pro,max}.json`
Expand All @@ -51,7 +52,7 @@ M1 Run Supervisor는 **모든 작업 전** 다음을 순서대로 검증합니
4. **claude CLI + plugin install** — plugin 자체 로드 상태 확인.
5. **api.anthropic.com 연결** — 기본 reachability 확인.
6. **LESSONS pre-load** — `~/.claude/preview-forge/memory/LESSONS.md`에서 관련 카테고리(1. PreviewDD, 4. Memory, 6. Plugin 배포)를 읽어 department lead들의 system prompt에 주입.
7. **profile resolve** (v1.3+) — `--profile` 플래그 · env `PF_PROFILE` · `settings.json` defaultProfile 순으로 해결 → `runs/<id>/.profile` 파일에 기록. 이후 모든 hook·monitor가 이 값을 참조.
7. **profile resolve** (v1.3+, v1.4+ default flipped to `standard`) — `--profile` 플래그 env `PF_PROFILE` `settings.json` `pf.defaultProfile` (현재 `"standard"`) → 최종 fallback `"standard"` 순으로 해결 → `runs/<id>/.profile` 파일에 기록. 이후 모든 hook·monitor가 이 값을 참조. 사용자가 처음부터 깊은 검증을 원하면 `/pf:new "..." --profile=pro|max` 또는 `PF_PROFILE=pro` 환경변수 사용.
8. **idea-input size cap** (umbrella #95 follow-up — defense in depth, layer 1) — orchestrator MUST invoke [`scripts/pre-flight.sh --idea "<seed>"`](../../../scripts/pre-flight.sh) (or the equivalent direct call to [`scripts/validate-idea-input.sh`](../../../scripts/validate-idea-input.sh)) on the raw seed idea **BEFORE** writing it to `runs/<id>/idea.json`, computing any cache key (`scripts/preview-cache.sh key …`), or expanding the I1 Socratic interview prompt. The validator exits 0 if `len(idea) ≤ 5000` Unicode code points (matching the `idea_summary` schema cap), exits non-zero otherwise. On non-zero, abort the run with the validator's stderr message — do NOT silently truncate. Rationale: the schema's `idea_summary.maxLength: 5000` only fires at S-3 validation, well after the seed idea has already inflated the Socratic system prompt and been hashed into the cache key. This pre-flight gate stops a 10MB seed idea at the door. Bypass policy: NONE — `--no-cache` does not bypass this check. Truncate mode (`scripts/validate-idea-input.sh --truncate -`) exists for non-interactive automation pipelines that explicitly opt in; `/pf:new` itself MUST default to reject so the user keeps full intent over what gets trimmed. The size cap also runs at S-3 schema validation as the canonical authority — this layer-1 gate is belt-and-suspenders.

CLI 환경에서는 `scripts/pre-flight.sh` 또는 `pf check`로 동일 검증 수동 실행 가능. 아이디어 텍스트까지 포함해 한 번에 검증하려면 `scripts/pre-flight.sh --idea "<seed>"` (or `--idea-file <path>` for inputs that may exceed ARG_MAX).
Expand Down
14 changes: 10 additions & 4 deletions plugins/preview-forge/hooks/cost-regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,13 @@ def load_profile(name: str) -> dict | None:


def load_active_profile(run_dir: Path) -> dict | None:
"""Priority: run_dir/.profile → env PF_PROFILE → settings.defaultProfile → 'pro'."""
"""Priority: run_dir/.profile → env PF_PROFILE → settings.defaultProfile → 'standard'.

v1.4+ default is 'standard' (was 'pro' in v1.3.0; flipped for demo-first
UX — see LESSON 0.10). settings.json ships with defaultProfile: standard;
the hard-coded fallbacks below match that so a missing/malformed
settings.json behaves consistently.
"""
marker = run_dir / ".profile"
if marker.exists():
name = marker.read_text(encoding="utf-8").strip()
Expand All @@ -52,11 +58,11 @@ def load_active_profile(run_dir: Path) -> dict | None:
if not name and SETTINGS_PATH.exists():
try:
s = json.load(SETTINGS_PATH.open(encoding="utf-8"))
name = s.get("pf", {}).get("defaultProfile", "pro")
name = s.get("pf", {}).get("defaultProfile", "standard")
except (OSError, json.JSONDecodeError):
name = "pro"
name = "standard"
if not name:
name = "pro"
name = "standard"
return load_profile(name)


Expand Down
2 changes: 1 addition & 1 deletion plugins/preview-forge/schemas/pf-profile.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://two-weeks-team.github.io/PreviewForgeForClaudeCode/schemas/pf-profile.schema.json",
"title": "PF Profile",
"description": "Preview Forge run profile — controls cost, speed, and thoroughness of a 3-DD cycle. Three values ship: standard (cheapest), pro (default, balanced), max (all-in 143 agents).",
"description": "Preview Forge run profile — controls cost, speed, and thoroughness of a 3-DD cycle. Three values ship: standard (default since v1.4 — demo/prototype, fastest), pro (real project, balanced), max (production launch, all-in 143 agents).",
"type": "object",
"required": [
"name",
Expand Down
Loading