Scan and report had grown into two sections saying the same thing, and
step 4 repeated step 1's "show the table". Down to four steps.
Adds what nearly went wrong on the first real run: a day already
confirmed weeks ago looks identical to a planned one in a bulk approval,
and overwriting it needs its own yes. Also records the 15-minute
rounding the app enforces, and the ${VAR:-x} expansion that prints a
token instead of hiding it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Five minutes with two projects open was counted as five for each, so
Wednesday's columns summed to 18h against 13h10 of wall clock and no
column said which number to trust.
Each slot's minutes are now divided evenly among the projects live in
it, largest remainder over whole minutes, so the columns add up to the
total exactly. That ratio is what a submission scales the user's stated
day length by.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Splitting a fixed 8h day by share turned 160 minutes of Friday morning
into "7h Tesser". The number looked measured and was not, and no column
in the table said which.
Cells now carry the time each project was actually active. The total
column is wall-clock presence — the union of active slots — so it reads
lower than the row sum when sessions overlapped. Measured time is a
floor; the skill says so and leaves adding the rest to the user.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The drawn grid was solving the wrong problem: the script output was
already right, and fencing it in chat is what turned a rendered table
into raw dashes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A markdown table carries no borders of its own; whether any get drawn is
up to the renderer, and terminal renderers mostly draw none. Emitting the
grid directly makes the output look the same everywhere it lands.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Padded pipes, so it reads as a grid in the terminal and renders as a
real table when pasted anywhere else. Each cell carries hours, share and
active minutes; a flags column carries what needs judgement.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The matrix table dropped the evidence — share, active minutes, hour
range, and the outside-working-hours flags — which are what make a
proposed number checkable rather than asserted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
One row per day, one column per project, hours in the cell. The per-day
blocks repeated the project name on every line and buried the totals.
Share, active minutes, hour ranges, and the outside-working-hours flags
move to --json, which is where the skill reads them anyway.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Half-days forced every result into a 4h bucket. Days with hours split by
share give the same answer at finer granularity and drop a concept.
Session minutes are now stated as a floor on real work, not a measure:
the day's length comes from the calendar and only the split between
projects comes from the sessions. Meetings and review leave no
transcript, so a thin day is still a full day.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Turns Claude Code and Codex session activity into a half-day-per-project
proposal, reconciles it against the timesheet API, and submits only what
the user approves in-session.
Activity is measured in 5-minute active slots, deduplicated per project,
not message counts — otherwise one overnight autonomous run outweighs a
real morning's work.
The path-to-project mapping and the API credentials stay in
~/.config/hourlog/ and ~/.env.claude. This repo is public.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>