omnidevx Integration¶
This document describes how omnidevx-core joins with PRISM Control to attribute per-session token usage and effort to initiatives.
Join Model¶
omnidevx-core collects Claude Code session events, each carrying an
EventContext.SessionID (a UUID assigned by Claude Code to each
conversation). PRISM Control tracks work assignments with a worker
field on each assignment row.
The join between the two systems is:
When a Claude Code session claims an RMI via prismctl work claim, the
--worker value is stored in assignments.worker. If that value is the
Claude Code session UUID, omnidevx can attribute every token from that
session to the claimed RMI and, by extension, to its initiative.
Worker Auto-Detection¶
Claude Code exposes the session UUID via the CLAUDE_CODE_SESSION_ID
environment variable. When claiming work, prismctl auto-detects this:
# The session UUID is automatically used when CLAUDE_CODE_SESSION_ID is set
prismctl work claim RMI-MYREPO-042 --lease-hours 4
# Or explicitly provide it if needed
prismctl work claim RMI-MYREPO-042 \
--worker "$CLAUDE_CODE_SESSION_ID" \
--lease-hours 4
The auto-detection enables seamless attribution: every token event from the claiming session is automatically attributed to the claimed RMI.
Token Attribution Reports¶
Use prismctl report tokens to generate attribution reports:
# Initiative mode: per-RMI and per-model breakdown
prismctl report tokens --initiative INIT-PRISM-001 --format markdown
# Quarter mode: all initiatives in the period
prismctl report tokens --quarter 2026-Q3
# Custom date range
prismctl report tokens --since 2026-07-01 --until 2026-07-31
# JSON output for programmatic use
prismctl report tokens --initiative INIT-PRISM-001 --format json
Reports show:
- Attributed spend: tokens/cost mapped to RMIs via session→assignment
- Residual: tokens matched to a repository but not a specific RMI
- Unmanaged: tokens from workspaces not in the registry
- Coverage: managed spend ÷ total spend
Legacy Worker IDs¶
Prior to auto-detection, sessions used timestamp-based IDs like
"session-$(date +%s)". These don't match Claude Code session UUIDs
and won't attribute correctly. Update old assignments or re-claim work
with the proper session UUID to enable attribution.
SQL View¶
The v_assignment_sessions view (defined in docs/sql/omnidevx-views.sql)
flattens the assignment-to-initiative path into a single row:
| Column | Source | Description |
|---|---|---|
| assignment_id | assignments.assignment_id | Unique assignment ID |
| rmi_id | roadmap_items.rmi_id | Roadmap Item ID |
| initiative_id | roadmap_items.initiative_roadmap_items | Parent initiative ID |
| worker | assignments.worker | Session ID / worker identifier |
| workspace | assignments.workspace | Optional workspace path |
| status | assignments.status | Assignment status |
| created_at | assignments.created_at | When the assignment was created |
| completed_at | assignments.completed_at | When the assignment was completed |
Example Join Query¶
Given a set of omnidevx events loaded into a session_tokens table (or
computed in-memory), join against the view to get per-initiative totals:
SELECT
vas.initiative_id,
SUM(st.input_tokens) AS total_input_tokens,
SUM(st.output_tokens) AS total_output_tokens,
SUM(st.cost_usd) AS total_cost,
COUNT(DISTINCT st.session_id) AS session_count
FROM v_assignment_sessions vas
JOIN session_tokens st
ON vas.worker = st.session_id
GROUP BY vas.initiative_id;
In Go, the equivalent join is done in-memory: build a
map[string]string (session ID to initiative ID) from the view rows,
then pass it to report.InitiativeReportFromEvents() in omnidevx-core.