115 lines
6.6 KiB
Markdown
115 lines
6.6 KiB
Markdown
---
|
|
created: '2026-05-10'
|
|
path: Sources/Homelab
|
|
project: trellis-mcp
|
|
status: active
|
|
tags:
|
|
- mcp
|
|
- claude-code
|
|
- lovebug
|
|
type: project-plan
|
|
updated: '2026-05-10'
|
|
---
|
|
|
|
## Goal
|
|
|
|
Build an MCP server (`trellis`) that captures and resumes long-running threads of work across artificial conversation boundaries. The unit is a *thread* — a logical work effort that may span multiple chat sessions over days or weeks. Pause/resume verbs let you switch contexts without losing state.
|
|
|
|
Solves the "where exactly did we leave the Traefik debugging" problem. Memory is too lossy; chat history finds old conversations but doesn't restore working state. Trellis sits between them: synthesized state per thread, on demand.
|
|
|
|
## Locked Decisions
|
|
|
|
**Three-layer model** — keep these separate, none should swallow another's job:
|
|
- CLAUDE.md / LOVEBUG.md = instructions (how to behave)
|
|
- Trellis threads = record (where we are in the doing)
|
|
- Memory / vault = lessons and outcomes (what we learned, what we built)
|
|
|
|
**Naming** — `trellis`. Garden-themed, fits the brand world, metaphor maps cleanly (persistent structure things grow on, you keep returning to it).
|
|
|
|
**Deployment** — separate MCP server, not folded into herby-dev. Different scope: herby-dev is your knowledge management, trellis is cross-cutting infrastructure usable from any agent context. Same deployment pattern as herby-dev: Cloudflare Tunnel, FastMCP, Authentik in front. Hostname `trellis.herbylab.dev`.
|
|
|
|
**Storage** — Postgres on the existing instance. Database `trellis`, schema `trellis`. Schema namespace makes future consolidation into a single database trivial.
|
|
|
|
**Schema shape** — four tables, append-only events log:
|
|
- `threads` — one row per named thread (slug, topic, goal, status, parent_id for forks)
|
|
- `tags` — separate table with DB-level normalization (lowercase, dash-separated, regex-checked)
|
|
- `thread_tags` — join table
|
|
- `events` — append-only log (started, checkpoint, status_change, fork, metadata_change)
|
|
|
|
Checkpoint payload is freeform markdown. The agent synthesizes whatever shape fits the thread (current state, decisions, open questions, next steps) — structure not enforced at the DB level.
|
|
|
|
**Tool surface (v1)** — seven tools, all suffixed with `_thread`:
|
|
- `start_thread` — creates row, writes `started` event
|
|
- `pause_thread` — writes `checkpoint` event, requires state payload
|
|
- `resume_thread` — reads thread + latest checkpoint (no write)
|
|
- `get_thread` — read-only inspection, optional full event history
|
|
- `list_threads` — filtered summary view
|
|
- `fork_thread` — new thread row with parent_id, fork event on parent
|
|
- `update_thread` — mutates thread fields, writes metadata_change/status_change event
|
|
|
|
**Lifecycle is prompt-driven** — system does nothing autonomously. No background jobs, no auto-abandon, no reminders. Threads exist and persist until you explicitly act on them.
|
|
|
|
**Active context lives in the harness, not the DB** — pause is a signal to the harness ("save and switch"); the DB just stores the trail. One active thread at a time in any given chat session is the harness's concern; the DB doesn't care how many threads are in flight.
|
|
|
|
## Open Items
|
|
|
|
- [ ] Postgres deployment shape — LXC vs Docker, fresh instance vs reusing existing
|
|
- [ ] Migration tooling — Alembic, plain SQL files, or simpler
|
|
- [ ] Tunnel + Authentik setup for `trellis.herbylab.dev` (parallels herby-dev work)
|
|
- [ ] Server framework — presumably FastMCP + Python to match herby-dev, confirm at build time
|
|
- [ ] First-run question: when trellis is operational, the trellis build itself becomes the first thread; paste design state from this project plan as the initial checkpoint
|
|
|
|
## Phases
|
|
|
|
### Phase 1 — Infrastructure
|
|
|
|
- [ ] Postgres instance available with `trellis` database and `trellis` schema
|
|
- [ ] Cloudflare Tunnel hostname `trellis.herbylab.dev`
|
|
- [ ] Authentik application + provider for trellis
|
|
- [ ] Repo `trellis-mcp` scaffolded
|
|
|
|
### Phase 2 — Schema and migrations
|
|
|
|
- [ ] Apply v1 schema (threads, tags, thread_tags, events)
|
|
- [ ] Verify CHECK constraints (status enum, tag normalization regex)
|
|
- [ ] Verify GIN/btree indexes resolve the resume-by-slug hot path
|
|
|
|
### Phase 3 — Tool implementation
|
|
|
|
- [ ] `start_thread`, `pause_thread`, `resume_thread` (the core loop)
|
|
- [ ] `get_thread`, `list_threads` (read paths)
|
|
- [ ] `fork_thread`, `update_thread` (mutation paths)
|
|
- [ ] Tag normalization in tool layer with clear errors before DB constraint fires
|
|
|
|
### Phase 4 — Wire-up and first use
|
|
|
|
- [ ] Connect from desktop Claude, mobile Claude, Claude Code, Lovebug
|
|
- [ ] Bootstrap: file the trellis build itself as the first thread
|
|
- [ ] Iterate based on real use — payload shape, missing affordances, etc.
|
|
|
|
## Notes
|
|
|
|
**Deferred to v2:**
|
|
|
|
- Multi-agent / non-Claude support
|
|
- Auto-thread for unnamed conversations
|
|
- Auto-status changes (abandon after N days, surfacing stale threads, etc.)
|
|
- Read patterns beyond resume-by-name: date ranges, full-text search, decision timelines, fork trees
|
|
- Fork merging
|
|
- Soft delete / archival
|
|
- Tag metadata (description, color)
|
|
- Transcript path as a real column (Claude Code transcripts at `~/.claude/projects/`)
|
|
- A `resumed` event kind if telemetry on resumes proves useful
|
|
|
|
**Design principles that drove the shape:**
|
|
|
|
- *Append-only in spirit* — historical information isn't adjusted, only added to. Even fields that look mutable (current state, next steps) are superseded by newer events rather than rewritten. The thread row reflects current state; events tell you how it got there.
|
|
- *Coarse event grain* — about session-level state ("we paused here, this is what we knew"), not per-interaction ("decision added"). The unit is the checkpoint, not the keystroke.
|
|
- *Pause = save-and-switch action, not a status* — every thread that isn't actively being worked on is implicitly paused. No separate "paused" status needed.
|
|
- *Trigger is naming* — short topical Q&A doesn't need a thread. Lifting to trellis happens when you explicitly say "start a thread called X."
|
|
|
|
**Schema-namespacing rationale** — putting trellis tables in a `trellis` schema (even inside its own database) costs nothing now and makes any future merge into another database a no-op. Connection sets `search_path` so queries don't qualify table names.
|
|
|
|
**Why two MCPs instead of one** — herby-dev is your knowledge management, scoped to your homelab. Trellis is cross-cutting infrastructure usable from any agent context. Folding them couples unrelated concerns; deployment overhead of a second MCP is low given herby-dev established the pattern.
|
|
|
|
**Why separate tags table** — preference for normalization upfront. Array column would work for v1 but you know you'll end up at a join table eventually, so start there. |