@moreih29/nexus-core 0.2.0 → 0.4.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/agents/researcher/body.md +1 -1
- package/conformance/README.md +203 -15
- package/conformance/lifecycle/README.md +17 -0
- package/conformance/lifecycle/agent-complete.json +43 -0
- package/conformance/lifecycle/agent-resume.json +42 -0
- package/conformance/lifecycle/agent-spawn.json +39 -0
- package/conformance/lifecycle/session-end.json +31 -0
- package/conformance/lifecycle/session-start.json +36 -0
- package/conformance/scenarios/full-plan-cycle.json +15 -0
- package/conformance/scenarios/task-deps-ordering.json +12 -0
- package/conformance/schema/fixture.schema.json +139 -9
- package/conformance/tools/artifact-write.json +97 -0
- package/conformance/tools/context.json +172 -0
- package/conformance/tools/history-search.json +219 -0
- package/conformance/tools/plan-decide.json +69 -0
- package/conformance/tools/plan-start.json +14 -0
- package/conformance/tools/plan-status.json +127 -0
- package/conformance/tools/plan-update.json +341 -0
- package/conformance/tools/task-add.json +89 -6
- package/conformance/tools/task-close.json +65 -4
- package/conformance/tools/task-list.json +177 -0
- package/conformance/tools/task-update.json +167 -0
- package/docs/consumer-implementation-guide.md +3 -3
- package/docs/nexus-outputs-contract.md +277 -0
- package/manifest.json +79 -84
- package/package.json +2 -1
- package/skills/nx-init/body.md +8 -8
- package/skills/nx-init/meta.yml +2 -0
- package/skills/nx-plan/body.md +3 -3
- package/skills/nx-sync/body.md +5 -5
- package/skills/nx-setup/body.md +0 -196
- package/skills/nx-setup/meta.yml +0 -5
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"test_id": "task_list_no_tasks_file",
|
|
4
|
+
"description": "task_list returns exists:false when tasks.json does not exist",
|
|
5
|
+
"covers": {
|
|
6
|
+
"return_value": {
|
|
7
|
+
"task_list": ["exists"]
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"precondition": {
|
|
11
|
+
"state_files": {
|
|
12
|
+
".nexus/state/tasks.json": null
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"action": {
|
|
16
|
+
"tool": "task_list",
|
|
17
|
+
"params": {}
|
|
18
|
+
},
|
|
19
|
+
"postcondition": {
|
|
20
|
+
"return_value": {
|
|
21
|
+
"$.exists": false
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"test_id": "task_list_happy_path",
|
|
27
|
+
"description": "task_list returns goal, full task list, and a correct progress summary when tasks.json exists",
|
|
28
|
+
"covers": {
|
|
29
|
+
"return_value": {
|
|
30
|
+
"task_list": ["goal", "tasks", "summary.total", "summary.completed", "summary.pending", "summary.ready"]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"precondition": {
|
|
34
|
+
"state_files": {
|
|
35
|
+
".nexus/state/tasks.json": {
|
|
36
|
+
"goal": "Ship conformance fixtures for nexus-core",
|
|
37
|
+
"decisions": ["Use declarative JSONPath assertions"],
|
|
38
|
+
"tasks": [
|
|
39
|
+
{
|
|
40
|
+
"id": 1,
|
|
41
|
+
"title": "Create fixture.schema.json",
|
|
42
|
+
"context": "Define the JSON Schema for fixture files",
|
|
43
|
+
"status": "completed",
|
|
44
|
+
"deps": [],
|
|
45
|
+
"created_at": "2026-04-12T00:00:00.000Z"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": 2,
|
|
49
|
+
"title": "Write plan_start fixture",
|
|
50
|
+
"context": "Happy path and missing-research-summary error case",
|
|
51
|
+
"status": "pending",
|
|
52
|
+
"deps": [1],
|
|
53
|
+
"created_at": "2026-04-12T00:00:00.000Z"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": 3,
|
|
57
|
+
"title": "Write task_add fixture",
|
|
58
|
+
"context": "Happy path and with-goal case",
|
|
59
|
+
"status": "pending",
|
|
60
|
+
"deps": [1],
|
|
61
|
+
"created_at": "2026-04-12T00:00:00.000Z"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"action": {
|
|
68
|
+
"tool": "task_list",
|
|
69
|
+
"params": {}
|
|
70
|
+
},
|
|
71
|
+
"postcondition": {
|
|
72
|
+
"return_value": {
|
|
73
|
+
"$.goal": "Ship conformance fixtures for nexus-core",
|
|
74
|
+
"$.tasks.length": 3,
|
|
75
|
+
"$.summary.total": 3,
|
|
76
|
+
"$.summary.completed": 1,
|
|
77
|
+
"$.summary.pending": 2,
|
|
78
|
+
"$.summary.ready.length": 2,
|
|
79
|
+
"$.summary.ready[0]": 2,
|
|
80
|
+
"$.summary.ready[1]": 3
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"test_id": "task_list_all_pending_no_deps",
|
|
86
|
+
"description": "task_list marks all tasks as ready when they have no dependencies and are all pending",
|
|
87
|
+
"covers": {
|
|
88
|
+
"return_value": {
|
|
89
|
+
"task_list": ["summary.total", "summary.pending", "summary.completed", "summary.ready"]
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"precondition": {
|
|
93
|
+
"state_files": {
|
|
94
|
+
".nexus/state/tasks.json": {
|
|
95
|
+
"goal": "Validate ready computation",
|
|
96
|
+
"decisions": [],
|
|
97
|
+
"tasks": [
|
|
98
|
+
{
|
|
99
|
+
"id": 1,
|
|
100
|
+
"title": "Independent task A",
|
|
101
|
+
"context": "No dependencies",
|
|
102
|
+
"status": "pending",
|
|
103
|
+
"deps": [],
|
|
104
|
+
"created_at": "2026-04-12T00:00:00.000Z"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"id": 2,
|
|
108
|
+
"title": "Independent task B",
|
|
109
|
+
"context": "No dependencies",
|
|
110
|
+
"status": "pending",
|
|
111
|
+
"deps": [],
|
|
112
|
+
"created_at": "2026-04-12T00:00:00.000Z"
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"action": {
|
|
119
|
+
"tool": "task_list",
|
|
120
|
+
"params": {}
|
|
121
|
+
},
|
|
122
|
+
"postcondition": {
|
|
123
|
+
"return_value": {
|
|
124
|
+
"$.summary.total": 2,
|
|
125
|
+
"$.summary.pending": 2,
|
|
126
|
+
"$.summary.completed": 0,
|
|
127
|
+
"$.summary.ready.length": 2
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"test_id": "task_list_blocked_task_not_ready",
|
|
133
|
+
"description": "task_list excludes a task from ready when its dependency is still pending",
|
|
134
|
+
"covers": {
|
|
135
|
+
"return_value": {
|
|
136
|
+
"task_list": ["summary.total", "summary.ready"]
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"precondition": {
|
|
140
|
+
"state_files": {
|
|
141
|
+
".nexus/state/tasks.json": {
|
|
142
|
+
"goal": "Validate blocked task exclusion",
|
|
143
|
+
"decisions": [],
|
|
144
|
+
"tasks": [
|
|
145
|
+
{
|
|
146
|
+
"id": 1,
|
|
147
|
+
"title": "Prerequisite task",
|
|
148
|
+
"context": "Must finish first",
|
|
149
|
+
"status": "pending",
|
|
150
|
+
"deps": [],
|
|
151
|
+
"created_at": "2026-04-12T00:00:00.000Z"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"id": 2,
|
|
155
|
+
"title": "Dependent task",
|
|
156
|
+
"context": "Cannot start until task 1 is done",
|
|
157
|
+
"status": "pending",
|
|
158
|
+
"deps": [1],
|
|
159
|
+
"created_at": "2026-04-12T00:00:00.000Z"
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"action": {
|
|
166
|
+
"tool": "task_list",
|
|
167
|
+
"params": {}
|
|
168
|
+
},
|
|
169
|
+
"postcondition": {
|
|
170
|
+
"return_value": {
|
|
171
|
+
"$.summary.total": 2,
|
|
172
|
+
"$.summary.ready.length": 1,
|
|
173
|
+
"$.summary.ready[0]": 1
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
]
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"test_id": "task_update_status_to_in_progress",
|
|
4
|
+
"description": "task_update transitions a pending task to in_progress and returns the updated task object",
|
|
5
|
+
"covers": {
|
|
6
|
+
"state_schemas": {
|
|
7
|
+
"tasks.schema.json": ["tasks[].id", "tasks[].status"]
|
|
8
|
+
},
|
|
9
|
+
"return_value": {
|
|
10
|
+
"task_update": ["task"]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"precondition": {
|
|
14
|
+
"state_files": {
|
|
15
|
+
".nexus/state/tasks.json": {
|
|
16
|
+
"goal": "Validate task_update behaviour",
|
|
17
|
+
"decisions": [],
|
|
18
|
+
"tasks": [
|
|
19
|
+
{
|
|
20
|
+
"id": 1,
|
|
21
|
+
"title": "Implement core feature",
|
|
22
|
+
"context": "Write the initial implementation",
|
|
23
|
+
"status": "pending",
|
|
24
|
+
"deps": [],
|
|
25
|
+
"created_at": "2026-04-12T00:00:00.000Z"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"action": {
|
|
32
|
+
"tool": "task_update",
|
|
33
|
+
"params": {
|
|
34
|
+
"id": 1,
|
|
35
|
+
"status": "in_progress"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"postcondition": {
|
|
39
|
+
"return_value": {
|
|
40
|
+
"$.task.id": 1,
|
|
41
|
+
"$.task.status": "in_progress",
|
|
42
|
+
"$.task.title": "Implement core feature"
|
|
43
|
+
},
|
|
44
|
+
"state_files": {
|
|
45
|
+
".nexus/state/tasks.json": {
|
|
46
|
+
"$.tasks[0].id": 1,
|
|
47
|
+
"$.tasks[0].status": "in_progress"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"test_id": "task_update_status_to_completed",
|
|
54
|
+
"description": "task_update transitions an in_progress task to completed and persists the change in tasks.json",
|
|
55
|
+
"covers": {
|
|
56
|
+
"state_schemas": {
|
|
57
|
+
"tasks.schema.json": ["tasks[].id", "tasks[].status"]
|
|
58
|
+
},
|
|
59
|
+
"return_value": {
|
|
60
|
+
"task_update": ["task"]
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"precondition": {
|
|
64
|
+
"state_files": {
|
|
65
|
+
".nexus/state/tasks.json": {
|
|
66
|
+
"goal": "Validate task_update behaviour",
|
|
67
|
+
"decisions": [],
|
|
68
|
+
"tasks": [
|
|
69
|
+
{
|
|
70
|
+
"id": 1,
|
|
71
|
+
"title": "Implement core feature",
|
|
72
|
+
"context": "Write the initial implementation",
|
|
73
|
+
"status": "in_progress",
|
|
74
|
+
"deps": [],
|
|
75
|
+
"created_at": "2026-04-12T00:00:00.000Z"
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"action": {
|
|
82
|
+
"tool": "task_update",
|
|
83
|
+
"params": {
|
|
84
|
+
"id": 1,
|
|
85
|
+
"status": "completed"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"postcondition": {
|
|
89
|
+
"return_value": {
|
|
90
|
+
"$.task.id": 1,
|
|
91
|
+
"$.task.status": "completed",
|
|
92
|
+
"$.task.title": "Implement core feature"
|
|
93
|
+
},
|
|
94
|
+
"state_files": {
|
|
95
|
+
".nexus/state/tasks.json": {
|
|
96
|
+
"$.tasks[0].id": 1,
|
|
97
|
+
"$.tasks[0].status": "completed"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"test_id": "task_update_not_found_error",
|
|
104
|
+
"description": "task_update returns an error when the referenced task id does not exist in tasks.json",
|
|
105
|
+
"covers": {
|
|
106
|
+
"state_schemas": {
|
|
107
|
+
"tasks.schema.json": []
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"uncovered_params": ["id", "status"],
|
|
111
|
+
"precondition": {
|
|
112
|
+
"state_files": {
|
|
113
|
+
".nexus/state/tasks.json": {
|
|
114
|
+
"goal": "Validate task_update behaviour",
|
|
115
|
+
"decisions": [],
|
|
116
|
+
"tasks": [
|
|
117
|
+
{
|
|
118
|
+
"id": 1,
|
|
119
|
+
"title": "Only task",
|
|
120
|
+
"context": "The only task in the list",
|
|
121
|
+
"status": "pending",
|
|
122
|
+
"deps": [],
|
|
123
|
+
"created_at": "2026-04-12T00:00:00.000Z"
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"action": {
|
|
130
|
+
"tool": "task_update",
|
|
131
|
+
"params": {
|
|
132
|
+
"id": 99,
|
|
133
|
+
"status": "completed"
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"postcondition": {
|
|
137
|
+
"error": true,
|
|
138
|
+
"error_contains": "Task id 99 not found"
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"test_id": "task_update_no_tasks_file_error",
|
|
143
|
+
"description": "task_update returns an error when tasks.json does not exist",
|
|
144
|
+
"covers": {
|
|
145
|
+
"state_schemas": {
|
|
146
|
+
"tasks.schema.json": []
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
"uncovered_params": ["id", "status"],
|
|
150
|
+
"precondition": {
|
|
151
|
+
"state_files": {
|
|
152
|
+
".nexus/state/tasks.json": null
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"action": {
|
|
156
|
+
"tool": "task_update",
|
|
157
|
+
"params": {
|
|
158
|
+
"id": 1,
|
|
159
|
+
"status": "completed"
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"postcondition": {
|
|
163
|
+
"error": true,
|
|
164
|
+
"error_contains": "tasks.json not found"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
]
|
|
@@ -719,9 +719,9 @@ If your harness exposes an inter-agent communication tool, it must be available
|
|
|
719
719
|
|
|
720
720
|
---
|
|
721
721
|
|
|
722
|
-
## 11. Conformance Verification
|
|
722
|
+
## 11. Conformance Verification (Required)
|
|
723
723
|
|
|
724
|
-
|
|
724
|
+
Consumers MUST pass all conformance fixtures to claim nexus-core compatibility. This is not optional — it is the mechanism by which cross-harness interoperability is guaranteed. Non-conforming implementations may produce state files that other Nexus ecosystem components cannot read, or exhibit behavioral divergence that breaks plan/task lifecycle assumptions.
|
|
725
725
|
|
|
726
726
|
### Fixture types
|
|
727
727
|
|
|
@@ -761,7 +761,7 @@ For runner implementation patterns and a TypeScript sketch, see [conformance/REA
|
|
|
761
761
|
|
|
762
762
|
### CI integration
|
|
763
763
|
|
|
764
|
-
Add the conformance test runner to your CI pipeline. Conformance failures
|
|
764
|
+
Add the conformance test runner to your CI pipeline. Conformance failures MUST block release. Do not merge harness changes that break conformance — a conformance failure means your implementation diverges from the Nexus ecosystem contract.
|
|
765
765
|
|
|
766
766
|
Conformance verification is distinct from your harness's own unit tests. Run both.
|
|
767
767
|
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Nexus 산출물 제어 계약
|
|
2
|
+
|
|
3
|
+
이 문서는 nexus-core를 소비하는 하네스(claude-nexus, opencode-nexus, nexus-code)가 준수해야 할 **산출물 제어 normative 계약**이다. 산출물이란 Nexus 세션 또는 프로젝트 사이클에서 생성·수정·삭제되는 모든 파일을 의미하며, 그 책임 주체·생성 조건·삭제 조건·상호운용 의무를 선언적으로 기술한다.
|
|
4
|
+
|
|
5
|
+
이 문서는 `docs/nexus-state-overview.md`와 역할을 명확히 분담한다.
|
|
6
|
+
|
|
7
|
+
- `docs/nexus-state-overview.md` — **기술적 사실**: 각 state 파일의 schema, field 정의, lifecycle facts, tool 접근 매핑.
|
|
8
|
+
- `docs/nexus-outputs-contract.md` (본 문서) — **의무 선언**: 하네스가 MUST / MUST NOT / SHOULD로 지켜야 할 normative 조항. 기술 사실이 아니라 준수 의무를 다룬다.
|
|
9
|
+
|
|
10
|
+
두 문서는 서로를 전제하며 상호 대체하지 않는다. 기술 상세는 state-overview를 참조하고, 준수 여부 판단은 본 문서를 기준으로 한다.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 산출물 3 카테고리
|
|
15
|
+
|
|
16
|
+
Nexus 산출물은 생성 책임 주체에 따라 세 카테고리로 분류된다.
|
|
17
|
+
|
|
18
|
+
| 카테고리 | 책임 주체 | 예시 파일 |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Tool-produced | MCP tool 계약 (nexus-tools-contract.md 정의) | `plan.json`, `tasks.json`, `history.json` |
|
|
21
|
+
| Harness-produced | Session hook (하네스 구현 책임) | `runtime.json`, `agent-tracker.json` |
|
|
22
|
+
| Agent-produced (ephemeral) | `artifact_write` 도구 (에이전트가 호출) | `artifacts/*.md` (등 임의 파일명) |
|
|
23
|
+
|
|
24
|
+
카테고리 간 경계는 "누가 파일을 만드는가"로 정의된다. MCP tool이 직접 write하면 Tool-produced, 하네스 hook이 세션 초기화·종료 시 관리하면 Harness-produced, 에이전트가 `artifact_write`를 통해 기록하면 Agent-produced다.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Tool-produced 산출물
|
|
29
|
+
|
|
30
|
+
### `plan.json` — 활성 계획 세션
|
|
31
|
+
|
|
32
|
+
**책임 주체**: MCP tool (`plan_start`, `plan_status`, `plan_update`, `plan_decide`, `task_close`). `plan_status`는 read-only이며 `docs/nexus-tools-contract.md`의 tool 열거 순서와 일치한다.
|
|
33
|
+
|
|
34
|
+
**생성 trigger**: `plan_start` 호출 시 MUST 생성한다. 이전 세션이 존재할 경우 반드시 `history.json`에 아카이브한 뒤 덮어쓴다.
|
|
35
|
+
|
|
36
|
+
**삭제 trigger**: `task_close` 호출 시 MUST `history.json`에 아카이브 후 삭제한다. `plan_start` 재호출 시에도 동일한 순서(아카이브 → 삭제 → 신규 생성)로 처리해야 한다.
|
|
37
|
+
|
|
38
|
+
**Schema reference**: `conformance/state-schemas/plan.schema.json`
|
|
39
|
+
|
|
40
|
+
**Interop requirement**:
|
|
41
|
+
- 하네스는 `plan.json`을 생성할 때 MUST `conformance/state-schemas/plan.schema.json`에 유효한 JSON을 기록해야 한다.
|
|
42
|
+
- 다른 하네스가 이 파일을 읽어 parse·편집할 수 있어야 한다. MUST NOT 하네스 고유 확장 필드를 schema 외부에 추가해서는 안 된다.
|
|
43
|
+
- `created_at` 필드는 MUST ISO 8601 형식을 사용해야 한다.
|
|
44
|
+
|
|
45
|
+
**Conformance fixture reference**: `conformance/tools/plan-start.json`, `conformance/tools/plan-decide.json`
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### `tasks.json` — 활성 태스크 목록
|
|
50
|
+
|
|
51
|
+
**책임 주체**: MCP tool (`task_add`, `task_update`, `task_close`).
|
|
52
|
+
|
|
53
|
+
**생성 trigger**: `task_add` 최초 호출 시 MUST `{ goal: "", decisions: [], tasks: [] }` 구조로 초기화한 뒤 첫 태스크를 추가한다.
|
|
54
|
+
|
|
55
|
+
**삭제 trigger**: `task_close` 호출 시 MUST `history.json`에 아카이브 후 삭제한다.
|
|
56
|
+
|
|
57
|
+
**Schema reference**: `conformance/state-schemas/tasks.schema.json`
|
|
58
|
+
|
|
59
|
+
**Interop requirement**:
|
|
60
|
+
- 하네스는 `tasks.json`을 기록할 때 MUST `conformance/state-schemas/tasks.schema.json`에 유효한 JSON을 기록해야 한다.
|
|
61
|
+
- `created_at` 필드는 MUST ISO 8601 형식을 사용해야 한다.
|
|
62
|
+
- `status` 값은 MUST `"pending"`, `"in_progress"`, `"completed"` 중 하나여야 한다. 하네스 고유 status 값은 MUST NOT 사용해서는 안 된다.
|
|
63
|
+
- `owner_reuse_policy` 값은 MUST `"fresh"`, `"resume_if_same_artifact"`, `"resume"` 중 하나 또는 absent여야 한다.
|
|
64
|
+
|
|
65
|
+
**Conformance fixture reference**: `conformance/tools/task-add.json`, `conformance/tools/task-update.json`, `conformance/tools/task-list.json`, `conformance/tools/task-close.json`
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### `history.json` — 완료된 사이클 ledger
|
|
70
|
+
|
|
71
|
+
**책임 주체**: MCP tool (`plan_start`, `task_close`).
|
|
72
|
+
|
|
73
|
+
**생성 trigger**: `plan_start` 또는 `task_close`가 최초 아카이브를 수행할 때 파일이 없으면 MUST 생성한다. 이후 호출은 기존 파일의 `cycles` 배열에 append한다.
|
|
74
|
+
|
|
75
|
+
**삭제 trigger**: MUST NOT 삭제해서는 안 된다. `history.json`은 프로젝트 영구 기록이며 어떤 도구도 이 파일을 삭제해서는 안 된다.
|
|
76
|
+
|
|
77
|
+
**Schema reference**: `conformance/state-schemas/history.schema.json`
|
|
78
|
+
|
|
79
|
+
**Interop requirement**:
|
|
80
|
+
- 하네스는 cycle 레코드를 append할 때 MUST `conformance/state-schemas/history.schema.json`에 유효한 구조를 기록해야 한다.
|
|
81
|
+
- `completed_at` 및 각 태스크의 `created_at` 필드는 MUST ISO 8601 형식을 사용해야 한다.
|
|
82
|
+
- 새 cycle 레코드는 MUST append-only 방식으로 추가해야 한다. 기존 cycle 레코드의 수정은 MUST NOT 허용되어서는 안 된다.
|
|
83
|
+
- `history.json`은 git-tracked 파일이다. 하네스는 SHOULD 세션 종료 후 이 파일을 commit 대상에 포함할 것을 권장한다.
|
|
84
|
+
|
|
85
|
+
**Conformance fixture reference**: `conformance/tools/task-close.json` (archive 동작 포함)
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Harness-produced 산출물
|
|
90
|
+
|
|
91
|
+
### `runtime.json` — 세션 런타임 메타데이터
|
|
92
|
+
|
|
93
|
+
**책임 주체**: Session hook (하네스 구현 책임). 어떤 MCP tool도 이 파일을 write해서는 안 된다.
|
|
94
|
+
|
|
95
|
+
**생성 trigger**: 하네스는 세션 초기화 시 MUST `runtime.json`을 생성해야 한다. 이 파일은 MCP tool 호출이 시작되기 전에 존재해야 한다.
|
|
96
|
+
|
|
97
|
+
**삭제 trigger**: 하네스는 세션 종료 시 MUST `runtime.json`을 삭제해야 한다.
|
|
98
|
+
|
|
99
|
+
**Schema reference**: `conformance/state-schemas/runtime.schema.json`
|
|
100
|
+
|
|
101
|
+
**Interop requirement**:
|
|
102
|
+
- 하네스는 `runtime.json`을 기록할 때 MUST `conformance/state-schemas/runtime.schema.json`에 유효한 JSON을 기록해야 한다.
|
|
103
|
+
- 다른 하네스의 session hook이 이 파일을 read할 경우 schema에 정의된 필드에만 의존해야 한다. MUST NOT schema 외부의 하네스 전용 필드에 의존해서는 안 된다.
|
|
104
|
+
- `runtime.json`은 MUST NOT git-tracked 상태로 commit되어서는 안 된다.
|
|
105
|
+
|
|
106
|
+
**Conformance fixture reference**: 해당 없음. `runtime.json`은 MCP tool behavioral fixture 범위 외에 있으며 하네스 session hook이 전적으로 책임진다.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### `agent-tracker.json` — 에이전트 인스턴스 추적
|
|
111
|
+
|
|
112
|
+
**책임 주체**: Session hook (하네스 구현 책임). 어떤 MCP tool도 이 파일에 직접 write해서는 안 된다.
|
|
113
|
+
|
|
114
|
+
**생성 trigger**: 하네스는 세션 초기화 시 MUST `agent-tracker.json`을 생성해야 한다. 파일 구조는 세션 중 에이전트 인스턴스 spawn 정보를 기록할 수 있어야 한다.
|
|
115
|
+
|
|
116
|
+
**삭제 trigger**: 하네스는 세션 종료 시 MUST `agent-tracker.json`을 삭제해야 한다.
|
|
117
|
+
|
|
118
|
+
**Schema reference**: `conformance/state-schemas/agent-tracker.schema.json`
|
|
119
|
+
|
|
120
|
+
**Interop requirement**:
|
|
121
|
+
- 하네스는 `agent-tracker.json`을 기록할 때 MUST `conformance/state-schemas/agent-tracker.schema.json`에 유효한 JSON을 기록해야 한다.
|
|
122
|
+
- `task_add` 도구가 `owner_agent_id` 필드를 읽어 harness에 전달하는 방식으로 간접 연계된다. 하네스는 이 연계가 동작하도록 MUST `owner_agent_id` 기반 agent 재개 로직을 구현해야 한다.
|
|
123
|
+
- `agent-tracker.json`은 MUST NOT git-tracked 상태로 commit되어서는 안 된다.
|
|
124
|
+
|
|
125
|
+
**Conformance fixture reference**: 해당 없음. `agent-tracker.json`은 MCP tool behavioral fixture 범위 외에 있으며 하네스 session hook이 전적으로 책임진다.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Agent-produced 산출물 (ephemeral)
|
|
130
|
+
|
|
131
|
+
### `artifacts/` 디렉토리 — 에이전트 생성 파일
|
|
132
|
+
|
|
133
|
+
**책임 주체**: `artifact_write` 도구. 에이전트가 이 도구를 호출하여 산출물을 기록한다. 디렉토리 자체는 첫 `artifact_write` 호출 시 자동 생성된다.
|
|
134
|
+
|
|
135
|
+
**생성 trigger**: 에이전트가 `artifact_write`를 호출할 때 MUST `.nexus/state/artifacts/<filename>` 경로에 파일을 기록해야 한다. 디렉토리가 없으면 MUST 자동 생성해야 한다.
|
|
136
|
+
|
|
137
|
+
**삭제 trigger**: `task_close`는 `artifacts/` 디렉토리를 아카이브하지 않는다. 세션 종료 시 하네스가 이 디렉토리를 정리하거나 유지하는 것은 하네스의 구현 결정이다. 에이전트 또는 사용자가 artifact를 세션 이후에도 보존하려면 MUST `task_close` 이전에 명시적으로 다른 경로로 복사하거나 git-commit해야 한다.
|
|
138
|
+
|
|
139
|
+
**Schema reference**: `artifact_write` 산출물 파일 자체에 대한 schema 제약은 없다. 내용 형식은 도구 호출자가 결정한다.
|
|
140
|
+
|
|
141
|
+
**Interop requirement**:
|
|
142
|
+
- `artifact_write`는 MUST 동일 `filename`으로 반복 호출 시 파일을 덮어써야 한다. 이 덮어쓰기 동작은 하네스 간에 일관되어야 한다.
|
|
143
|
+
- 다른 하네스가 동일 세션 내 `artifacts/` 파일을 읽을 경우, 파일이 존재하면 MUST 읽을 수 있어야 한다. 특정 하네스만 읽을 수 있는 인코딩이나 잠금은 MUST NOT 사용해서는 안 된다.
|
|
144
|
+
- `artifact_write`의 반환값 중 `path` 필드는 MUST 실제 기록된 파일의 절대 경로를 포함해야 한다.
|
|
145
|
+
|
|
146
|
+
**Conformance fixture reference**: 해당 없음. `artifact_write`의 파일 내용 형식에 대한 fixture는 정의되지 않는다. 도구 동작(디렉토리 생성, 파일 write, 반환값)은 `docs/nexus-tools-contract.md`의 `artifact_write` 섹션이 normative source다.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Cross-harness Interop 원칙
|
|
151
|
+
|
|
152
|
+
이 섹션은 하네스 간 상호운용성을 보장하기 위한 최소 의무 조항을 정의한다. 하네스 A가 생성한 산출물을 하네스 B가 읽고 처리할 수 있어야 한다는 원칙에서 도출된다.
|
|
153
|
+
|
|
154
|
+
### MUST 조항
|
|
155
|
+
|
|
156
|
+
1. **Schema 기반 parse 가능성**: 하네스 A가 생성한 `plan.json`은 하네스 B가 `conformance/state-schemas/plan.schema.json`을 기준으로 parse하여 편집·아카이브할 수 있어야 한다. 마찬가지로 `tasks.json`, `history.json`에 대해서도 동일 원칙이 적용된다. 하네스는 MUST schema에 정의된 필드 집합만 기록해야 하며, schema 외부 필드를 추가해서는 안 된다.
|
|
157
|
+
|
|
158
|
+
2. **Forward-compatible schema**: 모든 산출물의 schema는 forward-compatible이어야 한다. 기존 field 제거 또는 type 변경은 MUST semver major bump 대상이며, `CHANGELOG.md`에 "Consumer Action Required" 섹션을 포함해야 한다. 하네스는 MUST 새 minor version의 schema에서 추가된 optional field를 unknown field로 거부해서는 안 된다.
|
|
159
|
+
|
|
160
|
+
3. **ISO 8601 timestamp**: 모든 산출물에 포함되는 timestamp 필드(`created_at`, `completed_at` 등)는 MUST ISO 8601 형식을 사용해야 한다. 하네스별 locale timestamp, Unix epoch, 비표준 포맷은 MUST NOT 사용해서는 안 된다.
|
|
161
|
+
|
|
162
|
+
4. **append-only ledger 보전**: `history.json`은 모든 하네스 간에 MUST append-only로 처리되어야 한다. 기존 cycle 레코드를 수정하거나 삭제하는 하네스는 cross-harness 호환성 보장 대상에서 제외된다.
|
|
163
|
+
|
|
164
|
+
5. **session-scoped 파일 격리**: `plan.json`, `tasks.json`, `runtime.json`, `agent-tracker.json`, `artifacts/` 디렉토리는 MUST git-tracked 상태로 commit되어서는 안 된다. 이 파일들은 세션 범위에 속하며 프로젝트 영구 기록이 아니다. 하네스는 MUST `.gitignore`에 이 경로들을 포함해야 한다.
|
|
165
|
+
|
|
166
|
+
6. **Tool 이름 참조 금지**: 산출물 파일 내용 안에 harness-specific tool 이름(하네스별 MCP prefix, 하네스별 도구 식별자 등)을 MUST NOT 기록해서는 안 된다. 산출물은 harness-neutral해야 한다.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Harness-local State Extension
|
|
171
|
+
|
|
172
|
+
하네스가 nexus-core 공통 schema로 수렴되지 않는 자체 state 파일을 필요로 할 때의 normative 규약이다.
|
|
173
|
+
|
|
174
|
+
### 3 파일 유형 분류
|
|
175
|
+
|
|
176
|
+
| 유형 | 경로 패턴 | Schema 소유 | Lifecycle 책임 |
|
|
177
|
+
|---|---|---|---|
|
|
178
|
+
| 공통 state | `.nexus/state/{name}.json` | nexus-core `conformance/state-schemas/` | nexus-core MCP tool |
|
|
179
|
+
| 하네스 extension | `.nexus/state/{harness-id}/{base}.extension.json` | 하네스 repo `state-schemas/` | 하네스 session hook |
|
|
180
|
+
| 하네스 독립 파일 | `.nexus/state/{harness-id}/{any}.json` | 하네스 repo `state-schemas/` | 하네스 session hook |
|
|
181
|
+
|
|
182
|
+
### Harness-id 식별 규약
|
|
183
|
+
|
|
184
|
+
- **MUST**: `{harness-id}`는 하네스 npm package name의 마지막 segment를 사용한다.
|
|
185
|
+
- `@moreih29/claude-nexus` → `claude-nexus`
|
|
186
|
+
- `@moreih29/opencode-nexus` → `opencode-nexus`
|
|
187
|
+
- `@moreih29/nexus-code` → `nexus-code`
|
|
188
|
+
- **MUST NOT**: nexus-core는 하네스 id 레지스트리를 소유하지 않는다. 규약은 각 하네스 `CONSUMING.md` / `README.md`에서 자기 id를 선언한다.
|
|
189
|
+
|
|
190
|
+
### Extension 파일 의무
|
|
191
|
+
|
|
192
|
+
- **MUST**: 파일명은 `{공통-base}.extension.json` 형식이다. 예: `plan.extension.json`, `tasks.extension.json`, `history.extension.json`.
|
|
193
|
+
- **MUST**: 최상위 `extends` 필드로 참조 대상 공통 schema를 명시한다. 예: `"extends": "plan.schema.json"`.
|
|
194
|
+
- **MUST**: 공통 파일의 레코드와 연결되는 join 필드를 명시한다. 권장 표준:
|
|
195
|
+
- plan extension: `extension_for_plan_id: N` + `issue_extensions: { "<issue_id>": { ... } }`
|
|
196
|
+
- tasks extension: `task_extensions: { "<task_id>": { ... } }`
|
|
197
|
+
- history extension: `cycle_extensions: [ { completed_at, ... } ]`
|
|
198
|
+
- **MUST**: 하네스 repo의 자체 `state-schemas/{base}.extension.schema.json` 파일에 JSON Schema(draft 2020-12, `additionalProperties: false`)를 정의한다.
|
|
199
|
+
- **MUST NOT**: 공통 schema의 필드(id/title/status/created_at 등)를 extension에서 재선언한다.
|
|
200
|
+
- **MUST NOT**: nexus-core MCP tool이 extension 파일을 직접 참조한다고 가정한다. extension은 하네스 session hook이 전담한다.
|
|
201
|
+
|
|
202
|
+
### Namespace 디렉토리 규약
|
|
203
|
+
|
|
204
|
+
- **MUST**: 하네스 고유 파일(독립 파일 + extension)은 모두 `.nexus/state/{harness-id}/` 하위에만 배치한다.
|
|
205
|
+
- **MUST NOT**: `.nexus/state/` 루트에 신규 하네스 파일을 추가한다.
|
|
206
|
+
- **MUST NOT**: 다른 하네스의 namespace 디렉토리에 쓰거나 읽는다.
|
|
207
|
+
- **MUST NOT**: `{harness-id}/` 하위에서 공통 schema 파일명(plan.json, tasks.json, history.json, runtime.json, agent-tracker.json)을 재사용한다. 예: `.nexus/state/claude-nexus/plan.json` 금지.
|
|
208
|
+
- **예외**: v0.3.x 이하에 루트 경로로 등록된 legacy 2종(`edit-tracker.json`, `reopen-tracker.json`)은 `task_close` tool 계약에 묶여 있어 backward-compat으로 루트 유지 허용한다. 신규 파일에는 예외 편승 금지.
|
|
209
|
+
|
|
210
|
+
### Archive 정책
|
|
211
|
+
|
|
212
|
+
- **MUST NOT**: nexus-core의 `history.json`에 하네스 extension을 포함한다.
|
|
213
|
+
- **SHOULD**: 하네스가 archive가 필요한 경우 자체 `.nexus/state/{harness-id}/history.extension.json`을 운영한다. git-tracking 여부는 하네스 결정.
|
|
214
|
+
- **MUST**: `plan_start` 재호출 또는 `task_close` 시 공통 파일이 archive/삭제되면, 하네스 session hook은 대응 extension 파일도 함께 archive/삭제하여 stale 상태를 방지한다.
|
|
215
|
+
|
|
216
|
+
### Atomicity
|
|
217
|
+
|
|
218
|
+
- **MUST**: 공통 파일 쓰기와 대응 extension 쓰기는 하네스 session hook의 책임 하에 함께 성공하거나 함께 실패하도록 처리한다.
|
|
219
|
+
- **SHOULD**: consumer가 extension 파일 부재를 "이 하네스는 해당 공통 파일에 확장 정보 없음"으로 해석한다. 공통 파일은 extension 없이도 valid해야 한다.
|
|
220
|
+
|
|
221
|
+
### 예시 디렉토리 구조
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
.nexus/state/
|
|
225
|
+
├── plan.json ← 공통, strict
|
|
226
|
+
├── tasks.json
|
|
227
|
+
├── runtime.json
|
|
228
|
+
├── agent-tracker.json
|
|
229
|
+
├── artifacts/
|
|
230
|
+
└── claude-nexus/ ← namespace 디렉토리
|
|
231
|
+
├── plan.extension.json ← plan.json의 확장 (priority, estimated_effort 등)
|
|
232
|
+
├── tasks.extension.json
|
|
233
|
+
├── history.extension.json ← 하네스 자체 archive
|
|
234
|
+
├── edit-tracker.json ← 독립 파일
|
|
235
|
+
├── reopen-tracker.json ← 독립 파일
|
|
236
|
+
└── tool-log.jsonl
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
(루트 레벨 `edit-tracker.json`/`reopen-tracker.json`은 legacy carve-out으로 v0.3.x 이하 호환 유지)
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Conformance 의무와의 연결
|
|
244
|
+
|
|
245
|
+
### CONSUMING.md §Conformance Obligation
|
|
246
|
+
|
|
247
|
+
`CONSUMING.md`의 §Conformance Obligation은 하네스가 `conformance/tools/*.json` 및 `conformance/scenarios/*.json`의 모든 fixture를 통과해야 함을 명시한다. 본 문서는 그 의무의 **의미를 확장**한다.
|
|
248
|
+
|
|
249
|
+
fixture 통과 = schema field 100% coverage ≠ 산출물 제어 의무 이행.
|
|
250
|
+
|
|
251
|
+
fixture는 도구 호출의 반환값과 state file postcondition을 검증하지만, 아래 항목은 fixture만으로 검증되지 않는다.
|
|
252
|
+
|
|
253
|
+
- Harness-produced 산출물(`runtime.json`, `agent-tracker.json`)의 생성·삭제 타이밍
|
|
254
|
+
- Cross-harness interop 의무(다른 하네스가 생성한 파일을 읽을 수 있는가)
|
|
255
|
+
- Forward-compatible schema 유지 의무
|
|
256
|
+
- git-tracking 격리 의무
|
|
257
|
+
|
|
258
|
+
하네스는 fixture 통과를 필요조건으로 충족한 뒤, 본 문서의 MUST 조항을 추가 의무로 준수해야 한다.
|
|
259
|
+
|
|
260
|
+
### conformance/README.md Schema Field Coverage Obligation
|
|
261
|
+
|
|
262
|
+
`conformance/README.md`가 정의하는 schema field coverage 의무: 모든 state-schema field는 최소 하나의 fixture의 `covers` 항목에 등장해야 한다. 이 의무는 fixture suite가 schema 전체를 검증함을 보장한다.
|
|
263
|
+
|
|
264
|
+
본 문서는 이 의무가 **Tool-produced 산출물에 대해서만** 적용됨을 명시한다. Harness-produced 산출물(`runtime.json`, `agent-tracker.json`)의 field coverage는 하네스 자체 테스트 suite의 책임이다.
|
|
265
|
+
|
|
266
|
+
schema field가 신규 추가되었을 때, nexus-core 관리자는 MUST 해당 field를 cover하는 fixture를 추가하거나 기존 fixture를 갱신해야 한다. field를 schema에 추가하면서 fixture를 갱신하지 않는 것은 coverage 의무 위반이다.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 관련 문서
|
|
271
|
+
|
|
272
|
+
- `docs/nexus-state-overview.md` — state 파일별 schema, field 정의, tool 접근 매핑 (기술적 사실)
|
|
273
|
+
- `docs/nexus-tools-contract.md` — 11 MCP tool의 parameter, return value, side effect, error condition normative 명세
|
|
274
|
+
- `docs/nexus-layout.md` — `.nexus/` 디렉토리 canonical 구조
|
|
275
|
+
- `docs/behavioral-contracts.md` — task/plan state machine, resume tier, permission model
|
|
276
|
+
- `conformance/README.md` — conformance fixture 형식 및 test runner 작성 가이드
|
|
277
|
+
- `.nexus/rules/neutral-principles.md` — harness-neutral 원칙 enforceable 규칙 (6개 규칙)
|