Early preview · v0.1.0 · under construction Status & limitations

Sealmesh

Security model

Sealmesh reads what coding agents are doing on people's own machines and shows it to their teammates. What it handles isn't a database: it's what people are working on, including work they haven't shared. This page states what's protected and what isn't yet.

What leaves a machine

Per agent, only typed fields: job id, repository slug, run state, branch, ticket id, commits ahead, uncommitted file count, completed/total tasks, pull request number, and two timestamps.

  • No text a person or agent wrote. Every field on the wire is an enum, a number, a timestamp, or a newtype whose constructor enforces a charset and a length. Claude Code's intent and detail hold the raw prompt; they're dropped where the file is read. A canary test plants a prompt in every free-text field and fails the build if it appears in the output. Getting free text onto the wire is the highest-severity bug this project can have.
  • No filesystem paths. A repository is named by its remote slug.
  • Only allowlisted repositories and paths. Anything else produces no output, not even the fact that it exists.

What is kept, and where

WhereWhatHow long
Router, diskRoom chat: room, sender host, kind, body7 days, swept hourly. Only with chat enabled
Router, memoryLive connections and each one's GitHub token; names of hosts seen since start; access cacheUntil disconnect or restart; cache 30–300 s
Router, logsGitHub logins and project ids on stderrWhatever your log setup keeps
Your machineaudit.jsonl (who asked, when); PR/CI cache; declared-agent recordsUntil you delete them

The router never stores a snapshot, an agent row or a who answer. A machine that disconnects leaves nothing behind.

Held by design

  • Identity comes from the credential. The host a connection speaks for is derived from the GitHub login its token resolves to, never from a path, a body or config.
  • Membership is checked live. Only active members of the router's organization can connect. Removing someone from the org removes their access.
  • Readers see only what they could read anyway. Every who and every room is cut down to repositories the reader's own token can read.
  • A panic is a denial of service. unsafe is forbidden, and unwrap, expect, panic and slice indexing are denied outside tests.
  • Plaintext is refused to anything but loopback, on both the daemon and the router.

Known and not yet held

These are recorded rather than hidden.

  1. A compromised router is a remote read trigger. Whoever controls the router can make every connected machine run its collector. The allowlists bound what that reaches and the per-machine rate limit bounds how often, but the trigger is inherent to answering on demand.
  2. The daemon can't verify who is asking. asked_by is the router's claim, so a compromised router could attribute a query to someone who never made it. sealmesh audit shows it as claimed. Signing by the requester would close this; it isn't built.
  3. The GitHub token is broader than the router needs. gh auth token hands over whatever you authorized, typically including repo, while the router needs read:org and repo read. The router holds it in memory for the life of the connection, never on disk or in logs. A GitHub App device flow issuing a narrower token is the planned fix.

Reporting a vulnerability

Privately, through GitHub security advisories, or by email to security@sealmesh.dev. See Security.

Something wrong or unclear? Open an issue.