coord

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 4, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package coord implements the coordination layer of dibs: leases on file patterns, agent presence, broadcast notes, and the event journal.

All state is plain JSON files under the store's State dir. Nothing here runs in the background: expiry is evaluated lazily whenever state is read or mutated, so dibs needs no daemon.

Index

Constants

View Source
const (
	DefaultTTL = 30 * time.Minute
	MaxTTL     = 24 * time.Hour
)

Variables

This section is empty.

Functions

func AutoName

func AutoName(worktree string) string

AutoName derives a stable, human-friendly agent name from a worktree path. The same worktree always maps to the same name, so an agent working in ./wt-auth is "the same agent" across sessions without any configuration.

func Intersect

func Intersect(a, b string) bool

Intersect reports whether two normalized patterns can cover the same file.

func Normalize

func Normalize(p, repoRoot string) (string, error)

Normalize canonicalizes a claim pattern: slashes, absolute paths mapped into the repo, no escaping the repo, and directory-like literals expanded to "dir/**". A meta-free pattern stays literal only when it names an existing regular file; a directory — or a path that does not exist (yet, or in this worktree) — is claimed as its whole subtree, which errs on the conservative side. Note that "dir/**" also matches "dir" itself in doublestar semantics. repoRoot may be "" in contexts (like tests) with no filesystem to consult.

func NormalizePath added in v0.1.1

func NormalizePath(p, repoRoot string) (string, error)

NormalizePath canonicalizes a concrete filesystem path for conflict checking. Unlike Normalize it never reinterprets the path as a glob and never expands it — a path is data, not a pattern.

func PathCoveredBy added in v0.1.1

func PathCoveredBy(path, pattern string) bool

PathCoveredBy reports whether a concrete path is covered by a claim pattern. The path is matched literally: glob metacharacters in file names ("docs/[draft].md") have no special meaning.

func SanitizeName added in v0.1.1

func SanitizeName(s string) string

SanitizeName restricts an agent name to filesystem- and display-safe characters. Presence records are stored under the agent's name, so this is a safety boundary, not cosmetics.

Types

type AgentInfo

type AgentInfo struct {
	Name         string    `json:"name"`
	Worktree     string    `json:"worktree,omitempty"`
	Branch       string    `json:"branch,omitempty"`
	LastReason   string    `json:"last_reason,omitempty"`
	FirstSeen    time.Time `json:"first_seen"`
	LastSeen     time.Time `json:"last_seen"`
	LastNoteRead time.Time `json:"last_note_read,omitempty"`
}

AgentInfo is what dibs knows about one agent, updated as a side effect of every command that agent runs. There are no heartbeats: freshness is simply "when did it last do something".

type Conflict

type Conflict struct {
	Pattern string `json:"pattern"`
	Holder  Lease  `json:"holder"`
}

Conflict pairs a requested pattern (or checked path) with the foreign lease that covers it.

type Event

type Event struct {
	At      string         `json:"at"`
	Event   string         `json:"event"`
	Agent   string         `json:"agent"`
	Details map[string]any `json:"details,omitempty"`
}

Event is one line of the append-only journal: who did what, when. The journal is the answer to "what have the agents been doing?".

type Lease

type Lease struct {
	ID        string    `json:"id"`
	Agent     string    `json:"agent"`
	Patterns  []string  `json:"patterns"`
	Reason    string    `json:"reason,omitempty"`
	CreatedAt time.Time `json:"created_at"`
	ExpiresAt time.Time `json:"expires_at"`
	Renewals  int       `json:"renewals,omitempty"`
	Worktree  string    `json:"worktree,omitempty"`
	Branch    string    `json:"branch,omitempty"`
}

Lease is one agent's claim on a set of file patterns for a limited time.

func (Lease) ExpiresIn

func (l Lease) ExpiresIn(now time.Time) time.Duration

ExpiresIn returns the remaining lease time, floored at zero.

type Manager

type Manager struct {
	St    *store.Store
	Agent string
	// AutoIdentity is true when Agent was derived from the worktree path
	// rather than chosen explicitly. An auto identity means "I am this
	// worktree", which widens what counts as our own lease — see isSelf.
	AutoIdentity bool
	Now          func() time.Time
}

Manager performs coordination operations as one named agent.

func NewManager

func NewManager(st *store.Store, explicit string) *Manager

NewManager resolves the acting agent's identity and returns a manager. Identity precedence: explicit name (--agent) > DIBS_AGENT env > a stable name derived from the worktree path.

func (*Manager) ActiveLeases

func (m *Manager) ActiveLeases() ([]Lease, error)

ActiveLeases returns unexpired leases without mutating state.

func (*Manager) Agents

func (m *Manager) Agents() ([]AgentInfo, error)

Agents lists every agent seen recently, most recently active first.

func (*Manager) Check

func (m *Manager) Check(paths []string) ([]Conflict, error)

Check reports which of the given paths (repo-relative or absolute) are covered by another agent's active lease. Paths are matched literally — never parsed as globs — so file names containing glob metacharacters are handled correctly. Check never mutates state, so it is safe and fast to call from hooks on every file edit.

func (*Manager) Claim

func (m *Manager) Claim(patterns []string, reason string, ttl time.Duration) (*Lease, []Conflict, error)

Claim asks for a lease on patterns. It returns either the granted (or renewed) lease, or the list of conflicts that denied it.

func (*Manager) Journal

func (m *Manager) Journal(n int) ([]Event, error)

Journal returns the most recent n events, oldest first.

func (*Manager) MarkNotesRead

func (m *Manager) MarkNotesRead(seen []Note) error

MarkNotesRead advances this agent's read cursor to the newest note it actually saw — never to "now", which would silently swallow any note that lands between reading and acknowledging.

func (*Manager) Notes

func (m *Manager) Notes() ([]Note, error)

Notes returns all live notes, oldest first.

func (*Manager) PostNote

func (m *Manager) PostNote(msg string) (*Note, error)

PostNote broadcasts a message to every agent on this repository. The timestamp is assigned inside the lock, so a note can never be created in another agent's past (which would let a read cursor skip it).

func (*Manager) Release

func (m *Manager) Release(ids, patterns []string, all bool) ([]Lease, error)

Release drops leases held by this agent: all of them, by lease ID, or by exact pattern. It returns the leases that were released.

func (*Manager) Renew

func (m *Manager) Renew(ttl time.Duration) ([]Lease, error)

Renew extends every lease this agent holds by ttl from now.

func (*Manager) Touch

func (m *Manager) Touch()

Touch records activity for this agent; exported for commands that don't otherwise mutate state (status, mcp startup).

func (*Manager) UnreadNotes

func (m *Manager) UnreadNotes() ([]Note, error)

UnreadNotes returns notes from other agents newer than this agent's read cursor.

type Note

type Note struct {
	ID        string    `json:"id"`
	From      string    `json:"from"`
	Message   string    `json:"message"`
	CreatedAt time.Time `json:"created_at"`
}

Note is a small broadcast message between agents: "I changed the User schema — regenerate types before touching api/". Notes are the handoff mechanism; anything bigger belongs in a lesson or a commit message.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL