Your objective is to generate and open the CocoMeter token attribution dashboard.
CocoPlus 2.0 Console-Aware Redirect
Before generating standalone HTML, check .cocoplus/lifecycle/console-state.json.
If the file exists and contains running: true with a port value:
- Output:
Opening Cost panel in CocoConsole. - Open
http://localhost:<port>/costin the browser. - Stop. Do not generate a standalone snapshot.
If CocoConsole is not running, continue with the standalone CocoMeter dashboard behavior below.
Pre-flight Check
Check that .cocoplus/ exists. If not:
Output: "CocoPlus not initialized. Run $pod init to begin." Then stop.
Read Attribution Data
Read .cocoplus/meter/request-map.jsonl. If the file is missing or empty, continue — the dashboard must still render with local-only data and zero Snowflake rows. Use an injected payload shaped like:
{
"local_only": true,
"rows": [],
"stages": [],
"warning": "No local CocoMeter request-map entries were found yet."
}
Partition entries into two sets:
- Direct IDs: entries where
is_subagent_anchoris absent or false - Anchor IDs: entries where
is_subagent_anchoris true
Query Snowflake Usage History
If any Direct IDs exist, execute Pass 1:
SELECT REQUEST_ID, PARENT_REQUEST_ID, USAGE_TIME, TOKENS, TOKEN_CREDITS,
TOKENS_GRANULAR, CREDITS_GRANULAR
FROM SNOWFLAKE.ACCOUNT_USAGE.CORTEX_CODE_CLI_USAGE_HISTORY
WHERE REQUEST_ID IN (<direct_ids>)
OR PARENT_REQUEST_ID IN (<direct_ids>)
ORDER BY USAGE_TIME ASC;
If Anchor IDs also exist, execute Pass 2:
SELECT REQUEST_ID, PARENT_REQUEST_ID, USAGE_TIME, TOKENS, TOKEN_CREDITS,
TOKENS_GRANULAR, CREDITS_GRANULAR
FROM SNOWFLAKE.ACCOUNT_USAGE.CORTEX_CODE_CLI_USAGE_HISTORY
WHERE PARENT_REQUEST_ID IN (<anchor_ids>)
AND REQUEST_ID NOT IN (<pass_1_request_ids>)
ORDER BY USAGE_TIME ASC;
Union Pass 1 and Pass 2 results. If either query fails (permission denied, connection error), log the error and continue with whatever was retrieved — do not abort.
Join and Aggregate
Join Snowflake rows with request-map.jsonl:
- Direct rows: match on
REQUEST_ID - Pass-2 rows: resolve
stage_idby matchingPARENT_REQUEST_IDto anchor records inrequest-map.jsonl - Unmatched rows:
stage_id = "unattributed"
Compute summary aggregations:
- Total tokens, total credits
- Cache efficiency %:
cache_read_input / (input + cache_read_input + cache_write_input) * 100 - Total output tokens
- Per-stage and per-model breakdowns
Serialise the merged dataset as JSON.
Locate the HTML Template
Locate templates/meter-view.html.template relative to the installed CocoPlus plugin root. Do not hard-code an OS-specific plugin directory.
Read the template. If missing: Output: "CocoMeter template not found in the CocoPlus plugin templates directory. Re-install or update the CocoPlus plugin." Then stop.
Inject Meter Data
Find the injection block:
- Start:
/* __METER_INJECTION_START__ */ - End:
/* __METER_INJECTION_END__ */
Replace with:
const INJECTED_METER_DATA = <serialised_json>;
Write and Open
Write the injected HTML to .cocoplus/meter-view.html atomically (write to .tmp, then rename).
Write sync metadata: .cocoplus/meter/last-sync.json:
{ "last_sync": "<ISO timestamp>", "row_count": <n> }
Open .cocoplus/meter-view.html:
- macOS:
open .cocoplus/meter-view.html - Linux:
xdg-open .cocoplus/meter-view.html - Windows:
powershell -Command "Invoke-Item '.cocoplus/meter-view.html'"
Output
With Snowflake data:
✓ CocoMeter dashboard generated.
Stages: <N> | Requests: <N> | Snowflake rows: <N>
Total tokens: <N> | Cache efficiency: <N>%
Opening: .cocoplus/meter-view.html
If Snowflake returned no rows:
⚠ No usage data from Snowflake yet.
CORTEX_CODE_CLI_USAGE_HISTORY has up to 90-minute latency.
Dashboard generated with local attribution data only.
Run $meter sync after ~90 minutes to refresh.
Opening: .cocoplus/meter-view.html
If browser open failed:
✓ CocoMeter dashboard generated.
Could not open browser automatically.
Open this file manually: .cocoplus/meter-view.html
Anti-Rationalization
| Shortcut / Temptation | Why It Fails |
|---|---|
| Abort if Snowflake query fails | Partial data is still valuable; the dashboard renders in local-only mode gracefully |
| Abort because request-map.jsonl is missing | A new project still needs a usable dashboard shell; render a local-only empty dashboard |
| Skip atomic write for meter-view.html | A mid-write crash would leave a corrupt file that the browser opens as blank |
| Skip last-sync.json update | $meter sync uses this to show when data was last refreshed |
Exit Criteria
-
.cocoplus/meter-view.htmlwritten withINJECTED_METER_DATAcontaining merged Snowflake + local data -
.cocoplus/meter/last-sync.jsonupdated with current timestamp and row count - Output reports stage count, request count, total tokens, and cache efficiency
- No git commit created (dashboard is ephemeral, gitignored)