Skip to main content

claudex_cli/skill/
templates.rs

1//! Content templates for the claudex agent skill.
2//!
3//! One shared markdown body is wrapped in target-specific frontmatter so each
4//! harness gets a header it understands:
5//! - Claude Code / Codex / Pi / OpenClaw: `SKILL.md` (YAML frontmatter + markdown)
6//! - AGENTS.md: plain markdown wrapped in idempotency markers
7//! - Claude Code plugin: `plugin.json` (JSON manifest, no frontmatter)
8//!
9//! `command_list` is derived from the live clap command tree so the skill never
10//! drifts from the real CLI.
11
12/// Markers bounding the claudex block inside a shared `AGENTS.md`, so the block
13/// is replaced in place rather than duplicated on re-runs.
14pub const AGENTS_START: &str = "<!-- claudex:start -->";
15pub const AGENTS_END: &str = "<!-- claudex:end -->";
16
17/// Frontmatter flavor for a generated `SKILL.md`.
18#[derive(Debug, Clone, Copy)]
19pub enum Flavor {
20    /// Claude Code: supports `allowed-tools` + `argument-hint`.
21    ClaudeCode,
22    /// OpenAI Codex CLI: minimal Agent Skills subset.
23    Codex,
24    /// Pi coding agent: Agent Skills subset plus `allowed-tools`.
25    Pi,
26    /// OpenClaw: Agent Skills frontmatter, project/global `skills/` layout.
27    OpenClaw,
28}
29
30/// One-line skill description, reused by every frontmatter generator.
31pub fn description() -> &'static str {
32    "Query, search, and analyze Claude Code, OpenAI Codex, GitHub Copilot, Pi, and OpenClaw sessions using the claudex CLI. \
33Use when asked about session history, token costs, tool usage, search past conversations, export \
34sessions, or inspect agent activity across providers and projects."
35}
36
37/// A concise, always-accurate list of top-level commands, derived from the clap
38/// command tree so it never drifts from the real CLI.
39pub fn command_list(root: &clap::Command) -> String {
40    let mut lines = Vec::new();
41    for sub in root.get_subcommands() {
42        if sub.is_hide_set() {
43            continue;
44        }
45        let name = sub.get_name();
46        let about = sub
47            .get_about()
48            .map(|about| about.to_string())
49            .unwrap_or_default();
50        lines.push(format!("- `claudex {name}` — {about}"));
51    }
52    lines.join("\n")
53}
54
55/// The shared markdown body (everything after the frontmatter).
56fn body(command_list: &str) -> String {
57    format!(
58        r#"# claudex — multi-provider agent session analytics
59
60claudex indexes the local session transcripts of six coding agents into a
61SQLite database at `~/.claudex/index.db` and reports across all of them:
62
63- **Claude Code** — `~/.claude/projects/**.jsonl`
64- **OpenAI Codex** — `~/.codex/sessions/**` and `~/.codex/archived_sessions/`
65- **GitHub Copilot CLI** — `~/.copilot/session-state/*/events.jsonl`
66- **VS Code Copilot Chat** — VS Code `workspaceStorage/*/chatSessions/` (stable + Insiders)
67- **Pi** — `~/.pi/agent/sessions/**`
68- **OpenClaw** — `${{OPENCLAW_STATE_DIR:-~/.openclaw}}/agents/*/sessions/`
69
70Every reporting command spans all six providers by default. The index is
71**additive**: sessions archived or deleted from disk are retained, so historical
72usage never disappears.
73
74## Commands
75
76{command_list}
77
78Run `claudex <command> --help` for full flags.
79
80## Filtering
81
82| Flag | Effect |
83| --- | --- |
84| `--provider <claude\|codex\|copilot\|copilot-vscode\|pi\|openclaw>` | Restrict indexed reports to provider(s); repeatable or comma-separated. Default: all. |
85| `--model <substr>` | Filter indexed reports by model (e.g. `opus`, `gpt-5`). |
86| `--since <when>` / `--until <when>` | Date range. Accepts `YYYY-MM-DD`, RFC3339, or a relative span (`7d`, `12h`, `2w`). |
87| `--on-disk-only` | Exclude retained sessions whose file was archived/deleted. |
88| `--project <substr>` | Filter by project path substring on commands that expose project scoping. |
89| `--json` | Machine-readable output. Row-oriented reports include a `provider` key per row. |
90| `--no-index` | Scan Claude transcripts directly; this rejects non-Claude providers. |
91
92Provider/date/model filters work on indexed reporting commands including
93`summary`, `sessions`, `cost`, `tools`, `models`, `search`, `turns`, `prs`, and
94`files`. Session drill-down resolves OpenClaw/Codex/Pi sessions through indexed
95records. Use `--no-index` only for Claude transcript recovery/debugging.
96
97## When to use
98
99- "How much have I spent on Codex this month?" → `claudex cost --provider codex --since 30d`
100- "What would my Copilot usage cost at API rates?" → `claudex cost --provider copilot --since 30d`
101- "List my recent Pi sessions" → `claudex sessions --provider pi`
102- "Search OpenClaw trajectory-backed sessions" → `claudex search "tool timeout" --provider openclaw --json`
103- "Find where I discussed schema migrations" → `claudex search "schema migration"`
104- "What did session e1a2f4 do?" → `claudex session e1a2f4`
105- "Overall dashboard" → `claudex summary`
106- "Model cost breakdown across providers" → `claudex models`
107
108## Output for agents
109
110Add `--json` to any reporting command for stable, scriptable output. Each row
111carries a `"provider"` key so results are unambiguous across providers. Cost is
112in USD; Pi/OpenClaw sessions report the provider's own per-message cost when
113available (local models are $0), Claude/Codex/Copilot are priced from a built-in
114per-model table (Copilot is subscription-billed, so its USD figure is an
115API-equivalent estimate; VS Code Copilot Chat stores no token counts and
116reports $0).
117
118## Notes
119
120- The index refreshes automatically (staleness window 5 min); `claudex index`
121  forces a sync, `claudex index --force` wipes and rebuilds (the only path that
122  discards retained data).
123- Worktree sessions roll up to their parent project; Claude subagent transcripts
124  roll up to their parent session.
125"#
126    )
127}
128
129/// Render a `SKILL.md` with target-specific frontmatter.
130pub fn skill_md(flavor: Flavor, command_list: &str) -> String {
131    let description = description();
132    let frontmatter = match flavor {
133        Flavor::ClaudeCode => format!(
134            "---\nname: claudex\ndescription: {description}\nargument-hint: [subcommand or query]\nallowed-tools: Bash(claudex:*), Read, Glob, Grep\nlicense: MIT\n---\n"
135        ),
136        Flavor::Codex => format!("---\nname: claudex\ndescription: {description}\n---\n"),
137        Flavor::Pi => format!(
138            "---\nname: claudex\ndescription: {description}\nallowed-tools: Bash(claudex:*)\nlicense: MIT\n---\n"
139        ),
140        Flavor::OpenClaw => format!("---\nname: claudex\ndescription: {description}\n---\n"),
141    };
142    format!("{frontmatter}\n{}", body(command_list))
143}
144
145/// Render the `AGENTS.md` block, wrapped in idempotency markers.
146pub fn agents_block(command_list: &str) -> String {
147    format!(
148        r#"{AGENTS_START}
149## claudex — agent session analytics
150
151Use the `claudex` CLI to query and analyze local Claude Code, OpenAI Codex,
152GitHub Copilot (CLI + VS Code), Pi, and OpenClaw session transcripts: token
153cost, tool usage, full-text search, per-session drill-down, and exports —
154across all six providers from one index.
155
156- **Spans providers by default;** narrow with `--provider claude|codex|copilot|copilot-vscode|pi|openclaw`.
157- **Filter** with `--project`, `--model`, `--since`/`--until` (`7d`/`2w`/dates).
158- **JSON for agents:** add `--json`; every row carries a `provider` key.
159- The index is additive — archived/deleted sessions are retained.
160
161Commands:
162
163{command_list}
164
165Run `claudex --help` or `claudex <command> --help` for full flags.
166{AGENTS_END}"#
167    )
168}
169
170/// Render a Claude Code plugin manifest (`.claude-plugin/plugin.json`).
171pub fn plugin_json() -> String {
172    let manifest = serde_json::json!({
173        "name": "claudex",
174        "description": description(),
175        "version": env!("CARGO_PKG_VERSION"),
176        "author": { "name": "James Brink" },
177        "homepage": "https://utensils.io/claudex/",
178        "repository": "https://github.com/utensils/claudex",
179        "license": "MIT",
180        "keywords": ["claude-code", "codex", "copilot", "pi", "openclaw", "cli", "agents", "sessions"],
181    });
182    serde_json::to_string_pretty(&manifest).unwrap_or_default()
183}