Add 'Which AI agents developers are using' card to the AI Governance dashboard
Stacked on Add a reusable donut chart for the AI Governanc... (!256313 - merged).
What does this MR do and why?
- Adds the "Which AI agents developers are using" card to the AI Governance dashboard (#629071+), built on the donut from Add a reusable donut chart for the AI Governanc... (!256313 - merged).
- The agent filter picks the slices: All shows one slice per agent with GitLab Duo as one slice, DAP shows Duo flow types, Connected shows external agents.
- Slices count distinct developers. The center shows the distinct total, so a developer using two agents counts once.
- Reshapes the experiment field
aiGovernanceMetrics.sessionDistribution(Add session distribution to the AI Governance m... (!258249 - merged)) tototalSessions,totalDevelopersandslices { name sessions developers }. - Reads ClickHouse only, like
aiGovernanceSessionsin Add aiGovernanceSessions GraphQL field (!257545 - merged). Null whileai_governance_dashboard_chartsis off.
What we're building and how
What. One card that answers "which AI agents are developers using?". The Show control picks the view:
- All agents: one slice per agent, with every GitLab Duo session as one "GitLab Duo" slice.
- DAP: GitLab Duo sessions only, one slice per flow (Chat, Code review, and so on).
- Connected: external agents only, one slice per agent type (Claude Code, OpenCode).
A slice is the number of developers who used that agent or flow. The center is the number of developers across the whole view.
What "X developers" means. The number of distinct users who started at least one AI session in the group or project during the selected 7 or 30 days. A person counts once in the center even if they used several agents, and once in each slice they used, so the slices can add up to more than the center.
How it's calculated. One ClickHouse query over siphon_ai_governance_sessions, the replica of ai_governance_sessions. It takes the latest version of each session, drops deleted ones, keeps the sessions under the group or project path that started in the window, and returns each slice's sessions and distinct developers plus the exact totals in the same pass.
Out of scope. Flow labels use the dashboard's existing humanized names. Using the flows' own display names across the dashboard is a follow-up.
Data notes
- The PostgreSQL reader from Add session distribution to the AI Governance m... (!258249 - merged) is removed. Self-managed instances without ClickHouse get an empty chart until the PostgreSQL sessions finder (Add finder for AI governance sessions (!257556 - merged)) lands.
- A session counts as GitLab Duo only when its source is
gitlab_duoand it has noagent_type. Until Update the external agent session API to use ai... (!257427 - merged) merges, glab sessions are synced from workflows with sourcegitlab_duoand anagent_type, so this keeps them under their agent. - External agent slices fill once Update the external agent session API to use ai... (!257427 - merged) (glab sessions written with their own source) and Re-add ai_governance_session_id to ClickHouse a... (!258682 - merged) are on GitLab.com. Today
agent_typeisclaude-codeoropencode. - Developers are the session's user. Autonomous flows that run as a service account (behind
autonomous_service_account_execution, off by default) count that account as a developer.
ClickHouse query
SELECT
if((source = 0 AND ifNull(agent_type, '') = ''), 'gitlab_duo',
coalesce(nullIf(ifNull(agent_type, ''), ''), 'unknown')) AS name,
count() AS sessions,
uniqExact(user_id) AS developers,
grouping(name) AS is_total
FROM (
SELECT id, session_started_at,
argMax(user_id, _siphon_replicated_at) AS user_id,
argMax(source, _siphon_replicated_at) AS source,
argMax(flow_type, _siphon_replicated_at) AS flow_type,
argMax(agent_type, _siphon_replicated_at) AS agent_type,
argMax(_siphon_deleted, _siphon_replicated_at) AS deleted
FROM siphon_ai_governance_sessions
WHERE startsWith(traversal_path, {traversal_path:String})
AND session_started_at >= {from:DateTime64(6, 'UTC')}
AND session_started_at < {to:DateTime64(6, 'UTC')}
GROUP BY traversal_path, session_started_at, id
)
WHERE deleted = false
GROUP BY GROUPING SETS ((name), ())
ORDER BY is_total DESC, developers DESC, sessions DESC, name ASC
LIMIT {limit:UInt8}DAP names slices by the version-less flow type and keeps only Duo sessions; Connected names them by agent type and keeps the rest. The primary key (traversal_path, session_started_at, id) prunes on the path prefix and the time window: with 2M sessions, a group's last 7 days read 88 of 980 granules (about 40 to 100 ms), a project's read 1.
Screenshots
| All agents | DAP | Connected | All agents, dark |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
How to set up and validate locally
- Enable ClickHouse for analytics and the flags
ai_governance_dashboardandai_governance_dashboard_chartsfor a group. - Have sessions in
siphon_ai_governance_sessionsfor that group from a few users across Duo flows and external agents. - Open the group's AI Governance dashboard and switch the agent filter.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist.
Rollout notes
- The card reads
ai_governance_sessionswheneverai_governance_dashboard_chartsis on, while the tiles read that table only withai_governance_sessions_apion. Enable the charts flag only where the sessions flag is on, so the card and the tiles count the same sessions. - Without ClickHouse the card shows its empty state, while the tiles fall back to PostgreSQL. The flag is wip and off by default; a ClickHouse-off message is a follow-up.
- Developers can use several agents, so the slices can add up to more than the total. Percentages are computed against the distinct developer total.



