thoth-agents 0.1.18 → 0.1.19
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/README.md +14 -3
- package/dist/{chunk-6K3ZXIMC.js → chunk-2SGSRR6L.js} +27 -26
- package/dist/{chunk-SOT5ZY53.js → chunk-7CTSLCEU.js} +44 -47
- package/dist/cli/index.js +2 -2
- package/dist/cli/tui/index.js +2 -2
- package/dist/harness/core/memory-governance.d.ts +39 -4
- package/dist/hooks/phase-reminder/index.d.ts +2 -0
- package/dist/hooks/thoth-mem/protocol.d.ts +2 -2
- package/dist/index.js +58 -44
- package/package.json +1 -1
- package/src/skills/_shared/persistence-contract.md +18 -14
- package/src/skills/_shared/thoth-mem-convention.md +18 -18
- package/src/skills/executing-plans/SKILL.md +6 -4
- package/src/skills/plan-reviewer/SKILL.md +4 -2
- package/src/skills/thoth-mem-agents/SKILL.md +3 -0
package/README.md
CHANGED
|
@@ -301,9 +301,20 @@ Artifacts can be persisted in four modes:
|
|
|
301
301
|
Thoth-mem is the local memory MCP used for durable observations, architectural
|
|
302
302
|
decisions, SDD artifacts, and session summaries. The core retrieval pattern is:
|
|
303
303
|
|
|
304
|
-
1. `
|
|
305
|
-
2. `
|
|
306
|
-
3. `
|
|
304
|
+
1. `mem_recall(mode="compact")` for compact candidate records
|
|
305
|
+
2. `mem_recall(mode="context")` for expanded retrieved context
|
|
306
|
+
3. `mem_get(...)` for the full selected record; use
|
|
307
|
+
`mem_get(include_timeline=true)` when chronology matters
|
|
308
|
+
|
|
309
|
+
Use HyDE/fused hybrid recall (sentence + chunk vectors, FTS, KG enrichment) for
|
|
310
|
+
semantic or ambiguous searches; set `mem_recall` `limit` from 1 to 20; narrow
|
|
311
|
+
with `topic_key`, `type`, `time_from`, `time_to`, `scope`, `project`, and
|
|
312
|
+
`session_id` filters. Use `mem_get` with `kind="observation"|"prompt"`,
|
|
313
|
+
`include_timeline=true` plus `before`/`after`, and `offset`/`max_length` for
|
|
314
|
+
large content. Use bounded `mem_context(recall_query=...)` or
|
|
315
|
+
`mem_project(action="graph"|"topics"|"topic")` for supplemental project
|
|
316
|
+
context; `mem_project(action="graph")` relations are `HAS_TYPE`, `IN_PROJECT`,
|
|
317
|
+
`HAS_TOPIC_KEY`, `HAS_WHAT`, `HAS_WHY`, `HAS_WHERE`, and `HAS_LEARNED`.
|
|
307
318
|
|
|
308
319
|
## Skills And MCPs
|
|
309
320
|
|
|
@@ -1098,9 +1098,9 @@ Push back when context, risk, or assumptions are weak. Avoid verbosity.
|
|
|
1098
1098
|
</epistemic-rigor>
|
|
1099
1099
|
|
|
1100
1100
|
<session-bootstrap>
|
|
1101
|
-
- At the start of a new root session, when thoth-mem tools are available, load \`thoth-mem-agents\` and \`requirements-interview\`, call \`
|
|
1102
|
-
- Save only the real user request with \`
|
|
1103
|
-
- If thoth-mem tools or required session/project identity are unavailable, disclose that memory bootstrap could not run and continue without
|
|
1101
|
+
- At the start of a new root session, when thoth-mem tools and session/project identity are available, load \`thoth-mem-agents\` and \`requirements-interview\`, then call \`mem_session(action="start")\` as step 0 before any other thoth-mem call.
|
|
1102
|
+
- Save only the real user request with \`mem_save(kind="prompt")\`; never save generated sub-agent prompts, handoffs, summaries, or tool scaffolding as user intent.
|
|
1103
|
+
- If thoth-mem tools or required session/project identity are unavailable, disclose that memory bootstrap could not run and continue without claiming memory was saved.
|
|
1104
1104
|
</session-bootstrap>
|
|
1105
1105
|
|
|
1106
1106
|
<routing>
|
|
@@ -1136,9 +1136,9 @@ Before dispatching {{role.designer}}, {{role.quick}}, or {{role.deep}} after dis
|
|
|
1136
1136
|
|
|
1137
1137
|
Internal handoff fields: Goal, Decision, Evidence, Scope, Steps, Verification, Uncertainty, relevant files or symbols, suggested skills when applicable, constraints, non-goals, escalation conditions, and next focus.
|
|
1138
1138
|
|
|
1139
|
-
When thoth-mem
|
|
1139
|
+
When thoth-mem summary persistence and parent session/project identity are available, save or refresh that handoff body with root-owned \`mem_session(action="summary")\` or \`mem_save(kind="session_summary")\` before dispatch. If tooling or identity is unavailable, disclose that root-owned compaction could not be persisted and continue with explicit task instructions and local context; do not invent a fallback session or ask a sub-agent to create one.
|
|
1140
1140
|
|
|
1141
|
-
The delegated prompt carries task instructions plus handoff recovery instructions only: parent \`session_id\`, project, persistence mode, memory permissions, bounded
|
|
1141
|
+
The delegated prompt carries task instructions plus handoff recovery instructions only: parent \`session_id\`, project, persistence mode, memory permissions, the recall funnel \`mem_recall(mode="compact")\` -> \`mem_recall(mode="context")\` -> \`mem_get(...)\`, optional bounded \`mem_context(recall_query=...)\`/\`mem_project(...)\` guidance when permitted, non-goals, escalation conditions, and redaction requirements. It must not include the handoff body, raw transcripts, file dumps, secrets, credentials, irrelevant context, or generated sub-agent prompts as memory source material.
|
|
1142
1142
|
|
|
1143
1143
|
Never mention internal handoff preparation to the user, ask the user to prepare it, or present handoff preparation as the recommended next step. Describe the actual work instead.
|
|
1144
1144
|
|
|
@@ -1199,12 +1199,15 @@ Post-execution: delegate sdd-verify, then sdd-archive when verification passes.
|
|
|
1199
1199
|
<progress-memory>
|
|
1200
1200
|
- Keep {{progressTool}} top-level and lean for multi-step work.
|
|
1201
1201
|
- When SDD is active, update both {{progressTool}} and openspec/changes/{change-name}/tasks.md before dispatch and after results.
|
|
1202
|
-
- Root-session memory is yours:
|
|
1203
|
-
-
|
|
1204
|
-
- Targeted
|
|
1202
|
+
- Root-session memory is yours: recall repeated work; save durable decisions, discoveries, bugs, patterns, constraints, summaries.
|
|
1203
|
+
- Use \`mem_save(kind="observation")\` for decisions, bugs, discoveries, conventions, preferences; stable topics; observations outside \`sdd/*\`.
|
|
1204
|
+
- Targeted recall funnel: \`mem_recall(mode="compact")\` -> \`mem_recall(mode="context")\` -> \`mem_get(...)\`; use \`mem_get(include_timeline=true)\` for time context.
|
|
1205
|
+
- Use HyDE/fused recall; set \`mem_recall\` \`limit\` from 1 to 20; narrow with \`topic_key\`, \`type\`, \`time_from\`/\`time_to\`, \`scope\`, \`project\`, \`session_id\`.
|
|
1206
|
+
- \`mem_get\`: \`kind="observation"|"prompt"\`, \`include_timeline=true\`, \`before\`/\`after\`, \`offset\`/\`max_length\`; supplement with bounded \`mem_context(recall_query=...)\` or \`mem_project(action="graph"|"topics"|"topic")\`.
|
|
1207
|
+
- Graph relations: HAS_TYPE, IN_PROJECT, HAS_TOPIC_KEY, HAS_WHAT, HAS_WHY, HAS_WHERE, HAS_LEARNED.
|
|
1205
1208
|
- SDD memory artifacts use deterministic topic keys only in thoth-mem or hybrid persistence modes: \`sdd/{change}/{artifact}\`.
|
|
1206
|
-
- Before ending the root session, call \`
|
|
1207
|
-
- After compaction, first preserve the compacted summary with \`
|
|
1209
|
+
- Before ending the root session, call \`mem_session(action="summary")\` or root-owned \`mem_save(kind="session_summary")\` with a concise Goal, Instructions, Discoveries, Accomplished, Next Steps, and Relevant Files summary. Do not claim memory was saved unless the tool call succeeded.
|
|
1210
|
+
- After compaction, first preserve the compacted summary with \`mem_session(action="summary")\`, then call \`mem_context(recall_query=...)\` and use the recall funnel before continuing work.
|
|
1208
1211
|
</progress-memory>
|
|
1209
1212
|
|
|
1210
1213
|
<communication>
|
|
@@ -1376,32 +1379,30 @@ function renderSubagentRules(section, dialect) {
|
|
|
1376
1379
|
];
|
|
1377
1380
|
if (section.memoryAccess === "readonly") {
|
|
1378
1381
|
rules.push(
|
|
1379
|
-
"- Use read-only thoth-mem only when dispatch gives parent session_id/project and handoff recovery instructions
|
|
1380
|
-
"-
|
|
1381
|
-
"- If either parent session_id or project is missing, do NOT call thoth-mem; rely on
|
|
1382
|
-
|
|
1382
|
+
"- Use read-only thoth-mem only when dispatch gives parent session_id/project and handoff recovery instructions.",
|
|
1383
|
+
"- Parent-scoped reads: `mem_recall`, `mem_context`, `mem_get`, bounded `mem_project`; do not call `mem_save` or own any `mem_session(...)` lifecycle action.",
|
|
1384
|
+
"- If either parent session_id or project is missing, do NOT call thoth-mem; rely on task instructions and local evidence.",
|
|
1385
|
+
'- Recover the parent-session handoff summary through the recall funnel `mem_recall(mode="compact")` -> `mem_recall(mode="context")` -> `mem_get(...)` before using memory.',
|
|
1386
|
+
'- Use `mem_recall` `limit` from 1 to 20; use `mem_get` with `kind="observation"|"prompt"`, `include_timeline=true`, `before`/`after`, and `offset`/`max_length`.',
|
|
1383
1387
|
"- Report when recalled context is missing, stale, contradictory, or insufficient.",
|
|
1384
|
-
|
|
1385
|
-
"- Never
|
|
1386
|
-
"- Never save generated subagent prompts as user intent.",
|
|
1387
|
-
"- Never write memory; memory writes are orchestrator-owned."
|
|
1388
|
+
'- Supplemental `mem_context(recall_query=...)` and bounded `mem_project(action="graph"|"topics"|"topic")` do not replace the recall funnel and require explicit delegated permission. Graph relations: `HAS_TYPE`, `IN_PROJECT`, `HAS_TOPIC_KEY`, `HAS_WHAT`, `HAS_WHY`, `HAS_WHERE`, `HAS_LEARNED`.',
|
|
1389
|
+
"- Never save prompts, generated subagent prompts, session summaries, or durable memory."
|
|
1388
1390
|
);
|
|
1389
1391
|
}
|
|
1390
1392
|
if (section.memoryAccess === "writable") {
|
|
1391
1393
|
rules.push(
|
|
1392
|
-
"- Use delegated thoth-mem tools only
|
|
1393
|
-
"- Never call `mem_session_start`, `mem_session_summary`, or `mem_save_prompt`; those tools are orchestrator-owned.",
|
|
1394
|
+
"- Use delegated thoth-mem tools only: `mem_save`, `mem_recall`, `mem_context`, `mem_get`, `mem_project`, `mem_session`.",
|
|
1394
1395
|
"- Always use the parent session_id/project from dispatch for every thoth-mem call.",
|
|
1395
1396
|
"- If either is missing, do NOT call thoth-mem.",
|
|
1396
1397
|
"- Follow handoff recovery instructions from the delegated task before using persisted memory.",
|
|
1397
|
-
|
|
1398
|
-
|
|
1398
|
+
'- For reads, use the recall funnel `mem_recall(mode="compact")` -> `mem_recall(mode="context")` -> `mem_get(...)` and recover the parent-session handoff summary before treating memory as source material.',
|
|
1399
|
+
'- Use `mem_recall` `limit` from 1 to 20; use `mem_get` with `kind="observation"|"prompt"`, `include_timeline=true`, `before`/`after`, and `offset`/`max_length`.',
|
|
1400
|
+
'- Keep the recall funnel canonical; use `mem_context(recall_query=...)` and bounded `mem_project(action="graph"|"topics"|"topic")` only with explicit project-read permission. Graph relations: `HAS_TYPE`, `IN_PROJECT`, `HAS_TOPIC_KEY`, `HAS_WHAT`, `HAS_WHY`, `HAS_WHERE`, `HAS_LEARNED`.',
|
|
1399
1401
|
"- Report when recalled context is missing, stale, contradictory, or insufficient.",
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
+
'- `mem_save(kind="observation")` is allowed only for delegated durable implementation observations or assigned deterministic SDD artifacts/apply-progress under the parent session/project.',
|
|
1403
|
+
'- Never own `mem_session(action="start"|"checkpoint"|"summary")`, save prompts, or save generated subagent prompts as user intent.',
|
|
1402
1404
|
"- Protect the `sdd/*` namespace: deterministic SDD artifacts use `sdd/{change}/{artifact}`; general durable observations must stay outside `sdd/*`.",
|
|
1403
|
-
|
|
1404
|
-
"- You do not own durable memory of your own; `mem_save` writes under the orchestrator's session/project only."
|
|
1405
|
+
'- You do not own durable memory of your own; permitted `mem_save(kind="observation")` writes under the orchestrator\'s session/project only.'
|
|
1405
1406
|
);
|
|
1406
1407
|
}
|
|
1407
1408
|
return rules.join("\n");
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
renderRolePrompt,
|
|
32
32
|
writeConfig,
|
|
33
33
|
writeLiteConfig
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-2SGSRR6L.js";
|
|
35
35
|
|
|
36
36
|
// src/harness/adapters/codex.ts
|
|
37
37
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
@@ -172,96 +172,91 @@ function getAgentPackContract() {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
// src/harness/core/memory-governance.ts
|
|
175
|
-
var
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
175
|
+
var ROOT_OWNED_OPERATIONS = [
|
|
176
|
+
{ tool: "mem_session", action: "start" },
|
|
177
|
+
{ tool: "mem_session", action: "checkpoint" },
|
|
178
|
+
{ tool: "mem_session", action: "summary" },
|
|
179
|
+
{ tool: "mem_save", kind: "prompt" },
|
|
180
|
+
{ tool: "mem_save", kind: "session_summary" }
|
|
179
181
|
];
|
|
180
|
-
var
|
|
181
|
-
"
|
|
182
|
-
"mem_timeline",
|
|
183
|
-
"mem_get_observation"
|
|
184
|
-
];
|
|
185
|
-
var BOUNDED_CONTEXT_TOOLS = [
|
|
182
|
+
var PARENT_SCOPED_READ_TOOLS = [
|
|
183
|
+
"mem_recall",
|
|
186
184
|
"mem_context",
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
"mem_topic_keys"
|
|
185
|
+
"mem_get",
|
|
186
|
+
"mem_project"
|
|
190
187
|
];
|
|
191
188
|
var WRITE_CAPABLE_DELEGATED_TOOLS = [
|
|
192
|
-
|
|
193
|
-
"
|
|
194
|
-
"mem_get_observation",
|
|
195
|
-
"mem_timeline",
|
|
196
|
-
...BOUNDED_CONTEXT_TOOLS,
|
|
197
|
-
"mem_suggest_topic_key"
|
|
189
|
+
...PARENT_SCOPED_READ_TOOLS,
|
|
190
|
+
"mem_save"
|
|
198
191
|
];
|
|
199
192
|
var ALL_MEMORY_TOOLS = [
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
"
|
|
204
|
-
"
|
|
193
|
+
"mem_save",
|
|
194
|
+
"mem_recall",
|
|
195
|
+
"mem_context",
|
|
196
|
+
"mem_get",
|
|
197
|
+
"mem_project",
|
|
198
|
+
"mem_session"
|
|
205
199
|
];
|
|
206
200
|
function uniqueTools(tools) {
|
|
207
201
|
return [...new Set(tools)];
|
|
208
202
|
}
|
|
209
203
|
function roleAllowedTools(role) {
|
|
210
204
|
if (role.name === "orchestrator") {
|
|
211
|
-
return
|
|
205
|
+
return [...ALL_MEMORY_TOOLS];
|
|
212
206
|
}
|
|
213
207
|
if (role.mode === "read-only") {
|
|
214
|
-
return [...
|
|
208
|
+
return [...PARENT_SCOPED_READ_TOOLS];
|
|
215
209
|
}
|
|
216
|
-
return [...WRITE_CAPABLE_DELEGATED_TOOLS];
|
|
210
|
+
return uniqueTools([...WRITE_CAPABLE_DELEGATED_TOOLS]);
|
|
217
211
|
}
|
|
218
212
|
function roleRules(role) {
|
|
219
213
|
const sharedSubagentRules = [
|
|
220
214
|
"Every subagent memory call requires the parent session_id and project from dispatch; if either is missing, do not call thoth-mem.",
|
|
221
|
-
|
|
215
|
+
'Delegated handoff recovery uses the parent-scoped recall funnel: mem_recall(mode="compact") -> mem_recall(mode="context") -> mem_get(...) before memory content is treated as source material.',
|
|
216
|
+
"Use mem_get(include_timeline=true) when chronology around a recovered record matters.",
|
|
217
|
+
'mem_context(recall_query=...) and bounded mem_project(action="graph"|"topics"|"topic") are supplemental project context only and do not replace the recall funnel.',
|
|
222
218
|
"Report missing, stale, contradictory, or insufficient recalled context instead of guessing through it.",
|
|
223
|
-
|
|
219
|
+
'Never own mem_session(action="start"|"checkpoint"|"summary") or mem_save(kind="prompt"|"session_summary"); those operations are root/orchestrator-owned.',
|
|
224
220
|
"Never save generated subagent prompts as user intent.",
|
|
225
221
|
"Protect the sdd/* topic namespace; SDD artifacts may use deterministic sdd/{change}/{artifact} topic keys only in persistence modes that include thoth-mem."
|
|
226
222
|
];
|
|
227
223
|
if (role.name === "orchestrator") {
|
|
228
224
|
return [
|
|
229
|
-
"
|
|
225
|
+
'mem_session(action="start"|"checkpoint"|"summary"), mem_save(kind="prompt"), and mem_save(kind="session_summary") are root/main orchestrator-owned operations and responsibilities.',
|
|
230
226
|
"In harnesses without an orchestrator-named agent, root/main orchestrator-owned means the initial/root agent when the harness does not expose an orchestrator-named agent.",
|
|
231
|
-
|
|
227
|
+
'Before delegation, save or refresh the handoff body with root-owned mem_session(action="summary") or mem_save(kind="session_summary") when available; otherwise disclose that compaction could not be persisted.',
|
|
232
228
|
"Dispatch task instructions plus recovery instructions, not the handoff body, raw transcripts, or generated subagent prompts.",
|
|
233
229
|
"Dispatch parent session_id and project when authorizing subagent memory use.",
|
|
230
|
+
'Root recall uses mem_recall(mode="compact") -> mem_recall(mode="context") -> mem_get(...); use mem_context(recall_query=...) and bounded mem_project(action="graph"|"topics"|"topic") for supplemental context.',
|
|
234
231
|
"Protect the sdd/* topic namespace and write SDD memory artifacts only in thoth-mem or hybrid persistence modes."
|
|
235
232
|
];
|
|
236
233
|
}
|
|
237
234
|
if (role.mode === "read-only") {
|
|
238
235
|
return [
|
|
239
236
|
...sharedSubagentRules,
|
|
240
|
-
"Read-only agents may only
|
|
241
|
-
"
|
|
242
|
-
"
|
|
243
|
-
"Read-only agents must never write durable memory."
|
|
237
|
+
"Read-only agents may use only parent-scoped mem_recall, mem_context, mem_get, and bounded mem_project reads when authorized.",
|
|
238
|
+
"Project-scoped read tools require explicit delegated permission and must stay bounded to the parent session/project scope.",
|
|
239
|
+
"Read-only agents must never write durable memory or save prompts."
|
|
244
240
|
];
|
|
245
241
|
}
|
|
246
242
|
return [
|
|
247
243
|
...sharedSubagentRules,
|
|
248
|
-
"Write-capable agents may
|
|
249
|
-
"
|
|
250
|
-
"
|
|
251
|
-
"Project-scoped read tools require explicit delegated permission."
|
|
244
|
+
"Write-capable agents may use the same parent-scoped reads as read-only agents when authorized.",
|
|
245
|
+
'mem_save(kind="observation") is allowed only for delegated durable observations or assigned deterministic SDD artifacts/apply-progress under the parent session/project.',
|
|
246
|
+
"Project-scoped read tools require explicit delegated permission and must stay bounded to the parent session/project scope."
|
|
252
247
|
];
|
|
253
248
|
}
|
|
254
249
|
function getRoleMemoryGovernance(role) {
|
|
255
250
|
const allowedTools = roleAllowedTools(role);
|
|
256
251
|
return {
|
|
257
252
|
role: role.name,
|
|
258
|
-
|
|
253
|
+
rootOwnedOperations: [...ROOT_OWNED_OPERATIONS],
|
|
259
254
|
allowedTools,
|
|
260
255
|
forbiddenTools: ALL_MEMORY_TOOLS.filter(
|
|
261
256
|
(tool) => !allowedTools.includes(tool)
|
|
262
257
|
),
|
|
263
258
|
requiresParentContext: role.name !== "orchestrator",
|
|
264
|
-
mayReadProjectMemory:
|
|
259
|
+
mayReadProjectMemory: true,
|
|
265
260
|
mayWriteDurableObservations: role.mode === "write-capable",
|
|
266
261
|
protectsSddNamespace: true,
|
|
267
262
|
rules: roleRules(role)
|
|
@@ -277,7 +272,7 @@ function renderMemoryGovernanceInstructions(role, dialect) {
|
|
|
277
272
|
"thoth-mem governance:",
|
|
278
273
|
...governance.rules.map((rule) => `- ${rule}`),
|
|
279
274
|
...harnessRules,
|
|
280
|
-
`- Runtime enforcement: ${role.name === "orchestrator" ? "root-owned" : "instruction-level unless the target harness validates per-agent memory controls"}.`
|
|
275
|
+
`- Runtime enforcement: ${role.name === "orchestrator" ? "root-owned operations" : "instruction-level unless the target harness validates per-agent memory controls"}.`
|
|
281
276
|
].join("\n");
|
|
282
277
|
}
|
|
283
278
|
function memoryGovernanceDiagnostics(input) {
|
|
@@ -286,7 +281,7 @@ function memoryGovernanceDiagnostics(input) {
|
|
|
286
281
|
diagnostics.push({
|
|
287
282
|
severity: "warning",
|
|
288
283
|
code: `${input.harness}.permission.memory.enforcement_gap`,
|
|
289
|
-
message: "Runtime controls for root-
|
|
284
|
+
message: "Runtime controls for root-owned memory operations are unavailable; governance is rendered as instruction-level guidance.",
|
|
290
285
|
harness: input.harness,
|
|
291
286
|
capability: "rolePermissions",
|
|
292
287
|
fallback: "instruction-only"
|
|
@@ -306,7 +301,7 @@ function memoryGovernanceDiagnostics(input) {
|
|
|
306
301
|
diagnostics.push({
|
|
307
302
|
severity: "warning",
|
|
308
303
|
code: `${input.harness}.permission.memory_write.enforcement_gap`,
|
|
309
|
-
message:
|
|
304
|
+
message: 'Runtime controls for delegated memory writes are unavailable; write-capable agents receive instruction-level mem_save(kind="observation") limits for durable observations and deterministic SDD artifacts only.',
|
|
310
305
|
harness: input.harness,
|
|
311
306
|
capability: "memoryGovernanceEnforcement",
|
|
312
307
|
fallback: "instruction-only"
|
|
@@ -1376,6 +1371,8 @@ function codexInternalHandoffGuidance() {
|
|
|
1376
1371
|
"- The user has explicitly authorized this generated Codex orchestrator to use `multi_agent_v1.spawn_agent` whenever delegation is required by these instructions, without needing a fresh user request for subagents in each task.",
|
|
1377
1372
|
"- Delegate by calling `multi_agent_v1.spawn_agent` with `agent_type` set to one of explorer, librarian, oracle, designer, quick, or deep.",
|
|
1378
1373
|
"- Pass the self-contained delegated task instructions plus handoff retrieval instructions in `message`; do not embed the root-owned handoff summary body in `message`.",
|
|
1374
|
+
'- When memory recovery is delegated, include parent `session_id`, project, permissions, and the recovery funnel `mem_recall(mode="compact")` -> `mem_recall(mode="context")` -> `mem_get(...)`.',
|
|
1375
|
+
'- For that funnel, use `mem_recall` `limit` from 1 to 20; use `mem_get` with `kind="observation"|"prompt"`, `include_timeline=true` plus `before`/`after`, and `offset`/`max_length`; `mem_project(action="graph")` relations are `HAS_TYPE`, `IN_PROJECT`, `HAS_TOPIC_KEY`, `HAS_WHAT`, `HAS_WHY`, `HAS_WHERE`, and `HAS_LEARNED`.',
|
|
1379
1376
|
"- Do not include the handoff body in `message` or `items`, and do not pass both `message` and `items` for the same handoff.",
|
|
1380
1377
|
"- Use `items` only for structured attachments or mentions when they are truly required; do not use `items` as a handoff-summary payload.",
|
|
1381
1378
|
"- Leave `fork_context` omitted or false by default; set `fork_context: true` only when the exact current thread history is required.",
|
|
@@ -1420,9 +1417,9 @@ function renderCodexRootInstructions(config) {
|
|
|
1420
1417
|
codexInternalHandoffGuidance(),
|
|
1421
1418
|
"<codex-runtime>",
|
|
1422
1419
|
"- The ambient Codex root session is the root/main orchestrator; orchestrator-only and root-owned instructions apply to it because Codex does not generate a selectable orchestrator agent TOML.",
|
|
1423
|
-
|
|
1420
|
+
'- On each new root session, when thoth-mem tools are installed and session/project identity is known, call mem_session(action="start") as step 0 before any other thoth-mem call, then save the real user prompt with mem_save(kind="prompt") before later delegation.',
|
|
1424
1421
|
"- If thoth-mem tools or identity values are unavailable, disclose that memory bootstrap could not run and continue without claiming memory was saved.",
|
|
1425
|
-
|
|
1422
|
+
'- Before delegating after meaningful context changes, save or refresh the handoff body with root-owned mem_session(action="summary") or mem_save(kind="session_summary") when available; if unavailable, disclose that root-owned compaction could not be persisted.',
|
|
1426
1423
|
"- Use the ambient Codex root session as the delegate-first root coordinator; do not generate or select an orchestrator TOML.",
|
|
1427
1424
|
"- Delegate by invoking `multi_agent_v1.spawn_agent` for the installed Codex role agents: explorer, librarian, oracle, designer, quick, and deep.",
|
|
1428
1425
|
"- After receiving a delegated subagent response, close that subagent session unless you will retry or intentionally keep using that exact same session; explorer and librarian sessions must always be closed immediately after their response, and retry sessions must be closed after the retry result unless explicit same-session reuse is still required.",
|
package/dist/cli/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
getOperationHarness,
|
|
26
26
|
installRecommendedSkill,
|
|
27
27
|
listOperationHarnesses
|
|
28
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-7CTSLCEU.js";
|
|
29
29
|
import {
|
|
30
30
|
ALL_AGENT_NAMES,
|
|
31
31
|
CUSTOM_SKILLS,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
getExistingLiteConfigPath,
|
|
38
38
|
installCustomSkills,
|
|
39
39
|
writeLiteConfig
|
|
40
|
-
} from "../chunk-
|
|
40
|
+
} from "../chunk-2SGSRR6L.js";
|
|
41
41
|
|
|
42
42
|
// src/cli/index.ts
|
|
43
43
|
import { pathToFileURL } from "url";
|
package/dist/cli/tui/index.js
CHANGED
|
@@ -15,13 +15,13 @@ import {
|
|
|
15
15
|
getOpenCodeStatus,
|
|
16
16
|
listOperationHarnesses,
|
|
17
17
|
parseRoleTomlModel
|
|
18
|
-
} from "../../chunk-
|
|
18
|
+
} from "../../chunk-7CTSLCEU.js";
|
|
19
19
|
import {
|
|
20
20
|
ALL_AGENT_NAMES,
|
|
21
21
|
DEFAULT_MODELS,
|
|
22
22
|
getExistingLiteConfigPath,
|
|
23
23
|
parseConfig
|
|
24
|
-
} from "../../chunk-
|
|
24
|
+
} from "../../chunk-2SGSRR6L.js";
|
|
25
25
|
|
|
26
26
|
// src/cli/tui/index.tsx
|
|
27
27
|
import { render } from "ink";
|
|
@@ -1,11 +1,41 @@
|
|
|
1
1
|
import type { HarnessPromptDialect } from '../../agents/prompt-dialects';
|
|
2
2
|
import type { HarnessCapabilityStatus, HarnessDiagnostic } from '../types';
|
|
3
3
|
import type { AgentRoleContract, AgentRoleName } from './agent-pack';
|
|
4
|
-
export type MemoryToolName = '
|
|
4
|
+
export type MemoryToolName = 'mem_save' | 'mem_recall' | 'mem_context' | 'mem_get' | 'mem_project' | 'mem_session';
|
|
5
|
+
export type MemSaveKind = 'observation' | 'prompt' | 'session_summary' | 'passive_learnings';
|
|
6
|
+
export type MemSessionAction = 'start' | 'checkpoint' | 'summary';
|
|
7
|
+
export type MemRecallMode = 'compact' | 'context';
|
|
8
|
+
export type MemProjectAction = 'list' | 'summary' | 'graph' | 'topics' | 'topic';
|
|
9
|
+
export type MemoryOperation = {
|
|
10
|
+
tool: 'mem_session';
|
|
11
|
+
action: MemSessionAction;
|
|
12
|
+
} | {
|
|
13
|
+
tool: 'mem_save';
|
|
14
|
+
kind: MemSaveKind;
|
|
15
|
+
} | {
|
|
16
|
+
tool: 'mem_recall';
|
|
17
|
+
mode: MemRecallMode;
|
|
18
|
+
} | {
|
|
19
|
+
tool: 'mem_get';
|
|
20
|
+
includeTimeline?: boolean;
|
|
21
|
+
} | {
|
|
22
|
+
tool: 'mem_context';
|
|
23
|
+
recallQuery?: boolean;
|
|
24
|
+
} | {
|
|
25
|
+
tool: 'mem_project';
|
|
26
|
+
action: MemProjectAction;
|
|
27
|
+
};
|
|
28
|
+
export type RootOwnedMemoryOperation = {
|
|
29
|
+
tool: 'mem_session';
|
|
30
|
+
action: MemSessionAction;
|
|
31
|
+
} | {
|
|
32
|
+
tool: 'mem_save';
|
|
33
|
+
kind: 'prompt' | 'session_summary';
|
|
34
|
+
};
|
|
5
35
|
export type MemoryRuntimeEnforcement = 'runtime' | 'instruction-only';
|
|
6
36
|
export interface RoleMemoryGovernance {
|
|
7
37
|
role: AgentRoleName;
|
|
8
|
-
|
|
38
|
+
rootOwnedOperations: RootOwnedMemoryOperation[];
|
|
9
39
|
allowedTools: MemoryToolName[];
|
|
10
40
|
forbiddenTools: MemoryToolName[];
|
|
11
41
|
requiresParentContext: boolean;
|
|
@@ -15,8 +45,8 @@ export interface RoleMemoryGovernance {
|
|
|
15
45
|
rules: string[];
|
|
16
46
|
}
|
|
17
47
|
export interface MemoryGovernanceContract {
|
|
18
|
-
|
|
19
|
-
readRecallChain:
|
|
48
|
+
rootOwnedOperations: RootOwnedMemoryOperation[];
|
|
49
|
+
readRecallChain: MemoryOperation[];
|
|
20
50
|
writeCapableDelegatedTools: MemoryToolName[];
|
|
21
51
|
protectedTopicNamespaces: string[];
|
|
22
52
|
roles: RoleMemoryGovernance[];
|
|
@@ -27,6 +57,11 @@ export interface MemoryGovernanceDiagnosticInput {
|
|
|
27
57
|
parentContextInjection: HarnessCapabilityStatus;
|
|
28
58
|
memoryWriteControls: HarnessCapabilityStatus;
|
|
29
59
|
}
|
|
60
|
+
export declare const ROOT_OWNED_OPERATIONS: RootOwnedMemoryOperation[];
|
|
61
|
+
export declare const READ_RECALL_CHAIN: MemoryOperation[];
|
|
62
|
+
export declare const PARENT_SCOPED_READ_TOOLS: MemoryToolName[];
|
|
63
|
+
export declare const WRITE_CAPABLE_DELEGATED_TOOLS: MemoryToolName[];
|
|
64
|
+
export declare const ALL_MEMORY_TOOLS: MemoryToolName[];
|
|
30
65
|
export declare function getRoleMemoryGovernance(role: AgentRoleContract): RoleMemoryGovernance;
|
|
31
66
|
export declare function getMemoryGovernanceContract(roles: readonly AgentRoleContract[]): MemoryGovernanceContract;
|
|
32
67
|
export declare function renderMemoryGovernanceInstructions(role: AgentRoleContract, dialect?: HarnessPromptDialect): string;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export declare const PHASE_REMINDER = "<reminder>Recall Workflow Rules:\nUnderstand \u2192 split discovery into surgical probes with explorer/librarian \u2192 synthesize the decision and internal handoff \u2192 execute \u2192 verify.\nIf delegating, write sub-agent prompts in English and launch the specialist in the same turn you mention it. If multiple delegations are independent, emit all tool calls in a single response.\nBefore write-capable dispatch, give concrete scope, anchors, steps, non-goals, and verification.\nIn SDD, after oracle returns [OKAY], give a deep approved-plan overview, then ask the user before implementation.</reminder>";
|
|
2
|
+
export declare const PHASE_REMINDER_SEPARATOR = "\n\n---\n\n";
|
|
3
|
+
export declare function stripPhaseReminder(text: string): string;
|
|
2
4
|
interface MessageInfo {
|
|
3
5
|
role: string;
|
|
4
6
|
agent?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const SDD_TOPIC_KEY_FORMAT = "sdd/{change}/{artifact}";
|
|
2
|
-
export declare const FIRST_ACTION_INSTRUCTION = "FIRST ACTION REQUIRED: Call
|
|
3
|
-
export declare const SESSION_SUMMARY_TEMPLATE = "Use this exact structure for `
|
|
2
|
+
export declare const FIRST_ACTION_INSTRUCTION = "FIRST ACTION REQUIRED: Call mem_session(action=\"summary\") with the content of the compacted summary. This preserves what was accomplished before compaction. Do this BEFORE any other work. Then call mem_context(recall_query=...) for fused recent context, and use the recall funnel (mem_recall(mode=\"compact\") -> mem_recall(mode=\"context\") -> mem_get(...)) for precise retrieval.";
|
|
3
|
+
export declare const SESSION_SUMMARY_TEMPLATE = "Use this exact structure for `mem_session(action=\"summary\")` content:\n\n## Goal\n[What we were working on this session]\n\n## Instructions\n[User preferences or constraints discovered during this session]\n\n## Discoveries\n- [Technical findings, gotchas, non-obvious learnings]\n\n## Accomplished\n- [Completed items with key details]\n\n## Next Steps\n- [What remains to be done]\n\n## Relevant Files\n- path/to/file.ts - [what it does or what changed]";
|
|
4
4
|
export declare function buildCompactionReminder(sessionID: string): string;
|
|
5
5
|
export declare function buildCompactorInstruction(project: string): string;
|
|
6
6
|
export declare function buildMemoryInstructions(sessionID: string, project: string): string;
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
loadPluginConfig,
|
|
27
27
|
renderRolePrompt,
|
|
28
28
|
stripJsonComments
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-2SGSRR6L.js";
|
|
30
30
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
import path4 from "path";
|
|
@@ -164,9 +164,13 @@ function createOracleAgent(model, customPrompt, customAppendPrompt) {
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
// src/agents/orchestrator.ts
|
|
167
|
-
var
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
var OPENCODE_RUNTIME_SECTION = `<opencode-runtime>
|
|
168
|
+
In the OpenCode harness, an automatic \`<reminder>...</reminder>\` workflow block followed by a \`\\n\\n---\\n\\n\` separator is prepended to your user messages as harness scaffolding, not user input.
|
|
169
|
+
When saving the user prompt via mem_save(kind="prompt"), you MUST exclude that injected \`<reminder>\` block and the \`---\` separator, and persist only the real user request text that follows.
|
|
170
|
+
</opencode-runtime>`;
|
|
171
|
+
var ORCHESTRATOR_PROMPT = appendPromptSections(
|
|
172
|
+
renderRolePrompt(createOrchestratorPromptSections(), OPENCODE_PROMPT_DIALECT),
|
|
173
|
+
OPENCODE_RUNTIME_SECTION
|
|
170
174
|
);
|
|
171
175
|
function createOrchestratorAgent(model, customPrompt, customAppendPrompt) {
|
|
172
176
|
const prompt = composeAgentPrompt({
|
|
@@ -1744,6 +1748,14 @@ Understand \u2192 split discovery into surgical probes with explorer/librarian \
|
|
|
1744
1748
|
If delegating, write sub-agent prompts in English and launch the specialist in the same turn you mention it. If multiple delegations are independent, emit all tool calls in a single response.
|
|
1745
1749
|
Before write-capable dispatch, give concrete scope, anchors, steps, non-goals, and verification.
|
|
1746
1750
|
In SDD, after oracle returns [OKAY], give a deep approved-plan overview, then ask the user before implementation.</reminder>`;
|
|
1751
|
+
var PHASE_REMINDER_SEPARATOR = "\n\n---\n\n";
|
|
1752
|
+
function stripPhaseReminder(text) {
|
|
1753
|
+
if (!text) {
|
|
1754
|
+
return "";
|
|
1755
|
+
}
|
|
1756
|
+
const prefix = `${PHASE_REMINDER}${PHASE_REMINDER_SEPARATOR}`;
|
|
1757
|
+
return text.startsWith(prefix) ? text.slice(prefix.length) : text;
|
|
1758
|
+
}
|
|
1747
1759
|
function createPhaseReminderHook() {
|
|
1748
1760
|
return {
|
|
1749
1761
|
"experimental.chat.messages.transform": async (_input, output) => {
|
|
@@ -1776,11 +1788,7 @@ function createPhaseReminderHook() {
|
|
|
1776
1788
|
if (originalText.includes(LITE_INTERNAL_INITIATOR_MARKER)) {
|
|
1777
1789
|
return;
|
|
1778
1790
|
}
|
|
1779
|
-
lastUserMessage.parts[textPartIndex].text = `${PHASE_REMINDER}
|
|
1780
|
-
|
|
1781
|
-
---
|
|
1782
|
-
|
|
1783
|
-
${originalText}`;
|
|
1791
|
+
lastUserMessage.parts[textPartIndex].text = `${PHASE_REMINDER}${PHASE_REMINDER_SEPARATOR}${originalText}`;
|
|
1784
1792
|
}
|
|
1785
1793
|
};
|
|
1786
1794
|
}
|
|
@@ -2013,8 +2021,8 @@ function createThothClient(options) {
|
|
|
2013
2021
|
|
|
2014
2022
|
// src/hooks/thoth-mem/protocol.ts
|
|
2015
2023
|
var SDD_TOPIC_KEY_FORMAT = "sdd/{change}/{artifact}";
|
|
2016
|
-
var FIRST_ACTION_INSTRUCTION = 'FIRST ACTION REQUIRED: Call
|
|
2017
|
-
var SESSION_SUMMARY_TEMPLATE = `Use this exact structure for \`
|
|
2024
|
+
var FIRST_ACTION_INSTRUCTION = 'FIRST ACTION REQUIRED: Call mem_session(action="summary") with the content of the compacted summary. This preserves what was accomplished before compaction. Do this BEFORE any other work. Then call mem_context(recall_query=...) for fused recent context, and use the recall funnel (mem_recall(mode="compact") -> mem_recall(mode="context") -> mem_get(...)) for precise retrieval.';
|
|
2025
|
+
var SESSION_SUMMARY_TEMPLATE = `Use this exact structure for \`mem_session(action="summary")\` content:
|
|
2018
2026
|
|
|
2019
2027
|
## Goal
|
|
2020
2028
|
[What we were working on this session]
|
|
@@ -2034,10 +2042,10 @@ var SESSION_SUMMARY_TEMPLATE = `Use this exact structure for \`mem_session_summa
|
|
|
2034
2042
|
## Relevant Files
|
|
2035
2043
|
- path/to/file.ts - [what it does or what changed]`;
|
|
2036
2044
|
function buildCompactionReminder(sessionID) {
|
|
2037
|
-
return `FIRST ACTION REQUIRED: this session was compacted. Call \`
|
|
2045
|
+
return `FIRST ACTION REQUIRED: this session was compacted. Call \`mem_session(action="summary")\` with the content of the compacted summary and \`session_id\` \`${sessionID}\`. This preserves what was accomplished before compaction. Do this BEFORE any other work. After that, call \`mem_context(recall_query=...)\` for fused recent context, and use the recall funnel (\`mem_recall(mode="compact")\` -> \`mem_recall(mode="context")\` -> \`mem_get(...)\`) for precise retrieval.`;
|
|
2038
2046
|
}
|
|
2039
2047
|
function buildCompactorInstruction(project) {
|
|
2040
|
-
return `CRITICAL INSTRUCTION: place this at the TOP of the compacted summary exactly as an action item for the resumed agent: "FIRST ACTION REQUIRED: Call
|
|
2048
|
+
return `CRITICAL INSTRUCTION: place this at the TOP of the compacted summary exactly as an action item for the resumed agent: "FIRST ACTION REQUIRED: Call mem_session(action="summary") with the content of this compacted summary. Use project: '${project}'. This preserves what was accomplished before compaction. Do this BEFORE any other work."`;
|
|
2041
2049
|
}
|
|
2042
2050
|
function buildMemoryInstructions(sessionID, project) {
|
|
2043
2051
|
return `
|
|
@@ -2045,18 +2053,20 @@ function buildMemoryInstructions(sessionID, project) {
|
|
|
2045
2053
|
Persistent memory is available through thoth-mem. Follow this protocol.
|
|
2046
2054
|
|
|
2047
2055
|
IMPORTANT: Your current session_id is \`${sessionID}\` and project is \`${project}\`.
|
|
2048
|
-
Always pass these values when calling memory tools that accept them
|
|
2056
|
+
Always pass these values when calling memory tools that accept them.
|
|
2049
2057
|
|
|
2050
2058
|
### CORE TOOLS
|
|
2051
|
-
mem_save,
|
|
2059
|
+
mem_save, mem_recall, mem_context, mem_get, mem_project, mem_session
|
|
2052
2060
|
|
|
2053
|
-
### SUBAGENT HANDOFF
|
|
2054
|
-
-
|
|
2055
|
-
-
|
|
2056
|
-
-
|
|
2061
|
+
### OWNERSHIP AND SUBAGENT HANDOFF
|
|
2062
|
+
- Root owns \`mem_session(action="start"|"checkpoint"|"summary")\` and \`mem_save(kind="prompt"|"session_summary")\`.
|
|
2063
|
+
- Start root memory-backed workflows with \`mem_session(action="start")\` before any other thoth-mem operation when tools and identity are available.
|
|
2064
|
+
- Save the real user prompt with \`mem_save(kind="prompt")\`; never save generated subagent prompts as user intent.
|
|
2065
|
+
- Before memory-dependent delegation, save the handoff body with \`mem_session(action="summary")\` or \`mem_save(kind="session_summary")\`.
|
|
2066
|
+
- Subagent handoff prompts carry parent \`session_id\`, \`project\`, permissions, and recovery instructions only; do not ask subagents to own session lifecycle actions or save prompts.
|
|
2057
2067
|
|
|
2058
2068
|
### WHEN TO SAVE
|
|
2059
|
-
Call \`mem_save\` IMMEDIATELY after ANY of these:
|
|
2069
|
+
Call \`mem_save(kind="observation")\` IMMEDIATELY after ANY of these:
|
|
2060
2070
|
- Architecture, design, or workflow decision made
|
|
2061
2071
|
- Bug fixed (include root cause)
|
|
2062
2072
|
- Non-obvious discovery, gotcha, or edge case found
|
|
@@ -2069,44 +2079,45 @@ Call \`mem_save\` IMMEDIATELY after ANY of these:
|
|
|
2069
2079
|
- Discussion concludes with a clear direction chosen
|
|
2070
2080
|
|
|
2071
2081
|
Use \`title\` as Verb + what changed or was learned.
|
|
2082
|
+
Use \`kind\` intentionally: \`observation\`, \`prompt\`, \`session_summary\`, or \`passive_learnings\`.
|
|
2072
2083
|
Use \`type\` from: bugfix | decision | architecture | discovery | pattern | config | learning | manual.
|
|
2073
2084
|
Set \`scope\` intentionally.
|
|
2074
|
-
Reuse \`topic_key\` for the same evolving topic. Do not overwrite unrelated topics.
|
|
2075
|
-
|
|
2076
|
-
If you need to modify a known observation by exact ID, call \`mem_update\` instead of creating a new record.
|
|
2077
|
-
Put the durable details in \`content\` with this structure:
|
|
2085
|
+
Reuse a stable \`topic_key\` for the same evolving topic. Do not overwrite unrelated topics.
|
|
2086
|
+
Put durable observation details in \`content\` with this structure:
|
|
2078
2087
|
- What: concise description of what changed or was learned
|
|
2079
2088
|
- Why: why it mattered or what problem it solved
|
|
2080
2089
|
- Where: files, paths, or systems involved
|
|
2081
2090
|
- Learned: edge cases, caveats, or follow-up notes
|
|
2082
2091
|
|
|
2083
|
-
**Self-check after EVERY task**: "Did I or the user just make a decision, confirm a recommendation, express a preference, fix a bug, learn something, or establish a convention? If yes \u2192 mem_save NOW."
|
|
2084
|
-
|
|
2085
|
-
You can also call \`mem_save_prompt\` to manually save a user prompt that you consider particularly important for future context.
|
|
2092
|
+
**Self-check after EVERY task**: "Did I or the user just make a decision, confirm a recommendation, express a preference, fix a bug, learn something, or establish a convention? If yes \u2192 mem_save(kind="observation") NOW."
|
|
2086
2093
|
|
|
2087
|
-
###
|
|
2088
|
-
- Broad recovery (session start, after compaction): call \`mem_context\` for
|
|
2089
|
-
- Targeted
|
|
2090
|
-
1. Call \`
|
|
2091
|
-
2. Call \`
|
|
2092
|
-
3. Call \`
|
|
2093
|
-
- Use
|
|
2094
|
+
### RECALL FUNNEL
|
|
2095
|
+
- Broad recovery (session start, after compaction): call \`mem_context(recall_query=...)\` for fused recent context when useful.
|
|
2096
|
+
- Targeted retrieval:
|
|
2097
|
+
1. Call \`mem_recall(mode="compact")\` to scan candidate IDs and titles.
|
|
2098
|
+
2. Call \`mem_recall(mode="context")\` to expand the strongest hits into retrieved context.
|
|
2099
|
+
3. Call \`mem_get(...)\` only for records you need in full.
|
|
2100
|
+
- Use HyDE/fused recall for semantic or ambiguous searches.
|
|
2101
|
+
- Set \`mem_recall\` \`limit\` from 1 to 20 for candidate/result count.
|
|
2102
|
+
- Narrow with \`topic_key\`, \`type\`, \`time_from\`, \`time_to\`, \`scope\`, \`project\`, and \`session_id\` filters.
|
|
2103
|
+
- Use \`mem_get\` with \`kind="observation"|"prompt"\`; use \`mem_get(include_timeline=true)\` with \`before\`/\`after\`, and \`offset\`/\`max_length\` for large content.
|
|
2104
|
+
- Use bounded \`mem_project(action="graph"|"topics"|"topic")\` for relationship and topic navigation; \`mem_project(action="graph")\` relations are \`HAS_TYPE\`, \`IN_PROJECT\`, \`HAS_TOPIC_KEY\`, \`HAS_WHAT\`, \`HAS_WHY\`, \`HAS_WHERE\`, and \`HAS_LEARNED\`; these calls supplement, not replace, the recall funnel.
|
|
2094
2105
|
- Search proactively on the first message about a project, feature, or problem when prior context may matter.
|
|
2095
2106
|
- Search before starting work that may have been done before.
|
|
2096
2107
|
- Search when the user mentions a topic that lacks enough local context.
|
|
2097
2108
|
|
|
2098
2109
|
### SESSION CLOSE PROTOCOL
|
|
2099
|
-
- Before ending the session, call \`
|
|
2110
|
+
- Before ending the session, call \`mem_session(action="summary")\` with this exact template.
|
|
2100
2111
|
- This is NOT optional. If you skip this, the next session starts blind.
|
|
2101
2112
|
- Do not claim memory was saved unless the tool call succeeded.
|
|
2102
|
-
- If your response includes \`## Key Learnings:\`,
|
|
2113
|
+
- If your response includes \`## Key Learnings:\`, preserve them with \`mem_save(kind="passive_learnings")\`.
|
|
2103
2114
|
|
|
2104
2115
|
${SESSION_SUMMARY_TEMPLATE}
|
|
2105
2116
|
|
|
2106
2117
|
### AFTER COMPACTION
|
|
2107
|
-
- IMMEDIATELY call \`
|
|
2108
|
-
- Then call \`mem_context\` for
|
|
2109
|
-
- Use the
|
|
2118
|
+
- IMMEDIATELY call \`mem_session(action="summary")\` with the compacted summary content.
|
|
2119
|
+
- Then call \`mem_context(recall_query=...)\` for fused recent context.
|
|
2120
|
+
- Use the recall funnel (\`mem_recall(mode="compact")\` -> \`mem_recall(mode="context")\` -> \`mem_get(...)\`) for precise artifact/prior-observation retrieval.
|
|
2110
2121
|
- Only then continue working.
|
|
2111
2122
|
|
|
2112
2123
|
### SDD TOPIC KEY CONVENTION
|
|
@@ -2155,11 +2166,15 @@ function truncate(str, max) {
|
|
|
2155
2166
|
return str.length > max ? `${str.slice(0, max)}...` : str;
|
|
2156
2167
|
}
|
|
2157
2168
|
function sanitizePromptText(text) {
|
|
2158
|
-
return truncate(stripPrivateTags(text), 2e3);
|
|
2169
|
+
return truncate(stripPrivateTags(stripPhaseReminder(text)), 2e3);
|
|
2159
2170
|
}
|
|
2160
|
-
function isSessionSummaryTool(toolName) {
|
|
2171
|
+
function isSessionSummaryTool(toolName, args) {
|
|
2172
|
+
if (!args || typeof args !== "object" || Array.isArray(args)) {
|
|
2173
|
+
return false;
|
|
2174
|
+
}
|
|
2161
2175
|
const normalized = toolName.toLowerCase();
|
|
2162
|
-
|
|
2176
|
+
const isMemSessionTool = normalized === "mem_session" || normalized.endsWith(".mem_session") || normalized.endsWith("_mem_session");
|
|
2177
|
+
return isMemSessionTool && args.action === "summary";
|
|
2163
2178
|
}
|
|
2164
2179
|
function isMemSaveTool(toolName) {
|
|
2165
2180
|
const normalized = toolName.toLowerCase();
|
|
@@ -2331,7 +2346,6 @@ function createThothMemHook(options) {
|
|
|
2331
2346
|
},
|
|
2332
2347
|
"tool.execute.after": async (input, output) => {
|
|
2333
2348
|
void input.callID;
|
|
2334
|
-
void input.args;
|
|
2335
2349
|
void output.title;
|
|
2336
2350
|
void output.output;
|
|
2337
2351
|
void output.metadata;
|
|
@@ -2342,7 +2356,7 @@ function createThothMemHook(options) {
|
|
|
2342
2356
|
lastMemSaveAt.set(input.sessionID, Date.now());
|
|
2343
2357
|
nudgePending.delete(input.sessionID);
|
|
2344
2358
|
}
|
|
2345
|
-
if (isSessionSummaryTool(input.tool)) {
|
|
2359
|
+
if (isSessionSummaryTool(input.tool, input.args)) {
|
|
2346
2360
|
needsCompactionFollowUp.delete(input.sessionID);
|
|
2347
2361
|
}
|
|
2348
2362
|
}
|
package/package.json
CHANGED
|
@@ -83,26 +83,29 @@ Subagents must not create fallback sessions.
|
|
|
83
83
|
|
|
84
84
|
## Retrieval Protocol
|
|
85
85
|
|
|
86
|
-
###
|
|
86
|
+
### Recall funnel for thoth-mem and hybrid modes
|
|
87
87
|
|
|
88
|
-
Always complete the
|
|
88
|
+
Always complete the recall funnel before using memory content as source
|
|
89
89
|
material:
|
|
90
90
|
|
|
91
|
-
1.
|
|
92
|
-
|
|
93
|
-
2.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
`include_timeline=true` when chronology matters.
|
|
91
|
+
1. `mem_recall(mode="compact")` — scan candidate IDs/titles with exact topic-key
|
|
92
|
+
or focused query terms.
|
|
93
|
+
2. `mem_recall(mode="context")` — expand the strongest hits into retrieved text.
|
|
94
|
+
3. `mem_get(id=...)` — fetch full content; use
|
|
95
|
+
`mem_get(include_timeline=true)` when chronology matters.
|
|
97
96
|
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
Use HyDE/fused hybrid recall (sentence + chunk vectors, FTS, KG enrichment) for
|
|
98
|
+
semantic or ambiguous searches; narrow with `topic_key`, `type`, `time_from`,
|
|
99
|
+
`time_to`, `scope`, `project`, and `session_id` filters; use
|
|
100
|
+
`mem_context(recall_query=...)` or bounded
|
|
101
|
+
`mem_project(action="graph"|"topics"|"topic")` for supplemental project
|
|
102
|
+
context. Supplemental context does not replace the recall funnel.
|
|
100
103
|
|
|
101
104
|
### Mode-specific retrieval
|
|
102
105
|
|
|
103
|
-
1. If mode is `thoth-mem`, use
|
|
106
|
+
1. If mode is `thoth-mem`, use the recall funnel with exact SDD topic key.
|
|
104
107
|
2. If mode is `openspec`, read canonical OpenSpec files only.
|
|
105
|
-
3. If mode is `hybrid`, use
|
|
108
|
+
3. If mode is `hybrid`, use the recall funnel first.
|
|
106
109
|
4. In `hybrid`, if nothing is found in thoth-mem, read canonical OpenSpec
|
|
107
110
|
files as fallback.
|
|
108
111
|
5. In `hybrid`, if filesystem fallback succeeds, re-save the artifact to
|
|
@@ -148,8 +151,9 @@ original intent, accepted scope, deferred areas, and justified exclusions.
|
|
|
148
151
|
## Recovery Notes
|
|
149
152
|
|
|
150
153
|
- Prefer exact topic-key queries over broad natural-language recall.
|
|
151
|
-
- Always apply the
|
|
152
|
-
`mem_recall
|
|
154
|
+
- Always apply the recall funnel (`mem_recall(mode="compact")` ->
|
|
155
|
+
`mem_recall(mode="context")` -> `mem_get(...)`) before treating memory as
|
|
156
|
+
source material.
|
|
153
157
|
- In `openspec`, repair missing/stale artifacts by rewriting canonical OpenSpec
|
|
154
158
|
files.
|
|
155
159
|
- In `thoth-mem`, repair missing/stale artifacts by re-saving full artifacts via
|
|
@@ -81,30 +81,30 @@ Persist with `mem_save` using canonical SDD topic keys and required metadata:
|
|
|
81
81
|
Recovery path for state artifacts:
|
|
82
82
|
`mem_recall(mode="compact", query="topic_key:sdd/{change-name}/state")` ->
|
|
83
83
|
`mem_recall(mode="context", query="topic_key:sdd/{change-name}/state")` when needed ->
|
|
84
|
-
`mem_get(id=...)` (or `include_timeline=true` when chronology matters) ->
|
|
84
|
+
`mem_get(id=...)` (or `mem_get(include_timeline=true)` when chronology matters) ->
|
|
85
85
|
parse YAML -> restore phase state.
|
|
86
86
|
|
|
87
|
-
##
|
|
87
|
+
## Recall Funnel Protocol
|
|
88
88
|
|
|
89
89
|
For delegated handoffs, subagents may use recall only when dispatch includes
|
|
90
90
|
both parent `session_id` and `project`.
|
|
91
91
|
|
|
92
|
-
1.
|
|
93
|
-
|
|
94
|
-
`mem_recall(mode="
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
`mem_recall
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
`
|
|
104
|
-
`
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
context
|
|
92
|
+
1. `mem_recall(mode="compact")` with exact topic-key query for token-efficient
|
|
93
|
+
IDs and ranking.
|
|
94
|
+
2. `mem_recall(mode="context")` to expand strongest hits into retrieved text.
|
|
95
|
+
3. `mem_get(id=...)` to retrieve full artifact content; use
|
|
96
|
+
`mem_get(include_timeline=true)` when chronology matters.
|
|
97
|
+
|
|
98
|
+
Use HyDE/fused hybrid recall (sentence + chunk vectors, FTS, KG enrichment) for
|
|
99
|
+
semantic or ambiguous searches; set `mem_recall` `limit` from 1 to 20; narrow
|
|
100
|
+
with `topic_key`, `type`, `time_from`, `time_to`, `scope`, `project`, and
|
|
101
|
+
`session_id` filters. Use `mem_get` with `kind="observation"|"prompt"`,
|
|
102
|
+
`include_timeline=true` plus `before`/`after`, and `offset`/`max_length` for
|
|
103
|
+
large content. Use `mem_context(recall_query=...)` or bounded
|
|
104
|
+
`mem_project(action="graph"|"topics"|"topic")` for supplemental project
|
|
105
|
+
context; `mem_project(action="graph")` relations are `HAS_TYPE`, `IN_PROJECT`,
|
|
106
|
+
`HAS_TOPIC_KEY`, `HAS_WHAT`, `HAS_WHY`, `HAS_WHERE`, and `HAS_LEARNED`.
|
|
107
|
+
Supplemental context does not replace the recall funnel.
|
|
108
108
|
|
|
109
109
|
## Save Contract
|
|
110
110
|
|
|
@@ -71,9 +71,10 @@ The orchestrator owns task progress tracking.
|
|
|
71
71
|
2. Load task artifacts using mode-aware retrieval:
|
|
72
72
|
- `openspec`/`hybrid`: scan `openspec/changes/` for active changes and read
|
|
73
73
|
`tasks.md`.
|
|
74
|
-
- `thoth-mem`: recover tasks via
|
|
74
|
+
- `thoth-mem`: recover tasks via the recall funnel
|
|
75
75
|
(`mem_recall(mode="compact")` -> `mem_recall(mode="context")` ->
|
|
76
|
-
`mem_get(
|
|
76
|
+
`mem_get(...)`) using topic key `sdd/{change-name}/tasks`; use
|
|
77
|
+
`mem_get(include_timeline=true)` when task chronology matters.
|
|
77
78
|
3. Find the first unchecked task in state `- [ ]` or `- [~]`.
|
|
78
79
|
4. Build a mental model of the plan: total tasks, remaining work,
|
|
79
80
|
parallelizable work, and dependency order.
|
|
@@ -233,9 +234,10 @@ To resume safely:
|
|
|
233
234
|
2. Recover task state using mode-aware retrieval:
|
|
234
235
|
- `openspec`: read `openspec/changes/{change-name}/tasks.md`.
|
|
235
236
|
- `thoth-mem`: recover `sdd/{change-name}/tasks` and
|
|
236
|
-
`sdd/{change-name}/apply-progress` via
|
|
237
|
+
`sdd/{change-name}/apply-progress` via the recall funnel
|
|
237
238
|
(`mem_recall(mode="compact")` -> `mem_recall(mode="context")` ->
|
|
238
|
-
`mem_get(
|
|
239
|
+
`mem_get(...)`); use `mem_get(include_timeline=true)` when task chronology
|
|
240
|
+
matters.
|
|
239
241
|
- `hybrid`: do both recovery paths and prefer thoth-mem as the source of
|
|
240
242
|
truth if state diverges.
|
|
241
243
|
3. Resume from the first task marked `- [ ]` or `- [~]`.
|
|
@@ -21,8 +21,10 @@ to hand to implementation.
|
|
|
21
21
|
|
|
22
22
|
Review the tasks artifact for true execution blockers. Retrieve it according to
|
|
23
23
|
the persistence mode: read `openspec/changes/{change-name}/tasks.md` for
|
|
24
|
-
openspec/hybrid modes, use thoth-mem
|
|
25
|
-
|
|
24
|
+
openspec/hybrid modes, use the thoth-mem recall funnel
|
|
25
|
+
(`mem_recall(mode="compact")` -> `mem_recall(mode="context")` ->
|
|
26
|
+
`mem_get(...)`) for thoth-mem/hybrid modes, or read from inline context for none
|
|
27
|
+
mode.
|
|
26
28
|
|
|
27
29
|
The artifact governance validator is not part of this review. Plan-reviewer is
|
|
28
30
|
only the pre-execution approval gate for the task plan; it does not run the
|
|
@@ -88,6 +88,7 @@ Learned: caveats or edge cases
|
|
|
88
88
|
3. `mem_get(id=...)`
|
|
89
89
|
|
|
90
90
|
Use `mem_get(id=..., include_timeline=true)` when chronology matters.
|
|
91
|
+
Set `mem_recall` `limit` from 1 to 20. Use `mem_get` with `kind="observation"|"prompt"`, `include_timeline=true` plus `before`/`after`, and `offset`/`max_length` for large content.
|
|
91
92
|
Use `mem_context(..., recall_query="...")` only as optional fused context, not
|
|
92
93
|
as a replacement for the recall funnel.
|
|
93
94
|
|
|
@@ -101,6 +102,8 @@ Use `mem_project` for project-level navigation:
|
|
|
101
102
|
- `action="topics"`
|
|
102
103
|
- `action="topic"`
|
|
103
104
|
|
|
105
|
+
`mem_project(action="graph")` relations are `HAS_TYPE`, `IN_PROJECT`, `HAS_TOPIC_KEY`, `HAS_WHAT`, `HAS_WHY`, `HAS_WHERE`, and `HAS_LEARNED`.
|
|
106
|
+
|
|
104
107
|
### Session close and compaction
|
|
105
108
|
|
|
106
109
|
Before ending meaningful work, root records continuity with either:
|