therookie 0.4.3 → 0.4.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "therookie",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "the Rookie — the AI new hire that remembers what you teach it. A CLI that connects a personal AI memory to AI tools like Claude and Codex.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: rookie
3
- description: Rookie 회상·저장 Skill — recall 트리거 (어제/전에/그때 등) 감지 시 GET /api/rookie/recall 강제 호출. hot write 4 카테고리 (운영사실/능력증거/자기규칙/취향)는 batch-mutate 직접 호출로 저장.
3
+ description: Rookie 회상·저장 Skill — recall 트리거 (어제/전에/그때 등) 감지 시 GET /api/rookie/recall 강제 호출. hot write 4 카테고리 (운영사실/능력증거/자기규칙/취향)는 batch-mutate 로 저장.
4
4
  version: __VERSION__
5
5
  scope: __SCOPE__
6
6
  installed_at: __INSTALLED_AT__
@@ -11,25 +11,24 @@ installed_by: __INSTALLED_BY__
11
11
 
12
12
  ## ⚡ 로드 직후 필수 (다른 응답 전에)
13
13
 
14
- 진입카드·미link 상태는 SessionStart hook 이 아니라 **이 skill 이 로드한다** — 로드되면 **다른 말을 하기 전에** 아래 "세션 시작" 절차를 실행한다:
14
+ 진입카드·미link 상태는 이 skill 이 로드한다 — 로드되면 **다른 말을 하기 전에** 아래 "세션 시작" 절차를 실행한다:
15
15
 
16
16
  1. `GET /api/rookie/context` 를 curl 로 호출해 `system_prompt`·`current_project`·`entry_cards` 전문을 받는다.
17
17
  2. **진입 카드 확인:**
18
- - **1순위**: `entry_cards[]` 를 직접 읽는다. 비어있지 않으면 **그 작업을 이어가려는 사용자 의도를 우선 가정**해 먼저 언급한다. 안전 신호 반영 — `grade` `warn`/`old` → 이미 완료됐을 수 있으니 현재 상태부터 점검하는 톤 / `is_meta_card` → 메타 카드 의심 · 단일 fact 분리 권고 · `body` 절단본이라 전량 단정 금지 / `is_vague` → 목표 수준 카드 — recall 로 방법 맥락 보강 후 착수 / `has_contradiction` → 단정 전 점검 / `reasoning` → 근거로 고려.
19
- - **activity-stale 신호(2026-07-15)**: `activity_stale=true`(또는 `newer_activity_count > 0`) → 카드는 있지만 **그 이후 같은 프로젝트에서 세션이 더 진행됐다**. `effective_grade`(age 와 activity 중 높은 등급) 를 권위 기준으로 삼아, 이어가기 전에 recall + 현재 상태(git log·해당 파일) 점검 후 착수한다. "이게 마지막 작업"이라 단정 금지.
20
- - **`ephemeral_recovery`(임시 복구, 저장 아님)**: activity-stale 카드에 붙는 read-time 합성물. **`id` 가 없다** — 저장된 카드가 아니므로 `supersedes`·`task_id` 연결 대상이 아니고, 저장된 "다음 진입 카드"처럼 다루지 않는다. 기존 stale 카드와 **함께** 보여준다("직전 카드(오래됨) + 🛟 임시 복구: <headline>"). `synthesis_tier=bare`(메타데이터뿐)면 headline 을 확정 사실처럼 전하지 말고 "세션은 있었지만 세부 기록 없음"으로만. `synthesis_tier=evidence`(self-reported artifact_paths)는 "파일이 바뀐 것으로 보고됨"이지 "확인된 변경"이 아니다. 이 정보를 근거로 **진짜 다음 카드를 새로 저장**하면 다음 조회부터 임시 복구는 자연히 사라진다.
21
- - **폴백**(구버전 서버): `system_prompt` 의 `## 🔖 진행 중 작업 카드` 마커를 grep 해 전문을 읽는다(유동 위치 — head/tail 훑기 금지). 텍스트 경로엔 `🔀 이 카드 이후 … 세션 N건` + `🛟 임시 복구(저장 아님)` 라인으로 동기돼 있다.
18
+ - **1순위**: `entry_cards[]` 를 직접 읽는다. 비어있지 않으면 **그 작업을 이어가려는 사용자 의도를 우선 가정**해 먼저 언급한다. 안전 신호 — `grade` `warn`/`old` → 이미 완료됐을 수 있으니 현재 상태부터 점검 / `is_meta_card` → 메타 카드 의심·단일 fact 분리 권고·`body` 절단본(전량 단정 금지) / `is_vague` → 목표 수준 카드 — recall 로 방법 보강 후 착수 / `has_contradiction` → 단정 전 점검 / `reasoning` → 근거로 고려.
19
+ - **activity-stale**: `activity_stale=true`(또는 `newer_activity_count>0`) → 카드 이후 같은 프로젝트에서 세션이 더 진행됐다. `effective_grade`(age·activity 중 높은 등급)를 권위 기준으로, recall + 현재 상태(git log·해당 파일) 점검 후 착수. "이게 마지막 작업" 단정 금지.
20
+ - **`ephemeral_recovery`(임시 복구, 저장 아님)**: activity-stale 카드에 붙는 read-time 합성물. `id` 없음 — `supersedes`·`task_id` 연결 금지, 저장된 "다음 카드"처럼 다루지 않는다. stale 카드와 **함께** 표시("직전 카드(오래됨) + 🛟 임시 복구: <headline>"). `synthesis_tier=bare`(메타데이터뿐)는 "세션은 있었지만 세부 기록 없음"으로만, `evidence` 는 "파일이 바뀐 것으로 보고됨"(확인된 변경 아님). 진짜 다음 카드를 새로 저장하면 다음 조회부터 사라진다.
21
+ - **폴백**(구버전 서버): `system_prompt` 의 `## 🔖 진행 중 작업 카드` 마커를 grep 해 전문을 읽는다(유동 위치 — head/tail 훑기 금지). 텍스트 경로엔 `🔀 … 세션 N건`·`🛟 임시 복구` 라인으로 동기돼 있다.
22
22
  - **무-주제 "이어서/계속하자"** 는 `entry_cards`(최신순) 우선. relevance recall 은 특정 주제를 명시했을 때만.
23
23
  - **카드 소비 규칙**: `[고정]`·`[통과]` 자산은 폐기·제외 제안 금지 / `[실패]` 접근은 재제안 금지 / "다음:" 이 목표 수준("~이어가기")뿐이면 목표를 되묻지 말고 방법 1개를 추천안 삼아 착수 보고.
24
- 3. `current_project` 가 `null` 이면 미link — §6 등록 제안을 능동 수행한다.
25
- 4. 사용자 입력에 recall 트리거가 있으면 recall 한다.
24
+ 3. `current_project` 가 `null` 이면 §6 등록 제안. 사용자 입력에 recall 트리거가 있으면 recall 한다.
26
25
 
27
26
  ## 세션 시작
28
27
 
29
- > 이하 모든 `rookie <cmd>` 는 글로벌 미설치 시 `node <the-rookie>/packages/rookie-cli/bin/rookie.js <cmd>` 로 실행한다.
28
+ > `rookie <cmd>` 는 글로벌 미설치 시 `node <the-rookie>/packages/rookie-cli/bin/rookie.js <cmd>`.
30
29
 
31
30
  1. `.rookie-ignore` 파일 / `ROOKIE_DISABLED=1` / config 파일 부재면 이 스킬 전체를 건너뜁니다.
32
- 2. config 해석(B6 다계정 격리): `ROOKIE_ENDPOINT`/`ROOKIE_TOKEN` > 프로젝트-로컬 `<dir>/.rookie/config.json`(cwd 상향 탐색) > 전역 `~/.rookie/config.json`. 로컬 config 디렉토리는 그 계정으로만 동작(`rookie login --local`).
31
+ 2. config 해석(B6 다계정 격리): `ROOKIE_ENDPOINT`/`ROOKIE_TOKEN` > 프로젝트-로컬 `<dir>/.rookie/config.json`(cwd 상향 탐색) > 전역 `~/.rookie/config.json`. 로컬 config 는 그 계정 전용(`rookie login --local`).
33
32
  3. 현재 폴더 식별: `REPO_URL` = `git remote get-url origin` (실패 시 빈 값), `REPO_PATH` = cwd.
34
33
  **git 기준점 캡처(세션 보관)**: `SESSION_START_SHA` = `git rev-parse HEAD` / `START_DIRTY` = `git status --short` + `git diff --name-only HEAD`. 이 SHA 이후 *새* 변경만 이번 세션 산물 — 시작부터 dirty 던 파일로 task 자동 전환 금지.
35
34
  4. 컨텍스트 조회:
@@ -39,74 +38,55 @@ installed_by: __INSTALLED_BY__
39
38
  "$ENDPOINT/api/rookie/context?repo_url=$(url_encode $REPO_URL)&repo_path=$(url_encode $REPO_PATH)"
40
39
  ```
41
40
  5. 응답의 `system_prompt` 를 세션 페르소나로 채택(기억 상세는 recall 위임).
42
- - **이상 신호(B1 Identity Guard)**: 주입 페르소나·계정 요약(`[루키] 계정 …` 상태줄, `metadata.account`)이 평소와 다르면(프로젝트 0·낯선 호칭·빈 계정) 작업 전에 알린다.
43
- 6. **미link 감지·능동 제안**: `current_project` 가 `null` 이면 미link. 서버가 `metadata.link_hint: 'unlinked_repo'` 를 반환하면 클라이언트 판단 없이 그 신호를 신뢰한다(B2).
41
+ - **이상 신호(B1)**: 주입 페르소나·계정 요약(`[루키] 계정 …`, `metadata.account`)이 평소와 다르면(프로젝트 0·낯선 호칭·빈 계정) 작업 전에 알린다.
42
+ 6. **미link 감지·능동 제안**: `current_project` 가 `null` 이면 미link. 서버 `metadata.link_hint:'unlinked_repo'` 신호를 클라이언트 판단 없이 신뢰한다(B2).
44
43
  - `~/.rookie/link-dismissed.json`(경로 배열)에 현재 cwd 가 있으면 안내 skip.
45
- - 없으면 **매 세션 1회** 이점을 들어 "지금 등록할까요? (원치 않으시면 '그만 물어봐')" 로 제안. git remote 있는 repo 면 특히 권한다.
44
+ - 없으면 **매 세션 1회** "지금 등록할까요? (원치 않으시면 '그만 물어봐')" 로 제안 — git remote 있는 repo 면 특히.
46
45
  - **승인 시** 루키가 `rookie link` 직접 실행 + 1줄 보고. **거부 시** link-dismissed.json 에 cwd 추가. dismiss 후에도 "등록해줘" 하면 즉시 실행.
47
46
  - 자동 등록 금지(승인 전제). recall 0건(신규면 정상)과 미link 는 다른 신호 — **후자만** 알린다.
48
47
 
49
- 6.5. **link 후속 — 스펙 연결·소개글**: `system_prompt` 에 스펙 동기화 directive 가 있으면 그 `[루키 지시]` 대로 능동 제안한다(판정은 서버 책임). directive 없으면 스펙 안내 금지.
50
- - **미연결** directive: "스펙을 연결할까요?" → 승인 시 (A)+(C). / **반쪽** directive: "동기화할까요?" → 승인 시 (A) 의 task 동기화만(PUT 생략).
51
- - **(A) 스펙 연결·동기화**: 로컬 스펙 문서를 찾아 `spec_doc_paths` 설정 + 문서별 task 동기화(문서 1개=task 1개, `spec_ref`=파일경로, `spec_html`=렌더 HTML). **task 는 전부 todo 시작(스펙 ≠ 구현)** — sync 에 `status` 금지(서버가 todo 고정). 진척은 증거 기반 `PATCH /api/rookie/tasks`. 재동기화해도 기존 status 보존.
52
- ```bash
53
- # 미연결일 때만
54
- curl -s -X PUT "$ENDPOINT/api/rookie/projects/spec-source" -H "Authorization: Bearer $TOKEN" \
55
- -H "Content-Type: application/json" -d '{"project_id":"<id>","spec_doc_paths":["docs/specs/**"]}'
56
- # 공통
57
- curl -s -X POST "$ENDPOINT/api/rookie/tasks/sync" -H "Authorization: Bearer $TOKEN" \
58
- -H "Content-Type: application/json" \
59
- -d '{"project_id":"<id>","items":[{"title":"<스펙 제목>","spec_ref":"<파일경로>","spec_html":"<렌더 HTML>"}]}'
60
- ```
61
- 스펙 문서가 없으면 "같이 만들까요?" → brainstorming 으로 작성 후 연결.
62
- - **(C) 소개글**: 소개글이 비어 있으면 README·CLAUDE.md 파악 후 1~2문장 초안을 `PATCH /api/rookie/projects {"id","description"}` — 기존 소개글 덮어쓰기 금지. 완료 시 1줄 보고.
63
- - **거부** 시 `POST /api/rookie/projects/spec-dismiss {"project_id":"<id>","dismissed":true}` (되돌리기는 `false`). 명시 요청은 dismiss 와 무관하게 수행.
64
- - 미link(§6) → 미스펙(directive) → 정상 3단계 신호를 구분해 해당 단계만 1회 알린다(승인 전제).
48
+ 6.5. **link 후속 — 스펙 연결·소개글**: `system_prompt` 에 스펙 동기화 directive(`[루키 지시]`)가 있을 때만 능동 제안한다(판정은 서버 책임). **미연결** directive → "스펙을 연결할까요?" → 승인 시 (A)+(C) / **반쪽** directive → "동기화할까요?" → 승인 시 (A) 의 task 동기화만(PUT 생략).
49
+ - **(A) 스펙 연결·동기화**: 로컬 스펙 문서를 찾아 `spec_doc_paths` 설정 + 문서별 task 동기화(문서 1개=task 1개). **task 는 전부 todo 시작(스펙 ≠ 구현)** — sync 에 `status` 금지(서버가 todo 고정), 재동기화해도 기존 status 보존. 진척은 증거 기반 `PATCH /api/rookie/tasks`.
50
+ - 미연결일 때만: `PUT /api/rookie/projects/spec-source {"project_id":"<id>","spec_doc_paths":["docs/specs/**"]}`
51
+ - 공통: `POST /api/rookie/tasks/sync {"project_id":"<id>","items":[{"title":"<스펙 제목>","spec_ref":"<파일경로>","spec_html":"<렌더 HTML>"}]}`
52
+ - 스펙 문서가 없으면 "같이 만들까요?" → brainstorming 으로 작성 후 연결.
53
+ - **(C) 소개글**: 비어 있으면 README·CLAUDE.md 파악 후 1~2문장 초안을 `PATCH /api/rookie/projects {"id","description"}` — 기존 소개글 덮어쓰기 금지. 완료 시 1줄 보고.
54
+ - **거부** 시 `POST /api/rookie/projects/spec-dismiss {"project_id":"<id>","dismissed":true}` (되돌리기는 `false`). 명시 요청은 dismiss 와 무관하게 수행. 미link(§6) → 미스펙(directive) → 정상 3단계 중 해당 단계만 1회 알린다(승인 전제).
65
55
 
66
- 6.6. **spec 후속 자동 스캔**: link + `spec_doc_paths` 설정 시 세션 시작 1회 `rookie scan-specs`(cli 가 하루 1회 throttle — 중복 안전). 결과는 조용히 둔다(proposal 은 `/projects` 에서 처리). "후속 스캔해줘" 하면 `--force`. 미link·미설정·실패는 조용히 skip.
56
+ 6.6. **spec 후속 자동 스캔**: link + `spec_doc_paths` 설정 시 세션 시작 1회 `rookie scan-specs`(하루 1회 throttle — 중복 안전). 결과는 조용히 둔다(proposal 은 `/projects` 에서 처리). 명시 요청 시 `--force`. 미link·미설정·실패는 조용히 skip.
67
57
 
68
58
  7. **임베딩 헬스 경고**: `embedding_health.degraded:true` 면 세션당 1회 — ``⚠️ 회상 임베딩 가동률 {ratio×100}% (최근 {window_days}일 {call_count}건) — 키/quota 점검 필요.`` `false` 면 침묵.
69
- 8. **완료 후보 surface**: `## 🎯 완료 후보 감지` 블록의 `🎯 <task_id(전체 UUID)> "<title>" ← <sha> <subject>` 줄이 보이면 **다른 응답 전에** 각 후보를 done 승인 게이트로 여쭙는다. UUID 는 PATCH 용 — 두목께는 title 로만(§10e). `<sha>` 는 줄의 값 그대로(자르지 말 것):
70
- - `"'<title>' 을 완료로 올릴까요? — 근거: 커밋 <sha> <subject>"` → OK 시에만 `PATCH {id, status:'done', detail:'<기존>\n\n✅ 완료 <date> — 커밋 <sha>'}`. **자동 done 금지.**
71
- - "아직/보류" 면 `PATCH {id, detail:'<기존>\n__done_defer:<sha>'}` 로 재알림 차단 — 이후 **다른 새 커밋** 매칭 시만 재surface.
72
- - 블록 없으면 침묵. 근거는 주입된 git 출력만(자기 서술 근거·self-loop 금지).
59
+ 8. **완료 후보 surface**: `## 🎯 완료 후보 감지` 블록의 `🎯 <task_id(전체 UUID)> "<title>" ← <sha> <subject>` 줄이 보이면 **다른 응답 전에** 후보별 done 승인 게이트로 여쭙는다(UUID 는 PATCH 용 — 두목께는 title 로만. `<sha>` 는 줄의 값 그대로): `"'<title>' 을 완료로 올릴까요? — 근거: 커밋 <sha> <subject>"` → OK 시에만 `PATCH {id, status:'done', detail:'<기존>\n\n✅ 완료 <date> — 커밋 <sha>'}` (**자동 done 금지**) / "아직/보류" 면 `PATCH {id, detail:'<기존>\n__done_defer:<sha>'}` 로 재알림 차단 — 이후 **다른 새 커밋** 매칭 시만 재surface. 블록 없으면 침묵. 근거는 주입된 git 출력만(self-loop 금지).
73
60
  9. 실패(HTTP·네트워크)는 조용히 폴백 — 현재 프로젝트 `CLAUDE.md` 만 따릅니다.
74
61
 
75
62
  ## 복구 세션 tail 추출
76
63
 
77
64
  비정상 종료 세션은 Stop hook 이 못 돌아 fact·진입카드가 없다 — chunk 복구는 `orphan_recover`, **fact 추출은 차차 책임**(서버 추출 off). 컨텍스트에 ``🛟 …`` 블록과 ``- <sid> :: <transcript_path>`` 목록이 보이면 **다른 응답 전에** 처리한다:
78
65
 
79
- 1. `rookie orphan-extract --batch=5` — 대기 세션을 오래된 순으로 읽어 rule-base 초안(요약·파일 경로·git sha, redact 통과)을 뽑아 준다. transcript 원문 통째 Read 금지(부족할 때만 보조 확인 — Claude `~/.claude/projects/`, Codex `~/.codex/sessions/`).
66
+ 1. `rookie orphan-extract --batch=5` — 대기 세션을 오래된 순으로 읽어 rule-base 초안(요약·파일 경로·git sha, redact 통과)을 뽑는다. transcript 원문 통째 Read 금지(부족할 때만 보조 — Claude `~/.claude/projects/`, Codex `~/.codex/sessions/`).
80
67
  2. 초안에서 **저장 가치가 있는 것만** — 운영 사실/결정→working_card, 파일·결과물→evidence, 명시적 자기규칙→self_rule, 취향→personal_fact. 잡담·민감정보 금지(redactor 원칙). 0건 세션도 정상.
81
68
  3. **recall 로 dedup 후** 누락분만 `POST /api/rookie/batch-mutate`(`project_id` 포함).
82
- 4. 처리한 세션마다(0건이어도) 초안 하단의 완료 marker 명령을 **그대로** 실행해 큐에서 비운다 — 안 하면 매 세션 재노출된다:
69
+ 4. 처리한 세션마다(0건이어도) 초안 하단의 완료 marker 명령을 **그대로** 실행해 큐에서 비운다 — 안 하면 매 세션 재노출:
83
70
  ```bash
84
71
  source "$HOME/.rookie/bin/lib/orphan-recovery.sh" 2>/dev/null && orphan_mark_client_extracted '<sid>'
85
72
  ```
86
- (로컬 설치면 `<project>/.rookie/bin/lib/orphan-recovery.sh`) Codex 세션은 `ROOKIE_ORPHAN_DIR="…/codex"` prefix 로 나온다. transcript 소실 세션도 안내대로 marker 로 비운다.
87
- 5. 한 줄 보고(`[복구] 세션 N건 tail 추출·저장`). raw transcript·UUID 나열 금지. 남은 대기는 다음 세션에서 이어서.
73
+ (로컬 설치면 `<project>/.rookie/bin/…`) Codex 세션은 `ROOKIE_ORPHAN_DIR="…/codex"` prefix. transcript 소실 세션도 marker 로 비운다.
74
+ 5. 한 줄 보고(`[복구] 세션 N건 tail 추출·저장`). raw transcript·UUID 나열 금지. 남은 대기는 다음 세션에서.
88
75
 
89
- ## 컨텍스트 다이어트 (주1회, 승인 게이트 — spec 2026-07-10)
76
+ ## 컨텍스트 다이어트 (주1회, 승인 게이트)
90
77
 
91
- 주 1회 SessionStart hook 이 `rookie context-diet` 로 임계 초과를 감지하면 ``## 🍞 컨텍스트 다이어트 권고`` 블록을 주입한다. 블록이 보이면 **다른 응답 전에 1회** 제안, 없으면 침묵. **전 항목 승인 게이트 — 자동 실행 없음.** 승인 시:
78
+ 주 1회 SessionStart hook 이 임계 초과를 감지하면 ``## 🍞 컨텍스트 다이어트 권고`` 블록을 주입한다. 블록이 보이면 **다른 응답 전에 1회** 제안, 없으면 침묵. **전 항목 승인 게이트 — 자동 실행 없음.** 승인 시:
92
79
  - **CLAUDE.md**: 아카이브성 내용 `docs/` 이관 + 참조 1줄 치환. 의미 단위 압축(단순 truncate 금지). diff 제시 → 승인 후 커밋.
93
80
  - **스킬 정리**: 0회 후보 제시 → 고른 것만. settings 비활성화(가역) 우선 / 폴백 `~/.claude/skills/<name>` → `skills.disabled/` 이동(삭제 아님, symlink·플러그인은 안내만). keep 은 `~/.rookie/context-diet-keep.json`.
94
81
  - **루키 자기 다이어트**: rookie Skill 문서 중복 정리 — diff 제시 → 승인 후 반영(템플릿 SSOT 커밋 + 재배포).
95
82
 
96
- **거부/보류 snooze**: `~/.rookie/context-diet-snooze.json` 에 `{"<key>":"<ISO until>"}` 30일(전체 거부면 90일. key = claude_md_project·claude_md_total·skills_agents_desc·rookie_self·unused_skills). snooze 는 블록에서 자동 제외. 실패 항목만 1줄 보고. 상시 현황 `rookie doctor`.
83
+ **거부/보류 snooze**: `~/.rookie/context-diet-snooze.json` 에 `{"<key>":"<ISO until>"}` 30일(전체 거부 90일. key = claude_md_project·claude_md_total·skills_agents_desc·rookie_self·unused_skills). 실패 항목만 1줄 보고. 현황 `rookie doctor`.
97
84
 
98
85
  ## 회상 (recall)
99
86
 
100
- 다음 트리거가 **사용자 메시지에** 등장하면 반드시 `/api/rookie/recall` 호출:
101
-
102
- | 카테고리 | 키워드 |
103
- |---|---|
104
- | 시간 단서 | 어제·전에·그때·예전에·이전에·지난번·저번에 |
105
- | 작업 동사 | 진행해·이어·계속·다음·마저·배포·마무리 |
106
- | 환경 질의 | 포트·유저명·경로·서버·호스트·도메인 |
107
- | 과거 방법·재현 | 기존·예전·저번·어떻게 했/만들었/제작·재현·다시/새로 만들·파이프라인·방식 |
87
+ 다음 트리거가 **사용자 메시지에** 등장하면 반드시 `/api/rookie/recall` 호출 — 시간 단서(어제·전에·그때·예전에·이전에·지난번·저번에) / 작업 동사(진행해·이어·계속·다음·마저·배포·마무리) / 환경 질의(포트·유저명·경로·서버·호스트·도메인) / 과거 방법·재현(기존·어떻게 했/만들었/제작·재현·다시/새로 만들·파이프라인·방식).
108
88
 
109
- > **표는 예시다 (전부 아님).** 과거에 무엇을·어떻게 했는지가 답에 필요한 질문은 키워드가 없어도 grep/ls/파일 열람 **이전에** recall 을 먼저 호출한다. 애매하면 되묻기 전에 recall 먼저.
89
+ > **위는 예시다 (전부 아님).** 과거에 무엇을·어떻게 했는지가 답에 필요한 질문은 키워드가 없어도 grep/ls/파일 열람 **이전에** recall 을 먼저 호출한다. 애매하면 되묻기 전에 recall 먼저.
110
90
 
111
91
  기본은 `scope=all` (식별자 불필요, 항상 동작):
112
92
  ```
@@ -115,38 +95,32 @@ curl -s -H "Authorization: Bearer $TOKEN" \
115
95
  ```
116
96
  ⚠️ `scope=project` 는 `repo_url`·`repo_path` 필수 — 없으면 fail-closed 로 **무조건 0건**. 꼭 필요한 게 아니면 `scope=all`.
117
97
 
118
- 응답 `results[]` 의 `summary` 를 컨텍스트로 활용. 0건이면 추측하지 말고 아는 범위로 답하되 "recall 0건" 류 문구를 화면에 내지 않는다.
98
+ 응답 `results[]` 의 `summary` 를 활용. 0건이면 추측 말고 아는 범위로 답하되 "recall 0건" 류 문구는 화면에 내지 않는다.
119
99
 
120
100
  - **출처 프로젝트 구분 (필수)**: `project_name` 이 현재 세션 프로젝트와 **다르면** 출처를 밝히고, **현 세션의 "다음 할 일" 후보로 제안하지 않는다**(두목이 명시 언급 시 예외). `null` 은 전역/개인 — "(전역)" 표기.
121
101
  - **같은 주제 "다음:" 카드가 여러 장이면** `memory_at`(ISO 시각) 최신 카드가 현재 상태 기준. 구 카드는 이력으로만.
122
- - **0건 + `meta.fail_closed:true` 자가교정** (알리지 않고 1회 재시도): `missing_project_identifier` → 식별자 넣거나 `scope=all` / `project_not_linked` → `scope=all`.
102
+ - **0건 + `meta.fail_closed:true` 자가교정**(조용히 1회 재시도): `missing_project_identifier` → 식별자 추가 또는 `scope=all` / `project_not_linked` → `scope=all`.
123
103
  - **자기 출력 분석 금지** — 트리거는 사용자 입력에서만(self-loop 위험). **매 turn 호출 금지** — 트리거 등장 시만.
124
104
 
125
105
  ## 저장 (hot write, batch-mutate 직접 호출)
126
106
 
127
- | 카테고리 | 트리거 | 대상 |
128
- |---|---|---|
129
- | 운영 사실 | 자동 (서버/포트/유저명/경로/명시 결정) | working_cards |
130
- | 능력 증거 | 자동 (파일·결과물 산출 시) | evidence |
131
- | 자기 규칙 | 사용자 명시 시그널만 ("원칙·습관·항상·절대") | self_rules |
132
- | 개인 취향 | 사용자 명시 시그널만 ("좋아해·선호·취향") | personal_fact 별도 경로 |
133
- | 잡담·일회성 / 민감 정보 | 저장 안 함 | — |
107
+ 카테고리: 운영 사실(서버/포트/유저명/경로/명시 결정, 자동) → working_cards / 능력 증거(파일·결과물 산출 시, 자동) → evidence / 자기 규칙(사용자 명시 시그널 "원칙·습관·항상·절대" 만) → self_rules / 개인 취향(명시 시그널 "좋아해·선호·취향" 만) → personal_fact 별도 경로 / 잡담·일회성·민감 정보 → 저장 안 함.
134
108
 
135
- 저장 전 **recall 로 먼저 dedup** → 이미 있으면 저장 안 함(1차 책임은 루키). 성공 시 1줄 알림(`[기억] <요약> 저장`). 실패 시 retry 1회 + 알림.
109
+ 저장 전 **recall dedup** — 이미 있으면 저장 안 함(1차 책임은 루키). 성공 시 `[기억] <요약> 저장` 1줄, 실패 시 retry 1회 + 알림.
136
110
 
137
- **`rookie:mutate` fence 를 사용자 화면에 출력하지 않는다** — 저장은 `batch-mutate` 를 Bash 로 직접 호출하고 화면엔 `[기억] …` 한 줄만. (endpoint/token 은 `~/.rookie/config.json`. 토큰 출력 금지.)
111
+ **`rookie:mutate` fence 를 화면에 출력하지 않는다** — 저장은 Bash 직접 호출, 화면엔 `[기억] …` 한 줄만(endpoint/token 은 `~/.rookie/config.json`, 토큰 출력 금지).
138
112
 
139
113
  ```bash
140
114
  rookie save --file <body.json> # 또는: echo '<body>' | rookie save
141
115
  ```
142
- ⚠️ **`curl` 로 직접 batch-mutate 를 치지 않는다.** `rookie save` 가 **cwd·git remote·hostname 을 자동 주입**한다 — 차차가 워크스페이스 식별자를 빠뜨릴 여지 자체를 없애기 위한 진입점이다(2026-07-14: 손으로 붙이던 구조 때문에 evidence 의 51%가 전역으로 샜다). 본문에는 **기억할 내용만** 담는다.
116
+ ⚠️ **`curl` 로 직접 batch-mutate 를 치지 않는다.** `rookie save` 가 **cwd·git remote·hostname 을 자동 주입**한다 — 식별자 누락으로 전역에 새는 사고를 막는 진입점이다. 본문에는 **기억할 내용만** 담는다.
143
117
 
144
- ⚠️ **전역 fact 는 `project_id: null` 을 명시한다.** 워크스페이스도 명시 의사도 없으면 서버가 `missing_workspace_context` 로 **거부**한다(조용한 전역 누수 차단). 미등록 폴더(link 안 된 곳)의 저장은 전역이 아니라 **그 폴더에 격리**되며, 나중에 `rookie link` 하면 자동 승격된다.
118
+ ⚠️ **전역 fact 는 `project_id: null` 을 명시한다.** 식별자도 명시 의사도 없으면 서버가 `missing_workspace_context` 로 **거부**(조용한 전역 누수 차단). 미등록 폴더의 저장은 전역이 아니라 **그 폴더에 격리**, 이후 `rookie link` 시 자동 승격.
145
119
 
146
120
  `<body>` 스키마 (필요한 키만):
147
121
  ```json
148
122
  {
149
- "working_cards": { "items": [ { "summary": "진입 카드 본문", "verification": { "method": "ssh|curl|git|grep|lsof|read|reasoning|assertion", "evidence": "직접 명령 결과 한 줄" }, "supersedes": ["부모 fact UUID"], "tags": ["custom"], "ttl_at": "ISO8601?", "artifact_paths": ["task 매칭 입력용? ≤20 (저장 안 함)"], "project_id": "?", "task_id": "? (트리거 조건 참조)" } ], "repo_url": "(권장) git remote — 없으면 project 귀속 안 됨", "repo_path": "(권장) repo_url 없을 때 hostname 과 매칭", "project_id": "(레거시) batch 기본 — item 이 우선, 보통 생략", "conversation_id": "uuid?" },
123
+ "working_cards": { "items": [ { "summary": "진입 카드 본문", "verification": { "method": "ssh|curl|git|grep|lsof|read|reasoning|assertion", "evidence": "직접 명령 결과 한 줄" }, "supersedes": ["부모 fact UUID"], "tags": ["custom"], "ttl_at": "ISO8601?", "artifact_paths": ["task 매칭용? ≤20 (저장 안 함)"], "project_id": "?", "task_id": "?" } ], "repo_url": "(권장) git remote — 없으면 project 귀속 안 됨", "repo_path": "(권장) repo_url 없을 때 hostname 매칭", "project_id": "(레거시) item 이 우선, 보통 생략", "conversation_id": "uuid?" },
150
124
  "self_rules": [ { "category": "identity|voice|work_style|strength|preference|rule", "rule": "규칙 본문", "confidence": "high|medium|low", "supersedes": "기존 rule UUID?", "deprecation_reason": "user_override|conflict|noise|manual?" } ],
151
125
  "evidence": [ { "capability": "능력 진술문", "approach": "접근법?", "status": "completed|in-progress?", "context": "맥락?", "artifact_paths": ["파일 절대경로 (project 폴백 매칭에도 쓰임)"], "project_id": "? (uuid=명시 귀속 / null=전역 / 생략=세션 귀속)" } ],
152
126
  "verifications": [ { "fact_id": "검증 대상 fact UUID", "method": "(위와 동일 enum)", "outcome": "confirmed|refuted|ambiguous", "evidence": "검증 명령 결과 한 줄" } ]
@@ -154,20 +128,20 @@ rookie save --file <body.json> # 또는: echo '<body>' | rookie save
154
128
  ```
155
129
 
156
130
  ### 응답 확인 — `all_committed` 게이트 + 귀속 확인
157
- **귀속 확인 (all_committed 와 무관)**: `repo_url`/`repo_path` 를 보냈는데 응답 `working_cards.project_attributed` 가 `false` 이거나 `evidence.unattributed` 가 0 보다 크면(전역 의도로 `project_id:null` 명시한 경우 제외) `⚠️ [기억] 프로젝트 미귀속 저장 — rookie link 상태 확인 필요` 1줄 경고. 조용한 전역 NULL 누수 금지.
131
+ **귀속 확인**(all_committed 와 무관): `repo_url`/`repo_path` 를 보냈는데 `working_cards.project_attributed=false` 또는 `evidence.unattributed>0` 이면(전역 의도 `project_id:null` 명시 제외) `⚠️ [기억] 프로젝트 미귀속 저장 — rookie link 상태 확인 필요` 1줄 경고. 조용한 전역 NULL 누수 금지.
158
132
 
159
133
  top-level `all_committed` 가 **`true` 일 때만** `[기억] … 저장` 보고. `false` 면:
160
- - **`rejected[]`** (정책 거부 — 재시도 무의미): `meta_card_summary`(메타 카드)·`residual_marker`(민감정보 마커)·`self_rule_rejected`. 단일 fact 로 분리하거나 원인 제거 후 재저장. 민감정보 마커면 포기.
134
+ - **`rejected[]`**(정책 거부 — 재시도 무의미): `meta_card_summary`·`residual_marker`(민감정보)·`self_rule_rejected` — 단일 fact 분리 또는 원인 제거 후 재저장, 민감정보 마커면 포기.
161
135
  - **`failed[]`** (일시 실패): `insert_failed`·`unexpected_error` 등 — retry 1회, 그래도 실패면 보고.
162
136
  - 미저장이 남으면 `⚠️ [기억] N건 미저장 — <사유>` 한 줄(raw JSON·UUID 금지). `all_committed:true` 전엔 "저장 완료" 라 하지 않는다.
163
137
 
164
138
  > **레거시 폴백**: 직접 curl 불가한 실행환경만 응답 끝 ` ```rookie:mutate ``` ` fence(Stop hook 이 dispatch). 일반 세션에선 fence 금지.
165
139
 
166
140
  ### 트리거 조건
167
- - **working_cards**: 다음 세션 진입 카드 — 세션 종료 시점 권고, 매 단계 금지. **body 에 `repo_url`/`repo_path` 를 넣어라** — 서버가 세션 project 로 자동 귀속. 미link 세션이면 NULL(정상).
168
- - **직전 카드 supersede (필수 습관)**: 같은 작업 흐름(같은 프로젝트 + 제목·대상 파일·브랜치가 이어짐)의 새 "다음:" 카드는 recall dedup 에서 확인한 직전 카드 `id` 를 `supersedes` 에 넣어 닫는다. 애매하면 supersedes 없이 저장. 프로젝트 불일치 parent 는 서버가 자동 skip.
169
- - **cross-project·전역 예외**: 명백히 다른 프로젝트/전역 fact 는 **생략이 아니라 명시적으로 `project_id: null`**(전역) 또는 그 프로젝트 uuid — 생략은 세션 project 자동 귀속이라 오귀속된다. null 이어도 scope=all 회상에 잡힌다.
170
- - **task 연결 (P2.3)**: 확실히 매칭된 task 면 `task_id` 지정 — done 시 카드 자동 은퇴. project_id 는 생략해 task 에서 derive(불일치 시 400). **애매하면** task_id 없이 `__task_link_candidate:<task_id>` 태그만.
141
+ - **working_cards**: 다음 세션 진입 카드 — 세션 종료 시점 권고, 매 단계 금지. **body 에 `repo_url`/`repo_path` 필수** — 서버가 세션 project 로 자동 귀속, 미link 면 NULL(정상).
142
+ - **직전 카드 supersede (필수 습관)**: 같은 작업 흐름(같은 프로젝트·이어지는 제목/파일/브랜치)의 새 "다음:" 카드는 recall dedup 에서 확인한 직전 카드 `id` 를 `supersedes` 에 넣어 닫는다. 애매하면 supersedes 없이 저장. 프로젝트 불일치 parent 는 서버가 자동 skip.
143
+ - **cross-project·전역 예외**: 명백히 다른 프로젝트/전역 fact 는 **생략이 아니라 명시적으로 `project_id: null`**(전역) 또는 그 프로젝트 uuid — 생략은 세션 project 자동 귀속(오귀속). null 도 scope=all 회상에 잡힌다.
144
+ - **task 연결**: 확실히 매칭된 task 면 `task_id` 지정 — done 시 카드 자동 은퇴. project_id 는 생략해 task 에서 derive(불일치 시 400). **애매하면** task_id 없이 `__task_link_candidate:<task_id>` 태그만.
171
145
  - **self_rules**: 사용자 명시 자기 규칙 지시 시만. / **evidence**: 파일·결과물 산출 시. / **verifications**: 루키가 직접 명령으로 fact 검증 시.
172
146
 
173
147
  ### 파일 변경 알림
@@ -186,7 +160,7 @@ top-level `all_committed` 가 **`true` 일 때만** `[기억] … 저장` 보고
186
160
  git diff --name-only ${SESSION_START_SHA:-HEAD~20}..HEAD
187
161
  git status --short # START_DIRTY 제외분만 산물
188
162
  ```
189
- 커밋·파일·PR 또는 DB 검증 fact 가 매칭 근거. **양쪽 다 0 이면 어떤 status 도 바꾸지 않는다(특히 done).** 코드 없이 DB 검증만으로 완성되는 작업은 검증 fact 로 done 후보까지 인정(자동 done 은 여전히 금지). `SESSION_START_SHA` 미캡처 시 폴백 `HEAD~20`(과탐해도 doing 까지만).
163
+ 커밋·파일·PR 또는 DB 검증 fact 가 매칭 근거 — **양쪽 다 0 이면 어떤 status 도 바꾸지 않는다(특히 done)**. DB 검증만으로 완성되는 작업은 검증 fact 로 done 후보 인정(자동 done 금지 동일). `SESSION_START_SHA` 미캡처 시 폴백 `HEAD~20`(과탐해도 doing 까지만).
190
164
  - (나) 산물을 task 의 `spec_ref`/`title`/`detail` 과 의미 매칭 — 변경 파일이 `spec_ref` 영역과 겹치면 강한 매칭.
191
165
  - 작업했는데 todo → `PATCH {id, status:'doing'}` (자동). / 매칭 없음 → `POST /tasks {project_id, title, status:'doing', source:'agent'}`.
192
166
  - doing 중 근거 실재하는 완성건 → **일괄 1회 보고** `"다음 N개를 완료로 올릴까요? — A(근거…), B(근거…)"` → OK 시에만 done PATCH. "느낌상 완료" 제외.
@@ -195,20 +169,17 @@ top-level `all_committed` 가 **`true` 일 때만** `[기억] … 저장` 보고
195
169
 
196
170
  ## 프로젝트 task 추적 (status 는 루키 전용)
197
171
 
198
- `/projects` 의 task status 는 **루키가 실제 업무·증거 기반으로만 갱신**한다(수동 토글 없음). 매 turn 금지 — **착수/완료 시점만**. 자기 출력 분석 금지. (마무리 reconcile 은 위 섹션 — 안전망.)
172
+ `/projects` 의 task status 는 **루키가 실제 업무·증거 기반으로만 갱신**한다(수동 토글 없음). 매 turn 금지 — **착수/완료 시점만**. 자기 출력 분석 금지. (마무리 reconcile 은 위 섹션.)
199
173
 
200
174
  - **진행중 (doing)** — 착수 시 `GET /api/rookie/tasks?project_id=$PID` 후 의미 매칭: 확실 → `PATCH {id, status:'doing'}` + 1줄 알림 / 애매 → "이 작업이 'X' task 맞나요?" 1회 확인 / 매칭 없음 → `POST /tasks {…, status:'doing', source:'agent'}` 신규.
201
175
  - **완료 (done)** — **자동 done 금지.** `"'X' 를 완료로 올리겠습니다 — 근거: <파일/PR/검증 한 줄>. 올릴까요?"` → OK 시 `PATCH {id, status:'done', detail:'<기존>\n\n✅ 완료 YYYY-MM-DD — <근거>'}`.
202
- - **보류 (blocked)** — `PATCH {id, status:'blocked', blocked_reason:'<사유>'}`.
203
- - **재개 (done → doing)** — 추가 작업 발생 시 루키 자율 `PATCH {id, status:'doing', detail:'<기존>\n\n🔄 재개 YYYY-MM-DD — <사유>'}` (확인 불요).
176
+ - **보류 (blocked)** — `PATCH {id, status:'blocked', blocked_reason:'<사유>'}`. / **재개 (done→doing)** — 추가 작업 발생 시 루키 자율 `PATCH {id, status:'doing', detail:'<기존>\n\n🔄 재개 YYYY-MM-DD — <사유>'}` (확인 불요).
204
177
 
205
178
  ### 자동 계층 도출 (승인 게이트)
206
179
 
207
- 평면 task 가 많으면 루키가 상위 목표를 제안해 계층을 잡는다(spec `2026-07-05-auto-hierarchy-derivation-design.md`).
180
+ 평면 task 가 많으면 루키가 상위 목표를 제안해 계층을 잡는다(spec 2026-07-05).
208
181
 
209
182
  - **⭐ 3단 구조 원칙 (두목 2026-07-05, 항상 적용)**: 잎사귀 task 를 목표(1단) 직계에 붙이지 않는다 — 반드시 **목표 → 중간그룹(2단) → 잎(3단)**. 중간그룹이 없으면 먼저 만들거나 제안. done 잎도 예외 없다.
210
- - **트리거**: 두목 명시 요청 또는 미분류 최상위 task 다수(예 ≥8) 시 **1회 제안**.
211
- - **절차**: tasks 조회 → `title`/`detail` 의미로 배정 → 요약 제시(**raw uuid 금지, title 로**) → **승인 게이트**: OK 한 그룹만 기록.
212
- - **기록**: 신규 목표/중간그룹 `POST /api/rookie/tasks {project_id, title, detail?, status:'todo', source:'agent', parent_task_id?}` — 목표는 parent 없이, 중간그룹은 `parent_task_id`=목표. 잎은 `PATCH {id, parent_task_id:<중간그룹>}`. DB trigger 가 최종 검증(owner/project 일치·무사이클·≤32단), 실패 자식만 400 라벨 1줄 보고 후 건너뜀.
213
- - **안전**: 기존 `parent_task_id` 있는 task 재배정 금지(명시 지시 시만). 목표 중복이면 기존에 붙인다. 신규 목표에 자식 0건이면 명시 보고(자동 삭제 금지). 부분 실패 무손실.
214
- - **보고**: "목표 N개 · 자식 M건 연결(실패 K건: 사유)" 1줄.
183
+ - **트리거**: 두목 명시 요청 또는 미분류 최상위 task 다수(예 ≥8) 시 **1회 제안**. **절차**: tasks 조회 → `title`/`detail` 의미로 배정 → 요약 제시(**raw uuid 금지, title 로**) → **승인 게이트**: OK 한 그룹만 기록.
184
+ - **기록**: 신규 목표/중간그룹 `POST /api/rookie/tasks {project_id, title, detail?, status:'todo', source:'agent', parent_task_id?}` — 목표는 parent 없이, 중간그룹은 `parent_task_id`=목표. 잎은 `PATCH {id, parent_task_id:<중간그룹>}`. DB trigger 가 최종 검증(owner/project·무사이클·≤32단), 실패 자식만 400 라벨 1줄 보고 후 skip.
185
+ - **안전**: 기존 `parent_task_id` 있는 task 재배정 금지(명시 지시 시만). 목표 중복이면 기존에 붙인다. 신규 목표에 자식 0건이면 명시 보고(자동 삭제 금지). 부분 실패 무손실. **보고**: "목표 N개 · 자식 M건 연결(실패 K건: 사유)" 1줄.
package/version.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "cli_version": "0.4.3",
3
- "skill_version": "1.24.0"
2
+ "cli_version": "0.4.4",
3
+ "skill_version": "1.25.0"
4
4
  }