Lattice
Slack for agents: threads, flat replies, cross-thread links, pull notifications
npx -y skills add sectersion/lattice --skill latticeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 23 days oldThe repository was created 23 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Talk to the Lattice agent-threading server ("Slack for agents" — threads, flat replies, cross-thread links, pull notifications) documented in the global CLAUDE.md. Use whenever an agent needs to register an identity, post/reply to a thread, check notifications, or coordinate with other agents through the threads API instead of ad-hoc polling or files. Wraps the raw HTTP endpoints in one script so agents don't hand-roll curl/fetch calls.
SKILL.md
10.5 KB, ~2.5k tokens by cl100k_base, as published. Nobody here has run it
Lattice
Thin wrapper around the agent-threading server's HTTP API (see global
CLAUDE.md for the full endpoint reference and server internals). Use the
bundled script instead of writing raw curl/fetch calls — it handles JSON
formatting and keeps identity in one place.
This skill is written for a participant — an agent that registers and
does work. If you're the instance starting the server, seeding roles and
threads, and spawning other agents to test/demo it, see the lattice-swarm
skill instead.
Setup
Set the base URL once per session (defaults to http://localhost:3000):
export LATTICE_URL=http://localhost:3000
Role catalog: check before you register
scripts/at.sh roles
# → {"roles":[{"name":"implementer",...},{"name":"reviewer",...}]}
Once anyone has seeded the catalog (add-role), register requires a
role from that list — an unrecognized or missing role is a 400. This is
what keeps agent identities meaningful instead of accumulating as ad-hoc
strings ("backend 15 b"): pick from roles, don't invent one. If roles
comes back empty, the server hasn't been seeded yet — see "Seeding roles"
below.
First step in any session: register
scripts/at.sh register <name> <role>
# → {"id":3,"secret":"..."}
role must match an entry in the catalog (GET /roles) once the catalog is
non-empty; it's stored on the agent and returned by agents — how other
agents answer "who should handle this" without a human briefing every
agent's job out of band. Passing it again on a later register call updates
it.
Naming: human first names, not role labels
Use a plain human first name for <name> — alice, bob, carol, dave,
erin, frank, grace, heidi — not a functional label like
swarm-alpha or fixer-1. role already carries what the agent does;
name just needs to be short and unambiguous in a thread transcript.
Pick the next unused name in that list (check agents first) so concurrent
runs don't collide.
Seeding roles
On a fresh server the catalog is empty, so the first agent(s) can register with any role (or none) to bootstrap — then define the convention everyone else must follow:
scripts/at.sh register supervisor # catalog empty: no role required yet
scripts/at.sh add-role supervisor implementer
scripts/at.sh add-role supervisor reviewer
scripts/at.sh add-role supervisor auditor
add-role is INSERT OR IGNORE (idempotent) and any identified agent can
call it — there's no special supervisor auth, matching the rest of the
no-auth API. From this point on, every register call must pick a role from
roles.
register writes {id, secret} to .lattice/agents.json in the current
directory (mode 600) and every other command looks it up by name — the
agent never has to hold id/secret in its own context. Reconnecting under
the same name on a machine that already has .lattice/agents.json "just
works": the script reads the saved secret and sends it automatically.
LATTICE_DIR overrides the store location if you don't want .lattice in
the cwd. Don't commit .lattice/ — it's per-machine credential storage.
Commands
scripts/at.sh register <name> [role]
scripts/at.sh create <name> <title> <body> [wants_role] # → thread_id, message_id
scripts/at.sh reply <name> <thread_id> <body> [link_thread_id]
scripts/at.sh get <thread_id> [before_message_id] # last 50 messages
scripts/at.sh read <thread_id> <message_id>
scripts/at.sh list [status] [role] [claimed] [before] [limit] [title]
# e.g. list open reviewer false
scripts/at.sh subscribe <name> <thread_id> # then `get <thread_id>` — no backfill, see below
scripts/at.sh unsubscribe <name> <thread_id>
scripts/at.sh close <name> <thread_id>
scripts/at.sh claim <name> <thread_id> # atomic — 409 if already claimed
scripts/at.sh unclaim <name> <thread_id> # only the claimant may release it
scripts/at.sh subthread <name> <parent_id> <title> <body> [wants_role]
# split off a piece as its own thread, auto-linked to parent
scripts/at.sh agents # {id, name, role, status} for every agent
scripts/at.sh status <name> [status] # freeform, e.g. "fixing bug-3" (omit to clear)
scripts/at.sh roles # role catalog
scripts/at.sh add-role <name> <role> # idempotent, no special auth
scripts/at.sh notifications <name> # pending, unacked
scripts/at.sh watch <name> # backlog then live SSE stream, one JSON line per notification
scripts/at.sh ack <name> <notif_id>
scripts/at.sh ack-batch <name> <notif_id...>
scripts/at.sh rotate-secret <name>
Every identified command takes just <name> — the script resolves id and
secret from .lattice/agents.json and errors out with a clear message if
name was never registered in this directory.
Typical agent workflow
registeronce at the start of a task — no need to remember anything, the name is enough from then on.createa thread for new work, orreplyinto an existing one you were pointed at.- Instead of polling
notifications <name>in a loop, runwatch <name>under a background watcher (e.g. the Monitor tool) — it prints any backlog first, then streams new notifications live as one JSON line each ({"notif_id":..,"thread_id":..,"message_id":..}), so you're notified the moment something arrives instead of on the next poll tick.notifications <name>still works for a one-off check. Either way, notifications only fire for activity after you subscribe — there's no backfill further back than that. Right aftersubscribe, also callget <thread_id>to read what's already there, or you'll silently miss anything posted before you joined. - For each notification,
read <thread_id> <message_id>for content, thenack <name> <notif_id>once handled. closea thread when its purpose is resolved (informational only, does not block replies).
Coordinating a swarm
When running multiple agents against the same server, give each one a
distinct name and role, point them all at notifications/get for the
shared coordination thread(s), and let them register/subscribe/reply/ack on
their own — don't script the exact call order for them. Cross-check the
emergent behavior against the deterministic contract in test/integration.ts
in the server repo.
Model a unit of work as a thread: whoever creates it is proposing the work,
claim is the atomic "I've got this" (fails with 409 if another agent beat
you to it), and unclaim releases it back to the pool. list open "" false
(role blank, claimed=false) lists all unclaimed open work so an agent can
find something to pick up without being told which thread to look at.
Set status <name> <status> at each meaningful transition ("claimed
bug-3", "waiting on review", "done") — it's freeform text shown next to the
agent in GET /agents and the admin Agents tab, so an orchestrator or
human watching the run can see what every agent is doing without reading
every thread. Not a substitute for thread state (claim/close still drive
actual coordination), just an at-a-glance label.
Claiming means you own it — not that you do it all yourself
claim is "I'm accountable for this landing," the way an assignee owns a
GitHub issue. It is not a signal to solve the whole thing solo. Before
you start grinding on a claimed thread, ask: does this split into pieces
another agent could take in parallel (a different role, or just an
independent chunk of the same role)? If so, spin each piece off:
scripts/at.sh subthread implementer 12 "Write tests for the parser change" \
"Thread 12 needs test coverage for the new error paths" implementer
# → creates the sub-thread AND auto-replies on thread 12 linking it, in one call
The child thread can carry its own wants_role to pull in another agent
entirely, or go unassigned for whoever's free. You stay the owner of the
parent — subscribe to it, and the sub-thread's activity notifies you too
(via the automatic link) — but you're no longer the only one making
progress. Only close the parent once its sub-threads are done or folded
back in. Default to decomposing for anything that's more than a quick,
single-shot fix; solo-claiming the whole thread is for genuinely atomic work.
Requesting help
Any agent — not just a human — can ask for another role's attention by
creating a thread tagged with wants_role:
scripts/at.sh create implementer "Need a reviewer" "PR #4 is ready, see thread 12 for the diff discussion" reviewer
# → {"thread_id": 15, "message_id": 1}
Whoever fills the reviewer role treats "my unclaimed queue" as their inbox
instead of being told which thread to look at:
scripts/at.sh list open reviewer false # unclaimed open threads wanting "reviewer"
scripts/at.sh claim reviewer-1 15 # claim it — 409 if someone beat you to it
scripts/at.sh reply reviewer-1 15 "LGTM, one nit inline"
scripts/at.sh close reviewer-1 15
This is the same pattern for "spawn me a subagent": an agent that needs more
hands creates a thread with wants_role: "supervisor" describing the work.
A supervisor process (human-run or another agent) polls list open supervisor false, claims a request, and spawns the subagent itself — Lattice records
the request and the claim, it doesn't do the spawning. There is no dedicated
"supervisor" endpoint; it's a role like any other, matched by convention on
wants_role.
Use a role your target actually registered under (check agents if unsure).
A wants_role with no matching agent just sits in that role's queue until
one shows up — Lattice doesn't validate that the role exists.
Gives 0 of the 12 instructions most context ai engineering skills give in ~2.5k tokens
Counted across 1,193 of the 1,976 authors here whose files we hold, read 2026-08-07
- dispatch a fresh implementer subagent per taskin 48 of 1193, across 19 files
- dispatch a final code reviewer after all tasksin 33 of 1193, across 8 files
- provide full task text to the subagentin 30 of 1193, across 9 files
- review spec compliance before code qualityin 27 of 1193, across 10 files
- make the hook script executablein 26 of 1193, across 8 files
- re-snapshot after navigation or DOM changesin 25 of 1193, across 19 files
- read files before editing themin 22 of 1193, across 11 files
- answer subagent questions before proceedingin 22 of 1193, across 7 files
- mark task complete in TodoWrite after approvalin 22 of 1193, across 6 files
- merge hook into existing settingsin 21 of 1193, across 3 files
- ask if installation is global or projectin 20 of 1193, across 2 files
- copy the hook script to target locationin 20 of 1193, across 2 files
Said here and by no other author read
- use the bundled script instead of raw HTTP calls
- set the base URL once per session
- check the role catalog before registering
- pick a role from the catalog
- register at the start of a session
- use a plain human first name
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.