claude-nexus 0.24.0 → 0.25.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.
@@ -7,7 +7,7 @@
7
7
  {
8
8
  "name": "claude-nexus",
9
9
  "description": "Agent orchestration plugin for Claude Code. Injects optimized context per agent role with minimal overhead.",
10
- "version": "0.24.0",
10
+ "version": "0.25.0",
11
11
  "author": {
12
12
  "name": "kih"
13
13
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-nexus",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "description": "Agent orchestration plugin for Claude Code — optimized context injection per role",
5
5
  "author": {
6
6
  "name": "kih"
package/README.en.md CHANGED
@@ -88,12 +88,13 @@ Typical flow: `[plan]` to discuss and align → `[d]` to decide (within plan)
88
88
 
89
89
  Claude-callable tools exposed by the Nexus MCP server.
90
90
 
91
- ### Core (12 tools)
91
+ ### Core (11 tools)
92
92
 
93
93
  | Tool | Purpose |
94
94
  |------|---------|
95
95
  | `nx_context` | Current session state lookup (branch, tasks, plan) |
96
96
  | `nx_task_list/add/update/close` | Task management + history.json archiving |
97
+ | `nx_history_search` | Search past plan/task cycles (topic/decision query, last N) |
97
98
  | `nx_artifact_write` | Save artifacts (branch-isolated) |
98
99
  | `nx_plan_start` | Start plan session (topic + issues + research summary) |
99
100
  | `nx_plan_status` | Query plan state |
@@ -127,11 +128,12 @@ Nexus registers a single Gate module as a Claude Code hook.
127
128
 
128
129
  | Event | Role |
129
130
  |-------|------|
130
- | `SessionStart` | Initialize `.nexus/` structure, reset agent-tracker |
131
+ | `SessionStart` | Initialize `.nexus/` structure, reset agent-tracker, write `runtime.json` (teams_enabled), init `tool-log.jsonl` |
131
132
  | `UserPromptSubmit` | Tag detection → mode activation + TASK_PIPELINE injection + additionalContext guidance |
132
133
  | `PreToolUse` | Edit/Write: blocks when incomplete tasks exist |
133
- | `SubagentStart` | Auto-inject role-filtered core knowledge index (lazy-read) |
134
- | `SubagentStop` | Record agent completion. Warn if owned tasks remain incomplete |
134
+ | `PostToolUse` | On Edit/Write/NotebookEdit, append subagent file edits to `tool-log.jsonl` (only when agent_id present) |
135
+ | `SubagentStart` | Auto-inject role-filtered core knowledge index (lazy-read). Upsert `resume_count`/`last_resumed_at` when agent_id recurs |
136
+ | `SubagentStop` | Record agent completion + aggregate `tool-log.jsonl` → inject `files_touched` into agent-tracker entry |
135
137
  | `Stop` | Blocks exit with pending tasks. Forces nx_task_close when all completed |
136
138
  | `PostCompact` | Snapshot session state (mode, plan, agent status) |
137
139
 
@@ -166,8 +168,29 @@ Runtime state is stored under `.nexus/state/` and is excluded from git.
166
168
  .nexus/state/
167
169
  ├── tasks.json ← Task list ([run] cycle)
168
170
  ├── plan.json ← Planning session ([plan] cycle)
169
- ├── agent-tracker.json ← Subagent lifecycle tracking
171
+ ├── agent-tracker.json ← Subagent lifecycle tracking (resume_count, files_touched)
172
+ ├── runtime.json ← teams_enabled flag + session_started_at + plugin_version
173
+ ├── tool-log.jsonl ← Subagent Edit/Write/NotebookEdit call log (append-only)
170
174
  └── artifacts/ ← Artifacts
171
175
  ```
172
176
 
173
177
  </details>
178
+
179
+ <details>
180
+ <summary>Subagent Resume (resume_tier)</summary>
181
+
182
+ Completed subagents can be resumed within the same parent session via `SendMessage`. Each agent's `resume_tier` frontmatter classifies its policy.
183
+
184
+ | Tier | Policy | Agents |
185
+ |------|--------|--------|
186
+ | **persistent** | Default-resume within same issue, Lead opt-in across issues, forced fresh on counter-evidence/review | architect, designer, postdoc, strategist, researcher |
187
+ | **bounded** | Conditional resume only when working on the same artifact (file); forced fresh on loop/feedback cycles | engineer, writer |
188
+ | **ephemeral** | Always fresh spawn (preserves verification independence) | tester, reviewer |
189
+
190
+ **Activation requirement**: environment variable `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`. When absent, automatically falls back to fresh spawn (no errors).
191
+
192
+ **Rationale**: Agents are classified by their dominant work surface. Reasoning surface (exists only in agent context) → `persistent` (HOW + Researcher). Mixed with artifact surface (persisted to filesystem) → `bounded` (Engineer, Writer). Verification independence as quality metric → `ephemeral` (Tester, Reviewer). See `.nexus/memory/persistence-surface-theory.md` for details.
193
+
194
+ **Tracking**: `PostToolUse` hook appends subagent file edits to `tool-log.jsonl` → `SubagentStop` aggregates them into `files_touched` on `agent-tracker.json` → Lead uses this for bounded-tier conditional resume decisions.
195
+
196
+ </details>
package/README.md CHANGED
@@ -75,12 +75,13 @@ claude plugin install claude-nexus@nexus
75
75
 
76
76
  Claude가 직접 호출하는 도구입니다.
77
77
 
78
- ### Core (12개)
78
+ ### Core (11개)
79
79
 
80
80
  | 도구 | 용도 |
81
81
  |------|------|
82
82
  | `nx_context` | 현재 세션 상태 조회 (브랜치, 태스크, 플랜) |
83
83
  | `nx_task_list/add/update/close` | `.nexus/state/tasks.json` 기반 태스크 관리 + `.nexus/history.json` 아카이브 |
84
+ | `nx_history_search` | 과거 plan/task 사이클 검색 (topic/decision 검색, 최근 N개) |
84
85
  | `nx_artifact_write` | 팀 산출물 저장 (`.nexus/state/artifacts/`) |
85
86
  | `nx_plan_start` | 플랜 세션 시작 (토픽 + 논점 + 리서치 요약 등록) |
86
87
  | `nx_plan_status` | 플랜 상태 조회 |
@@ -114,11 +115,12 @@ Gate 단일 모듈로 동작합니다.
114
115
 
115
116
  | 이벤트 | 역할 |
116
117
  |--------|------|
117
- | `SessionStart` | `.nexus/` 구조 초기화, agent-tracker 리셋 |
118
+ | `SessionStart` | `.nexus/` 구조 초기화, agent-tracker 리셋, `runtime.json` 기록 (teams_enabled), `tool-log.jsonl` 초기화 |
118
119
  | `UserPromptSubmit` | 태그 감지 → 모드 활성화 + TASK_PIPELINE 주입 + additionalContext 안내 |
119
120
  | `PreToolUse` | Edit/Write: tasks.json 미완료 시 차단 |
120
- | `SubagentStart` | 에이전트 역할별 코어 지식 인덱스 자동 주입 (lazy-read) |
121
- | `SubagentStop` | 에이전트 완료 기록. 미완료 태스크 경고 |
121
+ | `PostToolUse` | Edit/Write/NotebookEdit 호출 서브에이전트의 파일 수정을 `tool-log.jsonl`에 append (agent_id 있을 때만) |
122
+ | `SubagentStart` | 에이전트 역할별 코어 지식 인덱스 자동 주입 (lazy-read). 기존 agent_id 재발 시 `resume_count`/`last_resumed_at` upsert |
123
+ | `SubagentStop` | 에이전트 완료 기록 + `tool-log.jsonl` 집계 → `files_touched` 주입 |
122
124
  | `Stop` | pending 태스크 있으면 종료 차단. all completed면 nx_task_close 강제 |
123
125
  | `PostCompact` | 세션 상태 스냅샷 (모드, 플랜, 에이전트 현황) |
124
126
 
@@ -153,8 +155,29 @@ Gate 단일 모듈로 동작합니다.
153
155
  .nexus/state/
154
156
  ├── tasks.json ← 태스크 목록 ([run] 사이클)
155
157
  ├── plan.json ← 플랜 세션 ([plan] 사이클)
156
- ├── agent-tracker.json ← 서브에이전트 라이프사이클
158
+ ├── agent-tracker.json ← 서브에이전트 라이프사이클 (resume_count, files_touched 포함)
159
+ ├── runtime.json ← teams_enabled 플래그 + session_started_at + plugin_version
160
+ ├── tool-log.jsonl ← 서브에이전트 Edit/Write/NotebookEdit 호출 로그 (append-only)
157
161
  └── artifacts/ ← 산출물
158
162
  ```
159
163
 
160
164
  </details>
165
+
166
+ <details>
167
+ <summary>에이전트 Resume (resume_tier)</summary>
168
+
169
+ 같은 부모 세션 내에서 종료된 서브에이전트를 `SendMessage`로 재개할 수 있습니다. 에이전트별 `resume_tier` frontmatter로 정책을 분류합니다.
170
+
171
+ | Tier | 정책 | 에이전트 |
172
+ |------|------|---------|
173
+ | **persistent** | 같은 이슈 내 default-resume, 이슈 간 Lead 명시적 opt-in, 반증/재검토는 강제 fresh | architect, designer, postdoc, strategist, researcher |
174
+ | **bounded** | 같은 artifact(파일) 연속 작업 시 conditional-resume, loop/feedback 사이클은 강제 fresh | engineer, writer |
175
+ | **ephemeral** | 항상 fresh spawn (검증 독립성 보장) | tester, reviewer |
176
+
177
+ **활성화 요구사항**: 환경 변수 `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`. 미감지 시 자동 fresh spawn fallback (에러 없음).
178
+
179
+ **이론 근거**: 에이전트의 본질적 작업 층위를 두 surface로 구분합니다. Reasoning surface(에이전트 컨텍스트에만 존재)가 지배적인 HOW/Researcher는 `persistent`, Artifact surface(파일 시스템에 persist)에 걸친 Engineer/Writer는 `bounded`, 검증 독립성이 품질 지표인 Tester/Reviewer는 `ephemeral`. 자세한 내용은 `.nexus/memory/persistence-surface-theory.md`.
180
+
181
+ **연계 추적**: `PostToolUse` 훅이 서브에이전트의 파일 수정을 `tool-log.jsonl`에 append → `SubagentStop`이 집계하여 `agent-tracker.json`의 `files_touched`에 주입 → Lead가 bounded tier 조건부 resume 판단에 활용.
182
+
183
+ </details>
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.24.0
1
+ 0.25.0
@@ -8,6 +8,7 @@ disallowedTools: [Edit, Write, NotebookEdit, mcp__plugin_claude-nexus_nx__nx_tas
8
8
  tags: [architecture, design, review, technical]
9
9
  alias_ko: 아키텍트
10
10
  category: how
11
+ resume_tier: persistent
11
12
  ---
12
13
 
13
14
  <role>
@@ -8,6 +8,7 @@ disallowedTools: [Edit, Write, NotebookEdit, mcp__plugin_claude-nexus_nx__nx_tas
8
8
  tags: [design, ux, ui, interaction, experience]
9
9
  alias_ko: 디자이너
10
10
  category: how
11
+ resume_tier: persistent
11
12
  ---
12
13
 
13
14
  <role>
@@ -8,6 +8,7 @@ disallowedTools: [mcp__plugin_claude-nexus_nx__nx_task_add]
8
8
  tags: [implementation, coding, debugging]
9
9
  alias_ko: 엔지니어
10
10
  category: do
11
+ resume_tier: bounded
11
12
  ---
12
13
 
13
14
  <role>
package/agents/postdoc.md CHANGED
@@ -8,6 +8,7 @@ disallowedTools: [Edit, Write, NotebookEdit, mcp__plugin_claude-nexus_nx__nx_tas
8
8
  tags: [research, synthesis, methodology]
9
9
  alias_ko: 포닥
10
10
  category: how
11
+ resume_tier: persistent
11
12
  ---
12
13
 
13
14
  <role>
@@ -8,6 +8,7 @@ disallowedTools: [Edit, Write, NotebookEdit, mcp__plugin_claude-nexus_nx__nx_tas
8
8
  tags: [research, investigation, web-search, analysis]
9
9
  alias_ko: 리서처
10
10
  category: do
11
+ resume_tier: persistent
11
12
  ---
12
13
 
13
14
  <role>
@@ -8,6 +8,7 @@ disallowedTools: [Edit, Write, NotebookEdit, mcp__plugin_claude-nexus_nx__nx_tas
8
8
  tags: [review, verification, fact-checking, content, quality]
9
9
  alias_ko: 리뷰어
10
10
  category: check
11
+ resume_tier: ephemeral
11
12
  ---
12
13
 
13
14
  <role>
@@ -8,6 +8,7 @@ disallowedTools: [Edit, Write, NotebookEdit, mcp__plugin_claude-nexus_nx__nx_tas
8
8
  tags: [strategy, business, market, competitive, positioning]
9
9
  alias_ko: 전략가
10
10
  category: how
11
+ resume_tier: persistent
11
12
  ---
12
13
 
13
14
  <role>
package/agents/tester.md CHANGED
@@ -8,6 +8,7 @@ disallowedTools: [Edit, Write, NotebookEdit, mcp__plugin_claude-nexus_nx__nx_tas
8
8
  tags: [verification, testing, security, quality]
9
9
  alias_ko: 테스터
10
10
  category: check
11
+ resume_tier: ephemeral
11
12
  ---
12
13
 
13
14
  <role>
package/agents/writer.md CHANGED
@@ -8,6 +8,7 @@ disallowedTools: [mcp__plugin_claude-nexus_nx__nx_task_add]
8
8
  tags: [writing, documentation, communication, presentation]
9
9
  alias_ko: 라이터
10
10
  category: do
11
+ resume_tier: bounded
11
12
  ---
12
13
 
13
14
  <role>
@@ -22040,9 +22040,10 @@ function registerPlanTools(server2) {
22040
22040
  issue_id: external_exports.number().describe("\uACB0\uC815\uD560 \uC548\uAC74 ID"),
22041
22041
  summary: external_exports.string().describe("\uACB0\uC815 \uC694\uC57D"),
22042
22042
  how_agents: external_exports.array(external_exports.string()).optional().describe('\uC774\uC288 \uBD84\uC11D\uC5D0 \uCC38\uC5EC\uD55C HOW \uC5D0\uC774\uC804\uD2B8 \uC774\uB984 \uBAA9\uB85D (\uC608: ["architect", "designer"])'),
22043
- how_summary: external_exports.record(external_exports.string(), external_exports.string()).optional().describe('\uC5D0\uC774\uC804\uD2B8\uBCC4 \uD575\uC2EC \uC758\uACAC \uC694\uC57D (\uC608: { "architect": "...", "designer": "..." })')
22043
+ how_summary: external_exports.record(external_exports.string(), external_exports.string()).optional().describe('\uC5D0\uC774\uC804\uD2B8\uBCC4 \uD575\uC2EC \uC758\uACAC \uC694\uC57D (\uC608: { "architect": "...", "designer": "..." })'),
22044
+ how_agent_ids: external_exports.record(external_exports.string(), external_exports.string()).optional().describe('\uC5D0\uC774\uC804\uD2B8 \uC774\uB984 \u2192 agentId \uB9E4\uD551 (resume\uC6A9). \uC608: { "architect": "ac01819f1cd295cb8" }')
22044
22045
  },
22045
- async ({ issue_id, summary, how_agents, how_summary }) => {
22046
+ async ({ issue_id, summary, how_agents, how_summary, how_agent_ids }) => {
22046
22047
  const data = await readPlan();
22047
22048
  if (!data) {
22048
22049
  return textResult({ error: "No active plan session" });
@@ -22055,6 +22056,7 @@ function registerPlanTools(server2) {
22055
22056
  issue2.decision = summary;
22056
22057
  if (how_agents !== void 0) issue2.how_agents = how_agents;
22057
22058
  if (how_summary !== void 0) issue2.how_summary = how_summary;
22059
+ if (how_agent_ids !== void 0) issue2.how_agent_ids = how_agent_ids;
22058
22060
  await writePlan(data);
22059
22061
  const allComplete = data.issues.every((i) => i.status === "decided");
22060
22062
  if (allComplete) {
@@ -22128,9 +22130,11 @@ function registerTaskTools(server2) {
22128
22130
  plan_issue: external_exports.number().optional().describe("plan issue ID this task originates from \u2014 used for tracing back to the plan session"),
22129
22131
  goal: external_exports.string().optional().describe("Set or update the goal for this task list"),
22130
22132
  decisions: external_exports.array(external_exports.string()).optional().describe("Top-level decisions from [plan] session to append"),
22131
- owner: external_exports.string().optional().describe("Assignee agent name for this task")
22133
+ owner: external_exports.string().optional().describe("Assignee agent name for this task"),
22134
+ owner_agent_id: external_exports.string().optional().describe("\uD2B9\uC815 agentId\uB85C resume\uD560 \uB54C \uC9C0\uC815. \uBBF8\uC124\uC815 \uC2DC fresh spawn."),
22135
+ owner_reuse_policy: external_exports.enum(["fresh", "resume_if_same_artifact", "resume"]).optional().describe("resume \uD310\uB2E8 \uC815\uCC45. fresh=\uAC15\uC81C \uC0C8 \uC2A4\uD3F0, resume_if_same_artifact=\uC774\uC804 owner\uAC00 \uAC19\uC740 artifact(target file) \uB9CC\uC84C\uC744 \uB54C\uB9CC resume, resume=\uBB34\uC870\uAC74 resume \uC2DC\uB3C4. bounded tier\uB294 resume_if_same_artifact \uAD8C\uC7A5.")
22132
22136
  },
22133
- async ({ title, context, deps, approach, acceptance, risk, plan_issue, goal, decisions, owner }) => {
22137
+ async ({ title, context, deps, approach, acceptance, risk, plan_issue, goal, decisions, owner, owner_agent_id, owner_reuse_policy }) => {
22134
22138
  let data = await readTasks();
22135
22139
  if (!data) {
22136
22140
  data = { goal: "", decisions: [], tasks: [] };
@@ -22153,6 +22157,8 @@ function registerTaskTools(server2) {
22153
22157
  deps: deps ?? [],
22154
22158
  plan_issue,
22155
22159
  owner,
22160
+ owner_agent_id,
22161
+ owner_reuse_policy,
22156
22162
  created_at: (/* @__PURE__ */ new Date()).toISOString()
22157
22163
  };
22158
22164
  data.tasks.push(newTask);
@@ -22242,6 +22248,35 @@ function registerTaskTools(server2) {
22242
22248
  });
22243
22249
  }
22244
22250
  );
22251
+ server2.tool(
22252
+ "nx_history_search",
22253
+ "Search past plan/task cycles in history.json",
22254
+ {
22255
+ query: external_exports.string().optional().describe("Search term to match against topic, decisions, research_summary"),
22256
+ last_n: external_exports.number().optional().describe("Return only the last N cycles (default: 10)")
22257
+ },
22258
+ async ({ query, last_n }) => {
22259
+ const historyPath = (0, import_path8.join)(NEXUS_ROOT, "history.json");
22260
+ if (!(0, import_fs8.existsSync)(historyPath)) return textResult({ cycles: [], total: 0 });
22261
+ const raw = await (0, import_promises3.readFile)(historyPath, "utf-8");
22262
+ const history = JSON.parse(raw);
22263
+ let cycles = history.cycles || [];
22264
+ if (query) {
22265
+ const q = query.toLowerCase();
22266
+ cycles = cycles.filter((c) => JSON.stringify(c).toLowerCase().includes(q));
22267
+ }
22268
+ const total = cycles.length;
22269
+ const limit = last_n || 10;
22270
+ const results = cycles.slice(-limit).map((c) => ({
22271
+ completed_at: c.completed_at,
22272
+ branch: c.branch,
22273
+ topic: c.plan?.topic,
22274
+ decisions: c.plan?.issues?.filter((i) => i.status === "decided").map((i) => ({ title: i.title, decision: i.decision })),
22275
+ task_count: c.tasks?.length
22276
+ }));
22277
+ return textResult({ total, showing: results.length, cycles: results });
22278
+ }
22279
+ );
22245
22280
  }
22246
22281
 
22247
22282
  // src/mcp/tools/artifact.ts