artshelf 0.4.1 → 0.6.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.
@@ -0,0 +1,315 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://calvinnwq.github.io/artshelf/schemas/artshelf-review-report.schema.json",
4
+ "title": "ArtshelfReviewReport",
5
+ "description": "Machine-readable decision packet for rendering an Artshelf review report.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "schemaVersion",
10
+ "scope",
11
+ "decisionSummary",
12
+ "decisionGroups",
13
+ "summary",
14
+ "recommendation",
15
+ "items",
16
+ "alternatives",
17
+ "safety",
18
+ "verification"
19
+ ],
20
+ "properties": {
21
+ "schemaVersion": {
22
+ "type": "integer",
23
+ "const": 1
24
+ },
25
+ "scope": {
26
+ "type": "object",
27
+ "additionalProperties": false,
28
+ "required": ["registryPath", "ledgerCount", "health", "registryHealth"],
29
+ "properties": {
30
+ "registryPath": { "type": "string" },
31
+ "ledgerCount": { "type": "integer", "minimum": 0 },
32
+ "health": { "type": "string", "enum": ["ok", "attention"] },
33
+ "registryHealth": { "type": "string", "enum": ["ok", "attention"] },
34
+ "affectedLedgers": {
35
+ "type": "array",
36
+ "items": {
37
+ "type": "object",
38
+ "additionalProperties": false,
39
+ "required": ["ledgerPath"],
40
+ "properties": {
41
+ "name": { "type": "string" },
42
+ "ledgerPath": { "type": "string" },
43
+ "validationStatus": {
44
+ "type": "string",
45
+ "enum": ["ok", "missing", "invalid"]
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ },
52
+ "plans": {
53
+ "type": "array",
54
+ "items": { "$ref": "#/$defs/plan" },
55
+ "default": []
56
+ },
57
+ "decisionSummary": {
58
+ "type": "object",
59
+ "additionalProperties": false,
60
+ "required": ["readyForApproval", "needsReviewFirst", "blocked"],
61
+ "properties": {
62
+ "readyForApproval": { "type": "integer", "minimum": 0 },
63
+ "needsReviewFirst": { "type": "integer", "minimum": 0 },
64
+ "blocked": { "type": "integer", "minimum": 0 }
65
+ }
66
+ },
67
+ "decisionGroups": {
68
+ "type": "object",
69
+ "additionalProperties": false,
70
+ "required": ["readyForApproval", "needsReviewFirst", "blocked"],
71
+ "properties": {
72
+ "readyForApproval": {
73
+ "type": "array",
74
+ "items": { "$ref": "#/$defs/approvalDecision" }
75
+ },
76
+ "needsReviewFirst": {
77
+ "type": "array",
78
+ "items": { "$ref": "#/$defs/nonApprovalDecision" }
79
+ },
80
+ "blocked": {
81
+ "type": "array",
82
+ "items": { "$ref": "#/$defs/nonApprovalDecision" }
83
+ }
84
+ }
85
+ },
86
+ "summary": {
87
+ "type": "object",
88
+ "additionalProperties": false,
89
+ "required": [
90
+ "executable",
91
+ "skipped",
92
+ "refused",
93
+ "manualReview",
94
+ "missingPath",
95
+ "trashed"
96
+ ],
97
+ "properties": {
98
+ "executable": { "type": "integer", "minimum": 0 },
99
+ "skipped": { "type": "integer", "minimum": 0 },
100
+ "refused": { "type": "integer", "minimum": 0 },
101
+ "manualReview": { "type": "integer", "minimum": 0 },
102
+ "missingPath": { "type": "integer", "minimum": 0 },
103
+ "trashed": { "type": "integer", "minimum": 0 }
104
+ }
105
+ },
106
+ "recommendation": { "type": "string", "minLength": 1 },
107
+ "items": {
108
+ "type": "array",
109
+ "items": { "$ref": "#/$defs/item" }
110
+ },
111
+ "alternatives": {
112
+ "type": "array",
113
+ "minItems": 1,
114
+ "items": { "type": "string", "minLength": 1 }
115
+ },
116
+ "safety": {
117
+ "type": "object",
118
+ "additionalProperties": false,
119
+ "required": [
120
+ "dryRunOnly",
121
+ "executeAllRefused",
122
+ "noExecuteRan",
123
+ "noResolveRan",
124
+ "noDeleteRan"
125
+ ],
126
+ "properties": {
127
+ "dryRunOnly": { "type": "boolean" },
128
+ "executeAllRefused": { "type": "boolean" },
129
+ "noExecuteRan": { "type": "boolean" },
130
+ "noResolveRan": { "type": "boolean" },
131
+ "noDeleteRan": { "type": "boolean" }
132
+ }
133
+ },
134
+ "verification": {
135
+ "type": "object",
136
+ "additionalProperties": false,
137
+ "required": ["command", "successCondition"],
138
+ "properties": {
139
+ "command": { "type": "string", "minLength": 1 },
140
+ "successCondition": { "type": "string", "minLength": 1 }
141
+ }
142
+ }
143
+ },
144
+ "$defs": {
145
+ "plan": {
146
+ "type": "object",
147
+ "additionalProperties": false,
148
+ "required": ["type", "ledgerPath", "planId", "approvalTarget"],
149
+ "properties": {
150
+ "type": { "type": "string", "enum": ["cleanup", "trash-purge"] },
151
+ "ledgerPath": { "type": "string" },
152
+ "planId": { "type": "string" },
153
+ "planPath": { "type": ["string", "null"] },
154
+ "approvalTarget": { "type": "string" }
155
+ },
156
+ "allOf": [
157
+ {
158
+ "if": {
159
+ "properties": { "type": { "const": "cleanup" } },
160
+ "required": ["type"]
161
+ },
162
+ "then": {
163
+ "properties": {
164
+ "approvalTarget": {
165
+ "pattern": "^approve artshelf cleanup ledger .+ plan .+$"
166
+ }
167
+ }
168
+ }
169
+ },
170
+ {
171
+ "if": {
172
+ "properties": { "type": { "const": "trash-purge" } },
173
+ "required": ["type"]
174
+ },
175
+ "then": {
176
+ "properties": {
177
+ "approvalTarget": {
178
+ "pattern": "^approve artshelf trash purge ledger .+ plan .+$"
179
+ }
180
+ }
181
+ }
182
+ }
183
+ ]
184
+ },
185
+ "item": {
186
+ "type": "object",
187
+ "additionalProperties": false,
188
+ "required": [
189
+ "classification",
190
+ "proposedAction",
191
+ "dueStatus",
192
+ "reason",
193
+ "note"
194
+ ],
195
+ "properties": {
196
+ "id": { "type": "string" },
197
+ "path": { "type": "string" },
198
+ "classification": {
199
+ "type": "string",
200
+ "enum": [
201
+ "trash-safe",
202
+ "needs-human-review",
203
+ "resolve-candidate",
204
+ "registry-problem"
205
+ ]
206
+ },
207
+ "proposedAction": { "type": "string", "minLength": 1 },
208
+ "dueStatus": {
209
+ "type": "string",
210
+ "enum": ["kept", "due", "manual-review", "missing-path", "trashed"]
211
+ },
212
+ "reason": { "type": "string", "minLength": 1 },
213
+ "note": { "type": "string", "minLength": 1 }
214
+ },
215
+ "anyOf": [
216
+ { "required": ["id"] },
217
+ { "required": ["path"] }
218
+ ]
219
+ },
220
+ "decision": {
221
+ "type": "object",
222
+ "additionalProperties": false,
223
+ "required": ["label", "actionType", "reason", "nextStep"],
224
+ "properties": {
225
+ "label": { "type": "string", "minLength": 1 },
226
+ "itemIds": {
227
+ "type": "array",
228
+ "items": { "type": "string", "minLength": 1 },
229
+ "default": []
230
+ },
231
+ "actionType": {
232
+ "type": "string",
233
+ "enum": [
234
+ "cleanup",
235
+ "trash-purge",
236
+ "resolve-missing",
237
+ "inspect",
238
+ "fix-registry",
239
+ "keep-or-snooze",
240
+ "change-retention"
241
+ ]
242
+ },
243
+ "approvalTarget": { "type": ["string", "null"] },
244
+ "reason": { "type": "string", "minLength": 1 },
245
+ "nextStep": { "type": "string", "minLength": 1 }
246
+ }
247
+ },
248
+ "approvalDecision": {
249
+ "allOf": [
250
+ { "$ref": "#/$defs/decision" },
251
+ {
252
+ "required": ["approvalTarget"],
253
+ "properties": {
254
+ "actionType": {
255
+ "enum": ["cleanup", "trash-purge", "resolve-missing"]
256
+ },
257
+ "approvalTarget": { "type": "string", "minLength": 1 }
258
+ }
259
+ },
260
+ {
261
+ "if": {
262
+ "properties": { "actionType": { "const": "cleanup" } },
263
+ "required": ["actionType"]
264
+ },
265
+ "then": {
266
+ "properties": {
267
+ "approvalTarget": {
268
+ "pattern": "^approve artshelf cleanup ledger .+ plan .+$"
269
+ }
270
+ }
271
+ }
272
+ },
273
+ {
274
+ "if": {
275
+ "properties": { "actionType": { "const": "trash-purge" } },
276
+ "required": ["actionType"]
277
+ },
278
+ "then": {
279
+ "properties": {
280
+ "approvalTarget": {
281
+ "pattern": "^approve artshelf trash purge ledger .+ plan .+$"
282
+ }
283
+ }
284
+ }
285
+ },
286
+ {
287
+ "if": {
288
+ "properties": { "actionType": { "const": "resolve-missing" } },
289
+ "required": ["actionType"]
290
+ },
291
+ "then": {
292
+ "properties": {
293
+ "approvalTarget": {
294
+ "pattern": "^approve artshelf resolve missing ledger .+ ids .+$"
295
+ }
296
+ }
297
+ }
298
+ }
299
+ ]
300
+ },
301
+ "nonApprovalDecision": {
302
+ "allOf": [
303
+ { "$ref": "#/$defs/decision" },
304
+ {
305
+ "properties": {
306
+ "actionType": {
307
+ "enum": ["inspect", "fix-registry", "keep-or-snooze", "change-retention"]
308
+ },
309
+ "approvalTarget": { "type": "null" }
310
+ }
311
+ }
312
+ ]
313
+ }
314
+ }
315
+ }
@@ -25,6 +25,10 @@ fresh. Do not infer intent later from filesystem age or path names.
25
25
  labels.
26
26
  - Capture the Artshelf id in handoffs, PRs, issue comments, memory, or run
27
27
  summaries when the artifact matters for restart or review.
28
+ - When `artshelf put --json` succeeds, report a deterministic Artshelf footnote
29
+ in the same handoff, status, final response, or run summary that mentions the
30
+ artifact. Include the path, Artshelf id, short reason, due date or
31
+ `manual-review`, and cleanup mode.
28
32
  - Cleanup execution is approval-only. Read-only review is fine; mutation needs
29
33
  a reviewed plan id and explicit human approval.
30
34
 
@@ -121,7 +125,7 @@ next safe action.
121
125
  them explicitly:
122
126
 
123
127
  ```bash
124
- artshelf ledgers add --ledger <repo>/.shelf/ledger.jsonl --name <project> --scope repo --json
128
+ artshelf ledgers add --ledger <repo>/.artshelf/ledger.jsonl --name <project> --scope repo --json
125
129
  ```
126
130
 
127
131
  `--all` is for discovery and review. Do not use it as permission to mutate
@@ -165,11 +169,78 @@ artshelf trash purge --execute --plan-id <purge-plan-id> --ledger <ledger-path>
165
169
  `artshelf review --all --json`, plus `artshelf trash list --ledger <ledger-path> --json`
166
170
  and purge receipt evidence after purge, or explain what remains.
167
171
 
172
+ ### Review Plan Report Schema
173
+
174
+ When a dry-run creates or reuses a cleanup or trash purge plan, surface the plan
175
+ in a compact human-readable report. The report should let the user approve, ask
176
+ for changes, or request alternatives without opening the plan file.
177
+
178
+ For deterministic agent integrations, construct an `ArtshelfReviewReport` JSON
179
+ object first, then render it to text. Use
180
+ `schemas/artshelf-review-report.schema.json` for the packet shape and
181
+ `examples/artshelf-review-report.json` as the canonical example. The schema
182
+ locks report structure; the CLI output and approval rules still define cleanup
183
+ safety.
184
+
185
+ Render the JSON packet as a compact decision card using `decisionSummary` and
186
+ `decisionGroups`. Lead with counts, then show exactly what is ready for approval
187
+ and what needs review first. Emojis are encouraged when the host renders them
188
+ well because they make the groups scannable; omit them only for plain-text or
189
+ accessibility-constrained surfaces.
190
+
191
+ ```text
192
+ Artshelf daily review
193
+ Status: <ok|attention needed>; registry <ok|attention>
194
+
195
+ ✅ Ready for approval: <n>
196
+ 👀 Needs review first: <n>
197
+ ⚠️ Blocked: <n>
198
+
199
+ Recommended action
200
+ <one short sentence with the next safest action>.
201
+
202
+ Ready for approval
203
+ 1. <short item label>
204
+ Why: <short reason>
205
+ Action: <what approval will do>
206
+ approve artshelf cleanup ledger <ledger-path> plan <plan-id>
207
+
208
+ 2. <short item label>
209
+ Why: <short reason>
210
+ Action: <ledger-only update, no file changes>
211
+ approve artshelf resolve missing ledger <ledger-path> ids <id...>
212
+
213
+ Needs review first
214
+ 1. <short item label>
215
+ Why: <short reason>
216
+ Suggested next step: inspect path, then choose keep, change retention, resolve, or clean up later
217
+ Path: <path>
218
+
219
+ Blocked
220
+ <none, or the registry/refused/missing-path blocker and next repair step>
221
+
222
+ Safety
223
+ Dry-run only. No execute, resolve, or delete ran.
224
+ ```
225
+
226
+ Keep the full `ArtshelfReviewReport` JSON as the audit packet and include it as
227
+ an attachment, linked file, or expandable detail when the host supports that.
228
+ Do not paste the whole packet into chat unless the user asks for it. For long
229
+ plans, show only the first 3 to 5 decisions under each visible group, then state
230
+ the hidden count by group and classification. Do not hide refused,
231
+ registry-problem, or missing-path items.
232
+
233
+ If the host supports buttons, menus, or other interactive controls, they should
234
+ emit exact text commands such as the approval targets below. Always include the
235
+ exact approval target in the message body as a fallback for clients where those
236
+ controls do not render.
237
+
168
238
  Approval wording should be exact:
169
239
 
170
240
  ```text
171
241
  approve artshelf cleanup ledger <ledger-path> plan <plan-id>
172
242
  approve artshelf trash purge ledger <ledger-path> plan <purge-plan-id>
243
+ approve artshelf resolve missing ledger <ledger-path> ids <id...>
173
244
  ```
174
245
 
175
246
  Never execute from a read-only preview id. Never generate a fresh plan and
@@ -219,6 +290,13 @@ Artshelf artifact: shf_20260601_182800_ab12, /tmp/parser-output, retain until
219
290
  2026-06-04, cleanup=review.
220
291
  ```
221
292
 
293
+ When a machine-readable registration succeeds, use the same deterministic
294
+ footnote shape:
295
+
296
+ ```text
297
+ Artshelf footnote: registered <artifact-path> as <artshelf-id>; reason: <short reason>; due: <YYYY-MM-DD|manual-review>; cleanup=<cleanup-mode>.
298
+ ```
299
+
222
300
  ## Completion Check
223
301
 
224
302
  Before finalizing a task, review your own file actions:
@@ -283,8 +361,17 @@ artshelf resolve <id> --status resolved --reason <text>
283
361
  ```
284
362
 
285
363
  Use a specific reason. `resolve` only updates the ledger; it does not move or
286
- delete files. Resolved records stop reappearing in future due and dry-run
287
- cleanup output while remaining visible in `artshelf list --status resolved`.
364
+ delete files. For batches of missing-path records, ask for approval that names
365
+ the exact ledger and ids:
366
+
367
+ ```text
368
+ approve artshelf resolve missing ledger <ledger-path> ids <id...>
369
+ ```
370
+
371
+ After resolution, verify with `artshelf review --all --json` and report whether
372
+ the review is quiet or what remains. Resolved records stop reappearing in future
373
+ due and dry-run cleanup output while remaining visible in
374
+ `artshelf list --status resolved`.
288
375
 
289
376
  ## Scheduled Review
290
377
 
@@ -0,0 +1,116 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "scope": {
4
+ "registryPath": "~/.artshelf/ledgers.json",
5
+ "ledgerCount": 3,
6
+ "health": "attention",
7
+ "registryHealth": "ok",
8
+ "affectedLedgers": [
9
+ {
10
+ "name": "example-project",
11
+ "ledgerPath": "/path/to/example-project/.artshelf/ledger.jsonl",
12
+ "validationStatus": "ok"
13
+ }
14
+ ]
15
+ },
16
+ "plans": [
17
+ {
18
+ "type": "cleanup",
19
+ "ledgerPath": "/path/to/example-project/.artshelf/ledger.jsonl",
20
+ "planId": "plan_20260606_120000_ab12",
21
+ "planPath": "/path/to/example-project/.artshelf/plans/plan_20260606_120000_ab12.json",
22
+ "approvalTarget": "approve artshelf cleanup ledger /path/to/example-project/.artshelf/ledger.jsonl plan plan_20260606_120000_ab12"
23
+ }
24
+ ],
25
+ "summary": {
26
+ "executable": 1,
27
+ "skipped": 2,
28
+ "refused": 0,
29
+ "manualReview": 1,
30
+ "missingPath": 1,
31
+ "trashed": 0
32
+ },
33
+ "decisionSummary": {
34
+ "readyForApproval": 2,
35
+ "needsReviewFirst": 1,
36
+ "blocked": 0
37
+ },
38
+ "decisionGroups": {
39
+ "readyForApproval": [
40
+ {
41
+ "label": "Clean up temp debug output",
42
+ "itemIds": ["shf_20260606_120000_ab12"],
43
+ "actionType": "cleanup",
44
+ "approvalTarget": "approve artshelf cleanup ledger /path/to/example-project/.artshelf/ledger.jsonl plan plan_20260606_120000_ab12",
45
+ "reason": "Disposable temp artifact has a reviewed cleanup plan.",
46
+ "nextStep": "Approve the exact cleanup plan to move the artifact into Artshelf trash."
47
+ },
48
+ {
49
+ "label": "Resolve missing report record",
50
+ "itemIds": ["shf_20260606_120500_cd34"],
51
+ "actionType": "resolve-missing",
52
+ "approvalTarget": "approve artshelf resolve missing ledger /path/to/example-project/.artshelf/ledger.jsonl ids shf_20260606_120500_cd34",
53
+ "reason": "The report path is already missing.",
54
+ "nextStep": "Approve the ledger-only resolve command after confirming the report is no longer needed."
55
+ }
56
+ ],
57
+ "needsReviewFirst": [
58
+ {
59
+ "label": "Inspect lifecycle smoke report",
60
+ "itemIds": ["shf_20260606_121000_ef56"],
61
+ "actionType": "inspect",
62
+ "approvalTarget": null,
63
+ "reason": "cleanup=review means the artifact should be inspected before closing.",
64
+ "nextStep": "Inspect the path, then choose keep, change retention, resolve, or clean up later."
65
+ }
66
+ ],
67
+ "blocked": []
68
+ },
69
+ "recommendation": "Approve the reviewed cleanup plan for the disposable temp directory, then resolve the missing record after confirming it is no longer needed.",
70
+ "items": [
71
+ {
72
+ "id": "shf_20260606_120000_ab12",
73
+ "path": "/tmp/example-debug-output",
74
+ "classification": "trash-safe",
75
+ "proposedAction": "execute reviewed cleanup plan",
76
+ "dueStatus": "due",
77
+ "reason": "temporary debug output retained for 3 days",
78
+ "note": "The path exists, cleanup=trash, and the dry-run plan moves it into Artshelf trash."
79
+ },
80
+ {
81
+ "id": "shf_20260606_120500_cd34",
82
+ "path": "/tmp/missing-report.json",
83
+ "classification": "resolve-candidate",
84
+ "proposedAction": "resolve ledger-only after confirmation",
85
+ "dueStatus": "missing-path",
86
+ "reason": "report path is already missing",
87
+ "note": "Resolution updates only the ledger and does not move or delete files."
88
+ },
89
+ {
90
+ "id": "shf_20260606_121000_ef56",
91
+ "path": "/tmp/lifecycle-smoke-report.json",
92
+ "classification": "needs-human-review",
93
+ "proposedAction": "inspect before choosing cleanup or retention",
94
+ "dueStatus": "manual-review",
95
+ "reason": "cleanup=review artifact retained for manual inspection",
96
+ "note": "No approval target is shown until the review decision is known."
97
+ }
98
+ ],
99
+ "alternatives": [
100
+ "keep the artifact and change retention",
101
+ "inspect the path before approving cleanup",
102
+ "regenerate the plan after edits",
103
+ "resolve missing records ledger-only"
104
+ ],
105
+ "safety": {
106
+ "dryRunOnly": true,
107
+ "executeAllRefused": true,
108
+ "noExecuteRan": true,
109
+ "noResolveRan": true,
110
+ "noDeleteRan": true
111
+ },
112
+ "verification": {
113
+ "command": "artshelf review --all --json",
114
+ "successCondition": "no due, manual-review, missing-path, executable, or refused entries remain unless explicitly reported"
115
+ }
116
+ }