Visual control room for Alec's agent memory system. Frontend for Firmament — the Supabase-backed personal memory layer that agents use through
personal-mcp.
Named for Odin's raven of memory.
Muninn makes the agent memory substrate visible, inspectable, and (eventually) curatable. The default view answers one question: what do agents currently know about me?
- Overview — Profile, active projects, recent sessions, recent memories, derived insights, and lightweight data-health signals (last memory/session, stale projects, totals)
- Memories — Browse, search, and filter the discrete facts agents have recorded (read-only in MVP)
- Sessions — Chronological feed of agent sessions with interface/machine filters
- Projects — Kanban board of projects agents orient themselves around (drag-and-drop, archiving, search)
- Insights — Derived patterns, trends, predictions, and connections produced by the reasoning pipeline
- Tools — AI subscription tracker (cost summary, renewal alerts) — secondary module
- Settings — Supabase connection status, theme toggle, version info
All data lives in your Firmament Supabase instance. Reads are live; the MVP intentionally avoids risky write flows for the new memory/insight tables.
| Layer | Choice |
|---|---|
| UI | React 19 + Vite |
| Styling | Tailwind CSS + HSL CSS variables |
| State | Zustand (devtools + persist) |
| Backend | Supabase (@supabase/supabase-js) |
| Drag & drop | @hello-pangea/dnd |
| Panels | react-resizable-panels |
| Icons | @phosphor-icons/react |
| Fonts | IBM Plex Sans + IBM Plex Mono |
| Router | React Router v7 |
| Tests | Vitest + Testing Library |
- Node.js 18+
- A Supabase project (the app uses anon key auth — no login required)
git clone https://github.com/alecvdp/muninn.git
cd muninn
npm installcp .env.example .envEdit .env with your Supabase credentials:
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key-here
Muninn reads from the existing Firmament tables: profile, projects, agent_sessions, memories, derived_insights, and tools. The schema is owned by personal-mcp. The migrations below only cover the columns Muninn itself adds (kanban state, archived flag, the tools table) — apply them only if you're starting fresh:
Projects table (add kanban columns):
alter table projects
add column if not exists board_status text default 'idea',
add column if not exists board_position integer default 0,
add column if not exists archived_at timestamptz;Tools table (new):
create table tools (
id uuid primary key default gen_random_uuid(),
name text not null,
category text not null default 'to-check-out',
cost numeric(10,2) default 0,
billing_cycle text,
renewal_date date,
platform text[] default '{}',
url text,
tags text[] default '{}',
notes text default '',
created_at timestamptz default now(),
updated_at timestamptz default now()
);
alter table tools enable row level security;
create policy "Allow all access" on tools for all using (true) with check (true);Enable realtime (for live sync):
alter publication supabase_realtime add table projects;
alter publication supabase_realtime add table tools;The profile, preferences, agent_sessions, memories, and derived_insights tables are managed by personal-mcp. Muninn reads from them but does not write — write/curation flows for memory data are intentionally deferred past MVP.
npm run devOpen http://localhost:5173.
| Command | What it does |
|---|---|
npm run dev |
Start dev server (Vite, port 5173) |
npm run build |
Type-check with tsc, then build for production |
npm run preview |
Preview the production build locally |
npm run lint |
Run ESLint |
npm test |
Run tests (Vitest, 135 tests) |
npm run test:watch |
Run tests in watch mode |
muninn/
├── src/
│ ├── components/
│ │ ├── agents/ # SessionFeed, SessionCard
│ │ ├── board/ # KanbanBoard, KanbanColumn, ProjectCard
│ │ ├── detail/ # ProjectDetail, ToolDetail, CreateProjectDetail
│ │ ├── layout/ # AppBar, Navbar, DetailPanel
│ │ ├── tools/ # ToolsGrid, ToolCard
│ │ └── ui/ # ErrorBoundary, ErrorToast
│ ├── lib/
│ │ ├── supabase.ts # Typed Supabase client
│ │ └── dates.ts # Date utilities (renewal checks)
│ ├── pages/
│ │ ├── OverviewPage.tsx # Profile + projects + sessions + memories + insights + health
│ │ ├── MemoriesPage.tsx # Memory list with search/filter/expand
│ │ ├── InsightsPage.tsx # Derived insights with type/confidence filters
│ │ ├── BoardPage.tsx # Kanban with search/filter/archive (mounted at /projects)
│ │ ├── ToolsPage.tsx # Tool grid with cost summary
│ │ ├── AgentsPage.tsx # Session feed with filters (mounted at /sessions)
│ │ ├── SettingsPage.tsx
│ │ └── NotFoundPage.tsx
│ ├── store/
│ │ ├── overview.ts # Aggregate fetch for the home dashboard
│ │ ├── memories.ts # Memory list with pagination + filters
│ │ ├── insights.ts # Derived insights with pagination + filters
│ │ ├── projects.ts # Projects CRUD, kanban state, realtime
│ │ ├── tools.ts # Tools CRUD, cost calculations, realtime
│ │ ├── sessions.ts # Sessions with pagination + server-side filters
│ │ └── ui.ts # Panel state, theme (persisted)
│ ├── types/
│ │ └── index.ts # Shared row/insert/update types
│ ├── database.types.ts # Generated Supabase schema types
│ ├── App.tsx # Layout shell (AppBar + Navbar + Outlet + DetailPanel)
│ ├── main.tsx # Router + ErrorBoundary
│ └── index.css # CSS variables, dark/light themes
├── supabase/
│ └── migrations/ # SQL migrations
├── docs/
│ └── screenshot.png
├── SPEC.md # Original design spec
├── .env.example
├── vite.config.ts
├── vitest.config.ts
├── tailwind.config.js
└── package.json
┌──────┬─────────────────────────────────────────────┐
│ │ Navbar (view title, theme toggle) │
│ App ├──────────────────────┬──────────────────────┤
│ Bar │ │ │
│ │ Main Content │ Detail Panel │
│ 48px │ (overview / mem / │ (440px, resizable, │
│ │ sess / proj / etc) │ opens on click) │
│ │ │ │
└──────┴──────────────────────┴──────────────────────┘
- AppBar — Icon rail on the left. Overview, Memories, Sessions, Projects, Insights, Tools, Settings.
- Navbar — Top bar with view title and theme toggle.
- Detail Panel — Slides in from the right when you click a card. Escape to close. Focus-trapped for accessibility.
The home view (/). A one-screen answer to "what do agents currently know?"
Sections:
- Profile card from the
profiletable (name, pronouns, location, timezone, communication style, context) - Active projects with stale-warning glyph for any active project that hasn't been touched in 60+ days
- Recent sessions (last 8) from
agent_sessions - Recent memories (last 8) from
memories(excludes superseded) - Recent insights (last 6) from
derived_insights(excludes superseded) - Health bar with totals and "last memory / last session" relative times
Read-only by design. Each section has a "View all →" link into the matching list page.
Browse, search, and filter the discrete facts agents have recorded (/memories).
- Server-side ILIKE search on
content - Filter by category, confidence, tag
- Click a row to expand inline (full content + tags + ids + provenance)
- Paginated (25 per page, "Load more")
- Read-only in MVP — promote/demote/edit flows come later
Chronological feed of agent sessions from agent_sessions (/sessions).
- Sessions grouped by date
- Paginated (25 per page, "Load more")
- Filter by interface (claude-code, claude.ai, amp, etc.)
- Filter by machine (midgard, mini-ygg, etc.)
- Server-side filtering (queries pushed to Supabase, not client-side)
Kanban board of projects (/projects) — the records agents read to orient themselves.
| Column | Status | Color |
|---|---|---|
| Idea | idea |
Blue |
| Todo | todo |
Yellow |
| In Progress | in-progress |
Orange |
| Paused | paused |
Gray |
| Done | done |
Green |
Features:
- Drag cards between columns to change status
- Reorder within columns (fractional positioning, handles filtered views)
- Search by name/description
- Filter by priority (P1–P5)
- Toggle archived projects visibility
- Click any card to edit in the detail panel
- Create new projects with the + button
Derived patterns, trends, predictions, and connections from derived_insights (/insights).
- Filter by
insight_type(pattern / trend / prediction / connection) - Filter by confidence (high / medium / low)
- Click a row to expand inline (full content + provenance counts)
- Excludes superseded insights
- Read-only in MVP
Track AI subscriptions and tools you're evaluating (/tools).
Summary stats bar at the top shows:
- Total monthly cost
- Total annual cost
- Active tool count
- Tools renewing within 30 days (highlighted)
Each tool card shows name, category badge (Using/To Check Out), cost, billing cycle, platform icons, renewal date, and tags.
Filters: Search by name, filter by category, filter by platform.
Dark and light themes via CSS variables. Toggle in the navbar or Settings page. Theme preference persists in localStorage.
Colors use HSL format for easy customization — edit src/index.css to adjust:
:root {
--brand: 25 82% 54%; /* Warm orange accent */
--bg-surface: 0 0% 13%; /* Main background */
--bg-muted: 0 0% 11%; /* Sidebar, panels */
--text-normal: 0 0% 77%; /* Body text */
}Kanban column colors and tool category badges use semantic CSS variables (--status-idea, --category-using, etc.) so themes stay consistent.
Projects and Tools use Supabase Realtime channels. Changes on one machine appear instantly on others — no refresh needed.
The subscription lifecycle uses a global registry pattern to survive Vite HMR without orphaning channels. Each store tracks subscriber count and only removes the channel when the last consumer unmounts.
Build and deploy as a static site:
npm run buildThe dist/ folder can go to Cloudflare Pages, Vercel, Netlify, GitHub Pages, or any static host. Set VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY as environment variables in your hosting platform.
App crashes on load with "Missing Supabase environment variables":
You need a .env file. Copy .env.example to .env and fill in your Supabase project URL and anon key.
Projects don't sync between tabs/machines:
Check that the supabase_realtime publication includes the projects table. Run:
alter publication supabase_realtime add table projects;Drag and drop feels janky after many reorders: Fractional positioning can accumulate precision issues over time. A future improvement would normalize positions periodically.
Build warns about chunk size:
The 660KB bundle is primarily @hello-pangea/dnd + Supabase client. Code splitting via React.lazy() is tracked as a future improvement.
Muninn's visual design and component architecture are heavily inspired by Vibe Kanban:
- Three-zone layout (AppBar + main + detail panel)
- Card styling with border overlap trick
- HSL color token system
- IBM Plex typography
- Phosphor icon set
Full design spec: SPEC.md
"Muninn and Huginn fly each day over the spacious earth. I fear for Huginn, that he come not back, yet more anxious am I for Muninn." — Odin
MIT License — Built for solo builders who ship.
