Hi @Stanislav_Kostomakha I worked thru a couple examples scenarios with my Cursor agent, let me know if this makes sense!
Most of what you’re after is already available from hooks, though two of the fields on your list aren’t yet.
Token counts: the stop hook
stop fires when the agent loop finishes for a turn, and the payload carries token usage accumulated across every model call in that turn:
{
"hook_event_name": "stop",
"conversation_id": "a1b2c3d4-1111-4222-8333-444455556666",
"generation_id": "f0e1d2c3-7777-4888-8999-aaaabbbbcccc",
"model": "cursor-grok-4.6-high-fast",
"model_id": "grok-4.6",
"model_params": [{ "id": "effort", "value": "high" }, { "id": "fast", "value": "true" }],
"status": "completed",
"loop_count": 0,
"input_tokens": 1180993,
"output_tokens": 8146,
"cache_read_tokens": 1007022,
"cache_write_tokens": 173957
}
The same four token fields are also on afterAgentResponse.They aren’t listed on the hooks docs page yet, which is why they’re easy to miss, and I’ve let the team know so we can get that page updated.
Three things to handle in your collector:
input_tokens is inclusive of cache_read_tokens and cache_write_tokens. In the payload above only 14 of the 1.18M input tokens were genuinely uncached. If you want a non overlapping breakdown, subtract the two cache figures from input_tokens and clamp at zero.
- The numbers are cumulative for the turn, not per message.
stop and afterAgentResponse report identical values for the same generation_id, so pick one hook as your source of truth rather than summing both.
- The token fields are optional, so treat them as possibly absent rather than defaulting to zero.
model, model_id and model_params are on every hook payload, so you get the model dimension for free. That covers your items 1, 3, 4, 5 and 6.
Duration
There’s no per-turn duration on stop. The simplest approach is to record a timestamp in beforeSubmitPrompt and subtract it at stop. Both payloads carry generation_id, which changes with every user message, so it works well as the join key for a turn. If you also want coarser or finer numbers, sessionEnd has duration_ms for the whole session and postToolUse has duration per tool call.
Reasoning tokens
Not currently exposed through hooks.
Subagents
subagentStop gives you subagent_id, subagent_type, status, duration_ms, message_count, tool_call_count, modified_files and agent_transcript_path, but no token counts.
One correction on the transcript files mentioned above: those JSONL lines only contain {role, message}, so there’s no token data to fall back on there.
For team-wide analytics
Since you’re on an Enterprise team, your Cursor admin can pull the Admin API usage events endpoint. Every event includes the model, inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens, the cost in cents, and a conversationId. It’s per model call rather than per turn and it’s the same data your billing is based on, so it’s a good cross-check against what you collect locally. Joining it to your hook events on the conversation ID should get you close to the full picture.