Memory

project

Cross-thread snapshot of what's in flight in the Claude_Code workspace. Updated end-of-session, read at start-of-session.

#Current focus

Active threads (2026-04-28):

  1. Skill Dashboard / Forge of Hephaestus — All 8 phases + UI pass + Forge evolution features (job queue, recent outputs, live pulse) + schema v2 + cross-stage edges shim + Memory tab + Brain View + Chat Queue + Apps detail panel + mobile pass. See project_dashboard.md.
  2. Citadel platform vision — Nomenclature fully locked 2026-04-25. See project_polis_vision.md.
  3. Library of Alexandria — Architecture phase complete 2026-04-28. Four canonical planning docs in _ops/library-of-alexandria/. Phase 0 prep next (design prototype, library-sources.json draft, Mnemosyne eval set). See project_library.md.
  4. LDH (Les Dames des Hypothèques) — canonical SpeakUp pipeline client. Apr-May launch batch in flight (13 posts; 8 shipped, 5 remaining as of 2026-04-30). Stories methodology v1 + Mois 2 scaffold built 2026-04-30. Open: §7 methodology gap, §4 BTS carve-out, Plankton routing deferred. See project_ldh.md.
  5. SpeakUp pipeline build — primary use case driving the workspace. Methodology + content tree + season framework all feeding into it.
  6. Kamvas — internal Milanote-style canvas tool. Phase 1 SHIPPED (2026-05-02) + 2 polish items (2026-05-04) + Phase 2 architecture LOCKED (2026-05-04). Days 1–5 + ImageCard caption editing + multi-handle workspace dropdown (prefs.workspaces map + activeWorkspaceName pointer with auto-migration). Phase 2 (Supabase opt-in per-board cloud sync + conflict modal + lazy asset upload + nanoid share links + Microlink unfurling) implementation ready: ~32h across 11 build steps. Spec authoritative: _ops/kamvas/SPEC.md "Phase 2 — Locked decisions". See project_kamvas.md.
  7. Bema — pitch deck builder for the agency. Phase 2.5+ SHIPPED 2026-05-10 (session 11). Visual-references layout system implemented end-to-end (4 presets: auto/hero-tiles/grid-3/solo; slide-level layout enum on VisualReferencesContent; data-layout attr on grid; segmented control in VisualReferencesPanel; Playwright-verified all 4 presets + hero-tiles at 4/3/2 right-tile counts). Two CSS gotchas caught during smoke-test: (1) hero-tiles needs explicit grid-template-rows per data-count for grid-row: 1 / -1 to span properly, (2) solo needs :not(:first-child) { display: none } to render only one cell. Phase 2.5+ closed. Next: Phase 3 (Supabase) — full multi-weekend effort, fresh session. Port :5177, bema-app/. See project_bema.md.

Recently shipped (2026-05-12 — Hestia Phase 2 SHIPPED + reconciled missing backend log): Started by trying to show Charles a preview, hit "Cannot GET /" on :5180. Traced to startup-only existsSync(PUBLIC_DIR) check in src/server.js — if the build finishes AFTER the server starts, the static middleware never registers. Patched to register express.static unconditionally + per-request existsSync on index.html with a 503 fallback. When Jason asked "where should we build up next," code scan surprised us: Phase 2 backend was already complete (Library /api/library/clients/:slug endpoint in library-app at routes/library.js:704 returns grouped docs by house_section + workspace notes.md content; Hestia adapter at src/adapters/library.js with 5-min cache + fetchBrandContext for Sonnet system block + groupBySection; Hestia routes src/routes/library.js proxy + src/routes/quick-wins.js full Sonnet 4.6 tool-use route with ephemeral brand-context cache + history endpoint; ClientDetail Notes + Library tabs both wired). Only Phase 2 gap was Quick Wins frontend. Shipped: added generateQuickWins/fetchQuickWinsHistory/markQuickWinActed to client/src/lib/api.js; built QuickWinsPanel component rendered as second card on Overview tab (chose over dedicated tab so wins live in the Monday-morning glance flow). Numbered wins with title bold, why italic muted, effort badge (small/medium/large color-coded green/yellow/red via new .badge.effort-* classes), timeframe badge. Footer surfaces timestamp · X/Y acted on · brand_context_used flag · cached/in/out tokens explicitly because the v1 prompt is open decision #3 — Jason needs to see what's being fed in to iterate. Post-test refactor: Jason flagged batch-level "Mark acted on" as coarse + unclear what got stored. Refactored to per-win: PATCH endpoint now takes {win_index, acted_on} and mutates suggestions JSON (sets wins[index].acted_on to ISO timestamp or null). Frontend swapped to per-win 18px checkbox with strikethrough + 55% opacity on acted wins. History row shows "X/Y acted on" per batch. Batch-level acted_on column on quick_wins table is now dead weight (kept for schema compat — drop in later migration). Gating: canComment = actorRole !== 'read'. Files touched: hestia-app/src/server.js, src/routes/quick-wins.js, client/src/lib/api.js, client/src/views/ClientDetail.jsx, client/src/styles/app.css. Hestia is NOT a git repo (noted for future commits). Carried: Phase 5 (Loom indicator — trivial) and Phase 6 (loyalty automation cron + Sonnet gift suggestions + Slack/email digest, decision #5 open) are next forward paths without external input. Phase 3 (GHL) blocks on Charles. Phase 4 (Plankton) blocks on Plankton's per-client endpoints. Quick Wins prompt v1 validation pending Monday real-client use. See project_hestia.md session-4 block.

Recently shipped (2026-05-12 — Library Phase D.1 review + commit + cleanup, session 7 morning): Closed the Phase D.1 wrap loop and two Pandoras in one short session. (1) Commit b8cd746 — Phase D.1 (18 files, +803/−240). Excluded the unrelated Ekho-import work from scope. (2) Migraine doc moved _temp/private-pending/migraines.md~/Library-Private/pursuits/holistic-health/migraines.md. (3) Sorting-drafts conversation surfaced a real architectural gap. Jason flagged the SpeakUp Pipeline SOP (then classified Frameworks > Methodology) as "SOP-thoughts, not finalized SOP — should go to Streams with tags pointing at intended end home." Same logic applied to the two migrated journal docs (content-tree + onboarding). Three docs reclassified by physical move into library/streams/voice-notes/2026/04/ with tags: frontmatter encoding intended destination: Pipeline SOP ["wip", "→ frameworks/sops"]; content-tree ["seed", "→ builds/loom", "→ frameworks/methodology"]; onboarding ["seed", "→ frameworks/sops"]. Three-entities note kept where it is (already path-classified to Streams > Voice Notes; frontmatter override stale, harmless). Watcher picked up all moves; verified via search. Three new architectural Pandoras opened, logged to project_library.md: (a) Library maturity layer + tag system (Daedalus-class — pills should act as tags pointing at intended destination, subs need sub-of-subs nesting, status field for draft→stable→published); (b) reader view base width too narrow; (c) drag-resize table columns. (4) Commit 31f80ca — Ekho-import code (src/capture/pipeline.js +97 / src/utils/frontmatter.js +6, sitting uncommitted since 2026-05-11). Adds initImportedTranscript() + runImportPipeline() — voice-note shape from external transcript, Mnemosyne routing skipping transcription step. (5) Commit 736a89c — reader view default width 820 → 960px (ReadingView.jsx initial state + app.css:996 fallback). Drag range unchanged. Closes Pandora opened earlier the same morning. Three commits total. Server stayed up PID 92609 on :5175 throughout. Open carry-over: Phase D.2 still gated on B (Daedalus rendering pass); the architectural maturity-layer/tags pass is its own Daedalus-class arc (don't try to half-implement). 6 Phase D Pandoras in spec § 9 unchanged. 46 classification_needs_review rows unchanged. Tailscale invites for Shady + Charles unchanged. Forge offline (:5174) unchanged. See project_library.md session-7 block (top of file).

Recently shipped (2026-05-12 — Library Phase D.1 COMPLETE, session 6 overnight autonomous): Closed everything from step 5 through DoD verification while Jason slept; 5 small polish fixes after he woke up. Backend: /stacks now returns {collections, lenses, private, stacks} (private is [] for non-owners — never leaks); new /stacks/:category/groups for stack-level private grouping (Pursuits=topic, FRM=person) with same-named-prefix stripping so group keys are slugs like holistic-health not the stack-name dir; matchesGroup on /stacks/:category applies the same logic for drill-downs; entryReferencesPrivate() filters /pending-routes + /routing-log for non-owners (checks library_category against private stacks + voice_note_path/destination.ref against private roots); isValidScopeRef walks registry private sources and rejects matching scope_refs. Mnemosyne: prompt reads lenses + private_stacks from registry, library_category enum is the union, new Mythology + Private routing guidance + dual-routing pattern note; schema.js validates against allSubsByCategory union. Collections cleanups: Journal removed from Streams (registry + both classification rules); 2 docs migrated _ops/journal/inbox/~/Library-Private/journal/; new partners source registered with full Partners-shape rules; partners/hoski/ + partners/speakup/ folders scaffolded. SpeakUp transcript reroute (P0): strict grep returned 0 matches — skipped per spec's "If found" conditional; rule already wired so future real meetings route to partners/speakup/team-meetings/ automatically. Frontend: 3-section sidebar (existing nav → Mythology with lens icon between Search and Collections → Collections unchanged → Private with lock icon + charcoal accent + toggleable open/closed persisted to localStorage → Forge Queue); StackDetailView handles stack-level groupingMode (Pursuits/FRM), section-aware back label, breadcrumb 🔒 badge for Private, third Folders↔flat toggle for private stacks; new stackRootGroups API helper; Mythology + 4 private hues added to FIXED_COLORS. 13/13 smoke tests passed across jason vs shady (stacks shape, file gate, publish-vercel 403, stack-root groups, drill-down, folder-share rejection, existing Neji token still excludes private, defense-in-depth via token, search filter 18 vs 20 results). One bug caught + fixed live during smoke (prefix segment was returned as group key on first try). Post-DoD polish: stale-error bleed-through across stack pages (missing setError(null)), Private toggle revert from <button> back to <div role="button"> (browser default button sizing grew the row even with font: inherit), Mythology dot → lens icon, search scope label THIS/ALLstack/all lowercase. Files touched (uncommitted — Jason commits in the morning): library-app/src/{routes/library.js, mnemosyne/prompt.js, mnemosyne/schema.js}, library-app/library-sources.json, library-app/client/src/{lib/api.js, lib/utils.js, components/Layout.jsx, components/InlineSearchBar.jsx, views/StackDetailView.jsx, styles/app.css}, partners/{hoski,speakup}/, ~/Library-Private/journal/{2026-04-23_content-tree.md, 2026-04-23_onboarding.md}, .claude/settings.local.json (autonomous permission batch added at session start). Server up PID 92609 on :5175 (LaunchAgent at gui/502/com.library.server, not gui/501 as the pickup brief said). Carry-over: migrated journal docs may want re-route to Lab/Workspace (they're work-thinking, not personal); StacksView title still says "Collections" though it includes Mythology + Private for owners; SpeakUp three-entities note still in Reference > Network (could move to partners/speakup/notes.md); 6 Phase D Pandoras logged in spec § 9; Phase D.2 gated on B (Daedalus rendering pass). See project_library.md session-6 block (top of file).

Recently shipped (2026-05-12 — Library folder shares + internal:true flag, session 4): Both steps 2 + 3 of the multi-session feature landed in one session, closing out the Neji-folder-share trigger. (1) Shared src/render/frontmatter.js got an internal badge (small warm-red pill in the meta line, tooltip "Hidden from external folder shares") — rendered identically in the in-app FrontmatterStrip wrapper AND the server-side renderHtml() Vercel-publish path. clients/neji-jedda/notes.md, clients/les-dames-des-hypotheques/notes.md, project_neji.md, project_ldh.md flagged. (2) Idempotent schema migration: share_tokens ALTERed for scope TEXT + scope_ref TEXT. New POST /api/library/folder/*/share (wildcard captures path-aware scope_ref like clients/neji-jedda; admin-only via new isAdmin() export; body {permission, label, expires_days}; synthetic doc_id = "folder:<scope_ref>"). New GET /api/library/folder/*/shares (list active folder shares). GET /api/share/:token extended with folder branch — returns {scope, scope_ref, count, docs:[...]}; legacy doc-scoped tokens (scope=NULL) fall through to original path (back-compat preserved). New GET /api/share/:token/doc/:docId for individual doc fetch within folder share. Defense-in-depth verified: internal-flagged notes.md absent from folder index AND 404 on direct fetch by id; scope-mismatch doc 404s. getEnrichedFiles exported from library.js → reused by share.js for cached file index. workspacePathForFile() helper derives <sourceRoot>/<relPath> for prefix matching (caught an off-by-one — relPath is source-relative, scope_ref workspace-relative). (3) Frontend: new client/src/views/ShareFolderView.jsx (~190 LOC) — header strip, docs grouped by subcategory, click opens individual doc in same surface via state machine + per-doc fetch. ShareView.jsx got a 1-line dispatcher branch (if (data.scope === 'folder') return <ShareFolderView .../>) — no router change, /share/:token handles both shapes transparently. Client bundle built clean. Pandora carry-over: vocabulary doc extraction, uncommitted Ekho-import code, Bema/Hestia favicons (no new items). Smoke-test token 01KRD61VRFH8CB3P10E131PXVX (Neji, 7-day) left in DB for follow-up testing. See project_library.md session-4 block.

Recently shipped (2026-05-11 — Library Builds-card enrichment + third hierarchy layer, session 3): Two scoped commits on library-app/main (f10a5d6, 728a2cb). (1) Builds folder grid renders per-app favicons auto-discovered from each app folder (12 candidate paths tried in order — 8/10 hit: Library/Forge/Loom/Mouseion/Kamvas/Delphi/Ekho/Gymnasio; Bema + Hestia fall back to dark monogram plate until they add a favicon). Each card also surfaces the "What it is" line from CLAUDE.md's Active apps table. Three hierarchy entries (Citadel/Workspace/Client System) render description-only — HIERARCHY_DESCRIPTIONS const in citadel-apps.js. Builds order locked: hierarchy first, then apps in workflow order with Library first. New /api/library/app-icon/:slug route streams the file. (2) Third hierarchy layer: StackDetailView learns a mode === 'group-folders' rendering branch. When a sub has groupingMode declared (currently 'client' on Houses>Clients and Houses>Prospects via the new sub_grouping map in library-sources.json), navigating to ?sub=Clients shows a folder card per client slug (Cody/LDH/Neji/Nicolas/Kevin/Spa Mobile/Wolf Pack). Click drills into the existing flat list filtered to that group, with house_section facet pills above the type filter (Brand/Strategy/Research/Deliverables/Notes). Breadcrumb extends to Collections › Houses › Clients › Neji Jedda › Brand, each segment clickable. Backend: new GET /api/library/stacks/:category/:sub/groups endpoint; /stacks/:category accepts &group=<key>. Groups gated to sources with client_aggregation: true so auto-memory project_ldh.md + _ops/recovery/HANDOVER-LDH-...md don't form phantom client folders. Pattern is reusable — adding "Lab": { "Studies": { "mode": "topic" } } + a topic derivation extends the third layer to Lab > Studies when populated. Decided: don't generalize speculatively; only Houses > Clients/Prospects + (future) Lab > Studies want this — other subs are flat by nature. Pandora logged in project_library.md (Forge offline): vocabulary doc extraction from MEMORY.md to reference_vocabulary.md (~5 min); uncommitted Ekho-import code in capture/pipeline.js + utils/frontmatter.js (~103 lines, working but never committed since 2026-05-11 Ekho integration). Steps 2+3 (internal: true flag + folder-scoped share tokens + ShareFolderView) deferred to fresh session — tightly coupled, ~2-3 hrs, and step 3 is the actual Neji trigger that motivates the feature. See project_library.md session-3 block.

Recently shipped (2026-05-11 — Library ReadingView UX batch + Citadel-apps reconciler, session 2): Closed the three ReadingView UX gaps flagged at end of the morning's Daedalus rendering pass session, then bonus-shipped a Citadel-aware Active Apps reconciler in response to Loom/Hestia/Ekho being missing from Builds. (1) Breadcrumb trail in ReadingView (Collections › stack › sub › title, each segment clickable except title; tooltip + ellipsis on long titles). (2) Classify section hide — the JSX wrap was already correct; the user-visible bug was actually two things: (a) stale classifyDone/classifyStack state bleeding across doc navigations (fixed with id-change reset), AND (b) most docs lack library_category in their .md frontmatter — classification lives in the source_index DB instead. (3) InlineSearchBar — new component top-right of StackDetailView, defaults to current stack/sub scope, This/All toggle, 220ms debounced dropdown of 8 results, Enter → full SearchView pre-scoped via ?q=&category=&sub=. (4) Backend: GET /file/:id now joins source_index and returns canonical libraryCategory+subcategory (this was the root-cause fix for the broken breadcrumb + the broken Classify-hide); /search accepts sub= param threaded through ftsSearch+vecSearch. (5) LDH brand-guide.md source cleanup: tab-separated tables → pipe-table syntax, section numbers → ##. (6) Citadel-apps reconciler — new src/citadel-apps.js parses the Active apps table in workspace CLAUDE.md and reconciles stacks.Builds + classification rules at registry load. Logged +3 subs (Loom, Hestia, Ekho), +14 classification rules. Post-bootstrap: Loom 4 / Hestia 2 / Ekho 0. Ekho is 0 because project_transcribe.md lives outside workspace auto-memory — flagged for next session. Verified the new rendering pipeline reaches production: republished library-memory.thecitadel.tools + library-library.thecitadel.tools via API; both serve fm-strip + prose-table-wrap markers. Two scoped commits land in next git step (UX batch + reconciler). Reconciler is additive-only, idempotent, runs on every registry load. Next session: third hierarchy layer (Stack → Sub → Sub-sub) + folder-scoped share tokens + internal: true visibility flag — multi-session feature, fresh start. See project_library.md.

Recently shipped (2026-05-11 — Neji onboarding kickoff + canonical client-template refactor): Second SpeakUp social pipeline client started. Neji Jedda, Xperto Hypothèques courtier, "Le Courtier-Professeur du Québec" (Plan de Match approved 2026-04-08). Phase 0 executed: clients/neji-jedda/ scaffolded from _template, 3 ingest docs filed into canonical slots (Plan de Match → strategy/plan-de-match.md, Fathom summary → research/onboarding-call-summary.md, full FR transcript → research/onboarding-call-transcript.md). Brand-guide.md + notes.md + client.yaml pre-filled from Plan de Match. Registered in CLAUDE.md > Current clients + MEMORY.md > Client System. Mid-session canonical-template refactor (Jason flagged scope overlap in brand-guide.md): locked lane definitions across all 5 client docs — brand-guide.md = identity card + visual identity only; messaging-framework.md = voice mechanics + verbal message bank (Key messages section added); strategy/plan-de-match.md = positioning, personas, pillars, production, calendar, pricing; notes.md = contacts, preferences, status, session log, process-improvement backlog; strategy/content-tree.md = Loom-managed. Stripped Neji's brand-guide to match (~40 lines vs original ~180), moved Key messages → messaging-framework, moved constraints → notes. Updated _template/brand/brand-guide.md + _template/brand/messaging-framework.md to enforce new lanes. Legacy client backfill (LDH + 5 others) NOT done — touched-next-time policy. Two parallel methodology threads flagged for upcoming sessions (block Mois 1 / visual identity session): (1) YouTube scripting framework SOP — Neji is YouTube-first, current workspace has only short-form scripting; principles to canonize: modular long-form built for clean shorts extraction + every long-form ships with 1-2 paired purpose-built short-form scripts as teaser/redirect. (2) Color psychology / visual style derivation methodology — codify process for deriving palette + visual style from extracted personality + audience-feeling + brand-feeling; especially for clients without pre-developed branding. Both schedule around Deep Dive date. Process-improvement backlog (in clients/neji-jedda/notes.md): ONBOARDING.md handoff format note, pipeline-sop.md Stage 2/3 clarification, plan-de-match-template enforcement, SPEC.md lane definitions. Hygiene: wrapped at 5/6 triggers fired before Phase 1 (Deep Map onboarding transcript + Messaging Playbook v1 draft) which is queued for fresh session. Full state in project_neji.md.

Recently shipped (2026-05-10 — Bema Phase 2.5+ SHIPPED, session 11): Visual-references layout system implemented end-to-end. Closed the open item from session 10's locked decision doc (bema-app/docs/visual-references-layout-decision.md). Code: src/archetypes/visual-references.tsx gained VisualReferencesLayout type + VisualReferencesContent interface + renderer reads content.layout (default 'auto') and emits data-layout on .slide-visual-refs__grid; AssetCell exposes --asset-aspect CSS var for solo. src/styles/slides.css got 3 new rules (hero-tiles/grid-3/solo) declared after the existing data-count rules so layout wins via source order. src/editor/VisualReferencesPanel.tsx got LAYOUT_PRESETS + 4-button segmented control between Headline and Embedded assets. src/styles/editor.css got .vr-panel__layout-picker 4-up grid + button styling matching existing aspect picker pattern. Two CSS gotchas surfaced during Playwright smoke-test and fixed in-session: (1) hero-tiles initially used grid-auto-rows: 1fr + grid-row: 1 / -1 — hero collapsed to one row because in CSS Grid, -1 resolves to the last explicit line and an implicit grid only has line 1; fixed by declaring grid-template-rows: repeat(N, 1fr) for data-count='3'/'4'/'5'. (2) solo initially stacked all cells tiny in a single column when slide had multiple assets; fixed with :not(:first-child) { display: none } (other assets preserved in data, restored on switch back to auto). Verification: headless Chromium @ 1600×1000, opened ?dev=1 LDH sample, clicked through all 4 layout buttons + reduced asset count from 4→3→2 to verify hero-tiles row count handling. Typecheck + production build both clean. Locked decisions (session 11): solo hides extras (doesn't move/trim them) · hero-tiles row template is data-count-aware up to 5 (clamps beyond) · CSS source order matters — layout rules MUST stay declared after data-count rules (same specificity, last wins). Pandora carry-over from session 10 (still not POSTed — Forge offline this session too): slide-level Surface/Ink/Line override UI in SlideStylePanel (~30 min add when needed; type/emit/labels already wired).

Recently shipped (2026-05-09 → 2026-05-10 — Library Phase 3: Publish to Vercel + thecitadel.tools): Long session. (1) Phase 3 Publish-to-Vercel feature shipped end-to-end: vercel_deploys SQLite table, POST /file/:id/publish-vercel (renders → uploads via SHA1 → creates v13 deployment → polls READY → adds domain → aliases → persists clean URL), GET /file/:id/vercel-deploy, ReadingView share panel "Publish to Vercel" section with idle/publishing/published states. Auto-disables Vercel Deployment Protection (SSO + password) on each deploy via PATCH /v9/projects/:name. Alias retry handles SSL cert provisioning. Best-effort fallback to random Vercel URL if alias step fails. (2) Domain locked: thecitadel.tools — registered via Squarespace, wildcard * CNAME → cname.vercel-dns.com. Locked as the unified Citadel umbrella for ALL apps (Library, Bema, Forge, Kamvas, future). Each app gets its own VERCEL_APP_PREFIX (default library). Multi-session deliberation: rejected libraryofalexandria.tools (per-app domains don't scale, ego-pull only, brand belongs INSIDE the page), rejected library.argodigital.ca (Argo expiry uncertainty + agency-brand confusion for SpeakUp clients), rejected *.vercel.app (too generic, user vetoed). All other Citadel TLDs taken (.com/.app/.io/.studio/.dev/.ai/.cloud/.tools), thecitadel.tools was the standout available. (3) Verified end-to-end: https://library-memory.thecitadel.tools → HTTP 200 in ~600ms. Republish reuses same alias (URL stable across revisions). Three commits: 2111211 (feature), f98bc9b (auto-disable Deployment Protection), b9eb037 (clean-URL aliasing). (4) Render parity gap surfaced + queued for Daedalus rendering pass (next session): in-app render uses React MarkdownRenderer + global app.css; Vercel-published HTML uses renderHtml() with raw marked.parse() + Phase-1 inline <style> block. They've drifted (table polish, deep-map pre-processor missing on published version). Decision: don't quick-port CSS (would create duplication and need redo); bundle into Daedalus pass as 4th scoped item — server-side render via react-dom/server.renderToStaticMarkup() so both surfaces consume the same engine. Single source of truth, zero drift forever. (5) Architectural principle locked: "one engine, every consumer" — Google Docs pattern. Specialized renderers ONLY for docs whose data shape ≠ markdown (DeepMap, VoiceNote, HtmlPassthrough already exist). Everything else (project_*, methodology_*, brand_guide, studio_setup, feedback_*) is "markdown done well + composable frontmatter strip" — same render path. Don't build N specialized renderers. See project_library.md "render parity gap" section.

Recently shipped (2026-05-09 — Bema Phase 2.5+ EXTENDED, session 10): Two-item session: architectural decision + brand palette depth. (1) Daedalus Learning-mode pass on visual-references span/layout: slide-level layout presets win over per-asset span (layout is a container concern; per-asset span breaks on mixed aspect ratios). 4 presets locked (auto/hero-tiles/grid-3/solo); layout field lives in JSONB content — zero Phase 3 schema column change. Phase 4 sub-archetypes are separate archetype IDs, never values on the layout enum. Decision doc with CSS templates + data model + Phase 3 impact + implementation notes at bema-app/docs/visual-references-layout-decision.md. Implementation deferred to next session per session-hygiene budget. (2) BrandTokens gained 3 optional fields (surface, ink, line) — added what slides.css already consumed via var() with hardcoded fallbacks, not the speculative gradient/shadow/borderRadius from the original brief. parseBrandGuide, brandToCssVars, brandOverridesToCssVars all conditionally emit (undefined → CSS fallback fires; existing brand guides keep working). All 7 curated palettes rebuilt with mood-matched depth — Tech midnight + Luxury noir become true dark-mode (dark surface + light ink); the 5 light-mode palettes get warm cream surfaces. BrandPanel: collapsible "Advanced colors" section (3 ColorRows with placeholder defaults), category filter pills above the grid (All + 7 categories), palette cards now use each palette's own surface/ink/line as their bg/text/border so the card itself previews the mood. AI brandBlock includes new tokens when defined. Stale --brand-bg orphan in slides.css:714 replaced with --brand-surface/--brand-ink. SlideStylePanel FIELD_LABELS extended (slide-level UI widgets for surface/ink/line deferred — Pandora). Typecheck + production build clean. Pandora (logged in project_bema.md, not POSTed — Forge wasn't on :5174): slide-level Surface/Ink/Line override UI in SlideStylePanel — type/emit/labels wired, just no widget yet, ~30 min add when needed.

Recently shipped (2026-05-08 — Hestia Phase 1 SHIPPED): Phase 1.5 closed in one focused session. Milestones + Loyalty CRUD UI shipped, Loyalty Calendar 3-month grid (View 4) shipped, drag-to-update on Pipeline (View 3) shipped with confirmation modal. Backend: nested REST routers /clients/:slug/milestones[/:id] (CHECK enums on type, parent_id integrity check on checkpoints, __now__ sentinel for completed_at toggle, FK cascade on delete) + /clients/:slug/loyalty[/:id] + global GET /loyalty (denormalized client_name/slug joined). All writes through requireClientRole('edit'). Frontend: lib/loyalty-recurrence.js with expandLoyaltyOccurrences(event, windowStart, windowEnd) projecting yearly/quarterly/monthly/once anchors onto a window with day-clamping for month-end edges. Extracted MilestonesTab (BigGoalCard + progress counter + parent_id checkpoint nesting + inline edit + modal) and LoyaltyTab (upcoming-90 cards + full table + add/edit modal). LoyaltyCalendar = 3-month grid (responsive 3-col → 1-col at ≤1100px), today highlighted ember, chips per day (max 3 + "+N more"), click → modal with mark-acted + jump-to-client. PipelineView = native HTML5 drag (no lib), confirmation modal "Move X from Y to Z?". DoD verified hands-on through Playwright preview: 3 clients listed → drag Wolf Pack paused→active (confirmed + persisted) → LDH big goal "Hit 1k followers on IG by Aug 31" + checkpoint "Ship May batch" with toggle complete (progress 1/1 100%) → Tatiana K. birthday yearly 2026-06-12 with notes (renders "in 5w" upcoming + Jun 12 chip on calendar) → chip click opens detail modal with jump-to-client. Notes save (already verified session 2). Phase 1 fully ships. Next: Phase 2 (Library /api/library/clients/:slug endpoint contribution + populate Notes/Library tabs + Quick Wins Sonnet 4.6 button). See project_hestia.md session-3 block.

Previously shipped (2026-05-08 — Hestia Phase 1 backbone): hestia-app/ scaffolded matching Library's shape on port 5180 (Vite dev 5181). All 7 locked tables created via src/db.js with CHECK enums + FK cascades. permissions.js ported from Library, adapted to read client_collaborators from DB instead of frontmatter; requireRole(min) (global) + requireClientRole(min) (per-client) middleware. Express + clients router with GET/POST/PATCH/DELETE + /me + /health. React + Vite + react-router-dom 7 frontend with hearth palette (cream/ember/charcoal/gold, Cormorant + Inter). Overview Grid (sortable, inline stage/health, "+ New client" modal) + Client Detail (7-tab bar, Overview + Notes tabs functional, 5 placeholder tabs) + Pipeline kanban + Health Dashboard scaffolded. End-to-end verified in browser: create → list → inline-patch → detail → notes save round-trip through SQLite. Notes ownership locked end-of-session: notes are Library projections (workspace clients/{slug}/notes.md Session Log), not Hestia-owned. Phase 2 Library /api/library/clients/:slug endpoint must include the client folder's notes.md. clients.notes DB column from Phase 1 = transitional. Phase 1.5 next: Milestones + Loyalty CRUD UI to close SPEC's definition-of-done. See project_hestia.md session-2 block + _ops/hestia/SPEC.md.

Recently shipped (2026-05-08 — Kamvas Phase 2 steps 9–10): create-share-link EF (auth → nanoid slug → bcrypt password → insert share_link → return url), get-share-board EF (always-200, service role: expiry check → password compare → fetch doc_json → signed asset URLs 1h TTL), src/share/shareLinks.ts (client wrappers), src/share/ShareLinkDialog.tsx (list + create modal, copy/revoke), src/share/ShareView.tsx (complete state machine: loading/not-found/expired/password-required/board-not-synced/error/ready; tldraw read-only via hand tool + null all UI), assetCache.ts remote override layer (share view uses signed URLs, editor uses IDB), BoardSettingsPanel Share… button (gated: cloudSyncEnabled && lastSyncedAt). Zero TS errors, clean Vite build (919 modules). Step 11 (testing + polish) remains. See project_kamvas.md.

Recently shipped (2026-05-07 session 8 — Bema Phase 2 CLOSED): Full design pass on all 6 spine archetypes (cover + next-steps dark bookends, overview eyebrow accent pill, deliverables CSS counters, investment 72px price hero). Extract scope & packages AI agent (Sonnet, JSON, inline Add/Add all/Skip suggestion UI). 3 agency preset packages from plan-de-match. Prompt copy constraints tightened across all archetypes. CSS overflow scaling (count-based font reduction + line-clamp). Favicon. Export bug fixed (ensureSaved always writes). Show in Finder button (sidecar /reveal). PDF verified on real 6-slide deck — brand tokens, dark bookends, gold accent, all clean through Playwright. Phase 2 fully closed. Next: Phase 2.5 (PNG upload, prompt config panel, brand presets) then Phase 3 (Supabase).

Recently shipped:

Open decisions:


#Session log

#2026-05-11 (session 4) — Methodology-timing correction + new feedback memory

Two-item mini-session, both in the same chat. (1) Jason corrected the timing logic for the two priority methodology threads in project_neji.md > Parallel methodology threads. Original notes had #1 (YouTube scripting framework) and #2 (visual-style derivation methodology) scheduled after the Deep Dive with reasoning like "use Neji as the framework's first real test case." That conflated designing the methodology (general, derivable from prior art + first principles, doesn't need client material) with testing the methodology (client is the test case). Worse: writing the SOP first makes the Deep Dive cleaner because the methodology defines its own required inputs (e.g. visual-style derivation specifies "how do you want people to feel" + brand-respect references + personality-trait extraction pass), so the Deep Dive call guide consumes those inputs cleanly instead of double-purposing as a writing-input scramble. Both thread timings flipped to before Deep Dive, pickup block in project_neji.md rewritten so methodology threads are the default next-session work (was: deferred option). (2) Saved feedback memory at feedback_methodology_before_testing.md + indexed in MEMORY.md so the conflation doesn't recur. Memory names the rule, the why (this specific incident), the how-to-apply (default to building methodology before client extraction; flip the dependency from "we need client answers to write the SOP" to "the SOP tells us what answers to extract"), and the edge case (don't apply if the "methodology" is actually a client-specific play in disguise — those belong in clients/{slug}/, not _ops/methodology/). No Pandora's Box, no cleanup needed. Next session: pick #1 or #2 (ordering still open), ship the full SOP solo, scour prior art (anthropic-skills / marketplace.claude.com / GitHub awesome-claude-skills / infsh-skills for #1; color-psychology references for #2), one thread per session.

#2026-05-11 (session 3) — Neji social presence audit shipped (Path B)

Single-path session, no thread-braiding, no Pandora's Box accumulation. Path B picked from the session 2 handoff fork (Deep Dive not scheduled; methodology pre-work deferred per session 2 plan).

Deliverable shipped: clients/neji-jedda/research/social-presence-audit.md (~12KB). Sections: TL;DR · Platform-by-platform (LinkedIn / FB / IG / TikTok / YouTube / Xperto bio) · Voice cross-check (public vs Deep Map) · Handle strategy + recommendations · Implications for messaging-framework v1 repass · 3 new Deep Dive questions · v1 LinkedIn About prose draft · Sources.

Key audit findings: (1) Near-zero public courtier presence today. Only on-template surface is the Xperto bio (xperto.ca/brokers/neji-jedda/ + /courtier/neji-jedda/) — generic Xperto template prose = anti-voice baseline = exactly the gap messaging-framework.md is built to fill. (2) LinkedIn /in/nejijedda exists; headline snippet shows banking-era title "B.A.A. — Gestionnaire des partenariats" — likely stale, needs Stage 4 verify+update. (3) Banking pedigree externally verifiable (BDC, Farm Credit Canada Directeur Principal, TD); bonus public artifact = 2014 Canwealth Minerals CFO board appointment (newswire archive) — pedagogical-authority anchor usable in long-form / LinkedIn About. (4) YouTube fully greenfield — @nejijedda + @neji.jedda + @professeur-hypotheques + @courtier-professeur all 404. Strong claim opportunity before first long-form drop. (5) Handle pattern lock: nejijedda everywhere; drop @xperto.neji variant from messaging-framework.md. (6) Email confirmed njedda@xperto.ca — resolves the "ngedda/NGDA" kickoff confusion at @39:53. (7) 3 new Deep Dive questions surfaced (audit doc #11–13): Bulgarian language origin (new signal from Xperto bio), "25 years (Xperto)" vs "22 ans (kickoff)" framing reconciliation, LinkedIn current-employer field status. (8) v1 LinkedIn About prose draft included (tu-form, em-dash-free, FR-Quebec posé register, opens with the pivot, names the specific institutions) — ready for Stage 4 review post-Deep-Dive.

Side effects: messaging-framework.md inline TBD callout (Bio LinkedIn About direction) updated from "🔎 Blocking" to "✅ Sub-task complete" with cross-ref. notes.md > Website/social handles row populated from TBD with the full handle inventory. project_neji.md > Open decisions audit row closed with ✅. Phase 1.5 entry added to project_neji.md > Active work; Pickup-for-next-session block rewritten to fork by Deep Dive scheduling status (audit closed all pre-Deep-Dive Neji-side tasks).

Pickup for next Neji session: if Deep Dive is scheduled → customize _ops/methodology/deep-dive-call-guide.md for Neji (add the 3 audit-driven questions + the visual-style extraction block), output clients/neji-jedda/research/deep-dive-prep.md. Otherwise → methodology pre-work threads (YouTube scripting framework #1 or visual-style derivation methodology #2) — separate dedicated sessions per project_neji.md > Parallel methodology threads.

#2026-05-11 (session 2) — Neji Phase 1 shipped (Deep Map + Messaging Playbook v1-pre-deep-dive)

Clean session, all 3 must-do items + 1 bonus shipped. (1) Deep Map of the May 7 onboarding call (43 min FR transcript): Pass 1 TOC at clients/neji-jedda/research/onboarding-call-deep-map-pass1.md (30 themes / ~85 sub-themes, timestamped); Pass 2 verbatim soundbites at …-pass2.md (2-4 quotes per sub-theme, speaker+timestamp attribution). Voice signal captured for messaging framework: "à chacun son métier" (recurring proverb), "c'est l'honneur de la guerre" (commercial background metaphor), "d'ici jusqu'à la lune" (his visual hyperbole — canonized as hook pattern #3), "pluritage" (his neologism), "mise en relief" (his term for visibility-as-personal-presence), bilingual flourishes ("watch out," "kingpin," "flight by night," "gibberish," "shadowing"). (2) Messaging Playbook v1-pre-deep-dive drafted at clients/neji-jedda/brand/messaging-framework.md. Full structure: Voice (persona/archetype/authority/energy), Tone spectrum, Language rules (tu confirmed, em dash banned), Words to use/avoid (anchored in actual phrasing), 5 Hook patterns extracted from rhetorical moves in transcript, 3 CTA patterns (marked TBD-until-Stage-8), Sample content before/after (court + long), Bio for YouTube/IG-A/IG-B/TikTok/LinkedIn, Highlights structure (7 IG categories mapped to Plan de Match pillars), 3 Pin posts directions for Mois 1 launch batch, 10 Open items for Deep Dive. (3) Bonus — Bio/Highlights/Pin Posts ported from Nicolas's framework shape as the v1 scaffold for Neji, with hardened status block naming three explicit repass triggers (post-Deep-Dive, post-Stage-8, post-visual-identity). (4) Deep social presence audit flagged as pre-Deep-Dive-useful task — focused audit (LinkedIn + IG + TikTok + YouTube + Xperto), not the full /social-strategy-research 6-phase SOP (Stage 1 already ✅ via Plan de Match). Output target: clients/neji-jedda/research/social-presence-audit.md. Informs messaging-framework v1 repass + LinkedIn About prose. Tracked in project_neji.md Open decisions + inline TBD in messaging-framework.md. (5) Priority locked on the two parallel methodology threads (YouTube scripting framework + visual style derivation methodology) — both flagged above in workspace Open decisions as cross-cutting workspace methodology. They block Neji at specific stages (Mois 1 scripts, visual identity session) AND serve future clients beyond Neji. Priority over the template-completion backlog (messaging-playbook-template, plan-de-match-template, ONBOARDING.md, SPEC.md edits). Clean wrap — no Pandora's Box items unlogged, no cleanup commands needed, no blown hygiene triggers. Next Neji session forks by trigger: if Deep Dive scheduled = wait, prep Deep Dive guide; pre-Deep-Dive useful = run social presence audit; methodology unblocks = YouTube SOP or visual style derivation session (separate dedicated sessions).

#2026-05-09 — Bema Phase 2.5+ EXTENDED (session 10)

Two-item session, both shipped clean. (1) Daedalus Learning-mode pass on the visual-references span/layout question that had been parked at session 9 wrap. Locked: slide-level layout?: 'auto' | 'hero-tiles' | 'grid-3' | 'solo' on SlideContent for the visual-references archetype. Per-asset span rejected (layout is a container concern; per-asset span fails on mixed aspect ratios — would require col-span + row-span + grid-template = full layout description system in disguise). 4 presets ceiling, no 2-col / 4-up / asymmetric variants — speculative. Phase 4 sub-archetypes (reels-grid, hero-reel, before-after, ig-mockup, brand-sheet, web-mockup) are separate archetype IDs with purpose-built renderers; never values on the generic slide's layout enum. layout field lives in JSONB content — zero Phase 3 schema column change. Decision doc with CSS templates + data model + Phase 3 impact + Phase 4 relationship + implementation notes at bema-app/docs/visual-references-layout-decision.md. Implementation deferred to next session per session-hygiene budget. (2) Brand palette depth shipped end-to-end. Pre-build read of slides.css surfaced the key signal: --brand-surface, --brand-ink, --brand-line are already consumed via var() with hardcoded fallbacks (#ffffff / #1a1a1a / #e6e2da) but not driven by BrandTokens. So the type expansion was "promote existing CSS consumers into the type system," not "speculatively add new tokens." BrandTokens gained 3 optional fields (surface, ink, line); the brief's original suggestion of gradient/shadow/borderRadius was rejected — none of those are referenced anywhere in slides.css and would have shipped as dead config. parseBrandGuide accepts new YAML keys (surface, ink, line); brandToCssVars and brandOverridesToCssVars conditionally emit (when undefined, CSS fallback fires; existing brand guides keep working with zero migration). All 7 CURATED_PALETTES rebuilt with mood-matched depth — Tech midnight (#0f1729 surface + #e8ecf4 ink) and Luxury noir (#0e0e0e surface + #f5f0e8 ink) are now true dark-mode palettes, the visible payoff of the depth work. BrandPanel got: collapsible "Advanced colors" section with 3 ColorRows (placeholders show defaults); category filter pills above the palette grid (All + 7 categories); palette cards now render with each palette's own surface/ink/line as their background/text/border so the card itself previews the mood (dark palettes land as dark cards). Stale --brand-bg orphan in slides.css:714 replaced with --brand-surface/--brand-ink (consistency fix on the blank slide rule — also makes blank slides render correctly under dark-mode brands). AI brandBlock in buildContextBundle.ts includes new tokens when defined so Sonnet knows the surface mood. SlideStylePanel FIELD_LABELS extended for the 3 new keys to satisfy the Record type (slide-level override UI widgets for surface/ink/line deferred to Pandora — brandOverridesToCssVars already supports them, just no widget). Typecheck clean, production build clean. Session-hygiene wrap recommended at +3 triggers (major topic boundary Daedalus→palette work; ~25 file ops; 2 distinct items shipped). Next: implement the visual-references layout system (decision is locked; small ~1-2hr session that closes the loop on Phase 2.5+ before Phase 3 lands). Pandora logged in project_bema.md, not POSTed (Forge wasn't on :5174): slide-level Surface/Ink/Line override UI in SlideStylePanel — type/emit/labels wired, just no widget yet, ~30 min add when needed.

#2026-05-08 — Library Phase 2.5 CLOSED (consultation surface session)

Phase 2.5 fully wrapped. Commit 8a33db9 on library-app/main. (1) Consultation surface — SearchView now reads ?q= on mount + syncs URL as user types; copy-link button in result count row; PWA start_url/search for quick-open on phone. Workflow: paste http://localhost:5175/search?q=LDH+brief into any Claude session or phone browser. (2) Search nav bug fixed — API returns docId (camelCase), old component was reading doc_id (snake_case); every search result click was silently broken. Fixed. (3) HTML renderer polishderiveTitle() strips .html extension; word count zeroed for html_file type on server + client. (4) Tailscale Funnel confirmed livehttps://macbook-pro-3.tail4a07f5.ts.net responding. Next session: Phase 3 — Publish to Vercel (export HTML → Vercel Deploy API → live URL; closes Mac-must-be-awake gap).

#2026-05-08 — Bema Phase 2.5 CLOSED (session 9)

All Phase 2.5 items shipped in one session. (1) PNG/JPG upload from anywhere in Visual References — showOpenFilePicker, auto-detects aspect ratio, copies to deck asset folder, drag-and-drop also wired, internal reorder drops tagged to avoid collision. (2) Prompt config panel — Deck.slotPromptHints, collapsible section in Brief panel with one textarea per archetype, cache-hash aware. (3) Aspect ratio picker + fit toggle + drag-to-reorder on asset rows — aspect + fit fields on VisualReferenceAsset, inline styles on slide renderer, grid-auto-rows: 1fr removed, grip-handle reorder with visual feedback. (4) Brand palette library — 7 curated read-only palettes (Agency/B2B/Tech/Luxury/Health/Creative/Finance) in 2-column swatch grid in BrandPanel. Next: Daedalus Learning-mode on visual-references span/layout before touching Phase 3 data model. Phase 3 (Supabase) is a fresh multi-weekend session.

#2026-05-08 — Library Phase C session 4 + Phase D + QOL pass

Long session. Phase C/D completed, then a round of QOL fixes, then rendering architecture flagged. All commits on library-app/main.

Phase C remainder + Phase D shipped (commit 42ce7cb): Thread replies (nested Comments tab, parent_id POST), export-with-comments backend + button, share_tokens SQLite table, create/list/revoke endpoints, public /api/share/:token route + src/routes/share.js, ShareView.jsx for token recipients, share panel in ReadingView (permission picker, label, 30d expiry, copies URL, active shares list, Tailscale Funnel command note).

QOL fixes (commits 9d832409ce37c5): Reader width 820px default + drag-to-resize handle (480–1400px, localStorage persisted). Audio endpoint + play/pause wired. Classify from uncategorized: StackDetailView modal + ReadingView marginalia picker. Deep map structural fix: normalizeDeepMapContent() pre-transformer converts 3-space-indented sub-items to markdown lists — works retroactively on all existing docs. Sidebar collapse: collapsed set overrides activeStack auto-expand; entire row click toggles sub-list when on stack root.

Rendering architecture flagged: Single prose pipeline is a holding pattern. project_library_rendering_architecture.md written. Next Library session MUST start with /daedalus Learning-mode pass on the rendering architecture before any type-specific rendering code.

Open blocks: Rendering Daedalus pass → rendering implementation (type registry, design system, deep map renderer, HTML passthrough). Jason admin: Tailscale Funnel + Tailscale invites + 42 classification triage rows.

#2026-05-07 (session 5) — Library Phase A solo edit-in-place shipped

Full Phase A code session. All 8 components built and deployed in one pass, ending with a successful Vite build + launchd restart. Lock/unlock/heartbeat endpoints verified via curl. mtime conflict check (409) smoke-tested and confirmed. Frontend bundle: ~940KB / 311KB gzip (expected — CodeMirror is large; acceptable for internal tool).

What shipped:

Architecture notes for Phase B pickup:

#2026-05-06 (session 4) — Library editing + collaboration architecture locked (Daedalus Learning)

Full architectural pass on editing and collaboration for the Library of Alexandria. No code written — this was the design-conversation session the scope pad (EDITING_AND_COLLABORATION_SCOPE.md) explicitly required before any editing code could land. Output: a complete locked decision pad at _ops/library-of-alexandria/EDITING_AND_COLLABORATION_DECISIONS.md (11 sections, cold-pickup ready for the next code session).

Decisions locked:

  1. Staging: lock full architecture this session; ship solo edit-in-place first (Phase A, 1-2 sessions) against a foundation compatible with collab. Do not ship solo case with a special-case conflict story.

  2. Editing surface: body + frontmatter (rename/move deferred Phase 2.5). CodeMirror 6 (markdown source) with live-preview toggle. WYSIWYG explicitly rejected — round-trip risk breaks markdown source-of-truth contract. Modal mode flip inside ReadingView (View/Edit state, ?mode=edit URL param). Hybrid save: IndexedDB draft + explicit commit + mtime 409 on conflict.

  3. Conflict model — decoupled per operation class (the key architectural decision): body edits = soft-lock (one writer at a time, Bema Citadel pattern reuse); annotations + highlights = append-only, no lock; suggestions = append-only proposals, owner accepts/rejects (acceptance routes through soft-lock as a body edit). CRDT held as future upgrade path on body edits only. This is the move that makes the Google Docs feel achievable without CRDT infra — commenting + suggesting stream simultaneously; body-edit exclusivity is rarely felt.

  4. Annotations: SQLite table in library/.search/ (extends existing infra, single backup target). W3C Web Annotation Data Model anchor (TextQuoteSelector + TextPositionSelector with fuzzy fallback on edit). Sidebar persists across both View and Edit modes (right rail desktop, bottom drawer mobile per session 3 Provenance pattern).

  5. Permissions: 4-role ladder (read/comment/suggest/edit) in collaborators: frontmatter block with folder-default cascade via new default_collaborators_by_path in library-sources.json. Phase 3 middleware from studio-setups/README.md extended from binary owner == requester to the 4-role check. Spec NOT redesigned, only extended.

  6. Sharing: stateful share-token table in SQLite (revocable per-token, labelable, auditable). Tailscale Funnel for public exposure. Stateless JWT explicitly rejected (cannot revoke without rotating signing key). Vercel proxy rejected. Hard rule: edit not available via share token. Lander pattern (Skawanotti/LDH multi-tab shape) canonized as frontmatter composition (lander.tabs[] with per-tab permission_override + access: internal_only) — closes the session 2 "shareable views canonization needed" flag.

  7. UI placement: inline mode flip inside ReadingView. Lock acquired on edit-mode entry; contention = banner, edit mode does NOT activate. Annotation sidebar persists across modes.

  8. Audit: dedicated edit_log SQLite table + unified-diff .patch files in library/logs/edits/{docId}/{ULID}.patch. Separate from routing log infrastructure (different concerns). History tab in annotations sidebar with timeline + diff expansion + "Restore this version." Cross-doc activity feed deferred Phase 2.5.

  9. Build phase order: Phase A (solo edit-in-place, 1-2 sessions, ships first) → Phase B (Tailscale auth foundation, ~1 session, independent) → Phase C (annotations + suggestions, multi-session, depends B) → Phase D (external sharing, 1-2 sessions, depends B+C). Phases B-D fold in BUILD_PHASES.md Phase 2 share-links + Phase 3 portal items.

Pandora's Box item 71940015-96e4-... (editing/collab architectural pass) closed — was tagged needs-daedalus; the thread is now answered.

project_library.md updated with locked decision highlights + statusLabel bumped + Phase 2 backlog reordered around Phase A/B/C/D. No library-app commits this session (decision pad lives in _ops/library-of-alexandria/ which is outside library-app's git scope).

#2026-05-05 (session 3) — Library Provenance reroute UI + mobile drawer + routing-log granularity

Continuing Library of Alexandria after session 2's Studio Setups landing. The pickup brief flagged a NEW backlog item (Provenance reroute UI) that took priority over the rest of the Phase 2 list — without it the user had no in-UI path to override Mnemosyne's classification when wrong, even though the backend already accepted the override. Plus mobile Provenance was unusable on iPhone (tap → nothing visible), and the routing log lacked stack/sub granularity for library routes.

All four must-do/stretch items landed in three scoped commits.

1. Backend: extend /modify to actually take effect for library routes. POST /pending-routes/:id/modify previously updated only the pending-route record's destination field. For library destinations the voice note's .md frontmatter retained the original Mnemosyne suggestion — so an override was a no-op as far as the Library's index was concerned. Extended the endpoint to accept { library_category, subcategory } alongside { destination }. For library type: persists override on the record AND reads/writes the voice note frontmatter (item.voice_note_path is captured at staging time), then invalidates the enriched-files cache so subsequent /api/library/recent, /stacks, /file/:id calls see the new category without waiting for the 30s TTL. forge_queue path unchanged (writeToForgeQueue still fires on modify).

2. Backend: routing trail carries library_category + subcategory. src/mnemosyne/trail.js was stamping library_category: null regardless of routingOutput shape. Updated to forward routingOutput.library_category + routingOutput.subcategory into the trail frontmatter. /routing-log endpoint helper now reads both fields. Existing trail files (pre-this-commit) gracefully fall back to → library since the fields are undefined.

3. Frontend: ProvenanceView rewritten with pickers + mobile drawer. New components PendingRoutePanel and IntegrityPanel (kept inline in ProvenanceView.jsx to keep the diff focused). Picker UX: native <select> dropdowns — keyboard accessible, mobile-friendly, no animation overhead. Library / integrity panels render two selects (stack + sub); forge_queue panel renders one (workspace). Stack list pulled from /api/library/stacks (filtered to drop uncategorized — never a target). Subcategory list filters to the chosen stack's declared subs (from same registry response). Workspace list hardcoded to the eight known tags from src/mnemosyne/prompt.js — there's no runtime registry endpoint for workspaces, so a comment in the file flags that the list must be extended manually if more workspaces are added. State pre-filled from the suggestion; on stack change the sub auto-resets to the first declared sub of the new stack. changed flag flips the approve/confirm button label and routes the action to modifyRoute (with overrides) or confirmClassification (with overrides) instead of plain approve/confirm.

4. Frontend: mobile drawer. Mobile-first CSS rewrite of .prov-d-right: fixed bottom drawer with transform: translateY(100%) collapsed state, animates up on .open. Backdrop element (.prov-d-backdrop) covers viewport behind the drawer at z-index 49 (drawer at 50). Close button () in top-right corner. padding-bottom: calc(24px + env(safe-area-inset-bottom)) keeps content above the iPhone home indicator. Desktop @media query overrides everything back to a static right column — position: static, transform: none, hides backdrop + close button. Same React tree on both, no JS branching needed.

5. Frontend: dismiss-as-skip rename + dismiss flow settled. Per the prior pickup brief's open question "what happens to dismissed rows" — the answer chosen this session is: records persist on disk (pending-routes.jsonl status='skipped' rows + classification_needs_review reviewed=1 rows are never deleted), the UI just hides them. With the picker now providing the reroute path, dismiss is no longer the only escape from a wrong suggestion — so the destructive feel of "dismiss" is replaced with the softer "skip" label. A "review history" surface to browse skipped/reviewed rows is flagged as Phase 2.5 polish (low priority — picker removes most of the need).

6. Routing log granularity polish. New helper formatRoutingLogDestination(item) in ProvenanceView.jsx renders → library : Frameworks / Methodology style for library items (when category fields are present), → forge / kamvas for forge_queue items, → <type> fallback. Old trail entries without category fields fall through to → library cleanly.

Three scoped commits on library-app/main: c3e8763 (backend modify endpoint + trail subcategory) · 2365537 (frontend reroute UI + drawer + dismiss-as-skip) · 0e9c761 (rebuilt bundle). Server restarted via launchctl stop/start com.library.server. Smoke-tested /stacks (returns 7-stack registry) and /integrity (42 review rows still pending, picker now available).

Phase frontmatter: statusLabel bumped to "Phase 2 in flight — Provenance reroute UI + mobile drawer + routing-log granularity shipped"; next field rewritten to point at the three big remaining Phase 2 items (consultation surface · shareable views canonization · HTML rendering) which all share the same surface and want a dedicated session. Forge auto-detects status from this frontmatter — no manual Forge edit needed.

Triage of 42 leftover classification_needs_review rows — deferred per session-hygiene budget. The picker UI is the unblocker; the actual triage is mechanical, ~5-10 min of tap-pick-confirm at the keyboard, not a code task. Most rows are Mnemosyne-drift categories ("Notes", "Strategy", etc.) — confirming with a 7-stack override rewrites library_category on the source_index row, and they won't reappear.

Pandora's Box at session start (carried over, none surfaced as Library scope): auto-download from social URL skill (8858c8b3-...), Mnemosyne extension to watch _ingest/ (b24d5634-...), LDH swipe-repurpose continuation (9713e25c-...), Tailscale invites for Shady + Charles. None blocked Library work.

Continuing Library of Alexandria after the prior session's 2D wiring. All five must-do/stretch items from the pickup brief landed in one session, on library-app/main.

1. Studio Setups wired end-to-end. _ops/studio-setups/ created with README + 4 stub files (solo-talking-head, dual-talking-head, dual-podcast, 3-person-podcast). Each carries the locked type: studio_setup frontmatter shape (slug · name · owner · variations · client_overrides · purpose_tags). One-line classification rule added at the top of the ops source's rules list in library-sources.json: studio-setups/**/*.md → Frameworks > Setups. Setups appended to the Frameworks subs registry. Re-bootstrap: 113 visible files indexed (was 102), 5 hard-rule-classified to Setups, no Mnemosyne hop. API confirms Frameworks > Setups (5).

2. Subcategories-as-folders shipped. Two-part change. Backend (src/routes/library.js): orderedSubs() now surfaces all declared subs even when count=0, so Houses exposes Prospects(0)/Clients(48)/Collabs(0)/Self(0)/Partners(0)/One-offs(0); Frameworks shows Methodology/SOPs/Playbooks/Templates/Setups; Lab/Operations/Reference all expose their declared sub shape. Stacks with no items at all also get their declared subs as empty folders. Frontend (StackDetailView.jsx rewritten): renders a folder grid by default reusing the existing .stack-card CSS, with a Folders / See flat list toggle pill row. Drill-down sets ?sub=<name>; flat mode is opt-in via ?view=flat. Breadcrumb back-link at Collections › <Stack> returns to the folder grid from a drill-down. Stacks with no declared subs (e.g. uncategorized) skip folder mode entirely and fall back to flat list. .breadcrumb-link button style added to app.css.

3. Color palette restored. client/src/lib/utils.js rewritten. Explicit FIXED_COLORS for the 7 stacks: Frameworks=sage(#6b7d5a), Builds=terracotta(#8c5a3a), Houses=slate-blue(#4a5878), Lab=plum(#6f5a78), Streams=amber(#a07a4a), Operations=slate-teal(#5a6f6b), Reference=wine(#7a4a4a). Each visually distinct at the sidebar dot scale. hashCategoryColor() hue range widened from 140-340 to 0-360 so warm tones return for legacy or Mnemosyne-drift categories that fall through to the hash.

4. Permissions Phase 2. _ops/studio-setups/README.md documents the owner convention (jason | shady | charles), a concrete scp-via-Tailscale upload path with the actual command, and a Phase 3 spec for Tailscale-User-Login middleware enforcement. Tailscale-add of Shady + Charles is admin work — flagged for Jason to do in the Tailscale admin console at https://login.tailscale.com/admin/users. UI dropzone deferred to Phase 2.5.

5. Setup cross-link in ReadingView. When a document has setup: <slug> in frontmatter, the reading view now renders an uppercase mono kicker above the title: USES SETUP: <Display Name> →. Click navigates to /file?id=ops:studio-setups/<slug>.md. Slug → display name is title-cased client-side (dual-podcast → "Dual Podcast"). .reading-setup-link style added to app.css. Reverse lookup (briefs-using-setup-X) still Phase 2.5.

Five scoped commits on library-app/main: 19a2c6e backend · ed1baa2 folder nav · 482f245 color palette · 0ea73cf setup cross-link · 117a6a0 rebuild bundle. Server restarted via launchctl stop/start com.library.server so registry edit + new /stacks shape are live.

New backlog item surfaced (flagged 2026-05-05): Provenance UI today only exposes skip/approve and dismiss/confirm-suggested. The backend already supports modify/override (api.modifyRoute + api.confirmClassification with subcategory override), but no UI affordance. When Mnemosyne's suggested path is wrong the user has no in-UI reroute path. Promoted to Phase 2 backlog item 1 — co-design with mobile Provenance modal port (item 2) and dismiss flow (item 3) since they share the same detail panel.

Cleanup decision: 47 leftover classification_needs_review rows from prior bootstraps → 42 (5 cleared by hard rule). User chose path (a) — triage in the Provenance UI — but that's gated on the reroute UI shipping first.

Phase status: advanced from 1.5 → 2 (in flight). project_library.md frontmatter updated; statusLabel reflects Phase 2 features shipped this session. Forge auto-detects from frontmatter so the Library card refreshes without manual edit.

#2026-05-04 (session 3) — Bema persistence + per-slide styling + recent-decks header

Continued Bema. Phase 1 went from ~50% to ~85% in one session, three architectural threads:

Local file persistence (item 1 from pickup brief). FS Access API + IDB-backed pref store mirrors the Kamvas pattern. New: storage/db.ts, storage/prefs.ts, lib/fs-access.ts (workspace handle, listClientSlugs, listPitchSlugs, readClientBrandGuide), lib/deck-storage.ts (save/load/listAtLocation/listAll), lib/brand-presets.ts (localStorage CRUD on bema:brand-presets). Deck JSON writes synchronously via the FS Access API; manual save with dirty indicator (auto-save rejected — clobber risk). Workspace handle persisted in IDB at bema:prefs:singleton, permission silently re-verified each session. Required @types/wicg-file-system-access because TS 5.5 lib.dom.d.ts is missing the FS Access types — added to tsconfig.

Save destinations are first-class. User pushed back on clients/{slug}/projects/decks/ being the only path: "we won't always be making pitch decks for clients." 60–70% of decks go to prospects who don't have a clients/ folder yet. Two-option destination picker in NewDeckDialog: {kind: 'client', clientSlug} writes under clients/{slug}/projects/decks/, {kind: 'pitches', slug} writes under _pitches/{slug}/. Custom-folder save (FS Access picker, handle stashed in IDB keyed by deck.id) deferred to future work — Pandora's Box 3300eed7-... logged because the Library of Alexandria restructure may revisit the workspace top-level layout (specifically whether _pitches/ keeps the underscore prefix or moves into a new top-level like inbox/). Deck.saveLocation added to the type; Deck.clientSlug is now just a label.

Brand placement reorganized: header pill + Style override tab. Original session 2 design had Brand as a sibling tab to Slide in the inspector. User flagged that this read as per-slide. Driving principle that emerged: deck-level adjustments must be reachable mid-edit without leaving the current slide context. Outcome: Brand pill (with primary swatch) in editor header → click opens a Popover containing the full deck BrandPanel (colors, fonts, presets, tone, reset). Inspector tabs renamed to Slide / Style; Style is per-slide overrides only. Added Slide.brandOverrides?: Partial<BrandTokens> with Inherit ↔ Override toggle per field. Override panel stores the deck value as the starting point on first override, strips the key on Inherit. CSS-var layering does the merge: deck vars at .editor shell, override vars at a slide-style-scope wrapper inside SlidePreview. No JS-side merging at render time. toneVoice excluded from per-slide overrides — tone is text instruction, not visual style.

Recent decks pill in header. Loads up to 8 recent decks from all clients/*/projects/decks/ and _pitches/*/ on workspace ready and after each save. Click switches deck with a window.confirm dirty-guard.

Blank archetype. Registered for the slide picker but excluded from default deck spine via DEFAULT_SPINE_ARCHETYPE_IDS separate from the full archetypes array. Pattern unblocks Phase 4 archetype additions without auto-bloating new decks.

Mid-session bug fixes. (1) Workspace re-pick affordance was missing — added "Change workspace" pill to dialog header so users aren't trapped if they pick the wrong folder. (2) "No clients/ folder found" warning was firing in New Prospect mode where it's irrelevant — gated on destination === 'client'. (3) Generic Popover component needed to ignore clicks on its anchor button (closing on every toggle click) — anchorRef prop fixes that.

npm run typecheck and npm run build clean across all checkpoints. New deps: idb, @types/wicg-file-system-access. New CSS sections: dialog, popover, brand pill swatch, recent menu, override toggles, Style tab badge, save status pills, Change workspace button, dialog__hint--mono. Two Pandora's Box items resolved (8e173dd3-... brand source picker, 05dbbb01-... named brand presets) and one logged (3300eed7-... LDA folder restructure dependency).

Wrap triggered by 2+ session hygiene flags (40+ file ops, ~3 hrs dense iteration). Next session: asset embed flow (Playwright sidecar — heaviest item left), then local Playwright PDF/PNG export, then LDH brand-guide YAML migration test.

#2026-05-04 (session 2) — Bema editor build

Continued Bema. Built the full 3-pane deck editor on top of the prior session's scaffold. Two architectural shifts mid-session:

Brand model relaxed. Original Daedalus lock said brand parser reads clients/{slug}/brand/brand-guide.md. User pushed back: most pitches go to NEW prospects who have no brand guide in our system. Bucket math is roughly 60–70% prospects (no guide), 20–30% existing-client expansion (guide exists), 10% brand-build pitches (brand IS the proposal). So Deck.brandTokens is now the deck's own snapshot, always editable in the inspector. The brand parser becomes one seeding mechanism among several: blank/manual, agency default (Speak Up + Hoski), existing client (parse guide), saved preset. Brand presets stored in localStorage:bema:brand-presets for Phase 1, Supabase brand_presets table in Phase 3. Save/load UI deferred to next session paired with new-deck flow.

Editor UX shape decided. Walked through real pixel widths on 1440 (13–14") vs 1728 (16") laptops. Option A (4 always-open panes including Brand column) squeezes preview to 620×349 on a small laptop. Option B (3 panes, brand as a tab inside inspector) gives 840×472 preview. User picked B with draggable column edges. Implemented: Splitter component using pointer-events with body cursor lock + pointer capture; pane widths persisted to localStorage:bema:editor:pane-widths with min-width clamping (160 / 280 / 360).

Built: render components for the other 5 archetypes (overview, deliverables, visual-references, investment, next-steps) matching Cover's pattern; SlideRenderer for archetype-id routing; SlidePreview wrapper that scales the locked 1280×720 design canvas via ResizeObserver (same DOM at preview AND at Playwright export — no separate render); FieldRenderer recursive form (text/longText/date/currency/asset stub/list with add+remove); DeckEditor shell owning all state; BrandPanel with color pickers + hex inputs + font selector with custom override + tone field. Sample LDH deck loads on open so the editor demoes itself end-to-end. npm run typecheck and npm run build clean.

Side fix: scaffold's tsconfig had three pre-existing issues (erasableSyntaxOnly requires TS 5.8+, tsBuildInfoFile needs composite: true, vite.config.ts imports node:url so @types/node was missing). Plus the typecheck script was tsc -b --noEmit which is illegal — script always errored out before running, so typecheck silently never worked in Phase 1 scaffold. All four fixed.

Wrapped per session-hygiene budget — pickup brief said items 1–3 must-do, items 4–6 (persistence, asset embed, Playwright export) heavier; trigger to wrap was crossed (20+ file ops, ~2hr build). Two new Pandora's Box items: brand source picker for new-deck flow, named brand preset save/load. Existing PB item b6acaaea-... (LDH brand-guide.md frontmatter migration) still pending — surfaces when item 7 (LDH parser test) lands next session.

#2026-05-04 — Bema spec + Daedalus review + Phase 1 scaffold

New thread: Bema, the agency's pitch deck builder. Replaces the team's "custom Figma per pitch" workflow with a brand-locked HTML deck builder. Single session covered four things end to end:

Spec discovery (4 forks). Walked Jason through four upstream architectural choices that dictate everything downstream: output format (HTML primary, PDF/PNG export — Figma deferred to v2 because team's existing habit is replaceable), where it lives (own app bema-app/, not a Mouseion sub-feature, because pitch decks are sequence-aware multi-slide deliverables not single artifacts), team access (Plankton-pattern cloud web app on Supabase in Phase 3), visual reference engine (compose existing carousel/thumbnail HTML, don't regenerate). Pushed back on skipping the pitch-doc step — kept it as a structured internal brief.

Naming. Pinakothiki rejected as too long. Stoa proposed but Jason wanted something more obvious. Suggested two place-words: Bema (the elevated speaker's platform in the Athenian assembly) and Pnyx (the assembly hill). Bema locked with explicit "I might change my mind later" reservation.

Daedalus review. Delegated structural review to a general-purpose agent running the /daedalus Learning-mode skill. Agent fetched relevant nodes from system-design, postgresql-dba, ai-engineer roadmaps and synthesized 5 decisive recommendations: (1) hybrid data model — slides table with JSONB content + manual_edits mask field; (2) two-stage AI pipeline — Opus once for strategic angle, Sonnet per slide parallel-batched 3-4 with edit-lock mask + hash cache + Anthropic prompt caching for the brand+brief preamble; (3) soft-lock via Supabase Realtime presence, no CRDT (wrong tool for one-writer-many-viewers); (4) snapshot-at-embed PNG via Playwright, no live iframes, manual refresh button; (5) Node sidecar for Playwright export — cannot run in Edge runtime, cannot deploy to Vercel. Three caveats Jason locked picks for: (a) brand parser → YAML frontmatter on existing brand-guide.md files, (b) archetype storage → reference table not Postgres enum, (c) Supabase tier → defer to Phase 3.

Phase plan + scaffold. Four phases mapped: Phase 1 local solo build (no Supabase, no AI, manual entry, six spine archetypes), Phase 2 AI assistance, Phase 3 cloud + team access, Phase 4 full archetype catalog + visual reference sub-archetypes + transcript-to-brief auto-gen. Scaffolded bema-app/ Phase 1: Vite + React 19 + TS on port 5177 (next Vite cascade after Kamvas), gray-matter for brand parsing, archetype registry with all 6 spine archetypes (Cover with full render component, other 5 schema-only placeholders), brand parser utility, Deck/Brief/BrandTokens TypeScript types, app shell with placeholder card listing registered archetypes, CLAUDE.md + PROJECT_MEMORY.md + README. Updated workspace CLAUDE.md Active apps table (Bema row, port 5177 in dev ports list). Registered bema config in .claude/launch.json. Verified live in preview — Vite ready in 396ms, zero console errors, all 6 archetypes rendering in the registered list.

Pandora's Box this session: brand-guide YAML frontmatter migration. New parser depends on YAML frontmatter (primary, secondary, accent, font_heading, font_body, tone_voice) on existing brand-guide.md files but no client has it yet. Posted as Pandora's Box item to surface when next working on LDH (canonical client to test parser against). Logged here and in project_bema.md open questions.

Next session pickup: render components for the other 5 spine archetypes, deck editor UI shape decision (split-pane vs inline-edit), local JSON persistence to clients/{slug}/projects/decks/, asset embed via local Playwright snapshot, local Playwright PDF export. Test parser by adding YAML frontmatter to LDH's brand guide.

#2026-05-01 — Why-lines stripped + SpeakUp pipeline SOP triage (Code, same session as scripts)

Continuation of the LDH Mois 2 scripts session. Two corrections + a triage workstream surfaced.

Why-lines stripped from scripts.md. First-draft format leaked writer-side justification (*Why:* [explanation] under each of 3 hook variations × 14 posts = 42 explanation lines). Jason flagged as clutter for a client-facing brief. Stripped via Python pass. script-framework.md Layer 5 updated: client-facing format = role + category labels only, the three Why questions stay in the writer's process. Codified as new feedback memory feedback_deliverable_hygiene.md — internal reasoning never inline in client deliverables.

SOP triage opened. Jason raised: we wrote 14 scripts without invoking any of the relevant global skills (copywriting, copy-editing, brand-review, marketing-psychology). Skill-augmented passes might have caught the em-dash slip + Why-line bloat at draft time. Larger question: there's no formal SOP for the SpeakUp content pipeline end-to-end. Methodology files exist (14 of them in _ops/methodology/), client onboarding docs exist (_ops/client-system/ONBOARDING.md, SPEC.md), template folder exists (clients/_template/), CLAUDE.md auto-behaviors exist — but no single doc that says "for any new SpeakUp client, here's the 16-stage process, who runs each, what skills assist, what outputs land where, what review gates exist". Wrote scaffold/triage doc at _ops/methodology/speakup-pipeline-sop.md covering: pipeline stages table, custom skill map, global skill map (NOT invoked this session — flagged), skill gaps (build candidates), 8 open questions blocking the full SOP, soft-pass V2 protocol proposal for next session, pickup order.

Soft-pass V2 protocol (proposed for next session, not run this one). Take 3 LDH Mois 2 scripts (V1 tactical, V7 emotional, V9 humor test), run each through copywriting + brand-review, file as scripts-v2.md, compare side-by-side, decide on inclusion in standard SOP.

MEMORY.md index updated with two new entries: deliverable hygiene feedback + SOP scaffold pointer.

#2026-05-01 — LDH Mois 2 scripts drafted + script-framework Layer 5 rewritten (Code)

First session run under the formalized session-handoff ritual. Pickup prompt from previous session bootstrapped this one cold, all 3 must-do items closed in one session.

  1. Hook framework Layer 5 rewrite. _ops/methodology/script-framework.md Layer 5 expanded from "include 3 variations" to a full Primary/Secondary/Wildcard role system. Added: topic-shape → primary-category mapping table, Secondary pairing logic (avoid same-lever pairs), Wildcard selection patterns, justification format with mandatory Why lines, re-cut LDH M1-V1 example documenting the override case (Mois 1 led with Information Gap on a topic shape that says Reverse Logic — override justified by cold audience). Frames the 3-variation system as interpretable, not rigid.

  2. 10 Mois 2 video scripts. clients/les-dames-des-hypotheques/projects/2026-05-mois-2/scripts.md Section 2. V1–V10 each with 3-variation hook + Why lines, interest peak, body, CTA. Voice respects brief Pass 1 (Diana posée vs Tatiana posée vs duo, who-leads). Real numbers used (versements aux 2 semaines = 1 paiement extra/an = ~3y amortization shaved + ~$25-30K interest saved on 400K @ 5%; 30y vs 25y = ~$75-100K interest delta on assured first-time buyer; RAP 60K post-2024; ABD 39%/ATD 44%; CELIAPP 8K/y, 40K lifetime; ~60% of CDN mortgages renewing 2025-2026). DM keywords (QUALIFICATION, DOSSIER, PRÉ-APPRO) routed to human conversation per brief. V9 written under engagement-DR brief: Reverse Logic primary on engineered industry stereotype (quote-back), Personal Story secondary (sister-talking-to-sister), Information Gap wildcard. Body uses 5 situational beats including Tatiana's immigrant-femme double layer.

  3. 4 Mois 2 carousel scripts. scripts.md Section 3. C1 (Renouvellement 5 étapes, 7 slides, DM RENOUVELLEMENT), C2 (Frais de clôture cachés, 8 slides, no DM, reveal pattern with stacking dollar figures, total ~$7-11K on 425K purchase), C3 (Aides 2026 CELIAPP+RAP combo, 7 slides, DM CELIAPP, 100K combo punchline), C4 (Mur 300B$, 7 slides, DM RENOUVELLEMENT, "et toi?" anchor every slide). Each carousel: 3 hook variations for Slide 1, slide-by-slide copy, full IG caption.

Em-dash compliance. First draft used 49 em dashes (headers, hook variation labels, narrative). Cleanup pass: hook labels became A. Primary [X], headers became ### VIDÉO N. Title, narrative em dashes replaced or restructured. Only remaining em dash is the literal character reference inside the rule reminder at file bottom.

Brief.md status updated: hook framework + scripts checkboxes flipped to done. Files table updated with scripts.md description. Pass 2 (creative direction), calendar.md, production scheduling remain.

Pickup for next LDH session: Pass 2 creative direction per post (props, in-camera, pattern interrupts), calendar.md with IG video captions (carousel captions already in scripts.md), production scheduling with SpeakUp.

Validation point for handoff ritual. First session bootstrapped from a copy-pasted handoff prompt with no chat reconstruction. The prompt named the pickup order, must-do vs heavy items, files to read in order, and Pandora items to surface. Worked as designed. Worth keeping as the standard wrap pattern.

#2026-05-01 — LDH Mois 2 brief locked + handoff ritual formalized (Code)

Continuation of the LDH thread, same day as the recovery session below. All Mois 2 must-do items closed: V8 drop + V9=A locks re-confirmed (with distribution math push-back fixing a self-contradicting Ed 9 / DC 2 lock vs 1-DC-slot table), 4 lead magnet PDFs processed and mapping verified (2 fixes: C3 → DM CELIAPP, V4 → human convo), M2-V6 + M2-C2 finalized (Nouvel arrivant DC + Frais de clôture Ed). Brief on disk at clients/les-dames-des-hypotheques/projects/2026-05-mois-2/brief.md (v2 lean, v1 kept as brief-v1.md). Full state in project_ldh.md.

Methodology insight that emerged: creative direction is two passes. Pass 1 (concept) upstream of scripting, Pass 2 (execution craft) downstream. Pass 1 has documenting mode (most posts) and generating mode (gimmick-driven only). Engagement-DR toolkit splits across stages (strategy/script/Pass 2). Applied to Mois 2 brief, methodology files still need own dedicated session.

Workspace rule shipped: wrap-up ritual formalized in CLAUDE.md > Session hygiene. Step 7 is now "generate session handoff prompt" with full template. Goal: next session bootstraps cold via copy-pasted prompt, no chat reconstruction.

Skill registry finding: infsh-skills/skills@ai-image-generation (202K installs) is the install path for an image-gen skill. Pandora item: wrap it as skills/visual-ref/ for brief Pass 2 input handoff to editors.

Cleanup: _ingest/bricked-ldh/ (510MB transcript dump) deleted at session end — handover fully absorbed into project_ldh.md.

#2026-05-01 — LDH session recovery + Session hygiene framework (Cowork)

LDH bricked-session recovery. The 2026-04-30 LDH session continued past the stories work into Mois 2 feed planning, then bricked at 32MB on 2026-05-01 03:24 (PDF uploads pushed cumulative context past the request limit). This session recovered the dead transcript via jq streaming over the 510MB JSONL dump, extracted state into _ops/recovery/HANDOVER-LDH-2026-05-01.md, then promoted durable locks into project_ldh.md Mois 2 session log entry. See project_ldh.md for canonical Mois 2 state.

Mois 2 feed locks recovered: G1-G5 strategic decisions, 14-post topic table, Pin/Profile/Lead Gen tag assignments, distribution Ed 9 / DC 2 / NH 1 / VC 1 / M 1, V8 dropped, V9=A locked. Open: M2-V6 + M2-C2 topics, lead magnet PDF processing, V8/V9 re-confirmation (decided in unanswered final message).

Session hygiene framework shipped (workspace-wide): new section in CLAUDE.md (after "Memory system — write behavior"). Trigger thresholds (topic boundary, 2+ hours, 5+ Pandora's Box items, file uploads, 20+ file ops, context fatigue). Wrap-up ritual. Proactive surfacing rule. Pandora's Box added to MEMORY.md vocabulary. Goal: prevent the 2026-04-30 LDH brick failure mode.

New methodology threads opened (need scaffolding):

Hook framework update still owed: _ops/methodology/script-framework.md should get the 3-variation justification logic (Primary / Secondary / Wildcard with category mapping). Bricked Claude promised, never delivered. Logged in project_ldh.md Open decisions.

Cleanup: _ingest/bricked-ldh/ holds the 510MB transcript dump used for recovery. Safe to delete once handover is verified absorbed.

#2026-04-30 — LDH stories plan + methodology flags (Cowork session)

Built v1 stories plan for Les Dames des Hypothèques covering Apr 30 → May 13 + Mois 2 scaffold (May 14 → June 12). Saved to clients/les-dames-des-hypotheques/projects/2026-04-launch-batch/stories-plan.md — calendar view + bullet version for Content Studio brief import.

Methodology flags raised on stories-strategy-v1.md (in-file at top):

Workspace fix: projects/2026-04-launch-batch/calendar.md had wrong day labels. C4 moved May 9 → May 8 Fri; V2 moved May 12 → May 11 Mon.

Routing meta-discussion (deferred): Plankton should host stories production; strategy + methodology work upstream (Cowork or Code on workspace). Plankton needs build-time framework registry + runtime context-tag selector. Final decision deferred — Jason wants to think more; next move is to actually open social-manager-app/ and ground the recommendation in real code.

Skill candidate flagged: /draft-stories-from-framework {client-slug} is a strong candidate but premature. Hold until Plankton registry is settled and at least one more client uses the methodology.

Full state + open decisions: project_ldh.md.

#2026-04-30 — Library of Alexandria: full end-to-end voice capture confirmed

Short session — no new code beyond one bug fix. Focus was getting the iOS Back Tap → Library pipeline working live.

Bug fixed: indexer.js embed UNIQUE constraint error on re-index. sqlite-vec vec0 tables don't support INSERT OR REPLACE — changed upsertVec to deleteVec + insertVec (delete-before-insert).

iOS Shortcut built and tested: Record Audio → POST to http://100.72.220.52:5175/api/library/capture (form body, field audio). Back Tap double-tap assigned on Jason's iPhone.

Two live captures confirmed:

  1. Mic test — confidence 0.11, escalated to Sonnet, staged with alternatives. Correct.
  2. Real note — confidence 0.88, auto-executed, routed to library as self-contained entry. Transcript, paragraph_timestamps, routing trail, and search index all written correctly.

Server startup note: library server must be running for Back Tap to work. Currently manual (cd library-app && npm run dev). Launchd auto-start service is the first task next session.

Next: launchd server service → 1C + 1F frontend (blocked on Claude Design prototype).

#2026-04-29 — Library of Alexandria Phase 1 backend complete (1D + 1J)

Voice capture pipeline and Forge integration shipped. Phase 1 backend is now fully done. Only 1C (React frontend) and 1F (render pipeline) remain, both blocked on the Claude Design prototype.

1D — Voice capture + Whisper transcription:

1J — Forge integration:

Routes now live (were stubs):

package.json scripts updated: both dev and start now use --env-file=.env.

End-to-end test result: Groq transcribed test WAV correctly (returned word-level JSON), .whisper.json written, .md updated with transcript_status: done, paragraph_timestamps. Mnemosyne routing failed only because test input was a sine wave (Groq returned .) — correct behavior. GROQ_API_KEY was blank at first; user populated it during session.

Files touched:

library-app/src/utils/slug.js          — timestampPrefix fix (format + seconds)
library-app/src/transcribe/groq.js     — NEW
library-app/src/transcribe/paragraphs.js — NEW
library-app/src/transcribe/index.js    — NEW
library-app/src/routing/pending.js     — NEW
library-app/src/mnemosyne/forge.js     — NEW
library-app/src/capture/pipeline.js   — NEW
library-app/src/routes/library.js     — /capture + pending-routes endpoints implemented
library-app/package.json              — --env-file=.env added to dev + start scripts
auto-memory/project_library.md        — updated to reflect 1D/1J shipped, GROQ key note
auto-memory/MEMORY.md                 — index line updated
CLAUDE.md                             — library Status cell updated

Next: 1C + 1F (frontend + render) once Claude Design prototype arrives. Check claude-design/ at session start.

#2026-04-29 — Forge queue cleared (kanban + filter + edit + voice)

Five queued Forge items shipped in one session, all under the Chat Queue surface:

  1. Desktop Kanban redesignChatQueue.jsx rewritten. Mobile keeps the vertical sections; desktop renders three horizontal columns (In Progress / Queued / Done) with @dnd-kit/core drag between columns. Drop on started triggers the same copy-to-clipboard + status-change combo as the Start button. Drop on done / queued is plain status update. Compact card layout for desktop, original full-width row preserved for mobile.

  2. Default landing on QueueApp.jsx useState('grid')useState('queue'). Mobile bottom-nav already had Queue at position 1; no reorder needed.

  3. Non-app related-project options — new data/queue-projects.json (Workspace, Citadel, Alexandria, Cowork) + server/routes/queue-projects.js GET endpoint. Schema separate from apps (apps have tech/phase/apis/url; queue-projects only have id/name/color/scope). AddItemModal dropdown uses <optgroup> to split "Active builds" from "Other scopes". The merged projects array is the lookup for chips and clipboard text.

  4. Group/filter + bulk copy + edit-in-place — filter pill row above queue body, color-coded per project, only renders when distinctScopes > 1. When a filter is active, "Copy all" button bundles queued + started items into a single Claude Code paste (buildBulkClipboardText). AddItemModal refactored into unified ItemModal with optional editItem prop — POST when creating, PATCH when editing. Edit button visible on hover (desktop kanban) and inline in action row (mobile).

  5. Voice-to-text — Web Speech API (SpeechRecognition / webkitSpeechRecognition), zero infra, browser-native. Per-field mic button in ItemModal (title + context). Tap to start, tap to stop, transcript appends to the field on each pause. Graceful fallback when SpeechRecognition is missing (button hidden). Error message surfaces when mic permission is blocked or origin is insecure (Tailscale HTTP will hit this on Safari — separate problem).

Architectural choice for voice-to-text: built minimal Forge-only capture using browser-native API rather than deferring to Mnemosyne or building a separate transcription service. Reason: the queue text fields stay the canonical capture point; only the wiring layer between voice and the field gets replaced when Mnemosyne ships. No rework debt — Mnemosyne replaces the route into the field, not the field itself.

Architectural choice for non-app projects: new file rather than extending apps.json. Apps are products (tech/phase/apis); Workspace/Citadel/Alexandria/Cowork are scoping options. Force-fitting them into apps.json would pollute the apps schema and surface them in the Apps tab where they don't belong.

Files touched:

skill-dashboard/package.json                          — added @dnd-kit/core + sortable + utilities
skill-dashboard/src/components/ChatQueue.jsx          — full rewrite: kanban + filter + bulk copy + edit + voice
skill-dashboard/src/App.jsx                           — default view 'grid' → 'queue'
skill-dashboard/data/queue-projects.json              — NEW: 4 non-app scopes
skill-dashboard/server/routes/queue-projects.js       — NEW: GET endpoint
skill-dashboard/server/index.js                       — register queueProjects router
skill-dashboard/data/queue.jsonl                      — appended Kanban item; all 5 in-scope items now done
auto-memory/project_dashboard.md                      — session log
auto-memory/project_memory.md                         — this entry

Note: API server (PID 3536) was restarted to pick up the new queue-projects route. Frontend Vite hot-reloaded the JSX automatically.

Library of Alexandria phase 0 prep is next.

#2026-04-28 — Library of Alexandria architecture phase

Opus session, single long grilling pass. 36 architectural decisions locked, then four canonical planning docs written into _ops/library-of-alexandria/:

Key decisions: Library and auto-memory are separate corpora (Mnemosyne never writes auto-memory; cross-traffic via Forge Chat Queue with workspace tags). Streams + Documents primitives, file-per-Entry storage with year/month nesting, flat-by-type for Documents, ULIDs at file creation for internal refs. Hybrid render pipeline: headless Chromium for screen+PDF+HTML, Pandoc for DOCX. Mnemosyne is trigger-on-arrival with confirmation queue for ambiguous or destructive routes; Haiku default with Sonnet escalation. Read interface is atmospheric-with-spatial-flavor (Hall, Stacks, Provenance, Search). Stacks organize by content category not source. Search is hybrid keyword + semantic via SQLite FTS5 + sqlite-vec. Bootstrap classifies all existing content on day one with Provenance surfacing low-confidence classifications.

Cost envelope: ~$3.60/month at active use. Render pipeline is $0 marginal (Chromium local). Capture transport is hybrid PWA + iOS Shortcut bound to Back Tap on iPhone 14 Pro.

Pre-code artifacts required before Phase 1: design prototype from Claude Design, library-sources.json first draft, Mnemosyne eval set (~20 labeled voice note transcripts).

Standing reminder: switch from Opus to Sonnet at the start of Phase 1 build.

State summary: project_library.md. Full architectural reasoning: the four docs in _ops/library-of-alexandria/.

#2026-04-28 — Skill Dashboard: Chat Queue + mobile pass

Forge: Chat Queue tab shipped (data/queue.jsonl + /api/queue + ChatQueue.jsx + new tab). "Start" copies title + context to clipboard and moves item to In Progress — closes the loop from queued idea → paste into Claude Code session.

Mobile pass shipped (replaces tab bar overflow): bottom nav (Queue / Jobs / Apps / Memory / Systems), hamburger for builder tools (Skills / Analytics / Graph / Marketplace), 4 hardcoded localhost:5174 URLs replaced with relative /api/... (root cause of Apps + Systems being silently empty on phone), detail panels full-screen on mobile, Brain View tap-vs-hover with touch detection, touch-none on D3 SVGs to unblock pinch/drag, Apps grid single-column on mobile.

Build order revised mid-session — went Chat Queue → mobile pass → (next) Inline Notes per app, instead of spec's Chat Queue → Inline Notes → mobile pass. Reason: bottom-nav overflow made Queue physically unreachable on phone, defeating its primary use case.

Deferred: HTTPS, Brain tooltip touch placement, hybrid device handling, panel back-arrow polish.

Deeper detail and file list: project_dashboard.md.

#2026-04-25 — Gymnasio Phases 7 + 8 (Fuel + Mind pillars)

Fuel (Phase 7) — complete:

Mind (Phase 8) — complete:

Next: Phase 9 — Asclepius (AI layer). All three pillars now have data. See fitness-app/PROJECT_MEMORY.md.

#2026-04-25 — Skill Dashboard Phase 0 + memory pattern adoption

Skill hunt + install:

Skill dashboard Phase 0:

Memory pattern adoption:

IDE choice:

Next session (in Antigravity):


#Active project state files

FileThread
project_dashboard.mdSkill dashboard build
project_ldh.mdLDH (active — stories methodology + launch batch + Mois 2 scaffold)
(future) project_speakup_pipeline.mdSpeakUp pipeline build

Add a project_<thread>.md when a new thread becomes active and substantive enough to need its own doc.

#2026-05-11 — Library Daedalus rendering pass (SHIPPED)

Single session, all 4 scoped items closed. Architectural principle locked: one engine, every consumer.

  1. ✅ Rendering audit (_ops/library-of-alexandria/RENDERING_AUDIT.md) — only 3 genuine specializations (voice_note, deep_map, html_file); ~17 other doc shapes are all markdown + frontmatter.
  2. ✅ MarkdownRenderer hardening — heading anchors, smart link handling (internal SPA vs external+↗), code blocks with language label, mobile-responsive tables wrapped, GFM task lists with custom checkboxes, definition list extension, blockquote polish, kbd marks.
  3. ✅ FrontmatterStrip — composable header auto-detecting 6 shapes (status pill / phase chip / meta line / description / color swatches / font pair / tone quote / chip rows / phase-next). statusLabel wins over generated phase chip when both present.
  4. ✅ SSR parity via path C (pure-string twin) — deviation from literal renderToStaticMarkup() direction, sign-off taken mid-session. Extracted src/render/markdown.js + src/render/frontmatter.js + src/render/prose.css as shared modules. React components became 10-line wrappers; server renderHtml() calls the same functions + inlines the same CSS. Render parity gap CLOSED.

Files: NEW src/render/{markdown.js,frontmatter.js,prose.css} + audit doc. REWRITTEN client/src/renderers/{MarkdownRenderer,FrontmatterStrip}.jsx. MODIFIED app.css, ReadingView.jsx, src/routes/library.js.

Eyeball confirmed visible improvements: Polis Vision tables render polished (was "awful before"), Neji Jedda brand guide renders cleanly with proper table + bullet structure.

Known issue surfaced + logged: LDH brand guide source uses tab-separated columns, not markdown pipe-tables. Frontmatter strip works (colors/fonts/tone show); body renders as smushed paragraphs. Source cleanup task (~5 min) logged in project_library.md.

Three ReadingView UX gaps logged for next session: (1) breadcrumbs disappear when opening a doc, (2) Classify section shows for already-classified docs, (3) inline search bar wanted in stack views. All three logged in project_library.md.

Future-phase backlog logged for after current cleanup: third hierarchy layer (Houses → Clients → {client-slug} folders with flat-list toggle) + folder-scoped share tokens + internal: true fm flag for docs invisible to share recipients. Triggered by Neji Jedda onboarding — the user wants to send him one URL for his entire folder. Logged in project_library.md.