therookie 0.4.4 → 0.4.5
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 +2 -2
- package/src/cli.js +1 -1
- package/src/commands/save.js +23 -6
- package/templates/hook/lib/skill-gate.sh +3 -0
- package/templates/hook/user-prompt-skill-gate.sh +17 -0
- package/templates/skill/SKILL.md +27 -28
- package/version.json +2 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "therookie",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"description": "the Rookie
|
|
3
|
+
"version": "0.4.5",
|
|
4
|
+
"description": "the Rookie \u2014 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": [
|
|
7
7
|
"ai",
|
package/src/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ const HELP = `rookie — the Rookie Skill/Hook 설치 관리자
|
|
|
22
22
|
rookie login [--local]
|
|
23
23
|
rookie update [--force]
|
|
24
24
|
rookie link [--local]
|
|
25
|
-
rookie save [--file <body.json>] # 또는 stdin
|
|
25
|
+
rookie save [--file <body.json>] [--json] # 또는 stdin. --json = 서버 raw 응답 출력
|
|
26
26
|
rookie status
|
|
27
27
|
rookie doctor [--deep-scan] [--dead-letters]
|
|
28
28
|
rookie unlink [--local | --global]
|
package/src/commands/save.js
CHANGED
|
@@ -67,12 +67,29 @@ export async function runSave(flags) {
|
|
|
67
67
|
if (repoUrl) body.repo_url = repoUrl
|
|
68
68
|
else delete body.repo_url
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
let res
|
|
71
|
+
try {
|
|
72
|
+
res = await apiPost(cfg.endpoint, cfg.token, '/api/rookie/batch-mutate', body, {
|
|
73
|
+
headers: {
|
|
74
|
+
'x-rookie-hostname': getHostname(),
|
|
75
|
+
'x-rookie-surface': 'local_cli',
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
} catch (err) {
|
|
79
|
+
// --json 은 HTTP 실패도 파싱 가능한 JSON 으로 (spec 2026-07-16-checkpoint §2.2a)
|
|
80
|
+
if (flags.json) {
|
|
81
|
+
console.log(JSON.stringify({ error: String(err?.message ?? err) }))
|
|
82
|
+
process.exit(1)
|
|
83
|
+
}
|
|
84
|
+
throw err
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (flags.json) {
|
|
88
|
+
// 서버 raw 응답 그대로 — 재가공 없음. SKILL 은 summary.working_cards.ids[0]·superseded_count 를 읽는다.
|
|
89
|
+
console.log(JSON.stringify(res))
|
|
90
|
+
if (res.all_committed === false) process.exit(1)
|
|
91
|
+
return
|
|
92
|
+
}
|
|
76
93
|
|
|
77
94
|
if (flags.quiet) return
|
|
78
95
|
const s = res.summary ?? {}
|
|
@@ -24,5 +24,8 @@ skill_gate_record_epoch() {
|
|
|
24
24
|
mkdir -p "$dir" 2>/dev/null
|
|
25
25
|
printf '%s' "${size:-0}" > "$dir/$key.epoch" 2>/dev/null
|
|
26
26
|
rm -f "$dir/$key.loaded" 2>/dev/null
|
|
27
|
+
# checkpoint 리마인더 카운터 리셋 (spec 2026-07-16-checkpoint-working-card §2.4) —
|
|
28
|
+
# /clear·compact 직후 이월된 카운트로 리마인더가 바로 뜨지 않게 한다.
|
|
29
|
+
rm -f "$dir/$key.prompts" 2>/dev/null
|
|
27
30
|
return 0
|
|
28
31
|
}
|
|
@@ -41,6 +41,7 @@ cat | ROOKIE_GATE_DIR="$GATE_DIR" node -e '
|
|
|
41
41
|
process.stdin.on("data",c=>d+=c).on("end",()=>{
|
|
42
42
|
const SKILL_MSG="⚠️ 이 세션에서 아직 rookie Skill 을 로드하지 않았습니다. 다른 작업·응답 전에 먼저 rookie Skill 을 호출하세요 — 회상(recall)·미link 등록 제안·기억 저장 절차가 그 안에 있습니다. (이미 호출했다면 이 안내는 사라집니다.)";
|
|
43
43
|
const RECALL_MSG="🧠 이 프롬프트에 과거 맥락·방법 회상 신호가 있습니다. grep·파일 열람·자기판단·두목 되묻기 이전에 GET /api/rookie/recall 을 먼저 호출하세요 (brand.ts 회상-순서 룰).";
|
|
44
|
+
const CKPT_MSG="📌 이 세션이 길어지고 있습니다. 직전 checkpoint 이후 마일스톤(커밋·배포·설계 수렴·단계 전환)이 지났다면 checkpoint 진입카드를 저장하세요 — 지나지 않았다면 무시해도 됩니다.";
|
|
44
45
|
const injectMsg=(msg)=>{ try{ process.stdout.write(JSON.stringify({hookSpecificOutput:{hookEventName:"UserPromptSubmit",additionalContext:msg}})); }catch{} };
|
|
45
46
|
try{
|
|
46
47
|
const fs=require("fs"), path=require("path"), crypto=require("crypto");
|
|
@@ -80,8 +81,24 @@ cat | ROOKIE_GATE_DIR="$GATE_DIR" node -e '
|
|
|
80
81
|
if(skillLoaded && key){ try{ fs.mkdirSync(gateDir,{recursive:true,mode:0o700}); fs.writeFileSync(path.join(gateDir,key+".loaded"),JSON.stringify({session_id:sid,transcript_path:tp,loaded_at:new Date().toISOString()}),{mode:0o600}); }catch{} }
|
|
81
82
|
}
|
|
82
83
|
}
|
|
84
|
+
// checkpoint 리마인더 카운터 (spec 2026-07-16-checkpoint-working-card §2.4).
|
|
85
|
+
// 매 프롬프트 +1. 임계 도달 + 더 높은 우선순위 메시지 없음 → 주입 + 리셋. 충돌 시 이월(threshold).
|
|
86
|
+
let ckptDue=false;
|
|
87
|
+
const every=parseInt(process.env.ROOKIE_CHECKPOINT_REMINDER_EVERY||"20",10);
|
|
88
|
+
if(key && Number.isFinite(every) && every>0){
|
|
89
|
+
try{
|
|
90
|
+
const pf=path.join(gateDir,key+".prompts");
|
|
91
|
+
let n=0;
|
|
92
|
+
try{ const v=parseInt(String(fs.readFileSync(pf,"utf8")).trim(),10); if(Number.isFinite(v)&&v>0) n=v; }catch{}
|
|
93
|
+
n+=1;
|
|
94
|
+
if(skillLoaded && !recallSignal && n>=every){ ckptDue=true; n=0; }
|
|
95
|
+
fs.mkdirSync(gateDir,{recursive:true,mode:0o700});
|
|
96
|
+
fs.writeFileSync(pf,String(n),{mode:0o600});
|
|
97
|
+
}catch{ ckptDue=false; } // 카운터 실패 → 조용히 skip (fail-soft)
|
|
98
|
+
}
|
|
83
99
|
if(!skillLoaded) return injectMsg(SKILL_MSG); // 미로드 → skill 리마인더 (recall 리마인더 안 함, 한 turn 한 메시지)
|
|
84
100
|
if(recallSignal) return injectMsg(RECALL_MSG); // 로드됨 + 과거-방법 신호 → recall 리마인더
|
|
101
|
+
if(ckptDue) return injectMsg(CKPT_MSG); // 로드됨 + 무신호 + 임계 도달 → checkpoint 리마인더
|
|
85
102
|
return; // 로드됨 + 신호 없음 → 조용
|
|
86
103
|
}catch{ return injectMsg(SKILL_MSG); } // fail-soft
|
|
87
104
|
});
|
package/templates/skill/SKILL.md
CHANGED
|
@@ -11,14 +11,14 @@ installed_by: __INSTALLED_BY__
|
|
|
11
11
|
|
|
12
12
|
## ⚡ 로드 직후 필수 (다른 응답 전에)
|
|
13
13
|
|
|
14
|
-
진입카드·미link 상태는 이 skill 이 로드한다 —
|
|
14
|
+
진입카드·미link 상태는 이 skill 이 로드한다 — **다른 말 전에** 아래 "세션 시작" 절차를 실행한다:
|
|
15
15
|
|
|
16
16
|
1. `GET /api/rookie/context` 를 curl 로 호출해 `system_prompt`·`current_project`·`entry_cards` 전문을 받는다.
|
|
17
17
|
2. **진입 카드 확인:**
|
|
18
18
|
- **1순위**: `entry_cards[]` 를 직접 읽는다. 비어있지 않으면 **그 작업을 이어가려는 사용자 의도를 우선 가정**해 먼저 언급한다. 안전 신호 — `grade` `warn`/`old` → 이미 완료됐을 수 있으니 현재 상태부터 점검 / `is_meta_card` → 메타 카드 의심·단일 fact 분리 권고·`body` 절단본(전량 단정 금지) / `is_vague` → 목표 수준 카드 — recall 로 방법 보강 후 착수 / `has_contradiction` → 단정 전 점검 / `reasoning` → 근거로 고려.
|
|
19
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` 연결
|
|
21
|
-
- **폴백**(구버전 서버): `system_prompt` 의 `## 🔖 진행 중 작업 카드` 마커를 grep
|
|
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
24
|
3. `current_project` 가 `null` 이면 §6 등록 제안. 사용자 입력에 recall 트리거가 있으면 recall 한다.
|
|
@@ -27,43 +27,43 @@ installed_by: __INSTALLED_BY__
|
|
|
27
27
|
|
|
28
28
|
> `rookie <cmd>` 는 글로벌 미설치 시 `node <the-rookie>/packages/rookie-cli/bin/rookie.js <cmd>`.
|
|
29
29
|
|
|
30
|
-
1. `.rookie-ignore`
|
|
30
|
+
1. `.rookie-ignore` / `ROOKIE_DISABLED=1` / config 부재면 스킬 전체 skip.
|
|
31
31
|
2. config 해석(B6 다계정 격리): `ROOKIE_ENDPOINT`/`ROOKIE_TOKEN` > 프로젝트-로컬 `<dir>/.rookie/config.json`(cwd 상향 탐색) > 전역 `~/.rookie/config.json`. 로컬 config 는 그 계정 전용(`rookie login --local`).
|
|
32
32
|
3. 현재 폴더 식별: `REPO_URL` = `git remote get-url origin` (실패 시 빈 값), `REPO_PATH` = cwd.
|
|
33
|
-
**git 기준점
|
|
33
|
+
**git 기준점 캡처**: `SESSION_START_SHA` = `git rev-parse HEAD` / `START_DIRTY` = `git status --short` + `git diff --name-only HEAD`. 이 SHA 이후 *새* 변경만 이번 세션 산물 — 시작부터 dirty 던 파일로 task 자동 전환 금지.
|
|
34
34
|
4. 컨텍스트 조회:
|
|
35
35
|
```
|
|
36
36
|
curl -s -H "Authorization: Bearer $TOKEN" -H "x-rookie-hostname: $(hostname)" \
|
|
37
37
|
-H "x-rookie-surface: claude_code" \
|
|
38
38
|
"$ENDPOINT/api/rookie/context?repo_url=$(url_encode $REPO_URL)&repo_path=$(url_encode $REPO_PATH)"
|
|
39
39
|
```
|
|
40
|
-
5.
|
|
40
|
+
5. `system_prompt` 를 세션 페르소나로 채택(기억 상세는 recall 위임).
|
|
41
41
|
- **이상 신호(B1)**: 주입 페르소나·계정 요약(`[루키] 계정 …`, `metadata.account`)이 평소와 다르면(프로젝트 0·낯선 호칭·빈 계정) 작업 전에 알린다.
|
|
42
|
-
6. **미link 감지·능동 제안**: `current_project` 가 `null` 이면 미link. 서버 `metadata.link_hint:'unlinked_repo'`
|
|
42
|
+
6. **미link 감지·능동 제안**: `current_project` 가 `null` 이면 미link. 서버 `metadata.link_hint:'unlinked_repo'` 를 그대로 신뢰(B2).
|
|
43
43
|
- `~/.rookie/link-dismissed.json`(경로 배열)에 현재 cwd 가 있으면 안내 skip.
|
|
44
|
-
- 없으면 **매 세션 1회** "지금 등록할까요? (
|
|
44
|
+
- 없으면 **매 세션 1회** "지금 등록할까요? ('그만 물어봐' 가능)" 제안 — git remote 있는 repo 면 특히.
|
|
45
45
|
- **승인 시** 루키가 `rookie link` 직접 실행 + 1줄 보고. **거부 시** link-dismissed.json 에 cwd 추가. dismiss 후에도 "등록해줘" 하면 즉시 실행.
|
|
46
46
|
- 자동 등록 금지(승인 전제). recall 0건(신규면 정상)과 미link 는 다른 신호 — **후자만** 알린다.
|
|
47
47
|
|
|
48
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 보존. 진척은
|
|
49
|
+
- **(A) 스펙 연결·동기화**: 로컬 스펙 문서를 찾아 `spec_doc_paths` 설정 + 문서별 task 동기화(문서 1개=task 1개). **task 는 전부 todo 시작(스펙 ≠ 구현)** — sync 에 `status` 금지(서버가 todo 고정), 재동기화해도 기존 status 보존. 진척은 `PATCH /api/rookie/tasks`.
|
|
50
50
|
- 미연결일 때만: `PUT /api/rookie/projects/spec-source {"project_id":"<id>","spec_doc_paths":["docs/specs/**"]}`
|
|
51
51
|
- 공통: `POST /api/rookie/tasks/sync {"project_id":"<id>","items":[{"title":"<스펙 제목>","spec_ref":"<파일경로>","spec_html":"<렌더 HTML>"}]}`
|
|
52
52
|
- 스펙 문서가 없으면 "같이 만들까요?" → brainstorming 으로 작성 후 연결.
|
|
53
53
|
- **(C) 소개글**: 비어 있으면 README·CLAUDE.md 파악 후 1~2문장 초안을 `PATCH /api/rookie/projects {"id","description"}` — 기존 소개글 덮어쓰기 금지. 완료 시 1줄 보고.
|
|
54
54
|
- **거부** 시 `POST /api/rookie/projects/spec-dismiss {"project_id":"<id>","dismissed":true}` (되돌리기는 `false`). 명시 요청은 dismiss 와 무관하게 수행. 미link(§6) → 미스펙(directive) → 정상 3단계 중 해당 단계만 1회 알린다(승인 전제).
|
|
55
55
|
|
|
56
|
-
6.6. **spec 후속 자동 스캔**: link + `spec_doc_paths` 설정 시 세션 시작 1회 `rookie scan-specs`(하루 1회 throttle
|
|
56
|
+
6.6. **spec 후속 자동 스캔**: link + `spec_doc_paths` 설정 시 세션 시작 1회 `rookie scan-specs`(하루 1회 throttle). 결과는 조용히 둔다(proposal 은 `/projects`). 명시 요청 시 `--force`. 미link·미설정·실패 조용히 skip.
|
|
57
57
|
|
|
58
58
|
7. **임베딩 헬스 경고**: `embedding_health.degraded:true` 면 세션당 1회 — ``⚠️ 회상 임베딩 가동률 {ratio×100}% (최근 {window_days}일 {call_count}건) — 키/quota 점검 필요.`` `false` 면 침묵.
|
|
59
|
-
8. **완료 후보 surface**: `## 🎯 완료 후보 감지` 블록의 `🎯 <task_id(전체 UUID)> "<title>" ← <sha> <subject>` 줄이 보이면 **다른 응답 전에** 후보별 done 승인 게이트로 여쭙는다(UUID 는 PATCH
|
|
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 금지).
|
|
60
60
|
9. 실패(HTTP·네트워크)는 조용히 폴백 — 현재 프로젝트 `CLAUDE.md` 만 따릅니다.
|
|
61
61
|
|
|
62
62
|
## 복구 세션 tail 추출
|
|
63
63
|
|
|
64
64
|
비정상 종료 세션은 Stop hook 이 못 돌아 fact·진입카드가 없다 — chunk 복구는 `orphan_recover`, **fact 추출은 차차 책임**(서버 추출 off). 컨텍스트에 ``🛟 …`` 블록과 ``- <sid> :: <transcript_path>`` 목록이 보이면 **다른 응답 전에** 처리한다:
|
|
65
65
|
|
|
66
|
-
1. `rookie orphan-extract --batch=5` — 대기 세션을 오래된 순으로 읽어 rule-base 초안(요약·파일 경로·git sha, redact 통과)을 뽑는다. transcript 원문 통째 Read 금지(
|
|
66
|
+
1. `rookie orphan-extract --batch=5` — 대기 세션을 오래된 순으로 읽어 rule-base 초안(요약·파일 경로·git sha, redact 통과)을 뽑는다. transcript 원문 통째 Read 금지(부족 시 보조 — Claude `~/.claude/projects/`, Codex `~/.codex/sessions/`).
|
|
67
67
|
2. 초안에서 **저장 가치가 있는 것만** — 운영 사실/결정→working_card, 파일·결과물→evidence, 명시적 자기규칙→self_rule, 취향→personal_fact. 잡담·민감정보 금지(redactor 원칙). 0건 세션도 정상.
|
|
68
68
|
3. **recall 로 dedup 후** 누락분만 `POST /api/rookie/batch-mutate`(`project_id` 포함).
|
|
69
69
|
4. 처리한 세션마다(0건이어도) 초안 하단의 완료 marker 명령을 **그대로** 실행해 큐에서 비운다 — 안 하면 매 세션 재노출:
|
|
@@ -75,7 +75,7 @@ installed_by: __INSTALLED_BY__
|
|
|
75
75
|
|
|
76
76
|
## 컨텍스트 다이어트 (주1회, 승인 게이트)
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
SessionStart hook 이 주 1회 임계 초과 시 ``## 🍞 컨텍스트 다이어트 권고`` 블록을 주입한다. 보이면 **다른 응답 전에 1회** 제안, 없으면 침묵. **전 항목 승인 게이트 — 자동 실행 없음.** 승인 시:
|
|
79
79
|
- **CLAUDE.md**: 아카이브성 내용 `docs/` 이관 + 참조 1줄 치환. 의미 단위 압축(단순 truncate 금지). diff 제시 → 승인 후 커밋.
|
|
80
80
|
- **스킬 정리**: 0회 후보 제시 → 고른 것만. settings 비활성화(가역) 우선 / 폴백 `~/.claude/skills/<name>` → `skills.disabled/` 이동(삭제 아님, symlink·플러그인은 안내만). keep 은 `~/.rookie/context-diet-keep.json`.
|
|
81
81
|
- **루키 자기 다이어트**: rookie Skill 문서 중복 정리 — diff 제시 → 승인 후 반영(템플릿 SSOT 커밋 + 재배포).
|
|
@@ -86,9 +86,9 @@ installed_by: __INSTALLED_BY__
|
|
|
86
86
|
|
|
87
87
|
다음 트리거가 **사용자 메시지에** 등장하면 반드시 `/api/rookie/recall` 호출 — 시간 단서(어제·전에·그때·예전에·이전에·지난번·저번에) / 작업 동사(진행해·이어·계속·다음·마저·배포·마무리) / 환경 질의(포트·유저명·경로·서버·호스트·도메인) / 과거 방법·재현(기존·어떻게 했/만들었/제작·재현·다시/새로 만들·파이프라인·방식).
|
|
88
88
|
|
|
89
|
-
> **위는 예시다 (전부 아님).** 과거에 무엇을·어떻게 했는지가 답에
|
|
89
|
+
> **위는 예시다 (전부 아님).** 과거에 무엇을·어떻게 했는지가 답에 필요하면 키워드가 없어도 grep/ls/파일 열람 **이전에** recall 먼저. 애매하면 되묻기 전에 recall.
|
|
90
90
|
|
|
91
|
-
기본은 `scope=all`
|
|
91
|
+
기본은 `scope=all`(식별자 불필요):
|
|
92
92
|
```
|
|
93
93
|
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
94
94
|
"$ENDPOINT/api/rookie/recall?q=$(url_encode '질문 요점')&scope=all&limit=5&kind=all"
|
|
@@ -106,16 +106,16 @@ curl -s -H "Authorization: Bearer $TOKEN" \
|
|
|
106
106
|
|
|
107
107
|
카테고리: 운영 사실(서버/포트/유저명/경로/명시 결정, 자동) → working_cards / 능력 증거(파일·결과물 산출 시, 자동) → evidence / 자기 규칙(사용자 명시 시그널 "원칙·습관·항상·절대" 만) → self_rules / 개인 취향(명시 시그널 "좋아해·선호·취향" 만) → personal_fact 별도 경로 / 잡담·일회성·민감 정보 → 저장 안 함.
|
|
108
108
|
|
|
109
|
-
저장 전 **recall dedup** —
|
|
109
|
+
저장 전 **recall dedup** — 같은 취지 durable fact 존재 시 새 저장 금지. **재확인 근거가 있으면** `verifications` confirmed 1건(fact 당 하루 1회, 서버 동일 게이트 — working card·근거 없는 회상 제외)으로 반복 신호를 남긴다. 성공 시 `[기억] <요약> 저장` 1줄, 실패 시 retry 1회 + 알림.
|
|
110
110
|
|
|
111
|
-
**`rookie:mutate` fence 를 화면에 출력하지 않는다** — 저장은 Bash 직접 호출, 화면엔 `[기억] …` 한 줄만(
|
|
111
|
+
**`rookie:mutate` fence 를 화면에 출력하지 않는다** — 저장은 Bash 직접 호출, 화면엔 `[기억] …` 한 줄만(config 는 `~/.rookie/config.json`, 토큰 출력 금지).
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
114
|
rookie save --file <body.json> # 또는: echo '<body>' | rookie save
|
|
115
115
|
```
|
|
116
|
-
⚠️ **`curl` 로 직접 batch-mutate
|
|
116
|
+
⚠️ **`curl` 로 직접 batch-mutate 금지** — `rookie save` 가 cwd·git remote·hostname 을 자동 주입해 전역 누수를 막는다. 본문엔 **기억할 내용만**.
|
|
117
117
|
|
|
118
|
-
⚠️ **전역 fact 는 `project_id: null` 을 명시한다.** 식별자도 명시 의사도 없으면 서버가 `missing_workspace_context` 로
|
|
118
|
+
⚠️ **전역 fact 는 `project_id: null` 을 명시한다.** 식별자도 명시 의사도 없으면 서버가 `missing_workspace_context` 로 **거부**. 미등록 폴더 저장은 **그 폴더에 격리**, `rookie link` 시 자동 승격.
|
|
119
119
|
|
|
120
120
|
`<body>` 스키마 (필요한 키만):
|
|
121
121
|
```json
|
|
@@ -128,18 +128,19 @@ rookie save --file <body.json> # 또는: echo '<body>' | rookie save
|
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
### 응답 확인 — `all_committed` 게이트 + 귀속 확인
|
|
131
|
-
**귀속 확인**(all_committed 와 무관): `repo_url`/`repo_path` 를 보냈는데 `working_cards.project_attributed=false` 또는 `evidence.unattributed>0` 이면(전역 의도 `project_id:null` 명시 제외) `⚠️ [기억] 프로젝트 미귀속 저장 — rookie link 상태 확인 필요` 1줄 경고.
|
|
131
|
+
**귀속 확인**(all_committed 와 무관): `repo_url`/`repo_path` 를 보냈는데 `working_cards.project_attributed=false` 또는 `evidence.unattributed>0` 이면(전역 의도 `project_id:null` 명시 제외) `⚠️ [기억] 프로젝트 미귀속 저장 — rookie link 상태 확인 필요` 1줄 경고.
|
|
132
132
|
|
|
133
133
|
top-level `all_committed` 가 **`true` 일 때만** `[기억] … 저장` 보고. `false` 면:
|
|
134
134
|
- **`rejected[]`**(정책 거부 — 재시도 무의미): `meta_card_summary`·`residual_marker`(민감정보)·`self_rule_rejected` — 단일 fact 분리 또는 원인 제거 후 재저장, 민감정보 마커면 포기.
|
|
135
135
|
- **`failed[]`** (일시 실패): `insert_failed`·`unexpected_error` 등 — retry 1회, 그래도 실패면 보고.
|
|
136
136
|
- 미저장이 남으면 `⚠️ [기억] N건 미저장 — <사유>` 한 줄(raw JSON·UUID 금지). `all_committed:true` 전엔 "저장 완료" 라 하지 않는다.
|
|
137
137
|
|
|
138
|
-
> **레거시 폴백**: 직접 curl
|
|
138
|
+
> **레거시 폴백**: 직접 curl 불가 환경만 응답 끝 ` ```rookie:mutate ``` ` fence(Stop hook dispatch). 일반 세션 fence 금지.
|
|
139
139
|
|
|
140
140
|
### 트리거 조건
|
|
141
|
-
- **working_cards**: 다음 세션 진입 카드 — 세션
|
|
142
|
-
-
|
|
141
|
+
- **working_cards**: 다음 세션 진입 카드 — 세션 마무리 + 아래 checkpoint, 매 턴·매 단계 금지. **body 에 `repo_url`/`repo_path` 필수** — 서버가 세션 project 로 자동 귀속, 미link 면 NULL(정상).
|
|
142
|
+
- **checkpoint(세션 중간 저장)**: 마일스톤(커밋/push·배포·설계 수렴·큰 단계 전환) 완결 시 `rookie save --json` 으로 카드 1건 — `tags:["checkpoint"]`, 직전 checkpoint 를 `supersedes` 로 닫기(응답 `summary.working_cards.ids[0]` 기억, `superseded_count` 확인). 마무리 저장도 마지막 checkpoint supersede. id 분실 시 recall dedup, 애매하면 supersedes 생략.
|
|
143
|
+
- **직전 카드 supersede (필수 습관)**: 같은 작업 흐름(프로젝트·이어지는 제목/파일/브랜치)의 새 "다음:" 카드는 recall dedup 으로 확인한 직전 카드 `id` 를 `supersedes` 에 넣어 닫는다. 애매하면 생략. 프로젝트 불일치 parent 는 서버가 자동 skip.
|
|
143
144
|
- **cross-project·전역 예외**: 명백히 다른 프로젝트/전역 fact 는 **생략이 아니라 명시적으로 `project_id: null`**(전역) 또는 그 프로젝트 uuid — 생략은 세션 project 자동 귀속(오귀속). null 도 scope=all 회상에 잡힌다.
|
|
144
145
|
- **task 연결**: 확실히 매칭된 task 면 `task_id` 지정 — done 시 카드 자동 은퇴. project_id 는 생략해 task 에서 derive(불일치 시 400). **애매하면** task_id 없이 `__task_link_candidate:<task_id>` 태그만.
|
|
145
146
|
- **self_rules**: 사용자 명시 자기 규칙 지시 시만. / **evidence**: 파일·결과물 산출 시. / **verifications**: 루키가 직접 명령으로 fact 검증 시.
|
|
@@ -151,7 +152,7 @@ top-level `all_committed` 가 **`true` 일 때만** `[기억] … 저장` 보고
|
|
|
151
152
|
|
|
152
153
|
서버는 LLM 추출을 하지 않는다 — 세션 핵심 기억은 루키가 직접 저장한다. **마무리 징후 감지 시** (끝내자/수고/오늘 여기까지, 작업 완결, 의미 있는 단락):
|
|
153
154
|
|
|
154
|
-
1. **다음 진입점 1건** — 미완결 작업·다음 액션·대기 결정을 추론해 working_cards 1건. 본문은 "다음: <바로 실행할 첫 행동>"
|
|
155
|
+
1. **다음 진입점 1건** — 미완결 작업·다음 액션·대기 결정을 추론해 working_cards 1건. 본문은 "다음: <바로 실행할 첫 행동>" 시작(목표형 "~이어가기" 금지, 방법 미정이면 "다음: 방법 후보 A/B 중 두목과 결정"). `[고정]`·`[실패]`·`[두목 제약]` 마커 권장 + 파일·명령·근거 1줄(속기·내부기호 금지, 평이한 한국어). 명확히 완결됐으면 생략(0건 정상).
|
|
155
156
|
2. **미저장 운영 사실·능력 증거·자기 규칙** — recall dedup 후 누락분만.
|
|
156
157
|
3. **프로젝트 task status reconcile** (link 세션만) — `GET /api/rookie/tasks?project_id=<id>` 1회 후, **이번 세션 실제 산물과 사용자 지시**를 task 와 매칭(루키 자기 서술 근거 금지):
|
|
157
158
|
- **(가) git 산물 수집 먼저** (git 이 진실):
|
|
@@ -169,15 +170,13 @@ top-level `all_committed` 가 **`true` 일 때만** `[기억] … 저장` 보고
|
|
|
169
170
|
|
|
170
171
|
## 프로젝트 task 추적 (status 는 루키 전용)
|
|
171
172
|
|
|
172
|
-
`/projects` 의 task status 는 **루키가 실제 업무·증거 기반으로만 갱신**한다(수동 토글 없음). 매 turn 금지 — **착수/완료 시점만**. 자기 출력 분석
|
|
173
|
+
`/projects` 의 task status 는 **루키가 실제 업무·증거 기반으로만 갱신**한다(수동 토글 없음). 매 turn 금지 — **착수/완료 시점만**. 자기 출력 분석 금지(마무리 reconcile 은 위 §).
|
|
173
174
|
|
|
174
175
|
- **진행중 (doing)** — 착수 시 `GET /api/rookie/tasks?project_id=$PID` 후 의미 매칭: 확실 → `PATCH {id, status:'doing'}` + 1줄 알림 / 애매 → "이 작업이 'X' task 맞나요?" 1회 확인 / 매칭 없음 → `POST /tasks {…, status:'doing', source:'agent'}` 신규.
|
|
175
176
|
- **완료 (done)** — **자동 done 금지.** `"'X' 를 완료로 올리겠습니다 — 근거: <파일/PR/검증 한 줄>. 올릴까요?"` → OK 시 `PATCH {id, status:'done', detail:'<기존>\n\n✅ 완료 YYYY-MM-DD — <근거>'}`.
|
|
176
177
|
- **보류 (blocked)** — `PATCH {id, status:'blocked', blocked_reason:'<사유>'}`. / **재개 (done→doing)** — 추가 작업 발생 시 루키 자율 `PATCH {id, status:'doing', detail:'<기존>\n\n🔄 재개 YYYY-MM-DD — <사유>'}` (확인 불요).
|
|
177
178
|
|
|
178
|
-
### 자동 계층 도출 (승인 게이트)
|
|
179
|
-
|
|
180
|
-
평면 task 가 많으면 루키가 상위 목표를 제안해 계층을 잡는다(spec 2026-07-05).
|
|
179
|
+
### 자동 계층 도출 (승인 게이트) — 평면 task 다수 시 상위 목표 제안(spec 2026-07-05)
|
|
181
180
|
|
|
182
181
|
- **⭐ 3단 구조 원칙 (두목 2026-07-05, 항상 적용)**: 잎사귀 task 를 목표(1단) 직계에 붙이지 않는다 — 반드시 **목표 → 중간그룹(2단) → 잎(3단)**. 중간그룹이 없으면 먼저 만들거나 제안. done 잎도 예외 없다.
|
|
183
182
|
- **트리거**: 두목 명시 요청 또는 미분류 최상위 task 다수(예 ≥8) 시 **1회 제안**. **절차**: tasks 조회 → `title`/`detail` 의미로 배정 → 요약 제시(**raw uuid 금지, title 로**) → **승인 게이트**: OK 한 그룹만 기록.
|
package/version.json
CHANGED