geneseed 4.3.1 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +4 -4
  3. package/SHIPPED.md +2 -2
  4. package/adapters/opencode/plugins/geneseed-context.js +18 -1
  5. package/adapters/opencode/plugins/geneseed-learn.js +178 -46
  6. package/docs/concepts/agents.md +1 -0
  7. package/docs/concepts/hooks.md +1 -1
  8. package/docs/concepts/skills.md +1 -0
  9. package/docs/reference/plugin-learn.md +2 -2
  10. package/docs/understand/a-day.md +3 -3
  11. package/docs/understand/machine-claude.md +1 -1
  12. package/docs/understand/machine-opencode.md +1 -1
  13. package/harness.config.json +1 -1
  14. package/js/README.md +1 -1
  15. package/js/build/bundle.mjs +2 -0
  16. package/js/build/emit-claude.mjs +2 -0
  17. package/js/build/emit-opencode.mjs +2 -0
  18. package/js/build/stubs.mjs +9 -4
  19. package/js/cli-table.json +32 -2
  20. package/js/hosts/hooks-context.mjs +25 -1
  21. package/js/hosts/hooks-learn.mjs +42 -16
  22. package/js/hosts/memory-files.mjs +283 -60
  23. package/js/inspect/checks-build.mjs +2 -1
  24. package/js/inspect/cost.mjs +1 -1
  25. package/js/inspect/inventory.mjs +1 -1
  26. package/js/maintain/memory.mjs +38 -11
  27. package/js/web/actions.mjs +4 -3
  28. package/package.json +1 -1
  29. package/registry.json +14 -0
  30. package/src/AGENT.md.tmpl +2 -0
  31. package/src/agents/memory-curator.md +71 -0
  32. package/src/memory/README.md +41 -10
  33. package/src/skills/deck.md +56 -0
  34. package/src/skills/frontend-design.md +1 -0
  35. package/src/skills/geneseed.md +1 -1
  36. package/src/skills/rule/consolidate.md +18 -11
  37. package/src/skills/rule.md +9 -6
  38. package/themes/_TEMPLATE.json +2 -0
  39. package/themes/biker.json +2 -0
  40. package/themes/commentator.json +2 -0
  41. package/themes/cyberpunk.json +2 -0
  42. package/themes/gamer.json +2 -0
  43. package/themes/imperial.json +2 -0
  44. package/themes/joker.json +2 -0
  45. package/themes/marvin.json +2 -0
  46. package/themes/mean.json +2 -0
  47. package/themes/military.json +2 -0
  48. package/themes/neutral.json +2 -0
  49. package/themes/pirate.json +2 -0
  50. package/themes/sports.json +2 -0
  51. package/themes/verstappen.json +2 -0
  52. package/themes/wizard.json +2 -0
  53. package/web/dist/assets/{Activity-UiGvYgEl.js → Activity-BZE6REef.js} +1 -1
  54. package/web/dist/assets/{ActivityDetail-COXCSeXn.js → ActivityDetail-DCB8Cr2W.js} +1 -1
  55. package/web/dist/assets/{Dashboard-DkdOUpke.js → Dashboard-B4Drq5wp.js} +2 -2
  56. package/web/dist/assets/{Docs-TtVyc_Dy.js → Docs-D30CiqYy.js} +1 -1
  57. package/web/dist/assets/{GreenhouseView-Bh0xq6Up.js → GreenhouseView-Djt-4oO5.js} +1 -1
  58. package/web/dist/assets/{Installs-J3IoSqk6.js → Installs-B3bw5ckh.js} +1 -1
  59. package/web/dist/assets/{JournalView-BrD33V35.js → JournalView-OWhx9YKg.js} +1 -1
  60. package/web/dist/assets/{Laws-Cjkenizx.js → Laws-B9day2FV.js} +1 -1
  61. package/web/dist/assets/Library-BpIrLH-O.js +1 -0
  62. package/web/dist/assets/{Loops-D15LDhZO.js → Loops-CxH14kyE.js} +1 -1
  63. package/web/dist/assets/{OperatorHudView-B5CcWoJ6.js → OperatorHudView-otOz6Gha.js} +1 -1
  64. package/web/dist/assets/{Personal-BBdGbJn6.js → Personal-abL6089y.js} +1 -1
  65. package/web/dist/assets/{Tabs-s8T501po.js → Tabs-DjWN0i7A.js} +1 -1
  66. package/web/dist/assets/{drawable-DALqyS4l.js → drawable-C2ZsBZCv.js} +1 -1
  67. package/web/dist/assets/{index-BP4foUp0.js → index-CdpLpPQN.js} +2 -2
  68. package/web/dist/index.html +1 -1
  69. package/web/dist/assets/Library-CKyeB096.js +0 -1
@@ -25,11 +25,16 @@
25
25
  *
26
26
  * `memoryDropIndex` is the hook module's, not a copy: writing the fact and unwriting its
27
27
  * index line are two halves of one format, and the half that writes lives there.
28
+ *
29
+ * `rm` ARCHIVES BY DEFAULT. A removed fact moves into `archive/` (`archiveFact`, the helper
30
+ * learn uses), so a slip of the keyboard or a click in the console is reversible; only
31
+ * `--purge` unlinks. `--archived` points `list` and `rm` at `archive/` itself, and a file
32
+ * there can only be purged — it has nowhere further to go.
28
33
  */
29
34
  import { readdirSync, unlinkSync } from 'node:fs';
30
35
  import path from 'node:path';
31
36
 
32
- import { memoryDropIndex } from '../hosts/memory-files.mjs';
37
+ import { archiveFact, memoryDropIndex } from '../hosts/memory-files.mjs';
33
38
  import { resolveMemoryDir } from '../hosts/hosts.mjs';
34
39
  import { printOut, printErr, isFile } from '../lib/fs.mjs';
35
40
 
@@ -58,13 +63,28 @@ export function memoryFacts(dir) {
58
63
  .map((n) => n.slice(0, -3)).filter(isFactName).sort();
59
64
  }
60
65
 
61
- /** `api_memory_delete`, minus the HTTP: the file, then its line in the index. */
62
- export function memoryDelete(dir, name) {
63
- if (!isFactName(name)) return false;
66
+ /**
67
+ * Take a fact out of the store and its line out of the index. Archived into `archive/` unless
68
+ * `purge`, which unlinks it. Returns where it went (the archive path, or '' when purged), or
69
+ * null when `name` is not a fact here.
70
+ */
71
+ export function memoryDelete(dir, name, purge = false) {
72
+ if (!isFactName(name)) return null;
64
73
  const p = path.join(dir, `${name}.md`);
74
+ if (!isFile(p)) return null;
75
+ let dest = '';
76
+ if (purge) unlinkSync(p);
77
+ else dest = archiveFact(dir, name);
78
+ memoryDropIndex(dir, name);
79
+ return dest;
80
+ }
81
+
82
+ /** Unlink `archive/<name>.md`. True when a file went. The archive has no index to update. */
83
+ export function memoryPurgeArchived(dir, name) {
84
+ if (!isFactName(name)) return false;
85
+ const p = path.join(dir, 'archive', `${name}.md`);
65
86
  if (!isFile(p)) return false;
66
87
  unlinkSync(p);
67
- memoryDropIndex(dir, name);
68
88
  return true;
69
89
  }
70
90
 
@@ -78,13 +98,14 @@ export function cmdMemory(args) {
78
98
  + 'or run this from a directory with a memory/ store.\n');
79
99
  return 1;
80
100
  }
101
+ const where = args.archived ? path.join(dir, 'archive') : dir;
81
102
  if (args.action === 'list') {
82
- const facts = memoryFacts(dir);
103
+ const facts = memoryFacts(where);
83
104
  if (!facts.length) {
84
- printOut(`[memory] ${dir}: no facts.\n`);
105
+ printOut(`[memory] ${where}: no facts.\n`);
85
106
  return 0;
86
107
  }
87
- printOut(`[memory] ${dir}\n`);
108
+ printOut(`[memory] ${where}\n`);
88
109
  for (const name of facts) printOut(` ${name}\n`);
89
110
  return 0;
90
111
  }
@@ -92,14 +113,20 @@ export function cmdMemory(args) {
92
113
  printErr('[memory] rm needs the name of a fact.\n');
93
114
  return 2;
94
115
  }
95
- if (!memoryDelete(dir, args.name)) {
116
+ if (args.archived && !args.purge) {
117
+ printErr('[memory] an archived fact can only be purged: add --purge to delete it.\n');
118
+ return 2;
119
+ }
120
+ const done = args.archived ? (memoryPurgeArchived(dir, args.name) ? '' : null)
121
+ : memoryDelete(dir, args.name, Boolean(args.purge));
122
+ if (done === null) {
96
123
  // ONE MESSAGE FOR BOTH REFUSALS, which is the endpoint's shape too — it raises the same
97
124
  // `NotFound(name)` for a reserved name, a name with a separator and a fact that is not
98
125
  // there. Telling a caller that `MEMORY` exists but is protected is a distinction this
99
126
  // verb has no reason to draw.
100
- printErr(`[memory] no such fact '${args.name}' in ${dir}.\n`);
127
+ printErr(`[memory] no such fact '${args.name}' in ${where}.\n`);
101
128
  return 1;
102
129
  }
103
- printOut(`[memory] deleted ${args.name}.\n`);
130
+ printOut(done ? `[memory] archived ${args.name} -> ${done}\n` : `[memory] deleted ${args.name}.\n`);
104
131
  return 0;
105
132
  }
@@ -276,7 +276,8 @@ export function apiPickFolder(done) {
276
276
  // ---- memory ------------------------------------------------------------------------------
277
277
 
278
278
  /**
279
- * One fact file, and its line in the MEMORY.md index.
279
+ * One fact file, and its line in the MEMORY.md index. The file is ARCHIVED into
280
+ * `memory/archive/`, never unlinked: the console has no purge, `geneseed memory rm --purge` does.
280
281
  *
281
282
  * `name` is a BARE SLUG: a path separator, or one of the two reserved names, is refused, so
282
283
  * this can only ever remove a fact inside the resolved memory dir. MEMORY.md is the index the
@@ -290,9 +291,9 @@ export function apiMemoryDelete(state, name) {
290
291
  // `memoryDelete` is the `geneseed memory rm` engine, and its reserved-name check is
291
292
  // CASE-FOLDED: this endpoint's own compared `MEMORY` exactly, so on Windows and macOS `memory`
292
293
  // resolved to MEMORY.md, passed, and deleted the index the agent reads at session start.
293
- if (!memoryDelete(d, name)) throw new NotFound(name);
294
+ if (memoryDelete(d, name) === null) throw new NotFound(name);
294
295
  state.refresh();
295
- return { deleted: name };
296
+ return { archived: name };
296
297
  }
297
298
 
298
299
  // ---- sovereign-repo exclusions -------------------------------------------------------------
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//": "Every field here is argued and gated in tests/unit/package_manifest.test.mjs. `files`, `bin` and `engines` each have a test that fails when reality drifts from this file; `version` mirrors harness.config.json and is gated too. Read that docblock before editing this one.",
3
3
  "name": "geneseed",
4
- "version": "4.3.1",
4
+ "version": "4.4.1",
5
5
  "description": "A portable, theme-able harness you implant once and use everywhere to grow a disciplined AI coding agent.",
6
6
  "keywords": [
7
7
  "ai",
package/registry.json CHANGED
@@ -57,6 +57,13 @@
57
57
  "added": "2026-06-08",
58
58
  "last_verified": ""
59
59
  },
60
+ "agents/memory-curator": {
61
+ "status": "experimental",
62
+ "version": "1.0.0",
63
+ "owner": "Guillaume Lemer",
64
+ "added": "2026-10-16",
65
+ "last_verified": ""
66
+ },
60
67
  "agents/operator": {
61
68
  "status": "approved",
62
69
  "version": "1.0.0",
@@ -190,6 +197,13 @@
190
197
  "added": "2026-06-03",
191
198
  "last_verified": "2026-09-06"
192
199
  },
200
+ "skills/deck": {
201
+ "status": "experimental",
202
+ "version": "1.0.0",
203
+ "owner": "Guillaume Lemer",
204
+ "added": "2026-10-16",
205
+ "last_verified": ""
206
+ },
193
207
  "skills/dependencies": {
194
208
  "status": "approved",
195
209
  "version": "1.0.0",
package/src/AGENT.md.tmpl CHANGED
@@ -166,6 +166,7 @@ Active packs: {{DOCTRINES_LIST}}{{EXCLUDED_RULES_LINE}}
166
166
  | [performance]({{DIR_AGENTS}}/performance.md) | something is reported slow or heavy, or a diff touches a hot path — measured, never guessed |
167
167
  | [explorer]({{DIR_AGENTS}}/explorer.md) | you must sweep many files for an answer but only want the conclusion |
168
168
  | [researcher]({{DIR_AGENTS}}/researcher.md) | a question needs the open web — fetched, cross-checked, and returned as sourced findings, not pages |
169
+ | [memory-curator]({{DIR_AGENTS}}/memory-curator.md) | the {{MEMORY}} store needs bulk curation |
169
170
  | [advocate]({{DIR_AGENTS}}/advocate.md) | a council debate needs the strongest case **for** the motion argued in isolation |
170
171
  | [skeptic]({{DIR_AGENTS}}/skeptic.md) | a council debate needs a devil's advocate to attack the motion's failure modes |
171
172
  | [pragmatist]({{DIR_AGENTS}}/pragmatist.md) | a council debate needs the cost, effort, and complexity weighed against the payoff |
@@ -255,6 +256,7 @@ the ten council seats are convened by the [council {{SKILL}}]({{DIR_SKILLS}}/cou
255
256
  | [bruno]({{DIR_SKILLS}}/bruno.md) | creating, converting, or testing a Bruno API collection — requests, environments, assertions, chaining — from routes, OpenAPI, curl, or an endpoint list |
256
257
  | [prose]({{DIR_SKILLS}}/prose.md) | writing prose for a human — a commit body, PR, doc, comment, memory note, or reply — that should not read like a model wrote it |
257
258
  | [frontend-design]({{DIR_SKILLS}}/frontend-design.md) | building or reshaping a UI that should carry a deliberate point of view, not a templated default |
259
+ | [deck]({{DIR_SKILLS}}/deck.md) | a presentation, slides or a deck with no file format named — one offline HTML file |
258
260
  | [handoff]({{DIR_SKILLS}}/handoff.md) | context filling, or passing work to another agent or session |
259
261
  | [roast-me]({{DIR_SKILLS}}/roast-me.md) | you want your own ask, plan or idea torn apart, brutally and actionably (code goes to code review) |
260
262
  | [council]({{DIR_SKILLS}}/council.md) | a decision, change, or discussion needs debating from several points of view before committing |
@@ -0,0 +1,71 @@
1
+ # {{AGENT}}: memory-curator
2
+
3
+ > {{DESC_MEMORY_CURATOR}}
4
+
5
+ ## When to dispatch
6
+ - The {{MEMORY}} store needs tidying in bulk. The session context says so in one
7
+ line when a topic holds over 40 facts or a `misc` topic exists; or the user asks
8
+ to tidy, dedupe or re-topic their memory.
9
+ - `geneseed learn --consolidate` reported duplicate descriptions that need a merge.
10
+
11
+ ## When NOT to dispatch
12
+ - A handful of facts to review — the rule {{SKILL}}'s consolidation flow does
13
+ it in the main session.
14
+ - Writing one new fact, or promoting a lesson into `user-rules.md` — that is the
15
+ rule {{SKILL}}.
16
+
17
+ ## Inputs
18
+ - The path of the {{MEMORY}} store (`{{DIR_MEMORY}}/`), and the user's standing on
19
+ scope: the whole store, or named topics only.
20
+
21
+ ## Allowed tools
22
+ - **Read + write to the {{MEMORY}} store only.** May run `geneseed memory` and
23
+ `geneseed learn --consolidate`. A write into the store may stop for the user's consent
24
+ at the tool boundary, so it batches its edits per topic behind one plan.
25
+ <!-- bash: allow -->
26
+ - Moves a fact out with `geneseed memory rm <name>`, which archives it — never a raw
27
+ `mv` or `rm` past that gate. Deletes only with `--purge`, and only what the user
28
+ approved by code ({{LAW:deletion-is-deliberate}}).
29
+
30
+ ## Procedure
31
+ 0. If `{{DIR_MEMORY}}/agents/<your-name>.md` exists, read it first — your durable lessons from prior dispatches ({{DOCTRINE:persist-insight}}).
32
+ 1. Read the map (`MEMORY.md`), then one topic file at a time, then only the facts
33
+ that topic needs ({{DOCTRINE:context-economy}}). On a large store, work topic by
34
+ topic and report progress after each one (`3/14 topics: 4 merged, 2 archived`).
35
+ 2. For each topic, verify and classify its facts as the
36
+ rule {{SKILL}}'s consolidation flow does (verify, classify, apply with consent):
37
+ keep, merge, rewrite, promote or retire. Show the topic's plan, then apply it.
38
+ 3. **Merge** overlapping facts into one survivor that keeps both `**Why:**` /
39
+ `**How to apply:**` lines and both sets of `[[links]]`; archive the merged-away
40
+ file with `geneseed memory rm`.
41
+ 4. **Topic** every fact lacking `topic:`: reuse an existing topic before inventing
42
+ one, keep the store to about 10-25 topics, never name a topic `misc` or after a
43
+ bare `type`, and split a topic past 40 facts into narrower ones.
44
+ 5. **Archive** what is stale — a finished project's status log, a superseded
45
+ decision — with `geneseed memory rm`. A fact carrying `force:` is never merged,
46
+ re-topicked or archived without the user's ruling (the Bridge rule in
47
+ `{{DIR_MEMORY}}/README.md`).
48
+ 6. **Propose deletion** of archived facts nobody will need again
49
+ (`geneseed memory list --archived`), as a coded list (`P1 old-sprint-log — why`),
50
+ and run `geneseed memory rm <name> --archived --purge` only for the codes the user
51
+ approves. A fact holding a secret, live or archived, is proposed for `--purge` on sight
52
+ ({{LAW:sealed-secrets}}).
53
+ 7. Finish with `geneseed learn --consolidate --memory <the store's path>`, so both
54
+ index levels match the files.
55
+
56
+ ## Output contract
57
+ - Counts — merged / re-topicked / archived / purged / left as-is — the topic list
58
+ before and after, the consolidate output verbatim, and the open deletion
59
+ proposals still awaiting the user.
60
+ - If the store cannot be written (consent refused, a path outside the store), stop
61
+ and report what was planned and what was applied — never a partial merge left
62
+ unreported ({{LAW:surface-failures}}).
63
+
64
+ ## Self-improvement
65
+
66
+ If this spec misled you — an input you needed but were not given, a boundary
67
+ that proved wrong, a step you could not execute — end your report with one line:
68
+ `spec-feedback: <what failed — the one-line fix>`. Omit it when there is no
69
+ friction. The caller weighs the feedback, folds a real flaw back into this file
70
+ with the user's assent, and records it to {{MEMORY}} only if it clears
71
+ {{DOCTRINE:persist-insight}}'s bar — most reports carry no feedback at all.
@@ -7,8 +7,8 @@
7
7
  > it in code, docs, or the project's `user-rules.md` instead.)
8
8
 
9
9
  Durable knowledge that must survive across sessions lives here as **one fact per
10
- file**. An agent reads `MEMORY.md` (the local index it creates) at the start of a
11
- session. A new fact is written through the rule {{SKILL}}, which settles with the user
10
+ file**. An agent reads `MEMORY.md` (the local index map) at the start of a session,
11
+ and opens the topic file a task needs (see *The index* below). A new fact is written through the rule {{SKILL}}, which settles with the user
12
12
  whether it is a fact for here or a standing rule ({{DOCTRINE:persist-insight}}) — never on the
13
13
  agent's own initiative. The one automatic writer is the `learn` hook, where the host
14
14
  runs it: a distiller the user opted into at install, not an agent's judgement call.
@@ -26,6 +26,7 @@ Each memory is a Markdown file with frontmatter:
26
26
  name: <short-kebab-case-slug>
27
27
  description: <one-line summary — used to judge relevance during recall>
28
28
  type: user | feedback | project | reference
29
+ topic: <kebab-case-slug> # optional; index group, defaults to type
29
30
  force: constraint | choice | conviction | tempered # optional
30
31
  ---
31
32
 
@@ -66,25 +67,55 @@ firmly it binds. Absent `force`, a memory is a plain fact under the rules below.
66
67
  inline (the date, what changed, and why) rather than deleting the history. The one
67
68
  exception: a `constraint` is not the agent's to overturn — surface the
68
69
  contradiction to the user and let them rule, then record their decision (often as
69
- a `tempered` memory). A memory with no `force` follows the ordinary "delete a
70
- memory that turns out to be wrong" rule.
70
+ a `tempered` memory). A memory with no `force` follows the ordinary "archive a
71
+ memory that turns out to be wrong" rule. The `learn` hook never updates or archives a
72
+ memory that carries a `force`; revising one stays with the agent and the user.
71
73
 
72
74
  ## Rules
73
75
 
74
76
  - One fact per file. Before creating, check for an existing file that covers it
75
- and update that instead — no duplicates.
76
- - Delete a memory that turns out to be wrong.
77
+ and update that instead, merging in what is new and keeping what is still true —
78
+ no duplicates. The `learn` hook does the same: it is shown every stored fact and
79
+ updates one (`action: update`) rather than writing a twin. It sees only each
80
+ fact's description, so it first moves the old version into `archive/`: every
81
+ update can be undone.
82
+ - Archive a memory that turns out to be wrong or obsolete: move it into `archive/`
83
+ (`learn` does it with `action: archive`). An archived fact leaves the index but
84
+ stays on disk, under a `-2`, `-3`, … name if `archive/` already holds one of that
85
+ name. `geneseed memory rm <name>` archives the same way. Deleting a file from
86
+ `archive/` needs the user's consent ({{LAW:deletion-is-deliberate}}):
87
+ `geneseed memory list --archived`, then `geneseed memory rm <name> --archived --purge`.
88
+ `archive/` is part of this git-ignored store.
89
+ - When the store outgrows one careful read — a topic over 40 facts, or facts in
90
+ `misc` — the session context says so in one line; the memory-curator {{AGENT}} then
91
+ merges, assigns topics and archives in bulk, and proposes deletions for approval.
77
92
  - Don't store what the repo already records (code structure, git history, the
78
93
  {{LAWS}}, `user-rules.md`). Store what was *non-obvious*.
79
94
  - When the same `feedback` lesson keeps recurring, propose promoting it into a
80
95
  standing rule in `user-rules.md` (the rule {{SKILL}}) — with the user's
81
- consent, and delete or archive the memory once promoted so the lesson is not
82
- loaded twice.
83
- - After writing a file, add one line to `MEMORY.md`:
84
- `- [Title](file.md) — one-line hook`.
96
+ consent, and archive the memory once promoted so the lesson is not loaded twice.
97
+ - After writing a file, rebuild the index (*The index* below) rather than editing it
98
+ by hand — its counts are derived.
85
99
  - Verify a recalled memory still matches reality before acting on it
86
100
  ({{LAW:verify-before-asserting}}).
87
101
 
102
+ ## The index
103
+
104
+ The index has two levels, so the part loaded every session stays small however many
105
+ facts the store holds:
106
+
107
+ - `MEMORY.md` — the map: one line per topic, `- [<topic>](topics/<topic>.md) — <N> facts`.
108
+ - `topics/<topic>.md` — one line per fact in that topic,
109
+ `- [Title](../file.md) — one-line hook`.
110
+
111
+ A fact's topic is its `topic:`, else its `type:`, else `misc`, normalised to
112
+ lowercase `[a-z0-9-]`. Both levels are generated from the fact files:
113
+ `geneseed learn --consolidate --memory <this dir>` rebuilds them (refreshing each
114
+ hook from its `description`), and the `learn` hook rebuilds them after every fact it
115
+ writes, updates or archives. Only top-level fact files are indexed; `archive/` and
116
+ `agents/` never are. A build moves a flat, one-line-per-fact `MEMORY.md` from an older install to
117
+ this layout once, keeping each line's own title and hook; it never touches a fact file.
118
+
88
119
  ## Per-{{AGENT}} memory (`agents/` subdirectory)
89
120
 
90
121
  Beyond the shared store above, each capability {{AGENT}} may hold its own durable
@@ -0,0 +1,56 @@
1
+ # {{SKILL}}: deck
2
+
3
+ > {{DESC_DECK}}
4
+ <!-- aliases: slides, presentation -->
5
+
6
+ **Trigger:** the user asks for a presentation, slides or a deck without naming a file format.
7
+ An explicit `.pptx` request belongs to the host's pptx skill. To change an existing deck, edit
8
+ its HTML file in place rather than regenerating it.
9
+
10
+ ## Procedure
11
+ 1. **Interview, one question at a time**, each with a recommended default the user can accept
12
+ with "ok": subject and source; audience (technical peers); goal — inform, convince, train,
13
+ report (inform); length as duration or slide count (~10); style — sober, editorial, dark
14
+ technical, playful, or an imposed brand's colours and logo (sober, follows system light/dark);
15
+ usage — projected live, read alone, or both (both); speaker notes (no); PDF export (yes);
16
+ density (from usage: projected 1-3 bullets a slide, read alone 4-8); a browser render check
17
+ (only if asked). Given a source or outline, skip what it answers, batch the rest in one
18
+ message, and go to step 2.
19
+ 2. **Propose the outline** — parts and one line per slide — and generate only once the user
20
+ validates or corrects it. Write the slides in the user's language unless asked otherwise.
21
+ 3. **Write the whole deck by hand as ONE self-contained file** — no bundled shell, no CDN, no
22
+ external script; all CSS and JS inline:
23
+ - A fixed 1920x1080 stage scaled uniformly to the window, letterboxed, never reflowed; each
24
+ slide a `<section>` with that fixed size, never `height: auto`. Inactive slides hidden with
25
+ `visibility`/`opacity`, not layout tricks.
26
+ - Keys ←/→, Space, PageUp/PageDown, Home/End, and touch swipe; the URL hash `#N` tracks the
27
+ slide, with back/forward working.
28
+ - `@media print` plus `@page` size so each slide prints as one page (`@page` size is Baseline
29
+ 2024; animations never reach the PDF).
30
+ - Speaker notes in `<aside class="notes">`, hidden, toggled with N.
31
+ - A system font stack; a web font only with a system fallback, so the deck degrades offline.
32
+ - Diagrams as inline SVG; raster images base64 only when small (base64 adds ~33%).
33
+ - Colours as `:root` variables with a `prefers-color-scheme: dark` set and checked contrast;
34
+ one real heading per slide in a sane order; `prefers-reduced-motion` honoured; animations
35
+ off unless asked for.
36
+ - Palette, type and avoiding templated defaults: follow the
37
+ [frontend-design {{SKILL}}](../{{DIR_SKILLS}}/frontend-design.md) — not repeated here.
38
+ 4. **Write** `<slug>.html` in the working directory unless the user gives a path; ask before
39
+ overwriting an existing file. Open it in the default browser with the platform's opener
40
+ (`open`, `xdg-open`, or `start ""` on Windows).
41
+ 5. **Verify.** By default, hold every slide to the density limit and say plainly that the render
42
+ was not checked. Only on request, open the deck in a browser the host offers (Chrome MCP,
43
+ Orca browser, Playwright) and run this — it works because inactive slides keep their layout:
44
+ ```js
45
+ [...document.querySelectorAll('section')].map((s, i) => [i + 1, s])
46
+ .filter(([, s]) => s.scrollHeight > s.clientHeight || s.scrollWidth > s.clientWidth)
47
+ .map(([i]) => i)
48
+ ```
49
+ Fix each flagged slide and re-run, two repair rounds at most ({{DOCTRINE:bound-the-loop}}).
50
+ 6. Reply in one line: the file, slide count, ←/→ to move, N for notes, Ctrl+P for PDF.
51
+
52
+ ## Done when
53
+ - One offline HTML file opens in the browser, navigates by key, swipe and hash, prints one slide
54
+ per page, and the reply states whether the render was checked.
55
+
56
+ <!-- INCLUDE: skills/_self-improvement.md -->
@@ -4,6 +4,7 @@
4
4
 
5
5
  **Trigger:** building a new UI or reshaping an existing one, and it should carry a
6
6
  deliberate point of view rather than read as a templated default.
7
+ A presentation or slide deck goes to the [deck {{SKILL}}](../{{DIR_SKILLS}}/deck.md).
7
8
 
8
9
  **Requires:** a way to render and screenshot the result (a browser or the host's
9
10
  preview tool) — the second-pass critique in step 6 cannot run without one.
@@ -10,7 +10,7 @@
10
10
  2. **Read state** with the read-only verbs, cheapest first ({{DOCTRINE:context-economy}}): `geneseed status --json`, `geneseed version`, `geneseed catalog` (optionally `agents|skills|laws|ontology|doctrines`), `geneseed doctor`, `geneseed diff`, `geneseed mcp`, `geneseed memory list`, `geneseed exclude list`.
11
11
  3. **Read a piece** from disk, not from recall ({{LAW:verify-before-asserting}}): `<root>/agents/<name>.md`, `<root>/skills/<name>/SKILL.md`, `<root>/memory/`, `<root>/notebook/`. The {{ONTOLOGY}}, the {{LAWS}} and the active {{DOCTRINES}} are numbered `## N. …` sections of the install's root file.
12
12
  4. **Change an install only when the user asked for that change** ({{LAW:one-intent-one-act}}). Take that install's `rebuild` command from step 1, edit only the flag the user named (add it if the command omits it — `--posture`, `--mode` and `--trust` are left out at their defaults) — `--theme`, `--footprint lean|full`, `--posture`, `--mode direct|foreman`, `--trust prudent|balanced|aggressive`, `--doctrines craft,rigor|none`, `--exclude-rules "process 7"|none` — dry-run it first by running the same flags through `geneseed validate`, show the command, and run it once the user agrees. Never rebuild from a bare `geneseed build`: every omitted flag resets that setting to the generator default. Confirm with `geneseed status`.
13
- 5. **Other writes also need the user's word:** `geneseed memory rm <name>`, `geneseed exclude add|remove <path>`, `geneseed web start|stop`, `geneseed uninstall --target <root> --yes`. Personal rules and the profile belong to their own {{SKILLS}}; do not edit `user-rules.md` or `PROFILE.md` from here.
13
+ 5. **Other writes also need the user's word:** `geneseed memory rm <name>` (archives; `--purge` deletes for good), `geneseed exclude add|remove <path>`, `geneseed web start|stop`, `geneseed uninstall --target <root> --yes`. Personal rules and the profile belong to their own {{SKILLS}}; do not edit `user-rules.md` or `PROFILE.md` from here.
14
14
  6. **Never on your own initiative:** `geneseed setup` (interactive only), `geneseed upgrade`, `geneseed update`, `geneseed bootstrap`, `geneseed sync-self`, `geneseed rebuild-all`, `geneseed migrate`, `geneseed link`, `geneseed unlink`. `learn`, `context` and the `*-gate` verbs are `geneseed-hook` verbs the host's hooks run — never run them by hand.
15
15
  7. Directory and section names are plain English in every theme; only prose changes. Do not search by flavour words.
16
16
  8. **Custom OpenCode colour theme** (a different concept from the `--theme` package name in step 4 — that one changes the agent's *voice*, this one its terminal colours): clone a shipped palette (`catppuccin tokyonight rosepine gruvbox nord everforest kanagawa dracula`) or derive one from a described vibe, filling all 19 roles in `themes/opencode/README.md` (`bg bgPanel bgElement fg fgMuted accent secondary border ok warn err kw str fn num type comment addBg delBg`) as `#rrggbb` hex. Keep `fg` on `bg` readable (~7:1), `error` red-family, `warning` amber, `success` green, and `addBg`/`delBg` distinct from each other and the background. Write the overrides to a small JSON (`{role: "#hex", …}` or `{"palette": {…}}`) and run `geneseed theme <name> --from <shipped> --palette <file.json>` — either flag alone works, both together lets the palette override the cloned base; `--solid-only`/`--transparent-only` for one flavour, `--global` to force the global dir from inside a repo. Tell the user to select it with `/theme geneseed-<name>` (opaque) or `/theme geneseed-<name>-transparent` (terminal background shows through) — a rebuild never erases it.
@@ -1,9 +1,11 @@
1
1
  # {{SKILL}}: rule — consolidation flow
2
2
 
3
- Tends the {{MEMORY}} set as a whole.
3
+ Tends the {{MEMORY}} set as a whole. A store too large for one careful read (a
4
+ topic over 40 facts, or a `misc` topic) goes to the memory-curator {{AGENT}}
5
+ instead: it runs this flow topic by topic in its own context and also assigns topics.
4
6
 
5
- 1. **Read the whole set once**: `MEMORY.md`, every file it indexes, and any file in
6
- `{{DIR_MEMORY}}/` it forgot, into a scratch table — name, type, the claim in one
7
+ 1. **Read the whole set once**: `MEMORY.md`, its `topics/` files, every fact they
8
+ index, and any file in `{{DIR_MEMORY}}/` they forgot, into a scratch table — name, type, the claim in one
7
9
  line, date written, and whether this session already saw it contradicted
8
10
  ({{DOCTRINE:context-economy}}: read to decide, not to reread).
9
11
  2. **Verify against the live repo, not memory** ({{LAW:verify-before-asserting}}): every path,
@@ -14,19 +16,24 @@ Tends the {{MEMORY}} set as a whole.
14
16
  (the fact drifted — fix the claim, keep the lesson), *promote* (a `feedback` lesson
15
17
  that fired three times or more goes through Branch B of the rule {{SKILL}}), *retire* (wrong, superseded,
16
18
  or re-derivable by a fresh read). In doubt between keep and retire, keep and date it.
17
- 4. **Show the plan, apply it with consent** ({{LAW:deletion-is-deliberate}} — retirement is
18
- deletion). Merges keep both parents' `[[links]]`; rewrites keep the file name so
19
+ 4. **Show the plan, apply it with consent** ({{LAW:deletion-is-deliberate}}). To retire is to
20
+ archive: move the file into `{{DIR_MEMORY}}/archive/`, never delete it; deleting a file
21
+ from `archive/` is a further act that needs its own consent. A merge archives the
22
+ file that did not survive. Merges keep both parents' `[[links]]`; rewrites keep the file name so
19
23
  inbound links hold; every survivor keeps valid frontmatter and the `**Why** / **How
20
- to apply**` lines its type demands. A memory holding a secret is retired on sight
24
+ to apply**` lines its type demands. A memory holding a secret is the exception:
25
+ archiving would keep it on disk, so propose deleting it outright, on sight
21
26
  ({{LAW:sealed-secrets}}).
22
- 5. **Rebuild `MEMORY.md`**: exactly one pointer line per surviving file, each with a
23
- hook saying why a future session would open it — lost entries added, retired ones
24
- removed, compaction archive lines kept short, no memory content.
27
+ 5. **Rebuild the index** with
28
+ `geneseed learn --consolidate --memory <the {{DIR_MEMORY}}/ dir's path>`: one pointer line per
29
+ surviving file in its `topics/<topic>.md`, and the `MEMORY.md` map recounted. Each
30
+ hook is the fact's `description`, so sharpen a weak hook there — it should say why a
31
+ future session would open the fact.
25
32
  6. **Exit with a count** — kept / merged / rewritten / promoted / retired — and the
26
33
  one or two lessons the pass surfaced (a category that keeps drifting, a kind of
27
34
  note nobody reads) as a proposal for how memories get written, not as a memory.
28
35
 
29
36
  ## Done when
30
37
  - Every memory was verified against the live repo, changes
31
- were applied with consent, no secret remains, and `MEMORY.md` indexes the directory
32
- exactly, one line per file.
38
+ were applied with consent, no secret remains, and the index (`MEMORY.md` and its
39
+ `topics/`) covers the directory exactly, one line per file.
@@ -24,8 +24,9 @@ session; a memory records something *true* that would otherwise be lost or
24
24
  re-derived. Then take exactly one branch.
25
25
 
26
26
  ### Branch A — a fact to remember
27
- 1. Search {{MEMORY}} for a file that already covers it. If one exists, update that
28
- file — never mint a twin.
27
+ 1. Search {{MEMORY}} for a file that already covers it. If one exists, merge into it —
28
+ keep what is still true, add or correct the rest — never mint a twin. If the new
29
+ fact proves the old one wrong, archive the old one (move it into `archive/`).
29
30
  2. Ask which **binding force** the fact carries, in plain words, not jargon:
30
31
  *imposed by you, not mine to relax* (`constraint`) · *a choice taken among real
31
32
  alternatives* (`choice`) · *a stance I hold until evidence overturns it*
@@ -33,7 +34,9 @@ re-derived. Then take exactly one branch.
33
34
  3. Infer the `type` (`user` | `feedback` | `project` | `reference`), draft the file
34
35
  per the {{MEMORY}} convention, and **show the exact content, frontmatter
35
36
  included** — so a wrong inference is visible before it is written, not after.
36
- 4. On the user's word, write the file and add its one-line entry to `MEMORY.md`.
37
+ 4. On the user's word, write the file and rebuild the index
38
+ (`geneseed learn --consolidate --memory <the {{DIR_MEMORY}}/ dir's path>`) so its line
39
+ lands in `topics/<topic>.md` and the `MEMORY.md` map recounts.
37
40
 
38
41
  ### Branch B — a standing rule
39
42
  1. **Triage.** A rule earns its place only if it is all three of: *standing
@@ -74,8 +77,8 @@ re-derived. Then take exactly one branch.
74
77
  `source:` to the memory's name and add `trial until:` about a month out — a
75
78
  promoted rule starts on probation.
76
79
  7. Show the exact text to the user and wait for explicit consent ({{LAW:deletion-is-deliberate}}) before
77
- appending it. For a promotion, after the rule lands, delete or archive the source
78
- memory (with the same consent) so the lesson is not loaded twice.
80
+ appending it. For a promotion, after the rule lands, archive the source memory into
81
+ `archive/` (with the same consent) so the lesson is not loaded twice.
79
82
  8. **Keep the set lean.** After writing, if the file holds more than ~15 rules or
80
83
  any rule no longer changes behaviour, say so and propose merges or prunes — every
81
84
  rule is loaded every session, and a bloated set dilutes the rules that matter.
@@ -93,7 +96,7 @@ adoption.
93
96
 
94
97
  ## Done when
95
98
  - For a rule or memory: the fork was put to the user, and then either a {{MEMORY}} file exists carrying its
96
- `force`, its `type` and its `MEMORY.md` line — or a rule stands in the right
99
+ `force`, its `type` and its index line — or a rule stands in the right
97
100
  `user-rules.md`, having survived reformulation, its own counter-example and the
98
101
  {{LAWS}}, consented to explicitly, with any promoted source memory archived. The
99
102
  {{ONTOLOGY}}, {{LAWS}} and {{DOCTRINES}} files are untouched either way.
@@ -23,6 +23,7 @@
23
23
  "DESC_PERFORMANCE": "<one-line description: measures where the time and memory go, names the bottleneck with numbers, never guesses>",
24
24
  "DESC_EXPLORER": "<one-line description: reads/searches widely, returns only distilled findings>",
25
25
  "DESC_RESEARCHER": "<one-line description: searches and fetches the open web, cross-checks every claim, returns sourced findings>",
26
+ "DESC_MEMORY_CURATOR": "<one-line description: curates the memory store — merges duplicates, assigns topics, archives the stale, proposes deletions>",
26
27
  "DESC_ADVOCATE": "<council seat: argues the strongest case FOR the proposal>",
27
28
  "DESC_SKEPTIC": "<council seat: devil's advocate — failure modes and hidden assumptions>",
28
29
  "DESC_PRAGMATIST": "<council seat: weighs cost, effort, complexity vs payoff>",
@@ -141,6 +142,7 @@
141
142
  "DESC_BRUNO": "<one-line description: build, reorganise or test a Bruno API collection — requests, environments, assertions, chaining — every secret a placeholder>",
142
143
  "DESC_PROSE": "<one-line description: write prose for a human that doesn't read like a model — cut filler, active voice, vary rhythm, trust the reader>",
143
144
  "DESC_FRONTEND_DESIGN": "<one-line description: design a UI with intent — palette/type/layout chosen for the brief, not templated defaults; plan tokens, critique against the brief, keep one bold move>",
145
+ "DESC_DECK": "<one-line description: build slides or a presentation as one self-contained offline HTML file — short interview, outline approved first, keys, URL hash, one slide per printed page>",
144
146
  "DESC_WORKFLOW": "<one-line description: run a saved, code-driven workflow that orchestrates subagents deterministically>",
145
147
  "AGENT_COLORS": {
146
148
  "architect": "primary",
package/themes/biker.json CHANGED
@@ -23,6 +23,7 @@
23
23
  "DESC_PERFORMANCE": "Puts it on the dyno — measures where the power goes before anyone touches the engine.",
24
24
  "DESC_EXPLORER": "Sends the scout ahead — sweeps wide on a throwaway recon run, brings back only the read.",
25
25
  "DESC_RESEARCHER": "Rides out past the county line — reads the road signs everyone else skipped, checks each one twice, brings back only what held up.",
26
+ "DESC_MEMORY_CURATOR": "Clears out the clubhouse lockers — merges the doubles, labels every shelf, boxes the old gear, asks before anything hits the skip.",
26
27
  "DESC_ADVOCATE": "Argues for the run — the ground to be gained, the opening, the cost of staying parked.",
27
28
  "DESC_SKEPTIC": "Plays the doubter — calls the move on its failure modes, its risks, and the assumptions nobody checked.",
28
29
  "DESC_PRAGMATIST": "Weighs the run — the cost, the effort, the wear, and whether the payoff is worth the miles.",
@@ -141,6 +142,7 @@
141
142
  "DESC_BRUNO": "Build, re-rack, or test a Bruno API collection — requests, environments, assertions, chaining — and never let a secret ride along.",
142
143
  "DESC_PROSE": "Write like a human, not a bot — strip the filler, keep it plain, mix up the rhythm, and trust whoever's reading.",
143
144
  "DESC_FRONTEND_DESIGN": "Design a UI with real attitude — pick palette, type, and layout for this job, not the stock defaults, then trim it down to one bold move.",
145
+ "DESC_DECK": "Build slides or a presentation as one offline HTML file — a quick interview, the outline signed off first, then a deck that rides on arrow keys and prints clean.",
144
146
  "DESC_WORKFLOW": "Run a saved route that sends your riders by script — many rolled out at once, their findings gathered and checked in one clean run.",
145
147
  "AGENT_COLORS": {
146
148
  "architect": "primary",
@@ -23,6 +23,7 @@
23
23
  "DESC_PERFORMANCE": "Brings out the stopwatch — times every lap and names the slow sector with the split.",
24
24
  "DESC_EXPLORER": "Sends the track scout — sweeps wide from a throwaway recon lap, returns only the read.",
25
25
  "DESC_RESEARCHER": "Sends the pit reporter down the paddock — checks every rumour against two sources before it goes on air.",
26
+ "DESC_MEMORY_CURATOR": "Tidies the archive between races — merges the duplicate notes, files each by topic, shelves the old ones, asks before binning any.",
26
27
  "DESC_ADVOCATE": "Calls for the overtake — the place to be gained, the gap, the cost of staying put.",
27
28
  "DESC_SKEPTIC": "Plays the doubter — attacks the move for the failure modes, the risks, and the assumptions nobody checked on the grid.",
28
29
  "DESC_PRAGMATIST": "Weighs the strategy — the cost, the effort, the tyre wear, and whether the payoff is worth the stop.",
@@ -141,6 +142,7 @@
141
142
  "DESC_BRUNO": "Build, re-order, or test a Bruno API collection — requests, environments, assertions, chaining — no secret leaks, every one kept as a placeholder.",
142
143
  "DESC_PROSE": "Write copy that sounds human, not machine-read — cut the filler, keep it active, vary the pace, trust the audience.",
143
144
  "DESC_FRONTEND_DESIGN": "Design a UI with a point of view — palette, type, and layout built for this brief, not the templated defaults, then critique and cut to one bold move.",
145
+ "DESC_DECK": "Build slides or a presentation as one offline HTML file — a short interview, the outline approved first, then a deck that runs on arrow keys and prints one slide a page.",
144
146
  "DESC_WORKFLOW": "Run a saved race plan that drives your team by script — many sent out at once, their results gathered and checked in one clean grand prix.",
145
147
  "AGENT_COLORS": {
146
148
  "architect": "primary",
@@ -23,6 +23,7 @@
23
23
  "DESC_PERFORMANCE": "Traces the lag in the net — profiles the run and names the choke point with numbers.",
24
24
  "DESC_EXPLORER": "Scouts the net — sweeps wide in a throwaway shell, returns only the intel.",
25
25
  "DESC_RESEARCHER": "Jacks into the open net — pulls the intel, cross-checks it against two nodes, returns only what verified.",
26
+ "DESC_MEMORY_CURATOR": "Defrags the memory banks — merges the dupes, tags every shard, cold-stores the stale, asks before a wipe.",
26
27
  "DESC_ADVOCATE": "Pushes the build — the upside, the opening, the cost of sitting on it.",
27
28
  "DESC_SKEPTIC": "Runs devil's advocate — stress-tests the build for failure modes, risks, and buried assumptions.",
28
29
  "DESC_PRAGMATIST": "Weighs the spec — the cost, the effort, the complexity, and whether the payoff clears.",
@@ -141,6 +142,7 @@
141
142
  "DESC_BRUNO": "Forge, reorganise, or wire tests into a Bruno collection — requests, environments, assertions, chaining — every secret a placeholder.",
142
143
  "DESC_PROSE": "Write prose with a human pulse, not synthetic filler — strip the boilerplate, stay active, vary the cadence, trust the reader.",
143
144
  "DESC_FRONTEND_DESIGN": "Design a UI with edge — palette, type, and layout forged for this brief, not the stock defaults; plan, critique, and keep one bold move.",
145
+ "DESC_DECK": "Build slides or a presentation as one self-contained offline HTML file — short interview, outline cleared first, keyboard-driven, no CDN, prints one slide per page.",
144
146
  "DESC_WORKFLOW": "Jack in a saved routine that drives your daemons on rails — parallel forks, staged pipelines, and verification, all in one deterministic run.",
145
147
  "AGENT_COLORS": {
146
148
  "architect": "primary",
package/themes/gamer.json CHANGED
@@ -23,6 +23,7 @@
23
23
  "DESC_PERFORMANCE": "Checks the frame times — profiles the run and names the bottleneck before any tuning.",
24
24
  "DESC_EXPLORER": "Scouts the map — sweeps wide in a throwaway scout run, returns only the intel.",
25
25
  "DESC_RESEARCHER": "Reads the wiki and the patch notes — cross-checks every claim against two sources before it goes in the build guide.",
26
+ "DESC_MEMORY_CURATOR": "Sorts the inventory — stacks the duplicates, tags every item, stashes the old loot, asks before dropping any.",
26
27
  "DESC_ADVOCATE": "Calls for the play — the upside, the opening, the cost of passing it up.",
27
28
  "DESC_SKEPTIC": "Runs the counter — attacks the play for failure modes, risks, and assumptions nobody checked.",
28
29
  "DESC_PRAGMATIST": "Weighs the build — the cost, the effort, the complexity, and whether the payoff's worth it.",
@@ -141,6 +142,7 @@
141
142
  "DESC_BRUNO": "Build, reorganise, or write tests into a Bruno collection — requests, environments, assertions, chaining — secrets as placeholders.",
142
143
  "DESC_PROSE": "Write like a player, not a bot — cut the filler, keep it active, mix up the rhythm, and trust the reader.",
143
144
  "DESC_FRONTEND_DESIGN": "Design a UI with a real identity — palette, type, and layout picked for this brief, not the default skin, then cut it down to one bold move.",
145
+ "DESC_DECK": "Build slides or a presentation as one offline HTML file — a quick setup interview, outline locked first, then a deck that plays on arrow keys and prints one slide a page.",
144
146
  "DESC_WORKFLOW": "Run a saved combo that scripts your party — fan out, chain the stages, and verify the clear, all in one deterministic rotation.",
145
147
  "AGENT_COLORS": {
146
148
  "architect": "primary",
@@ -23,6 +23,7 @@
23
23
  "DESC_PERFORMANCE": "Weighs the machine-spirit’s labour — measures where time is spent and names the burden, never guessing.",
24
24
  "DESC_EXPLORER": "Ranges far and wide through a throwaway context, returning only the distilled truth.",
25
25
  "DESC_RESEARCHER": "Ranges beyond the archives into the wider realm, holding every claim to two witnesses before it is entered as truth.",
26
+ "DESC_MEMORY_CURATOR": "Keeps the Reliquary in order — merges the redundant relics, files each under its chapter, entombs the stale, and destroys none without the sovereign’s word.",
26
27
  "DESC_ADVOCATE": "Champions the proposal — presses its strongest case, the prize to be won, the cost of staying the hand.",
27
28
  "DESC_SKEPTIC": "Stands as devil's advocate — assails the proposal for its weaknesses, its perils, and its unspoken assumptions.",
28
29
  "DESC_PRAGMATIST": "Weighs the campaign's true cost — the labour, the complexity, whether the spoils are worth the war.",
@@ -141,6 +142,7 @@
141
142
  "DESC_BRUNO": "Raise, reshape, or set trials upon a Bruno collection — requests, environments, assertions, chaining — every secret a placeholder.",
142
143
  "DESC_PROSE": "Inscribe prose fit for human eyes, not machine-cant — strike the filler, speak plainly, vary the cadence, and trust the reader.",
143
144
  "DESC_FRONTEND_DESIGN": "Design an interface with intent — palette, type, and layout forged for this brief, not the common defaults; plan, scrutinise, and keep one bold stroke.",
145
+ "DESC_DECK": "Forge slides or a presentation as one self-contained offline HTML scroll — a brief interrogation, the outline sanctioned first, arrow-key navigation, one slide per printed page.",
144
146
  "DESC_WORKFLOW": "Unleash a sealed battle-rite that marshals your Adepts by iron script — many loosed at once, their findings martialled and proven in one disciplined campaign.",
145
147
  "AGENT_COLORS": {
146
148
  "architect": "primary",
package/themes/joker.json CHANGED
@@ -23,6 +23,7 @@
23
23
  "DESC_PERFORMANCE": "Times the act — finds which bit drags, and proves it with a stopwatch, not a hunch.",
24
24
  "DESC_EXPLORER": "Sends a scout — sweeps wide in a throwaway open-mic run, brings back only the read.",
25
25
  "DESC_RESEARCHER": "Sends a scout out of the club — reads the reviews everyone skipped, checks each twice, brings back only the ones that held up.",
26
+ "DESC_MEMORY_CURATOR": "Cleans out the joke book — merges the repeats, files each bit by topic, retires the dead ones, asks before burning any.",
26
27
  "DESC_ADVOCATE": "Argues for the bit — the laugh to be had, the opening, the cost of cutting it.",
27
28
  "DESC_SKEPTIC": "Plays the heckler — calls the bit on its failure modes, its risks, and the assumptions nobody checked.",
28
29
  "DESC_PRAGMATIST": "Weighs the set — the cost, the effort, the complexity, and whether the payoff is worth it.",
@@ -141,6 +142,7 @@
141
142
  "DESC_BRUNO": "Build, reorganise, or write tests for a Bruno collection — requests, environments, assertions, chaining — secrets as placeholders, honestly.",
142
143
  "DESC_PROSE": "Write like a human, not a model — ditch the filler, keep it active, vary the rhythm, and don't over-explain the joke.",
143
144
  "DESC_FRONTEND_DESIGN": "Design a UI with actual personality — palette, type, and layout for this brief, not the stock defaults, then trim to one bold move.",
145
+ "DESC_DECK": "Build slides or a presentation as one offline HTML file — a short interview, the outline approved first, arrow keys to drive it, and it prints one slide a page.",
144
146
  "DESC_WORKFLOW": "Run a saved set that sends your sidekicks by script — many sent out at once, their findings gathered and checked in one clean show.",
145
147
  "AGENT_COLORS": {
146
148
  "architect": "primary",