AI ProgramsRetreat
AboutCareersBook a Conversation
Workflows/InnovationBuilt

Human Token Tracker

Every project has a cost in human hours and AI tokens, and nobody wants to log either by hand. These jobs read the effort off the systems where it already happens: pull requests on GitHub, session telemetry from the Claude Code recorder, and the effort-log file each repo carries. The ledger is rebuilt from keys, so running a job twice never counts anything twice.

Source GitHub PRs, effort logs, session telemetryCadence 03:30 local, then 09:10, 10:10, 11:10 (+07)Human touchpoints Register the repo, read the ledger

Work in, ledger out

Five steps, one of them human. The team works as normal; four scheduled jobs turn what they did into rows, then into summaries. The rail is the orientation; the step cards and the exceptions table are the truth.

01Every session
Work Happens
Team
02Session end, or 03:30
Sessions Recorded
System
0303:30 local, 09:10 hosted
PRs Synced
System
0410:10 hosted
Effort Logs Ingested
System
0511:10 hosted
Summaries Refreshed
Claude

How each step works

01
Work happens, and only registration is manualTeam

A repo enters the tracker when someone commits a registration file to the tracker’s telemetry branch. The PR sync processes those files first, verifies that the committer is the person named in the request, and creates the repo record. There is no auto-enrol; an already-registered repo is a no-op, so a file that cannot be deleted is retried harmlessly every night. After that, the team just works.

02
Sessions recordedSystemSession end, or 03:30 (+07)

The recorder plugin posts a Claude Code session the moment it ends, and the row is stored before the request returns. The Mac mini job covers the other paths: it pulls recorder telemetry from the tracker branch and backfills the Mac mini’s own local transcripts, deduplicating token counts by message id. Both paths apply the same rules: the repo must be registered, the client’s own identities are excluded, the Claude token row is keyed by session so a retry is an update, and the hours rule recomputes each day the session touched.

03
Pull requests syncedSystem03:30 (+07) local, 09:10 (+07) hosted

For every tracked repo with a GitHub repo, the job fetches pull requests updated since that repo’s last sync and upserts them by GitHub id. The author is resolved to a person from the author block in the PR body first, then from the GitHub login; an unresolved author is stored unattributed and counted. Session token rows on the same branch are linked to the PR afterwards, and the run writes its own sync row with repos synced, PRs upserted and errors. The hosted job returns as skipped until its GitHub token exists; the launchd job on the office Mac mini runs the same handler in the meantime.

04
Effort logs ingestedSystem10:10 (+07) hosted

Each tracked repo may carry a committed effort-log file. Every entry becomes up to two token rows: Claude tokens keyed on the session id, and human hours as centihours keyed on the session id plus a suffix. Only entries by the client’s own identities are kept, because Edge8 contributors are already captured by telemetry and would otherwise be counted twice. Persisting is delete-then-insert by session id, so the same file ingested twice yields the same rows.

05
Summaries and goals refreshedClaude11:10 (+07) hosted, after the PR sync

Per repo, three things may be written and each has a rule for when the model is allowed to run. The executive summary is generated once from the repo’s status page and after that only when someone explicitly regenerates it. The digest of the latest ten PRs regenerates only when the set of PR numbers and states changed since last night. The FAST goal is suggested when the repo has none yet or its status page changed, and a goal set by hand is never replaced. The whole sweep shares a budget of forty model calls as a circuit breaker; steady-state nights spend a handful.

Every exception has an owner

Most of these are quiet on purpose: a ledger that guesses is worse than one with a gap. Each row is a condition the code actually handles, what it does, and where a human sees it.

ConditionWhat happensWhere you hear about it
GitHub token not configured in the hosted environmentThe hosted job returns without doing anything; the Mac mini job carries the loadSettings → Agents, as a skipped run
Repo archived, or registered without a GitHub repoLeft out of every sync, ingest and refreshNowhere, by design
PR author cannot be matched to a personPR stored with no person; counted as unattributedThe sync run row and the run result
One repo’s GitHub fetch failsError recorded against that repo; the other repos still syncThe sync run’s error list
Repo homepage cannot be readExisting live URL kept, never cleared (best-effort)Nowhere, by design
Effort-log entry has no session id or no dayDropped, because it could not be re-ingested safelyThe run result, as a skipped count
Effort-log entry belongs to an Edge8 contributorFiltered out; telemetry already covers themNowhere, by design
Session arrives for a repo nobody registeredNot stored; there is no auto-enrolThe ingest result; the plugin holds the record and re-probes
Session author is one of the client’s own identitiesExcluded, never billedThe ingest result
Repo has no status pageExecutive summary marked as such; no model call, re-checked cheaply next nightThe run report
PR set unchanged since the last digestDigest skipped; no model callThe run report
Model budget spent (40 calls a night)The sweep stops and says so; remaining repos wait for tomorrowThe run result, budgetExhausted
A goal was set by handNever overwritten by the nightly suggestionNowhere, by design
Sync run row cannot be openedThe sync aborts before touching a PR, rather than run unobservedSettings → Agents, as an error run
Local job log contains an errorRun recorded as error, with the log attachedSettings → Agents

The seven elements

Every workflow we document has the same anatomy: seven elements, each assigned to a human, a machine, or both. This is the Centaur Map from our workflow design method.

01 TriggerMachine

Time. 03:30 (+07) on the office Mac mini, then 09:10, 10:10 and 11:10 (+07) for the three hosted jobs. Nobody fills in a timesheet.

02 InputsMachine

GitHub pull requests for every tracked repo, each repo’s committed effort-log file, Claude session telemetry from the recorder plugin, and the Mac mini’s own local Claude transcripts.

03 DecisionBoth

The machine decides whose work a PR is, which sessions count, and whether a summary needs regenerating. A human decides what the numbers mean, and only a human registers a repo.

04 RoutingMachine

Every row lands in one schema keyed by repo, person and day. Client-side identities are excluded before anything is written; Edge8 contributors are never counted twice across telemetry and effort logs.

05 OutputMachine

Pull request rows, token entries (human hours as centihours, Claude tokens), work sessions behind the hours rule, one executive summary and one PR digest per repo, and one FAST goal suggestion per repo.

06 DeliveryMachine

The ledger and the per-repo pages in the team app. The weekly check-in summary reads the same tables for its Human and AI token report.

07 MeasurementHuman

Each run leaves a row on Settings → Agents with its counts, errors and the model calls it spent. A skipped or error run is the alarm; an unattributed PR count that keeps growing is the second one.

Reads and writes

  • Reads: tracked repos, client identities, GitHub PRs and repo homepages, each repo’s effort-log file and status page, recorder telemetry, local Claude transcripts
  • Writes: pull requests, token entries, work sessions and the hours ledger, per-repo summaries, project goals, a sync run row, and a routine run row per job
  • Keys: GitHub PR id for PRs; session id for token rows; repo, person and day for the hours ledger; a fingerprint of PR numbers and states for the digest; the status page’s blob sha for the executive summary and the goal

The standing rules

  • No auto-enrol: a repo is tracked only after an explicit, committer-verified registration
  • A client’s own identities are captured and excluded, never billed
  • Every write is keyed, so any job can be re-run from any machine without double counting
  • The model runs only on change, inside a nightly budget; a summary is pinned until a human asks for a new one