Documentation
¶
Overview ¶
Package coord is the shared multi-agent coordination DB — the "swarm brain". It lives at <main>/.spectackle/cache/coord.db and is shared by all spectackle processes (one per agent session) via WAL-mode SQLite.
It owns: the agent registry (heartbeats), scope leases, the global ID counters (item AND rule IDs — the only collision-free mint across worktrees), the swarm event log (realtime learnings: rejections, rules, drift), replay bookkeeping (applied event IDs), worktree records and the global integrate lock.
coord.db is unversioned but NOT knowledge: losing it loses only ephemeral coordination state. Counters are floor-seeded on every mint (max(stored, scan-derived floor)+1), so deletion can never regress IDs.
Index ¶
- func GenName() string
- func Overlaps(a, b string) bool
- type AgentRow
- type DB
- func (d *DB) After(after int64, limit int) ([]Event, error)
- func (d *DB) Agents() ([]AgentRow, error)
- func (d *DB) Applied(item string) (map[string]bool, error)
- func (d *DB) Blocked(paths []string, agentTTL time.Duration) (*Lease, error)
- func (d *DB) Claim(paths []string, item string, ttl, agentTTL time.Duration) (*Lease, error)
- func (d *DB) Close() error
- func (d *DB) Cursor() (int64, error)
- func (d *DB) DelWorktree(item string) error
- func (d *DB) Deregister() error
- func (d *DB) Emit(ev, ref, msg string) error
- func (d *DB) GetWorktree(item string) (Worktree, bool, error)
- func (d *DB) Heartbeat() error
- func (d *DB) Leases(agentTTL time.Duration) ([]Lease, error)
- func (d *DB) Lock(name string, ttl time.Duration) (bool, string, error)
- func (d *DB) LockIntegrate(ttl time.Duration) (bool, string, error)
- func (d *DB) MarkApplied(item string, eids []string) error
- func (d *DB) MaxSeq() (int64, error)
- func (d *DB) NextID(kind string, floor int) (int, error)
- func (d *DB) PutWorktree(w Worktree) error
- func (d *DB) RefreshLeases(ttl time.Duration) error
- func (d *DB) Release(paths []string) error
- func (d *DB) ReleaseItem(item string) error
- func (d *DB) SearchEvents(q string, kinds []string, k int) ([]Event, error)
- func (d *DB) SetActive(item, wtRoot string) error
- func (d *DB) SetCursor(c int64) error
- func (d *DB) Sweep(agentTTL time.Duration) ([]Lease, error)
- func (d *DB) Unlock(name string) error
- func (d *DB) UnlockIntegrate() error
- func (d *DB) WithLock(name string, fn func() error) error
- func (d *DB) Worktrees() ([]Worktree, error)
- type Event
- type Lease
- type Worktree
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type DB ¶
type DB struct {
Agent string
// contains filtered or unexported fields
}
DB wraps the shared coordination database for one agent.
func (*DB) After ¶
After returns up to limit events with seq > after, oldest first, skipping this agent's own events.
func (*DB) Claim ¶
Claim reserves the paths for this agent, all-or-nothing. A conflicting live foreign lease is returned instead of an error.
func (*DB) DelWorktree ¶
func (*DB) Deregister ¶
Deregister removes this agent's leases and registry row — the clean goodbye on server shutdown, so short-lived sessions never linger in the swarm view until the TTL sweep.
func (*DB) Heartbeat ¶
Heartbeat marks this agent alive; called by the tool gate. It is an upsert: an agent whose row was removed by a sibling's sweep (idle past agent_ttl) silently re-registers on its next call instead of heartbeating into a void.
func (*DB) Lock ¶ added in v0.2.0
Lock acquires a named lock row in the `locks` table. It is the one serialization primitive coord.db offers, generalized from what used to be a single hardcoded 'integrate' row: the schema was already generic (name is the primary key), only the caller ever picked one name. Returns (false, holder) when a live foreign lock blocks it; a lock whose ttl expired counts as free, so a holder that crashed mid-operation can never wedge the name forever — the next caller simply takes it.
Re-acquiring a name this same agent already holds extends its expiry instead of blocking (the WHERE clause only rejects a DIFFERENT agent's live row). That is deliberate, not an oversight: within one process, tool calls are already serialized by Server.mu (see mcpserver's gate), so this agent never actually contends with itself for the same name — the row only ever needs to repel OTHER processes. Treating it as reentrant avoids a self-deadlock if a future caller ever nests two locked calls under the same name from the same agent.
func (*DB) LockIntegrate ¶
LockIntegrate acquires the global integration lock (one submit merges at a time) — a thin, name-fixed caller of Lock, kept so the submit path (and its tests) are untouched by the generalization above. Returns (false, holder) when busy; a lock whose ttl expired counts as free (crashed integrator).
func (*DB) MarkApplied ¶
MarkApplied / Applied track replayed event IDs per worktree item.
func (*DB) NextID ¶
NextID atomically mints the next number for a counter kind ("item:P", "rule:CUDA-KRN"), never below floor+1 (floor = caller's file-scan max, so a deleted coord.db cannot regress IDs).
func (*DB) PutWorktree ¶
PutWorktree / GetWorktree / DelWorktree / Worktrees manage worktree records.
func (*DB) RefreshLeases ¶
RefreshLeases extends all own leases; called by the tool gate.
func (*DB) Release ¶
Release drops leases: the given paths, or all of this agent's when paths is nil. Only own leases are touched.
func (*DB) ReleaseItem ¶
ReleaseItem drops all leases bound to an item (any holder — used when aborting an orphaned worktree of a dead agent).
func (*DB) SearchEvents ¶
SearchEvents does a LIKE search over the swarm event log (unioned into find scope=rejection|history so sibling learnings surface pre-merge).
func (*DB) Sweep ¶
Sweep expires leases of agents whose heartbeat is older than agentTTL and emits an expire event per lease. Returns the expired leases.
func (*DB) UnlockIntegrate ¶
UnlockIntegrate releases the integration lock if held by this agent.
func (*DB) WithLock ¶ added in v0.2.0
WithLock runs fn while holding the named lock, and releases it on every exit path — including a panic in fn — via defer. A bare Lock/Unlock pair invites the missing-defer that reintroduces the exact class of bug this exists to close (an early return or panic between the two leaves the name held until its ttl lapses). Acquisition retries on a short jittered interval until it succeeds or writeLockAcquireTimeout elapses, at which point it returns an error naming the current holder instead of blocking forever — a stuck caller should fail loudly, not hang the agent that called it.
WithLock (via coord.DB) is the concrete implementation of workspace.Locker: item/spec/drift's writers call it through workspace.Root.Lock, a small interface workspace declares so those packages need not import coord directly — they persist bundle files, not swarm coordination.
type Event ¶
type Event struct {
Seq int64
T time.Time
Agent string
Ev string // reject|rule|drift|claim|release|start|submit|abort|expire|remap
Ref string
Msg string
}
Event is one swarm learning/coordination notice.