thoth-agents 0.1.18 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -12
- package/dist/agents/prompt-dialects.d.ts +9 -0
- package/dist/{chunk-6K3ZXIMC.js → chunk-3NOVCFN7.js} +88 -29
- package/dist/chunk-4WYCZ5Z7.js +698 -0
- package/dist/{chunk-SOT5ZY53.js → chunk-WH3F3GWE.js} +1498 -350
- package/dist/cli/claude-code-install.d.ts +53 -0
- package/dist/cli/claude-code-paths.d.ts +31 -0
- package/dist/cli/codex-install.d.ts +1 -5
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/index.js +85 -27
- package/dist/cli/managed-state-io.d.ts +16 -0
- package/dist/cli/operations/claude-code.d.ts +21 -0
- package/dist/cli/tui/index.js +87 -9
- package/dist/cli/tui/operations.d.ts +2 -0
- package/dist/cli/types.d.ts +3 -3
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schema.d.ts +11 -0
- package/dist/config/utils.d.ts +5 -0
- package/dist/harness/adapters/claude-code.d.ts +24 -0
- package/dist/harness/core/memory-governance.d.ts +39 -4
- package/dist/harness/core/package-version.d.ts +7 -0
- package/dist/harness/types.d.ts +1 -1
- package/dist/harness/writers/claude-code-plugin-package.d.ts +32 -0
- package/dist/harness/writers/claude-code-skill-layout.d.ts +16 -0
- package/dist/harness/writers/claude-code-subagent.d.ts +26 -0
- package/dist/harness/writers/fs-skill-collect.d.ts +7 -0
- package/dist/hooks/phase-reminder/index.d.ts +2 -0
- package/dist/hooks/thoth-mem/protocol.d.ts +2 -2
- package/dist/index.js +54 -512
- 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/thoth-agents.schema.json +16 -0
- package/dist/chunk-DYGVRAMS.js +0 -182
|
@@ -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:
|
package/thoth-agents.schema.json
CHANGED
|
@@ -466,6 +466,22 @@
|
|
|
466
466
|
"type": "boolean"
|
|
467
467
|
}
|
|
468
468
|
}
|
|
469
|
+
},
|
|
470
|
+
"claudeCode": {
|
|
471
|
+
"type": "object",
|
|
472
|
+
"properties": {
|
|
473
|
+
"enabled": {
|
|
474
|
+
"default": false,
|
|
475
|
+
"type": "boolean"
|
|
476
|
+
},
|
|
477
|
+
"outputRoot": {
|
|
478
|
+
"type": "string"
|
|
479
|
+
},
|
|
480
|
+
"dryRun": {
|
|
481
|
+
"default": true,
|
|
482
|
+
"type": "boolean"
|
|
483
|
+
}
|
|
484
|
+
}
|
|
469
485
|
}
|
|
470
486
|
},
|
|
471
487
|
"title": "thoth-agents",
|
package/dist/chunk-DYGVRAMS.js
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
// src/utils/subprocess.ts
|
|
2
|
-
import {
|
|
3
|
-
spawn as nodeSpawn,
|
|
4
|
-
spawnSync as nodeSpawnSync
|
|
5
|
-
} from "child_process";
|
|
6
|
-
import { Readable } from "stream";
|
|
7
|
-
function emptyReadableStream() {
|
|
8
|
-
return new ReadableStream({
|
|
9
|
-
start(controller) {
|
|
10
|
-
controller.close();
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
function toWebReadable(stream) {
|
|
15
|
-
if (!stream) {
|
|
16
|
-
return emptyReadableStream();
|
|
17
|
-
}
|
|
18
|
-
return Readable.toWeb(
|
|
19
|
-
stream
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
function fallbackStdin() {
|
|
23
|
-
return {
|
|
24
|
-
write: () => void 0,
|
|
25
|
-
end: () => void 0
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
function spawn(command, options = {}) {
|
|
29
|
-
const child = nodeSpawn(command[0], command.slice(1), {
|
|
30
|
-
cwd: options.cwd,
|
|
31
|
-
env: options.env,
|
|
32
|
-
stdio: [
|
|
33
|
-
options.stdin ?? "pipe",
|
|
34
|
-
options.stdout ?? "pipe",
|
|
35
|
-
options.stderr ?? "pipe"
|
|
36
|
-
]
|
|
37
|
-
});
|
|
38
|
-
const managed = {
|
|
39
|
-
stdin: child.stdin ?? fallbackStdin(),
|
|
40
|
-
stdout: toWebReadable(child.stdout),
|
|
41
|
-
stderr: toWebReadable(child.stderr),
|
|
42
|
-
exited: new Promise((resolve) => {
|
|
43
|
-
child.on("exit", (code) => {
|
|
44
|
-
managed.exitCode = code;
|
|
45
|
-
resolve(code ?? 1);
|
|
46
|
-
});
|
|
47
|
-
child.on("error", () => {
|
|
48
|
-
managed.exitCode = 1;
|
|
49
|
-
resolve(1);
|
|
50
|
-
});
|
|
51
|
-
}),
|
|
52
|
-
exitCode: child.exitCode,
|
|
53
|
-
kill: () => {
|
|
54
|
-
child.kill();
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
return managed;
|
|
58
|
-
}
|
|
59
|
-
function spawnSync(command, options = {}) {
|
|
60
|
-
const result = nodeSpawnSync(command[0], command.slice(1), {
|
|
61
|
-
cwd: options.cwd,
|
|
62
|
-
env: options.env,
|
|
63
|
-
stdio: [
|
|
64
|
-
options.stdin ?? "ignore",
|
|
65
|
-
options.stdout ?? "pipe",
|
|
66
|
-
options.stderr ?? "pipe"
|
|
67
|
-
]
|
|
68
|
-
});
|
|
69
|
-
return { exitCode: result.status };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// src/cli/system.ts
|
|
73
|
-
import { statSync } from "fs";
|
|
74
|
-
var cachedOpenCodePath = null;
|
|
75
|
-
function getOpenCodePaths() {
|
|
76
|
-
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
77
|
-
return [
|
|
78
|
-
// PATH (try this first)
|
|
79
|
-
"opencode",
|
|
80
|
-
// User local installations (Linux & macOS)
|
|
81
|
-
`${home}/.local/bin/opencode`,
|
|
82
|
-
`${home}/.opencode/bin/opencode`,
|
|
83
|
-
`${home}/bin/opencode`,
|
|
84
|
-
// System-wide installations
|
|
85
|
-
"/usr/local/bin/opencode",
|
|
86
|
-
"/opt/opencode/bin/opencode",
|
|
87
|
-
"/usr/bin/opencode",
|
|
88
|
-
"/bin/opencode",
|
|
89
|
-
// macOS specific
|
|
90
|
-
"/Applications/OpenCode.app/Contents/MacOS/opencode",
|
|
91
|
-
`${home}/Applications/OpenCode.app/Contents/MacOS/opencode`,
|
|
92
|
-
// Homebrew (macOS & Linux)
|
|
93
|
-
"/opt/homebrew/bin/opencode",
|
|
94
|
-
"/home/linuxbrew/.linuxbrew/bin/opencode",
|
|
95
|
-
`${home}/homebrew/bin/opencode`,
|
|
96
|
-
// macOS user Library
|
|
97
|
-
`${home}/Library/Application Support/opencode/bin/opencode`,
|
|
98
|
-
// Snap (Linux)
|
|
99
|
-
"/snap/bin/opencode",
|
|
100
|
-
"/var/snap/opencode/current/bin/opencode",
|
|
101
|
-
// Flatpak (Linux)
|
|
102
|
-
"/var/lib/flatpak/exports/bin/ai.opencode.OpenCode",
|
|
103
|
-
`${home}/.local/share/flatpak/exports/bin/ai.opencode.OpenCode`,
|
|
104
|
-
// Nix (Linux/macOS)
|
|
105
|
-
"/nix/store/opencode/bin/opencode",
|
|
106
|
-
`${home}/.nix-profile/bin/opencode`,
|
|
107
|
-
"/run/current-system/sw/bin/opencode",
|
|
108
|
-
// Cargo (Rust toolchain)
|
|
109
|
-
`${home}/.cargo/bin/opencode`,
|
|
110
|
-
// npm/npx global
|
|
111
|
-
`${home}/.npm-global/bin/opencode`,
|
|
112
|
-
"/usr/local/lib/node_modules/opencode/bin/opencode",
|
|
113
|
-
// Yarn global
|
|
114
|
-
`${home}/.yarn/bin/opencode`,
|
|
115
|
-
// PNPM
|
|
116
|
-
`${home}/.pnpm-global/bin/opencode`
|
|
117
|
-
];
|
|
118
|
-
}
|
|
119
|
-
function resolveOpenCodePath() {
|
|
120
|
-
if (cachedOpenCodePath) {
|
|
121
|
-
return cachedOpenCodePath;
|
|
122
|
-
}
|
|
123
|
-
const paths = getOpenCodePaths();
|
|
124
|
-
for (const opencodePath of paths) {
|
|
125
|
-
if (opencodePath === "opencode") continue;
|
|
126
|
-
try {
|
|
127
|
-
const stat = statSync(opencodePath);
|
|
128
|
-
if (stat.isFile()) {
|
|
129
|
-
cachedOpenCodePath = opencodePath;
|
|
130
|
-
return opencodePath;
|
|
131
|
-
}
|
|
132
|
-
} catch {
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return "opencode";
|
|
136
|
-
}
|
|
137
|
-
async function isOpenCodeInstalled() {
|
|
138
|
-
const paths = getOpenCodePaths();
|
|
139
|
-
for (const opencodePath of paths) {
|
|
140
|
-
try {
|
|
141
|
-
const proc = spawn([opencodePath, "--version"], {
|
|
142
|
-
stdout: "pipe",
|
|
143
|
-
stderr: "pipe"
|
|
144
|
-
});
|
|
145
|
-
await proc.exited;
|
|
146
|
-
if (proc.exitCode === 0) {
|
|
147
|
-
cachedOpenCodePath = opencodePath;
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
150
|
-
} catch {
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
async function getOpenCodeVersion() {
|
|
156
|
-
const opencodePath = resolveOpenCodePath();
|
|
157
|
-
try {
|
|
158
|
-
const proc = spawn([opencodePath, "--version"], {
|
|
159
|
-
stdout: "pipe",
|
|
160
|
-
stderr: "pipe"
|
|
161
|
-
});
|
|
162
|
-
const output = await new Response(proc.stdout).text();
|
|
163
|
-
await proc.exited;
|
|
164
|
-
if (proc.exitCode === 0) {
|
|
165
|
-
return output.trim();
|
|
166
|
-
}
|
|
167
|
-
} catch {
|
|
168
|
-
}
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
function getOpenCodePath() {
|
|
172
|
-
const path = resolveOpenCodePath();
|
|
173
|
-
return path === "opencode" ? null : path;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
export {
|
|
177
|
-
spawn,
|
|
178
|
-
spawnSync,
|
|
179
|
-
isOpenCodeInstalled,
|
|
180
|
-
getOpenCodeVersion,
|
|
181
|
-
getOpenCodePath
|
|
182
|
-
};
|