@atheon-labs/trinity-daemon
v0.4.0
Published
Folder-scoped IDE relay for Trinity — watches a repo and ships secret-redacted coding-session summaries.
Readme
Trinity Daemon
A folder-scoped IDE relay you run on your laptop. It watches one repo, tails your
Claude Code and Codex session logs (cwd-matched to that repo), and every few minutes
ships two things to the Trinity backend: secret-redacted verbatim turns (role-tagged
prompts, assistant text, and clipped tool I/O — the coding_session_v2 transcript
lane) and a repo summary (turn / tool-call counts, prompt & result summaries, the changed-file
list, a git diff --stat, and the HEAD commit SHA).
It never sends file contents or full transcripts. The published package is a single self-contained file — zero runtime dependencies, Node ≥ 20.
Onboard (the one-liner)
The dashboard's People → Connect IDE screen hands you a ready-to-run command. Paste it in the repo you want to track:
npx -y @atheon-labs/trinity-daemon@latest onboard --relay "<relay-url-from-dashboard>"onboard writes .trinity/config.json (auto-gitignored), runs preflight checks, proves it can
reach the backend, and installs a background service that runs on boot. Re-running it rotates the
relay and reloads the service. Flags:
--foreground— run in the terminal instead of installing a service.--no-service— write config only; start it yourself later.
Within seconds the dashboard shows the daemon as connected; your first captured coding session appears there too.
Provisioning a relay URL (dashboard or API)
The daemon authenticates with a per-developer relay token the backend mints. Normally you click Connect IDE on the People screen and copy the command. Via API:
API=http://localhost:8080
TOK=<your bearer token> # from /auth/login or /auth/signup
PID=<your project id> # from /projects
PERSON=$(curl -s -X POST "$API/people" -H "Authorization: Bearer $TOK" \
-H 'content-type: application/json' -d '{"email":"[email protected]","name":"You"}' | jq -r .person.id)
RELAY=$(curl -s -X POST "$API/people/$PERSON/relay?projectId=$PID" \
-H "Authorization: Bearer $TOK" | jq -r .relay.ingestUrl)
echo "$RELAY" # e.g. http://localhost:8080/ingest/hook/<token>The returned
ingestUrluses the server'sINGEST_PUBLIC_URLif set (e.g. a Cloudflare tunnel). Running the daemon and backend on the same laptop, you can swap the host forhttp://localhost:8080— keep the/ingest/hook/<token>path.
Sessions land in the project the relay token is scoped to — open that project's Activity Log or People → sessions in the dashboard, or Ask about what you worked on.
CLI
trinity-daemon onboard [dir] --relay <url> config + service + connectivity, one shot
trinity-daemon init [dir] [--relay <url>] write .trinity/config.json
trinity-daemon update-config [dir] --relay <url>
update an existing relay URL
trinity-daemon watch [dir] watch the repo and ship summaries
trinity-daemon install-service [dir] run on boot (macOS LaunchAgent)
trinity-daemon restart [dir] | restart-service rebuild + reload the service
trinity-daemon uninstall-service [dir] remove the boot service
trinity-daemon update [--force] fetch the latest npm version + reload the service
trinity-daemon [dir] alias for `watch`The lower-level init / watch / install-service commands stay for power users; onboard
composes them into one idempotent step.
Updating
The background service runs a version-pinned copy, so it doesn't pick up new npm releases on its own. To upgrade:
npx -y @atheon-labs/trinity-daemon@latest updateupdate fetches the latest published version from npm (just fetch + the system tar — no npm
CLI needed), stages it in ~/.trinity/bin/, and re-points + reloads every installed background
service onto it. Add --force to re-download and reload even when already on the latest version.
A running daemon checks npm on startup and once a day and logs an "update available" notice
when a newer version is published, so long-lived services don't silently fall behind. Applying it
stays the explicit update command by default. To let a daemon update itself unattended, set
"autoUpdate": true in its .trinity/config.json — on detecting a newer version it installs it and
reloads its own service automatically.
Build from source
npm install
npm run build # → dist/index.js (single bundled file; bin: trinity-daemon)
npm test
# or run from source: npm run dev -- watch /path/to/repoPrivacy
- Only paths under the repo are buffered; file contents are never read (git
diff --statonly). .gitignore+.trinityignoreare honored; secrets (.env*,*.pem,*.key,id_rsa,.npmrc,.netrc, …) are always blocked.- A send-log prints before every flush, so you always see exactly what leaves the machine.
- On startup the daemon sends a tiny connectivity ping (version + a daily-keyed id — no repo path, email, branch, or file names) so the dashboard can show it as connected immediately.
Config (.trinity/config.json)
{
"relayUrl": "http://localhost:8080/ingest/hook/<token>",
"repoPath": "/path/to/repo",
"flushIntervalMs": 300000,
"autoUpdate": false,
"mirrorRelayUrls": ["http://localhost:8080/ingest/hook/<dev-token>"]
}autoUpdate (optional, default false) lets a running daemon install newer published versions and
reload its own service without a manual update.
mirrorRelayUrls (optional) sends a best-effort copy of everything — sessions, connectivity
pings, worktree provenance — to each extra relay URL, e.g. a local dev stack alongside prod. Each
entry is a full tokenized relay URL minted by that backend's own dashboard. Mirrors are strictly
fire-and-forget: only the primary relayUrl's response decides whether a flush is committed or
retried, so a dead mirror can never stall or roll back real ingestion. Mirrors may miss windows
(that's the deal); both backends dedupe re-sends on external_id. Mirror endpoints appear
(token-masked) in the send-log.
Manage mirrors from the CLI — changes apply live (an installed background service is restarted;
a foreground watch needs a manual restart):
trinity-daemon mirror add "http://localhost:8080/ingest/hook/<dev-token>"
trinity-daemon mirror list
trinity-daemon mirror remove "http://localhost:8080/ingest/hook/<dev-token>"mirror add probes the new mirror with a hello ping but only warns if it's unreachable — a
mirror is allowed to be down; that's the whole design.
