@rubytech/create-maxy 1.0.890 → 1.0.891

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 (48) hide show
  1. package/package.json +2 -2
  2. package/payload/platform/plugins/admin/PLUGIN.md +3 -2
  3. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.d.ts +2 -0
  4. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.d.ts.map +1 -0
  5. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.js +88 -0
  6. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.js.map +1 -0
  7. package/payload/platform/plugins/admin/mcp/dist/index.js +62 -5
  8. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  9. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts +13 -0
  10. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts.map +1 -1
  11. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js +14 -0
  12. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js.map +1 -1
  13. package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +1 -1
  14. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  15. package/payload/platform/plugins/docs/references/troubleshooting.md +2 -0
  16. package/payload/platform/plugins/memory/PLUGIN.md +1 -1
  17. package/payload/platform/scripts/check-skill-load-coverage.mjs +100 -0
  18. package/payload/platform/scripts/logs-read.sh +108 -5
  19. package/payload/platform/templates/agents/admin/IDENTITY.md +10 -10
  20. package/payload/platform/templates/agents/public/IDENTITY.md +1 -1
  21. package/payload/platform/templates/specialists/agents/content-producer.md +2 -2
  22. package/payload/platform/templates/specialists/agents/database-operator.md +3 -3
  23. package/payload/platform/templates/specialists/agents/personal-assistant.md +2 -2
  24. package/payload/platform/templates/specialists/agents/project-manager.md +1 -1
  25. package/payload/platform/templates/specialists/agents/research-assistant.md +1 -1
  26. package/payload/server/chunk-NZ6D7QJM.js +3571 -0
  27. package/payload/server/chunk-RICR2PXW.js +9771 -0
  28. package/payload/server/client-pool-PG23WNFG.js +34 -0
  29. package/payload/server/maxy-edge.js +27 -3
  30. package/payload/server/public/assets/{Checkbox-ebZSKvw2.js → Checkbox-CeujDRv0.js} +1 -1
  31. package/payload/server/public/assets/{admin-Ewxzru2U.js → admin-BM3orGyK.js} +2 -2
  32. package/payload/server/public/assets/data-LYciLZK9.js +1 -0
  33. package/payload/server/public/assets/graph-C-SKAbGX.js +1 -0
  34. package/payload/server/public/assets/{graph-labels-DHQuVOgO.js → graph-labels-Co03qEv5.js} +1 -1
  35. package/payload/server/public/assets/jsx-runtime-BcZkJOEw.css +1 -0
  36. package/payload/server/public/assets/{page-DL8yJkUn.js → page-C4E0CWHe.js} +1 -1
  37. package/payload/server/public/assets/{page-DJiTa_Y_.js → page-DGLz4ozf.js} +1 -1
  38. package/payload/server/public/assets/{public-BS-tmbAu.js → public-rILg7e8-.js} +1 -1
  39. package/payload/server/public/assets/{useVoiceRecorder-COlUADaA.js → useVoiceRecorder-D3Upd7Q3.js} +1 -1
  40. package/payload/server/public/data.html +5 -5
  41. package/payload/server/public/graph.html +6 -6
  42. package/payload/server/public/index.html +8 -8
  43. package/payload/server/public/public.html +5 -5
  44. package/payload/server/server.js +5 -3
  45. package/payload/server/public/assets/data-pOc8b2rA.js +0 -1
  46. package/payload/server/public/assets/graph-DeG4HsDI.js +0 -1
  47. package/payload/server/public/assets/jsx-runtime-CqFGUuze.css +0 -1
  48. /package/payload/server/public/assets/{jsx-runtime-BCHoQyWP.js → jsx-runtime-BWYXu1CT.js} +0 -0
@@ -18,4 +18,17 @@ export interface PluginReadHint {
18
18
  }
19
19
  export declare function findSkillOwners(platformRoot: string, skillName: string): SkillFindResult;
20
20
  export declare function computePluginReadHint(platformRoot: string, pluginName: string, file: string): PluginReadHint | null;
21
+ export type SkillLoadOutcome = {
22
+ status: "unique";
23
+ pluginName: string;
24
+ file: string;
25
+ absolutePath: string;
26
+ body: string;
27
+ } | {
28
+ status: "ambiguous";
29
+ candidates: SkillOwner[];
30
+ } | {
31
+ status: "not-found";
32
+ };
33
+ export declare function loadSkill(platformRoot: string, skillName: string): Promise<SkillLoadOutcome>;
21
34
  //# sourceMappingURL=skill-resolution.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skill-resolution.d.ts","sourceRoot":"","sources":["../src/skill-resolution.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,CAAC,UAAU,CAAC,CAAA;CAAE,GAC9C;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,UAAU,EAAE,CAAA;CAAE,GACjD;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,EAAE,CAAA;CAAE,CAAC;AAU5C,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,CA4BxF;AAcD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,cAAc,GAAG,IAAI,CASvB"}
1
+ {"version":3,"file":"skill-resolution.d.ts","sourceRoot":"","sources":["../src/skill-resolution.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,CAAC,UAAU,CAAC,CAAA;CAAE,GAC9C;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,UAAU,EAAE,CAAA;CAAE,GACjD;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,EAAE,CAAA;CAAE,CAAC;AAU5C,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,CA4BxF;AAcD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,cAAc,GAAG,IAAI,CASvB;AASD,MAAM,MAAM,gBAAgB,GACxB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1F;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,UAAU,EAAE,CAAA;CAAE,GACjD;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC;AAE5B,wBAAsB,SAAS,CAC7B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CAY3B"}
@@ -10,6 +10,7 @@
10
10
  // (plugin dir → skill dir), never recursive, so deeper skill subtrees and
11
11
  // sibling references/ directories are ignored.
12
12
  import { existsSync, readdirSync, statSync } from "node:fs";
13
+ import { readFile } from "node:fs/promises";
13
14
  import { resolve } from "node:path";
14
15
  const SKILL_FILE_PATH = /^skills\/([a-z0-9][a-z0-9-]*)\//;
15
16
  // Task 1000 — the symmetric misuse: skill slug buried inside `pluginName`
@@ -75,4 +76,17 @@ export function computePluginReadHint(platformRoot, pluginName, file) {
75
76
  return null;
76
77
  return { pluginName: owner.pluginName, file: correctedFile };
77
78
  }
79
+ export async function loadSkill(platformRoot, skillName) {
80
+ const result = findSkillOwners(platformRoot, skillName);
81
+ if (result.status === "ambiguous") {
82
+ return { status: "ambiguous", candidates: result.candidates };
83
+ }
84
+ if (result.status === "not-found") {
85
+ return { status: "not-found" };
86
+ }
87
+ const [{ pluginName, file }] = result.candidates;
88
+ const absolutePath = resolve(platformRoot, "plugins", pluginName, file);
89
+ const body = await readFile(absolutePath, "utf-8");
90
+ return { status: "unique", pluginName, file, absolutePath, body };
91
+ }
78
92
  //# sourceMappingURL=skill-resolution.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"skill-resolution.js","sourceRoot":"","sources":["../src/skill-resolution.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skill-resolution.js","sourceRoot":"","sources":["../src/skill-resolution.ts"],"names":[],"mappings":"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"}
@@ -72,7 +72,7 @@ Call `premium-deliver` with `pluginName` set to the plugin name. The tool handle
72
72
  - Scans for public agent templates
73
73
  - Returns a structured result with per-sub-plugin status and available templates
74
74
 
75
- Report the tool's result to the user. If templates are found, present them and ask whether the user wants to create any now. For template creation, load the public agent management skill via `plugin-read` from `admin/skills/public-agent-manager/SKILL.md` and follow the "Create from Template" instructions, passing the template directory path from the tool's result.
75
+ Report the tool's result to the user. If templates are found, present them and ask whether the user wants to create any now. For template creation, run `skill-load skillName=public-agent-manager` and follow the "Create from Template" instructions, passing the template directory path from the tool's result.
76
76
 
77
77
  If the delivered plugin has specialist agents (files in `agents/` with the `{plugin-name}--{agent-name}.md` naming convention, distinct from template directories), load the specialist management skill and follow the premium plugin agent activation instructions.
78
78
 
@@ -129,7 +129,7 @@ Skill content, plugin manifests, agent templates, and reference files reference
129
129
 
130
130
  **Author rule:** never write the literal string `Maxy` (or any brand name) in shipped skill, plugin, or template content. Use `{{productName}}` whenever the operator should see the brand name. The audit grep `grep -rn "\bMaxy\b" platform/plugins/admin/skills/ platform/plugins/*/skills/ platform/templates/agents/` must return zero matches; a literal brand name is a defect, not a stylistic choice.
131
131
 
132
- The runtime substitution happens at the read sites that flow content into a system prompt or operator-visible UI (admin agent's `plugin-read` tool, public agent's recursive plugin assembly, IDENTITY/SOUL/AGENTS/KNOWLEDGE markdown reads). Missing or empty `productName` hard-fails — there is no fallback to a default brand string. See [.docs/agents.md](../../.docs/agents.md) § "Brand templating" for the full contract.
132
+ The runtime substitution happens at every read site that flows content into a system prompt or operator-visible UI: the admin agent's `plugin-read` tool (references + `PLUGIN.md`), the `skill-load` tool (SKILL.md by skill name — one-call resolver+reader, the canonical primitive for SKILL.md), the public agent's recursive plugin assembly, and `IDENTITY` / `SOUL` / `AGENTS` / `KNOWLEDGE` markdown reads. Missing or empty `productName` hard-fails — there is no fallback to a default brand string. See [.docs/agents.md](../../.docs/agents.md) § "Brand templating" for the full contract.
133
133
 
134
134
  ## MCP Plugin Observability (for plugin authors)
135
135
 
@@ -188,6 +188,8 @@ replaced the ttyd/xterm admin terminal with a detached action runner. Upgrades a
188
188
 
189
189
  **"Connection lost — reconnecting…" banner appears during an upgrade.** On post-Task-666 bundles this should never appear while the upgrade is in flight — the routes live on the always-on edge. If you see the banner during steps 8→11 of an upgrade on a current bundle, it is a **regression**, not expected behaviour: the routes have drifted back onto `maxy.service` or the edge's Hono dispatcher is not intercepting them. Check `~/.maxy/logs/edge.log` for `[edge-admin]` entries during the window; absence means the edge never received the request. The prebuild gate `platform/ui/scripts/check-edge-admin-routes.mjs` exists specifically to catch this drift before it ships.
190
190
 
191
+ **Agent does not respond to any message after a fresh install or restart.** The chat ingress quartet surfaces where the request silently stopped. From admin chat, ask the agent to read the chat-ingress timeline for the last 5 minutes — internally it runs `logs-read.sh --tail chat-attempts 5`, which cross-greps `edge.log` and `server.log` for the four checkpoints (edge inbound, admin-auth verdict, handler entry, edge outcome). Any missing row localises the failure: no edge inbound = request never reached the device (network, DNS, or cloudflare tunnel); inbound present + no auth verdict = handler unreachable (Hono routing regression); auth verdict = reject + a `code=` value the client banner matches; auth = accept + no handler entry = post-auth routing regression; all three rows present + no edge outcome = upstream crash or socket abort. See the developer doc `.docs/web-chat.md#chat-ingress-quartet` for the full state-machine and the prefix taxonomy.
192
+
191
193
  **Heartbeat stalled** (log panel header shows rising `silent Ns` amber badge).
192
194
 
193
195
  - Open the log panel header: `state: <systemd_state>` tells you the unit's current state.
@@ -87,7 +87,7 @@ Graph hygiene is **agent-directed, case by case** — no autonomous rule engine,
87
87
 
88
88
  ## Conversational Memory
89
89
 
90
- The owner's profile and preferences accumulate organically from conversation — never from questionnaires. Load the conversational memory skill via `plugin-read` for full guidance on when to observe preferences, how to handle remember/forget requests, and how to answer "what do you know about me?" transparently with confidence scores and evidence trail.
90
+ The owner's profile and preferences accumulate organically from conversation — never from questionnaires. Run `skill-load skillName=conversational-memory` for full guidance on when to observe preferences, how to handle remember/forget requests, and how to answer "what do you know about me?" transparently with confidence scores and evidence trail.
91
91
 
92
92
  ## UserProfile + Person Field Management
93
93
 
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env node
2
+ // Task 1015 — build-time gate: rejects prose that tells an agent to load a
3
+ // SKILL.md via `plugin-read`. `skill-load skillName=<name>` is the canonical
4
+ // resolve+read primitive for skills; `plugin-read` retains ownership of
5
+ // `references/*` and `PLUGIN.md` (both inherently plugin-scoped).
6
+ //
7
+ // Two phrasing classes regressed historically (corrections ledger:
8
+ // `path-as-pluginName`, count >= 1):
9
+ // 1. Literal-path: "Load `<plugin>/skills/<slug>/SKILL.md` via `plugin-read`"
10
+ // 2. Manifest-pointer: "load via `plugin-read` (find its path in the manifest ...)"
11
+ // Both surface the same failure — the LLM packs the path into the `pluginName`
12
+ // argument and hits the not-found branch. This gate fails CI if either phrasing
13
+ // reappears in `platform/templates/` or in any plugin's `SKILL.md` / `PLUGIN.md`.
14
+ //
15
+ // Scope: prose-only Markdown the agent reads as instructions. Code files are
16
+ // out of scope (TypeScript / shell already lint elsewhere). References under
17
+ // `skills/*/references/` are out of scope because they document end-user
18
+ // behaviour, not agent routing. The MCP server's `index.ts` and tests are
19
+ // covered by their own type checks + the `skill-load.test.ts` suite.
20
+
21
+ import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs'
22
+ import { dirname, join, basename } from 'node:path'
23
+ import { fileURLToPath } from 'node:url'
24
+
25
+ const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url))
26
+ const REPO_ROOT = join(SCRIPT_DIR, '..', '..')
27
+
28
+ const SCAN_ROOTS = [
29
+ join(REPO_ROOT, 'platform', 'templates'),
30
+ join(REPO_ROOT, 'platform', 'plugins'),
31
+ ]
32
+
33
+ // Phrasing 1 — literal SKILL.md path with `via plugin-read`. Matches every
34
+ // historical site that named a path string.
35
+ const PATH_PHRASING_RE = /Load\s+[`"]?[\w/-]*skills\/[a-z0-9-]+\/SKILL\.md[`"]?\s+via\s+`?plugin-read`?/i
36
+
37
+ // Phrasing 2 — manifest-pointer "via plugin-read (find its path in the manifest ...)"
38
+ // from sites that referred the agent to the manifest instead of naming a path.
39
+ const MANIFEST_PHRASING_RE = /via\s+`?plugin-read`?\s*\(\s*find its path in the manifest/i
40
+
41
+ // Only scan files that an agent reads as routing instructions.
42
+ function shouldScanFile(filePath) {
43
+ const base = basename(filePath)
44
+ if (base === 'SKILL.md' || base === 'PLUGIN.md' || base === 'IDENTITY.md' || base === 'SOUL.md') return true
45
+ // Specialist agent files live under platform/templates/specialists/agents/*.md
46
+ if (filePath.includes('/templates/specialists/agents/') && filePath.endsWith('.md')) return true
47
+ // Other markdown under templates/agents/ (admin/public IDENTITY.md handled by base check)
48
+ if (filePath.includes('/templates/agents/') && filePath.endsWith('.md')) return true
49
+ return false
50
+ }
51
+
52
+ const SKIP_DIR_NAMES = new Set(['node_modules', 'dist', '.git', 'references', 'archive'])
53
+
54
+ function* walk(root) {
55
+ if (!existsSync(root)) return
56
+ for (const entry of readdirSync(root)) {
57
+ if (SKIP_DIR_NAMES.has(entry)) continue
58
+ const full = join(root, entry)
59
+ let stat
60
+ try { stat = statSync(full) } catch { continue }
61
+ if (stat.isDirectory()) {
62
+ yield* walk(full)
63
+ } else if (stat.isFile()) {
64
+ yield full
65
+ }
66
+ }
67
+ }
68
+
69
+ const violations = []
70
+
71
+ for (const root of SCAN_ROOTS) {
72
+ for (const file of walk(root)) {
73
+ if (!shouldScanFile(file)) continue
74
+ let text
75
+ try { text = readFileSync(file, 'utf-8') } catch { continue }
76
+ const lines = text.split('\n')
77
+ for (let i = 0; i < lines.length; i++) {
78
+ const line = lines[i]
79
+ if (PATH_PHRASING_RE.test(line)) {
80
+ violations.push({ file, line: i + 1, phrasing: 'literal-path', text: line.trim() })
81
+ } else if (MANIFEST_PHRASING_RE.test(line)) {
82
+ violations.push({ file, line: i + 1, phrasing: 'manifest-pointer', text: line.trim() })
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ if (violations.length > 0) {
89
+ console.error(`check-skill-load-coverage: ${violations.length} prose site(s) still tell the agent to load a skill via plugin-read.`)
90
+ console.error(`Rewrite each to: Run \`skill-load skillName=<name>\``)
91
+ console.error(``)
92
+ for (const v of violations) {
93
+ const rel = v.file.replace(REPO_ROOT + '/', '')
94
+ console.error(` ${rel}:${v.line} [${v.phrasing}]`)
95
+ console.error(` ${v.text.slice(0, 200)}${v.text.length > 200 ? '…' : ''}`)
96
+ }
97
+ process.exit(1)
98
+ }
99
+
100
+ console.log(`check-skill-load-coverage: ok (0 prose sites use legacy plugin-read for skills)`)
@@ -14,10 +14,12 @@
14
14
  #
15
15
  # Types: agent-stream (canonical, per-session tool-use/tool-result archive;
16
16
  # `system` is kept as a backwards-compatible alias), session, error,
17
- # heartbeat, public, server, mcp, vnc
17
+ # heartbeat, public, server, mcp, vnc, chat-attempts
18
18
  # For per-session types (agent-stream/system/session/error/public): sessionKey
19
19
  # is required in the first mode. For platform-scoped types (server/vnc/
20
- # heartbeat): the id is ignored.
20
+ # heartbeat): the id is ignored. chat-attempts is --tail-only (Task 1018):
21
+ # cross-grep of edge.log + server.log for the chat-ingress quartet within
22
+ # the most recent N minutes.
21
23
  #
22
24
  # Every invocation writes a one-line trailer describing files searched,
23
25
  # matches returned, and files rejected — empty output never leaves a reader
@@ -116,7 +118,13 @@ is_per_conversation_type() {
116
118
  }
117
119
 
118
120
  SEARCH_TYPES="agent-stream error session public server mcp vnc"
119
- VALID_TYPES="agent-stream, system, session, error, heartbeat, public, server, mcp, vnc"
121
+ VALID_TYPES="agent-stream, system, session, error, heartbeat, public, server, mcp, vnc, chat-attempts"
122
+
123
+ # Task 1018 — chat-attempts cross-grep prefixes. One row per chat-ingress
124
+ # checkpoint emitted across edge.log + server.log: edge-side inbound/outcome,
125
+ # admin-auth gate verdict, chat-route handler entry. Absence of a row at any
126
+ # checkpoint localises the failure to one stage of the ingress pipeline.
127
+ CHAT_ATTEMPT_GREP='\[edge-admin\] inbound|\[edge-admin\] outcome|\[admin-auth\] outcome|\[chat-route\] entered'
120
128
 
121
129
  # Authoritative sessionKey character set.
122
130
  # Writer-side (Task 1008) emits `sk_<hex16>` filenames; the underscore must
@@ -133,14 +141,19 @@ usage() {
133
141
  Usage:
134
142
  logs-read.sh <sessionKey-or-prefix> [type] Read {prefix}-{sessionKey}.log
135
143
  logs-read.sh --tail [type] [lines] Tail most recent log of type
144
+ logs-read.sh --tail chat-attempts [min] Cross-grep edge.log + server.log
145
+ for the chat-ingress quartet
136
146
  logs-read.sh --grep <sessionKey> [type] Legacy grep across log files
137
147
 
138
148
  Types: $VALID_TYPES
139
- Default type: agent-stream | Default lines: 50
149
+ Default type: agent-stream | Default lines: 50 | Default chat-attempts minutes: 5
140
150
 
141
151
  Per-session types (agent-stream, system, session, error, public) require
142
152
  sessionKey in the first mode — the log file is named {prefix}-{sessionKey}.log.
143
153
  Platform-scoped types (server, vnc, heartbeat) ignore the id.
154
+ chat-attempts is --tail-only — it aggregates the four ingress checkpoints
155
+ ([edge-admin] inbound, [admin-auth] outcome, [chat-route] entered,
156
+ [edge-admin] outcome) into one timeline.
144
157
  EOF
145
158
  exit 2
146
159
  }
@@ -148,11 +161,93 @@ EOF
148
161
  validate_type() {
149
162
  local t="$1"
150
163
  case "$t" in
151
- agent-stream|system|session|error|heartbeat|public|server|mcp|vnc) return 0 ;;
164
+ agent-stream|system|session|error|heartbeat|public|server|mcp|vnc|chat-attempts) return 0 ;;
152
165
  *) echo "Error: invalid type '$t'. Valid types: $VALID_TYPES" >&2; exit 2 ;;
153
166
  esac
154
167
  }
155
168
 
169
+ # Task 1018 — chat-attempts cross-grep mode. Combines edge.log + server.log
170
+ # lines matching the chat-ingress quartet, filtered to the last N minutes,
171
+ # sorted chronologically. Default window: 5 minutes (matches the typical
172
+ # "agent doesn't respond" report window — operator sees the silence,
173
+ # screenshots the chat, then runs this within a few minutes).
174
+ #
175
+ # Output preserves source-file prefix so operators can see whether the line
176
+ # came from the edge process (edge.log) or maxy-ui (server.log). On a
177
+ # successful chat POST the timeline reads:
178
+ #
179
+ # [edge-admin] inbound method=POST path=/api/admin/chat token=present … (edge.log)
180
+ # [admin-auth] outcome=accept … (server.log)
181
+ # [chat-route] entered route=admin method=POST cacheKey=… … (server.log)
182
+ # [edge-admin] outcome method=POST path=/api/admin/chat status=200 … (edge.log)
183
+ #
184
+ # Any missing row in that sequence is itself diagnostic. Three-strike rule:
185
+ # zero edge inbound = browser/network problem; inbound present + admin-auth
186
+ # missing = handler unreachable; admin-auth=reject = auth failure; entered
187
+ # missing after accept = Hono routing regression; outcome missing = upstream
188
+ # proxy crash.
189
+ chat_attempts_mode() {
190
+ local minutes="${1:-5}"
191
+ if ! [[ "$minutes" =~ ^[0-9]+$ ]]; then
192
+ echo "Error: minutes must be a number, got '$minutes'" >&2
193
+ exit 2
194
+ fi
195
+
196
+ local EDGE_LOG="$CONFIG_DIR/logs/edge.log"
197
+ local since_epoch
198
+ since_epoch=$(date -u -v-"${minutes}"M +%s 2>/dev/null || date -u -d "${minutes} minutes ago" +%s 2>/dev/null || true)
199
+ if [[ -z "$since_epoch" ]]; then
200
+ echo "Error: could not compute time window — neither BSD nor GNU date available" >&2
201
+ exit 2
202
+ fi
203
+
204
+ # Each log line carries an ISO-8601 timestamp at the head (server.log via
205
+ # pino, edge.log via console — both written line-buffered with leading
206
+ # `YYYY-MM-DDTHH:MM:SS` then either `.sssZ` or a space). awk filters to
207
+ # the time window; sed prefixes the source filename so the timeline
208
+ # remains attributable; sort -k1 keeps chronological order.
209
+ local filter_awk='
210
+ BEGIN { since = '"$since_epoch"' }
211
+ {
212
+ ts = substr($0, 1, 19)
213
+ gsub("T", " ", ts)
214
+ cmd = "date -u -j -f \"%Y-%m-%d %H:%M:%S\" \"" ts "\" +%s 2>/dev/null || date -u -d \"" ts "\" +%s 2>/dev/null"
215
+ cmd | getline epoch
216
+ close(cmd)
217
+ if (epoch >= since) print
218
+ }
219
+ '
220
+
221
+ local hits=0
222
+ local tmp
223
+ tmp=$(mktemp -t chat-attempts.XXXXXX)
224
+ trap 'rm -f "$tmp"' EXIT
225
+
226
+ if [[ -f "$EDGE_LOG" ]]; then
227
+ grep -E "$CHAT_ATTEMPT_GREP" "$EDGE_LOG" 2>/dev/null | awk "$filter_awk" | sed 's|^|edge.log |' >> "$tmp" || true
228
+ fi
229
+ if [[ -f "$SERVER_LOG" ]]; then
230
+ grep -E "$CHAT_ATTEMPT_GREP" "$SERVER_LOG" 2>/dev/null | awk "$filter_awk" | sed 's|^|server.log|' >> "$tmp" || true
231
+ fi
232
+
233
+ hits=$(wc -l < "$tmp" | tr -d ' ')
234
+ if [[ "$hits" -eq 0 ]]; then
235
+ echo "# chat-attempts (last ${minutes} min) — no events" >&2
236
+ echo "-- trailer: type=chat-attempts window_min=${minutes} matches=0 searched=edge.log,server.log" >&2
237
+ exit 1
238
+ fi
239
+
240
+ echo "# chat-attempts (last ${minutes} min — chronological)"
241
+ echo ""
242
+ # Sort by the timestamp column that begins immediately after the source-file
243
+ # prefix. Prefix is "edge.log " or "server.log" — both 10 chars before the
244
+ # timestamp begins, so column 11 onward is the chronological key.
245
+ sort -k1.11 "$tmp"
246
+ echo "" >&2
247
+ echo "-- trailer: type=chat-attempts window_min=${minutes} matches=${hits} searched=edge.log,server.log" >&2
248
+ exit 0
249
+ }
250
+
156
251
  # --- Per-session mode: prefix-match {prefix}{sessionKey-prefix}*.log ---
157
252
  #
158
253
  # Task 1006 — one filename shape per session: {prefix}{sessionKey}.log.
@@ -368,6 +463,14 @@ tail_mode() {
368
463
  local log_type="${1:-agent-stream}"
369
464
  local lines="${2:-50}"
370
465
 
466
+ # Task 1018 — chat-attempts is cross-grep + time-windowed, not single-file
467
+ # tail. Dispatch before validate_type's numeric `lines` check (which would
468
+ # be wrong here — argument 2 is `minutes`, not `lines`).
469
+ if [[ "$log_type" == "chat-attempts" ]]; then
470
+ chat_attempts_mode "${lines:-5}"
471
+ return
472
+ fi
473
+
371
474
  validate_type "$log_type"
372
475
 
373
476
  if ! [[ "$lines" =~ ^[0-9]+$ ]]; then
@@ -115,7 +115,7 @@ Everything else is out of bounds. You do not drive Cloudflare's dashboard via Pl
115
115
 
116
116
  When a sanctioned surface fails, report the failure with the exact output, cite the matching recovery step from `reset-guide.md`, and stop. Improvisation — "let me try a different flag", "let me check the dashboard myself", "let me call the Cloudflare API to list zones" — is the behaviour this rule exists to prevent. The cost of stopping is low; the cost of improvising is a state-corruption cascade that takes the operator far longer to unwind than a clean report of failure would.
117
117
 
118
- Load `plugins/cloudflare/skills/setup-tunnel/SKILL.md` via `plugin-read` on the first Cloudflare-related request of a session. The skill names the four sanctioned surfaces and the exact inputs each script requires.
118
+ Run `skill-load skillName=setup-tunnel` on the first Cloudflare-related request of a session. The skill names the four sanctioned surfaces and the exact inputs each script requires.
119
119
 
120
120
  ## Questions
121
121
 
@@ -129,9 +129,9 @@ Operationalises the CONCISE prerogative for clarification. Three rules:
129
129
 
130
130
  ## Tool Routing
131
131
 
132
- **Bundled-SKILL access contract.** Plugin skills and references live in the bundled npm package, not on disk under `<accountDir>/agents/admin/plugins/`. Load them with `mcp__admin__plugin-read` only — the `<plugin-manifest>` `Skills:` and `References:` lines name the exact `pluginName` and file path to pass. `Read`, `Glob`, and `Bash` against those paths will fail with `File does not exist`, and the runtime agent-loop-stop interceptor cannot distinguish a generic-error retry from a tool-routing mistake. Subagents inherit this contract via the parent system prompt — never dispatch an `Agent` subagent with a `Read` directive against a bundled SKILL path.
132
+ **Bundled-SKILL access contract.** Plugin skills and references live in the bundled npm package, not on disk under `<accountDir>/agents/admin/plugins/`. Load skills with `mcp__admin__skill-load skillName="<name>"` (one call: resolves the owning plugin and returns the SKILL.md body with brand placeholders substituted). Load references and `PLUGIN.md` with `mcp__admin__plugin-read` (plugin-scoped by their nature) — the `<plugin-manifest>` `Skills:` and `References:` lines name the exact arguments to pass. `Read`, `Glob`, and `Bash` against those paths will fail with `File does not exist`, and the runtime agent-loop-stop interceptor cannot distinguish a generic-error retry from a tool-routing mistake. Subagents inherit this contract via the parent system prompt — never dispatch an `Agent` subagent with a `Read` directive against a bundled SKILL path.
133
133
 
134
- **Plain-English precision pass.** Load `admin/skills/plainly/SKILL.md` via `plugin-read` on the first turn of a session where the user asks to explain, define, or pre-empts one of the trigger phrases ("explain in plain English", "what does X mean", "define X", "I don't understand", "what is this"), AND on the first turn where you are about to return a reply containing a term not in the operator's prior turn. Apply the AI-tells strip + recursive-rule pass to the reply before sending it. The skill applies to prose returned to the operator, not to MCP tool arguments — agent-to-machine payloads pass through unmodified.
134
+ **Plain-English precision pass.** Run `skill-load skillName=plainly` on the first turn of a session where the user asks to explain, define, or pre-empts one of the trigger phrases ("explain in plain English", "what does X mean", "define X", "I don't understand", "what is this"), AND on the first turn where you are about to return a reply containing a term not in the operator's prior turn. Apply the AI-tells strip + recursive-rule pass to the reply before sending it. The skill applies to prose returned to the operator, not to MCP tool arguments — agent-to-machine payloads pass through unmodified.
135
135
 
136
136
  Plugins provide domain-specific tools that query their own data stores directly. `memory-search` is a general-purpose semantic search across the entire knowledge graph — it finds nodes by vector similarity, which means results are ranked by semantic closeness to the query, not by domain relevance. A query containing the word "email" will surface product documentation *about* email features before it surfaces actual Email nodes whose content is unrelated to the query wording.
137
137
 
@@ -162,7 +162,7 @@ Consult LEARNINGS.md before repeating an approach that failed or interacting in
162
162
 
163
163
  ## Capabilities
164
164
 
165
- Your capabilities come from **MCP tools**, **specialist subagents** listed in `agents/admin/AGENTS.md`, and **native Claude Code tools** (Read, Grep, Glob for observation; Write, Edit for agent configuration). The `<plugin-manifest>` contains two sections: a `<specialist-domains>` block mapping intent domains to specialists, and full entries for plugins the admin agent handles directly. Use the manifest to find admin-owned plugin resources (skills, references) via `plugin-read`.
165
+ Your capabilities come from **MCP tools**, **specialist subagents** listed in `agents/admin/AGENTS.md`, and **native Claude Code tools** (Read, Grep, Glob for observation; Write, Edit for agent configuration). The `<plugin-manifest>` contains two sections: a `<specialist-domains>` block mapping intent domains to specialists, and full entries for plugins the admin agent handles directly. Use the manifest to find admin-owned plugin resources — load skills via `skill-load skillName=<name>` and references via `plugin-read`.
166
166
 
167
167
  When the user asks what you can do, answer from the specialist domains, admin-owned plugins, and business context in the graph. Only describe active capabilities in response to general queries. When the user's stated intent matches a dormant plugin's purpose, you may mention the dormant capability — see Dormant Plugin Nudges below.
168
168
 
@@ -171,7 +171,7 @@ When the user asks what you can do, answer from the specialist domains, admin-ow
171
171
  - Be proactive in surfacing what needs attention. Never proactive in acting on it — the Intent Gate applies.
172
172
  - When the owner asks what needs doing, or when context suggests a status check is appropriate, assess the state of the business from the graph and report what needs attention. Check the `businessType` property on the `LocalBusiness` node — when set, it determines which vertical schema reference to load alongside `schema-base.md` for structured writes.
173
173
  - When the business context in the graph is sparse or missing, learn the business, understand the stage, gather customer details, build a comprehensive picture.
174
- - When operational data is missing or incomplete on the LocalBusiness node, load the business-profile skill via `plugin-read` (find its path in the manifest under `admin`).
174
+ - When operational data is missing or incomplete on the LocalBusiness node, run `skill-load skillName=business-profile`.
175
175
  - Think strategically. Surface problems before they become urgent. Recommend actions based on what you know.
176
176
  - Never state a future commitment ("I'll flag", "I'll check", "I'll remind") without immediately creating the mechanism to fulfil it — a scheduled event, a task, or a workflow trigger. A commitment without a backing mechanism is a broken promise.
177
177
  - Store everything you learn about the business in the graph — not in files.
@@ -194,7 +194,7 @@ This is distinct from the rule about your own commitments (above). That rule say
194
194
 
195
195
  ## Conversational Memory
196
196
 
197
- You learn about the owner through conversation — never through questionnaires or onboarding forms. Load the conversational memory skill via `plugin-read` (find its path in the manifest under `memory`) for full guidance. The essentials:
197
+ You learn about the owner through conversation — never through questionnaires or onboarding forms. Run `skill-load skillName=conversational-memory` for full guidance. The essentials:
198
198
 
199
199
  - When the owner reveals a preference or working pattern, store it via `profile-update`. Explicit statements get `source: "explicit"`; behavioural patterns observed at least twice get `source: "behavioural"`. Always include `conversationId` for evidence linking.
200
200
  - When the owner says "remember this" or "forget that", use `profile-update` or `profile-delete` accordingly and confirm what you did.
@@ -208,7 +208,7 @@ Purchased premium plugins are automatically delivered from the staging area at e
208
208
 
209
209
  ## Public Agent Management
210
210
 
211
- Any request to create, edit, clone, list, preview, or delete a public agent must go through the public agent management skill. Load it via `plugin-read` (find its path in the manifest under `admin`). Do not duplicate or improvise agent operations outside the skill. Public agents are optional — the platform works without any.
211
+ Any request to create, edit, clone, list, preview, or delete a public agent must go through the public agent management skill. Run `skill-load skillName=public-agent-manager`. Do not duplicate or improvise agent operations outside the skill. Public agents are optional — the platform works without any.
212
212
 
213
213
  ## Admin User Management
214
214
 
@@ -229,7 +229,7 @@ Only the owner (or any current admin) can manage admins. Role is a label only
229
229
 
230
230
  ## Plugin and Account Management
231
231
 
232
- Plugin installation, removal, and account settings changes are managed via conversation. Load the relevant skill via `plugin-read` (find its path in the manifest under `admin`).
232
+ Plugin installation, removal, and account settings changes are managed via conversation. Run `skill-load skillName=plugin-management` for the relevant skill.
233
233
 
234
234
  ## WhatsApp Configuration
235
235
 
@@ -290,7 +290,7 @@ The `<specialist-domains>` block lists every specialist-owned tool with a descri
290
290
  - **No matching tool in the manifest** — fall back to memory-search. Only if memory-search cannot answer, and the capability is clearly admin-owned, use ToolSearch as a last resort.
291
291
  - After a specialist run, synthesise its results into the final response to the user.
292
292
  - Retain all task management. Specialists do not create, update, or complete tasks.
293
- - To install or remove specialists, load the specialist management skill via `plugin-read` (find its path in the manifest under `admin`). Keep `agents/admin/AGENTS.md` in sync.
293
+ - To install or remove specialists, run `skill-load skillName=specialist-management`. Keep `agents/admin/AGENTS.md` in sync.
294
294
 
295
295
  ## Browser
296
296
 
@@ -306,7 +306,7 @@ The document-editor's markdown parser fails silently on these specific typograph
306
306
 
307
307
  ## Plugins and Skills
308
308
 
309
- Your behaviour is defined by your loaded plugins and specialist domains. The `<plugin-manifest>` contains a `<specialist-domains>` block (domains owned by specialists — delegate, don't load skills) and full entries for admin-owned plugins (skills and references loadable via `plugin-read`). To load a skill or reference for an admin-owned plugin, call `plugin-read` with the plugin's directory name and the file path from the manifest. Do not use `plugin-read` for specialist-owned domains — the specialists have domain knowledge embedded in their system prompts.
309
+ Your behaviour is defined by your loaded plugins and specialist domains. The `<plugin-manifest>` contains a `<specialist-domains>` block (domains owned by specialists — delegate, don't load skills) and full entries for admin-owned plugins. To load a skill for an admin-owned plugin, run `skill-load skillName=<name>` — one call resolves the owning plugin and returns the SKILL.md body. To load a reference or `PLUGIN.md`, use `plugin-read` with the plugin's directory name and the file path from the manifest. Do not call either tool for specialist-owned domains — the specialists have domain knowledge embedded in their system prompts.
310
310
 
311
311
  ## Dormant Plugin Nudges
312
312
 
@@ -51,6 +51,6 @@ When you need to clarify intent before acting, follow two rules.
51
51
 
52
52
  ## Plain-English precision pass
53
53
 
54
- Load `admin/skills/plainly/SKILL.md` via `plugin-read` on the first text-producing turn of every session. Apply the AI-tells strip and the recursive plain-English rule to every reply you return to the visitor before emitting it — this is a prime-directive prerogative that overrides every other formatting preference. Customers are the highest-stakes audience this platform serves; plain English is not a polish step, it is the contract.
54
+ Run `skill-load skillName=plainly` on the first text-producing turn of every session. Apply the AI-tells strip and the recursive plain-English rule to every reply you return to the visitor before emitting it — this is a prime-directive prerogative that overrides every other formatting preference. Customers are the highest-stakes audience this platform serves; plain English is not a polish step, it is the contract.
55
55
 
56
56
  The skill applies to prose returned to the visitor and to text content passed through `render-component`. It does NOT apply to the structured arguments you pass into `render-component` (component name, option lists, IDs) — those are agent-to-machine payloads.
@@ -74,7 +74,7 @@ When a brief carries a "host this website" / "publish this site" / "put this onl
74
74
 
75
75
  The chain (≤4 turns, total):
76
76
 
77
- 1. **Read the skill texts** via `mcp__admin__plugin-read` — load `admin/skills/unzip-attachment/SKILL.md` and `admin/skills/publish-site/SKILL.md` into context. Both ship invariants (zip-slip guard, declared-uncompressed cap, slug regex, refusal taxonomy) that are mechanically enforced by their shell primitives — read, do not paraphrase.
77
+ 1. **Read the skill texts** run `skill-load skillName=unzip-attachment` then `skill-load skillName=publish-site` to load both into context. Both ship invariants (zip-slip guard, declared-uncompressed cap, slug regex, refusal taxonomy) that are mechanically enforced by their shell primitives — read, do not paraphrase.
78
78
  2. **Extract** the attached archive via the `unzip-attachment` skill's deterministic Bash flow. Output lands at `<accountDir>/extracted/<attachmentId>/`. Refusals (oversize, zip-slip, symlink, unreadable) are loud-fail; relay the operator message verbatim and stop.
79
79
  3. **Confirm the slug** with the operator if not already explicit. The slug is one or more `/`-separated segments under `<accountDir>/sites/`; each segment matches `/^[a-z0-9_][a-z0-9_.-]{0,99}$/i` and no segment starts with `.` or equals `..`. Never invent a slug.
80
80
  4. **Publish** via the `publish-site` skill's deterministic Bash flow — single `mv` from the extracted tree into `<accountDir>/sites/<slug>/`. Refusals (`unsafe-slug`, `destination-occupied`, `symlink-in-source`, `zero-html`, `ambiguous-html`) are loud-fail; relay the operator message verbatim and stop.
@@ -99,6 +99,6 @@ When a tool returns an error, surface the failure and its diagnostic context bef
99
99
 
100
100
  ## Plain-English precision pass
101
101
 
102
- Load `admin/skills/plainly/SKILL.md` via `plugin-read` on the first turn of every session. Apply the AI-tells strip + recursive plain-English rule to every prose artifact you return to the admin agent — captions, brochure prose, summaries, the "What you did" / "Summary" output contract above. This is a prime-directive prerogative; do not wait for admin to ask.
102
+ Run `skill-load skillName=plainly` on the first turn of every session. Apply the AI-tells strip + recursive plain-English rule to every prose artifact you return to the admin agent — captions, brochure prose, summaries, the "What you did" / "Summary" output contract above. This is a prime-directive prerogative; do not wait for admin to ask.
103
103
 
104
104
  **Receiving-endpoint carve-out.** Plainly applies to prose returned to admin or to `render-component` text content. It does NOT apply to arguments passed to `image-generate` — those are agent-to-machine payloads where technical descriptors (`backlit, shallow DOF, 35mm grain, recraft-v4 design composition`) are required vocabulary, not jargon to strip. Pass image prompts through verbatim.
@@ -110,7 +110,7 @@ You ingest two classes of input into the graph: **unstructured documents** (PDFs
110
110
 
111
111
  ### Branch A — unstructured documents (universal `document-ingest` skill)
112
112
 
113
- For any unstructured document, load `platform/plugins/memory/skills/document-ingest/SKILL.md` via `plugin-read` and follow it. The skill is generic — there are no per-doctype skills (no `cv-import`, no `contract-import`, no `transcript-import`). It loads the active ontology (`schema-base.md` + the active vertical schema named on the LocalBusiness `businessType` property), confirms the document subject (the anchor node) with the operator if the brief is ambiguous, runs Haiku-driven section classification via `memory-classify`, and writes typed graph nodes via `memory-ingest` with the natural edges named in the ontology.
113
+ For any unstructured document, run `skill-load skillName=document-ingest` and follow it. The skill is generic — there are no per-doctype skills (no `cv-import`, no `contract-import`, no `transcript-import`). It loads the active ontology (`schema-base.md` + the active vertical schema named on the LocalBusiness `businessType` property), confirms the document subject (the anchor node) with the operator if the brief is ambiguous, runs Haiku-driven section classification via `memory-classify`, and writes typed graph nodes via `memory-ingest` with the natural edges named in the ontology.
114
114
 
115
115
  The classifier maps document sections to typed ontology labels. It does not invent labels — every returned `kind` is verified against the loaded ontology label set; sections whose `kind` is not in the ontology are written as generic `:Section` nodes (the legacy fallback) with one `[document-ingest] unmapped-section` log line per. The operator sees ontology gaps named in the log; the document still completes.
116
116
 
@@ -118,7 +118,7 @@ The classifier maps document sections to typed ontology labels. It does not inve
118
118
 
119
119
  Per-source archive imports keep their own skill because their CSVs already encode entity types deterministically and need no LLM classifier. Currently shipped:
120
120
 
121
- - **linkedin-import** — LinkedIn Basic Data Export. Ships with references for `Profile.csv` and `Connections.csv`; additional CSVs land as new references inside the same plugin over time. Path: `platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md`. Load via `plugin-read` before any ingestion.
121
+ - **linkedin-import** — LinkedIn Basic Data Export. Ships with references for `Profile.csv` and `Connections.csv`; additional CSVs land as new references inside the same plugin over time. Run `skill-load skillName=linkedin-import` before any ingestion.
122
122
  - **conversation-archive** — Conversation transcripts (any source) ingest via the `conversation-archive` skill. One skill, one bash entry, one writer, with `--source <enum>` selecting the per-source normaliser (`whatsapp`, `telegram`, `signal`, `linkedin-messages`, `zoom-transcript`, `meeting-minutes`, `imessage`, `slack`, `other`). Phase 0 ships only `whatsapp`; other normalisers land per-source. Pipeline: operator confirms owner + every distinct sender → `bash platform/plugins/memory/bin/conversation-archive-ingest.sh <archive> --source <enum> --owner-element-id <id> --participant-person-ids <id1>,<id2>,... --scope <admin|public>`. The script normalises (per source), sessionizes at gap-hours boundaries (default 12h), classifies each session via Haiku (`memory-classify` with `mode='chat'`) into topic-bounded `:Section:Conversation` chunks, and writes them under a parent `:ConversationArchive` MERGEd on `conversationIdentity = sha256(accountId + ":" + sortedParticipantElementIds)`. Re-imports are delta-append; the writer is bound to the operator-confirmed sender set (parser-miss = LOUD-FAIL). SKILL: `platform/plugins/memory/skills/conversation-archive/SKILL.md`. Distinct from the live `whatsapp` plugin (Baileys QR pairing, in-memory store).
123
123
  - **conversation-archive-enrich** — Phase 2 over a named `:ConversationArchive`. Source-agnostic — runs against any archive produced by the `conversation-archive` skill regardless of source. Operator-triggered only (never auto-fires on Phase 1 completion). Walks `:Section:Conversation` chunks in pages via the read-only MCP tool `mcp__memory__conversation-archive-derive-insights` (which calls Haiku per chunk on OAuth, NOT the API key) and surfaces high-confidence claims for per-row operator gate (`wire / skip / reject`) over four kinds — `mention`, `task`, `preference`, `observed-relationship`. Idempotent on `(elementId(chunk), kind, contentHash)`: re-runs collapse identical claims via MERGE. Load: `platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md`. Trigger phrasing: operator names a specific archive AND asks for insights / enrichment / derived claims — never the ingest skill's completion event.
124
124
 
@@ -194,6 +194,6 @@ When a tool returns an error, surface the failure and its diagnostic context bef
194
194
 
195
195
  ## Plain-English precision pass
196
196
 
197
- Load `admin/skills/plainly/SKILL.md` via `plugin-read` on the first turn of every session. Apply the AI-tells strip + recursive plain-English rule to every prose return payload — ingest summaries, derived-insight reports, dedupe results, every textual report back to admin. This is a prime-directive prerogative; do not wait for admin to ask.
197
+ Run `skill-load skillName=plainly` on the first turn of every session. Apply the AI-tells strip + recursive plain-English rule to every prose return payload — ingest summaries, derived-insight reports, dedupe results, every textual report back to admin. This is a prime-directive prerogative; do not wait for admin to ask.
198
198
 
199
199
  **Receiving-endpoint carve-out.** Plainly applies to prose returned to admin. It does NOT apply to arguments passed to `memory-write`, `memory-classify`, `memory-ingest`, `memory-update`, or any `cypher-shell` invocation — those are agent-to-machine payloads where node labels (`:Person:LocalBusiness`), edge types (`PARTICIPANT`, `MENTIONS`), and Cypher tokens are required vocabulary, not jargon to strip. Pass Cypher statements and structured tool arguments through verbatim.
@@ -63,7 +63,7 @@ Manages events, appointments, and recurring triggers in the graph.
63
63
 
64
64
  Guides setting up a Cloudflare Tunnel so the platform is reachable via a custom domain. The Cloudflare plugin exposes zero MCP tools; every operation runs through one of four sanctioned surfaces — `setup-tunnel.sh` (autonomous), `reset-tunnel.sh` (reset), `manual-setup.md` (runbook), or `dashboard-guide.md` (click-paths the operator runs in their browser). The operator's logged-in Cloudflare dashboard is the single source of truth; the agent never reads or mutates account state via any API path.
65
65
 
66
- **Skill + references.** Load `plugins/cloudflare/skills/setup-tunnel/SKILL.md` via `plugin-read` on the first Cloudflare-related turn. It names the four surfaces and the inputs to collect before invoking the autonomous script.
66
+ **Skill + references.** Run `skill-load skillName=setup-tunnel` on the first Cloudflare-related turn. It names the four surfaces and the inputs to collect before invoking the autonomous script.
67
67
 
68
68
  **Autonomous setup.** Collect the admin hostname (and optionally public + apex hostnames), then invoke `~/setup-tunnel.sh <brand> <port> <admin-hostname> [<public-hostname>] [<apex-hostname>]` via Bash. The script handles OAuth login, tunnel creation, DNS routing, config + state files, service restart, and post-restart verification. When an apex hostname is passed, it prints an `ACTION REQUIRED` block — relay it verbatim so the operator edits the exact dashboard record the CLI cannot create.
69
69
 
@@ -204,6 +204,6 @@ When a tool returns an error (email send, WhatsApp send, browser navigate, Teleg
204
204
 
205
205
  ## Plain-English precision pass
206
206
 
207
- Load `admin/skills/plainly/SKILL.md` via `plugin-read` on the first turn of every session. Apply the AI-tells strip + recursive plain-English rule to every prose return payload — every report you send back to admin, every email body or WhatsApp text you compose for the owner to send, every status summary. This is a prime-directive prerogative; do not wait for admin to ask.
207
+ Run `skill-load skillName=plainly` on the first turn of every session. Apply the AI-tells strip + recursive plain-English rule to every prose return payload — every report you send back to admin, every email body or WhatsApp text you compose for the owner to send, every status summary. This is a prime-directive prerogative; do not wait for admin to ask.
208
208
 
209
209
  **Receiving-endpoint carve-out.** Plainly applies to prose returned to admin and to message bodies destined for human readers. It does NOT apply to MCP tool arguments — `email-send` subject/body fields that target a human reader DO get plainly; structured arguments to `schedule-create` or any browser-automation call do NOT.
@@ -127,6 +127,6 @@ When a tool returns an error, surface the failure and its diagnostic context bef
127
127
 
128
128
  ## Plain-English precision pass
129
129
 
130
- Load `admin/skills/plainly/SKILL.md` via `plugin-read` on the first turn of every session. Apply the AI-tells strip + recursive plain-English rule to every prose return payload — status updates, sprint summaries, project digests, every textual report back to admin. This is a prime-directive prerogative; do not wait for admin to ask.
130
+ Run `skill-load skillName=plainly` on the first turn of every session. Apply the AI-tells strip + recursive plain-English rule to every prose return payload — status updates, sprint summaries, project digests, every textual report back to admin. This is a prime-directive prerogative; do not wait for admin to ask.
131
131
 
132
132
  The skill applies to prose returned to admin. It does NOT apply to MCP tool arguments — `task-create` title/description fields meant for the operator's reading DO get plainly; structured task-state enums, IDs, and JSON-shaped relationship payloads do NOT.
@@ -110,6 +110,6 @@ Return to the admin agent:
110
110
 
111
111
  ## Plain-English precision pass
112
112
 
113
- Load `admin/skills/plainly/SKILL.md` via `plugin-read` on the first turn of every session. Apply the AI-tells strip + recursive plain-English rule to every prose return payload — research summaries, source synthesis, the "Key findings" section above, every textual report back to admin. This is a prime-directive prerogative; do not wait for admin to ask.
113
+ Run `skill-load skillName=plainly` on the first turn of every session. Apply the AI-tells strip + recursive plain-English rule to every prose return payload — research summaries, source synthesis, the "Key findings" section above, every textual report back to admin. This is a prime-directive prerogative; do not wait for admin to ask.
114
114
 
115
115
  The skill applies to prose returned to admin. It does NOT apply to MCP tool arguments — `WebSearch` queries and `WebFetch` URLs pass through verbatim. Source titles and URLs in the "Sources" list above are quoted literal data and pass through verbatim too.