sea-lite
Integrates with Git repositories through a pre-commit guard that blocks commits staging files inside another agent's live claim, and through worktree-bound claims that are released when the worktree is removed.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
sea-lite
A work queue for parallel coding agents that can't collide.
Run three agents against one backlog and the failure mode is not that they are slow. It is that two of them pick up the same ticket, both "finish" it, and the one that finishes second overwrites the first. Or one of them dies holding a ticket and nobody else ever touches it.
sea-lite is a small MCP server where tickets are fenced:
sea_nextatomically picks the best eligible ticket and claims it. The caller gets a one-time claim token; every write (sea_update,sea_transition,sea_link) must present it. A write from anyone else is refused and says who holds the ticket and until when.Claims are leases (default 15 min, up to 1 h) that renew while the holder is active: every sea-lite tool call by the holder, and the
sea-lite heartbeata hook runs, push the expiry out again. An agent that dies stops renewing; the next reader sees the lapsed lease, treats the ticket as free, and records that it did. No sweeper, no cron.A claim can carry a scope: the paths the holder will edit. Two holders' live scopes may not overlap (
scope_conflictnames the holder, ticket, paths and expiry), andsea_scope_checklets an edit hook refuse a write inside someone else's scope. A holder is an actor label plus a session, so two Claude Code terminals that both run--actor claudeare still two holders (see Identity). The numbers that motivated it: PR pairs from different agents conflicted 41.7% of the time, pairs from one agent 19.8% (arXiv 2607.04697) — agents could lock tickets but not each other's files.Enforcement outside the model: an edit hook for Claude Code, and a git pre-commit guard (
sea-lite precommit --install) that refuses a commit staging files inside someone else's live claim, which works the same for Cursor, Codex, Copilot and humans.Tickets belong to the project (git repository) they were created in, so one shared store serves many repositories without one repo's queue or locks leaking into another.
Tickets carry typed links (
depends_on,blocks,parent_of, …).sea_nextwill not hand out a ticket whose predecessors are still open, and the precedence graph is kept acyclic on every write.sea_applylays down up to 50 tickets and 100 links in one all-or-nothing write, so an epic with its children and dependency edges lands as a unit or not at all — and its links may point at tickets that already exist. Templates let the model write a 20-ticket chain once (for_each+{i}/{value}/{ref}/{prev}); the server expands it deterministically. The result is a ref → id map, not an echo.Lean on context:
serve --corepublishes the nine day-to-day tools in ~12 KB oftools/list(the full fifteen take ~32 KB; 0.4.0 took 59 KB), and results are compact JSON.sea_finishends work on a ticket — an outcome (done/blocked/abandoned), a note, an optional commit sha, claim released — in one call, for one ticket or many.A claim can be bound to a git worktree; removing the worktree (
sea-lite release-worktree, aWorktreeRemovehook) releases it.Every change is an event on a hash chain — the one kronicle-lite keeps. The same SQLite file holds both.
sea_historyshows a ticket's record and whether the chain still verifies;sea-lite rebuildreplays the tables from the chain.
One process, one file, no accounts. Speaks MCP 2026-07-28 (per-request
metadata, server/discover, cacheable tools/list, outputSchema +
structuredContent on every tool, multi round-trip confirmation) and still
serves 2025-era clients that open with initialize, over stdio and over
HTTP — the same process answers both. Runs over stdio next to Claude Code, Cursor, Codex, Copilot,
Claude Desktop or any MCP client, or over Streamable HTTP
(serve --http, loopback, bearer tokens, one token per actor if you want
attributable claims). sea_stats / sea-lite stats account for who held
what for how long; sea-lite doctor checks the install. Several server processes (one per agent,
or one shared) can point at the same file; SQLite's write lock and
BEGIN IMMEDIATE make claims exclusive across processes.
Install
Requires Node ≥ 20. Data lives in ~/.kronicle-lite/kronicle-lite.db (or
--data-dir, or $KRONICLE_LITE_DATA_DIR), shared with kronicle-lite if
you run that too. One store serves every repository: tickets are keyed by
project. The --actor label is what humans see on the board; you do
not need a different label per terminal — each server process is its
own session (see Identity).
Claude Code
claude mcp add sea-lite -- npx -y sea-lite serve --core --actor claude--core serves the tools an agent uses day to day (see
Profiles); drop it for all fifteen.
Each Claude Code session's server picks up CLAUDE_CODE_SESSION_ID and
CLAUDE_PROJECT_DIR, so two sessions in one repo are two holders and
their queue is that repo's. Copy skills/work-queue/ into
.claude/skills/work-queue/ so the agent knows the claim → scope → work →
release loop, wire the edit hook from hooks/README.md (or install the
cc-anchor plugin, which ships it) so an Edit/Write inside someone
else's scope is blocked before it happens, and add the git guard:
npx sea-lite precommit --install # .git/hooks/pre-commitHeartbeat. sea-lite renews a holder's leases on every sea-lite tool call
it makes, which covers an agent that keeps using the queue. A long stretch of
plain edits and test runs makes no sea-lite call, so also wire a
PostToolUse heartbeat: cc-anchor's heartbeat hook is the recommended
one (it renews your claims as you work, rate-limited, in the background),
or sea-lite heartbeat --hook from hooks/README.md. Measured
(agent-memory-bench S13, lease 5 s, task 12 s): without a hook the lease
lapses mid-task and the holder learns it only at its next fenced write; with
cc-anchor's heartbeat the claim held 3/3.
Cursor
.cursor/mcp.json in the project (or ~/.cursor/mcp.json for everywhere):
{
"mcpServers": {
"sea-lite": {
"type": "stdio",
"command": "npx",
"args": ["-y", "sea-lite", "serve", "--actor", "cursor"],
"env": { "KRONICLE_LITE_DATA_DIR": "${userHome}/.kronicle-lite" }
}
}
}Cursor asks before running MCP tools unless you allowlist them; the
read-only ones (sea_get, sea_list, sea_history, sea_scope_check,
sea_stats) are safe to allow. Put skills/work-queue/SKILL.md into a project rule so
the agent claims its paths before editing.
Codex (CLI, IDE extension, app)
~/.codex/config.toml (or .codex/config.toml in a trusted project):
[mcp_servers.sea_lite]
command = "npx"
args = ["-y", "sea-lite", "serve", "--actor", "codex"]
env_vars = ["KRONICLE_LITE_DATA_DIR"]
startup_timeout_sec = 20
default_tools_approval_mode = "writes" # prompt only on write tools
[mcp_servers.sea_lite.tools.sea_transition]
approval_mode = "prompt" # terminal states are irreversible
[mcp_servers.sea_lite.tools.sea_finish]
approval_mode = "prompt" # closes tickets (terminal, no exit)Codex reads the server instructions; the loop is in them.
GitHub Copilot coding agent
Repository Settings → Copilot → MCP servers, "MCP configuration". The
coding agent runs in a fresh Actions sandbox, so point it at a store the
run can reach, and allowlist tools explicitly: GitHub recommends read-only
tools, and Copilot code review only loads tools whose
annotations.readOnlyHint is true. Ours that qualify: sea_get,
sea_list, sea_history, sea_scope_check, sea_stats.
{
"mcpServers": {
"sea-lite": {
"type": "local",
"command": "npx",
"args": ["-y", "sea-lite", "serve", "--actor", "copilot", "--data-dir", "/tmp/sea-lite"],
"env": { "SEA_LITE_ROLE": "agent" },
"tools": ["sea_get", "sea_list", "sea_history", "sea_scope_check", "sea_stats"]
}
}
}Once a server is configured Copilot calls its tools without asking, so add
the write tools (sea_create, sea_apply, sea_claim, sea_next,
sea_update, sea_transition, sea_finish, sea_link, sea_refresh,
sea_release)
only if you want the agent taking and closing tickets on its own. Secrets
and variables for the env block must be named COPILOT_MCP_*.
Any other client
{ "mcpServers": { "sea-lite": { "command": "npx", "args": ["-y", "sea-lite", "serve", "--actor", "me"] } } }A 2026-07-28 client probes with server/discover; a 2025 client sends
initialize; both are served.
Over HTTP (serve --http)
For a client that cannot spawn a process, or several agents sharing one queue server:
npx sea-lite serve --http --actor owner # http://127.0.0.1:7418/mcp
npx sea-lite add-token --actor agent-a # prints a token once; stores its sha256
npx sea-lite add-token --actor agent-b{ "mcpServers": { "sea-lite": { "type": "http", "url": "http://127.0.0.1:7418/mcp",
"headers": { "Authorization": "Bearer <agent-a's token>" } } } }Flag | Default | |
|
| kronicle-lite's |
|
| the shared owner token (same file kronicle-lite uses); a token file group or others can read is refused unless |
|
| per-actor tokens from |
| loopback only | DNS-rebinding defence; add the names clients use |
|
| serve 2025-era |
|
| the project this server's queue belongs to |
Identity per request. The shared bearer acts as
--actor(role--role), and a per-callactor_idis a self-asserted label, as on stdio. An actor token acts as its actor (and its entry'srole); anactor_idnaming anyone else is refused withforbidden. So claims, notes, chain events andsea_statsare attributable per token.Both protocol eras, stateless. POST to one endpoint; no session id;
GET/DELETE→ 405. 2026-07-28 clients send per-request_meta; 2025-era clients (Cursor today) open withinitializeand are served by the SDK's stateless legacy fallback from the same tools and the same per-request identity.--legacy rejectmakes the endpoint modern-only (initialize→ 400 /-32022). Missing or wrong bearer → 401; foreignOriginorHost→ 403.Projects. A team server sees every project unless started with
--project KEY(scopes are repo-relative, so run one server per repository or name it).One trust domain. Every token reaches the whole store; there are no per-ticket permissions, no read isolation, no TLS. Off-box, put TLS in front. Read
docs/THREAT-MODEL.md→ "HTTP transport" before exposing it.
Related MCP server: Pursers
Sixty-second tour
No MCP client and no LLM needed: the CLI drives the same queue the agents use. Every line below is run by the test suite against a fresh store.
npm i -g sea-lite # or: alias sea-lite='npx -y sea-lite'
export KRONICLE_LITE_DATA_DIR=$(mktemp -d) # a scratch store
cd "$(mktemp -d)" && git init -q # any repository: tickets belong to itsea-lite create "Add rate limiting to login" --triaged
sea-lite create "Fix session expiry" --triaged
sea-lite next --paths src/auth --actor alice # alice takes the first ticket and locks src/auth
sea-lite next --paths src/auth/session.ts --actor bob # exit 1: refused, alice holds src/auth
sea-lite next --paths src/billing --actor bob # bob takes the other ticket instead
sea-lite board # who holds what, which paths, time left
sea-lite scope-check src/auth/login.ts --actor bob # exit 1: what an edit hook or pre-commit asks
sea-lite release --all --actor alice # alice is done; src/auth is free again
sea-lite scope-check src/auth/login.ts --actor bob # exit 0
sea-lite verify # every chain hash recomputedboard prints:
sea-lite board — project /tmp/tmp.BUtjgMu1sO; 2 open ticket(s); 02:45:16Z
ID STATUS PRI TITLE HOLDER LOCKS LEASE
cecadce3 triaged medium Fix session expiry bob src/billing 15m00s left
a57e63b8 triaged medium Add rate limiting to login alice src/auth 14m59s leftAgents show up as claude#9b1d0c22 (actor#session); watch -n1 sea-lite board in a spare pane is the live view.
The agent's loop, in tool calls:
sea_next scope.paths=[src/handlers] → { ticket, claim_token, expires_at } (paths locked too)
sea_scope_check paths=[...] before touching a path you did not claim
sea_update (notes, tags) fenced by claim_token; any call renews your leases
sea_finish outcome=done note="…" resolved + claim and scope released, one call
— or —
sea_release note="where I stopped"Also: sea-lite list, show ID, stats --since 7d, rebuild,
doctor, whoami, heartbeat. sea-lite help lists everything.
Tools
Tool | What it does |
| One ticket ( |
| 1–50 tickets + ≤ 100 links, all-or-nothing. A link end is a batch |
| Ticket by id or ≥ 8-char prefix: fields, |
| Filters (status, kind, priority, assignee |
| Lease one or a set of tickets (all-or-nothing, locked in id order). Returns a token per ticket. Re-claiming your own ticket rotates the token. |
| Extend a lease to now + N (default: the claim's own lease, ≤ 3600); never shortens; holder-only. Not chained. Rarely needed: any sea-lite call by the holder renews its claims. |
| Holder gives the ticket back (with a hand-off |
| Title/body/kind/priority/assignee, tags add/remove, append a note. Fenced; |
| Move status. Fenced. Rejections carry |
| End your work in one call. Required |
|
|
| Pick + claim the highest-priority unclaimed |
| Events for one ticket, or a |
| Read-only: would editing these paths collide with someone else's live scope? |
| Read-only, per actor, derived from the chain: claims taken / rotated / released / expired / force-released, lease-seconds held, transitions, tickets created, live claims. |
Plus a sea://tickets/{id} resource (same shape as sea_get).
Every tool publishes an outputSchema and returns the same JSON as
structuredContent and as compact text. The published schemas are lean
(top-level result fields in full, nested objects as a field list such as
{id,kind,title,…}, no $schema or string-length noise); the server still
validates every argument and every result against the full schemas. Every error is { error: <code>, message, details } with a closed code set (fence_invalid, fence_foreign_holder,
fence_expired, already_claimed, scope_conflict, version_conflict,
illegal_transition, cycle, batch_invalid, confirmation_required,
confirmation_declined, …) so an agent can branch on it.
Profiles: core and full
tools/list is paid for in every session's context, so serve has two
profiles:
Profile | Tools |
|
| all fifteen | ~32 KB |
|
| ~12 KB |
core also gives shorter descriptions, does not advertise rarely-needed
inputs (actor_id, idempotency_key, expected_version, sea_next's
kind / tag filters, operator-only force, …; they are still accepted),
and publishes result schemas as field names and types only. The behaviour
of every tool is identical in both. serve --http --core works too.
core leaves out sea_create, sea_update, sea_link, sea_list,
sea_history and sea_stats, and its server instructions say so: to get
them, run serve without --core (or with --profile full /
SEA_LITE_PROFILE=full). The CLI (sea-lite list, show, stats)
covers the read side either way.
Templated batches
A template repeats one ticket, and its links, for each value of for_each
(an array of strings/numbers, or a count n meaning 1..n). In every string
of the template's ticket and links, and in its ref:
Placeholder | Becomes |
| the item's 1-based index |
| the |
| this item's expanded |
| the expanded |
Anything else in braces is left as written. Expansion is deterministic
(explicit tickets first, then each template's items in order), happens on
the server before validation, and the batch caps (50 tickets, 100 links),
cycle check and idempotency all apply to the expanded batch. dry_run: true
returns the expanded plan without writing.
Errors name exactly what failed. Each batch_invalid problem carries
where (tickets[2] (a), links[4], templates[0] item 3 (t03),
templates[0] item 3 (t03) links[1], claims[0]) plus the structured
template, item (1-based), ref and link indexes, and its message
starts with the same location. A cycle error gives the cycle as a path of
refs (existing tickets by id) and closed_by, the link that closes it.
Nothing is written when anything fails.
An epic and a 20-step migration chain, every step a child of the epic and each depending on the one before (21 tickets, 39 links), in one call:
{
"tickets": [{ "ref": "epic", "title": "Retire the v1 API", "kind": "epic" }],
"templates": [{
"for_each": ["users", "orders", "invoices", "…17 more"],
"ref": "m{i}",
"ticket": { "title": "Migrate endpoint /{value} to v2", "status": "triaged" },
"links": [
{ "from_ref": "epic", "to_ref": "{ref}", "link_type": "parent_of" },
{ "from_ref": "{ref}", "to_ref": "{prev}", "link_type": "depends_on" }
]
}],
"idempotency_key": "retire-v1-plan"
}Result: {"created":{"epic":"…","m1":"…",…,"m20":"…"},"links":39,"idempotent_replay":false}.
Re-sending it with the same idempotency_key replays that result
(idempotent_replay: true) instead of creating 21 more tickets. A key is
bound to its request: re-using it with a different batch is
invalid_input ("idempotency_key reused with a different request"), never
a replay of the first one — the same holds for every keyed tool.
Waiting for a claim (wait_seconds)
sea_claim and sea_next take wait_seconds (≤ 300; CLI --wait S).
Instead of failing with already_claimed / scope_conflict at once, the
call waits for the ticket or scope to free up and then claims it. The
result carries waited: {seconds, attempts, blocked_by: {kind, ticket_id, title, holder, holder_label, expires_at}, freed}, where freed is
released, finished (the holder closed the ticket), lease_expired or
changed. If it never frees up the call fails with wait_timeout, naming
the holder, ticket and expiry that still block it (CLI exit 1). sea_next
also waits when nothing is free but someone else holds work that could free
up (an eligible ticket, or a predecessor of one); an empty queue still
answers nothing_eligible at once. Refusals waiting cannot fix (unknown
ticket, bad input) fail at once.
How it waits, without hammering the store: nothing is locked while waiting.
A waiter retries only when something changed: another process committed
(SQLite PRAGMA data_version, one counter read, polled with a 20 → 250 ms
backoff), this process committed (an in-process notifier wakes it
immediately), or the blocking lease reached its expiry. A release in
another process is picked up within about 250 ms; in the same process,
immediately.
Client timeouts. A wait is one MCP request, so it must fit the client's
request timeout. The TypeScript SDK's default is 60 s; other clients
differ. When the client sends a progressToken, sea-lite sends a progress
notification every 5 s naming who it is waiting on, and a client that
resets its timeout on progress (resetTimeoutOnProgress in the TypeScript
SDK) will then sit through the whole wait. Otherwise keep wait_seconds
below your client's timeout. Cancelling the request ends the wait
(wait_cancelled).
Scopes: locking the files, not just the ticket
A ticket lock stops two agents from doing the same work. It does not stop them from editing the same file for different tickets — and that is where most cross-agent merge conflicts come from. So a claim can carry the paths its holder is going to touch:
sea_claim { ticket_ids: [id], scope: { paths: ["src/handlers", "docs/*.md"] } }An entry without glob characters is a prefix: the path and, when it is a directory, everything beneath it.
src/handlers/claims.tsis one file;src/handlersis the subtree;next.js/(trailing slash) says a dotted name is a directory. A git worktree or a package directory is a natural scope.An entry with
* ? [ ] { }is a glob (picomatch): exactly the paths it matches.*stays inside one segment,**crosses..is the whole repository.Two scopes overlap when any entry of one can name the same file as any entry of the other (
src↔src/**/*.ts,docs/x.md↔docs/*.md; notsrc↔src2, not*.ts↔*.md). The full rule is indocs/MODEL.md.Paths are resolved through symlinks (stdio
serve, the CLI, the hooks and the pre-commit guard know the repository): the longest existing prefix of an entry (the literal part before any glob) is replaced by its realpath, made repo-relative again.hlink/claims.ts, wherehlink → src/handlers, issrc/handlers/claims.tsto every claim and every check, and results show that form. A link that resolves outside the repository is refused (invalid_input,reason: "outside_repo").serve --httpserves many machines and keeps paths as written.Overlap with someone else's live, unexpired scope — another actor, or the same actor in another session — is refused with
scope_conflictlisting every holder, ticket, overlapping pair and expiry. Your own scopes never conflict with each other. Only claims of the same project are compared.The scope lives and dies with the claim: release, a terminal transition, or lease expiry frees it. It is on the chain (
sea_ticket.claimed), sosea-lite rebuildrestores it.sea_scope_check { paths }/sea-lite scope-checkis the fast path for a hook: one read, no claim. See Enforcement.Paths are repo-relative with
/; backslashes are accepted and normalized, so Windows agents and POSIX agents lock the same entries.
Worktree-bound claims
An agent working in a git worktree can bind its claim to it:
sea_next { scope: { paths: ["src/auth"], worktree: "/home/me/repo-wt-auth" } }worktree is an absolute path (normalized: C:\Repo\wt\ → c:/Repo/wt),
may come with or without paths (alone it locks no paths), and shows up
as claim.worktree in sea_get / sea_list. When the worktree is
removed, sea-lite release-worktree <path> — or the WorktreeRemove hook
in hooks/ (release-worktree --hook) — releases every live claim bound
to it, whoever holds it, chained as claim_released with
via: release_worktree. sea-lite doctor warns about live claims bound
to a worktree that no longer exists.
Identity: who holds a claim
A claim belongs to an actor (a label: claude, alice, agent-a)
and a session. Two claims are the same holder's only when both match.
Where | Actor | Session |
|
|
|
hooks and CLI commands |
| found, in order: the session key ( |
| the token's actor (per-actor token), or | none: one token is one holder |
library ( |
|
|
Every stdio server writes a small entry to <data dir>/sessions/
(0600: actor, session, pid, ancestor pids, project) and removes it on
exit; dead entries are pruned on read. That registry is how the
PreToolUse hook of a Claude Code session, which only knows the hook
input's session_id, finds the identity its own MCP server claims under —
including after /clear, when the hook's session id changes but the
server keeps the one it was spawned with (verified against the
Claude Code environment variable reference:
CLAUDE_CODE_SESSION_ID reaches hooks, Bash and stdio MCP servers;
CLAUDE_PID reaches hooks and Bash). A hook that gives only a session
speaks for every agent of that session (main agent and subagents).
sea-lite whoami shows what a shell resolves to; sea-lite board lists
the live servers. Labels are self-asserted on stdio and on the CLI:
this separates honest sessions, it does not authenticate anyone. The
authenticated path is a per-actor token over HTTP. See
docs/THREAT-MODEL.md.
Enforcement: what actually stops an edit
Layer | Stops | Misses |
| two holders locking overlapping paths | edits made without claiming |
Claude Code |
| anything done through the Bash tool ( |
| committing staged files inside someone else's live claim — for every client (Cursor, Codex, Copilot, humans), and catches the Bash edits above at commit time | uncommitted working-tree edits; |
Install the git guard per clone with sea-lite precommit --install (it
refuses to overwrite a pre-commit hook that is not its own; add
sea-lite precommit to yours). It resolves the committer like a hook
does: an agent committing through its Bash tool is recognised as its own
session, so its own claims never block it.
Accounting and health
sea_stats (MCP, read-only) and sea-lite stats [--since 24h|7d|ISO] [--for ACTOR] [--json] report, per actor: claims taken (and token
rotations, scoped claims), released by the holder, released by a terminal
transition, expired, force-released (and force releases issued as
operator), lease-seconds held, live claims, status transitions and tickets
created. Everything is derived from the chain plus the live projection, so
it costs no writes and gives the same answer after rebuild. Lease time
runs from each claimed event to whatever ended it (the recorded expiry
for a lapsed lease, which includes unchained refreshes) and is clipped to
the window. scope_conflict refusals are not chained, so they are not
counted. Over serve --http with actor tokens the actor column is tied to
a credential; on stdio it is the label each agent chose.
sea-lite doctor [--json] [--cwd DIR] [--actors-file F] is read-only (the
database is opened readonly; nothing is created or swept) and exits 1 if
any check fails: Node ≥ 20, data dir present and 0700, HTTP token files
0600 and well-formed, the database opens and passes quick_check,
sea_schema_version vs this build, the full chain verifies and every sea
row's chain_seq exists, claims (live; lapsed leases nobody swept for an
hour; claims on vanished worktrees), and the served tool catalog matches
the fingerprint pinned for this release.
Lifecycle
stateDiagram-v2
[*] --> idea
idea --> triaged
triaged --> in_progress
in_progress --> resolved
state holding {
parked
blocked
needs_decision
}
idea --> holding
triaged --> holding
in_progress --> holding
holding --> idea
holding --> triaged
holding --> in_progress
state terminal {
resolved
wont_fix
duplicate
dropped
merged
}
idea --> terminal
triaged --> terminal
in_progress --> terminal
holding --> terminal
terminal --> [*]Work track moves are one step forward at a time. Any active ticket may enter a
holding state or a terminal state; holding states resume only to idea,
triaged or in_progress; terminals have no exit. An optional design track
(--tracks work,design) adds idea → in_design → ready → in_progress.
Kinds: feature research investigation refactor curiosity question other bug chore incident security epic spike log docs decision. Priorities: urgent high medium low parked (parked is never dispatched by sea_next).
Link types: parent_of relates_to inspired_by responds_to conflicts_with supersedes blocks depends_on condenses_into branches_from references duplicates. Direction reads from <type> to.
Composes with kronicle-lite
sea-lite does not have its own chain. It opens the kronicle-lite store (or
adopts an already-open one) and appends sea_ticket.* / sea_link.* /
sea.batch_applied events to the same hash chain, inside the same
transaction as the row change. That buys you:
One
get_system_state. An agent that orients with kronicle-lite sees ticket creations, status changes and link changes in its delta. Routine claim churn (claimed,claim_released,claim_expired) rolls up by default so it does not crowd the briefing; a force release is enumerated.Retractions. A tombstoned link is classified as a safety retraction by kronicle-lite's classifier, like a tombstoned block.
One verify, one export.
kronicle-lite verify-chain,checkpointandexportcover sea events. Afterkronicle-lite import, runsea-lite rebuildto re-project the tables (import rebuilds documents only).Shared idempotency.
idempotency_keylands in the chain's unique column under asea:prefix; a replay returns the first result.
You can run sea-lite without ever running kronicle-lite's server. The dependency is the library.
Limitations (read these)
Cooperative fencing. A claim token stops a well-behaved agent from writing a ticket it does not hold. It does not stop a process with the SQLite file from editing rows directly. The chain makes that detectable (
sea-lite verify), not impossible.Self-asserted actors and sessions. On stdio, on the CLI and with the shared HTTP bearer,
--actor,--sessionand per-callactor_idare values the caller chooses. Sessions keep honest agents apart; they do not stop a process that lies. Per-actor HTTP tokens bind the actor to a credential, within one trust domain. Seedocs/THREAT-MODEL.md.The edit hook does not see Bash. See the enforcement table; the pre-commit guard is the backstop.
Lazy expiry. A lapsed lease is noticed by the next read or write that touches the ticket (or by
sea_list/sea_next, which sweep). Leases renew on activity; a holder that goes quiet for the whole lease (one build longer than 15 min with no tool call) loses it — claim with a longerlease_seconds(≤ 3600) for that.Legacy tickets created before 0.4.0 carry no project and stay visible in every project; claims taken before 0.4.0 carry no session (they lapse within 10 minutes of the upgrade).
One file, one trust domain. stdio, or loopback HTTP with bearer tokens; no TLS, no per-ticket permissions, no multi-tenant isolation.
Roadmap
See ROADMAP.md. Next up: scope-aware dispatch, bulk mutate.
Development
npm install
npm run build && npm test && npm run lint && npm run typecheck
npm run catalog:check # tools/list etc. must match .mcp-catalog/sea-lite.json byte for byteThe tool catalog is a reviewed artifact: .mcp-catalog/sea-lite.json is
the canonical snapshot (via mcp-catalog-snap)
and CI fails on drift. Changed a description or schema on purpose? Run
npm run catalog:snapshot, copy the new sha256 into
CATALOG_FINGERPRINT in src/catalog.ts (what doctor checks a
running build against; a test keeps the two equal), and commit the diff.
CI runs on Linux, macOS and Windows, Node 20 and 22.
License
Apache-2.0. See LICENSE and NOTICE.
Built off-grid in Cochise County, AZ — https://theexiledentrepreneur.com
This server cannot be deployed
Maintenance
Related MCP Connectors
Coordinate multiple AI agents over MCP: atomic claims, leases, shared ledger, handoffs, tasks.
Durable agent-to-agent handoffs and shared scratchpad for multi-agent workflows.
Cross-agent artifact workspace with provenance across Claude Code, Codex, Cursor, LangGraph.
Shared task queue for humans and AI agents: leases, handoffs, approvals and signed receipts.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables agents to coordinate through a shared SQLite authority, claiming and handing off work, posting notes, and reading a live board with proof-gated completion.5MIT
- AlicenseNot gradedqualityAmaintenanceLocal OS for your AI Agents fleets. ——————- Enables AI agents to coordinate through a durable local board with shared state, ticket lifecycle, evidence-based approvals, and journal-woken handoffs.2Apache 2.0
- AlicenseAqualityCmaintenanceEnables parallel AI coding agents to claim files atomically, detect and prevent workspace collisions, and receive deterministic zero-latency safety verdicts on destructive shell commands without any network egress. It also provides autonomous wave dispatch, worker recovery, and completion verification for multi-agent workflows via a shared coordination board.713 npmMIT
- AlicenseAqualityCmaintenanceEnables heterogeneous AI agent CLIs to coordinate via a shared SQLite-backed state bus with inter-agent messaging, shared knowledge, swarm/activity discovery, and file-level mutex locks, all without an external daemon.10MIT