@blastin-dev/clocktopus-cli
v0.4.0
Published
Readme
Clocktopus CLI
Command-line interface for Clocktopus time tracking.
Installation
npm install -g @blastin-dev/clocktopus-cliOr run directly with npx:
npx @blastin-dev/clocktopus-cli <command>Getting Started
Authenticate with your Clocktopus account:
clocktopus loginThis will open a browser window where you authorize the CLI. Once complete, your session is stored locally.
Commands
clocktopus login
Authenticate using the device authorization flow. Opens a URL in your browser to approve access.
clocktopus logout
Clear stored credentials.
clocktopus whoami
Display the current authenticated user.
clocktopus clock (in|out)
clocktopus clock (in|out) [--ago <duration> | --at <time>]Record the start or end of a work session. Defaults to "now" when no flag is passed.
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------- |
| --ago <duration> | Backdate by a duration from now (15m, 1h, 1h30m). Mutually exclusive with --at. |
| --at <time> | Backdate to an absolute wall-clock time today (HH:mm or HH:mm:ss). |
clocktopus clock status
clocktopus clock status [-d <YYYY-MM-DD>]Show clock signals for a given date.
| Option | Description |
| ------------------- | --------------------------------------------------------------------------- |
| -d, --date <date> | Show signals for a specific date in YYYY-MM-DD format. Defaults to today. |
clocktopus agent setup
clocktopus agent setup [--name <label>] [--force] [--agent <ids>]Configures this machine to report AI agent spend — token cost, active time, and the repository each session worked in — so the true cost of a piece of work can be measured as human time × rate plus agent spend.
One command, however many agents you have. It looks for each supported CLI on PATH and configures what it finds:
Agents on this machine
1 Claude Code 2.1.234 already configured
2 Codex CLI 0.147.0 not configured
Which should report to Clocktopus? [all]:With one agent installed there is no question to ask, so it just runs. With
several it prompts; --agent skips the prompt, and a non-interactive shell
configures everything found and says so.
| Agent | --agent id | Writes |
| ----------- | ------------ | --------------------------------------------- |
| Claude Code | claude | ~/.claude/settings.json |
| Codex CLI | codex | ~/.codex/config.toml, ~/.codex/hooks.json |
| OpenCode | opencode | ~/.config/opencode/plugin/clocktopus.js |
It mints one ingest token for the machine, writes each agent's exporter
configuration and SessionStart / SessionEnd hooks, then confirms the
receiver accepts the token before reporting success.
| Option | Description |
| ---------------- | --------------------------------------------------------------------------------------------------------------- |
| --name <label> | Label for this machine's token. Defaults to the hostname — keep it recognisable, since revocation is per token. |
| --force | Mint a replacement token instead of reusing the one already installed. |
| -a, --agent | Configure only these agents. Repeatable, or comma-separated: --agent claude,codex. |
Re-running without --force is safe and idempotent: it repairs the hooks and
refreshes the endpoint while keeping the existing token. Installing a second
agent later and re-running costs nothing — the new one inherits the token the
first is already using rather than minting a second against the same machine.
Restart the agent afterwards. Every exporter and hook reads its configuration once, at process start, so a session that is already open will not pick any of it up. This is the most common reason a correct setup appears to do nothing.
OpenCode is a plugin, not a hook. It has no hook system, so setup
writes one generated file into ~/.config/opencode/plugin/, which OpenCode
auto-loads. Your opencode.json is not touched — that file is your model,
provider and permission configuration, and leaving it alone removes a whole
class of ways to break your setup. Uninstalling is deleting the file.
OpenCode also has experimental.openTelemetry, which looks like an easier
route and is not one: its spans carry your prompts and the model's replies
verbatim, with no way to switch that off, and no cost or repository. The
plugin reads OpenCode's own per-message totals instead and sends counts and
identifiers only.
Codex needs one extra step, once. It will not run a hooks.json it has
not been shown, so the next Codex session asks — answer Trust all and
continue. Until you do, Codex reports what your sessions cost but not which
repository they were spent on. clocktopus agent doctor reports the state
until it is approved.
Everything for an agent lands in that agent's own config rather than a shell
profile. That single source of truth per agent is what lets agent doctor
say which value is actually in force. Note the ingest token is stored there
in plaintext: if you keep ~/.claude or ~/.codex in a dotfiles repository,
ignore the file.
Setup then checks the repository you ran it in, because configuring the machine is only half the job — sessions will arrive either way, but two things decide whether they mean anything, and neither is visible locally:
| Check | If it fails | | -------------------------------- | -------------------------------------------------------------------------------- | | Repository attached to a project | Spend is recorded, but lands in the unattributed row instead of against a client | | Push webhook delivering | No human time entries, so there is nothing to compare the spend against |
The second does not stop agent→commit links — the SessionEnd hook reads your checkout's own reflog locally and posts the commits it authored, so those are created with no webhook involved. What is missing is the other side of the comparison: true cost is human time × rate plus agent spend, and one term alone is not a smaller answer.
Both are reported separately, with the exact next step, because they send you to two different places. Setup only tells you — it never changes your GitHub settings. Note the webhook URL is per person, not per repository, so on a shared repo each teammate adds their own.
clocktopus agent status
Shows what the receiver has actually received. Local configuration is a claim; this is the evidence.
The two ingest lanes are reported separately because they fail separately:
| Lane | Carries | If it alone goes quiet |
| ----- | -------------------------------- | -------------------------------------------------------- |
| Hook | repository, branch, commit range | spend is recorded but cannot be attributed to a project |
| Spend | tokens, cost, active time | sessions show $0.00, indistinguishable from cheap work |
It also lists every supported agent found on this machine, including any that are installed but not reporting — a state the server-side lanes cannot show, because those sessions simply never arrive.
That second failure is why there is no single "connected" line — it is the one that silently understates what work cost.
clocktopus agent doctor
Checks every link in the chain, per agent, and names the first one that is broken: the config file parses, the exporter is configured, every signal the receiver reads is being sent, both hooks are installed, the hook command actually executes, Codex has approved its hooks, the receiver accepts the token, no other file is shadowing the configuration, and whether that agent needs restarting.
The signals check is there for configurations written before a signal
existed. Those still hold a valid token and endpoint, so everything else
passes while one stream never leaves the machine — a Claude Code install
predating BLA-671 reports cost correctly and no sub-agent runtime at all.
Re-running agent setup merges the missing keys in; nothing needs removing
first. The repository
checks — attached to a project, delivering commits — run once at the end,
since they are facts about the repo rather than about any one agent.
The receiver check is the one that cannot be done locally — it crosses the network to a different host than the dashboard, so a wrong endpoint and a revoked token are otherwise indistinguishable from an idle afternoon.
clocktopus agent disable
clocktopus agent disable [--revoke] [--agent <ids>]Removes this machine's telemetry configuration from every agent, leaving any hooks and settings you added yourself untouched.
| Option | Description |
| ------------- | --------------------------------------------------------------------------- |
| --revoke | Also revoke the ingest token, making it useless everywhere. |
| -a, --agent | Remove only these agents (claude, codex), leaving the others reporting. |
--revoke is ignored when combined with --agent: the token is shared by
every agent on the machine, so killing it while another one still has it
written would leave that agent posting into a 401 forever — which looks
like an idle week rather than a broken install.
Stopping and revoking are separate on purpose: removing the local configuration stops this machine reporting, but does nothing about a token that has already been copied elsewhere or committed.
Token Storage
Credentials are stored in a platform-specific config directory:
- macOS:
~/Library/Preferences/clocktopus-cli-nodejs/conf ig.json - Linux:
~/.config/clocktopus-cli-nodejs/config.json - Windows:
%APPDATA%/clocktopus-cli-nodejs/config.json
Run clocktopus logout to clear stored credentials.
The agent telemetry setup deliberately keeps no copy of the ingest token here. It has to live in each agent's own config for that agent's exporter to read it, and a second copy would be another thing to leak and another thing to fall out of date. Only the token id (needed to revoke) and its display prefix are kept.
