@onedotmint/charterleaf 0.4.0 → 0.4.1
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_SNIPPET.md +6 -1
- package/README.md +93 -30
- package/extensions/charterleaf.js +50 -9
- package/package.json +4 -2
- package/skills/charterleaf/SKILL.md +28 -2
- package/skills/charterleaf/runtime.md +8 -4
package/AGENTS_SNIPPET.md
CHANGED
|
@@ -28,7 +28,12 @@ With automation enabled, use supplied constraints or explicitly read the
|
|
|
28
28
|
named specs before retrying a gated write/edit. Use standard `write`/`edit`
|
|
29
29
|
for spec changes: Confirm requires each approval; Reference allows no
|
|
30
30
|
spec changes. Do not bypass these cooperative checks with Bash or another
|
|
31
|
-
writer.
|
|
31
|
+
writer. During normal development or investigation, capture newly established
|
|
32
|
+
or newly discovered knowledge only with reliable evidence, long-term value and a
|
|
33
|
+
documentation/discoverability gap; no code change or prior spec is required.
|
|
34
|
+
Prefer short scoped references to authoritative owners over copying documents.
|
|
35
|
+
Explicit no-file-write/read-only instructions override Auto. No justified durable
|
|
36
|
+
knowledge means no spec edit; never relax a spec merely
|
|
32
37
|
to accommodate conflicting code. Preserve user/parallel work and keep
|
|
33
38
|
state, plans, evidence and history in their existing authoritative owners,
|
|
34
39
|
not in a new Charterleaf workflow.
|
package/README.md
CHANGED
|
@@ -36,10 +36,10 @@ Install once in Pi to discover the bundled Extension and Skill:
|
|
|
36
36
|
pi install npm:@onedotmint/charterleaf
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
`.tgz` file).
|
|
42
|
-
|
|
39
|
+
For the standalone CLI, use `npm install -g @onedotmint/charterleaf`.
|
|
40
|
+
For local development, use `pi install /absolute/path/to/charterleaf` (a package
|
|
41
|
+
directory, not a `.tgz` file). To test the CLI from a local package, run `npm pack`
|
|
42
|
+
then `npm install -g ./onedotmint-charterleaf-0.4.1.tgz`.
|
|
43
43
|
|
|
44
44
|
Restart Pi or run `/reload` after installation, then use `/charterleaf` in each
|
|
45
45
|
project you want to enable. To stop automation, choose **Not Enable** in that
|
|
@@ -128,18 +128,55 @@ requires fresh delivery; successful standard spec writes invalidate loaded state
|
|
|
128
128
|
Compaction invalidates loaded context so constraints must be delivered
|
|
129
129
|
again. This is task-local bookkeeping, not a watcher or persistent index.
|
|
130
130
|
|
|
131
|
+
Knowledge capture happens **during normal work**, not just after code changes:
|
|
132
|
+
development, debugging, substantive code/test/architecture investigation and
|
|
133
|
+
accepted technical decisions can establish or uncover durable knowledge. A project
|
|
134
|
+
with only `specs/.charterleaf.json` is a valid initial state. When evidence warrants
|
|
135
|
+
it, the Agent creates a concise scoped spec using ordinary authorized `write`/`edit`;
|
|
136
|
+
Core immediately routes its `id`/`applies_to` on later related code reads or edits.
|
|
137
|
+
There is no initialization scan, document quota or adoption wizard.
|
|
138
|
+
|
|
131
139
|
At successful, actionable `agent_before_settle`, the Extension may request
|
|
132
|
-
**at most one final semantic review per task
|
|
133
|
-
|
|
140
|
+
**at most one final semantic review per task**. Actual development remains a
|
|
141
|
+
fallback, but an unresolved evidenced knowledge candidate can also trigger it
|
|
142
|
+
without file changes or Git. The existing Agent makes the semantic judgment; the
|
|
143
|
+
Extension observes standalone assistant lifecycle comments outside fenced examples
|
|
144
|
+
(`charterleaf: review` or an explicit `covered`/`no-value`/`proposed` knowledge
|
|
145
|
+
conclusion; an exact terminal conclusion also works inline), never interprets read
|
|
146
|
+
counts as knowledge. A generic `done` cannot suppress the development fallback.
|
|
147
|
+
In an empty-spec project, a development fallback
|
|
148
|
+
remains eligible when the Agent says `no-value`; this gives the existing single
|
|
149
|
+
review a chance to catch a missed discovery gap. These are
|
|
150
|
+
cooperative intent signals, not evidence or permissions. Already judged/captured,
|
|
151
|
+
proposed or effectively documented knowledge needs no repeat review when a
|
|
152
|
+
completion signal is observed. If the Agent
|
|
153
|
+
omits its completion signal, the bounded fallback can repeat an already answered
|
|
154
|
+
knowledge judgment; zero redundant reviews is not guaranteed. Successful
|
|
155
|
+
structurally valid standard spec writes mark capture complete; later actual code
|
|
156
|
+
edits or distinct candidates may rearm. Opaque activity after capture still uses
|
|
157
|
+
bounded Git comparison when available. Ordinary views, queries and chat do not
|
|
158
|
+
by themselves request another model call.
|
|
159
|
+
|
|
160
|
+
For the development fallback, the Extension separates successful standard-tool
|
|
161
|
+
paths whose observed content is still
|
|
134
162
|
unchanged from **unattributed** changes observed against the task's Git
|
|
135
163
|
baseline. Neither a touched file nor a dirty worktree proves ownership
|
|
136
164
|
of every line. Preserve existing user dirt and parallel work; unattributed
|
|
137
165
|
changes alone must not justify spec edits. No automatic revert, stage,
|
|
138
166
|
commit or push is performed.
|
|
139
167
|
|
|
140
|
-
**No durable knowledge means no spec edit.**
|
|
141
|
-
|
|
142
|
-
|
|
168
|
+
**No justified durable knowledge means no spec edit.** Distinguish **newly
|
|
169
|
+
established** contracts/decisions from **newly discovered** existing constraints;
|
|
170
|
+
both can qualify even in a code-read-only investigation. Require reliable evidence
|
|
171
|
+
(accepted decisions, authoritative docs, tests or sufficiently verified behavior),
|
|
172
|
+
future mistake-prevention value, and a documentation/discoverability gap. If an
|
|
173
|
+
existing authoritative document covers it, prefer a short routed reference when
|
|
174
|
+
needed; otherwise do nothing. Keep non-obvious contracts, invariants, boundaries,
|
|
175
|
+
pitfalls or accepted decisions — not code summaries, progress, debugging logs,
|
|
176
|
+
temporary plans/todos or speculation. Current code alone is not an accepted
|
|
177
|
+
correct contract. Explicit **no-file-write/read-only** instructions override Auto:
|
|
178
|
+
report a finding/proposal without writing. Confirm/Reference retain their existing
|
|
179
|
+
permissions. A
|
|
143
180
|
code/spec conflict is not permission to accommodate incorrect code:
|
|
144
181
|
distinguish implementation bugs, authoritatively obsolete specs and
|
|
145
182
|
explicitly intended contract changes. When uncertain, preserve the spec
|
|
@@ -256,7 +293,8 @@ specs/
|
|
|
256
293
|
|
|
257
294
|
A spec records a constraint whose absence would plausibly cause a future
|
|
258
295
|
developer or agent to make a wrong decision. It should be non-obvious,
|
|
259
|
-
durable, **already true**,
|
|
296
|
+
durable, **already true or explicitly accepted**, evidenced, mistake-preventing,
|
|
297
|
+
and not already effectively documented. Good fits: contracts,
|
|
260
298
|
invariants, architecture boundaries, non-goals, recurring pitfalls,
|
|
261
299
|
accepted rationale, verification constraints.
|
|
262
300
|
|
|
@@ -274,8 +312,8 @@ review comes first, or a multi-step migration is underway. A change must
|
|
|
274
312
|
contain at least one of `ADD`, `MODIFY`, `REMOVE`; `PRESERVE` alone is
|
|
275
313
|
not a change.
|
|
276
314
|
|
|
277
|
-
Otherwise, implement
|
|
278
|
-
changed
|
|
315
|
+
Otherwise, implement/verify as needed and maintain the living spec when durable
|
|
316
|
+
truth changed **or an existing valuable constraint lacks effective documentation**. After an accepted change is implemented, merge the durable
|
|
279
317
|
result into living specs and delete the change file. Git keeps history.
|
|
280
318
|
|
|
281
319
|
## Agent conventions
|
|
@@ -348,34 +386,59 @@ Verification commands:
|
|
|
348
386
|
|
|
349
387
|
```bash
|
|
350
388
|
npm test
|
|
351
|
-
npm run test:pi #
|
|
389
|
+
npm run test:pi # isolated real RPC/UI smoke; no model calls
|
|
390
|
+
CHARTERLEAF_MODEL=deepseek/deepseek-flash npm run test:organic # paid isolated A–G acceptance
|
|
391
|
+
CHARTERLEAF_MODEL=deepseek/deepseek-flash CHARTERLEAF_BASELINE=5d470db npm run test:context # paid comparison against v0.4.0
|
|
392
|
+
node scripts/organic-smoke.js --self-test # harness/oracle check, no model calls
|
|
352
393
|
node --test tests/extension.test.js
|
|
353
394
|
npm pack --dry-run
|
|
354
395
|
node bin/charterleaf.js related extensions/charterleaf.js
|
|
355
396
|
node bin/charterleaf.js lint
|
|
356
397
|
```
|
|
357
398
|
|
|
358
|
-
Validated on Node.js 24.21.0 and Pi 1.1.0:
|
|
399
|
+
Validated on Node.js 24.21.0 and Pi 1.1.0: 183 automated Core/Extension tests,
|
|
359
400
|
structural lint, dry-run npm packaging, and real Pi RPC loading/native selection
|
|
360
401
|
for cancellation, mode changes, disable and cross-process restore. The RPC smoke
|
|
361
402
|
uses isolated temporary projects/settings and makes no model calls.
|
|
362
403
|
|
|
363
|
-
|
|
364
|
-
isolated Git projects
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
404
|
+
The 0.4.1 organic-capture acceptance used real `deepseek/deepseek-flash` sessions
|
|
405
|
+
in isolated Git projects. Actual tool results, approval records, specs, routing,
|
|
406
|
+
file snapshots/diffs, original tests and an independent exact-money oracle were
|
|
407
|
+
checked, not just assistant claims. Empty-spec development and investigation,
|
|
408
|
+
ordinary-query non-triggers, authoritative-document references, bug-versus-contract
|
|
409
|
+
handling, cross-session reuse and mode/read-only/no-UI permissions all have passing
|
|
410
|
+
evidence. **The strict matrix was not consistently all-green:** the latest focused
|
|
411
|
+
A→F1→F2 run passed A and F1, while F2 omitted its knowledge-completion comment and
|
|
412
|
+
received one redundant fallback review. Its actual routing, code behavior and
|
|
413
|
+
unchanged-spec checks passed. These bounded examples do not prove model reliability
|
|
414
|
+
on every task or provider, or guarantee zero redundant reviews.
|
|
415
|
+
|
|
416
|
+
The controlled organic-capture comparison (`scripts/context-smoke.js`) keeps cwd,
|
|
417
|
+
package paths, prompt and native tools identical. On `deepseek/deepseek-flash`:
|
|
418
|
+
disabled 1,616 input tokens; v0.4.0 baseline 2,036 (increment 420); organic runtime
|
|
419
|
+
2,142 (increment 526), or **106 additional fixed input tokens**. Input here includes
|
|
420
|
+
cached input. Each chat made exactly one request and no tool calls; the full Skill
|
|
421
|
+
remains on demand. Absolute path tokenization and provider tokenizers vary, and
|
|
422
|
+
cache-hit sizes affect uncached charges, so these are measured examples, not fixed
|
|
423
|
+
billing guarantees. The script defaults to `HEAD`; set `CHARTERLEAF_BASELINE` to the
|
|
424
|
+
older revision being compared (the command above uses the v0.4.0 release commit).
|
|
425
|
+
Substantive work requests **zero or at most one** extra model review: observed
|
|
426
|
+
capture/coverage/proposal completion skips the fallback; empty-spec development can
|
|
427
|
+
still get the one fallback after a `no-value` judgment.
|
|
428
|
+
|
|
429
|
+
The real-model acceptance script retains raw RPC/JSONL, conversations, actual tool
|
|
430
|
+
records, before/after files, tracked/untracked diffs, validation output and individual
|
|
431
|
+
assertions in the printed private temporary directory, including failures. It copies
|
|
432
|
+
credentials only to isolated settings and removes that copy on normal/error
|
|
433
|
+
completion; a forced process kill may require deleting the private credential
|
|
434
|
+
copy manually. It does not
|
|
435
|
+
import personal extensions/instructions or modify other repositories, and it is not
|
|
436
|
+
an OS security sandbox. Both paid scripts require explicit `CHARTERLEAF_MODEL=provider/id`; neither chooses
|
|
437
|
+
another provider automatically. The requested model must be available;
|
|
438
|
+
`--case A,B,...` selects bounded scenarios. F cases run A first, then B only if A failed to capture; they reuse only
|
|
439
|
+
model-written knowledge in the same project across fresh sessions. A's failure
|
|
440
|
+
remains a failed assertion; a successful B→F chain does not conceal it. Model usage counts visible assistant responses, not hidden
|
|
441
|
+
provider HTTP retries. Cost fixtures also remove copied credentials on exit.
|
|
379
442
|
|
|
380
443
|
For an interactive smoke check in a disposable project, install the local
|
|
381
444
|
package in a compatible Pi host and run `/charterleaf`: check immediate
|
|
@@ -26,7 +26,7 @@ module.exports = function charterleaf(pi) {
|
|
|
26
26
|
if (mode === 'off') { state = undefined; return; }
|
|
27
27
|
if (!state || state.root !== root) state = {
|
|
28
28
|
root, mode, loaded: new Map(), staged: new Map(), pages: new Map(), pending: new Map(), denied: new Set(),
|
|
29
|
-
owned: new Map(), parents: new Map(), envelopes: new Map(), before: gitSnapshot(root), budget: 24000, reviewed: false, miss: false, opaque: false,
|
|
29
|
+
owned: new Map(), parents: new Map(), envelopes: new Map(), before: gitSnapshot(root), budget: 24000, reviewed: false, miss: false, opaque: false, knowledge: undefined,
|
|
30
30
|
};
|
|
31
31
|
state.mode = mode;
|
|
32
32
|
return state;
|
|
@@ -148,6 +148,23 @@ module.exports = function charterleaf(pi) {
|
|
|
148
148
|
} };
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
+
// Semantic intent comes from the existing agent, never from file/read counts.
|
|
152
|
+
pi.on('message_end', (event, ctx) => {
|
|
153
|
+
if (event.message.role !== 'assistant' || ['error', 'aborted'].includes(event.message.stopReason)) return;
|
|
154
|
+
let s;
|
|
155
|
+
try { s = current(ctx); } catch { return; }
|
|
156
|
+
if (!s) return;
|
|
157
|
+
const text = event.message.content.filter((part) => part.type === 'text').map((part) => part.text).join('\n');
|
|
158
|
+
const prose = text.replace(/```[\s\S]*?(?:```|$)|~~~[\s\S]*?(?:~~~|$)/g, '');
|
|
159
|
+
const signal = prose.match(/<!-- charterleaf: (covered|no-value|proposed) -->\s*$/) ||
|
|
160
|
+
[...prose.matchAll(/^<!-- charterleaf: (review|covered|no-value|proposed) -->[ \t]*$/gm)].at(-1);
|
|
161
|
+
if (signal) {
|
|
162
|
+
if (signal[1] === 'proposed' && s.mode === 'confirm' && !s.proposed) return;
|
|
163
|
+
s.knowledge = signal[1];
|
|
164
|
+
if (s.knowledge !== 'review') { s.capture = gitSnapshot(s.root); s.opaque = false; }
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
151
168
|
// A sibling tool call has not seen another sibling's result yet. Promote only at the next model request.
|
|
152
169
|
pi.on('context', (_event, ctx) => {
|
|
153
170
|
if (!state || state.root !== projectRoot(ctx.cwd)) return;
|
|
@@ -181,13 +198,14 @@ module.exports = function charterleaf(pi) {
|
|
|
181
198
|
if (mutation && (isSpec(file) || (lexical && isSpec(lexical)))) {
|
|
182
199
|
if (s.mode === 'reference') return { block: true, reason: 'Charterleaf Reference mode: report a proposal; do not modify specs.' };
|
|
183
200
|
if (s.mode === 'confirm') {
|
|
201
|
+
s.proposed = true;
|
|
184
202
|
if (!ctx.hasUI) return { block: true, reason: 'Charterleaf Confirm mode requires interactive approval. Report the proposal without writing.' };
|
|
185
203
|
const proposal = JSON.stringify(event.input, null, 2);
|
|
186
204
|
if (proposal.length > 12000) return { block: true, reason: 'Spec proposal too large to approve safely. Use smaller standard edits.' };
|
|
187
205
|
if (s.denied.has(proposal)) return { block: true, reason: 'This exact spec proposal was already refused in this task. Do not retry; report it without writing.' };
|
|
188
206
|
const before = fingerprint(s.root, file);
|
|
189
207
|
const approved = await ctx.ui.confirm(`Charterleaf: modify ${file}?`,
|
|
190
|
-
`Approve this exact ${event.toolName} only if the durable
|
|
208
|
+
`Approve this exact ${event.toolName} only if the evidenced durable knowledge maintenance is intended. Never relax a spec just to match conflicting code.\n\n${proposal}`, { timeout: 60000 });
|
|
191
209
|
if (!approved) {
|
|
192
210
|
s.denied.add(proposal);
|
|
193
211
|
return { block: true, reason: 'Spec modification not approved. Preserve the current spec and report the proposal; do not retry.' };
|
|
@@ -223,7 +241,12 @@ module.exports = function charterleaf(pi) {
|
|
|
223
241
|
s.envelopes.delete(event.toolCallId);
|
|
224
242
|
if (event.isError) {
|
|
225
243
|
if (call?.mutation) {
|
|
226
|
-
try {
|
|
244
|
+
try {
|
|
245
|
+
if (fingerprint(s.root, call.file) !== call.before) {
|
|
246
|
+
s.opaque = true;
|
|
247
|
+
if (s.knowledge !== 'review') s.knowledge = undefined;
|
|
248
|
+
}
|
|
249
|
+
} catch { s.opaque = true; s.knowledge = undefined; }
|
|
227
250
|
}
|
|
228
251
|
if (envelope) return { content: [...event.content, { type: 'text', text: `[Charterleaf]\n${envelope}` }] };
|
|
229
252
|
return;
|
|
@@ -233,13 +256,18 @@ module.exports = function charterleaf(pi) {
|
|
|
233
256
|
if (call) {
|
|
234
257
|
const hash = fingerprint(s.root, call.file);
|
|
235
258
|
if (call.mutation && hash !== call.before) {
|
|
259
|
+
if (s.knowledge !== 'review') s.knowledge = undefined;
|
|
236
260
|
s.owned.set(call.file, hash);
|
|
237
261
|
if (isSpec(call.file)) {
|
|
238
262
|
s.loaded.delete(call.file);
|
|
239
263
|
s.pages.delete(call.file);
|
|
240
264
|
let output = '';
|
|
241
265
|
const stream = { write: (text) => { output += text; } };
|
|
242
|
-
lint(s.root, { stdout: stream, stderr: stream })
|
|
266
|
+
if (lint(s.root, { stdout: stream, stderr: stream }) === 0) {
|
|
267
|
+
s.knowledge = 'captured';
|
|
268
|
+
s.capture = gitSnapshot(s.root);
|
|
269
|
+
s.opaque = false;
|
|
270
|
+
}
|
|
243
271
|
note = `Charterleaf structural check (not semantic verification):\n${output.slice(0, 4000)}`;
|
|
244
272
|
}
|
|
245
273
|
} else if (!call.mutation) {
|
|
@@ -278,30 +306,43 @@ module.exports = function charterleaf(pi) {
|
|
|
278
306
|
if (!s || s.reviewed || event.outcome !== 'completed') return;
|
|
279
307
|
s.reviewed = true;
|
|
280
308
|
try {
|
|
281
|
-
if (
|
|
309
|
+
if (['captured', 'covered', 'proposed'].includes(s.knowledge)) {
|
|
310
|
+
if (!s.opaque) return;
|
|
311
|
+
const afterCapture = gitSnapshot(s.root);
|
|
312
|
+
if (s.capture && afterCapture && !changedSince(s.capture, afterCapture).some((file) => !isSpec(file))) return;
|
|
313
|
+
}
|
|
314
|
+
if (!['review', 'no-value'].includes(s.knowledge) && !s.owned.size && !s.opaque) return;
|
|
282
315
|
const after = gitSnapshot(s.root);
|
|
283
316
|
const comparable = s.before && after;
|
|
284
317
|
const observed = changedSince(s.before, after);
|
|
285
318
|
const owned = [...s.owned].filter(([file, hash]) => fingerprint(s.root, file) === hash && !isSpec(file)).map(([file]) => file);
|
|
286
319
|
const unattributed = observed.filter((file) => !s.owned.has(file) || fingerprint(s.root, file) !== s.owned.get(file));
|
|
287
|
-
|
|
320
|
+
const emptySpecs = s.knowledge === 'no-value' && resolveRelated('', s.root).available.length === 0;
|
|
321
|
+
if (s.knowledge === 'no-value' && !(emptySpecs && owned.length > 0)) return;
|
|
322
|
+
const candidate = s.knowledge === 'review';
|
|
323
|
+
if (!candidate && !owned.length && !unattributed.length && !(s.opaque && !comparable)) return;
|
|
288
324
|
const relevant = new Set();
|
|
289
325
|
for (const file of [...owned, ...unattributed].slice(0, 50)) {
|
|
290
326
|
const result = resolveRelated(file, s.root);
|
|
291
327
|
for (const spec of [...result.global, ...result.scoped, ...result.changes]) relevant.add(spec);
|
|
292
328
|
}
|
|
293
329
|
const content = `Charterleaf final review — once only; mode=${s.mode}.\n` +
|
|
330
|
+
(candidate ? 'The agent identified unresolved durable knowledge in this task; file changes are not required. Judge the conversation evidence, not the signal itself.\n' : '') +
|
|
331
|
+
(emptySpecs ? 'Development in an empty-spec project: verify the no-value conclusion against evidence of existing undocumented constraints, not just newly changed contracts.\n' : '') +
|
|
294
332
|
`Successful standard tool edits still unchanged at settlement: ${JSON.stringify(owned.slice(0, 50))}.\n` +
|
|
295
333
|
`Observed worktree changes NOT attributable to this agent: ${JSON.stringify(unattributed.slice(0, 50))}. ` +
|
|
296
334
|
'These may belong to the user or a parallel session; preserve them; do not modify specs based solely on them. Existing dirty content is not yours.\n' +
|
|
297
335
|
`Possibly affected specs (routing hints only): ${JSON.stringify([...relevant].slice(0, 50))}.\n` +
|
|
298
336
|
(!comparable ? 'Git change inspection unavailable (baseline or final snapshot missing). Opaque tool changes cannot be identified or attributed. Review only evidence in this conversation.\n' : '') +
|
|
299
|
-
'
|
|
300
|
-
'
|
|
337
|
+
'Consider newly established AND newly discovered knowledge, including read-only investigation or accepted decisions; no code change is required. In an empty-spec project, tests or accepted behavior that reveal a non-obvious invariant without effective code-path guidance is a discovery gap; do not dismiss it merely because tests pass or the implementation already works. ' +
|
|
338
|
+
'No justified durable knowledge means no spec edit; no code summary, task log or plans. ' +
|
|
339
|
+
'Record only evidenced, non-obvious contracts, invariants, boundaries, pitfalls or accepted decisions whose absence risks future mistakes and which are not effectively documented. ' +
|
|
340
|
+
'Current code alone is not an accepted contract. Prefer a short routed reference to an authoritative document over copying it; do not duplicate knowledge already captured in this task. ' +
|
|
341
|
+
'Honor explicit no-file-write/read-only instructions even in Auto; report only. ' +
|
|
301
342
|
'A code/spec conflict is not permission to rewrite the spec: distinguish implementation bug, obsolete spec and explicitly intended contract change. ' +
|
|
302
343
|
'If uncertain, preserve the spec and report the conflict. ' +
|
|
303
344
|
(s.mode === 'reference' ? 'Reference: report necessary proposals/conflicts only; never write specs. ' :
|
|
304
|
-
s.mode === 'confirm' ? 'Confirm:
|
|
345
|
+
s.mode === 'confirm' ? 'Confirm: invoke the exact spec write/edit to open the Extension approval dialog; the extension must obtain approval before execution. If already refused/no UI, report without retrying. ' :
|
|
305
346
|
'Auto: update only when durable knowledge is justified by this task; otherwise leave specs unchanged. ') +
|
|
306
347
|
'For unfamiliar authoring/staging details, read the guide. Use standard write/edit and lint. ' +
|
|
307
348
|
'Report task results/tests, not routine review bookkeeping; do not start another development cycle.';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onedotmint/charterleaf",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Lightweight Agent-Native Constraint Layer: opt-in spec discovery and maintenance for Pi, with a standalone zero-dependency CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,7 +38,9 @@
|
|
|
38
38
|
],
|
|
39
39
|
"scripts": {
|
|
40
40
|
"test": "node --test",
|
|
41
|
-
"test:pi": "node scripts/pi-smoke.js"
|
|
41
|
+
"test:pi": "node scripts/pi-smoke.js",
|
|
42
|
+
"test:organic": "node scripts/organic-smoke.js",
|
|
43
|
+
"test:context": "node scripts/context-smoke.js"
|
|
42
44
|
},
|
|
43
45
|
"pi": {
|
|
44
46
|
"extensions": [
|
|
@@ -14,14 +14,40 @@ Read this guide only for unfamiliar spec formats, staged changes or manual CLI u
|
|
|
14
14
|
|
|
15
15
|
Source owns implementation; tests own executable verification; `AGENTS.md` owns project entry/navigation; specs own durable constraints. Never copy signatures, inventories, current state or existing documentation into specs. Link the authoritative owner instead. Charterleaf is not task management, planning, memory, evidence, history or a project workflow.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Capture during ordinary development, debugging, code/test/architecture investigation or technical decisions; do not wait for settlement or require existing specs. An enabled project containing only `specs/.charterleaf.json` is a valid starting state, not a bootstrap request.
|
|
18
|
+
|
|
19
|
+
Distinguish **newly established knowledge** (an accepted new contract/decision) from **newly discovered knowledge** (an existing but ineffectively documented constraint). Either can qualify without code changes; neither obliges every task to produce a document. Apply all three checks:
|
|
20
|
+
|
|
21
|
+
1. Reliable evidence: accepted user intent, authoritative documentation, tests or sufficiently verified implementation behavior. Current code alone does not establish an accepted correct contract.
|
|
22
|
+
2. Long-term value: ignoring it could plausibly cause a future developer/Agent to make a wrong decision.
|
|
23
|
+
3. A documentation or discoverability gap: inspect relevant existing owners/specs before writing. If an authoritative document already covers it, add only a short scoped reference when routing is genuinely missing; otherwise do nothing. Never duplicate a captured rule. Executable tests provide evidence, not automatically effective code-path discovery: accepted non-obvious invariants scattered among tests may warrant a short scoped constraint/reference even when no new contract was established. Do not copy test cases or document trivial assertions; judge whether a future code change could miss the boundary.
|
|
24
|
+
|
|
25
|
+
Honor explicit no-file-write/read-only restrictions in every mode. Otherwise **code edits are allowed normally in all three modes**, including Reference and Confirm. Auto can create or update specs immediately when justified; Confirm uses the existing exact-spec-write approval; Reference only proposes spec changes, never restricts implementation edits. **In Confirm, invoke standard `write`/`edit` with the exact spec proposal to open the Extension's approval dialog; do not merely ask for prose permission and stop.** The call is an approval request, not an unauthorized mutation: the Extension pauses it before execution, denies it without UI, and only executes the exact operation if approved. If evidence conflicts, verify authority and distinguish a bug from an accepted change, never rewrite truth to match suspect code.
|
|
26
|
+
|
|
27
|
+
Place qualifying non-obvious knowledge in:
|
|
18
28
|
|
|
19
29
|
- `specs/constitution.md`: rare project-wide boundaries;
|
|
20
30
|
- `specs/capabilities/`: observable contracts, invariants and non-goals;
|
|
21
31
|
- `specs/engineering/`: long-lived implementation boundaries, recurring pitfalls and verification constraints;
|
|
22
32
|
- `specs/decisions/`: accepted rationale and revisit conditions.
|
|
23
33
|
|
|
24
|
-
Living capability/engineering specs need a unique `id` and non-empty `applies_to` list
|
|
34
|
+
Living capability/engineering specs need a unique `id` and non-empty `applies_to` list, including the first organically created spec. For example:
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
---
|
|
38
|
+
id: engineering.amounts
|
|
39
|
+
applies_to:
|
|
40
|
+
- src/amounts.js
|
|
41
|
+
- tests/amounts.test.js
|
|
42
|
+
---
|
|
43
|
+
# Amount boundary
|
|
44
|
+
|
|
45
|
+
Preserve the accepted rounding contract; see [accounting policy](../../docs/accounting.md#rounding) and its executable cases in `tests/amounts.test.js`.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Use this shape, not this example's rule, for the actual project evidence. Route rationale in `decisions/` through a relevant capability/engineering reference when automatic code-path discovery is needed. Keep scope narrow, preserve existing formats and requirement IDs, and verify explicit local references normally. `anchors` and `verified_by` are not required. Do not create speculative standards or code summaries to satisfy a final review. Task progress, implementation inventories, one-off debugging, temporary plans/todos and unverified behavior never belong in Specs.
|
|
49
|
+
|
|
50
|
+
The runtime's standalone assistant comments (outside code fences; exact terminal completion comments also work inline) `<!-- charterleaf: review -->`, `<!-- charterleaf: covered -->`, `<!-- charterleaf: no-value -->` and `<!-- charterleaf: proposed -->` are task-local lifecycle signals, not spec contents, evidence or permissions. `review` means a concrete evidenced candidate still needs knowledge judgment; `covered` means relevant authority is already effectively discoverable; `no-value` means the evidence/value/gap checks found no qualifying knowledge; `proposed` means a Reference/read-only proposal was reported or a Confirm proposal passed through the gate and was refused/no UI. Use these exact comments; put explanation outside, never inside them. If an explicit no-write task surfaced a qualified constraint, report the finding/proposal in the normal answer and finish the knowledge judgment there rather than requesting a continuation just to repeat it. Ordinary code/test completion is not any of those conclusions: a generic `done` comment is deliberately ignored. Never use `covered` merely because tests exercise a boundary without effective code-path discovery. In an enabled empty-spec project, do not reject a non-obvious accepted invariant merely because the tests already exercise it. Waiting for human approval is not unresolved knowledge judgment: do not request a semantic continuation just to ask the same permission again. After submitting an exact proposal to the approval gate, handle approval/refusal/no UI and finish normally. New distinct findings may rearm, but the Extension continues at most once. Successful structurally valid standard spec writes also mark capture complete; later code edits rearm the development fallback. In an empty-spec project, owned development after `no-value` still permits the single fallback to check for missed discovery gaps. Omitting a recognized conclusion can cause a redundant fallback even when the normal answer already states that nothing needs documenting. Plain reads, file counts, search results and task wording are not semantic discovery signals.
|
|
25
51
|
|
|
26
52
|
## Optional staged changes
|
|
27
53
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# Charterleaf runtime
|
|
2
2
|
|
|
3
|
-
Use
|
|
3
|
+
Use supplied specs; no bulk/unchanged rereads. Blocked write/edit: inspect constraints/read the complete spec, then retry; never bypass via another writer. Routing: a hint.
|
|
4
4
|
|
|
5
|
-
Modes govern specs, not code: Auto maintains
|
|
5
|
+
Modes govern specs, not code: Auto maintains justified knowledge; Confirm calls spec write/edit to open Extension approval (refusal/no UI: preserve, no retry); Reference proposes, never writes specs. All modes allow normal code edits. Use standard write/edit only. User-owned config. read-only/no-file-write requests override Auto. Not a filesystem sandbox.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Internal/refactor requests do not authorize changing return or ownership contracts. Conflicts: verify authority, fix bugs; never relax specs to match code. Invariant-breaking method? Preserve spec/tests; get an explicit contract decision before coding. Uncertain: preserve and report. Preserve user/parallel work; Git dirt/touched files aren't line ownership. No automatic revert/commit/push.
|
|
8
|
+
|
|
9
|
+
## Organic knowledge capture
|
|
10
|
+
|
|
11
|
+
During development/debugging/investigation/decisions capture newly established OR newly discovered knowledge, even without code changes/prior specs. Need reliable evidence (accepted decisions, authoritative docs, tests or verified behavior), mistake-prevention value and a documentation/discoverability gap. Code alone is not an accepted contract. Check owners; tests aren't automatic code-path routing; prefer short routed references over copying docs. New capability/engineering specs: unique id, narrow applies_to; see guide. No justified knowledge: no spec. No code summaries/progress/logs/plans/todos/speculation.
|
|
8
12
|
|
|
9
13
|
## One final semantic review
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
Judge during work, not by read counts. Use one exact comment: <!-- charterleaf: review --> (evidenced pending), <!-- charterleaf: covered --> (effective authority), <!-- charterleaf: no-value --> (no value), <!-- charterleaf: proposed --> (Reference/refused Confirm/read-only report). Reasons outside, never inside comments. NOT merely finishing code/tests. Signals aren't evidence/permission. At most one extra review; no loop. Report results/tests, not review logs. Lint is structural only.
|