Background
Recall now stores structured session_events from AI coding sessions. The current event contract is already useful for command/tool/file analytics, but skill usage is still inferred indirectly.
Current observed event kinds in the local index include:
command
file_read
file_write
search
session_meta
tool_call
tool_result
turn
Skill usage currently appears in two incomplete ways:
- High-confidence Claude Code events where
name = 'Skill' and attrs_json.skill is present.
- Medium-confidence traces where an event references a path like
~/.agents/skills/<skill>/SKILL.md.
This makes it possible to approximate skill usage, but not to answer product questions reliably across adapters.
Problem
Recall cannot currently represent "a skill was invoked" as a first-class event.
As a result:
- Skill usage rankings are adapter-specific and inconsistent.
- Codex skill usage can only be inferred from file reads, command args, or session text.
- Reading a skill file is mixed with actually invoking a skill.
tool_call analytics are polluted with Skill as a generic tool name.
- It is hard to correlate skill usage with outcomes such as tests run, corrections, token use, or project/session patterns.
Example current ambiguity:
pre-ship may appear thousands of times by path-reference / file-read traces.
verification-before-completion may be the top explicit Claude Code Skill call.
- These are different semantics, but Recall has no normalized event kind to distinguish them.
Proposal
Add a normalized event kind:
This event should represent evidence that a skill was intentionally invoked or selected for a session/task.
Proposed event contract
For session_events rows with kind = 'skill_invocation':
| Field |
Proposed semantics |
kind |
Always skill_invocation |
actor |
Usually user, assistant, or system, depending on who initiated/selected the skill |
name |
Canonical skill name, e.g. pre-ship, codex-review, vibe-calibrate |
target |
Skill definition path when known, e.g. /Users/x/.agents/skills/pre-ship/SKILL.md |
status |
Optional: started, completed, failed, inferred, or source-native status if available |
message_seq |
User/assistant message that triggered the skill when known |
summary |
Short human-readable invocation summary, not the full skill body |
source_event_id |
Source-native call id / line id when available |
attrs_json |
Structured metadata for attribution and confidence |
Suggested attrs_json shape:
{
"skill": "pre-ship",
"trigger": "explicit_slash",
"confidence": "high",
"evidence": "user_message",
"raw_name": "Skill",
"args": "--committed"
}
Suggested fields:
| attr |
Meaning |
skill |
Canonical skill name, duplicated from name for JSON consumers |
trigger |
explicit_slash, explicit_dollar, tool_call, skill_file_read, session_text, inferred |
confidence |
high, medium, low |
evidence |
Where the attribution came from: tool_event, user_message, assistant_message, file_path, command_target, etc. |
raw_name |
Source-native tool/function name, e.g. Skill |
args |
Optional skill invocation args, if source exposes them |
path |
Optional skill path, if known |
Attribution confidence rules
High confidence
Create skill_invocation with confidence = high when any of these are true:
- Source-native event explicitly records a skill call, e.g. Claude Code
name = 'Skill' and attrs_json.skill exists.
- User explicitly invokes a skill by name, e.g.
/skill:pre-ship, $vibe-calibrate, or equivalent known syntax.
- A source has a dedicated skill/tool invocation envelope.
Medium confidence
Create skill_invocation with confidence = medium when:
- The agent reads a canonical skill definition path such as
~/.agents/skills/<skill>/SKILL.md and the read occurs near the start of a task or shortly after a user request.
- A command/tool target references a skill path in a way that strongly indicates loading that skill.
Low confidence
Do not create a default skill_invocation for low-confidence pattern matches unless we explicitly decide to support inferred analytics.
Potential low-confidence signals:
- Session text mentions a skill name without invocation syntax.
- Workflow resembles a skill but no direct skill evidence exists.
If low-confidence inference is ever added, it should be clearly marked confidence = low and excluded from default rankings.
Adapter notes
Claude Code
Current source evidence exists today:
session_events.name = 'Skill'
attrs_json.skill = '<skill-name>'
The adapter can emit skill_invocation directly instead of only a generic tool_call, or emit both if backward compatibility is desired.
Codex
Codex currently needs inference from:
- User syntax such as
$vibe-calibrate if captured in indexed messages.
- Reads of
/Users/x/.agents/skills/<name>/SKILL.md.
- Tool/command args that reference a skill path.
Codex should start with high-confidence explicit syntax and medium-confidence SKILL.md path reads.
OpenCode and other adapters
If a source has a source-native skill/tool concept, map it directly.
Otherwise, support only path/syntax-based attribution.
Analytics enabled by this event
Once this exists, Recall can answer:
- Top skills by invocation count.
- Top skills by distinct sessions.
- Top skills by project/source/time range.
- Skill usage before/after corrections.
- Skill usage correlated with command/test/build outcomes.
- Skills that are frequently loaded but rarely explicitly invoked.
- Skills that should be promoted, merged, deprecated, or converted into native Recall workflows.
Example future query:
SELECT
name AS skill,
COUNT(*) AS invocations,
COUNT(DISTINCT session_id) AS sessions
FROM session_events
WHERE kind = 'skill_invocation'
AND json_extract(attrs_json, '$.confidence') IN ('high', 'medium')
GROUP BY name
ORDER BY invocations DESC;
CLI / UX follow-up ideas
This issue only requires the event contract, but it should unblock later commands such as:
recall events --kind skill_invocation
recall stats skills
recall stats skills --source codex --time 30d
recall stats skills --json
Acceptance criteria
Non-goals
- Do not classify arbitrary workflow similarity as skill usage by default.
- Do not parse or copy full
SKILL.md bodies into event rows.
- Do not mutate skill files or instruction files.
- Do not make
skill_invocation depend on a specific agent vendor.
Implementation sketch
- Add a helper in
src/adapters/events.rs, for example:
pub fn skill_invocation_event(
context: EventContext,
skill: String,
trigger: SkillTrigger,
confidence: SkillConfidence,
target: Option<String>,
args: Option<String>,
) -> RawSessionEvent
- Keep
kind = 'skill_invocation', name = Some(skill.clone()), and structured metadata in attrs_json.
- Update Claude Code parsing to map native
Skill calls.
- Add Codex path/syntax attribution as a second step.
- Add regression tests in adapter tests and export tests.
- Consider a later
recall stats skills CLI after the event contract lands.
Background
Recall now stores structured
session_eventsfrom AI coding sessions. The current event contract is already useful for command/tool/file analytics, but skill usage is still inferred indirectly.Current observed event kinds in the local index include:
commandfile_readfile_writesearchsession_metatool_calltool_resultturnSkill usage currently appears in two incomplete ways:
name = 'Skill'andattrs_json.skillis present.~/.agents/skills/<skill>/SKILL.md.This makes it possible to approximate skill usage, but not to answer product questions reliably across adapters.
Problem
Recall cannot currently represent "a skill was invoked" as a first-class event.
As a result:
tool_callanalytics are polluted withSkillas a generic tool name.Example current ambiguity:
pre-shipmay appear thousands of times by path-reference / file-read traces.verification-before-completionmay be the top explicit Claude CodeSkillcall.Proposal
Add a normalized event kind:
This event should represent evidence that a skill was intentionally invoked or selected for a session/task.
Proposed event contract
For
session_eventsrows withkind = 'skill_invocation':kindskill_invocationactoruser,assistant, orsystem, depending on who initiated/selected the skillnamepre-ship,codex-review,vibe-calibratetarget/Users/x/.agents/skills/pre-ship/SKILL.mdstatusstarted,completed,failed,inferred, or source-native status if availablemessage_seqsummarysource_event_idattrs_jsonSuggested
attrs_jsonshape:{ "skill": "pre-ship", "trigger": "explicit_slash", "confidence": "high", "evidence": "user_message", "raw_name": "Skill", "args": "--committed" }Suggested fields:
skillnamefor JSON consumerstriggerexplicit_slash,explicit_dollar,tool_call,skill_file_read,session_text,inferredconfidencehigh,medium,lowevidencetool_event,user_message,assistant_message,file_path,command_target, etc.raw_nameSkillargspathAttribution confidence rules
High confidence
Create
skill_invocationwithconfidence = highwhen any of these are true:name = 'Skill'andattrs_json.skillexists./skill:pre-ship,$vibe-calibrate, or equivalent known syntax.Medium confidence
Create
skill_invocationwithconfidence = mediumwhen:~/.agents/skills/<skill>/SKILL.mdand the read occurs near the start of a task or shortly after a user request.Low confidence
Do not create a default
skill_invocationfor low-confidence pattern matches unless we explicitly decide to support inferred analytics.Potential low-confidence signals:
If low-confidence inference is ever added, it should be clearly marked
confidence = lowand excluded from default rankings.Adapter notes
Claude Code
Current source evidence exists today:
session_events.name = 'Skill'attrs_json.skill = '<skill-name>'The adapter can emit
skill_invocationdirectly instead of only a generictool_call, or emit both if backward compatibility is desired.Codex
Codex currently needs inference from:
$vibe-calibrateif captured in indexed messages./Users/x/.agents/skills/<name>/SKILL.md.Codex should start with high-confidence explicit syntax and medium-confidence
SKILL.mdpath reads.OpenCode and other adapters
If a source has a source-native skill/tool concept, map it directly.
Otherwise, support only path/syntax-based attribution.
Analytics enabled by this event
Once this exists, Recall can answer:
Example future query:
CLI / UX follow-up ideas
This issue only requires the event contract, but it should unblock later commands such as:
Acceptance criteria
session_events.kindcan containskill_invocationrows.skill_invocationevents from source-native skill evidence.$skill-name//skill:<name>style detection if present in messages, or documents why not.attrs_jsonincludes at leastskill,trigger, andconfidence.skill_invocationevents without schema breakage.Non-goals
SKILL.mdbodies into event rows.skill_invocationdepend on a specific agent vendor.Implementation sketch
src/adapters/events.rs, for example:kind = 'skill_invocation',name = Some(skill.clone()), and structured metadata inattrs_json.Skillcalls.recall stats skillsCLI after the event contract lands.