@supersuit/analytics
v0.1.0
Published
Share how you use your agent supersuit with whoever you choose (a teammate, a company, anyone), at a privacy tier you choose, with your own copy of everything written first. Zero dependencies.
Maintainers
Readme
@supersuit/analytics
Share how you use your agent setup (your supersuit) with whoever you choose: a teammate, your company, a community, anyone. You pick how much each one sees. Your own copy of everything is written before anything leaves your machine. No dependencies. Needs Node 20 or later.
It was extracted from the usage analytics in Freedom. In Freedom the recipient was fixed to one backend. Here you pick the recipients.
30 seconds
npx @supersuit/analytics from gary
npx @supersuit/analytics add wilson --tier usage --file ~/Dropbox/shared/gary.jsonl --deny "desiet:*"
npx @supersuit/analytics preview wilson # the exact record Wilson would getWilson reads the shared file back:
npx @supersuit/analytics summarize ~/Dropbox/shared/gary.jsonlgary: 212 events on 19 days, 41 sessions, ~63.5h active, 96% of skill runs ok
38 freedom:save-my-progress
21 cw:ship-freedom
...A file is enough to share usage. Anything that syncs a folder (a git repo, Dropbox, iCloud) carries it, so there is no server to run. You can also send records to a webhook or to Firestore.
Privacy tiers
Each recipient gets exactly one tier.
| Tier | What they learn |
|---|---|
| presence | That you used it, and when. Nothing about what you did. |
| usage | The above, plus which skill ran, whether it worked, how long it took, the error class, and session counts. |
| full | The above, plus OS, timezone and a hashed workspace id. Snapshots too, but only if you also pass --snapshots. |
You can narrow any tier further:
--deny "desiet:*,freedom:read-messages"never mentions those skills. A trailing*covers a whole namespace.--allow "cw:*"limits the recipient to the listed skills and nothing else.--drop errorClassremoves one field the tier would otherwise send.
The schema is an allowlist, and a field nobody declared never leaves. The full rules are in PRIVACY.md.
Commands
| Command | What it does |
|---|---|
| status | Lists each recipient, its tier and transport, and whether it is sending. |
| add <id> --tier T (--file P \| --webhook URL [--token-env VAR]) | Starts sharing with someone. Accepts --name, --deny, --allow, --drop and --snapshots. |
| remove <id>, pause <id>, resume <id> | Stops sharing with one recipient for good, or for now. |
| off, on | Stops or restarts all sharing. Your local copies stay either way. |
| from <label> | Sets the name recipients see you as. |
| preview <id> [--event JSON] | Shows the exact record that recipient would receive. |
| sent <id> | Shows your copy of what already went to them. |
| emit [--detach] | Reads one JSON event on stdin and shares it. Always exits 0, for hooks. |
| summarize <file.jsonl> [--days N] | For the recipient: reads a shared file as a picture of how someone works. |
Every command takes --app-dir and --json. The config lives in
~/.supersuit/analytics/recipients.json, or in $SUPERSUIT_ANALYTICS_DIR if set. The config
never holds a secret: a webhook token is read from the env var named by --token-env.
Exit codes: 0 means ok, 1 means the command was refused, 2 means a usage error.
SUPERSUIT_ANALYTICS=off silences everything.
Hook it into Claude Code
{ "hooks": { "PostToolUse": [{ "matcher": "Skill", "hooks": [{ "type": "command",
"command": "jq -c '{skill: .tool_input.skill, ok: true}' | supersuit-analytics emit --detach" }] }] } }As a library
import { createAnalytics, defineSchema } from "@supersuit/analytics";
const analytics = createAnalytics({
appDir: "~/.myapp", // recipients.json, local copies, state
killEnv: "MYAPP_ANALYTICS", // MYAPP_ANALYTICS=off silences everything
schema: defineSchema({ // extend the default event fields
recAnswer: { type: "string", enum: ["now", "later", "declined"], tier: "usage" },
}),
transports: { mine: (spec) => ({ event: async (record) => ({ sent: true }) }) },
});
await analytics.share({ skill: "my:skill", ok: true, durationMs: 812 }); // never throws
await analytics.snapshot({ schema: 1, projects: 4 }); // only full-tier recipients with snapshots on
analytics.preview("wilson", { skill: "my:skill" }); // exactly what they would get
await analytics.announce(); // tells a recipient once when you pause or resume themThese exports are also available on their own: recordThenSend, project, scrub,
closed, hashId, errorClass and summarize.
The rules it keeps
- It never throws or blocks your work. Every public method resolves.
- It never sends a field nobody declared.
- Your copy comes first. A record that could not be written locally is not sent.
