vibe-coding-master 0.8.10 → 0.8.12
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/dist/backend/api/message-routes.js +4 -0
- package/dist/backend/cli/install-vcm-harness.js +5 -4
- package/dist/backend/server.js +3 -0
- package/dist/backend/services/code-intelligence-service.js +3 -1
- package/dist/backend/services/gate-review-service.js +53 -10
- package/dist/backend/services/harness-feedback-service.js +21 -11
- package/dist/backend/services/harness-service.js +12 -7
- package/dist/backend/services/lsp-plugin.js +39 -0
- package/dist/backend/services/message-service.js +20 -2
- package/dist/backend/services/runtime-coordinator-service.js +1 -1
- package/dist/backend/services/runtime-recovery-service.js +5 -3
- package/dist/backend/services/session-service.js +11 -3
- package/dist/backend/services/workflow-control-service.js +110 -17
- package/dist/backend/templates/harness/architect-agent.js +2 -2
- package/dist/backend/templates/harness/vcm-code-navigation-skill.js +1 -1
- package/dist/backend/templates/harness/vcm-propose-memory-skill.js +5 -0
- package/dist-frontend/assets/{index-uWFnvFv6.js → index-DqANomt1.js} +37 -37
- package/dist-frontend/index.html +1 -1
- package/package.json +1 -1
- package/scripts/harness-tools/run-long-check +25 -6
|
@@ -189,6 +189,9 @@ export function createWorkflowControlService(deps) {
|
|
|
189
189
|
await assertRouteAuthorized(input);
|
|
190
190
|
const state = await getState(input);
|
|
191
191
|
const pending = state.pendingDispatch;
|
|
192
|
+
const timestamp = now();
|
|
193
|
+
const progress = await readProgress(deps.fs, input);
|
|
194
|
+
const evidenceBaseline = await captureEvidenceBaseline(deps.fs, input, progress.history.length + 1, pending.effectiveFlow, pending.targetRole, timestamp);
|
|
192
195
|
await saveState(input, {
|
|
193
196
|
...state,
|
|
194
197
|
pendingDispatch: {
|
|
@@ -196,7 +199,8 @@ export function createWorkflowControlService(deps) {
|
|
|
196
199
|
status: "dispatching",
|
|
197
200
|
routeContentHash: input.routeContentHash,
|
|
198
201
|
messageId: input.messageId,
|
|
199
|
-
|
|
202
|
+
evidenceBaseline,
|
|
203
|
+
updatedAt: timestamp
|
|
200
204
|
},
|
|
201
205
|
updatedAt: now()
|
|
202
206
|
});
|
|
@@ -215,18 +219,37 @@ export function createWorkflowControlService(deps) {
|
|
|
215
219
|
status: "pending",
|
|
216
220
|
routeContentHash: undefined,
|
|
217
221
|
messageId: undefined,
|
|
222
|
+
confirmationError: undefined,
|
|
223
|
+
evidenceBaseline: undefined,
|
|
218
224
|
updatedAt: now()
|
|
219
225
|
},
|
|
220
226
|
updatedAt: now()
|
|
221
227
|
});
|
|
222
228
|
});
|
|
223
229
|
}
|
|
230
|
+
async function markDispatchUnconfirmed(input, messageId, reason) {
|
|
231
|
+
await withLock(statePath(input), async () => {
|
|
232
|
+
const state = await getState(input);
|
|
233
|
+
const pending = state.pendingDispatch;
|
|
234
|
+
if (!pending || pending.status !== "dispatching" || pending.messageId !== messageId)
|
|
235
|
+
return;
|
|
236
|
+
await saveState(input, {
|
|
237
|
+
...state,
|
|
238
|
+
pendingDispatch: { ...pending, confirmationError: reason, updatedAt: now() },
|
|
239
|
+
updatedAt: now()
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
}
|
|
224
243
|
async function cancelPendingDispatch(input) {
|
|
225
244
|
await withLock(statePath(input), async () => {
|
|
226
245
|
const state = await getState(input);
|
|
227
246
|
const pending = state.pendingDispatch;
|
|
228
247
|
if (!pending)
|
|
229
248
|
return;
|
|
249
|
+
if (pending.status === "dispatching" && !pending.confirmationError) {
|
|
250
|
+
throw workflowError("WORKFLOW_DISPATCH_PENDING", `Message ${pending.messageId} is being delivered and cannot be cleared before confirmation.`);
|
|
251
|
+
}
|
|
252
|
+
const timestamp = now();
|
|
230
253
|
const progress = await readProgress(deps.fs, input);
|
|
231
254
|
await commitStateAndProgress(input, renderWorkflowProgress({
|
|
232
255
|
...progress,
|
|
@@ -234,21 +257,26 @@ export function createWorkflowControlService(deps) {
|
|
|
234
257
|
}), {
|
|
235
258
|
...state,
|
|
236
259
|
pendingDispatch: null,
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
updatedAt: now()
|
|
260
|
+
...abandonPendingApprovals(state, pending, "Pending route was cleared before confirmation.", timestamp),
|
|
261
|
+
updatedAt: timestamp
|
|
240
262
|
});
|
|
241
263
|
});
|
|
242
264
|
}
|
|
243
|
-
async function confirmDispatch(input, messageId) {
|
|
265
|
+
async function confirmDispatch(input, messageId, source = "hook") {
|
|
244
266
|
await withLock(statePath(input), async () => {
|
|
245
267
|
const state = await getState(input);
|
|
246
|
-
failOnStateWarnings(
|
|
268
|
+
failOnStateWarnings({
|
|
269
|
+
...state,
|
|
270
|
+
warnings: state.warnings.filter((warning) => warning !== unconfirmedDispatchWarning(state.pendingDispatch))
|
|
271
|
+
});
|
|
247
272
|
failWhileAwaitingUser(state);
|
|
248
273
|
const pending = state.pendingDispatch;
|
|
249
274
|
if (!pending || pending.status !== "dispatching" || pending.messageId !== messageId) {
|
|
250
275
|
throw workflowError("WORKFLOW_DISPATCH_CONFIRMATION_MISMATCH", `Message ${messageId} does not own the pending workflow dispatch.`, "Do not advance Workflow Progress from an unrelated UserPromptSubmit event.");
|
|
251
276
|
}
|
|
277
|
+
if (source === "manual" && !pending.confirmationError) {
|
|
278
|
+
throw workflowError("WORKFLOW_DISPATCH_NOT_UNCONFIRMED", "Manual confirmation is only available for a delivered dispatch whose confirmation failed.");
|
|
279
|
+
}
|
|
252
280
|
const current = await readProgress(deps.fs, input);
|
|
253
281
|
if (current.revision !== pending.revision || historyHash(current.history) !== pending.baseHistoryHash) {
|
|
254
282
|
throw workflowError("WORKFLOW_APPROVAL_STALE", "Workflow Progress changed before the approved dispatch was confirmed.", "Repair workflow-progress.md before continuing.");
|
|
@@ -258,12 +286,14 @@ export function createWorkflowControlService(deps) {
|
|
|
258
286
|
sequence: current.history.length + 1,
|
|
259
287
|
flow: pending.effectiveFlow,
|
|
260
288
|
targetRole: pending.targetRole,
|
|
261
|
-
evidence:
|
|
289
|
+
evidence: source === "manual"
|
|
290
|
+
? `${pending.evidence} [User manually confirmed execution of message ${messageId}.]`
|
|
291
|
+
: pending.evidence,
|
|
262
292
|
overrideAuthorizationId: pending.overrideAuthorizationId,
|
|
263
293
|
followUpApprovalId: pending.followUpApprovalId,
|
|
264
294
|
confirmedAt: timestamp
|
|
265
295
|
};
|
|
266
|
-
const activeDispatch = await captureEvidenceBaseline(deps.fs, input, entry.sequence, entry.flow, entry.targetRole, timestamp);
|
|
296
|
+
const activeDispatch = pending.evidenceBaseline ?? await captureEvidenceBaseline(deps.fs, input, entry.sequence, entry.flow, entry.targetRole, timestamp);
|
|
267
297
|
const flowRun = await advanceFlowRun(deps.fs, input, state, current, pending.effectiveFlow, entry.sequence);
|
|
268
298
|
const completed = {
|
|
269
299
|
...current,
|
|
@@ -293,8 +323,24 @@ export function createWorkflowControlService(deps) {
|
|
|
293
323
|
return withLock(statePath(input), async () => {
|
|
294
324
|
await recoverCommitJournal(input);
|
|
295
325
|
const state = await getState(input);
|
|
296
|
-
if (state.
|
|
326
|
+
if (state.pendingDispatch?.status !== "dispatching"
|
|
327
|
+
|| state.warnings.some((warning) => warning !== unconfirmedDispatchWarning(state.pendingDispatch)))
|
|
297
328
|
return false;
|
|
329
|
+
if (await wasDispatchDelivered(deps.fs, input, state.pendingDispatch.messageId)) {
|
|
330
|
+
if (state.pendingDispatch.confirmationError)
|
|
331
|
+
return false;
|
|
332
|
+
const timestamp = now();
|
|
333
|
+
await saveState(input, {
|
|
334
|
+
...state,
|
|
335
|
+
pendingDispatch: {
|
|
336
|
+
...state.pendingDispatch,
|
|
337
|
+
confirmationError: "VCM restarted before the delivered message received UserPromptSubmit confirmation.",
|
|
338
|
+
updatedAt: timestamp
|
|
339
|
+
},
|
|
340
|
+
updatedAt: timestamp
|
|
341
|
+
});
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
298
344
|
await saveState(input, {
|
|
299
345
|
...state,
|
|
300
346
|
pendingDispatch: {
|
|
@@ -302,6 +348,8 @@ export function createWorkflowControlService(deps) {
|
|
|
302
348
|
status: "pending",
|
|
303
349
|
routeContentHash: undefined,
|
|
304
350
|
messageId: undefined,
|
|
351
|
+
confirmationError: undefined,
|
|
352
|
+
evidenceBaseline: undefined,
|
|
305
353
|
updatedAt: now()
|
|
306
354
|
},
|
|
307
355
|
updatedAt: now()
|
|
@@ -323,6 +371,7 @@ export function createWorkflowControlService(deps) {
|
|
|
323
371
|
assertRouteAuthorized,
|
|
324
372
|
claimDispatch,
|
|
325
373
|
releaseDispatch,
|
|
374
|
+
markDispatchUnconfirmed,
|
|
326
375
|
cancelPendingDispatch,
|
|
327
376
|
confirmDispatch,
|
|
328
377
|
recoverTask
|
|
@@ -361,10 +410,12 @@ export function createWorkflowControlService(deps) {
|
|
|
361
410
|
async function requestUserInput(input, question) {
|
|
362
411
|
return withLock(statePath(input), async () => {
|
|
363
412
|
const state = await getState(input);
|
|
364
|
-
failOnStateWarnings(state);
|
|
365
413
|
if (state.pendingDispatch?.status === "dispatching") {
|
|
366
|
-
throw workflowError("WORKFLOW_DISPATCH_PENDING",
|
|
414
|
+
throw workflowError("WORKFLOW_DISPATCH_PENDING", state.pendingDispatch.confirmationError
|
|
415
|
+
? `A delivered role dispatch is unconfirmed: ${state.pendingDispatch.confirmationError}`
|
|
416
|
+
: "A role dispatch is already being submitted and cannot be canceled by a user question.", "Inspect the target session and confirm or clear the pending dispatch before asking the user.");
|
|
367
417
|
}
|
|
418
|
+
failOnStateWarnings(state);
|
|
368
419
|
const normalizedQuestion = question.trim();
|
|
369
420
|
if (!normalizedQuestion) {
|
|
370
421
|
throw workflowError("WORKFLOW_USER_QUESTION_REQUIRED", "A non-empty user question is required.");
|
|
@@ -378,8 +429,7 @@ export function createWorkflowControlService(deps) {
|
|
|
378
429
|
requestedAt: timestamp
|
|
379
430
|
},
|
|
380
431
|
pendingDispatch: null,
|
|
381
|
-
|
|
382
|
-
userApprovedFollowUps: state.userApprovedFollowUps.filter((entry) => entry.id !== pending?.followUpApprovalId),
|
|
432
|
+
...(pending ? abandonPendingApprovals(state, pending, "PM asked the user before dispatch confirmation.", timestamp) : {}),
|
|
383
433
|
updatedAt: timestamp
|
|
384
434
|
};
|
|
385
435
|
if (pending) {
|
|
@@ -1226,6 +1276,9 @@ function validateCandidateAgainstCurrent(current, candidate) {
|
|
|
1226
1276
|
function stateProgressConsistencyWarnings(state, progress) {
|
|
1227
1277
|
const warnings = [];
|
|
1228
1278
|
const pending = state.pendingDispatch;
|
|
1279
|
+
const unconfirmedWarning = unconfirmedDispatchWarning(pending);
|
|
1280
|
+
if (unconfirmedWarning)
|
|
1281
|
+
warnings.push(unconfirmedWarning);
|
|
1229
1282
|
if (!pending && progress.proposal) {
|
|
1230
1283
|
warnings.push("Workflow Progress contains a dispatch proposal without a runtime approval.");
|
|
1231
1284
|
}
|
|
@@ -1248,6 +1301,40 @@ function stateProgressConsistencyWarnings(state, progress) {
|
|
|
1248
1301
|
}
|
|
1249
1302
|
return warnings;
|
|
1250
1303
|
}
|
|
1304
|
+
function unconfirmedDispatchWarning(pending) {
|
|
1305
|
+
return pending?.confirmationError
|
|
1306
|
+
? `PM dispatch ${pending.messageId ?? "unknown"} to ${pending.targetRole} was delivered but not confirmed: ${pending.confirmationError} Inspect the target session and use Confirm Executed if it already ran; do not resend executed work.`
|
|
1307
|
+
: undefined;
|
|
1308
|
+
}
|
|
1309
|
+
function abandonPendingApprovals(state, pending, reason, timestamp) {
|
|
1310
|
+
return {
|
|
1311
|
+
userAuthorizations: state.userAuthorizations.map((entry) => entry.id === pending.overrideAuthorizationId
|
|
1312
|
+
? { ...entry, status: "abandoned", abandonedAt: timestamp, abandonReason: reason }
|
|
1313
|
+
: entry),
|
|
1314
|
+
userApprovedFollowUps: state.userApprovedFollowUps.map((entry) => entry.id === pending.followUpApprovalId
|
|
1315
|
+
? { ...entry, status: "abandoned", abandonedAt: timestamp, abandonReason: reason }
|
|
1316
|
+
: entry)
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
async function wasDispatchDelivered(fs, input, messageId) {
|
|
1320
|
+
if (!messageId)
|
|
1321
|
+
return false;
|
|
1322
|
+
const messagesPath = path.join(input.taskRepoRoot, input.stateRoot, "messages", `${input.taskSlug}.jsonl`);
|
|
1323
|
+
if (!(await fs.pathExists(messagesPath)))
|
|
1324
|
+
return false;
|
|
1325
|
+
try {
|
|
1326
|
+
let latest;
|
|
1327
|
+
for (const line of (await fs.readText(messagesPath)).split(/\r?\n/).filter(Boolean)) {
|
|
1328
|
+
const message = JSON.parse(line);
|
|
1329
|
+
if (message.id === messageId)
|
|
1330
|
+
latest = message;
|
|
1331
|
+
}
|
|
1332
|
+
return Boolean(latest?.deliveredAt);
|
|
1333
|
+
}
|
|
1334
|
+
catch {
|
|
1335
|
+
return true;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1251
1338
|
function createUserAuthorization(authorizationId, current, candidate, effectiveFlow, baseHistoryHash, violation, authorizationText, timestamp) {
|
|
1252
1339
|
return {
|
|
1253
1340
|
id: authorizationId,
|
|
@@ -1492,6 +1579,8 @@ function isPendingDispatch(value) {
|
|
|
1492
1579
|
&& (value.status === "pending" || value.status === "dispatching")
|
|
1493
1580
|
&& (value.routeContentHash === undefined || typeof value.routeContentHash === "string")
|
|
1494
1581
|
&& (value.messageId === undefined || typeof value.messageId === "string")
|
|
1582
|
+
&& (value.confirmationError === undefined || typeof value.confirmationError === "string")
|
|
1583
|
+
&& (value.evidenceBaseline === undefined || Boolean(normalizeDispatchEvidenceBaseline(value.evidenceBaseline)))
|
|
1495
1584
|
&& typeof value.createdAt === "string"
|
|
1496
1585
|
&& typeof value.updatedAt === "string";
|
|
1497
1586
|
}
|
|
@@ -1499,7 +1588,7 @@ function isUserAuthorization(value) {
|
|
|
1499
1588
|
if (!isRecord(value))
|
|
1500
1589
|
return false;
|
|
1501
1590
|
return typeof value.id === "string"
|
|
1502
|
-
&& (value.status === "accepted" || value.status === "consumed")
|
|
1591
|
+
&& (value.status === "accepted" || value.status === "consumed" || value.status === "abandoned")
|
|
1503
1592
|
&& value.role === "project-manager"
|
|
1504
1593
|
&& value.operation === "workflow-dispatch"
|
|
1505
1594
|
&& Number.isInteger(value.baseRevision)
|
|
@@ -1511,13 +1600,15 @@ function isUserAuthorization(value) {
|
|
|
1511
1600
|
&& typeof value.violatedRule === "string"
|
|
1512
1601
|
&& typeof value.authorizationText === "string"
|
|
1513
1602
|
&& typeof value.createdAt === "string"
|
|
1514
|
-
&& (value.consumedAt === undefined || typeof value.consumedAt === "string")
|
|
1603
|
+
&& (value.consumedAt === undefined || typeof value.consumedAt === "string")
|
|
1604
|
+
&& (value.abandonedAt === undefined || typeof value.abandonedAt === "string")
|
|
1605
|
+
&& (value.abandonReason === undefined || typeof value.abandonReason === "string");
|
|
1515
1606
|
}
|
|
1516
1607
|
function isUserApprovedFollowUp(value) {
|
|
1517
1608
|
if (!isRecord(value))
|
|
1518
1609
|
return false;
|
|
1519
1610
|
return typeof value.id === "string"
|
|
1520
|
-
&& (value.status === "accepted" || value.status === "consumed")
|
|
1611
|
+
&& (value.status === "accepted" || value.status === "consumed" || value.status === "abandoned")
|
|
1521
1612
|
&& value.role === "project-manager"
|
|
1522
1613
|
&& value.operation === "post-validation-follow-up"
|
|
1523
1614
|
&& Number.isInteger(value.baseRevision)
|
|
@@ -1529,7 +1620,9 @@ function isUserApprovedFollowUp(value) {
|
|
|
1529
1620
|
&& typeof value.evidence === "string"
|
|
1530
1621
|
&& typeof value.approvalText === "string"
|
|
1531
1622
|
&& typeof value.createdAt === "string"
|
|
1532
|
-
&& (value.consumedAt === undefined || typeof value.consumedAt === "string")
|
|
1623
|
+
&& (value.consumedAt === undefined || typeof value.consumedAt === "string")
|
|
1624
|
+
&& (value.abandonedAt === undefined || typeof value.abandonedAt === "string")
|
|
1625
|
+
&& (value.abandonReason === undefined || typeof value.abandonReason === "string");
|
|
1533
1626
|
}
|
|
1534
1627
|
function normalizeDispatchEvidenceBaseline(value) {
|
|
1535
1628
|
if (!isRecord(value) || !isRecord(value.artifactHashes) || !isRecord(value.gateFingerprints))
|
|
@@ -22,7 +22,7 @@ ${renderRoleMemoryRules("architect")}
|
|
|
22
22
|
### Semantic Code Navigation
|
|
23
23
|
|
|
24
24
|
- Follow the preloaded \`vcm-code-navigation\` skill whenever work requires code definitions, implementations, references, callers, callees, or behavior paths. This applies in every Architect mode and in direct user communication.
|
|
25
|
-
- LSP is mandatory
|
|
25
|
+
- LSP is mandatory for navigating project source code. Start source-code navigation with a registered LSP server. If a required language server is unavailable, stop the affected work and report its language, command, error, and installation hint through the current communication channel. Resume after the environment is fixed and Architect is restarted; do not substitute source text search.
|
|
26
26
|
- Use LSP definitions, implementations, references, document or workspace symbols, and incoming or outgoing calls for all source-code symbol and relationship queries.
|
|
27
27
|
- LSP reference results are symbol-specific. An accessor, its backing field, a trait declaration, its implementation method, a wrapper, and an alias are separate symbols. Query every relevant symbol separately; one symbol's reference result cannot prove a complete semantic class. When starting from an accessor or wrapper, read its implementation, resolve its backing field, delegate, or trait item with LSP, then query those symbols too.
|
|
28
28
|
- Do not use the built-in \`Grep\` tool or shell text-search commands such as \`grep\`, \`rg\`, \`git grep\`, \`ag\`, or \`ack\` to search project source code, test code, or executable scripts, except for the bounded fallback below. This prohibition includes locating or inferring definitions, implementations, references, callers, callees, symbols, and behavior paths.
|
|
@@ -141,7 +141,7 @@ ${renderRoleMemoryRules("architect")}
|
|
|
141
141
|
#### Code Scaffolding
|
|
142
142
|
|
|
143
143
|
- Use the Agent tool to invoke \`vcm-architect-scaffold-worker\` in the foreground after the plan and Scaffold Manifest are complete. Give it the exact plan path and require it to return before this Architect turn continues.
|
|
144
|
-
-
|
|
144
|
+
- Run at most one scaffold worker at a time. Do not run it in the background or end the Architect turn while it is active. If its report leaves scaffold items unfinished, verify the completed work and invoke another foreground scaffold worker with the previous report and exact remaining items. Continue until every item is complete or report the concrete failure to project-manager.
|
|
145
145
|
- Review the worker commit, actual diff, callable surfaces, marker placement, ledger reconciliation, and L0 results yourself. Architect owns every final scaffold claim and must correct any worker error before marking planning complete.
|
|
146
146
|
- Create or update only the minimum module/file scaffolding needed to make boundaries, callable surfaces, and placeholders unambiguous. Minimum limits depth (no business implementation), never breadth: every \`create\`, \`change\`, and \`delete\` item must be scaffolded.
|
|
147
147
|
- When a required configuration, package manifest, or build-definition change cannot safely contain a \`VCM:CODE\` marker, complete and commit it directly as Architect-owned scaffold work. Record it in the Module/File Plan and Scaffold Build Evidence. Do not add it to the Scaffold Manifest.
|
|
@@ -6,7 +6,7 @@ Use this skill when Architect must establish symbol definitions, implementations
|
|
|
6
6
|
## Navigation Order
|
|
7
7
|
|
|
8
8
|
1. Define the affected feature or module boundary and locate entry symbols with \`.ai/generated/module-index.json\` and \`.ai/generated/public-surface.json\` when available.
|
|
9
|
-
2. Use LSP workspace or file symbols, definitions, implementations, references, and incoming or outgoing call hierarchy to resolve project-owned relationships. If
|
|
9
|
+
2. Use LSP workspace or file symbols, definitions, implementations, references, and incoming or outgoing call hierarchy to resolve project-owned relationships. If a required language server is unavailable, stop the affected work and report its language, command, error, and installation hint through the current communication channel. Resume after the environment is fixed and Architect is restarted; do not substitute text search.
|
|
10
10
|
3. Treat LSP results as symbol-specific. An accessor, backing field, trait declaration, implementation method, wrapper, and alias are separate symbols. Query every relevant symbol separately. When starting from an accessor or wrapper, read its implementation, resolve the backing field, delegate, or trait item with LSP, then query those symbols too. Never use one symbol's references as proof of a complete semantic class.
|
|
11
11
|
4. If an initial workspace-symbol request is empty or reports indexing, wait and retry; startup or indexing time does not permit replacing a required semantic query with text matching. Retry the same bounded workspace query at most two more times. If it still cannot resolve, record the operation and result as unresolved.
|
|
12
12
|
5. Read the complete project-owned callable unit at every resolved location.
|
|
@@ -12,6 +12,11 @@ planning-session memory candidate and provides an exact path.
|
|
|
12
12
|
- If VCM did not provide a path, do not create a proposal.
|
|
13
13
|
- Propose only verified, durable, reusable project knowledge supported by task
|
|
14
14
|
evidence.
|
|
15
|
+
- Before proposing an add or update, check current durable documents, Harness
|
|
16
|
+
rules and skills, and the tool's help, usage, or error output. Cite the checked
|
|
17
|
+
source in Evidence. Do not duplicate existing knowledge in memory; propose
|
|
18
|
+
\`durable-doc\` only when the existing document is wrong or incomplete, or use
|
|
19
|
+
\`memory-reference\` when roles need a short pointer across tasks.
|
|
15
20
|
- Target shared project knowledge to \`shared\`. Target knowledge used only by
|
|
16
21
|
the current role to \`current-role\`.
|
|
17
22
|
- For every add or update, explain why the memory is necessary, what future
|