Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions docs/PLUGIN-VALIDATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,22 @@ job); layer 6 covers what can't live in the Rust test harness.
### 1. Schema validation (cargo test)

JSON artifacts in the bundles are validated against vendored JSON Schemas in
`tests/fixtures/cursor-schemas/`:
`tests/fixtures/cursor-schemas/` (Cursor/Codex shapes) and
`tests/fixtures/claude-schemas/` (Claude Code shapes):

| Artifact | Schema | Test |
|---|---|---|
| `plugin/.cursor-plugin/plugin.json` | `plugin.schema.json` | `tests/agent_suite/plugin_manifest_schema_test.rs` |
| `plugin/.codex-plugin/plugin.json` | `plugin.schema.json` + `interface` extension | `tests/agent_suite/plugin_manifest_schema_test.rs` |
| `plugin/.claude-plugin/marketplace.json` | `marketplace.schema.json` | vendored for refresh parity |
| `plugin/mcp-cursor.json` (deploys as `mcp.json`) | `mcp.schema.json` | `tests/agent_suite/plugin_config_schema_test.rs` |
| `plugin/hooks/hooks-cursor.json` and `plugin/hooks/hooks-codex.json` | `hooks.schema.json` | `tests/agent_suite/plugin_config_schema_test.rs` |
| `plugin/.cursor-plugin/plugin.json` | `cursor-schemas/plugin.schema.json` | `tests/agent_suite/plugin_manifest_schema_test.rs` |
| `plugin/.codex-plugin/plugin.json` | `cursor-schemas/plugin.schema.json` + `interface` extension | `tests/agent_suite/plugin_manifest_schema_test.rs` |
| `plugin/.claude-plugin/plugin.json` | `claude-schemas/plugin.schema.json` | `tests/agent_suite/claude_plugin_schema_test.rs` |
| `plugin/.claude-plugin/marketplace.json` | `claude-schemas/marketplace.schema.json` | `tests/agent_suite/claude_plugin_schema_test.rs` |
| `plugin/mcp-cursor.json` (deploys as `mcp.json`) | `cursor-schemas/mcp.schema.json` | `tests/agent_suite/plugin_config_schema_test.rs` |
| `plugin/hooks/hooks-cursor.json` and `plugin/hooks/hooks-codex.json` | `cursor-schemas/hooks.schema.json` | `tests/agent_suite/plugin_config_schema_test.rs` |
| `plugin/hooks/hooks-claude.json` | `claude-schemas/hooks.schema.json` | `tests/agent_suite/claude_plugin_schema_test.rs` |

(The Cursor `marketplace.schema.json` stays vendored for refresh parity; the
Claude marketplace uses its own schema above because Claude entries carry
fields — `category`, `homepage` — that Cursor's marketplace schema rejects.)

The tests use the `jsonschema` crate (dev-dependency only, no network
resolvers — the schemas are self-contained draft-07, and the shipped binary
Expand Down
72 changes: 72 additions & 0 deletions plugin/skills/diagnosing-analytics/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
name: diagnosing-analytics
description: 'Use when checking TraceDecay adoption or telemetry health — usage analytics, silent hooks, stale hook logs, or empty analytics tables. Uses the analytics, doctor, and sessions CLI, never raw database queries.'
---

# Diagnosing TraceDecay analytics

TraceDecay records three telemetry streams: durable `analytics_events` in the
user-level global store (`mcp_tool_call` rows from the MCP server,
`hook_route` rows from daemon routing, and `hook_<agent>` rows bridged from
hook logs), append-only `hook_analytics.jsonl` files (one per project store
plus a user-level fallback for hooks that could not resolve a project), and
the per-project session store used for message-level usage. Adoption and
health questions are answered from the durable table — never by opening
store databases directly.

## Commands

1. **`tracedecay analytics diagnostics`** — the one-stop summary. Imports any
new hook-log rows into the durable table first, then prints event, tool,
and hook counts, the TraceDecay tool-call count, per-tool/per-hook rollups,
`hook_sources` with per-file row counts, and usage ratios. Flags:
`--all` (every project, not just the current one), `--no-sync` (skip the
import pass; read-only).
2. **`tracedecay analytics sync`** — run only the hook-log import and report
how many rows each source contributed.
3. **`tracedecay doctor`** — per-agent install health: hook registration, MCP
config, binary staleness. Run this first when a hook seems silent
(Codex hooks may exist but stay skipped until trusted in Codex's own
hooks approval prompt).
4. **`tracedecay tool lcm_status --provider all --json`** and
**`tracedecay tool lcm_doctor --provider codex --mode diagnose --json`** —
session-store ingest and compression health per provider.
5. **`tracedecay sessions search "mcp__tracedecay" --provider all`** — find
tool usage evidence inside ingested transcripts across providers.
6. **`tracedecay gain`** / **`tracedecay cost`** — token savings ledger and
spend rollups.
7. **Dashboard**: `tracedecay dashboard` serves the same summaries at
`/api/plugins/analytics/overview|diagnostics|usage|hints`.

## Reading the diagnostics output

- `source: "analytics_events"` means durable data answered; a
`session_messages_and_hook_analytics` source means no durable events matched
and the summary fell back to hook logs only.
- `hook_sources` lists each hook-log file with `rows_total` vs
`rows_included`. A large gap means rows written before project attribution
existed; they are visible under `--all` but cannot be assigned to a project.
- `project_id: null` means the command ran outside an indexed project and
reported globally. Run from an indexed project root for per-project scope,
or pass `--all` deliberately.
- `import.imported` greater than zero means a hook-log backlog was just
bridged — re-read the counts, they include it.
- A high hook-call count with a low TraceDecay tool-call count is an adoption gap:
hooks fire, but sessions are not using tracedecay tools. Check
`by_prompt_category` to see which task types miss it.

## Guardrails

- A zero-row `analytics_events` table inside a project store is not evidence
that telemetry is broken — durable events live in the user-level store. Run
`tracedecay analytics diagnostics` before concluding anything is dead.
- Never query store databases with sqlite3 or scripts; schemas are internal.
The diagnostics JSON already merges every relevant source.
- If the MCP transport is down, every command above still works — they are
plain CLI subcommands (see `tracedecay:using-the-cli`).

## Output

- Headline counts (events, MCP tool calls, tracedecay calls, hook calls) with
the exact command used, plus any gaps found: unattributed hook rows, stale
or missing sources, providers with hooks firing but zero tool usage.
2 changes: 1 addition & 1 deletion src/agents/claude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1589,7 +1589,7 @@ mod tests {
.collect();

let skills = plugin_subdir_names("skills");
assert_eq!(skills.len(), 29, "expected 29 shared skill dirs");
assert_eq!(skills.len(), 30, "expected 30 shared skill dirs");
// Every file under plugin/skills/ (SKILL.md *and* any support files) is
// deployed — the recursive embed leaves nothing on disk unwired.
let skills_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("plugin/skills");
Expand Down
2 changes: 1 addition & 1 deletion src/agents/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1549,7 +1549,7 @@ mod tests {
.map(|entry| entry.file_name().to_string_lossy().into_owned())
.collect();
skill_dirs.sort();
assert_eq!(skill_dirs.len(), 29, "expected 29 shared skill dirs");
assert_eq!(skill_dirs.len(), 30, "expected 30 shared skill dirs");
// Every file under plugin/skills/ (SKILL.md *and* any support files) is
// deployed — the recursive embed leaves nothing on disk unwired.
for relative in skill_tree_files(&skills_root) {
Expand Down
10 changes: 5 additions & 5 deletions src/agents/plugin_bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
//! agent format.
//!
//! Layout of `plugin/`:
//! - `plugin/skills/*/SKILL.md` — the 16 shared model-invocable skills **plus**
//! the 13 canonical (`claude`/`codex`) workflow dispatcher skills (29 total).
//! Cursor deploys only the 16 model-invocable skills (not the dispatcher
//! - `plugin/skills/*/SKILL.md` — the 17 shared model-invocable skills **plus**
//! the 13 canonical (`claude`/`codex`) workflow dispatcher skills (30 total).
//! Cursor deploys only the 17 model-invocable skills (not the dispatcher
//! skills); its explicit dispatch is native commands (below).
//! - `plugin/overlays/cursor/commands/tracedecay-*.md` — Cursor 1.6+ native
//! slash commands, one per workflow slug, deployed to `commands/<slug>.md`.
Expand Down Expand Up @@ -235,7 +235,7 @@ fn compose(
}

/// Files Claude deploys: manifest + Claude agents + Claude commands + every
/// skill file (all 29 skills incl. dispatchers, plus any support files).
/// skill file (all 30 skills incl. dispatchers, plus any support files).
pub fn claude_files() -> Vec<(&'static str, &'static str)> {
compose(
&[
Expand All @@ -262,7 +262,7 @@ pub fn cursor_files() -> Vec<(&'static str, &'static str)> {
)
}

/// Files Codex deploys: manifest + every skill file (all 29 skills incl.
/// Files Codex deploys: manifest + every skill file (all 30 skills incl.
/// dispatchers, plus any support files). Codex ships no agents/commands/rules.
pub fn codex_files() -> Vec<(&'static str, &'static str)> {
compose(&[CODEX_MANIFEST_FILES], all_skill_files())
Expand Down
Loading
Loading