wendkeep 0.12.0 → 0.14.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/CHANGELOG.md +24 -0
- package/README.md +26 -6
- package/bin/wendkeep.mjs +2 -2
- package/hooks/subagent-usage.mjs +9 -2
- package/package.json +1 -1
- package/src/cost.mjs +8 -3
- package/src/taxonomy.mjs +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to **wendkeep** are documented here. Format based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this project follows
|
|
5
5
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.14.0] — 2026-07-06
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- **dotcontext is no longer a default companion.** wendkeep's native a2 loop (`change` /
|
|
11
|
+
`verify` / gate) recreates dotcontext's execution/gate role, so pinning it duplicates the
|
|
12
|
+
harness. The interactive / `--yes` default is now **`context-mode` only**; dotcontext stays
|
|
13
|
+
selectable via `--companions dotcontext` for anyone already invested.
|
|
14
|
+
- **README:** rewrote "Install & set up" with a clear **`init` options table** and a
|
|
15
|
+
per-companion breakdown; clarified that `--no-mcp` skips **only wendkeep's own** vault MCP
|
|
16
|
+
(companion MCPs still follow `--companions`).
|
|
17
|
+
|
|
18
|
+
## [0.13.0] — 2026-07-06
|
|
19
|
+
|
|
20
|
+
Cost intelligence: waste + average.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- **Wasted-spend tracking:** a killed/failed workflow run's subagent cost is now recorded per
|
|
24
|
+
session (`subagents_wasted_usd` + a line in the note's `## Subagents & Workflows`) and rolled
|
|
25
|
+
up by `wendkeep cost` (`desperdiçado (runs killed/failed): $X`). Money burned on aborted runs
|
|
26
|
+
was invisible before.
|
|
27
|
+
- **`wendkeep cost` per-session average** (`$/sessão`) alongside the vault total.
|
|
28
|
+
|
|
7
29
|
## [0.12.0] — 2026-07-06
|
|
8
30
|
|
|
9
31
|
Deeper subagent/workflow telemetry.
|
|
@@ -261,6 +283,8 @@ Initial release — the capture engine, extracted from a system in daily product
|
|
|
261
283
|
- `wendkeep init` (cross-platform installer) + optional `@bitbonsai/mcpvault` MCP server.
|
|
262
284
|
|
|
263
285
|
<!-- Only v0.4.0+ is tagged in git (history starts here); older versions link to npm. -->
|
|
286
|
+
[0.14.0]: https://github.com/rogersialves/wendkeep/releases/tag/v0.14.0
|
|
287
|
+
[0.13.0]: https://github.com/rogersialves/wendkeep/releases/tag/v0.13.0
|
|
264
288
|
[0.12.0]: https://github.com/rogersialves/wendkeep/releases/tag/v0.12.0
|
|
265
289
|
[0.11.0]: https://github.com/rogersialves/wendkeep/releases/tag/v0.11.0
|
|
266
290
|
[0.10.0]: https://github.com/rogersialves/wendkeep/releases/tag/v0.10.0
|
package/README.md
CHANGED
|
@@ -39,20 +39,40 @@ npx wendkeep init
|
|
|
39
39
|
|
|
40
40
|
1. Create the vault folder taxonomy and a templated `README.md` (default vault: `<project>/.<project-name>-vault`, e.g. `.MyApp-vault`; override with `--vault`).
|
|
41
41
|
2. **Merge** the three session hooks and `OBSIDIAN_VAULT_PATH` into `.claude/settings.json` — without clobbering your existing settings (a `.bak` is saved; an unparseable file is left untouched and a `.new` is written for you to merge).
|
|
42
|
-
3. Add the
|
|
43
|
-
4. Offer to pin **companion** plugins/MCP (multi-choice; `context-mode`
|
|
42
|
+
3. Add the **`wendkeep-vault`** MCP server to `.mcp.json` so the agent can read/write the vault. Skip with `--no-mcp` — e.g. when the agent already has a vault MCP. (`--no-mcp` skips *only wendkeep's own* MCP; companion MCPs still follow `--companions`.)
|
|
43
|
+
4. Offer to pin **companion** plugins/MCP (multi-choice; only `context-mode` pre-checked). Each is wired the most agent-agnostic way it supports:
|
|
44
|
+
- **`context-mode`** — context optimizer + FTS5 memory, as a `.mcp.json` MCP server (any agent). The recommended default.
|
|
45
|
+
- **`understand-anything`** — project domain graph, via a `understand-inject` SessionStart hook that injects the graph when generated.
|
|
46
|
+
- **`caveman`** — token-compression mode; runs its own cross-agent installer on non-Claude agents.
|
|
47
|
+
- **`dotcontext`** — *legacy, not recommended.* wendkeep's native a2 loop (`change` / `verify` / gate) already does its job, so installing it **duplicates the harness**. Still selectable via `--companions dotcontext` for anyone already invested (tune with `--dotcontext-mcp` / `--dotcontext-hooks`), but off by default.
|
|
48
|
+
|
|
49
|
+
Control with `--companions <csv>` or `--no-companions`. The Claude Code plugin layer (`extraKnownMarketplaces` + `enabledPlugins`) is wired as a bonus where the companion has one.
|
|
44
50
|
5. Install a **color system** into the vault's `.obsidian/`: a CSS snippet that accents notes by type (session/decision/bug/learning, via the `cssclasses` the hooks emit) plus graph color groups by folder. Non-destructive merge into `appearance.json`/`graph.json`; skip with `--no-colors`.
|
|
45
51
|
6. Seed the **curated memory layer**: `.brain/CORE.md` (the hand-curated hot layer, with the 3 required sections) and `.brain/COMPACTION_PROTOCOL.md` (the protocol guide). The auto layers (`DIGEST.md`, `index.jsonl`) are generated by the hooks. Validate the curated layer with `wendkeep validate-memory` (cap 25 lines, 3 sections, no secrets/PII).
|
|
46
52
|
7. Seed the **definitions + skills layer**: `.brain/agents/` + `.brain/skills/` (versioned source of truth), including the native process skills `wk-workflow` / `wk-tdd` / `wk-debugging` / `wk-brainstorming` / `wk-planning`. `init` runs `wendkeep sync-defs` for you, delivering them to `.codex/agents/` + `.claude/skills/` (re‑run `sync-defs` after editing `.brain`).
|
|
47
53
|
8. Seed the **change/spec lifecycle**: the `07-Specs/` + `08-Mudanças/` folders and a native `wendkeep.sensors.json` (a `validate-memory` sensor plus one per detected `package.json` script). Drives `wendkeep change` / `wendkeep verify` — see **Change lifecycle** below.
|
|
48
54
|
|
|
49
55
|
```bash
|
|
50
|
-
npx wendkeep init --vault "~/vaults/work" --project . --yes # non-interactive (
|
|
51
|
-
npx wendkeep init --companions "context-mode,
|
|
52
|
-
npx wendkeep init --no-companions --yes
|
|
56
|
+
npx wendkeep init --vault "~/vaults/work" --project . --yes # non-interactive (default companion: context-mode)
|
|
57
|
+
npx wendkeep init --companions "context-mode,understand-anything" --yes
|
|
58
|
+
npx wendkeep init --no-companions --no-mcp --yes # zero companions, no wendkeep MCP
|
|
53
59
|
```
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
### `init` options
|
|
62
|
+
|
|
63
|
+
| Flag | What it does |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `--vault <path>` | Vault folder. Default `<project>/.<project-name>-vault`; interactive init asks. Point it at an existing vault to install into it. |
|
|
66
|
+
| `--project <path>` | Project root to wire (default: current directory). |
|
|
67
|
+
| `--locale <pt-BR\|en>` | Vault language — folder names, scaffold, skills. Interactive init asks; locked at init. |
|
|
68
|
+
| `--companions <csv>` | Companions to pin: `context-mode,caveman,understand-anything` (default: `context-mode`; `dotcontext` is legacy). |
|
|
69
|
+
| `--no-companions` | Pin no companions. |
|
|
70
|
+
| `--no-mcp` | Skip **wendkeep's own** vault MCP (`wendkeep-vault`). Companion MCPs still follow `--companions`. |
|
|
71
|
+
| `--no-colors` | Skip the Obsidian color system (`.obsidian` snippet + graph groups). |
|
|
72
|
+
| `--yes`, `-y` | Non-interactive; accept defaults (skips the language / vault / companion prompts). |
|
|
73
|
+
| `--force` | Overwrite existing wendkeep config blocks. |
|
|
74
|
+
|
|
75
|
+
Then open the vault in Obsidian, send a test prompt in your agent, and confirm a note appears under `02-Sessões/…` (or `02-Sessions/…` for an `en` vault).
|
|
56
76
|
|
|
57
77
|
## Updating
|
|
58
78
|
|
package/bin/wendkeep.mjs
CHANGED
|
@@ -29,8 +29,8 @@ Usage:
|
|
|
29
29
|
--vault <path> Obsidian vault folder (default: <project>/.<project-name>-vault).
|
|
30
30
|
--project <path> Project root to wire (default: current directory).
|
|
31
31
|
--no-mcp Do not add the mcpvault MCP server to .mcp.json.
|
|
32
|
-
--companions <csv> Companion plugins/MCP to pin: context-mode,
|
|
33
|
-
(default
|
|
32
|
+
--companions <csv> Companion plugins/MCP to pin: context-mode,caveman,understand-anything
|
|
33
|
+
(default: context-mode). dotcontext is legacy — the native a2 loop replaces it.
|
|
34
34
|
--no-companions Skip companion plugins/MCP entirely.
|
|
35
35
|
--no-colors Skip the Obsidian color system (.obsidian snippet + graph groups).
|
|
36
36
|
--dotcontext-mcp <v> dotcontext MCP placement: auto (default; skip project entry
|
package/hooks/subagent-usage.mjs
CHANGED
|
@@ -143,10 +143,15 @@ export function collectSubagentUsage(sessionDir) {
|
|
|
143
143
|
};
|
|
144
144
|
});
|
|
145
145
|
|
|
146
|
+
// Wasted spend: cost of workflow runs that did not complete (killed/failed/…). The
|
|
147
|
+
// subagents that ran before the kill still cost money — this makes that visible.
|
|
148
|
+
const WASTE = /^(killed|failed|error|aborted|cancel(l)?ed)$/i;
|
|
149
|
+
const wasted = round4(workflows.filter((w) => WASTE.test(w.status)).reduce((s, w) => s + w.cost, 0));
|
|
150
|
+
|
|
146
151
|
return {
|
|
147
152
|
subagents,
|
|
148
153
|
workflows,
|
|
149
|
-
aggregate: { count, calls, tokens: tokensTotal(usageAgg), cost: round4(cost), usage: usageAgg, tools: [...allTools] },
|
|
154
|
+
aggregate: { count, calls, tokens: tokensTotal(usageAgg), cost: round4(cost), wasted, usage: usageAgg, tools: [...allTools] },
|
|
150
155
|
};
|
|
151
156
|
}
|
|
152
157
|
|
|
@@ -167,13 +172,14 @@ export function renderSubagentSection(c) {
|
|
|
167
172
|
const rows = c.subagents
|
|
168
173
|
.map((s) => `| ${s.id} | ${s.agentType || '-'} | ${s.workflow || '-'} | ${s.model} | ${s.tools} | ${fmt(s.tokens)} | ${usd(s.cost)} |`)
|
|
169
174
|
.join('\n');
|
|
175
|
+
const wasteLine = a.wasted ? `\n- **Desperdiçado (runs killed/failed):** ${usd(a.wasted)}` : '';
|
|
170
176
|
return `## Subagents & Workflows
|
|
171
177
|
|
|
172
178
|
> Custo de subagents/workflows desta sessão — NÃO incluído no total principal acima.
|
|
173
179
|
|
|
174
180
|
- **Subagents:** ${a.count} · ${a.calls} chamadas · ${fmt(a.tokens)} tokens · ${usd(a.cost)}
|
|
175
181
|
- **Workflows:** ${wf}
|
|
176
|
-
- **Tools (subagents):** ${tools}
|
|
182
|
+
- **Tools (subagents):** ${tools}${wasteLine}
|
|
177
183
|
|
|
178
184
|
<details><summary>Por subagent (${a.count})</summary>
|
|
179
185
|
|
|
@@ -220,6 +226,7 @@ export function upsertSubagentUsage(sessionPath, transcriptPath) {
|
|
|
220
226
|
content = setFrontmatterField(content, 'subagents_tokens_total', a.tokens);
|
|
221
227
|
content = setFrontmatterField(content, 'subagents_custo_usd', a.cost);
|
|
222
228
|
content = setFrontmatterField(content, 'subagents_tools', `"${(a.tools || []).join(', ')}"`);
|
|
229
|
+
content = setFrontmatterField(content, 'subagents_wasted_usd', a.wasted || 0);
|
|
223
230
|
content = setFrontmatterField(content, 'tokens_total_incl_subagents', frontmatterNumber(content, 'tokens_total') + a.tokens);
|
|
224
231
|
content = upsertSection(content, '## Subagents & Workflows', renderSubagentSection(collected));
|
|
225
232
|
writeFileSync(sessionPath, content, 'utf8');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wendkeep",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "A persistent-memory harness for AI coding agents on your Obsidian vault: turn-by-turn session capture plus a native, zero-dependency spec→change→verify→archive loop (sensor-gated, independent verdict, mutation discrimination). Local-first, agent-agnostic (Claude Code, Codex, Cursor…).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/cost.mjs
CHANGED
|
@@ -21,6 +21,7 @@ export function parseSessionCost(content) {
|
|
|
21
21
|
model: fmValue(content, 'custo_modelo_label') || fmValue(content, 'modelo') || '?',
|
|
22
22
|
mainCost: Number(fmValue(content, 'custo_modelo_usd')) || 0,
|
|
23
23
|
subCost: Number(fmValue(content, 'subagents_custo_usd')) || 0,
|
|
24
|
+
wasted: Number(fmValue(content, 'subagents_wasted_usd')) || 0,
|
|
24
25
|
tokens: Number(fmValue(content, 'tokens_total')) || 0,
|
|
25
26
|
subTokens: Number(fmValue(content, 'subagents_tokens_total')) || 0,
|
|
26
27
|
};
|
|
@@ -31,19 +32,22 @@ export function aggregateCosts(entries) {
|
|
|
31
32
|
const byModel = {};
|
|
32
33
|
let main = 0;
|
|
33
34
|
let sub = 0;
|
|
35
|
+
let wasted = 0;
|
|
34
36
|
let tokens = 0;
|
|
35
37
|
let subTokens = 0;
|
|
36
38
|
for (const e of entries) {
|
|
37
|
-
main += e.mainCost; sub += e.subCost; tokens += e.tokens; subTokens += e.subTokens;
|
|
39
|
+
main += e.mainCost; sub += e.subCost; wasted += e.wasted || 0; tokens += e.tokens; subTokens += e.subTokens;
|
|
38
40
|
const d = e.date || '?';
|
|
39
41
|
(byDay[d] = byDay[d] || { cost: 0, count: 0 }).cost += e.mainCost + e.subCost;
|
|
40
42
|
byDay[d].count += 1;
|
|
41
43
|
(byModel[e.model] = byModel[e.model] || { cost: 0, count: 0 }).cost += e.mainCost + e.subCost;
|
|
42
44
|
byModel[e.model].count += 1;
|
|
43
45
|
}
|
|
46
|
+
const total = main + sub;
|
|
44
47
|
return {
|
|
45
48
|
count: entries.length,
|
|
46
|
-
main: round4(main), sub: round4(sub), total: round4(
|
|
49
|
+
main: round4(main), sub: round4(sub), total: round4(total), wasted: round4(wasted),
|
|
50
|
+
avg: round4(entries.length ? total / entries.length : 0),
|
|
47
51
|
tokens, subTokens,
|
|
48
52
|
byDay: Object.entries(byDay).sort().map(([date, v]) => ({ date, cost: round4(v.cost), count: v.count })),
|
|
49
53
|
byModel: Object.entries(byModel).sort((a, b) => b[1].cost - a[1].cost).map(([model, v]) => ({ model, cost: round4(v.cost), count: v.count })),
|
|
@@ -93,8 +97,9 @@ export function runCost(argv) {
|
|
|
93
97
|
|
|
94
98
|
if (argv.includes('--json')) { process.stdout.write(`${JSON.stringify(agg, null, 2)}\n`); process.exit(0); }
|
|
95
99
|
|
|
96
|
-
process.stdout.write(`Custo total (vault): ${usd(agg.total)} — ${agg.count} sessão(ões)\n`);
|
|
100
|
+
process.stdout.write(`Custo total (vault): ${usd(agg.total)} — ${agg.count} sessão(ões) · ${usd(agg.avg)}/sessão\n`);
|
|
97
101
|
process.stdout.write(` main: ${usd(agg.main)} · subagents: ${usd(agg.sub)}\n`);
|
|
102
|
+
if (agg.wasted) process.stdout.write(` desperdiçado (runs killed/failed): ${usd(agg.wasted)}\n`);
|
|
98
103
|
if (agg.byModel.length) {
|
|
99
104
|
process.stdout.write('\nPor modelo:\n');
|
|
100
105
|
for (const m of agg.byModel) process.stdout.write(` ${m.model.padEnd(20)} ${usd(m.cost)} (${m.count})\n`);
|
package/src/taxonomy.mjs
CHANGED
|
@@ -124,8 +124,11 @@ export const COMPANIONS = [
|
|
|
124
124
|
},
|
|
125
125
|
{
|
|
126
126
|
id: 'dotcontext',
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
// Legacy: wendkeep's native a2 loop (change/verify/gate) recreates dotcontext's role,
|
|
128
|
+
// so it is no longer recommended — installing it would duplicate the native harness.
|
|
129
|
+
// Kept selectable for anyone already invested in it; not a default.
|
|
130
|
+
label: 'dotcontext — legado (o loop a2 nativo do wendkeep substitui; não recomendado)',
|
|
131
|
+
default: false,
|
|
129
132
|
// MCP-only (no Claude Code plugin). Agent-agnostic server, @latest surface.
|
|
130
133
|
mcp: { key: 'dotcontext', entry: { type: 'stdio', command: 'npx', args: ['-y', '@dotcontext/mcp@latest'], env: {} } },
|
|
131
134
|
// Lifecycle hooks via the pinned CLI; wired by wendkeep (single writer).
|