wiki-vault/Sources/Homelab/trellis-mcp-tool-surface-followups.md

5.4 KiB

created path project tags type
2026-05-23 Sources/Homelab trellis-mcp-tool-surface-followups
mcp
claude-code
lovebug
project-plan

Goal

Make the Trellis MCP tool surface more ergonomic for in-session use without changing the underlying data model. Two changes:

  1. Rename pause_thread to checkpoint_thread so the verb matches the event it writes (and stops colliding with the paused status value).
  2. Add optional id parameter to all tools that take slug, so threads can be addressed by their integer ID during a session. Slug remains canonical; ID is a convenience handle.

Both changes are small, scoped server-side edits. No data migrations, no breaking changes if done with aliases.

Locked Decisions

  • Slug stays canonical. Names are durable, meaningful, survive migrations. IDs are database-implementation artifacts. The model is: slug for discovery and persistence, ID for session-scoped operation. Same pattern as ps vs kill <pid>.
  • ID stability is explicitly not a goal. IDs may not survive a restore or migration. That's fine — you're not going to remember 232 next week either. You'll discover the thread again via list_threads, see whatever ID it has now, and use that.
  • Rename via alias, not hard cutover. Add checkpoint_thread as the new canonical name, leave pause_thread as a deprecated alias that calls through. Drop the alias after a grace period (TBD — could be one trellis release, could be a calendar deadline).
  • No id-only tools. Every tool that gains id keeps slug. If both are passed, prefer id and warn on mismatch. If neither, error. This preserves slug-first workflows and adds id as additive.

Open Items

  • Decide grace period for pause_thread alias before removal
  • Confirm whether parent_id field in list_threads already returns the integer (it filters by it, but does it return it?) — affects whether list_threads needs response-shape changes
  • Decide whether start_thread and fork_thread should return the new thread's ID in their response payload (probably yes — otherwise you have to immediately get_thread to learn the ID)
  • Audit the database schema to confirm threads.id is the right field to expose (vs some other internal identifier)

Phases

Phase 1 — Rename pause_thread → checkpoint_thread

  • Add checkpoint_thread tool that takes the same args as pause_thread (slug, state) and writes the same checkpoint event
  • Leave pause_thread registered as a deprecated alias — same handler, optionally logs a deprecation warning
  • Update tool descriptions to reflect the rename
  • Update any internal documentation / README references

Phase 2 — Add id parameter to read/write tools

Tools to modify:

  • get_thread(slug, include_events)get_thread(slug?, id?, include_events)
  • checkpoint_thread(slug, state)checkpoint_thread(slug?, id?, state)
  • resume_thread(slug)resume_thread(slug?, id?)
  • update_thread(slug, ...)update_thread(slug?, id?, ...)
  • fork_thread(parent_slug, new_slug, ...)fork_thread(parent_slug?, parent_id?, new_slug, ...)

For each:

  • Make slug optional in the schema
  • Add optional id (integer)
  • Server-side: branch on which was provided; error if neither; warn if both disagree
  • Update tool descriptions

Phase 3 — Expose id in responses

  • start_thread response includes id
  • fork_thread response includes id of new child
  • get_thread response includes id
  • list_threads response includes id per row (confirm whether already true)

Phase 4 — Verification

  • In-session test: address a thread by integer ID end-to-end (start → checkpoint → resume) without typing the slug
  • In-session test: cross-chat handoff using ID ("can you pull thread 232")
  • Confirm pause_thread alias still works for any prior tooling that calls it

Notes

Naming context — why pause is wrong for the action:

The existing pause_thread tool writes a checkpoint event, not a status change. Per its own docstring: "the thread row is not changed except for updated_at." So the verb doesn't describe what's happening — checkpointing is happening; pausing is not.

Worse, there's a paused value in the status enum (active | paused | done | abandoned). So you have:

  • A paused status that means "this thread is on hold"
  • A pause_thread action that does not set that status

checkpoint_thread resolves the collision. Pausing-the-status remains a separate decision via update_thread(slug, status='paused').

ID lookup context — why this matters ergonomically:

In session usage, slugs are friction: long, must be re-typed or re-quoted, easy to mistype. Integers are zero-friction: pull thread 232, checkpoint 232, resume 232. The slug stays useful for first-discovery ("which thread was the traefik debugging one?") but once you're operating on it, the integer wins.

Pattern parallel: Linux processes. ps shows names for discovery; kill 4729 for operation. Names for finding, numbers for doing.

What's explicitly out of scope:

  • Changing slug semantics (still required at creation, still kebab-case, still the URL-safe identifier)
  • Migrating existing data
  • Changing the event log structure
  • Adding any new event types
  • The three other trellis follow-ups already tracked (retry/cleanup on embedding failure, semantic dedup before insert, revisit enricher pause-during-reflector)