dreamcontext 0.5.4 → 0.7.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 (108) hide show
  1. package/LICENSE +201 -21
  2. package/NOTICE +7 -0
  3. package/README.md +79 -13
  4. package/agents/sleep-product.md +48 -10
  5. package/agents/sleep-state.md +43 -22
  6. package/agents/sleep-tasks.md +62 -9
  7. package/dist/agents/sleep-product.md +48 -10
  8. package/dist/agents/sleep-state.md +43 -22
  9. package/dist/agents/sleep-tasks.md +62 -9
  10. package/dist/dashboard/assets/{BrainCanvas3D-1HMiA14F.js → BrainCanvas3D-lFgJbbhZ.js} +1 -1
  11. package/dist/dashboard/assets/{_baseUniq-C7pfRmXz.js → _baseUniq-BpANgc_i.js} +1 -1
  12. package/dist/dashboard/assets/{arc-B5x_GF9Q.js → arc-CX32Jm7E.js} +1 -1
  13. package/dist/dashboard/assets/{architectureDiagram-Q4EWVU46-CWmjaqno.js → architectureDiagram-Q4EWVU46-ARASlGxO.js} +1 -1
  14. package/dist/dashboard/assets/{blockDiagram-DXYQGD6D-B7SyUIdV.js → blockDiagram-DXYQGD6D-BBvsYm9E.js} +1 -1
  15. package/dist/dashboard/assets/{c4Diagram-AHTNJAMY-OeJBWXHU.js → c4Diagram-AHTNJAMY-ChSUfXR9.js} +1 -1
  16. package/dist/dashboard/assets/channel-w_Bp182N.js +1 -0
  17. package/dist/dashboard/assets/{chunk-4BX2VUAB-2Oop1B0M.js → chunk-4BX2VUAB-COHoVEpt.js} +1 -1
  18. package/dist/dashboard/assets/{chunk-4TB4RGXK-Bh7qSu_X.js → chunk-4TB4RGXK-DKJFLaTC.js} +1 -1
  19. package/dist/dashboard/assets/{chunk-55IACEB6-gNeHRO_i.js → chunk-55IACEB6-CKZPWZRu.js} +1 -1
  20. package/dist/dashboard/assets/{chunk-EDXVE4YY-BRniAH53.js → chunk-EDXVE4YY-k1y4mGUJ.js} +1 -1
  21. package/dist/dashboard/assets/{chunk-FMBD7UC4-B5r8U2gJ.js → chunk-FMBD7UC4-ixXe5R10.js} +1 -1
  22. package/dist/dashboard/assets/{chunk-OYMX7WX6-Dd1c17fm.js → chunk-OYMX7WX6-NDFap7xg.js} +1 -1
  23. package/dist/dashboard/assets/{chunk-QZHKN3VN-BIw-OdTn.js → chunk-QZHKN3VN-vY0UpHjB.js} +1 -1
  24. package/dist/dashboard/assets/{chunk-YZCP3GAM-Dl9MlwCW.js → chunk-YZCP3GAM-yztvsKR-.js} +1 -1
  25. package/dist/dashboard/assets/classDiagram-6PBFFD2Q-CcQxcqy9.js +1 -0
  26. package/dist/dashboard/assets/classDiagram-v2-HSJHXN6E-CcQxcqy9.js +1 -0
  27. package/dist/dashboard/assets/clone-_znoR_ci.js +1 -0
  28. package/dist/dashboard/assets/{cose-bilkent-S5V4N54A-DlrROH5K.js → cose-bilkent-S5V4N54A-DKXM5Fh5.js} +1 -1
  29. package/dist/dashboard/assets/{dagre-KV5264BT-B0GpPXKL.js → dagre-KV5264BT-DN1Nlsmy.js} +1 -1
  30. package/dist/dashboard/assets/{diagram-5BDNPKRD-BBYcDW2Z.js → diagram-5BDNPKRD-DnoJFRqR.js} +1 -1
  31. package/dist/dashboard/assets/{diagram-G4DWMVQ6-BxHxugdp.js → diagram-G4DWMVQ6-CF1_jTNI.js} +1 -1
  32. package/dist/dashboard/assets/{diagram-MMDJMWI5-C9Jc19Wo.js → diagram-MMDJMWI5-D4-bZZEt.js} +1 -1
  33. package/dist/dashboard/assets/{diagram-TYMM5635-Vmo5GAAU.js → diagram-TYMM5635-al8RqVgf.js} +1 -1
  34. package/dist/dashboard/assets/{erDiagram-SMLLAGMA-pskr9x-V.js → erDiagram-SMLLAGMA-MEcC0rwO.js} +1 -1
  35. package/dist/dashboard/assets/{flowDiagram-DWJPFMVM-B1D7Ky0W.js → flowDiagram-DWJPFMVM-DCLyNpW8.js} +1 -1
  36. package/dist/dashboard/assets/{ganttDiagram-T4ZO3ILL-BVJZZV1M.js → ganttDiagram-T4ZO3ILL-DfEvbbJK.js} +1 -1
  37. package/dist/dashboard/assets/{gitGraphDiagram-UUTBAWPF-BiOGN6We.js → gitGraphDiagram-UUTBAWPF-C_YozdVL.js} +1 -1
  38. package/dist/dashboard/assets/{graph-D58deEXr.js → graph-DpIXS1G1.js} +1 -1
  39. package/dist/dashboard/assets/index-Bo5CUa_M.js +480 -0
  40. package/dist/dashboard/assets/index-DrqurW1c.css +1 -0
  41. package/dist/dashboard/assets/{infoDiagram-42DDH7IO-DgJYg1X1.js → infoDiagram-42DDH7IO-AdT6kjzj.js} +1 -1
  42. package/dist/dashboard/assets/{ishikawaDiagram-UXIWVN3A-arJgr-8P.js → ishikawaDiagram-UXIWVN3A-B0_9IZVO.js} +1 -1
  43. package/dist/dashboard/assets/{journeyDiagram-VCZTEJTY-B3DCvb8p.js → journeyDiagram-VCZTEJTY-BveNBswQ.js} +1 -1
  44. package/dist/dashboard/assets/{kanban-definition-6JOO6SKY-B--dN6Ma.js → kanban-definition-6JOO6SKY-CFI8j4jR.js} +1 -1
  45. package/dist/dashboard/assets/{layout-z2qEbZWC.js → layout-DI7XjZy1.js} +1 -1
  46. package/dist/dashboard/assets/{linear-BQu1dwrM.js → linear-CSjp56iw.js} +1 -1
  47. package/dist/dashboard/assets/{min-DkF5b2sh.js → min-pAGUJmEC.js} +1 -1
  48. package/dist/dashboard/assets/{mindmap-definition-QFDTVHPH-Bw04koyq.js → mindmap-definition-QFDTVHPH-C2mBnknr.js} +1 -1
  49. package/dist/dashboard/assets/{pieDiagram-DEJITSTG-vNqz64o8.js → pieDiagram-DEJITSTG-i_phWDqD.js} +1 -1
  50. package/dist/dashboard/assets/{quadrantDiagram-34T5L4WZ-TuVP5Gi6.js → quadrantDiagram-34T5L4WZ-Dv7TGJjw.js} +1 -1
  51. package/dist/dashboard/assets/{requirementDiagram-MS252O5E-D3mS8_ke.js → requirementDiagram-MS252O5E-CB2Jl-O5.js} +1 -1
  52. package/dist/dashboard/assets/{sankeyDiagram-XADWPNL6-BmVRers6.js → sankeyDiagram-XADWPNL6-DxCoN-EI.js} +1 -1
  53. package/dist/dashboard/assets/{sequenceDiagram-FGHM5R23-CTYCgk5P.js → sequenceDiagram-FGHM5R23-BeZyaehJ.js} +1 -1
  54. package/dist/dashboard/assets/{stateDiagram-FHFEXIEX-DNbP2aCg.js → stateDiagram-FHFEXIEX-D3AjQzD1.js} +1 -1
  55. package/dist/dashboard/assets/stateDiagram-v2-QKLJ7IA2-Ci9v--xK.js +1 -0
  56. package/dist/dashboard/assets/{timeline-definition-GMOUNBTQ-DKHJd4z8.js → timeline-definition-GMOUNBTQ-3l_8RFUg.js} +1 -1
  57. package/dist/dashboard/assets/{vennDiagram-DHZGUBPP-ChotNMNq.js → vennDiagram-DHZGUBPP-2QiY25JD.js} +1 -1
  58. package/dist/dashboard/assets/{wardley-RL74JXVD-Dmo2_ksP.js → wardley-RL74JXVD-DNLmFofz.js} +1 -1
  59. package/dist/dashboard/assets/{wardleyDiagram-NUSXRM2D-Z6Wbiv2H.js → wardleyDiagram-NUSXRM2D-BI0tupiS.js} +1 -1
  60. package/dist/dashboard/assets/{xychartDiagram-5P7HB3ND-BJa0AHtN.js → xychartDiagram-5P7HB3ND-CghXPE7_.js} +1 -1
  61. package/dist/dashboard/index.html +2 -2
  62. package/dist/dashboard/media/README.md +29 -0
  63. package/dist/dashboard/media/brain-hero.png +0 -0
  64. package/dist/dashboard/media/brain.mp4 +0 -0
  65. package/dist/dashboard/media/brain.webm +0 -0
  66. package/dist/dashboard/media/shot-disabled.png +0 -0
  67. package/dist/dashboard/media/shot-enabled.png +0 -0
  68. package/dist/index.js +3352 -2035
  69. package/dist/skill-packs/catalog.json +44 -0
  70. package/dist/skill-packs/excalidraw/SKILL.md +202 -0
  71. package/dist/skill-packs/excalidraw/examples/hello.spec.json +14 -0
  72. package/dist/skill-packs/excalidraw/examples/sample.png +0 -0
  73. package/dist/skill-packs/excalidraw/examples/style_board.js +31 -0
  74. package/dist/skill-packs/excalidraw/package.json +5 -0
  75. package/dist/skill-packs/excalidraw/reference/format.md +93 -0
  76. package/dist/skill-packs/excalidraw/scripts/build_excalidraw.js +357 -0
  77. package/dist/skill-packs/excalidraw/scripts/lib/fractional-indexing.LICENSE +121 -0
  78. package/dist/skill-packs/excalidraw/scripts/lib/fractional-indexing.js +311 -0
  79. package/dist/skill-packs/excalidraw/scripts/lib/imagesize.js +65 -0
  80. package/dist/skill-packs/excalidraw/scripts/lib/style.js +130 -0
  81. package/dist/skill-packs/video-watching/SKILL.md +192 -0
  82. package/dist/skill-packs/video-watching/scripts/build_frame_index.py +146 -0
  83. package/dist/skill-packs/video-watching/scripts/transcribe.sh +229 -0
  84. package/dist/templates/init/data-structures/default.md +26 -24
  85. package/package.json +4 -2
  86. package/skill/SKILL.md +31 -12
  87. package/skill-packs/catalog.json +44 -0
  88. package/skill-packs/excalidraw/SKILL.md +202 -0
  89. package/skill-packs/excalidraw/examples/hello.spec.json +14 -0
  90. package/skill-packs/excalidraw/examples/sample.png +0 -0
  91. package/skill-packs/excalidraw/examples/style_board.js +31 -0
  92. package/skill-packs/excalidraw/package.json +5 -0
  93. package/skill-packs/excalidraw/reference/format.md +93 -0
  94. package/skill-packs/excalidraw/scripts/build_excalidraw.js +357 -0
  95. package/skill-packs/excalidraw/scripts/lib/fractional-indexing.LICENSE +121 -0
  96. package/skill-packs/excalidraw/scripts/lib/fractional-indexing.js +311 -0
  97. package/skill-packs/excalidraw/scripts/lib/imagesize.js +65 -0
  98. package/skill-packs/excalidraw/scripts/lib/style.js +130 -0
  99. package/skill-packs/video-watching/SKILL.md +192 -0
  100. package/skill-packs/video-watching/scripts/build_frame_index.py +146 -0
  101. package/skill-packs/video-watching/scripts/transcribe.sh +229 -0
  102. package/dist/dashboard/assets/channel-CbuTKKsM.js +0 -1
  103. package/dist/dashboard/assets/classDiagram-6PBFFD2Q-HXl3A_sM.js +0 -1
  104. package/dist/dashboard/assets/classDiagram-v2-HSJHXN6E-HXl3A_sM.js +0 -1
  105. package/dist/dashboard/assets/clone-NKHOtdi8.js +0 -1
  106. package/dist/dashboard/assets/index-DK_2-eWY.css +0 -1
  107. package/dist/dashboard/assets/index-Ds-JXWtr.js +0 -476
  108. package/dist/dashboard/assets/stateDiagram-v2-QKLJ7IA2-CfN6kjo8.js +0 -1
package/skill/SKILL.md CHANGED
@@ -87,7 +87,7 @@ All three are auto-loaded every session via the SessionStart hook.
87
87
  Every session start injects these automatically (zero tool calls needed):
88
88
 
89
89
  - **Soul, User, Memory** -- full content
90
- - **Extended core files index** -- names/types of style guide, tech stack, data structures
90
+ - **Extended core files index** -- names/types of style guide, tech stack, system flow
91
91
  - **Active tasks** -- status, priority, last updated (answer "which tasks are active?" directly from this, zero tool calls needed)
92
92
  - **Bookmarks** -- tagged important moments from previous sessions, ordered by salience
93
93
  - **Contextual reminders** -- matching triggers for active tasks (prospective memory)
@@ -115,7 +115,7 @@ Decide dynamically. Match the task to what you need. Choose the right operation
115
115
  | `core/features/<name>.md` | READ | Feature scoping, sprint work, planning, "what's next" questions |
116
116
  | `core/3.style_guide_and_branding.md` | READ | UI/UX work, frontend, branding, copy, design tasks |
117
117
  | `core/4.tech_stack.md` | READ | Architecture decisions, integrations, dependency questions, infra |
118
- | `core/data-structures/<product>.md` (or `default.md`) | READ or SEARCH | Database work, API design, schema changes, data modeling |
118
+ | `knowledge/data-structures/<product>.md` (or `default.md`) | READ or SEARCH | Database work, API design, schema changes, data modeling (recall-indexed like all knowledge) |
119
119
  | `core/CHANGELOG.json` | SEARCH | Bug investigations, "what changed recently?" |
120
120
  | `core/RELEASES.json` | SEARCH | "Which release shipped this?", rollback decisions |
121
121
  | `state/<task>.md` | READ | Continuing previous work. Changelog section = where you left off |
@@ -134,17 +134,17 @@ When debugging (e.g., "notifications are broken"):
134
134
 
135
135
  Some projects are monorepos with multiple products. Init asks "Is this a monorepo with multiple products?" and records the product list in `_dream_context/state/.config.json` under `multiProduct: string[] | false`. When products are configured:
136
136
 
137
- - **Per-product data structures** live at `_dream_context/core/data-structures/<product>.md` (single-product projects use `default.md`).
137
+ - **Per-product data structures** live at `_dream_context/knowledge/data-structures/<product>.md` (single-product projects use `default.md`). They're knowledge files — recall-indexed, staleness-tracked, owned by `sleep-product`. **Body format: a single \`\`\`sql fenced block** with SQL comments (`-- ...`) for documentation — this is what the dashboard highlights. `migrateDataStructures` auto-wraps unfenced bodies; `dreamcontext init` scaffolds the fenced template.
138
138
  - **Per-product knowledge** lives at `_dream_context/knowledge/products/<product>.md`. Cross-cutting knowledge still lives at the top-level `knowledge/`.
139
139
  - **Tasks** MAY include `product: <name>` in frontmatter. The dashboard / CLI surfaces a product filter when `.config.json` lists products.
140
140
  - **Auto-injection — handled by the SessionStart hook.** The hook (`npx dreamcontext hook session-start` → `generateSnapshot()`) resolves the active task (override file `_dream_context/state/.active-task`, or fallback: most recently modified task with status `in_progress`). If that task's frontmatter has `product: <name>` and `<name>` is listed under `multiProduct`, the hook injects the body of `_dream_context/knowledge/products/<name>.md` into the snapshot under an `## Active Product Knowledge: <name>` section (capped at 200 lines, with a "read full" pointer if truncated). You don't need to remember to load it — it's already in your context. Cross-cutting knowledge still lives at the top-level `knowledge/`.
141
141
  - **Feature PRDs** MAY include `product: <name>` in frontmatter for product scoping; they still live in the flat `core/features/` directory.
142
142
 
143
- If `multiProduct` is `false` or missing, treat the project as single-product and use `data-structures/default.md` exclusively. The SessionStart hook no-ops the product-knowledge injection in that case.
143
+ If `multiProduct` is `false` or missing, treat the project as single-product and use `knowledge/data-structures/default.md` exclusively. The SessionStart hook no-ops the product-knowledge injection in that case.
144
144
 
145
145
  ### Extended Core Files (3+)
146
146
 
147
- Beyond the auto-loaded soul/user/memory, projects define additional core files (style guide, tech stack, data structures, and potentially more).
147
+ Beyond the auto-loaded soul/user/memory, projects define additional core files (style guide, tech stack, and potentially more). (Data structures are no longer a core file — they live under `knowledge/data-structures/` as recall-indexed knowledge.)
148
148
 
149
149
  **Discovery protocol**:
150
150
  1. The extended core files index is auto-loaded each session (names and types visible).
@@ -318,7 +318,9 @@ Sleep debt reminders are injected on every user message (via UserPromptSubmit ho
318
318
  - user hint mentions knowledge or a feature
319
319
  - When unsure, **over-fire** `sleep-product` — it no-ops cheaply.
320
320
  - Pass each specialist a small text brief in its prompt: epoch, session IDs, active task slugs, planning version, signals relevant to that specialist, optional user hint. Do **not** include transcript content — specialists call `dreamcontext transcript distill <id>` themselves.
321
+ - **Consolidation discipline (remind both specialists in the brief):** prefer *updating/extending* an existing entity over creating a new one. `sleep-tasks` folds a smaller slice into the task that already covers it (broaden its title + insert sub-items) rather than forking a duplicate or a needless sub-task; `sleep-product` keeps similar verticals/brands/topics in the fewest knowledge files, splitting only on a sharp topical boundary that sharpens tags. Duplicate tasks and fragmented near-duplicate knowledge are the top consolidation failure modes — but genuinely separate concerns/topics still get their own task/file.
321
322
  5. Wait for all specialist reports. Each returns a short structured report.
323
+ 5a. Run `dreamcontext reflect` — each candidate is a term seen across multiple sessions not yet in soul/user/memory/knowledge; promote into `2.memory.md` or a knowledge file ONLY if genuinely load-bearing; most are noise, discard; NEVER auto-promote.
322
324
  6. Marketing pass if `_dream_context/marketing/` exists: `dreamcontext mk rem-sleep`.
323
325
  7. Council promote check: `dreamcontext council list --unpromoted` — promote if user engaged positively.
324
326
  8. `dreamcontext sleep done "<one-paragraph summary stitched from specialist reports>"` — clears pre-epoch state, resets debt.
@@ -364,6 +366,18 @@ Tasks are your **working documents**. All context, decisions, user stories, acce
364
366
  dreamcontext tasks list # List non-completed tasks (or --all for everything)
365
367
  Read _dream_context/state/<task>.md # Load full context (Why + Changelog = where you left off)
366
368
 
369
+ # Slice the list — filters compose (AND), and stack with --status / --all
370
+ dreamcontext tasks list --version S5 # All tasks in version/milestone S5 (no more frontmatter scraping)
371
+ dreamcontext tasks list --tag memoryos --tag backend --status todo # --tag is repeatable, AND semantics (must have ALL)
372
+ dreamcontext tasks list --any-tag lina --any-tag studio # --any-tag is repeatable, OR semantics (at least one)
373
+ dreamcontext tasks list --priority critical # critical | high | medium | low
374
+ dreamcontext tasks list --feature recall-engine # match related_feature
375
+ dreamcontext tasks list --long # also show version + tags inline
376
+ dreamcontext tasks list --group-by version --all # sectioned output with per-group counts (tag|version|priority|status)
377
+ dreamcontext tasks list --tag lina --json # scriptable: emit the filtered set as JSON (use this, not awk/grep)
378
+ dreamcontext tasks tags # distinct tags with counts (--all to include completed)
379
+ # Filters are case-insensitive; version/priority/feature match exactly; multiple --tag = AND, --any-tag = OR.
380
+
367
381
  # Create (rich task with Why, User Stories, Acceptance Criteria, Constraints, Technical Details, Notes, Changelog)
368
382
  dreamcontext tasks create <name> --description "..." --priority medium --why "What this task accomplishes"
369
383
 
@@ -449,9 +463,6 @@ dreamcontext memory status
449
463
  _dream_context/
450
464
  +-- core/
451
465
  | +-- features/<feature>.md <- Feature PRDs (may include product: <name>)
452
- | +-- data-structures/ <- Per-product schemas
453
- | | +-- default.md <- single-product fallback
454
- | | +-- <product>.md <- one per product if monorepo
455
466
  | +-- 0.soul.md <- Identity, principles, rules
456
467
  | +-- 1.user.md <- Preferences, project details
457
468
  | +-- 2.memory.md <- Decisions + Known Issues (ship narrative moved to CHANGELOG 2026-05-23)
@@ -460,6 +471,9 @@ _dream_context/
460
471
  | +-- 6.system_flow.md
461
472
  | +-- CHANGELOG.json, RELEASES.json
462
473
  +-- knowledge/<topic>.md <- Deep research, resources (global)
474
+ | +-- data-structures/ <- Per-product schemas (recall-indexed knowledge)
475
+ | | +-- default.md <- single-product fallback
476
+ | | +-- <product>.md <- one per product if monorepo
463
477
  | +-- products/<product>.md <- Per-product knowledge (multi-product)
464
478
  +-- state/
465
479
  | +-- <task>.md <- Active tasks (frontmatter may include product:)
@@ -474,14 +488,15 @@ All commands prefixed with `dreamcontext`. For reading/searching, use native too
474
488
 
475
489
  | Command | Description |
476
490
  |---------|-------------|
477
- | `init [--multi-product=a,b,c]` | Initialize `_dream_context/`. Prompts interactively whether the project is a monorepo with multiple products; `--multi-product=a,b,c` skips the prompt and provides kebab-case product names directly. Creates `core/data-structures/<product>.md` per product (or `default.md` for single-product) and seeds `knowledge/products/`. |
491
+ | `init [--multi-product=a,b,c]` | Initialize `_dream_context/`. Prompts interactively whether the project is a monorepo with multiple products; `--multi-product=a,b,c` skips the prompt and provides kebab-case product names directly. Creates `knowledge/data-structures/<product>.md` per product (or `default.md` for single-product) and seeds `knowledge/products/`. |
478
492
  | `core changelog add` | Add changelog entry (interactive) |
479
493
  | `core releases add [--ver v --summary s --yes] [--status planning]` | Create release (default: released with auto-discovery; --status planning: empty planning version, auto-becomes active) |
480
494
  | `core releases active [<version>] [--clear]` | Get/set/clear the active planning version (default for new tasks' `version` field) |
481
495
  | `core releases list [-n count]` | List recent releases |
482
496
  | `core releases show <version>` | Show release details |
483
- | `features create <name>` | Create feature PRD |
484
- | `features insert <name> <section> <content>` | Insert into feature section |
497
+ | `features create <name> [-w why] [-t tags] [-s status] [--related-tasks a,b]` | Create feature PRD; frontmatter set without hand-editing (status: planning\|in_progress\|in_review\|active\|shipped\|deprecated) |
498
+ | `features insert <name> <section> <content>` | Insert into feature section (replaces template placeholders on first write; `user_stories`/`acceptance_criteria` auto-formatted as `- [ ]` items) |
499
+ | `features set <name> <tags\|status\|related_tasks> <value...>` | Set a feature frontmatter field (comma-separated for tags/related_tasks) without hand-editing |
485
500
  | `knowledge create <name>` | Create knowledge file |
486
501
  | `knowledge index [--tag <tag>]` | Show knowledge index |
487
502
  | `knowledge tags` | List standard tags |
@@ -492,7 +507,8 @@ All commands prefixed with `dreamcontext`. For reading/searching, use native too
492
507
  | `memory delete <slug> [--force]` | Remove a knowledge entry |
493
508
  | `memory list [--types ...]` | List indexable memory corpus by type |
494
509
  | `memory status` | Show corpus size broken down by type |
495
- | `tasks list [-s status] [--all]` | List tasks (default: excludes completed) |
510
+ | `tasks list [-s status] [--all] [--tag t]… [--any-tag t]… [--version id] [--priority p] [--feature slug] [--group-by tag\|version\|priority\|status] [--long] [--json]` | List/filter/group tasks. Default excludes completed. `--tag` repeatable (AND), `--any-tag` repeatable (OR), filters compose; `--json` emits the filtered set; case-insensitive matching |
511
+ | `tasks tags [--all] [--json]` | List distinct task tags with counts (discover before filtering) |
496
512
  | `tasks create <name> [-d desc] [-p priority] [-s status] [-t tags] [-w why] [--reach N --impact N --confidence N --effort N]` | Create task (defaults: priority=medium, status=todo). RICE flags optional and additive. |
497
513
  | `tasks rice <name> [--reach N] [--impact N] [--confidence N] [--effort N] [--clear]` | Print or update RICE values; no flags prints current values |
498
514
  | `tasks insert <name> <section> <content>` | Insert into task section |
@@ -505,6 +521,7 @@ All commands prefixed with `dreamcontext`. For reading/searching, use native too
505
521
  | `trigger add "<when>" "<remind>" [-m max_fires] [-s source]` | Create contextual trigger |
506
522
  | `trigger list` | Show active triggers |
507
523
  | `trigger remove <id>` | Remove a trigger |
524
+ | `reflect [--min-sessions N] [--max N] [--write]` | Detect recurring cross-session terms not yet in knowledge/memory as CANDIDATES; `--write` persists to `state/.reflection.md` |
508
525
  | `transcript distill <session_id>` | Extract high-signal content from session transcript |
509
526
  | `sleep status` | Show sleep state and history |
510
527
  | `sleep add <score> "<desc>"` | Manual debt add |
@@ -523,6 +540,8 @@ All commands prefixed with `dreamcontext`. For reading/searching, use native too
523
540
  | `snapshot --tokens` | Estimate snapshot token count |
524
541
  | `doctor` | Validate `_dream_context/` structure |
525
542
  | `install-skill` | Install skill + hooks |
543
+ | `config show` | Print project config (platforms, packs, native-memory state) |
544
+ | `config native-memory <enable\|disable>` | Toggle Claude's native auto-memory; disabled by default so dreamcontext owns project memory |
526
545
  | `upgrade [--check]` | Update the dreamcontext CLI itself to the latest npm release |
527
546
 
528
547
  Feature insert sections: `changelog`, `notes`, `technical_details`, `constraints`, `user_stories`, `acceptance_criteria`, `why`
@@ -352,6 +352,50 @@
352
352
  "security"
353
353
  ],
354
354
  "alwaysApply": false
355
+ },
356
+ {
357
+ "name": "excalidraw",
358
+ "file": "excalidraw/SKILL.md",
359
+ "description": "Generate or extend Obsidian Excalidraw (.excalidraw.md) boards — lay out images/screenshots, text, shapes, arrows, frames, lanes and grids — by writing a small JSON spec and running a deterministic script that emits valid plugin markup (near-zero tokens, always renders). Embeds local images via the plugin's sha1 wikilink trick (no base64). Triggers: 'draw this in excalidraw', 'make an excalidraw board', 'excalidraw diagram', 'funnel map board', 'embed screenshots into excalidraw', 'excalidraw çiz', 'excalidraw board oluştur'.",
360
+ "tags": [
361
+ "excalidraw",
362
+ "obsidian",
363
+ "diagram",
364
+ "board",
365
+ "visualization",
366
+ "screenshots",
367
+ "funnel-map",
368
+ "drawing"
369
+ ],
370
+ "alwaysApply": false,
371
+ "bundleDir": true
372
+ },
373
+ {
374
+ "name": "video-watching",
375
+ "file": "video-watching/SKILL.md",
376
+ "description": "Load when the user hands over a video file/link or asks to watch/analyze a video, extract a transcript, or 'bu videoda ne var'. Turns a video into a time-mapped transcript with on-screen visuals (slides, UI, charts, text) described inline, then reasons about it. Triggers: 'watch this video', 'videoyu izle/analiz et', 'transkript çıkar', 'video transcript'.",
377
+ "tags": [
378
+ "video",
379
+ "transcript",
380
+ "whisper",
381
+ "ffmpeg",
382
+ "frames",
383
+ "ocr",
384
+ "marketing-teardown",
385
+ "media"
386
+ ],
387
+ "alwaysApply": false,
388
+ "bundleDir": true,
389
+ "requiresBinaries": [
390
+ "whisper-cpp",
391
+ "ffmpeg",
392
+ "yt-dlp (remote links only)"
393
+ ],
394
+ "crossPackDeps": [
395
+ "growth (marketing-video teardown handoff)",
396
+ "meta-marketing (ad-creative teardown handoff)",
397
+ "design/onboarding-design (app-demo / FTE reconstruction handoff)"
398
+ ]
355
399
  }
356
400
  ],
357
401
  "agents": [
@@ -0,0 +1,202 @@
1
+ ---
2
+ name: excalidraw
3
+ description: >-
4
+ Generate or extend Obsidian Excalidraw (.excalidraw.md) boards in this vault — lay out
5
+ images/screenshots, text labels, shapes, arrows, frames, lanes and grids — by writing a small
6
+ JSON spec and letting a deterministic script emit valid plugin markup (so it costs ~no tokens and
7
+ always renders). Embeds local images via the plugin's sha1 wikilink trick (no base64). Triggers:
8
+ '/excalidraw', 'draw this in excalidraw', 'make an excalidraw board', 'excalidraw diagram',
9
+ 'funnel map board', 'embed screenshots into excalidraw', 'add images to an excalidraw file',
10
+ 'excalidraw çiz', 'excalidraw board oluştur', 'ekran görüntülerini excalidraw a ekle'.
11
+ ---
12
+
13
+ # Excalidraw board generator (Obsidian)
14
+
15
+ Write `.excalidraw.md` files that render natively in this vault's Obsidian Excalidraw plugin.
16
+ **Do not hand-author the scene JSON.** Build a small spec and run the generator — it produces the
17
+ frontmatter, `## Text Elements`, `## Embedded Files`, and the `%% ## Drawing … %%` JSON, with
18
+ correct sha1 image links, fractional z-indices, and deterministic seeds (clean git diffs).
19
+
20
+ ## The one trick that makes images work
21
+ An image element references `fileId` = **sha1 of the image file**. The `## Embedded Files` section
22
+ maps `<sha1>: [[image.png]]`. The plugin resolves the picture from the vault via that wikilink —
23
+ **no base64 needed.** The generator computes the sha1 and writes both sides for you.
24
+
25
+ ## Usage
26
+
27
+ ### CLI (most common)
28
+ ```bash
29
+ node .claude/skills/excalidraw/scripts/build_excalidraw.js <spec.json> [--out <path.excalidraw.md>]
30
+ ```
31
+ Write a spec JSON, then run it. The script prints `elements/images/texts` counts on success.
32
+
33
+ ### JS API (for pipelines that generate many boards)
34
+ ```js
35
+ const path = require('path');
36
+ // skill lives at <project>/.claude/skills/excalidraw/ — adjust leading ../ count to match your script's depth from project root
37
+ const { buildExcalidraw, lane, grid } = require(path.resolve(__dirname, '../.claude/skills/excalidraw/scripts/build_excalidraw.js'));
38
+ buildExcalidraw({ out: path.resolve(__dirname, '../boards/Board.excalidraw.md'), elements: [ ...lane({ title, images, x, y, thumbW }) ] });
39
+ ```
40
+
41
+ ## File layout
42
+
43
+ ### Single board (default)
44
+ Keep the spec next to the generated board but clearly separated:
45
+ ```
46
+ boards/
47
+ ├── MyBoard.excalidraw.md ← generated deliverable; do not hand-edit
48
+ └── _spec/
49
+ └── MyBoard.json ← source of truth; edit this, then regenerate
50
+ ```
51
+ The `.excalidraw.md` is **disposable** — it is fully derived from the spec. If the two ever
52
+ disagree, the spec wins. Commit both (the board for Obsidian/GitHub preview, the spec for
53
+ reproducibility), but only edit the spec.
54
+
55
+ ### Multi-board pipeline
56
+ When a single generator produces several boards, isolate it in a `pipeline/` folder so the
57
+ deliverable boards stay at the top of the project and are easy to open in Obsidian:
58
+ ```
59
+ boards/
60
+ ├── Overview.excalidraw.md ← generated
61
+ ├── Funnel.excalidraw.md ← generated
62
+ ├── Pricing.excalidraw.md ← generated
63
+ └── pipeline/
64
+ ├── generate.js ← single regen entrypoint: `node pipeline/generate.js`
65
+ ├── shared-style.js ← shared palette / helpers
66
+ └── spec/
67
+ ├── Overview.json ← source spec for Overview board
68
+ ├── Funnel.json ← source spec for Funnel board
69
+ └── Pricing.json ← source spec for Pricing board
70
+ ```
71
+ - **Generated files** (`*.excalidraw.md`) live one level above `pipeline/` — open them in Obsidian without navigating into a sub-folder.
72
+ - **Source specs** live in `pipeline/spec/` — one JSON per board.
73
+ - **Single entrypoint**: `node pipeline/generate.js` rebuilds every board. No per-board manual commands.
74
+
75
+ ### Many boards from shared data (recipe)
76
+ Use this pattern when multiple boards pull from the same data set (e.g. one board per product, per region, or per funnel step):
77
+
78
+ ```js
79
+ // pipeline/generate.js (lives at boards/pipeline/generate.js)
80
+ const path = require('path');
81
+ const ROOT = path.resolve(__dirname, '..'); // boards/ directory
82
+ // ../../ = project root (boards/ → project/); adjust if boards/ is nested deeper
83
+ const { buildExcalidraw, lane } = require(path.resolve(__dirname, '../../.claude/skills/excalidraw/scripts/build_excalidraw.js'));
84
+ const style = require(path.resolve(__dirname, 'shared-style.js'));
85
+ const items = require(path.resolve(__dirname, 'spec/items.json')); // shared data
86
+
87
+ for (const item of items) {
88
+ const elements = style.buildItemBoard(item); // per-item spec logic
89
+ buildExcalidraw({
90
+ out: path.resolve(ROOT, `${item.slug}.excalidraw.md`),
91
+ elements,
92
+ });
93
+ console.log('wrote', item.slug);
94
+ }
95
+ ```
96
+
97
+ ```js
98
+ // pipeline/shared-style.js (lives at boards/pipeline/shared-style.js)
99
+ const path = require('path');
100
+ // ../../ = project root (boards/ → project/); adjust if boards/ is nested deeper
101
+ const { card, connector, sectionTitle } = require(path.resolve(__dirname, '../../.claude/skills/excalidraw/scripts/lib/style.js'));
102
+
103
+ exports.buildItemBoard = (item) => [
104
+ sectionTitle({ x: 0, y: 0, text: item.name, fontSize: 40 }),
105
+ // … common layout using item fields
106
+ ];
107
+ ```
108
+
109
+ Key conventions:
110
+ - `ROOT = path.resolve(__dirname, '..')` pins paths relative to the generator file, not the working directory. The generator works correctly wherever it is invoked from.
111
+ - Each item produces exactly one board; the mapping is `items.json → <slug>.excalidraw.md`.
112
+ - `shared-style.js` owns the layout logic — boards stay visually consistent; change the style once, regenerate all.
113
+ - Add a `package.json` script or `Makefile` alias so the command is always `npm run boards` (or similar) and never has to be rediscovered.
114
+
115
+ ## Spec schema
116
+ ```jsonc
117
+ {
118
+ "out": "./boards/Board.excalidraw.md", // prefer __dirname-relative in JS generators; relative to cwd for CLI
119
+ "vaultRoot": "/abs/vault", // optional; auto-detected by walking up to `.obsidian`
120
+ "attachDir": "Attachments", // external images get copied here (relative to board dir)
121
+ "wikilinkMode": "basename", // "basename" (default) or "path" (vault-relative)
122
+ "background": "#ffffff",
123
+ "elements": [ /* ElementSpec… */ ]
124
+ }
125
+ ```
126
+
127
+ **Paths in generators**: always use `path.resolve(__dirname, ...)` for `out` and image `path` fields — never
128
+ hardcode absolute paths. This keeps the generator portable: move the folder and it still runs.
129
+
130
+ ### Element types
131
+ - `text` — `{ x, y, text, fontSize?, color?, width?, align?, fontFamily? }` (fontFamily 1=hand, 2=normal, 3=code). **Set `width` for any caption/label that must stay inside a column or card** → the text WRAPS to that width (autoResize off) and its height is computed from the wrapped line count. Omit `width` only for short single-line text you want sized to content (it renders on one line and will overlap neighbours if long).
132
+ - `image` — `{ x, y, path, width? , height? }` — give ONE of width/height; the other is derived from aspect. `path` is an absolute file path.
133
+ - `rectangle`/`ellipse`/`diamond` — `{ x, y, width, height, strokeColor?, backgroundColor?, fillStyle?(solid|hachure|cross-hatch), strokeWidth?, roundness?(true=rounded) }`
134
+ - `line`/`arrow` — `{ points: [[x1,y1],[x2,y2],…], strokeColor?, strokeWidth?, endArrow?, startArrow? }` (coords are absolute; arrows default to an end arrowhead)
135
+ - `frame` — `{ x, y, width, height, name }`
136
+
137
+ ### Layout helpers (JS API) — dimension-aware, never gap/overlap
138
+ Both read each image's real pixel size at layout time, so every caption **hugs its own image's bottom**
139
+ (no fixed-aspect guess → no big gap under a short screenshot, no overlap under a tall one). They return
140
+ an `ElementSpec[]` you spread with `...`, and that array also carries `.height`, `.width`, and **`.nextY`**
141
+ so you can stack lanes/grids/sections without doing height math by hand.
142
+ - `lane({ title, images:[{path, caption}], x, y, thumbW, gap, captionSize, captionGap })` → titled horizontal
143
+ strip; caption wraps to `thumbW` under each thumb. Ideal for **funnel step maps** (one lane per funnel).
144
+ - `grid({ images:[{path, caption}], x, y, cols, thumbW, gapX, gapY, captionSize })` → wrapping grid; each
145
+ row sizes to its tallest image, each caption hugs its image.
146
+ - `thumbHeight(path, thumbW)` → the on-board height a thumbnail of width `thumbW` will get (exported for
147
+ custom layouts that need to place captions/rows themselves).
148
+ ```js
149
+ const a = lane({ title:'Pilates', images, x:60, y:120, thumbW:150 });
150
+ const b = lane({ title:'Fasting', images2, x:60, y:a.nextY, thumbW:150 }); // stacks under `a`, no overlap
151
+ buildExcalidraw({ out, elements:[ ...a, ...b ] });
152
+ ```
153
+ House-style `card()` labels are also vertically centered correctly even when the label **wraps** to the card width.
154
+
155
+ ## House style (`scripts/lib/style.js`) — learned from the vault's presentation boards
156
+ Match the team's look by default. The builder now defaults text to **Excalifont (fontFamily 5)**.
157
+ `style.js` exports the palette + ready-made builders so boards look hand-drawn and consistent:
158
+
159
+ - **`PALETTE`** (semantic, = Excalidraw's native swatches): `green` benefit/go · `red` pain/risk ·
160
+ `blue` system/flow · `purple` core service · `yellow` processing · `mint` result · `gray` muted.
161
+ Each is `{ fill, stroke }`. `INK` = `#1e1e1e` (the default 2px card outline). Fills are **solid**,
162
+ rects are **always rounded**.
163
+ - **`card({x,y,w,h,text,color,fontSize})`** → rounded filled rect + centered label, grouped (move as one).
164
+ - **`node(...)`** → smaller card for flow steps.
165
+ - **`sectionTitle({x,y,text,fontSize})`** → big plain header (no box), like "Configuration" / "Flow".
166
+ - **`connector({from,to,label,double,dashed})`** → labeled arrow between two points.
167
+ - **`annotate({from,to,text})`** → short arrow to a side-spec note (the "90sec / deepseek…" pattern).
168
+ - **`column({x,y,items,color})`** → vertical stack of cards (benefit/risk lists). `items` may be
169
+ strings or `{text,color}`.
170
+ - **`hub({cx,cy,label,spokes})`** → central node + satellites with arrows (the "Layer + APIs" pattern).
171
+ - **`bullets({x,y,items})`** → one left-aligned bulleted text block (their spec-list pattern).
172
+ - Edge helpers `center/rightOf/leftOf/topOf/bottomOf(x,y,w,h)` to wire connectors to card edges.
173
+
174
+ Compose these into a `buildExcalidraw({ out, elements })` call. Runnable example: `examples/style_board.js`.
175
+ Conventions: color nodes by ROLE, label every arrow, put specs in side-annotations, use big plain
176
+ section titles to break the board into "slides", keep one idea per card.
177
+
178
+ ## Rules & gotchas
179
+ - **Unique image filenames.** Obsidian resolves `[[name.png]]` by basename; if two different files
180
+ share a name anywhere in the vault the link is ambiguous. Name screenshots uniquely
181
+ (e.g. `bm-pilates-2707-step-03.png`) or use `"wikilinkMode": "path"`.
182
+ - Images must live inside the vault. External paths are auto-copied into `attachDir`.
183
+ - Output is uncompressed JSON inside `%% … %%`. The plugin reads it; on its first save it may
184
+ re-compress — that's expected and harmless.
185
+ - Re-running with the same `out` + same spec yields a byte-stable file (seeds are derived from the
186
+ output path), so boards diff cleanly in git.
187
+ - **Self-contained / portable.** No `npm install` — `build_excalidraw.js` uses only Node builtins +
188
+ the vendored `scripts/lib/*` (fractional-indexing, imagesize, style). Copy `.claude/skills/excalidraw/`
189
+ into any project and it works. `vaultRoot` auto-detects `.obsidian`; with none it falls back to the
190
+ board's own folder, so the `.excalidraw.md` is still written (it just renders inside Obsidian).
191
+
192
+ ## Verify
193
+ Run the bundled examples from the skill folder (they use skill-relative paths + a bundled `sample.png`,
194
+ so they work in any project):
195
+ ```bash
196
+ cd .claude/skills/excalidraw
197
+ node scripts/build_excalidraw.js examples/hello.spec.json # spec-driven: text/shapes/image → examples/Hello Excalidraw.excalidraw.md
198
+ node examples/style_board.js # JS API: card/connector/lane house style → examples/Style Demo.excalidraw.md
199
+ ```
200
+ Then open the resulting board in Obsidian (Excalidraw view) to confirm it renders.
201
+
202
+ See `reference/format.md` for the exact `.excalidraw.md` anatomy reverse-engineered from this vault.
@@ -0,0 +1,14 @@
1
+ {
2
+ "out": "examples/Hello Excalidraw.excalidraw.md",
3
+ "background": "#ffffff",
4
+ "elements": [
5
+ { "type": "text", "x": 0, "y": -70, "text": "excalidraw skill — portable smoke test", "fontSize": 28, "color": "#1971c2" },
6
+ { "type": "text", "x": 0, "y": -28, "text": "Give a text a width and it wraps to that width (no overlap). The image embeds via sha1 wikilink — no base64. Only skill-relative paths, so this runs in any project.", "fontSize": 15, "color": "#868e96", "width": 540 },
7
+ { "type": "rectangle", "x": 0, "y": 40, "width": 260, "height": 140, "strokeColor": "#1e1e1e", "backgroundColor": "#a5d8ff", "fillStyle": "solid", "strokeWidth": 2, "roundness": true },
8
+ { "type": "text", "x": 24, "y": 96, "text": "rounded rect\n+ fill", "fontSize": 20, "color": "#1e1e1e" },
9
+ { "type": "ellipse", "x": 340, "y": 40, "width": 160, "height": 140, "strokeColor": "#2f9e44", "backgroundColor": "#b2f2bb", "fillStyle": "hachure" },
10
+ { "type": "arrow", "points": [[260, 110], [340, 110]], "strokeColor": "#e8590c", "strokeWidth": 3 },
11
+ { "type": "text", "x": 0, "y": 220, "text": "embedded image (resolved from vault by sha1 wikilink):", "fontSize": 16, "color": "#555", "width": 420 },
12
+ { "type": "image", "x": 0, "y": 250, "path": "examples/sample.png", "width": 320 }
13
+ ]
14
+ }
@@ -0,0 +1,31 @@
1
+ // style_board.js — house-style demo. Run from anywhere: node examples/style_board.js
2
+ // Shows card/connector/sectionTitle + the dimension-aware lane() (captions hug images, .nextY stacks).
3
+ const path = require('path');
4
+ const { buildExcalidraw, lane } = require(path.join(__dirname, '..', 'scripts', 'build_excalidraw.js'));
5
+ const { card, connector, sectionTitle, rightOf, leftOf, bottomOf, topOf } = require(path.join(__dirname, '..', 'scripts', 'lib', 'style.js'));
6
+
7
+ const SAMPLE = path.join(__dirname, 'sample.png');
8
+ const els = [];
9
+ const P = (...a) => els.push(...a.flat());
10
+
11
+ // --- flow row with labeled connectors (color nodes by role) ---
12
+ P(sectionTitle({ x: 0, y: 0, text: 'House style', fontSize: 40 }));
13
+ const A = { x: 0, y: 90, w: 220, h: 84 }, B = { x: 360, y: 90, w: 220, h: 84 }, C = { x: 720, y: 90, w: 220, h: 84 };
14
+ P(card({ ...A, text: 'input', color: 'blue' }));
15
+ P(card({ ...B, text: 'core service', color: 'purple' }));
16
+ P(card({ ...C, text: 'result', color: 'mint' }));
17
+ P(connector({ from: rightOf(A.x, A.y, A.w, A.h), to: leftOf(B.x, B.y, B.w, B.h), label: 'request' }));
18
+ P(connector({ from: rightOf(B.x, B.y, B.w, B.h), to: leftOf(C.x, C.y, C.w, C.h), label: 'response' }));
19
+
20
+ // --- a dimension-aware lane: captions hug each image, .nextY gives the next free row ---
21
+ const imgs = [
22
+ { path: SAMPLE, caption: 'lane() reads the real image size, so this caption hugs the bottom and wraps to the thumb width — no gap, no overlap.' },
23
+ { path: SAMPLE, caption: 'second thumb' },
24
+ { path: SAMPLE, caption: 'third thumb' },
25
+ ];
26
+ const strip = lane({ title: 'lane() — funnel-step style strip', images: imgs, x: 0, y: 220, thumbW: 200 });
27
+ P(strip);
28
+ P(sectionTitle({ x: 0, y: strip.nextY, text: 'stacked below via strip.nextY', fontSize: 22, color: '#868e96' }));
29
+
30
+ buildExcalidraw({ out: path.join(__dirname, 'Style Demo.excalidraw.md'), elements: els, background: '#fbfbfb' });
31
+ console.log('style demo →', path.join(__dirname, 'Style Demo.excalidraw.md'));
@@ -0,0 +1,5 @@
1
+ {
2
+ "type": "commonjs",
3
+ "private": true,
4
+ "description": "Scopes the excalidraw skill's vendored scripts to CommonJS so `require()` works even when the host project sets \"type\": \"module\". No dependencies — scripts use only Node builtins + vendored lib/."
5
+ }
@@ -0,0 +1,93 @@
1
+ # Obsidian `.excalidraw.md` format (reverse-engineered from this vault)
2
+
3
+ Source files inspected: `lina/excalidraw/Lina Web Funnel.excalidraw.md` (decompressed),
4
+ `Lina Web Funnel Benchmark.excalidraw.md`. Plugin: `zsviczian/obsidian-excalidraw-plugin`.
5
+
6
+ ## File anatomy
7
+ ```
8
+ ---
9
+
10
+ excalidraw-plugin: parsed
11
+ tags: [excalidraw]
12
+
13
+ ---
14
+ ==⚠ Switch to EXCALIDRAW VIEW … ⚠== …saving hint…
15
+
16
+
17
+ # Excalidraw Data
18
+
19
+ ## Text Elements
20
+ <text content> ^<elementId> ← one block per text element, blank line between
21
+
22
+ ## Embedded Files
23
+ <sha1>: [[image filename.png]] ← maps fileId → vault image, blank line between
24
+
25
+ %%
26
+ ## Drawing
27
+ ```json
28
+ { "type":"excalidraw", "version":2, "source":"…", "elements":[…], "appState":{…}, "files":{} }
29
+ ```
30
+ %%
31
+ ```
32
+ - `## Drawing` may be ` ```compressed-json ` (LZString.compressToBase64) **or** ` ```json `
33
+ (uncompressed). The plugin reads both. We emit uncompressed JSON — readable, no deps.
34
+ - The whole drawing block is wrapped in `%% … %%` (Obsidian comment) so it hides in reading view.
35
+ - `## Text Elements` and `## Embedded Files` sit **before** the `%%`.
36
+
37
+ ## Image embedding (the key mechanism)
38
+ - An image element is `{"type":"image", "fileId":"<sha1>", …, "scale":[1,1], "status":"pending", "crop":null}`.
39
+ - `fileId` is the **sha1 of the image file's bytes**.
40
+ - The `## Embedded Files` line `<sha1>: [[file.png]]` is what the plugin uses to load the picture
41
+ from the vault. **The scene `files` object can be empty (`{}`)** — no base64 dataURL required.
42
+ - `crop` is optional (only when the user cropped). `null` shows the whole image.
43
+
44
+ ## Ground-truth image element (decompressed from the vault)
45
+ ```json
46
+ {
47
+ "id":"GtJwnnEj","type":"image","x":-147.3,"y":-290.5,"width":118.8,"height":469,
48
+ "angle":0,"strokeColor":"transparent","backgroundColor":"transparent","fillStyle":"solid",
49
+ "strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,
50
+ "index":"a0","roundness":null,"seed":2054545386,"version":188,"versionNonce":1261541290,
51
+ "isDeleted":false,"boundElements":[],"updated":1779266944741,"link":null,"locked":false,
52
+ "status":"pending","fileId":"3eaa974da433f70ba06cb3fb2587b486d6143d32","scale":[1,1],
53
+ "crop":{ "x":713.7,"y":0,"width":871.3,"height":3440,"naturalWidth":2283,"naturalHeight":3440 },
54
+ "hasTextLink":false
55
+ }
56
+ ```
57
+ …and its `## Embedded Files` line:
58
+ ```
59
+ 3eaa974da433f70ba06cb3fb2587b486d6143d32: [[Pasted Image 20260515130812_941.png]]
60
+ ```
61
+
62
+ ## z-order: fractional indices
63
+ - Every element has a string `index` (`"a0"`, `"a1"`, …) — fractional indexing, compared
64
+ lexicographically. We generate them with the vendored `fractional-indexing` lib
65
+ (`generateNKeysBetween(null,null,N)`), which matches the vault output exactly.
66
+ - Excalidraw's `restore()` (run by the plugin on load) repairs invalid/missing indices, but we emit
67
+ valid ascending ones anyway.
68
+
69
+ ## appState
70
+ Minimal is fine: `{"gridSize":null,"gridStep":5,"gridModeEnabled":false,"viewBackgroundColor":"#ffffff"}`.
71
+
72
+ ## House style (measured from MemoryOS High Level / Personalization Module / Research)
73
+ The vault's presentation boards share one fingerprint — `scripts/lib/style.js` encodes it:
74
+ - **Font:** Excalifont, `fontFamily: 5`, for ~100% of text. Sizes form a scale: ~16 labels, ~20 body,
75
+ ~28 sub-headers, ~44–50 section titles (scaled up on large zoomed-out canvases).
76
+ - **Fills:** `fillStyle: "solid"` exclusively (never hachure). **Every rectangle is rounded.**
77
+ - **Ink:** `strokeColor: "#1e1e1e"`, `strokeWidth: 2` dominant (1 for fine/secondary).
78
+ - **Semantic palette** (Excalidraw native swatches): green `#b2f2bb`/`#2f9e44` (benefit/go),
79
+ red `#ffc9c9`/`#e03131` (pain/risk), blue `#a5d8ff`/`#1971c2` (system/flow), purple `#d0bfff`/`#6741d9`
80
+ (core service), yellow `#ffec99`/`#f08c00` (processing), mint `#96f2d7`/`#0c8599` (result),
81
+ pale variants `#ebfbee`/`#e7f5ff`/`#f3f0ff` for backdrops.
82
+ - **Patterns:** rounded-card (rect + centered label, grouped) · color nodes by role · ellipse = actor,
83
+ diamond = decision, container-rect groups sub-states · arrows almost always single end-arrowhead,
84
+ labeled inline ("req", "msg+ctx") · side-annotation arrows to spec notes · big plain section titles
85
+ ("Configuration", "Flow") · benefit/risk **card columns** · hub-and-spoke concept maps · bulleted
86
+ spec lists as one text block. Heavy use of embedded screenshots in research murals (huge canvases,
87
+ 29+ groups) — exactly the funnel-map use case.
88
+
89
+ ## Tooling note
90
+ The `yctimlin/mcp_excalidraw` MCP server was evaluated and rejected for this vault: it needs a
91
+ running localhost canvas server and exports excalidraw.com JSON / PNG / share-URLs — it does **not**
92
+ write Obsidian `.excalidraw.md` with the `## Embedded Files` wikilink section. Hand-generating the
93
+ file (this skill) is the correct, dependency-light path for bulk-embedding local screenshots.