What posthook data looks like
Posthook runs on each engineer’s machine and records what Claude Code, Cursor and Codex CLI wrote, what the engineer prompted, and which of those lines were committed. Bilanc models it into four tables, all reachable through the metrics endpoint:
Two more posthook metrics live on the
pull_requests table because they measure AI lines that reached merged PRs: posthook-merged-ai-lines and posthook-ai-pct-of-code.
All four posthook tables carry the session owner’s Bilanc identity (merged_user_id, team_ids, squad and manager details), so every people filter and the same row-level security apply as elsewhere.
Only sessions from engineers whose posthook identity is mapped to a Bilanc user are returned. Sessions from unmapped emails are excluded, matching the dashboard.
Metrics
Session summary metrics (posthook_sessions)
count
Distinct sessions that generated or committed at least one AI line. Response column
posthook_sessions_count. Matches the dashboard’s Active Sessions card. Sessions with no captured AI activity exist in the table but are not counted.count
Distinct engineers with at least one session in the window. Response column
posthook_active_users.aggregation required
AI working time in seconds, derived from hook events: each session is active for every 5-minute window containing at least one event. Response column
posthook_active_time. Pass "aggregation": "SUM"; the value is always a sum regardless.aggregation required
Input + output tokens. Response column
{agg}_total_tokens. Cache-read and cache-creation tokens are excluded, matching the posthook dashboard. The raw per-session total_tokens column includes them.aggregation required
Output tokens only. Response column
{agg}_output_tokens.aggregation required
Lines the agent wrote, from edit events. Response column
{agg}_generated_lines.aggregation required
Lines the agent wrote that posthook attributed into commits. Response column
{agg}_committed_lines.ratio
Committed ÷ generated lines. Response column
posthook_ai_code_ratio.string
Most-used model among sessions that committed AI code, ignoring placeholder slugs like
default and unknown. Response column posthook_top_model.Detail-table counts
count
Distinct messages in
posthook_session_messages. Response column posthook_session_message_counts.count
Rows in
posthook_session_files. Response column posthook_session_file_counts.count
Distinct commits in
posthook_session_commits. Response column posthook_session_commit_counts.PR-level attribution (pull_requests)
aggregation required
AI-attributed lines that landed in merged PRs. Response column
{agg}_merged_ai_lines. Uses PR date fields (pr_merged_at, pr_created_at, …) and PR filters.ratio
AI committed lines ÷ lines added across the selected PRs, capped at 1. Response column
posthook_ai_pct_of_code. The dashboard’s “AI % of Code” card requests this with "pr_states": ["merged"] and "date_field": "pr_merged_at".Columns
Any column can be used ingroup_by and order_by; date-typed columns can be used in date_field.
posthook_sessions
posthook_sessions
posthook_session_messages
posthook_session_messages
posthook_session_files
posthook_session_files
posthook_session_commits
posthook_session_commits
Example: team summary by agent, week over week
This is the request behind the Posthook team table in the dashboard. Noteposthook-ai-pct-of-code is a PR-table metric, so it gets pr_merged_at as its date field and the pr_states filter; the session-table metrics ignore pr_states.
Example: every session as a row
Group bysession_id and the columns you want. This is the request behind the dashboard’s session list. metric_min_value: 1 keeps only sessions that generated or committed AI code; drop it to include every captured session.
get-multiple-metrics. See Paging through large tables.
Example: a session’s prompts and replies
Pin the query to one session withfilters.session_id. Set start_date a day or two before the session started: the date column of a message falls back to the session date, but commits attributed later can land after the session’s own day.
session_id and window by date instead, adding session_id and engineer_email to group_by so each message keeps its context.
Example: files touched and commits attributed
The same shape, against the other two detail tables. These are the dashboard’s “Files” and “Commits” panels.Example: daily usage per engineer
A conventional aggregate: tokens, active time and committed lines per engineer per day.Parameter notes
string
All four posthook tables default to
date. Sessions also accept started_at and ended_at; messages message_ts; files first_edit_ts and last_edit_ts; commits committed_at. The two PR-table metrics take PR date fields (pr_merged_at, pr_created_at, pr_closed_at, …).object
Posthook tables honour
member, team, departments, locations, levels, squad_ids, squad_levels, manager_ids and session_id. They have no repository or PR-state columns, so repositories and pr_states are ignored for them (filter on the repo_name column via group_by instead). posthook-merged-ai-lines and posthook-ai-pct-of-code are PR-table metrics and honour every PR filter.string
Required for
posthook-total-tokens, posthook-output-tokens, posthook-generated-lines, posthook-committed-lines, posthook-active-time and posthook-merged-ai-lines. Use SUM for totals and AVG for per-session averages. Count, ratio and top-model metrics take none.
