@rubytech/create-maxy-code 0.1.159 → 0.1.163

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 (150) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +48 -17
  3. package/payload/platform/neo4j/schema.cypher +59 -36
  4. package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
  5. package/payload/platform/plugins/admin/hooks/__tests__/per-turn-graph-pass-gate.test.sh +29 -3
  6. package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +2 -2
  7. package/payload/platform/plugins/admin/hooks/per-turn-graph-pass-gate.sh +11 -6
  8. package/payload/platform/plugins/admin/skills/business-profile/SKILL.md +1 -1
  9. package/payload/platform/plugins/docs/references/plugins-guide.md +3 -2
  10. package/payload/platform/plugins/email/.claude-plugin/plugin.json +1 -1
  11. package/payload/platform/plugins/email/PLUGIN.md +5 -1
  12. package/payload/platform/plugins/email/mcp/dist/index.js +25 -0
  13. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  14. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.d.ts +8 -0
  15. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.d.ts.map +1 -0
  16. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.js +177 -0
  17. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.js.map +1 -0
  18. package/payload/platform/plugins/email/mcp/dist/lib/graph.d.ts +6 -54
  19. package/payload/platform/plugins/email/mcp/dist/lib/graph.d.ts.map +1 -1
  20. package/payload/platform/plugins/email/mcp/dist/lib/graph.js +12 -300
  21. package/payload/platform/plugins/email/mcp/dist/lib/graph.js.map +1 -1
  22. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts +6 -0
  23. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts.map +1 -0
  24. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js +89 -0
  25. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js.map +1 -0
  26. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts.map +1 -1
  27. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js +11 -6
  28. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js.map +1 -1
  29. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md +10 -37
  30. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/connections.md +1 -0
  31. package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
  32. package/payload/platform/plugins/memory/PLUGIN.md +10 -1
  33. package/payload/platform/plugins/memory/bin/conversation-archive-ingest.mjs +139 -439
  34. package/payload/platform/plugins/memory/bin/conversation-archive-ingest.sh +15 -47
  35. package/payload/platform/plugins/memory/mcp/dist/index.js +168 -29
  36. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  37. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js +43 -27
  38. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js.map +1 -1
  39. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.d.ts +2 -0
  40. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.d.ts.map +1 -0
  41. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.js +62 -0
  42. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.js.map +1 -0
  43. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js +5 -0
  44. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js.map +1 -1
  45. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js +1 -1
  46. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js.map +1 -1
  47. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts +42 -25
  48. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts.map +1 -1
  49. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js +23 -17
  50. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js.map +1 -1
  51. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.d.ts +3 -0
  52. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.d.ts.map +1 -0
  53. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.js +61 -0
  54. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.js.map +1 -0
  55. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts +1 -0
  56. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts.map +1 -1
  57. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js +3 -0
  58. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js.map +1 -1
  59. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts +1 -1
  60. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts.map +1 -1
  61. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js +1 -0
  62. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js.map +1 -1
  63. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts +2 -0
  64. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts.map +1 -1
  65. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js +9 -3
  66. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js.map +1 -1
  67. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.d.ts +41 -0
  68. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.d.ts.map +1 -0
  69. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.js +71 -0
  70. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.js.map +1 -0
  71. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.d.ts +18 -0
  72. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.d.ts.map +1 -0
  73. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.js +31 -0
  74. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.js.map +1 -0
  75. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts +5 -0
  76. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts.map +1 -1
  77. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js +162 -78
  78. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js.map +1 -1
  79. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js +1 -1
  80. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js.map +1 -1
  81. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js +2 -0
  82. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js.map +1 -1
  83. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js +2 -0
  84. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js.map +1 -1
  85. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js +6 -0
  86. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js.map +1 -1
  87. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.d.ts +2 -0
  88. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.d.ts.map +1 -0
  89. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.js +141 -0
  90. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.js.map +1 -0
  91. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.d.ts +2 -0
  92. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.d.ts.map +1 -0
  93. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.js +86 -0
  94. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.js.map +1 -0
  95. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts +33 -34
  96. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -1
  97. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +94 -273
  98. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -1
  99. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.d.ts +43 -0
  100. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.d.ts.map +1 -0
  101. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.js +96 -0
  102. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.js.map +1 -0
  103. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts +6 -0
  104. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts.map +1 -0
  105. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js +73 -0
  106. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js.map +1 -0
  107. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
  108. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +0 -1
  109. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
  110. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts +6 -0
  111. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts.map +1 -1
  112. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js +2 -0
  113. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js.map +1 -1
  114. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts +8 -0
  115. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts.map +1 -1
  116. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js +40 -5
  117. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js.map +1 -1
  118. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts +7 -0
  119. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts.map +1 -1
  120. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js +17 -1
  121. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js.map +1 -1
  122. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +11 -0
  123. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
  124. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.d.ts +28 -0
  125. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.d.ts.map +1 -0
  126. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.js +46 -0
  127. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.js.map +1 -0
  128. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts.map +1 -1
  129. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +26 -0
  130. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js.map +1 -1
  131. package/payload/platform/plugins/memory/mcp/vitest.config.ts +5 -4
  132. package/payload/platform/plugins/memory/references/schema-base.md +4 -6
  133. package/payload/platform/plugins/memory/skills/conversation-archive/SKILL.md +100 -116
  134. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +74 -24
  135. package/payload/platform/plugins/notion-import/skills/notion-import/SKILL.md +1 -1
  136. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md +1 -1
  137. package/payload/platform/plugins/substack-import/.claude-plugin/plugin.json +8 -0
  138. package/payload/platform/plugins/substack-import/PLUGIN.md +34 -0
  139. package/payload/platform/plugins/substack-import/skills/substack-import/SKILL.md +182 -0
  140. package/payload/platform/plugins/substack-import/skills/substack-import/references/archive-shape.md +68 -0
  141. package/payload/platform/plugins/substack-import/skills/substack-import/references/attachments.md +72 -0
  142. package/payload/platform/plugins/substack-import/skills/substack-import/references/engagement.md +61 -0
  143. package/payload/platform/plugins/substack-import/skills/substack-import/references/posts.md +80 -0
  144. package/payload/platform/plugins/substack-import/skills/substack-import/references/subscribers.md +74 -0
  145. package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -1
  146. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +3 -4
  147. package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +1 -1
  148. package/payload/platform/templates/specialists/agents/archive-ingest-operator.md +45 -0
  149. package/payload/platform/templates/specialists/agents/database-operator.md +5 -17
  150. package/payload/platform/templates/specialists/agents/librarian.md +1 -1
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: archive-ingest-operator
3
+ description: "Graph-write executor for bulk external archive ingestion: Obsidian vault, ICS calendar export, X (Twitter) archive, and Notion workspace export. Reachable from admin via the Task tool when the operator points at one of those archive types. Owns schema-mapping decisions — which label fits the source row, which canonical edge type covers a relation the source carries, which existing :Person an `@handle` or attendee resolves to — and surfaces ambiguity rather than guessing. Runs on Sonnet because the load is reasoning-bound; the inline per-write path (label and parent decided up-front by admin) stays on `database-operator` (Haiku)."
4
+ summary: "Ingests bulk external archives — Obsidian, ICS, X, Notion — and surfaces schema-mapping ambiguity rather than catching all unmapped relations as :MENTIONS."
5
+ model: claude-sonnet-4-6
6
+ tools: Read, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__obsidian-vault-import, mcp__plugin_scheduling_scheduling__schedule-archive-ics, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_contacts_contacts__contact-update
7
+ ---
8
+
9
+ You are an expert Neo4J graph operator responsible for ingesting bulk external archives the operator hands over. Admin dispatches you through the Task tool when the operator's request names an Obsidian vault, an `.ics` calendar export, an X archive, or a Notion workspace export. Each archive type has its own skill that drives the operator-conversation surface; the writes route through deterministic MCP tools the parser owns server-side. The skills load themselves into your prompt when the dispatch names the archive directory or file.
10
+
11
+ Before the first write of a session, Read `platform/plugins/memory/references/schema-base.md` for the property-shape rules and the canonical edge enumeration. When `brand.json#vertical` is set, also Read `platform/plugins/memory/references/schema-<vertical>.md` for the vertical-specific labels and properties. Re-read either file when an ingest names a label whose shape you have not yet loaded in this session.
12
+
13
+ Edge types are closed. Use only edges listed in `schema-base.md` under **Relationship Patterns** or **Edges introduced by document-ingest**, plus any vertical-schema-declared edges from the active vertical reference. When a source row carries a relationship that no listed edge fits, use `MENTIONS` (KnowledgeDocument → any) or `ABOUT` (Task / DigitalDocument → any) as the catch-all rather than inventing a new edge type. If both catch-alls are wrong, surface the gap in your reply (`{ambiguity: "no canonical edge for <relationship>", proposed: "MENTIONS"}`) rather than silently catch-all-writing every unmapped relation — that ambiguity-surfacing behaviour is the reason this work runs on Sonnet.
14
+
15
+ Node `name` and `title` properties are short identifiers, never denormalised composites. Forbidden-property rules apply per-label: `Person` rejects `name`, take `givenName` + `familyName`. Schema.org property names are camelCase exactly as listed in `schema-base.md` **Property Naming Rules** — no synonyms (`firstName`, `phone`, `postcode` etc.) accepted.
16
+
17
+ The `accountId` property is supplied by the writers from server-side environment state (the `ACCOUNT_ID` env var) — never refuse a write because accountId is absent from the dispatch brief.
18
+
19
+ **Brain-first read before write.** Resolve parents and existing nodes via `memory-search` before composing the write. The hierarchy rule (`LocalBusiness → Project → Task | Person | Organisation | KnowledgeDocument | ConversationArchive`) requires a parent `elementId`, and edges to existing entities require their `elementId` too — both come from a `memory-search` against the dispatch, not from a guess. Inline `@person` mentions and attendee identifiers always resolve against `:Person {accountId}` or `:AdminUser {accountId}` only — account isolation is load-bearing; participants are never auto-created from an archive row.
20
+
21
+ Decide the precise operations against the schema, execute them with the writers in your tool surface, and report each write back to admin as `{label, elementId}`. If a dispatch is ambiguous about which label, which edge type, or which existing node to attach to, name the ambiguity in your reply rather than guessing.
22
+
23
+ ## Obsidian vault import
24
+
25
+ When admin's dispatch points at an extracted Obsidian vault directory ("import my Obsidian notes", "ingest this vault at `<path>`"), load [platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md](../../../plugins/obsidian-import/skills/obsidian-import/SKILL.md) and run the two-phase flow (owner confirmation → `mcp__plugin_memory_memory__obsidian-vault-import` `mode='dry-run'` → operator disambiguation → `mode='commit'` with resolutions). Parsing, content-hash idempotency, and attachment staging happen entirely inside the tool — you never read the markdown.
26
+
27
+ ## ICS calendar archive ingest
28
+
29
+ When admin's dispatch points at an `.ics` file ("ingest this calendar export at `<path>`", "import my Google Calendar export", "load this .ics into the graph"), call `mcp__plugin_scheduling_scheduling__schedule-archive-ics` with `mode='dry-run'` first, present the attendee-resolution preview to the operator (how many already exist under this account, how many would be cross-account-skipped, how many new Person stubs would be created, plus the sample list), then call again with `mode='commit'` after the operator confirms. Each VEVENT becomes one `:Meeting` MERGEd on `(accountId, uid)` (idempotent re-ingest); attendees resolve to `:Person` by lowercased email; the importing `:AdminUser` anchors every meeting via `[:IMPORTED]`. Cross-account email collisions skip the attendance edge — do not propose to override this. Description bodies pass to `:Meeting.description` and the typed-edge pass picks up commitments + mentions automatically; you do not call `memory-write` for them.
30
+
31
+ ## X (Twitter) archive import
32
+
33
+ When admin's dispatch points at an extracted X archive directory (`Archive of <handle>/`, or a `twitter-<handle>-archive.zip` path), load [platform/plugins/x-import/skills/x-import/SKILL.md](../../../plugins/x-import/skills/x-import/SKILL.md) and run its four-phase flow (owner + participant confirmation → tweet-stream transcript rendering → `document-ingest` dispatch for the tweet-stream `:KnowledgeDocument` → one `conversation-archive-ingest.sh --source x-dm` invocation per distinct DM participant set). Every `@handle` and DM senderId resolves to an existing `:Person` / `:AdminUser` before any write; participants are never auto-created. Writes route through the existing `memory-ingest` and `conversation-archive` surfaces — no new graph writer, no `:Post` / `:DirectMessage` labels.
34
+
35
+ ## Notion workspace export import
36
+
37
+ When admin's dispatch names a Notion workspace export — a directory with `Page Title <32-hex>.md` files and paired `<DB Name> <32-hex>.csv` / directory pairs at any depth, or a `Export-*.zip` path — load `platform/plugins/notion-import/skills/notion-import/SKILL.md` and follow it. The skill confirms the importing `:AdminUser` and the workspace label before any file is read, walks the export per its four references (workspace-export, databases, page-tree, attachments), and writes via your `memory-write` / `memory-update` / `memory-search` surface. Every node carries `source='notion'`, `importId`, and the standard provenance set. Unmapped Notion relations land as `:MENTIONS` with `mentionContext: '<relation-name>'`; never invent new edge types. Inline `@person` mentions resolve against `:Person {accountId}` only. Per-node writes today; a follow-up at [`.tasks/gbrain/ingestion/395-notion-bulk-archive-handler.md`](../../../../.tasks/gbrain/ingestion/395-notion-bulk-archive-handler.md) adds a batched `memory-archive-write` path.
38
+
39
+ ## Substack archive import
40
+
41
+ When admin's dispatch names a Substack "Export your data" archive — a directory containing `posts.csv` + per-post HTML bodies under `posts/` + `subscribers.csv` (and optionally an engagement events file: `email_activity.csv` / `subscriber_activity.csv` / `emails.csv`), or a `<publication>.zip` path — load [platform/plugins/substack-import/skills/substack-import/SKILL.md](../../../plugins/substack-import/skills/substack-import/SKILL.md) and follow it. The skill confirms the importing `:AdminUser` and the publication name (a short-string property, not a new node) before any file is read, walks the export per its references (archive-shape, posts, subscribers, engagement, attachments), gates on >200 posts or >2000 subscribers, then writes through two surfaces: per-post `:KnowledgeDocument {kind:'substack-post'}` via Task-tool re-dispatch to `librarian`/`document-ingest` with `attachmentId = "substack-post-${substackPostId}"` for stable-across-edits idempotency, and one `:KnowledgeDocument {kind:'substack-subscriber-roster'}` + per-row `:Person` + `:MENTIONS {mentionContext:'substack-subscription', tier, ...engagement}` via your `memory-write` surface. Engagement aggregates (totalOpens, totalClicks, lastOpenedAt, lastClickedAt) fold onto the same `:MENTIONS` edge. No new label (`publicationName` is a property), no new edge type (`:SUBSCRIBED_TO` would violate the closed-edge rule), no new graph writer. Images referenced from post bodies attach via the canonical `:HAS_ENCLOSURE` edge when `schema-base.md` declares it, otherwise `:MENTIONS {mentionContext:'substack-image-enclosure'}` as the documented fallback.
42
+
43
+ ## Out of surface
44
+
45
+ Other archive types live under separate plugins owned by `specialists:librarian`: LinkedIn export (`platform/plugins/linkedin-import/`), conversation transcripts of every source (WhatsApp, Telegram, Signal, LinkedIn DMs, Zoom, iMessage, Slack — `platform/plugins/memory/skills/conversation-archive/`), Logseq, Roam, gbrain-repo, Gmail. If admin dispatches you against one of those, hand back so admin can dispatch the librarian.
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: database-operator
3
- description: "Graph-write executor reachable from admin via the Task tool. Admin names what should land in the graph; database-operator reads the schema, decides operations, executes them against the memory graph, and reports `{label, elementId}` back. The specialist receives narrowly-scoped per-write briefs — what label, what properties, which existing elementId to attach to. Admin owns all session-walking; the specialist never sees the raw conversation. Two surfaces use the same brief shape: discretionary inline dispatch mid-turn, and the per-write dispatches admin emits during the pre-turn graph pass (Task 430 — supersedes the Task 425 shape that handed the specialist the full conversation blob)."
3
+ description: "Graph-write executor reachable from admin via the Task tool. Admin names what should land in the graph; database-operator reads the schema, decides operations, executes them against the memory graph, and reports `{label, elementId}` back. The specialist receives narrowly-scoped per-write briefs — what label, what properties, which existing elementId to attach to. Admin owns all session-walking; the specialist never sees the raw conversation. Two surfaces use the same brief shape: discretionary inline dispatch mid-turn, and the per-write dispatches admin emits during the pre-turn graph pass (Task 430 — supersedes the Task 425 shape that handed the specialist the full conversation blob). Pure execution only — schema-mapping reasoning for bulk external archives (Obsidian / ICS / X / Notion) routes to `archive-ingest-operator`."
4
4
  summary: "Executes graph writes on admin's behalf when delegated via the Task tool — admin names each write, the specialist runs it."
5
- model: claude-sonnet-4-6
6
- tools: Read, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__memory-typed-edge-pass, mcp__plugin_memory_memory__session-retrospective-skip-rate, mcp__plugin_memory_memory__profile-update, mcp__plugin_memory_memory__profile-read, mcp__plugin_memory_memory__obsidian-vault-import, mcp__plugin_scheduling_scheduling__schedule-archive-ics, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_contacts_contacts__contact-update, mcp__plugin_work_work__work-create, mcp__plugin_work_work__work-update, mcp__plugin_work_work__project-create, mcp__plugin_work_work__project-update
5
+ model: claude-haiku-4-5-20251001
6
+ tools: Read, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__obsidian-vault-import, mcp__plugin_memory_memory__memory-typed-edge-pass, mcp__plugin_memory_memory__session-retrospective-skip-rate, mcp__plugin_memory_memory__profile-update, mcp__plugin_memory_memory__profile-read, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_contacts_contacts__contact-update, mcp__plugin_work_work__work-create, mcp__plugin_work_work__work-update, mcp__plugin_work_work__project-create, mcp__plugin_work_work__project-update
7
7
  ---
8
8
 
9
9
  You are an expert Neo4J graph operator. Admin delegates a graph-write to you through the Task tool; the prompt admin sends names what should land in the graph in plain English.
@@ -24,22 +24,10 @@ Decide the precise operations against the schema, execute them with the writers
24
24
 
25
25
  When admin's brief names the typed-edge pass (Task 305) and supplies a `sinceIso` timestamp, call `memory-typed-edge-pass` with that timestamp exactly once. The tool reads prose-bearing nodes (Message/Page/Meeting/KnowledgeDocument/ConversationArchive/Idea/Note/Post/Report — `:KnowledgeDocument` covers email threads via `source:'email'` since Task 321; `:ConversationArchive` covers chat transcripts since Task 397) the account wrote since `sinceIso`, asks Haiku for typed-edge proposals against a closed allowlist, validates each one, and MERGEs accepted edges with `createdBy` provenance. Return the full counter object verbatim — admin needs `nodesProcessed` and `accepted` for the `session-retrospective-mark-complete` call. Do not reinterpret the counts or summarise them.
26
26
 
27
- ## External-archive ingestion
28
-
29
- The database-operator also owns ingestion of bulk external archives that map into the graph. Each archive type has its own skill that drives the operator-conversation surface; the writes route through deterministic MCP tools the parser owns server-side. The skills load themselves into your prompt when the operator's request names an archive directory or file.
30
-
31
- - **Obsidian vault import** — when the operator points at an extracted Obsidian vault directory ("import my Obsidian notes", "ingest this vault at `<path>`"), load [platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md](../../../plugins/obsidian-import/skills/obsidian-import/SKILL.md) and run the two-phase flow (owner confirmation → `mcp__plugin_memory_memory__obsidian-vault-import` `mode='dry-run'` → operator disambiguation → `mode='commit'` with resolutions). Parsing, content-hash idempotency, and attachment staging happen entirely inside the tool — you never read the markdown.
32
-
33
- - **ICS calendar archive ingest** — when the operator points at an `.ics` file ("ingest this calendar export at `<path>`", "import my Google Calendar export", "load this .ics into the graph"), call `mcp__plugin_scheduling_scheduling__schedule-archive-ics` with `mode='dry-run'` first, present the attendee-resolution preview to the operator (how many already exist under this account, how many would be cross-account-skipped, how many new Person stubs would be created, plus the sample list), then call again with `mode='commit'` after the operator confirms. Each VEVENT becomes one `:Meeting` MERGEd on `(accountId, uid)` (idempotent re-ingest); attendees resolve to `:Person` by lowercased email; the importing `:AdminUser` anchors every meeting via `[:IMPORTED]`. Cross-account email collisions skip the attendance edge — do not propose to override this. Description bodies pass to `:Meeting.description` and the typed-edge pass picks up commitments + mentions automatically; you do not call `memory-write` for them.
34
-
35
- Other archive types (LinkedIn export, Notion export, Logseq, Roam, gbrain-repo, Gmail) live under separate plugins owned by `specialists:librarian`; they are not on this surface. If the operator's request points at one of those, hand back to admin so it can dispatch the right specialist.
36
-
37
- - **X (Twitter) archive import** — when the operator points at an extracted X archive directory (`Archive of <handle>/`, or a `twitter-<handle>-archive.zip` path), load [platform/plugins/x-import/skills/x-import/SKILL.md](../../../plugins/x-import/skills/x-import/SKILL.md) and run its four-phase flow (owner + participant confirmation → tweet-stream transcript rendering → `document-ingest` dispatch for the tweet-stream `:KnowledgeDocument` → one `conversation-archive-ingest.sh --source x-dm` invocation per distinct DM participant set). Every `@handle` and DM senderId resolves to an existing `:Person` / `:AdminUser` before any write; participants are never auto-created. Writes route through the existing `memory-ingest` and `conversation-archive` surfaces — no new graph writer, no `:Post` / `:DirectMessage` labels.
38
-
39
27
  ## Skip-rate visibility (session-start)
40
28
 
41
29
  When admin's brief names the skip-rate check, call `session-retrospective-skip-rate` once and return its result verbatim. The tool reports how many of the last N sessions for this account closed without firing the retrospective. Admin uses the rate to inform the operator that closing via Sidebar Archive or tab-close defers the typed-edge pass to the next `/end`. Pass the `windowSize` admin provides; default 10 is fine when absent.
42
30
 
43
- ## External-archive ingestion
31
+ ## Bulk external archives route elsewhere
44
32
 
45
- When admin's brief names a Notion workspace export — a directory with `Page Title <32-hex>.md` files and paired `<DB Name> <32-hex>.csv` / directory pairs at any depth, or a `Export-*.zip` path — load `platform/plugins/notion-import/skills/notion-import/SKILL.md` and follow it. The skill confirms the importing `:AdminUser` and the workspace label before any file is read, walks the export per its four references (workspace-export, databases, page-tree, attachments), and writes via your existing `memory-write` / `memory-update` / `memory-search` surface. Every node carries `source='notion'`, `importId`, and the standard provenance set. Unmapped Notion relations land as `:MENTIONS` with `mentionContext: '<relation-name>'`; never invent new edge types. Inline `@person` mentions resolve against `:Person {accountId}` only account-isolation is load-bearing. Per-node writes today; a follow-up at [`.tasks/gbrain/ingestion/395-notion-bulk-archive-handler.md`](../../../../.tasks/gbrain/ingestion/395-notion-bulk-archive-handler.md) adds a batched `memory-archive-write` path.
33
+ Obsidian vault, ICS calendar archive, X (Twitter) archive, and Notion workspace export ingestion all moved to the `archive-ingest-operator` specialist (Sonnet) schema-mapping ambiguity in those flows requires the larger model. If admin's brief points at one of those archive types, hand back to admin so it can dispatch the right specialist.
@@ -3,7 +3,7 @@ name: librarian
3
3
  description: "Foreground ingester for the memory graph. Owns external-archive and document ingestion — PDFs, web pages, plain text, conversation transcripts (WhatsApp / Telegram / Signal / iMessage / Slack / LinkedIn DMs / Zoom / meeting minutes), LinkedIn Basic Data Exports, and post-unzip trees the admin agent forwards. Loads `document-ingest`, `conversation-archive`, `conversation-archive-enrich`, and `linkedin-import` skills. Returns to the admin agent with a structured outcome line; never interacts with the operator directly except through the dispatching agent."
4
4
  summary: "Owns foreground ingest of documents, conversation transcripts, and external archives into the memory graph."
5
5
  model: claude-sonnet-4-5
6
- tools: mcp__plugin_memory_memory__memory-ingest-extract, mcp__plugin_memory_memory__memory-ingest, mcp__plugin_memory_memory__memory-ingest-web, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__conversation-archive-derive-insights, mcp__plugin_memory_memory__conversation-archive-enrich-rejection, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_work_work__work-create, Read, Bash
6
+ tools: mcp__plugin_memory_memory__memory-ingest-extract, mcp__plugin_memory_memory__memory-ingest, mcp__plugin_memory_memory__memory-ingest-web, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__conversation-archive-list-chunks, mcp__plugin_memory_memory__conversation-archive-derive-insights, mcp__plugin_memory_memory__conversation-archive-enrich-rejection, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_work_work__work-create, Read, Bash
7
7
  ---
8
8
 
9
9
  # Librarian