Repository navigation
Releases: shakibbinkabir/ccledger
Release list
v0.1.2
Server-side only. Teammates need to change nothing and are not interrupted:
the config contract, the member tokens and the ingest path are all untouched,
so an upgrade is npm install -g @thisissbk/ccledger@latest and a restart of
the server alone.
Added
-
Invitations from the dashboard. Members → Invite a teammate takes a name
and gives back the whole line to send, with a copy button, plus a list of who
has been invited and has not joined yet.ccledger invitestill works and is
unchanged; this exists because the person adding teammates and the person
with a shell on the server stop being the same once the server is not a
laptop.The command is assembled on the server, not in the browser, so the package
name in it comes from the manifest this build was published under. A wrong
version in that line is cosmetic; a wrong package name installs somebody
else's software.New routes:
POST /api/invitesandGET /api/invites, behind the admin
token like everything else under/api. A server with no public URL recorded
answers 409 and names the flag that fixes it, rather than minting an
invitation that points nowhere.
Changed
-
The dashboard no longer forgets the admin token on reload. It is kept in
sessionStoragefor the tab, and inlocalStorageonly behind an explicit
"remember me on this device" that is off by default.Lockerases both, and
so does any rejected token.This reverses a decision 0.1.0 made deliberately, and the reason is that it
was wrong in practice rather than in principle: the token is thirty-six
characters nobody memorises, so "never at rest" meant everybody kept it at
rest somewhere else and pasted it in several times a day. What makes the
trade defensible is the page's own CSP —script-src 'self'with no
relaxations — so there is no third-party script in the document to read
either store.
Fixed
- An unclaimed invitation showed "expires just now" whatever its expiry.
formatRelativemeasures elapsed time and folds every negative value to
"just now", which is exactly backwards for a countdown. Expiries now use
formatUntiland read "in 23h".
v0.1.1
Added
-
A guide and a bootstrap script for AWS.
docs/deploy-aws.mdand
deploy/lightsail.shput ccledger on a Lightsail instance for $5 a month,
with Caddy in front for TLS and systemd keeping it up. Prices in the guide
come from the Lightsail and EC2 pricing APIs rather than from memory, and it
says why EC2 is not cheaper — a public IPv4 address has been billable since
February 2024 and costs more than the instance it is attached to.The script installs the published npm package rather than building the
Docker image, because the $5 machine has 512 MB of RAM and building means
compiling a native SQLite addon and running a Vite build. Both run out of
memory. Anyone who wants the container needs the $7 tier.Lambda, App Runner and Fargate-on-EFS are documented as out of scope, with
the reasoning: they take away the single SQLite file, and with it the
idempotent ingest key, the transactional alert debounce, and a backup that
is one file.
Fixed
- The README on the registry. The 0.1.0 page was published before the scoped
name resolved, so its badges pointed at a package npm was still returning
404 for and rendered as "package not found". npm serves the README from
inside the tarball, frozen at publish time, so only a release can correct it.
v0.1.0
First release.
Published as @thisissbk/ccledger. The registry refused the unscoped name
as too close to an unrelated package; the command it installs is plain
ccledger, and nothing else about the project is scoped.
Added
- OTLP ingest.
POST /v1/logsaccepts OTLP/HTTP JSON log batches from
Claude Code, with or without gzip. Malformed bodies get 400 rather than 500,
because exporters retry on 5xx and a 500 on a body that will never parse
produces a retry storm from the whole team at once. - Idempotent storage. Rows are keyed on
client_request_id, falling back to
request_id, falling back to a hash of the session, timestamp and token
counts. OTLP delivery is at-least-once, so a redelivered batch has to be a
no-op; storing one twice would silently inflate every number on the dashboard. - Identity attributes dropped at parse time.
user.email,
user.account_uuid,user.account_idandorganization.idnever reach the
database, and neither do thepromptandresponsekeys. This is asserted
by searching the SQLite file byte by byte, not by inspecting the parser. - Per-member tokens and join codes.
ccledger invite <name>issues a
single-use code that expires in 24 hours, bundled with the endpoint into one
paste-able invite. Tokens are stored as SHA-256 hashes and shown once. ccledger setup. Joins a server and writes exactly five environment keys
into~/.claude/settings.json, after a timestamped backup, showing the
disclosure and requiring a yes before anything is written. Refuses rather
than overwriting when those keys already hold something else, and does that
check before spending the join code.ccledger doctor. Six checks with a specific remedy on each failure:
config keys, whether Claude Code has restarted, endpoint reachability, token
acceptance, conflictingOTEL_*variables, and content-logging switches set
by anything at all.--jsonfor bug reports, and it never prints a token.ccledger uninstall. Removes only the keys its own record says it added,
offers the backup instead, offers to tell the server so the token can be
revoked, and leaves a key that has since been edited alone.- Dashboard. Date range picker, per-member table sorted by share, stacked
area of tokens over time, tokens by model, per-member sparklines, and a member
detail view with sessions and installs. Costs are stored as integer micros and
labelledest.everywhere. The admin token is held in memory, never in
localStorage. - Overhead separation. Requests Claude Code makes on its own behalf —
generate_session_title,compact— can be shown separately from work, so a
comparison between two people is not distorted by housekeeping. - Alerts. Rules on share, tokens or estimated cost over a calendar day or
week, evaluated on ingest, debounced to one fire per rule per member per
window, delivered by webhook with a top-leveltextfield so Slack and
Discord accept it unmodified. Alert evaluation can never fail an ingest. - Laptop mode.
ccledger serveadvertisesccledger.localover mDNS,
falls back to printing LAN addresses, and refuses to guess when several
addresses are plausible. It warns clearly that the mode is unencrypted. - VPS mode.
docker/holds a multi-stage non-root image and a compose stack
with Caddy in front for automatic TLS. Two values in.envand one command. ccledger backup. SQLite's online backup API, safe while the server runs,
written to a temporary file and renamed into place so an interrupted backup
cannot leave a truncated file at the path someone will later reach for.- Health and version endpoints, and
--version. - CI on ubuntu, macOS and Windows against Node 22 and 24, plus a job that
asserts whatnpm packwould actually ship.
Known limitations
- Attribution is honor-system. A teammate can edit their own config.
- Costs are Claude Code's own estimates, not billed amounts.
- claude.ai browser and desktop usage is not tracked, and cannot be.
- Laptop mode is plain HTTP and belongs only on a network you trust.
- Tested against Claude Code 2.1.241. Telemetry attribute names are not a
stable API.