Labels are the query model
There is no folder tree in Moment Tally — a span is its labels. Every question you'll ever ask of your history ("hours per client this quarter", "review share by repo", "which spans map to that shipped PR?") is a group-by or a filter over label keys. That makes the schema — which keys exist, what values they take — the highest-leverage decision you make. Good news: a good schema is small, and the rules fit on one page.
Six principles
01
Label what you'll query by
A label earns its place by being grouped or filtered on. If you'd never break a report down by it or filter an export on it, it isn't a label — it's a note. Moment Tally has notes; use them for the color, and keep labels for the axes.
02
Cardinality is the budget
Every distinct value a key takes is one more bucket in every report that groups by it. Values should come from a small, slowly growing vocabulary. Unbounded values — ticket titles, timestamps, one-off prose — degenerate grouping into one span per bucket, and your reports stop compressing anything.
03
One fact per key
Don't pack repo, feature, and kind of work into a single value. Three separate keys filter and join independently; a compound value can only ever be matched whole, and you'll be splitting strings in a spreadsheet within a month.
04
Few, stable keys, consistently named
Pick repo once — not proj on Mondays and project on Thursdays. Renaming a key later severs your history in every query that uses it. Label Review can rescue a drifted schema, but a schema that never drifts needs no rescue.
05
Mirror the system you'll join against
If you plan to line time up with source control, use your code host's exact naming: repo: sfi/moment-tally, not repo: momenttally. Joins are literal — a value that's merely close matches nothing.
06
Decide what unlabeled means
Absent is a value too. Decide what a span with no client — or no repo — means in your reports (internal? overhead? unbilled?) and apply it consistently, so the gaps in your data carry information instead of doubt.
A starter schema
Four keys cover most solo and small-team work. Each holds one fact, each value comes from a vocabulary you could list from memory, and repo uses your code host's exact naming so exports join cleanly against commits and PRs.
# four keys, each drawing from a small, stable vocabulary
repo: sfi/moment-tally # exact source-control path — joins against commits & PRs
feat: label-review # the feature or stream of work
type: review # build | review | support | ops
client: acme # who the hours belong toWhat this buys you: hours per client across every repo, type: review share per repo, and a span-to-PR join for the time-joined-to-what-shipped workflow — none of which required deciding a hierarchy up front. Start smaller if in doubt; a key is easy to add and painful to rename.
How schemas fail
The same schema, gone wrong — each of these looks harmless on the day you type it, and each quietly breaks a query you'll want later.
task: fix-flaky-ci-on-auth-service-again
Unbounded values
Every span invents a new value, so grouping by task yields one span per bucket — the report is just your log, re-sorted. This is a note wearing a label costume.
work: moment-tally-auth-bugfix
Three facts fused into one key
Repo, area, and type are welded together, so you can never ask "all bugfix time, across repos" without string surgery. Split it: repo, area, type.
proj: momenttally · project: moment-tally
Drifting key names and spellings
Half your history lands under each spelling. Every query needs an OR, and totals silently miss whichever variant you forget.
repo: momenttally
Approximate naming
Your code host calls it sfi/moment-tally. A close-but-not-exact value matches nothing when you join time to commits and PRs — the whole point of the key.
The Prometheus lineage
None of this guidance is original, and that's its strength. Moment Tally's label system is modeled on Prometheus metric labels, and these principles are the operational lessons of running Prometheus at scale: high-cardinality labels explode timeseries the way they drown reports; compound values resist aggregation; renaming a label severs history. Time tracking hits the same walls for the same reasons — so we wrote down the same rules. More on what Moment Tally borrows, and from whom, on the attributions page.