total-recall-brain 3.40.7 → 3.41.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.
Files changed (170) hide show
  1. package/bin/total-recall-memory.mjs +0 -0
  2. package/bin/total-recall.mjs +9 -40
  3. package/docs/reference/cli-reference.md +65 -1
  4. package/frontend/dist/assets/{index-AGUes-VG.css → index-BG9NkVUy.css} +1 -1
  5. package/frontend/dist/assets/{index-Bt5iVPZj.js → index-BtuiZqwP.js} +20 -7
  6. package/frontend/dist/index.html +2 -2
  7. package/frontend/src/components/plugins/PluginPanel.tsx +31 -5
  8. package/frontend/src/components/plugins/card/CardEngine.tsx +15 -23
  9. package/frontend/src/components/plugins/card/CardScenes.tsx +52 -23
  10. package/frontend/src/components/plugins/card/card.css +2 -5
  11. package/frontend/src/components/plugins/card/contract.ts +13 -19
  12. package/frontend/src/components/plugins/card/format.ts +8 -1
  13. package/frontend/src/components/plugins/card/widgets.tsx +4 -35
  14. package/frontend/src/components/plugins/plugin-frame.ts +30 -3
  15. package/frontend/src/pages/PluginsPage.tsx +3 -2
  16. package/package.json +1 -1
  17. package/scaffold/.agent/skills/plugin/SKILL.md +110 -0
  18. package/scaffold/.agent/skills/plugin/evals/README.md +53 -0
  19. package/scaffold/.agent/skills/plugin/evals/cases/01-fabricated-seed.mjs +42 -0
  20. package/scaffold/.agent/skills/plugin/evals/cases/02-reassuring-default.mjs +39 -0
  21. package/scaffold/.agent/skills/plugin/evals/cases/03-declared-template.mjs +32 -0
  22. package/scaffold/.agent/skills/plugin/evals/cases/04-card-collects-credential.mjs +46 -0
  23. package/scaffold/.agent/skills/plugin/evals/cases/05-host-leak-in-scaffold.mjs +55 -0
  24. package/scaffold/.agent/skills/plugin/evals/cases/06-correct-plugin.mjs +92 -0
  25. package/scaffold/.agent/skills/plugin/evals/run.mjs +118 -0
  26. package/scaffold/.agent/skills/plugin/prompts/01-function.md +29 -0
  27. package/scaffold/.agent/skills/plugin/prompts/02-surfaces.md +43 -0
  28. package/scaffold/.agent/skills/plugin/prompts/03-scaffold.md +31 -0
  29. package/scaffold/.agent/skills/plugin/prompts/04-cli.md +49 -0
  30. package/scaffold/.agent/skills/plugin/prompts/05-credentials.md +41 -0
  31. package/scaffold/.agent/skills/plugin/prompts/06-card.md +46 -0
  32. package/scaffold/.agent/skills/plugin/prompts/07-scaffold.md +52 -0
  33. package/scaffold/.agent/skills/plugin/prompts/08-verify.md +43 -0
  34. package/scaffold/.agent/skills/plugin/references/anti-patterns.md +123 -0
  35. package/scaffold/.agent/skills/plugin/references/card.md +90 -0
  36. package/scaffold/.agent/skills/plugin/references/scaffold.md +120 -0
  37. package/scaffold/.agent/skills/plugin/references/surfaces.md +206 -0
  38. package/scaffold/.agent/skills/plugin/scripts/record.mjs +360 -0
  39. package/scaffold/.agent/skills/plugin/subagents/card-designer.md +60 -0
  40. package/scaffold/.agent/skills/plugin/subagents/plugin-reviewer.md +55 -0
  41. package/scaffold/.agent/skills/plugin/subagents/scaffold-extractor.md +71 -0
  42. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +71 -1441
  43. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +7 -5
  44. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +3 -44
  45. package/scaffold/.agent/skills/total-recall/plugins/auth/scripts/agent-login-pty.py +185 -0
  46. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +20 -1
  47. package/scaffold/.agent/skills/total-recall/plugins/auth/src/host-secrets-store.mjs +15 -0
  48. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-env-export.mjs +6 -4
  49. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-remote-deploy.mjs +1 -0
  50. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +0 -24
  51. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +4 -4
  52. package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +0 -21
  53. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +4 -4
  54. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +0 -32
  55. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +4 -4
  56. package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +11 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/README.md +5 -2
  58. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +4 -4
  59. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +1 -28
  60. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/DESIGN.md +95 -13
  61. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +553 -340
  62. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +0 -36
  63. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/card.js +383 -400
  64. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +4 -4
  65. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +0 -1
  66. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +0 -28
  67. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +4 -4
  68. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +0 -32
  69. package/scaffold/.agent/skills/total-recall/references/auth.md +3 -1
  70. package/scaffold/.agent/skills/total-recall/references/memory.md +4 -0
  71. package/scaffold/.agent/skills/total-recall/references/openwiki.md +2 -0
  72. package/scaffold/.agent/skills/total-recall/references/operations.md +12 -0
  73. package/src/cli/brain.mjs +4 -2
  74. package/src/cli/context-stats.mjs +104 -0
  75. package/src/cli/context.mjs +8 -0
  76. package/src/cli/daemon.mjs +10 -1
  77. package/src/cli/export.mjs +3 -2
  78. package/src/cli/ingest-okf.mjs +12 -15
  79. package/src/cli/init.mjs +0 -85
  80. package/src/cli/lint.mjs +3 -2
  81. package/src/cli/plugin/copies.mjs +68 -0
  82. package/src/cli/plugin/create.mjs +22 -24
  83. package/src/cli/plugin/index.mjs +49 -3
  84. package/src/cli/plugin/search.mjs +19 -2
  85. package/src/cli/rebuild.mjs +2 -0
  86. package/src/cli/remember.mjs +23 -0
  87. package/src/cli/status.mjs +10 -3
  88. package/src/cli/update.mjs +3 -2
  89. package/src/core/action-predictor.mjs +161 -0
  90. package/src/core/app-deploy/runtime-cli/node.mjs.tmpl +20 -3
  91. package/src/core/app-deploy/source.mjs +16 -9
  92. package/src/core/automatic-brain-updates.mjs +6 -3
  93. package/src/core/brain-registry.mjs +19 -2
  94. package/src/core/brain-state.mjs +23 -0
  95. package/src/core/cli-commands.mjs +1 -0
  96. package/src/core/cli-maintenance.mjs +1 -1
  97. package/src/core/cli-semantic-index.mjs +1 -1
  98. package/src/core/command-surface.mjs +3 -3
  99. package/src/core/composed-command-resolution.mjs +21 -0
  100. package/src/core/config.mjs +84 -0
  101. package/src/core/confined-memory.mjs +93 -0
  102. package/src/core/context-telemetry.mjs +214 -0
  103. package/src/core/daemon-control.mjs +14 -43
  104. package/src/core/fast-recall.mjs +1 -1
  105. package/src/core/memory-brain.mjs +2 -0
  106. package/src/core/plugin-activation.mjs +38 -6
  107. package/src/core/plugin-bundle.mjs +54 -0
  108. package/src/core/plugin-catalog.mjs +1 -1
  109. package/src/core/plugin-context.mjs +1 -1
  110. package/src/core/plugin-contracts/card.mjs +69 -37
  111. package/src/core/plugin-loader.mjs +5 -6
  112. package/src/core/plugin-runner.mjs +13 -6
  113. package/src/core/plugin-runtime.mjs +5 -4
  114. package/src/core/plugin-setup.mjs +5 -3
  115. package/src/core/plugin-state-store.mjs +12 -1
  116. package/src/core/plugin-state.mjs +46 -5
  117. package/src/core/plugin-store.mjs +78 -3
  118. package/src/core/plugin-tasks.mjs +3 -1
  119. package/src/core/plugin-updates.mjs +117 -0
  120. package/src/core/plugin-vendor.mjs +10 -4
  121. package/src/core/project-brain.mjs +14 -41
  122. package/src/core/project-id.mjs +4 -1
  123. package/src/core/required-plugins.mjs +151 -13
  124. package/src/core/skills-registry.mjs +27 -3
  125. package/src/core/ssss-kernel-bridge.mjs +3 -1
  126. package/src/core/startup-health.mjs +66 -16
  127. package/src/core/surface.mjs +51 -44
  128. package/src/core/testing/plugin-fixture.mjs +69 -0
  129. package/src/core/vault-files.mjs +13 -0
  130. package/src/core/vault.mjs +4 -30
  131. package/src/server/index.mjs +13 -1
  132. package/src/server/invoke-decision-child.mjs +49 -0
  133. package/src/server/invoke-execution.mjs +87 -0
  134. package/src/server/invoke-policy.mjs +64 -0
  135. package/src/server/invoke-read-child.mjs +26 -0
  136. package/src/server/invoke-targets.mjs +49 -0
  137. package/src/server/invoke-write-child.mjs +19 -0
  138. package/src/server/routes/invoke.mjs +314 -0
  139. package/src/server/routes/plugins.mjs +1 -1
  140. package/scaffold/.agent/skills/plugins/SKILL.md +0 -57
  141. package/scaffold/.agent/skills/plugins/references/card-design.md +0 -55
  142. package/scaffold/.agent/skills/plugins/references/distribution.md +0 -23
  143. package/scaffold/.agent/skills/plugins/references/manifest-contract.md +0 -90
  144. package/scaffold/.agent/skills/plugins/references/optimized/index.md +0 -9
  145. package/scaffold/.agent/skills/plugins/references/optimized/manifest.json +0 -35
  146. package/scaffold/.agent/skills/plugins/references/optimized/original.md +0 -58
  147. package/scaffold/.agent/skills/plugins/references/optimized/section-01.md +0 -5
  148. package/scaffold/.agent/skills/plugins/references/optimized/section-02.md +0 -25
  149. package/scaffold/.agent/skills/plugins/references/optimized/section-03.md +0 -12
  150. package/scaffold/.agent/skills/plugins/references/optimized/section-04.md +0 -7
  151. package/scaffold/.agent/skills/plugins/references/optimized/section-05.md +0 -5
  152. package/scaffold/.agent/skills/total-recall/openwiki/README.md +0 -10
  153. package/scaffold/.agent/skills/total-recall/openwiki/architecture.md +0 -5
  154. package/scaffold/.agent/skills/total-recall/openwiki/ide.md +0 -10
  155. package/scaffold/.agent/skills/total-recall/openwiki/memory.md +0 -11
  156. package/scaffold/.agent/skills/total-recall/openwiki/secrets.md +0 -7
  157. package/scaffold/.agent/skills/total-recall/openwiki/skills.md +0 -7
  158. package/scaffold/openwiki/README.md +0 -10
  159. package/scaffold/openwiki/architecture.md +0 -5
  160. package/scaffold/openwiki/ide.md +0 -10
  161. package/scaffold/openwiki/memory.md +0 -11
  162. package/scaffold/openwiki/secrets.md +0 -7
  163. package/scaffold/openwiki/skills.md +0 -7
  164. package/src/core/okf-adapter.mjs +0 -559
  165. package/templates/openwiki/README.md +0 -10
  166. package/templates/openwiki/architecture.md +0 -5
  167. package/templates/openwiki/ide.md +0 -10
  168. package/templates/openwiki/memory.md +0 -11
  169. package/templates/openwiki/secrets.md +0 -7
  170. package/templates/openwiki/skills.md +0 -7
@@ -0,0 +1,31 @@
1
+ # Prompt 3 — Scaffold, then stop generating
2
+
3
+ ## The prompt
4
+
5
+ ```
6
+ total-recall plugin create <id> --name "<plain descriptive name>" --description "<one concrete sentence>"
7
+ ```
8
+
9
+ You receive a manifest, a CLI handler and a test.
10
+
11
+ **No UI is generated, deliberately.** A card face is a design act: it requires knowing the users, their tasks and the domain's vocabulary, which is Prompt 1's work. A generated stub is precisely what produced an ecosystem of identical cards, so the scaffold refuses to write one.
12
+
13
+ **The scaffold is not yet a valid plugin.** It has no card, and `plugin info` will say so. Do not treat a successful scaffold as finished work, and do not declare a card you have not designed.
14
+
15
+ ## Correct means
16
+
17
+ - The repository exists at `tr-plugin-<id>` with a manifest carrying identity only.
18
+ - Its tests run.
19
+ - You know the face is outstanding, and that Prompts 4–6 are how it gets written.
20
+
21
+ ## Then
22
+
23
+ Set the surfaces you chose in Prompt 2: add `cli.subcommands`, `secrets`, `configuration`, `status`, `branding`, and finally `ui.elements` when the face exists.
24
+
25
+ ## Check
26
+
27
+ ```
28
+ node <skill>/scripts/record.mjs . --manifest
29
+ ```
30
+
31
+ Reports the surfaces present and the surfaces outstanding. A plugin with no `ui.elements` fails — correctly — until Prompt 6 is done.
@@ -0,0 +1,49 @@
1
+ # Prompt 4 — Write the CLI as an agent interface
2
+
3
+ The CLI is used by two audiences: an operator at a terminal, and **an agent** that discovers the plugin, calls it, and parses the result. Write for both.
4
+
5
+ ## The prompt
6
+
7
+ In `plugin.json`, for every operation:
8
+
9
+ - a **name** in lowercase kebab-case, unique
10
+ - a **description** of what it does
11
+ - an **effect**: `read`, `write`, `destructive` or `send`
12
+ - **typed arguments**, each with a label — `string`, `number`, `boolean`, `choice` with options. Mark positionals, mark requireds.
13
+ - a **secret argument** is marked `secret = true`, and its value travels over stdin, never `argv`. One per command, a string, no flag.
14
+ - `output: "json"` unless the result is genuinely prose
15
+ - `timeout_ms` for anything slow
16
+
17
+ In `cli.mjs`:
18
+
19
+ - `--json` emits structured output on **every** subcommand, including those that default to text
20
+ - a failure prints the real error to **stderr** and exits **non-zero**
21
+ - `--help` answers **without resolving credentials**, so it works before setup
22
+ - no secret value reaches `argv`, stdout, stderr or a log
23
+
24
+ ## Correct means
25
+
26
+ An agent can:
27
+
28
+ 1. run `total-recall plugin library --json` and see this plugin's operations, their arguments and their effects;
29
+ 2. choose an operation without reading prose;
30
+ 3. call `total-recall <id> <op> <args> --json`;
31
+ 4. parse the JSON;
32
+ 5. tell success from failure from the exit code.
33
+
34
+ ## Common wrong answers
35
+
36
+ - `--json` that only some subcommands honour.
37
+ - Resolving a credential at the top of `run()` so `--help` fails without a key.
38
+ - Printing a success message on a failed HTTP call.
39
+ - Taking an API key as `--key <value>`, which puts it in `argv`, in shell history and in the process list.
40
+ - Declaring an effect of `read` for an operation that mutates.
41
+
42
+ ## Check
43
+
44
+ ```
45
+ node <skill>/scripts/record.mjs . --manifest
46
+ node <skill>/scripts/record.mjs . --secrets
47
+ ```
48
+
49
+ Then run `--help` and one `--json` call by hand and read the real output.
@@ -0,0 +1,41 @@
1
+ # Prompt 5 — Declare credentials and settings
2
+
3
+ There is exactly **one** credential path in the whole system, and it belongs to the auth plugin.
4
+
5
+ ## The prompt
6
+
7
+ **Credentials.** Every key the plugin reads goes in `secrets[]`:
8
+
9
+ ```json
10
+ "secrets": [ { "key": "SERVICE_API_KEY", "description": "Reads and creates charges", "required": true } ]
11
+ ```
12
+
13
+ Resolve it only through `total-recall auth secret`. The plugin has no store of its own, reads no ambient environment variable as a fallback, and accepts no key on `argv`.
14
+
15
+ **Settings.** Every setting goes in `configuration.fields` with its type and default. Field keys are camelCase and may not contain `password`, `secret`, `apiKey` or `token` — those belong in `secrets`.
16
+
17
+ **The card** reports a credential as *present* or *missing*. It never renders a value, and never renders an input that accepts one. To set a key, the card hands over the command:
18
+
19
+ ```
20
+ total-recall auth secret set SERVICE_API_KEY --stdin
21
+ ```
22
+
23
+ ## Correct means
24
+
25
+ - Exactly one credential path exists, and it is auth.
26
+ - The card has no code path that can receive a key value, so it cannot leak one.
27
+ - A setting a user must change is declared, so it is visible rather than buried in code.
28
+
29
+ ## Why the card must not collect keys
30
+
31
+ The rule is not bureaucracy: one store means one rotation path and one audit trail. A per-plugin key screen violates it even when it writes to the same store, because it makes the plugin the place an operator thinks of when a key must change. It also creates a receive path for the secret inside plugin code, which is a leak surface that would otherwise not exist.
32
+
33
+ Evidence: a scaffolded panel rendered `<input type="password">` and dispatched the raw value to the host; a real card built three such screens.
34
+
35
+ ## Check
36
+
37
+ ```
38
+ node <skill>/scripts/record.mjs . --secrets
39
+ ```
40
+
41
+ Fails if a secret is reachable in `argv`, in stdout, in a log, or in the rendered card.
@@ -0,0 +1,46 @@
1
+ # Prompt 6 — Design the card face by hand
2
+
3
+ Every plugin has a card face. It is bespoke owner code, written for this plugin and no other.
4
+
5
+ Full specification: [card](../references/card.md).
6
+
7
+ ## The prompt
8
+
9
+ Work in this order. Write the reasoning into `ui/DESIGN.md` **before** writing component code.
10
+
11
+ 1. Who uses it, and what are they in the middle of doing? Name the real tasks.
12
+ 2. What must be visible without a single click? That decides the hierarchy.
13
+ 3. What is the one primary action, and what is destructive?
14
+ 4. What is the domain's own vocabulary? Use it. Never render a domain as "a list of commands".
15
+ 5. Then choose the arrangement, and justify it in the plugin's own terms.
16
+
17
+ Then author `ui/card.js`:
18
+
19
+ - **One bespoke Web Component**, declared as the single element of kind `card` in `ui.elements`. No `card_layout`, no template name, no region or widget vocabulary.
20
+ - **Screens the plugin defines**, ordered by the plugin's own tasks, most-used first. Never one screen per subcommand.
21
+ - **Wide, not a column.**
22
+ - **Real data only.** Every value from `host.run(subcommand, args)`. Anything not returned renders an em dash with its reason.
23
+ - **Failures are states**, each rendered explicitly with the time of the last attempt.
24
+ - **Name a value's driver** when severity combines several measures, or a red tile beside a green figure reads as a contradiction.
25
+ - **The host's tokens.** The dashboard is dark: use the injected `--text-*`, `--bg-*`, `--border`, `--accent` and your brand tokens. Declare state colours once in a `:host` block and keep them legible on dark.
26
+ - **Accessible**: 44 px controls, keyboard reachable, visible focus, contrast-checked states, `prefers-reduced-motion` respected.
27
+ - **Severity never by colour alone** — pair every colour with a word.
28
+ - **The card consumes credentials, never collects them.**
29
+
30
+ ## Correct means
31
+
32
+ 1. Render at **360, 768 and 1280 px** — no horizontal overflow anywhere.
33
+ 2. Render on the **real dashboard tokens** (dark), not on a white page.
34
+ 3. Exercise every state: credential present, missing, provider unreachable, call rejected, empty, stale.
35
+ 4. Put it beside another plugin's face. If you cannot tell which is which from the layout alone, it is not finished.
36
+ 5. No secret value can reach the DOM in any state.
37
+
38
+ **Then look at it.** Every defect in the anti-patterns catalogue that begins "only looking reveals" was invisible to a schema check.
39
+
40
+ ## Check
41
+
42
+ ```
43
+ node <skill>/scripts/record.mjs . --card
44
+ ```
45
+
46
+ Then render and inspect it yourself. A passing check is not a design.
@@ -0,0 +1,52 @@
1
+ # Prompt 7 — Extract the scaffold, if another application wants the capability
2
+
3
+ Only when Prompt 1 answered yes. Full specification: [scaffold](../references/scaffold.md).
4
+
5
+ ## The prompt
6
+
7
+ A **scaffold** is the capability extracted so a builder can put it into their own application. It is **not a copy of the plugin**. The plugin is the reference implementation.
8
+
9
+ Structure the repository as one source with two artifacts:
10
+
11
+ ```
12
+ tr-plugin-<id>/
13
+ capability/ ← the scaffold payload: exported functions, no host
14
+ index.mjs
15
+ cli.mjs ← the Total Recall entry: parse argv, resolve credentials, call capability/
16
+ ui/ ← the face; Total Recall only
17
+ test/
18
+ ```
19
+
20
+ Declare it:
21
+
22
+ ```json
23
+ "capability": { "entry": "capability/index.mjs", "exports": ["…"] }
24
+ ```
25
+
26
+ Move the domain logic — request construction, signature verification, payload building, response mapping — out of the CLI handler and into `capability/`. `cli.mjs` becomes a thin adapter.
27
+
28
+ The capability must be:
29
+
30
+ - **explicitly parameterised** — no `argv`, no `process.env`, no module-level singleton
31
+ - **free of environment defaults** — a missing `successUrl` is the caller's error, never a silent `example.com`
32
+ - **transport-injected**, so the app uses its own HTTP client and tests run offline
33
+ - **returning data**, not printing text
34
+ - **throwing errors**, not setting `process.exitCode`
35
+ - **free of Total Recall** — no `total-recall`, no `TOTAL_RECALL_BIN`, no auth store
36
+ - **free of UI** — no card, no `DESIGN.md`, no logo
37
+
38
+ Write `BRICK.md`: what to import, what to pass, where credentials come from, what comes back.
39
+
40
+ ## Correct means
41
+
42
+ A builder can lay the capability into their application and use it **without rewriting it**, with no Total Recall present, every environment value supplied by them.
43
+
44
+ The test is not "does it run". It is **"can a builder use this as it stands?"** Evidence: 19 of 34 plugins currently export only `run`, so a builder must extract the logic by hand — exactly the work a scaffold exists to remove.
45
+
46
+ ## Check
47
+
48
+ ```
49
+ node <skill>/scripts/record.mjs . --scaffold
50
+ ```
51
+
52
+ Asserts the capability loads with `TOTAL_RECALL_BIN` unset and no auth store, that no Total Recall string is reachable from it, that no placeholder value ships, and that its tests fail if it spawns a process.
@@ -0,0 +1,43 @@
1
+ # Prompt 8 — Verify, then report
2
+
3
+ Run every check and report the **real** result. A passing health probe is not a test result.
4
+
5
+ ## The prompt
6
+
7
+ ```
8
+ node <skill>/scripts/record.mjs . --json
9
+ ```
10
+
11
+ Then work the list, and record the actual outcome of each. Do not tick a box you did not test.
12
+
13
+ - [ ] `total-recall plugin info <id>` reports no errors and no warnings.
14
+ - [ ] Every surface the function needs is declared, and nothing unused.
15
+ - [ ] Every operation has typed arguments and an effect.
16
+ - [ ] `--json` works on every subcommand; failures exit non-zero; `--help` works without credentials.
17
+ - [ ] No secret value appears in `argv`, stdout, stderr, a log or the card state.
18
+ - [ ] The card declares exactly one element of kind `card`, and no `card_layout`.
19
+ - [ ] Every value on the card came from a command; failures render as failures; unknown values render an em dash.
20
+ - [ ] The card renders on the real dark dashboard at 360, 768 and 1280 px with no horizontal overflow.
21
+ - [ ] Every state renders: credential present, missing, provider unreachable, rejected call, empty, stale.
22
+ - [ ] The suite passes — per-subcommand unit tests including failure paths, a manifest test, a secrets test.
23
+ - [ ] No seeded value, placeholder or example default survives anywhere in the plugin.
24
+ - [ ] If a scaffold exists: it runs with `TOTAL_RECALL_BIN` unset, and its tests fail if it spawns a process.
25
+
26
+ ## Then, honestly
27
+
28
+ Bring `README.md` to describe the plugin **as it actually is**:
29
+
30
+ - what it does, in its own words
31
+ - the real commands
32
+ - where credentials come from
33
+ - **anything still outstanding**, stated plainly
34
+
35
+ No claim of a capability the plugin does not have. A stale warning about a fixed bug is itself a defect: one plugin's README described two reporting bugs as unfixed long after both were repaired and verified.
36
+
37
+ ## Correct means
38
+
39
+ Every claim in the report is backed by a command you ran, and anything you could not verify is named as unverified rather than omitted.
40
+
41
+ ## Check
42
+
43
+ A second reader can reproduce every claim from the report alone.
@@ -0,0 +1,123 @@
1
+ # Anti-patterns
2
+
3
+ Every entry below was observed in a real plugin in this ecosystem, with the evidence. They are the failure modes this recipe exists to prevent. Each is a rejection, not a preference.
4
+
5
+ ---
6
+
7
+ ## Fabrication
8
+
9
+ **Seeded readings.** A card constructor held a literal hostname, uptime, load average and `usedPercent: 99.1`, with the comment `// Retain fallback telemetry`. A host at 99.1% memory is in distress; this was a false alarm, and one machine's hostname shipped to every node.
10
+
11
+ **Invented API results.** A card's fallback branch fabricated `cs_live_…` session ids, `pi_…` intent ids, a payment URL and a latency of "42ms" when `host.run` was unavailable. That branch was not a degraded mode; it was a mock payment terminal.
12
+
13
+ **Hard-coded claims.** A header rendered `Stripe API (Live Secret)` and `HMAC-SHA256 Verified` with no command behind either. A merchant with no key and no webhook secret saw an identical card.
14
+
15
+ **Fixed text where a command belongs.** `card_face.metrics` held literal strings such as `ONLINE`. The validator warns on it; the card must never carry it.
16
+
17
+ > **Rule.** A value appears only if a command or the host returned it. If a source fails, show the failure and when it was last attempted.
18
+
19
+ ## Reassuring defaults
20
+
21
+ The single most damaging pattern found.
22
+
23
+ - A card read `data.worktree.unstaged`, `data.synced` and `data.upstream.status` — **none of which the command returns**. Every value fell through to its default.
24
+ - The defaults were `'Up to date'` and `'Synced'`.
25
+ - Therefore a repository with **three unpushed commits rendered as "Up to date."**
26
+
27
+ Related: a missing upstream comparison becoming `unpushedCommits: 0` instead of unknown.
28
+
29
+ > **Rule.** Unknown renders an em dash with its reason. `0` and `unknown` are different facts, and a reassurance the plugin has not verified is a lie.
30
+
31
+ ## Credential violations
32
+
33
+ - A scaffolded panel rendered `<input type="password">` for an API key and dispatched `save-token` with the raw value — a second credential store, and a path the key could leak from.
34
+ - A card built three separate key-entry screens.
35
+ - A plugin's error text told the *application's* users to run a Total Recall command.
36
+
37
+ > **Rule.** One credential path exists in the whole plugin, and it is `total-recall auth secret`. The card reports present or missing, never renders a value, and never collects one.
38
+
39
+ ## Templates
40
+
41
+ - Core enforced a closed allowlist of seven layouts, so a bespoke arrangement could not be declared even in principle.
42
+ - One engine rendered every card through a shared widget vocabulary. **24 of 34 plugins shared a byte-identical card signature**; Stripe, Domains and Tickets — three unrelated domains — were the same layout.
43
+ - 30 plugins shipped a real bespoke `card.js` that the card face never mounted.
44
+ - The scaffolder generated a stub panel and an empty `DESIGN.md`, which is the mechanism that produced the uniformity.
45
+
46
+ > **Rule.** No layout vocabulary anywhere. A face that could be dropped onto another plugin is a failed face.
47
+
48
+ ## Invented brands
49
+
50
+ | Plugin | Invented wordmark | Real identity |
51
+ | --- | --- | --- |
52
+ | Stripe wrapper | `PAYFORGE` | Stripe's own |
53
+ | git-sentinel | `[BLAME//GAME]` | plain descriptive name |
54
+ | system-monitor | `[PULSE//CHECK]` | plain descriptive name |
55
+
56
+ Two of the three also carried colour values contradicting their own manifest.
57
+
58
+ > **Rule.** A wrapper of someone else's API keeps that provider's name and brand. A first-party plugin uses a plain descriptive name and its own mark. Never an emoji, never a generic icon.
59
+
60
+ ## Values that break the capability elsewhere
61
+
62
+ - `const successUrl = "https://example.com/checkout/success"` shipped inside a vendorable plugin. An app scaffolding it would send paying customers to a placeholder domain.
63
+ - Defaults of `2000`, `"General Admission Ticket"` and `"usd"` — the author's examples — travelling into every copy.
64
+ - A domain default of `clean[1] || 'example.com'`.
65
+
66
+ > **Rule.** Every environment value is the caller's to supply. No placeholder, no author default, no example value in anything a builder might take.
67
+
68
+ ## Host leaks into a scaffold
69
+
70
+ - A vendored brick shelled out to the `total-recall` binary for every credential read: with `TOTAL_RECALL_BIN=/nonexistent` it failed with `Auth credential read failed`.
71
+ - It shipped `ui/card.js`, whose only data channel is `host.run` — a host that application does not have.
72
+ - **19 of 34 plugins** carry this runtime dependency, and every one of them is vendorable.
73
+
74
+ > **Rule.** A scaffold runs with Total Recall absent. Its tests must fail if it spawns a process.
75
+
76
+ ## Presentation defects only looking reveals
77
+
78
+ - `.figure[data-tone]` CSS was defined but the tone was never set on the wrapper, so all four accent borders rendered grey. Dead CSS, invisible to a schema check.
79
+ - A fleet tile showed a **red border beside a green load figure**: severity combined load and memory, but the tile only displayed load, so a memory-driven critical read as a contradiction.
80
+ - A selection outline collided with the severity border, so a critical tile appeared to have a green edge.
81
+ - Bars collapsed to slivers after a layout change, because a three-column grid left no room for the track.
82
+ - **"USD" appeared twice** — as a suffix in the amount field and on the currency button immediately beside it.
83
+ - A long payment URL ran into its copy button at narrow widths.
84
+
85
+ > **Rule.** Render it, look at it, measure it. A passing schema check is not a design.
86
+
87
+ ## Dark-surface blindness
88
+
89
+ The dashboard is **dark-only** (`--text-primary: #f1f5f9`, zero `prefers-color-scheme` rules), but cards were authored and verified against a white test page. Light-theme state colours were therefore unreadable in production, including the verdict line.
90
+
91
+ > **Rule.** Design and verify on the tokens the host actually injects.
92
+
93
+ ## Colour-only severity
94
+
95
+ Severity conveyed by hue alone, with no word and no value. Indistinguishable under colour blindness and in a screenshot without a legend.
96
+
97
+ > **Rule.** Every colour is paired with a word.
98
+
99
+ ## Host-derived screens
100
+
101
+ The host built one screen per CLI subcommand, so every plugin's screens were its command list. That is the template failure at a higher level.
102
+
103
+ > **Rule.** The plugin defines its screens, ordered by its own tasks, most-used first.
104
+
105
+ ## Stale documentation
106
+
107
+ A plugin's README described two reporting bugs as unfixed and pointed at a correction tracker. **Both had already been fixed and were verified against hostile input** — a file named `" leading-space.txt"` parses correctly, and a missing upstream yields `null`, not `0`. The stale warning misrepresented a working plugin and sent readers to a dead end.
108
+
109
+ > **Rule.** Documentation describes the plugin as it is now. A warning that no longer applies is a defect.
110
+
111
+ ## Environments that return confidently wrong data
112
+
113
+ `cat /proc/meminfo 2>/dev/null | head -4 || vm_stat` **never fell through on macOS**, because `cat missing | head` exits 0. The macOS memory branch was dead code, and the plugin reported a false `100%` where the truth was `58.3%`.
114
+
115
+ > **Rule.** Test the condition, not the exit status. Verify a computed figure against an independent calculation before trusting it.
116
+
117
+ ## Two definitions of one thing
118
+
119
+ - **30 of 30 plugin repositories** carried a stale copied `auth` plugin declaring a `yaml` dependency with no `node_modules`, so every secrets and mesh call from a plugin repository crashed.
120
+ - The scaffold held real directory copies of the nine default plugins rather than links, so each drifted independently.
121
+ - Two skills, `plugin` and `plugins`, described the same thing.
122
+
123
+ > **Rule.** One definition, referenced everywhere. A second copy is a second source of truth, and it will diverge.
@@ -0,0 +1,90 @@
1
+ # The card face
2
+
3
+ Every plugin has a card face. It is the plugin's interface in the Total Recall dashboard, and it is **bespoke owner code**: written by hand, for that one plugin, from that plugin's own function and brand.
4
+
5
+ There is no template, no layout vocabulary, no widget set, no region list. Core rejects `card_layout` outright. A face that could be dropped onto a different plugin is a failed face.
6
+
7
+ ---
8
+
9
+ ## What the host provides, and nothing more
10
+
11
+ - a **sandboxed frame** — opaque origin, `default-src 'none'`, `connect-src 'none'`, no dashboard DOM and no storage
12
+ - a frozen **`host`** object whose `run(subcommand, args, options)` is the only channel out
13
+ - the **design tokens** it injects into the frame
14
+ - the **drawer**, which carries settings and credentials so the face stays focused
15
+
16
+ Everything else — structure, vocabulary, hierarchy, controls, visual language — is yours to design for this plugin and no other.
17
+
18
+ ## The design process
19
+
20
+ Work in this order, and write the reasoning into `ui/DESIGN.md` **before** writing component code.
21
+
22
+ 1. **Who uses it, and what are they in the middle of doing?** Name the two or three real tasks. A payments operator reconciling a payout is not the same as one hunting a suspicious charge.
23
+ 2. **What must be visible without a single click?** That decides the hierarchy. A DNS plugin shows the zone and its records; a telephony plugin shows line state and the active call; a telemetry plugin shows which machine is struggling.
24
+ 3. **What is the one primary action, and what is destructive?** A destructive action gets confirmation, and never the visual weight of the obvious next step.
25
+ 4. **What is the domain's own vocabulary?** Use it. Amounts, dates and states in the arrangement an accountant expects; peers, routes and reachability for a mesh. Never render a domain as "a list of commands".
26
+ 5. **Then choose the arrangement**, and justify it in the plugin's own terms.
27
+
28
+ `ui/DESIGN.md` carries a real `tokens:` block matching the manifest, and the reasoning above. See the surfaces reference for the token fields.
29
+
30
+ ## Screens
31
+
32
+ A plugin with several jobs carries them across **screens the operator flips through**. The plugin defines them.
33
+
34
+ - Order them by the plugin's own tasks, **most-used first**.
35
+ - The first screen answers what the operator opened the card to do.
36
+ - **Never one screen per subcommand.** That is the host's command list wearing a costume, and it is what makes unrelated plugins look alike.
37
+ - Never a screen set the host derives or imposes.
38
+
39
+ ## Rules that make a face real
40
+
41
+ - **Real data only.** A value appears only if a command or the host returned it. Never a seeded reading, a placeholder, an example default or an `ONLINE` badge. If a source fails, show the failure and when it was last attempted.
42
+ - **Unknown is an em dash with a reason**, never a zero and never a reassuring word. `0 unpushed commits` and `unknown, no upstream configured` are different facts.
43
+ - **Failures are states**, first-class and rendered like any other. Missing credential, unreachable provider, rejected call, stale reading.
44
+ - **A value's driver is named.** If severity combines several measures, say which one drove it, or a red tile beside a green figure reads as a contradiction.
45
+ - **Every declared operation is reachable**, and its effect is visible — a `read` must not look like a `send`.
46
+ - **Destructive actions state their target and require confirmation.**
47
+ - **The card consumes credentials, never collects them.** Report present or missing; never render a value; never render an input that accepts one. Hand over the auth command to run instead.
48
+ - **Tokens only.** No hard-coded hex outside the single `:host` token block. The dashboard is **dark**, so the injected `--text-*`, `--bg-*`, `--border` and `--accent` values are light-on-dark; tune your state colours for that surface and keep them legible.
49
+ - **Wide, not a column.** A narrow column forces vertical stacking, which is what makes different plugins look alike.
50
+ - **Severity never by colour alone** — pair every colour with a word.
51
+ - **Accessible.** Controls at least 44 px, keyboard reachable, visible focus, contrast-checked state colours, `prefers-reduced-motion` respected.
52
+ - **No decoration.** No ambient animation, no emoji as icons, no hardware-skin imitation, no fake equaliser on a plugin that has no audio. Motion only when it reports a state change.
53
+ - **Copy.** No filler words, and no sentence ends with a preposition.
54
+
55
+ ## Shape of the component
56
+
57
+ ```js
58
+ export class ExampleCard extends HTMLElement {
59
+ get screens() { return [ { id: 'charge', label: 'Charge' }, /* … most-used first */ ] }
60
+ connectedCallback() { /* attach shadow, render frames with em dashes, then read */ }
61
+ disconnectedCallback() { /* clear timers; never leave one running */ }
62
+ async read() { /* host.run(...) → paint; a rejection clears figures and shows the error */ }
63
+ }
64
+ if (!customElements.get('tr-example-card')) customElements.define('tr-example-card', ExampleCard)
65
+ ```
66
+
67
+ - Values are painted **after** a command returns. Before the first read, the frames show em dashes.
68
+ - A failed read **clears** every figure rather than retaining the previous one as though current.
69
+ - Timers are cleared on disconnect.
70
+
71
+ ## Verifying a face
72
+
73
+ Run `scripts/record.mjs --card` for the mechanical checks, then look at it:
74
+
75
+ 1. Render at **360, 768 and 1280 px**. No horizontal overflow at any width.
76
+ 2. Render on the **real dashboard tokens** (dark), not on a white test page. A face that only reads on white is broken in production.
77
+ 3. Exercise every state: credential present, credential missing, provider unreachable, call rejected, empty, stale.
78
+ 4. Put it beside another plugin's face. If you cannot tell which is which from the layout alone, it is not finished.
79
+ 5. Confirm no secret value can reach the DOM in any state.
80
+
81
+ ## What a face must never do
82
+
83
+ - Never seed a value, a hostname, a reading or a status word.
84
+ - Never show a reassuring default in place of an unknown.
85
+ - Never render a secret, in any state, for any reason.
86
+ - Never collect a credential.
87
+ - Never present a command name as the primary structure.
88
+ - Never derive its screens from the command list.
89
+ - Never style a destructive action as the obvious next step.
90
+ - Never render as a narrow column when width is available.
@@ -0,0 +1,120 @@
1
+ # The scaffold
2
+
3
+ A plugin's capability may be wanted inside a **different application** — someone else's app, which owns the code and ships without Total Recall. The **scaffold** is that capability, extracted so a builder can put it into their application and use it.
4
+
5
+ The plugin is the reference implementation. The scaffold is what a builder takes so nobody starts from zero.
6
+
7
+ ---
8
+
9
+ ## A scaffold is not a copy of the plugin
10
+
11
+ Measured against the current ecosystem, vendoring a plugin copies its whole tree, and the result is unusable in an app:
12
+
13
+ | What a builder receives | Why it fails |
14
+ | --- | --- |
15
+ | the card face | its only data channel is `host.run`, a Total Recall host the app does not have |
16
+ | an auth client that shells out to `total-recall` | the app breaks the moment Total Recall is absent — `Auth credential read failed` |
17
+ | request logic inlined in `argv`-parsing handlers | there is nothing to import; 19 of 34 plugins export only `run` |
18
+ | `https://example.com/checkout/success`, a default amount of `2000` | a real app would send paying customers to a placeholder domain |
19
+
20
+ The test is not "does it run". It is **"can a builder lay this in without rewriting it?"**
21
+
22
+ ## What a scaffold contains
23
+
24
+ **The capability, as code the application imports:**
25
+
26
+ ```js
27
+ // capability/index.mjs — exported, importable, host-free
28
+ export async function createCheckoutSession({
29
+ secretKey, // supplied by the caller; never read from a store
30
+ amount, currency,
31
+ successUrl, cancelUrl, // the caller's URLs; never a placeholder
32
+ productName,
33
+ fetchImpl = fetch, // injectable: the app uses its own client, tests run offline
34
+ }) { /* … returns data … */ }
35
+
36
+ export function verifyWebhookSignature({ payload, signatureHeader, secret }) { /* … */ }
37
+ ```
38
+
39
+ The rules the shape enforces:
40
+
41
+ - **Explicit parameters.** No `argv`, no `process.env`, no module-level singleton, no ambient credential.
42
+ - **No defaults for environment values.** A missing `successUrl` is the caller's error to fix, never a silent `example.com`.
43
+ - **Injected transport.** The app supplies its own HTTP client; a test needs no network.
44
+ - **Returned data, not printed text.** Printing is the CLI's job.
45
+ - **Thrown errors, never `process.exitCode`.** The application decides how to fail.
46
+ - **No Total Recall.** The capability does not know it exists.
47
+ - **No card, no design tokens, no logo.** There is no dashboard to render them.
48
+
49
+ **Plus a builder entry point** — `BRICK.md`, short and concrete:
50
+
51
+ ```
52
+ # Checkout capability
53
+
54
+ Copy `capability/` into your app.
55
+
56
+ import { createCheckoutSession } from './capability/index.mjs'
57
+
58
+ await createCheckoutSession({
59
+ secretKey: process.env.STRIPE_SECRET_KEY, // your own configuration, never ours
60
+ amount: 2500, currency: 'usd',
61
+ successUrl: `${origin}/checkout/success`,
62
+ cancelUrl: `${origin}/checkout/cancel`,
63
+ productName: 'General admission',
64
+ })
65
+ ```
66
+
67
+ It states what to import, what to pass, where credentials come from, and what comes back. Not a description of a CLI.
68
+
69
+ ## What a scaffold never contains
70
+
71
+ - the card face, `ui/DESIGN.md`, a logo
72
+ - the plugin manifest — a manifest of Total Recall commands, secrets and a card means nothing in an app
73
+ - any call to `total-recall`, `TOTAL_RECALL_BIN`, or an auth store
74
+ - `argv` parsing or `console.log` as its output
75
+ - a placeholder URL, an example default, or the author's own values
76
+ - a message telling the app's users to install another product
77
+
78
+ ## How the plugin presents it
79
+
80
+ One source, two artifacts, separated by directory and declared in the manifest:
81
+
82
+ ```
83
+ tr-plugin-<id>/
84
+ capability/ ← the scaffold payload
85
+ index.mjs
86
+ cli.mjs ← the Total Recall entry; parses argv, resolves credentials, calls capability/
87
+ ui/ ← the face; Total Recall only
88
+ test/
89
+ ```
90
+
91
+ ```json
92
+ "capability": { "entry": "capability/index.mjs", "exports": ["createCheckoutSession", "verifyWebhookSignature"] }
93
+ ```
94
+
95
+ - `capability` present → the plugin is vendorable as a scaffold.
96
+ - `capability` absent → vendoring reports that this plugin has no separable capability, instead of copying a program into the app.
97
+
98
+ The CLI becomes a **thin adapter**: parse arguments, resolve credentials through auth, call the capability, format the output. The domain logic lives in `capability/` and is exercised by both.
99
+
100
+ ## Verifying a scaffold
101
+
102
+ - [ ] It runs with `TOTAL_RECALL_BIN` unset and no auth store present.
103
+ - [ ] Every exported function is callable with caller-supplied arguments and an injected transport.
104
+ - [ ] No `total-recall` string is reachable from the payload.
105
+ - [ ] No `example.com`, no author default, no placeholder value.
106
+ - [ ] No `ui/`, no `card.js`, no manifest.
107
+ - [ ] The suite fails if the capability spawns a process — proving standalone operation rather than assuming it.
108
+ - [ ] Vendored into a clean app, its suite passes there.
109
+
110
+ ## Distribution
111
+
112
+ ```json
113
+ "distribution": { "tier": "official", "license": "open" }
114
+ ```
115
+
116
+ `tier`: `core`, `official`, `personal`, `community`. `license`: `open` (vendorable and shareable) or `closed` (an operated service behind a thin client).
117
+
118
+ Monetized plugins state their model in `monetization` — `model`, `price_cents` or `take_rate_basis_points`, `period`, `license_key_secret`, `checkout_url`. **Never rely on a local license check for protection**: a closed plugin's value lives on the server, not in the client.
119
+
120
+ A third party publishes with the same manifest and the same conformance checks. A store lists signed, immutable versions and never runs plugin code.