@uzysjung/agent-harness 26.136.0 → 26.139.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-WCH7E3G6.js → chunk-4VDIAMSM.js} +2 -2
- package/dist/{chunk-WCH7E3G6.js.map → chunk-4VDIAMSM.js.map} +1 -1
- package/dist/index.js +27 -9
- package/dist/index.js.map +1 -1
- package/dist/trust-tier-drift.js +1 -1
- package/package.json +1 -1
- package/templates/CLAUDE.md +7 -0
- package/templates/agents/implementer.md +48 -0
- package/templates/hooks/session-start.sh +16 -3
- package/templates/rules/benchmark-parity.md +3 -2
- package/templates/rules/change-management.md +29 -50
- package/templates/rules/doc-governance.md +26 -30
- package/templates/rules/no-false-ship.md +2 -2
- package/templates/rules/playwright-launch.md +15 -57
- package/templates/skills/codex-consult/SKILL.md +9 -2
- package/templates/skills/gemini-consult/SKILL.md +79 -20
- package/templates/skills/gemini-consult/scripts/gemini-ask.sh +74 -11
- package/templates/skills/ui-visual-review/SKILL.md +51 -1
package/dist/trust-tier-drift.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uzysjung/agent-harness",
|
|
3
|
-
"version": "26.
|
|
3
|
+
"version": "26.139.0",
|
|
4
4
|
"description": "Curate vetted AI-coding skills & plugins by your tech stack — install only what you need, across Claude Code, Codex, OpenCode & Antigravity",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
package/templates/CLAUDE.md
CHANGED
|
@@ -60,6 +60,13 @@ If you genuinely think a convention is harmful, surface it. Don't fork silently.
|
|
|
60
60
|
"Tests pass" is wrong if any were skipped.
|
|
61
61
|
Default to surfacing uncertainty, not hiding it.
|
|
62
62
|
|
|
63
|
+
## Delegate the Building, Keep the Deciding
|
|
64
|
+
When work turns from deciding to building, delegate it — the main thread holds scope and sequencing,
|
|
65
|
+
not the edits. Dev tracks ship an `implementer` agent; without it use a general-purpose subagent on
|
|
66
|
+
the same contract: **done = a test that fails without the change**. Split before handing off — one
|
|
67
|
+
item per independently testable change, naming its files and its constraint. Review and verification
|
|
68
|
+
belong to a lane other than the one that wrote the code.
|
|
69
|
+
|
|
63
70
|
## Anti-Patterns (Forbidden)
|
|
64
71
|
"feels kind of weak intuitively" / "probably won't be used" → speculation
|
|
65
72
|
"it's an advanced feature, so low value" → assertion with no criteria
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: implementer
|
|
3
|
+
description: Implementation lane — writes code for a scoped change and closes it with a test that fails without the change. Use whenever work moves from deciding to building: a feature, a bug fix, a refactor, a migration step. Prefer this over implementing on the main thread. Korean triggers: 구현해 · 고쳐 · 만들어 · 적용해 · 리팩터 · 위임.
|
|
4
|
+
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
|
|
5
|
+
model: opus
|
|
6
|
+
origin: self-authored
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Implementer — 구현 레인
|
|
10
|
+
|
|
11
|
+
당신은 **코드를 쓰는** 레인이다. 검토하거나 조사하는 것이 아니라 변경을 만들어 끝낸다.
|
|
12
|
+
|
|
13
|
+
## 종료 조건 (하나뿐)
|
|
14
|
+
|
|
15
|
+
**이 변경을 무는 테스트가 green.** 그 테스트는 변경이 없으면 실패해야 한다 — 통과만 하고 아무것도
|
|
16
|
+
안 보는 테스트는 종료 조건을 충족하지 않는다. 확신이 안 서면 변경을 잠시 되돌려 테스트가 정말
|
|
17
|
+
빨간불이 되는지 보고, 다시 적용해 초록불을 확인하라.
|
|
18
|
+
|
|
19
|
+
테스트를 못 붙인 채로 끝내야 한다면 **완료라고 보고하지 않는다.** 무엇을 못 닫았는지, 왜 못
|
|
20
|
+
닫았는지("무엇이 풀리면 되는지"까지)를 적고 넘긴다. 이게 이 레인의 존재 이유다 — 구현과 검증이
|
|
21
|
+
갈리면 검증은 늘 나중으로 밀리고, 나중은 오지 않는다.
|
|
22
|
+
|
|
23
|
+
## 작업 방식
|
|
24
|
+
|
|
25
|
+
- **편집 직후에 확인한다.** 전체 스위트를 마지막에 한 번 돌리는 대신, 방금 고친 것을 무는
|
|
26
|
+
파일을 지정해 바로 실행하라(`npx vitest run tests/<관련>.test.ts`, `pytest tests/test_<관련>.py`).
|
|
27
|
+
실패를 편집에서 멀리 떼어놓을수록 원인을 좁히는 비용이 커진다.
|
|
28
|
+
- **범위 안에 머문다.** 인접 코드를 "개선"하지 않는다. 손대야만 하는 것만 손댄다.
|
|
29
|
+
- **읽고 나서 쓴다.** 바꿀 심볼의 호출부와 export 를 먼저 본다.
|
|
30
|
+
- 기존 코드의 관용구·명명·주석 밀도를 따른다. 취향보다 일관성이 우선이다.
|
|
31
|
+
|
|
32
|
+
## 멈춰야 할 때
|
|
33
|
+
|
|
34
|
+
다음이면 **구현을 계속하지 말고 멈춰서 보고**하라. 추측으로 밀고 나가면 되돌리는 비용이 훨씬 크다.
|
|
35
|
+
|
|
36
|
+
- 요구가 두 갈래로 읽히는데 어느 쪽이냐에 따라 결과물이 달라진다
|
|
37
|
+
- 시키지 않은 파일·모듈을 고쳐야만 문제가 풀린다
|
|
38
|
+
- 테스트가 요구와 모순된다 (테스트를 고치는 것이 답일 수도, 요구가 틀렸을 수도 있다)
|
|
39
|
+
- 되돌리기 어려운 것에 손이 닿는다 — 마이그레이션, 스키마, 배포 설정, 외부로 나가는 호출
|
|
40
|
+
|
|
41
|
+
## 보고 형식
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
변경: <무엇을 왜>
|
|
45
|
+
파일: <경로 목록>
|
|
46
|
+
테스트: <명령> → <결과>. 이 테스트는 변경 전 <어떻게> 실패한다.
|
|
47
|
+
미완: <없으면 "없음". 있으면 무엇이 풀리면 닫히는지>
|
|
48
|
+
```
|
|
@@ -7,7 +7,8 @@ BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
|
7
7
|
|
|
8
8
|
# 1. git pull (branch가 있고 detached HEAD가 아닐 때)
|
|
9
9
|
if [ -n "$BRANCH" ] && [ "$BRANCH" != "HEAD" ]; then
|
|
10
|
-
|
|
10
|
+
# stdout 도 버린다 — 여기 출력이 아래 JSON 앞에 붙으면 계약이 깨진다 (실측 21%).
|
|
11
|
+
git pull --rebase >/dev/null 2>&1 || true
|
|
11
12
|
fi
|
|
12
13
|
|
|
13
14
|
# 2. SPEC 존재 여부 확인
|
|
@@ -47,15 +48,27 @@ if [ "${ORPHANS:-0}" -gt 0 ]; then
|
|
|
47
48
|
fi
|
|
48
49
|
|
|
49
50
|
# 5. 세션 컨텍스트 출력
|
|
51
|
+
#
|
|
52
|
+
# **스키마가 계약이다.** CLI 가 읽는 필드가 아니면 **유효 JSON 인 채로 조용히 버려진다** —
|
|
53
|
+
# 훅은 돌고 exit 0 이고 로그에도 남지만 모델은 아무것도 못 본다. 실패가 아무 증상을 안 내므로
|
|
54
|
+
# 사람이 알아채지 못한다. SessionStart 가 읽는 것은
|
|
55
|
+
# `hookSpecificOutput.{additionalContext|initialUserMessage}` 다.
|
|
56
|
+
# 조용히 버려지는 출력은 컨텍스트 비용이 0 인 대신 기능도 0 이다.
|
|
50
57
|
if [ "$SPEC_EXISTS" = "true" ]; then
|
|
51
58
|
MSG="Session started. Branch: ${BRANCH:-detached}. SPEC exists — read docs/SPEC.md first (Persistent Anchor). Check Change Log and current Phase before starting work.${COMPACT_WARNING}${ORPHAN_NOTE}"
|
|
52
59
|
else
|
|
53
60
|
MSG="Session started. Branch: ${BRANCH:-detached}. No SPEC found.${COMPACT_WARNING}${ORPHAN_NOTE}"
|
|
54
61
|
fi
|
|
55
62
|
|
|
63
|
+
# JSON 문자열 이스케이프 — 백슬래시 먼저, 그 다음 따옴표(순서를 바꾸면 이중 이스케이프된다).
|
|
64
|
+
# `jq` 를 쓰지 않는 이유: 훅은 jq 미설치 환경에서도 돌아야 한다 (cli-development.md).
|
|
65
|
+
ESCAPED=$(printf '%s' "$MSG" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g')
|
|
66
|
+
|
|
56
67
|
cat <<EOF
|
|
57
68
|
{
|
|
58
|
-
"
|
|
59
|
-
|
|
69
|
+
"hookSpecificOutput": {
|
|
70
|
+
"hookEventName": "SessionStart",
|
|
71
|
+
"additionalContext": "$ESCAPED"
|
|
72
|
+
}
|
|
60
73
|
}
|
|
61
74
|
EOF
|
|
@@ -17,8 +17,9 @@ SSOT — 없으면 갭 판정 기준 자체가 없다.
|
|
|
17
17
|
| (예: 문서/위키) | (예: Confluence) | Playwright capture | `~/.<ref>-audit-profile` |
|
|
18
18
|
| (예: 리포트) | (예: 내부 확보한 정적 HTML/PDF) | 정적 자료 | `docs/raw/` |
|
|
19
19
|
|
|
20
|
-
- 실측
|
|
21
|
-
|
|
20
|
+
- 실측 수단은 둘로 나뉜다 — **금지**(활성 Chrome attach · 일회성 context 등)는 `playwright-launch`
|
|
21
|
+
룰이, **절차**(영속 profile launcher · capture 형태)는 `ui-visual-review` 스킬이 SSOT.
|
|
22
|
+
본 rule 은 어느 쪽도 재규정하지 않는다.
|
|
22
23
|
|
|
23
24
|
## 반복 루프 (capture → 핵심 기능 → 완결성 → 발전)
|
|
24
25
|
|
|
@@ -1,41 +1,32 @@
|
|
|
1
1
|
# Change Management
|
|
2
2
|
|
|
3
|
-
## Change Request (CR)
|
|
3
|
+
## Change Request (CR) 분류
|
|
4
4
|
|
|
5
|
-
구현 중 SPEC/PRD 변경이
|
|
5
|
+
구현 중 SPEC/PRD 변경이 필요해지면 셋 중 하나로 분류한다:
|
|
6
6
|
|
|
7
7
|
| 유형 | 기준 | 처리 |
|
|
8
8
|
|------|------|------|
|
|
9
|
-
| **Clarification** | 이미 합의된 내용의 구체화 |
|
|
10
|
-
| **Minor** | 현재 Phase 내부에 국한 |
|
|
11
|
-
| **Major** | AC/Phase
|
|
9
|
+
| **Clarification** | 이미 합의된 내용의 구체화 | 즉시 반영 + Change Log |
|
|
10
|
+
| **Minor** | 현재 Phase 내부에 국한 | 제안 → **인간 승인** → Change Log |
|
|
11
|
+
| **Major** | AC 의 Pass/Fail · 다른 Phase 의 입출력 · Non-Goals 경계 · DO NOT CHANGE 중 **하나라도** 건드림 | **인간 결정 필수** → Change Log + 영향 분석 |
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## DO NOT CHANGE
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
IF 다른 Phase의 입력/산출물에 영향 → Major
|
|
18
|
-
IF DO NOT CHANGE 영역에 영향 → Major
|
|
19
|
-
IF Non-Goals 경계에 영향 → Major
|
|
20
|
-
IF 현재 Phase 내부에 국한 → Minor
|
|
21
|
-
IF 합의 내용의 구체화 → Clarification
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## DO NOT CHANGE Protection
|
|
25
|
-
|
|
26
|
-
- SPEC/PRD의 DO NOT CHANGE 영역은 **절대 수정 금지**.
|
|
27
|
-
- 수정이 불가피한 경우: Major CR 작성 → 인간 결정 대기.
|
|
28
|
-
- 안정적으로 보이는 영역도 수정 전 확인: "이 부분도 수정 범위입니까?"
|
|
15
|
+
SPEC/PRD 의 DO NOT CHANGE 영역은 **수정 금지**다. 불가피하면 Major CR 을 쓰고 인간 결정을
|
|
16
|
+
기다린다. 안정적으로 보이는 영역도 손대기 전에 묻는다 — "이 부분도 수정 범위입니까?"
|
|
29
17
|
|
|
30
18
|
## Decision Log (ADR)
|
|
31
19
|
|
|
32
|
-
|
|
20
|
+
SPEC 에 없던 의사결정은 `docs/decisions/` 에 기록한다.
|
|
21
|
+
|
|
22
|
+
- **대상**: 아키텍처 변경 · 외부 의존성 도입/제거 · 데이터 모델 변경 · 보안 정책 · breaking API
|
|
23
|
+
- **비대상**: 한 함수의 구현 디테일 · 임시 워크어라운드 · 명백한 버그 fix
|
|
33
24
|
|
|
34
25
|
```markdown
|
|
35
26
|
# ADR-NNN: [결정 제목]
|
|
36
27
|
- Status: Proposed | Accepted | Superseded | Deprecated
|
|
37
28
|
- Date: YYYY-MM-DD
|
|
38
|
-
- PR: #123
|
|
29
|
+
- PR: #123
|
|
39
30
|
- Supersedes: ADR-MMM (있으면)
|
|
40
31
|
- Context: [왜 결정이 필요했는가]
|
|
41
32
|
- Decision: [무엇을 결정했는가]
|
|
@@ -43,38 +34,26 @@ IF 합의 내용의 구체화 → Clarification
|
|
|
43
34
|
- Consequences: [이 결정의 영향]
|
|
44
35
|
```
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
| Status | 의미 | 다음 가능 transition |
|
|
55
|
-
|--------|------|-------------------|
|
|
56
|
-
| **Proposed** | PR 작성 + 검토 중. 아직 적용 X | Accepted, (Rejected) |
|
|
57
|
-
| **Accepted** | 머지됨. 본 결정에 따라 코드/문서 작성 | Superseded, Deprecated |
|
|
58
|
-
| **Superseded** | 다른 ADR이 본 결정을 대체 | (terminal — `Supersedes:` 필드로 link) |
|
|
59
|
-
| **Deprecated** | 더 이상 유효하지 않으나 대체 ADR 없음 | (terminal — 사유 PR/section 기록) |
|
|
60
|
-
|
|
61
|
-
### 채택 프로세스
|
|
62
|
-
|
|
63
|
-
1. **Proposed**: 의사결정 필요 시 ADR 초안 PR 생성. Status: Proposed.
|
|
64
|
-
2. **검토**: PR review에서 Alternatives + Consequences 검증.
|
|
65
|
-
3. **Accepted**: 머지 직전 Status: Accepted, PR 번호 채움.
|
|
66
|
-
4. **변경**: 새 ADR로 Supersedes/Deprecates 명시. 기존 ADR Status 갱신.
|
|
67
|
-
|
|
68
|
-
### 어떤 결정이 ADR 대상인가
|
|
37
|
+
| Status | 의미 | 다음 |
|
|
38
|
+
|--------|------|------|
|
|
39
|
+
| **Proposed** | 초안 PR 검토 중, 아직 미적용 | Accepted / 기각 |
|
|
40
|
+
| **Accepted** | 머지됨. 이 결정에 따라 코드·문서를 쓴다 | Superseded / Deprecated |
|
|
41
|
+
| **Superseded** | 다른 ADR 이 대체 (terminal) | — |
|
|
42
|
+
| **Deprecated** | 무효이나 대체 ADR 없음 (terminal — **사유를 PR/본문에 남긴다**) | — |
|
|
69
43
|
|
|
70
|
-
|
|
71
|
-
|
|
44
|
+
PR review 에서 `Alternatives` 와 `Consequences` 를 검증하고, 머지 직전에 Status 를
|
|
45
|
+
Accepted 로 바꾸고 PR 번호를 채운다. 기각은 **별도 ADR 을 만들지 않고**
|
|
46
|
+
PR comment 에 사유를 남긴다. 결정을 바꿀 때는 새 ADR 에 `Supersedes:` 를 쓰고 기존 ADR 의 Status
|
|
47
|
+
도 함께 갱신한다 — 한쪽만 고치면 어느 것이 현행인지 알 수 없다.
|
|
72
48
|
|
|
73
|
-
## Savepoint
|
|
49
|
+
## Savepoint
|
|
74
50
|
|
|
75
|
-
Major CR 적용 전, 또는
|
|
51
|
+
Major CR 적용 전, 또는 되돌리기 어려운 변경 직전에 커밋으로 지점을 남긴다:
|
|
76
52
|
|
|
77
53
|
```bash
|
|
78
|
-
git
|
|
54
|
+
git commit -a -m "chore: savepoint before [변경 설명]"
|
|
79
55
|
```
|
|
80
56
|
|
|
57
|
+
**`git add -A` 를 쓰지 않는다.** 설치 직후처럼 `.gitignore` 가 아직 시크릿을 덮지 못한 상태에서는
|
|
58
|
+
그 한 줄이 `.env` 를 그대로 커밋한다 — 같은 하네스의 `git-policy` 가 금지하는 것을 savepoint 가
|
|
59
|
+
수행하게 된다. 추적 중인 변경만 담고, 새 파일이 꼭 필요하면 경로를 하나씩 지정해 추가한다.
|
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
# Document Governance
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
실서비스 운영에서 검증된 관행의 일반화.
|
|
3
|
+
프로젝트 문서가 "거짓 상태"가 되는 것을 막는 SSOT 규약.
|
|
5
4
|
|
|
6
5
|
## SSOT 위계 (한 사실은 한 곳)
|
|
7
6
|
|
|
8
7
|
| 문서 | 역할 | 갱신 시점 |
|
|
9
8
|
|------|------|----------|
|
|
10
|
-
| `NORTH_STAR.md` | 왜·어디로 (비전 ·
|
|
11
|
-
| `SPEC.md` (+ `specs/`) | 무엇 (제품/기능 스펙
|
|
9
|
+
| `NORTH_STAR.md` | 왜·어디로 (비전 · 지표 · Non-Goals) | 방향 전환 시만 |
|
|
10
|
+
| `SPEC.md` (+ `specs/`) | 무엇 (제품/기능 스펙) | 기능 정의/변경 |
|
|
12
11
|
| `PRD.md` | 문제 · 솔루션 · 요구사항 | 제품 방향 변경 |
|
|
13
|
-
| `TODO.md` (또는 `tasks/todo.md`) | 다음 할 일 · 진행/완료 추적 | 작업 시작/완료 |
|
|
12
|
+
| `TODO.md` (또는 `tasks/todo.md`·`docs/todo.md`) | 다음 할 일 · 진행/완료 추적 | 작업 시작/완료 |
|
|
14
13
|
| `README.md` | 진입점 · 현재 상태 (shipped/stack/배포) | 현재 상태 변동 |
|
|
15
|
-
| `docs/decisions/` |
|
|
14
|
+
| `docs/decisions/` | ADR (아키텍처·의존성·데이터모델·보안) | change-management 분류 따름 |
|
|
16
15
|
|
|
17
|
-
- 파일 위치는 프로젝트 레이아웃을
|
|
18
|
-
-
|
|
19
|
-
- **같은 사실을 두 곳에 쓰지 않는다.** 한
|
|
16
|
+
- 파일 위치는 프로젝트 레이아웃을 따르되(루트 또는 `docs/`) **역할·위계·동기화 의무는 불변**.
|
|
17
|
+
- **충돌 시 상위 우선** — NORTH_STAR 와 SPEC 이 모순되면 NORTH_STAR 가 이긴다.
|
|
18
|
+
- **같은 사실을 두 곳에 쓰지 않는다.** 한 곳에 두고 나머지는 링크로 가리킨다. 중복 서술 = drift 의 씨앗.
|
|
20
19
|
|
|
21
20
|
## 무엇을 언제 쓰나
|
|
22
21
|
|
|
23
|
-
- 신규 기능 →
|
|
24
|
-
|
|
22
|
+
- 신규 기능 → **SPEC 등재가 먼저, 구현은 그 다음**(spec-first). "추가하자"는 문서 작업 지시이지
|
|
23
|
+
구현 착수 신호가 아니다.
|
|
24
|
+
- 아키텍처 · 외부 의존성 · 데이터 모델 · 보안 · breaking API → **ADR** (템플릿은 change-management).
|
|
25
25
|
- 진행/완료 추적 → TODO. 현재 상태 변동 → README.
|
|
26
26
|
|
|
27
27
|
## 작업 완료 처리 (merge = 코드 + 추적 동기화) — 핵심 의무
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
머지 직후 **같은 작업 단위로** 처리한다:
|
|
30
30
|
|
|
31
|
-
1. TODO
|
|
31
|
+
1. TODO 항목 → `[x] (✅ #PR번호)`.
|
|
32
32
|
2. AC / Phase / Non-Goals / DO NOT CHANGE 에 영향 시 → SPEC Change Log.
|
|
33
|
-
3.
|
|
33
|
+
3. shipped/배포 상태 변동 시 → README.
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
미완분을 완료로 오인해 건너뛴다.**
|
|
35
|
+
빠뜨리면 추적 SSOT 가 거짓이 되고, **다음 세션이 완료분을 backlog 로 오인해 중복 작업하거나
|
|
36
|
+
미완분을 완료로 오인해 건너뛴다.**
|
|
37
37
|
|
|
38
38
|
## 착수 전 baseline 대조 (Pre-flight)
|
|
39
39
|
|
|
@@ -62,24 +62,20 @@ PR 머지로 작업이 끝난 게 아니다. **머지 직후 같은 작업 단
|
|
|
62
62
|
|
|
63
63
|
## 현행 vs archive
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- 변경 이력이 길어진 문서는 이력만 archive 로 빼고 본문에는 최근분만 남긴다.
|
|
65
|
+
현행 SSOT 만 루트/`docs/` 에 둔다 — 위 위계 문서 + `specs/` + `decisions/`. 히스토리(옛 버전, 폐기
|
|
66
|
+
sub-spec, 완료된 audit 산출물)는 `docs/archive/` 로 격리하고 지도 파일(`archive/README.md`) 하나로 찾게 한다. 현행
|
|
67
|
+
문서에 히스토리가 쌓이면 "지금 무엇이 맞는지" 읽는 비용이 히스토리에 비례해 커진다. 이력이 길어진
|
|
68
|
+
문서는 이력만 빼고 본문엔 최근분만 남긴다.
|
|
70
69
|
|
|
71
70
|
## 작성 원칙
|
|
72
71
|
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
- **추정/임의 단정 금지** — "직관상 별로", "일반적으로 필요", "내 경험상"은 출처 없는 일반화.
|
|
76
|
-
측정/스펙 참조/재현 증거로 입증한다.
|
|
72
|
+
**why 중심으로 쓴다** — what 은 코드와 diff 가 보여준다. SPEC 이 800줄을 넘으면 기능별로 분리한다
|
|
73
|
+
(`spec-scaling` 스킬). 추정·임의 단정 금지는 `CLAUDE.md` 의 Anti-Patterns 가 소유한다.
|
|
77
74
|
|
|
78
75
|
## 검증 게이트
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
검출한다 — verify
|
|
77
|
+
`.claude/hooks/spec-drift-check.sh`(전 트랙 설치)가 SPEC/TODO 의 미완 잔존·Status 불일치를
|
|
78
|
+
검출한다 — verify 는 경고, ship 은 차단.
|
|
82
79
|
|
|
83
|
-
**한계를 알고 써라**: 탐지
|
|
84
|
-
|
|
85
|
-
게이트 쪽을 넓혀라, 프로즈를 늘리지 말고.
|
|
80
|
+
**한계를 알고 써라**: 탐지 경로 밖의 문서 레이아웃은 게이트가 못 본다. 그 경우 본 규약은 프로즈로만
|
|
81
|
+
작동한다 — 안 지켜져도 아무도 안 막는다. 그게 확인되면 **게이트를 넓혀라, 프로즈를 늘리지 말고.**
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
**한 경로의 증거를 다른 경로에 전용하지 않는다** (플래그가 통과했다고 위저드도 된다고 쓰는 것).
|
|
20
20
|
|
|
21
21
|
실패한 명령은 산출물을 내지 않는다 — **빈 결과는 부재의 증거가 아니다**. 확인 명령에 `2>/dev/null`
|
|
22
|
-
을 붙이면 실패와 "이상 없음"이 구분되지 않는다 (`cli-development.md` 참조).
|
|
22
|
+
을 붙이면 실패와 "이상 없음"이 구분되지 않는다 (설치돼 있으면 `cli-development.md` 참조).
|
|
23
23
|
|
|
24
24
|
## 완료 보고 양식
|
|
25
25
|
|
|
@@ -64,4 +64,4 @@
|
|
|
64
64
|
|
|
65
65
|
1. 즉시 정정 보고 — 어느 보고가 어떻게 거짓이었는지 명시한다. 조용히 고치지 않는다.
|
|
66
66
|
2. 수정을 최우선으로 처리한다.
|
|
67
|
-
3. 재발이면
|
|
67
|
+
3. 재발이면 기록 → 룰 → 구조 게이트 사다리를 탄다 (`recurrence-prevention` 스킬이 없으면 직접).
|
|
@@ -1,66 +1,24 @@
|
|
|
1
1
|
# Playwright Launch
|
|
2
2
|
|
|
3
|
-
브라우저를 띄워 **사용자가 직접
|
|
3
|
+
브라우저를 띄워 **사용자가 직접 쓰는** 모든 상황(E2E 수동 확인, UX 비교, fidelity audit, OAuth
|
|
4
|
+
로그인)에 적용. 여기 남긴 것은 **위반을 막는 금지문뿐**이다 — 절차·스크립트 골격·사용 패턴은
|
|
5
|
+
`ui-visual-review` 스킬이 SSOT. 금지문만 상주하는 이유는 위반이 **작업을 시작한 뒤에** 일어나서,
|
|
6
|
+
스킬 발화를 기다리면 이미 늦기 때문이다.
|
|
4
7
|
|
|
5
8
|
## 절대 금지
|
|
6
9
|
|
|
7
|
-
-
|
|
8
|
-
- Playwright MCP (`
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
- reference SaaS
|
|
10
|
+
- **사용자 활성 Chrome 에 attach** (`mcp__chrome-devtools__*`) — 입력 latency.
|
|
11
|
+
- **일회성 browser context** (Playwright MCP, `browser.newContext()`) — 영속 profile dir 이 없어
|
|
12
|
+
cookie/IndexedDB/SW 가 휘발한다. 매 launch 재로그인 + 버벅임.
|
|
13
|
+
- **사용자가 키를 입력하는 동안 자동화 process 동시 실행** (CDP latency).
|
|
14
|
+
- **reference SaaS(Linear/Notion/Jira 등) 측 `page.goto()`·`page.reload()`** — sidebar click only.
|
|
12
15
|
|
|
13
|
-
## 필수
|
|
16
|
+
## 필수
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
2. **Chrome for Testing 별도 binary** — `npx playwright install chromium` 으로 받은 `~/Library/Caches/ms-playwright/chromium-*/chrome-mac-arm64/Google Chrome for Testing.app`. 사용자 일반 Chrome 과 완전 분리.
|
|
18
|
-
3. **사용자 키 입력 시 자동화 layer 0** — main session 은 chromium 창 띄우기만. **사용자가 키보드 직접 입력**. 자동화 capture/검증은 **별도 process** (`node scripts/<launch>.mjs`) 에서 입력 끝난 후.
|
|
19
|
-
4. **자체 구현 측 = dev bypass auth** — Google OAuth 등 webdriver 차단 회피. 예: `POST /api/v1/_dev/test-login` 으로 JWT cookie 발급.
|
|
18
|
+
영속 profile dir + Chrome for Testing 별도 binary. 사용자 입력 구간에는 자동화 layer 0 — capture 는
|
|
19
|
+
입력이 끝난 뒤 별도 process 에서. 구현 형태는 `ui-visual-review` 스킬 참조.
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## 위반 시
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const PROFILE_DIR = process.env.PROJECT_PROFILE_DIR || `${process.env.HOME}/.<project>-audit-profile`;
|
|
27
|
-
const TARGET = process.env.PROJECT_URL || 'http://localhost:<port>';
|
|
28
|
-
const TEST_KEY = process.env.E2E_TEST_KEY || 'e2e-dev-key';
|
|
29
|
-
|
|
30
|
-
const ctx = await chromium.launchPersistentContext(PROFILE_DIR, {
|
|
31
|
-
headless: false,
|
|
32
|
-
viewport: { width: 1440, height: 900 },
|
|
33
|
-
args: ['--disable-blink-features=AutomationControlled', '--no-first-run', '--no-default-browser-check'],
|
|
34
|
-
});
|
|
35
|
-
const page = ctx.pages()[0] ?? (await ctx.newPage());
|
|
36
|
-
|
|
37
|
-
// (선택) dev bypass auth — same-origin cookie 자동 저장
|
|
38
|
-
await page.goto(`${TARGET}/`, { waitUntil: 'domcontentloaded' });
|
|
39
|
-
await ctx.request.post(`${TARGET}/api/v1/_dev/test-login`, {
|
|
40
|
-
data: { key: TEST_KEY, email: 'e2e@example.local' },
|
|
41
|
-
});
|
|
42
|
-
await page.reload({ waitUntil: 'networkidle' });
|
|
43
|
-
|
|
44
|
-
// 창 떠 있게 두고 자동화 detach — 사용자가 직접 사용.
|
|
45
|
-
// ctx.close() 호출 금지.
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## 사용 패턴
|
|
49
|
-
|
|
50
|
-
### A. 사용자가 직접 보고 싶을 때 (most common)
|
|
51
|
-
|
|
52
|
-
1. `pkill -f "playwright|Chrome for Testing"` 기존 launcher 정리 (선택)
|
|
53
|
-
2. `node scripts/<project>-launch.mjs` 실행 (chromium 창 살아있어야 함, 백그라운드 X)
|
|
54
|
-
3. 사용자에게 "URL: localhost:<port>, 로그인됨, 직접 사용하세요" 보고
|
|
55
|
-
4. **MCP playwright 로 추가 navigation/evaluate 금지** — 사용자 입력과 충돌
|
|
56
|
-
|
|
57
|
-
### B. fidelity 비교 / audit 자동 capture
|
|
58
|
-
|
|
59
|
-
1. `node scripts/<audit>.mjs` — launchPersistentContext + 비교 시나리오 자동 click
|
|
60
|
-
2. 산출물 = `docs/research/<ref>_audit_<sprint>/iter_<N>/`
|
|
61
|
-
|
|
62
|
-
## 위반 시 즉시 조치
|
|
63
|
-
|
|
64
|
-
1. 일회성 Playwright MCP context 사용 발견 → 닫고 영속 profile launcher 로 재기동
|
|
65
|
-
2. `chrome-devtools` MCP attach 발견 → 즉시 detach + Playwright 영속 패턴 전환
|
|
66
|
-
3. 사용자가 "버벅인다" / "느리다" 호소 → 본 rule 위반 확인 1순위
|
|
23
|
+
일회성 context 나 devtools attach 를 발견하면 즉시 닫고 영속 profile launcher 로 재기동한다.
|
|
24
|
+
사용자가 "버벅인다"고 하면 본 rule 위반 확인이 1순위다.
|
|
@@ -84,10 +84,17 @@ EOF
|
|
|
84
84
|
bash .claude/skills/codex-consult/scripts/codex-ask.sh -g ./scratch "PROMPT"
|
|
85
85
|
# attach input image(s) (screenshot to describe, reference for a redraw):
|
|
86
86
|
bash .claude/skills/codex-consult/scripts/codex-ask.sh -i shot.png "PROMPT"
|
|
87
|
-
# override model (default = codex's
|
|
88
|
-
bash .claude/skills/codex-consult/scripts/codex-ask.sh -m
|
|
87
|
+
# override model — only when the USER names one (default = codex's own default):
|
|
88
|
+
bash .claude/skills/codex-consult/scripts/codex-ask.sh -m MODEL_ID "PROMPT"
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
**Leave `-m` off by default.** With no `-m` the wrapper passes no model flag at
|
|
92
|
+
all, so codex uses whatever the user's own config selects — that tracks model
|
|
93
|
+
upgrades for free, while a model id written down here (or remembered from a
|
|
94
|
+
previous session) goes stale and pins the user to a retired model. Codex has no
|
|
95
|
+
`models` subcommand to enumerate against; the model codex actually used is
|
|
96
|
+
printed on **stderr** (`model: …`) — read it back if it matters.
|
|
97
|
+
|
|
91
98
|
Output contract: **stdout** carries only codex's final message, wrapped in
|
|
92
99
|
`<untrusted-codex-output>` tags; progress noise and — with `-g` — the list of
|
|
93
100
|
copied files go to **stderr**. Read both streams.
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gemini-consult
|
|
3
3
|
description: >-
|
|
4
|
-
Consult Google Gemini (via the local Antigravity `agy` CLI,
|
|
5
|
-
Pro) for three things: (1) natural, native-sounding KOREAN phrasing — copy,
|
|
4
|
+
Consult Google Gemini (via the local Antigravity `agy` CLI, Pro tier) for three things: (1) natural, native-sounding KOREAN phrasing — copy,
|
|
6
5
|
UI microcopy, marketing/brochure text, toasts, user-facing messages,
|
|
7
6
|
translations, rewrites — (2) a MULTI-PERSONA / second-opinion review of a
|
|
8
7
|
design, plan, spec, PR, or piece of writing, and (3) IMAGE GENERATION via
|
|
@@ -70,11 +69,11 @@ not bundled here. The wrapper resolves it at `$AGY_BIN` or `~/.local/bin/agy`.
|
|
|
70
69
|
## How to call it
|
|
71
70
|
|
|
72
71
|
Prefer the **bundled wrapper** — it encodes every guardrail in one place
|
|
73
|
-
(neutral cwd so the repo is NOT pulled into agy's workspace, model
|
|
74
|
-
allowlist, secret-shaped-prompt refusal, portable timeout,
|
|
75
|
-
artifact collection for image mode). It ships next to this
|
|
76
|
-
harness installs the skill directory. Run it via `bash` (no
|
|
77
|
-
assumption):
|
|
72
|
+
(neutral cwd so the repo is NOT pulled into agy's workspace, tier→model
|
|
73
|
+
resolution, env allowlist, secret-shaped-prompt refusal, portable timeout,
|
|
74
|
+
correct flag order, artifact collection for image mode). It ships next to this
|
|
75
|
+
skill when the harness installs the skill directory. Run it via `bash` (no
|
|
76
|
+
execute-bit assumption):
|
|
78
77
|
|
|
79
78
|
```bash
|
|
80
79
|
# Claude Code, project scope (harness default):
|
|
@@ -87,14 +86,19 @@ bash .claude/skills/gemini-consult/scripts/gemini-ask.sh <<'EOF'
|
|
|
87
86
|
EOF
|
|
88
87
|
# image generation — files land in OUT_DIR (see Mode C):
|
|
89
88
|
bash .claude/skills/gemini-consult/scripts/gemini-ask.sh -g ./scratch "PROMPT"
|
|
90
|
-
#
|
|
91
|
-
bash .claude/skills/gemini-consult/scripts/gemini-ask.sh -
|
|
89
|
+
# pro is the default; -t claude switches vendor (see "Which tier" below):
|
|
90
|
+
bash .claude/skills/gemini-consult/scripts/gemini-ask.sh -t claude "PROMPT"
|
|
91
|
+
# exact model, skipping tier resolution — read the slug out of `agy models`,
|
|
92
|
+
# don't type one from memory (agy rejects a retired model outright):
|
|
93
|
+
bash .claude/skills/gemini-consult/scripts/gemini-ask.sh -m SLUG "PROMPT"
|
|
92
94
|
```
|
|
93
95
|
|
|
94
96
|
Output contract: **stdout** carries only Gemini's reply, wrapped in
|
|
95
|
-
`<untrusted-gemini-output>` tags; progress
|
|
96
|
-
|
|
97
|
-
|
|
97
|
+
`<untrusted-gemini-output>` tags; progress, the resolved model line
|
|
98
|
+
(`tier 'pro' → model '…'`) and — with `-g` — the list of collected files go
|
|
99
|
+
to **stderr**. Read that model line back to the user when the tier mattered:
|
|
100
|
+
which model answered is part of the answer. Flags must come *before* the
|
|
101
|
+
prompt (trailing flags fail loud), and a prompt starting with `-` needs a `--`
|
|
98
102
|
separator first, or use the stdin form.
|
|
99
103
|
|
|
100
104
|
Calls block synchronously — the wrapper caps a call at 300s
|
|
@@ -120,11 +124,17 @@ they can't leak into your session:
|
|
|
120
124
|
(
|
|
121
125
|
AGY="${AGY_BIN:-$(command -v agy || echo "$HOME/.local/bin/agy")}"
|
|
122
126
|
[ -x "$AGY" ] || { echo "agy not found — ask the user to install it" >&2; exit 3; }
|
|
127
|
+
"$AGY" models # → read the list, pick a slug for the tier you want:
|
|
128
|
+
# gemini-*-pro-* · claude-*
|
|
123
129
|
D="$(mktemp -d)"; trap 'rm -rf "$D"' EXIT
|
|
124
|
-
cd "$D" && "$AGY" --model="
|
|
130
|
+
cd "$D" && "$AGY" --model="<slug>" -p "PROMPT"
|
|
125
131
|
)
|
|
126
132
|
```
|
|
127
133
|
|
|
134
|
+
Read the slug out of `agy models` rather than typing one from memory — agy
|
|
135
|
+
rejects a retired model outright (`invalid model selection`, exit 1), so a
|
|
136
|
+
remembered name fails the whole call.
|
|
137
|
+
|
|
128
138
|
The `( )` subshell matters: in an interactive terminal a bare `cd` persists
|
|
129
139
|
after the block and silently relocates every later command.
|
|
130
140
|
|
|
@@ -154,6 +164,48 @@ between `-p` and the prompt makes agy ignore the prompt.
|
|
|
154
164
|
(`1. … 2. … 3. …`) and ask for the same numbering back, instead of one call
|
|
155
165
|
per string.
|
|
156
166
|
|
|
167
|
+
## Which tier — `pro` / `claude`
|
|
168
|
+
|
|
169
|
+
`-t` picks a model **family**; the concrete model is resolved from `agy models`
|
|
170
|
+
on every call, so nothing here pins a version. Two measured facts shape the
|
|
171
|
+
policy below:
|
|
172
|
+
|
|
173
|
+
- **A tier name tells you nothing about recency.** The families do not share a
|
|
174
|
+
version line — measured on 2026-07-26, the fast family was two generations
|
|
175
|
+
ahead of pro. That is exactly why nothing here pins a version string: a slug
|
|
176
|
+
typed from memory gets rejected outright (`invalid model selection`, exit 1),
|
|
177
|
+
and "the newer one" is not a property you can infer from the tier name.
|
|
178
|
+
- **The Gemini quota is one pool per account; Claude models sit outside it.**
|
|
179
|
+
Measured 2026-07-26: `gemini-3.1-pro-high`, `gemini-3.1-pro-low` and a flash
|
|
180
|
+
model all refused with the *identical* `Individual quota reached … Resets in
|
|
181
|
+
166h` while a `claude` call in the same minute answered normally. Lowering the
|
|
182
|
+
tier does not dodge it — there is nothing below to fall back to.
|
|
183
|
+
|
|
184
|
+
**Every Gemini call this skill makes uses `pro`.** The reason is what the skill is for: it exists because a second model's *judgment* is worth an external round-trip — natural Korean that doesn't read translated, personas that stay distinct, critique that finds what you missed. Those are the calls where a cheaper tier costs you the thing you came for, and a round-trip you have to redo is more expensive than the one you did right. If a call is routine enough that a fast tier would do, it probably shouldn't be an external call at all.
|
|
185
|
+
|
|
186
|
+
**`-t claude`** — agy also serves Claude models. Reach for it when:
|
|
187
|
+
|
|
188
|
+
- The Gemini quota is spent and the work can't wait for the reset; it is the
|
|
189
|
+
only tier still answering.
|
|
190
|
+
- You want a **fresh, uncontaminated read** — the call carries no repo, no
|
|
191
|
+
conversation history, and none of the framing you already committed to. When
|
|
192
|
+
you suspect your own framing is the problem, that is worth more than a
|
|
193
|
+
different vendor.
|
|
194
|
+
- You are running **on Antigravity**, where you already are Gemini: there the
|
|
195
|
+
Claude tier is the outside opinion and the Gemini tiers are the circular one.
|
|
196
|
+
|
|
197
|
+
Not for **Mode A**. This skill exists because Claude's Korean reads translated —
|
|
198
|
+
routing Korean copy back to a Claude model defeats the premise.
|
|
199
|
+
|
|
200
|
+
**So when the Gemini pool is empty, Mode A waits.** Do not quietly reroute Korean
|
|
201
|
+
copy to `-t claude` to have *something* to show: the output would carry exactly
|
|
202
|
+
the quality this skill was created to avoid, and the user would have no way to
|
|
203
|
+
tell it apart from a Gemini answer. Report the refusal and the reset time, say
|
|
204
|
+
that Korean phrasing is unavailable until then, and let the user decide — write
|
|
205
|
+
it themselves, wait, or raise the subscription. An answer the user cannot trust
|
|
206
|
+
is worth less than a clearly stated gap. (Modes B and C have no such premise:
|
|
207
|
+
`-t claude` is a legitimate substitute there.)
|
|
208
|
+
|
|
157
209
|
## Mode A — natural Korean phrasing / copy
|
|
158
210
|
|
|
159
211
|
Give Gemini the text plus the context it needs to judge register, then ask for a
|
|
@@ -225,8 +277,11 @@ full-cost regeneration.
|
|
|
225
277
|
**Image quota is small and shared across model tiers.** A handful of
|
|
226
278
|
generations can exhaust it; Gemini then answers (politely) that quota is
|
|
227
279
|
exceeded — the wrapper surfaces that as exit 5 with the explanation inside the
|
|
228
|
-
tags.
|
|
229
|
-
|
|
280
|
+
tags. Once the whole Gemini pool is spent the call doesn't even reach the tool:
|
|
281
|
+
agy fails with `Individual quota reached` and its own nonzero exit. Observed
|
|
282
|
+
reset horizon: up to ~7 days. **Another Gemini tier would not help** — one
|
|
283
|
+
pool per account; only `-t claude` sits outside it. Don't retry-loop against a quota error; relay it and fall
|
|
284
|
+
back to `codex-consult` for the image.
|
|
230
285
|
|
|
231
286
|
```
|
|
232
287
|
이미지 생성 도구로 이미지를 하나 생성해줘:
|
|
@@ -243,7 +298,7 @@ inline:
|
|
|
243
298
|
[ -x "$AGY" ] || { echo "agy not found — ask the user to install it" >&2; exit 3; }
|
|
244
299
|
BRAIN="$HOME/.gemini/antigravity-cli/brain"
|
|
245
300
|
M="$(mktemp)"; D="$(mktemp -d)"; trap 'rm -rf "$D" "$M"' EXIT
|
|
246
|
-
cd "$D" && "$AGY" --model="
|
|
301
|
+
cd "$D" && "$AGY" --model="<slug from agy models>" -p "PROMPT — 생성만 하고 셸 저장은 시도하지 마"
|
|
247
302
|
find "$BRAIN" -type f \( -name '*.png' -o -name '*.jpg' \) -newer "$M" # → report/copy these
|
|
248
303
|
)
|
|
249
304
|
```
|
|
@@ -256,11 +311,15 @@ candidates, the clustered findings, or the file paths — not raw CLI noise.
|
|
|
256
311
|
|
|
257
312
|
## On failure
|
|
258
313
|
|
|
259
|
-
- exit `2` usage
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
314
|
+
- exit `2` usage (includes an unknown `-t` tier) · `3` agy missing
|
|
315
|
+
(Prerequisite) **or `agy models` offers nothing for the tier** — stderr lists
|
|
316
|
+
what it does offer; pick one with `-m`, never assume a substitute tier ·
|
|
317
|
+
`4` secret-shaped prompt refused · `5` image mode produced no artifacts (read
|
|
318
|
+
the tagged message for why) · `124` timed out (`GEMINI_CONSULT_TIMEOUT`,
|
|
319
|
+
default 300s) — do NOT blindly re-run the same prompt.
|
|
263
320
|
- Any other nonzero exit is agy's own failure — read stderr, report it.
|
|
321
|
+
`Individual quota reached` = the Gemini pool is spent (~7 day reset); retry
|
|
322
|
+
with `-t claude`, not with another Gemini tier.
|
|
264
323
|
- `Authentication required. Please visit the URL ...` → stop; the user runs
|
|
265
324
|
`agy` interactively once (Prerequisite).
|
|
266
325
|
- `a tool required the "command" permission ...` → the prompt induced a shell
|