feat(tags): derive skill + agent tags from conversation analysis #2
Reference in New Issue
Block a user
Delete Branch "conv-tags"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
The tag registry only knew where work happened (
project/service/stack). This adds the other axis — what it was done with — as two newderived kinds,
skill:<name>andagent:<name>, mined from the conversationsthemselves: the
Skill(…)calls a session made and the agent types it spawned(or was launched as). Nothing new is authored: like every other tag, these exist
because something in the homelab already refers to them, and the only editable
part stays colour / glyph / description.
They're linked to conversations in both directions — a conversation's detail
header wears the skills and agents it used, and each tag's card counts the
conversations that used it, with a last-used timestamp. Skills and agents also
become composer chips, so a new or resumed session can be told to reach for
one.
Key changes
backend/main.py— conversation cards,/api/conversation-summaryand/api/conversationnow carryskillsUsedandagentsUsed._skills_by_path()joins the indexer's per-transcript skill column back ontothe summaries (a stored summary has no
skillskey — the indexer pops it intoits own column);
_agents_by_conversation()folds the existing_agent_runs()list into a conversation → agent-types map. Both memoized on the store version.
backend/schemas.py+frontend/openapi.json+frontend/src/generated/—the two new optional string lists on
ConversationSummary.frontend/src/lib/tags.ts—TagKindgainsskill/agent;useTags()foldsin the skills and agents catalogs (name, description,
sourceKind, path) andcounts one conversation per session that used them;
TagUsagegainsagents(agent definitions a project ships, mirroring the existing
skills);new
tagHref()resolves a tag's own page.frontend/src/business/conversations/components/ConvMetaBits.tsx— newSkillTags/AgentTagspills (amber wrench / emerald bot), capped at 5 with anexpanding
+N, rendered on the conversation detail header only.frontend/src/business/skills/pages/Skills.tsx— accepts?skill=<name>,narrowing the catalog to one card with a "show all skills" chip, so a skill
pill has somewhere specific to land.
frontend/src/lib/richComposer.tsx+lib/shortcuts.tsx—toolMentions()/toolTags()add a chip per skill and per agent to both composers(recently-used first, reachable via
#); selecting one appends aUse the following in this task:block to the prompt.frontend/src/business/tags/pages/Tags.tsx,CLAUDE.md,mock/seed.ts—kind filters, usage stat, docs and mock data for the new kinds.
Key decisions
_agent_runs(), not from a second pass overTaskcalls.That list already resolves both origins correctly — a subagent run keys to its
parent conversation via the child's
agent-*.meta.json, and a cron/manualagent session to the conversation it is — so a card can never disagree with
the agents page. It also meant no
PARSER_VERSIONbump and no re-parse.listed on its own, so attributing its
Skill(…)calls only to itself wouldlose them entirely.
sessions used this"; the Skills/Agents pages already own the per-invocation
arithmetic.
off the two catalogs (asked and confirmed). A built-in like
Exploreis a tagwith
exists: falseand no file to open — the same treatment a danglingproject tag gets.
— a busy session touches a dozen skills — and the list cards stay about
location.
Work in the following homelab location(s):block (asked and confirmed). A skill isn't a location; pickingone writes its own bullet instead, which is the difference between a session
invoking
open-prand one hand-rolling a PR body./skills?skill=<name>rather than a new route: a skill'sreal "detail" is its
SKILL.mdin the editor, and the catalog page alreadylinks there.
Changelog
SkillandAgenttags alongside projects, services and stacks — each with how many conversations used it and when it last ran, and the same colour/glyph/description editing#), adding a line that tells the session to use them/skills?skill=<name>)Test notes
DB and the real transcripts:
/api/conversations,/api/conversation-summaryand
/api/conversationall return the new fields; spot-checked a conversationwith 7 skills + 1 agent against its transcript, and confirmed conversations
whose skills are invoked through shell aliases (not the
Skilltool) correctlyreport none.
npx tsc --noEmitclean, production build clean, then served thebuilt
distbehind a proxy to that backend and captured the conversationdetail, both new Tags filters, and the composer's
#menu (below).Screenshots