Skip to content

Commit 9b0e4aa

Browse files
committed
feat: $skill mentions — full backend + frontend + CLI
1 parent 6c14ea1 commit 9b0e4aa

22 files changed

Lines changed: 4999 additions & 1580 deletions

File tree

‎.opencode/agent/docs.md‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
description: ALWAYS use this when writing docs
3+
color: "#38A3EE"
4+
---
5+
6+
You are an expert technical documentation writer
7+
8+
You are not verbose
9+
10+
Use a relaxed and friendly tone
11+
12+
The title of the page should be a word or a 2-3 word phrase
13+
14+
The description should be one short line, should not start with "The", should
15+
avoid repeating the title of the page, should be 5-10 words long
16+
17+
Chunks of text should not be more than 2 sentences long
18+
19+
Each section is separated by a divider of 3 dashes
20+
21+
The section titles are short with only the first letter of the word capitalized
22+
23+
The section titles are in the imperative mood
24+
25+
The section titles should not repeat the term used in the page title, for
26+
example, if the page title is "Models", avoid using a section title like "Add
27+
new models". This might be unavoidable in some cases, but try to avoid it.
28+
29+
Check out the /packages/web/src/content/docs/docs/index.mdx as an example.
30+
31+
For JS or TS code snippets remove trailing semicolons and any trailing commas
32+
that might not be needed.
33+
34+
If you are making a commit prefix the commit message with `docs:`
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# CEO Plan: $skill Mentions — Manual Skill Inclusion
2+
3+
Generated by /plan-ceo-review on 2026-03-19
4+
Branch: prax-dev | Mode: SCOPE EXPANSION
5+
Repo: praxstack/opencode
6+
7+
## Vision
8+
9+
### 10x Check
10+
The 10x version is a **full skill workspace** — not just `$mention` but a complete skill management system. Users curate per-project skill profiles, skills compose with each other, the system learns which skills work best for which tasks. `$` becomes the entry point to a rich skill ecosystem, not just a one-shot loader. Skill presets, usage analytics, conflict detection, and a skill marketplace.
11+
12+
### Platonic Ideal
13+
The user opens a session. A small badge strip shows 3 skills auto-loaded for this project (from `.opencode/skills.json`). They type `$` and a beautiful popover shows all skills — grouped by category, with usage frequency indicators. They select `$brainstorming` and it appears as a warm-toned pill. The skill persists for the session. They can see via "skill trace" metadata exactly how the skill affected behavior. When they find a great combo (`$brainstorming` + `$tdd`), they save it as a **skill preset**. The next developer on the project gets those skills suggested. The system **feels** like having a mentor who knows exactly what tools to bring to each conversation.
14+
15+
## Implementation Approach
16+
17+
**Approach B: Server-Side Skill State** — full persistence via SessionSkills Effect service (like SessionSteer), new SQL table, sync channel. Skills survive page reload, visible across CLI/web/desktop.
18+
19+
### Architecture
20+
21+
```
22+
┌─────────────────────────────────────────────────────────────────┐
23+
│ FRONTEND (SolidJS) │
24+
│ │
25+
│ prompt-input.tsx slash-popover.tsx │
26+
│ ┌────────────┐ $ or Cmd+Shift+S ┌──────────────────┐ │
27+
│ │ Editor │ ──────────────────▶ │ PromptPopover │ │
28+
│ │ (pills + │ │ mode="skill" │ │
29+
│ │ tooltip) │ ◀── select ──────── │ [Recent] [All] │ │
30+
│ └────────────┘ │ [Empty state] │ │
31+
│ │ └──────────────────┘ │
32+
│ │ submit │
33+
│ ▼ │
34+
│ prompt context (ContentPart[]) badge-strip │
35+
│ [SkillPart, SkillPart, TextPart] ┌──────────────────┐ │
36+
│ │ │ [skill ×] [skill ×]│ │
37+
│ │ │ + context warning │ │
38+
│ │ POST /session/:id/chat └──────────────────┘ │
39+
└───────┼───────────────────────────────────┼───────────────────────┘
40+
│ │ POST/DELETE /session/:id/skill
41+
▼ ▼
42+
┌─────────────────────────────────────────────────────────────────┐
43+
│ BACKEND (Effect) │
44+
│ │
45+
│ session.ts (routes) SessionSkills (Effect service) │
46+
│ ┌────────────────┐ ┌────────────────────────┐ │
47+
│ │ POST /:id/skill│ ────────▶ │ .add(sessionID, name) │ │
48+
│ │ DELETE /:id/ │ │ .remove(sessionID, name)│ │
49+
│ │ skill/:name │ │ .list(sessionID) │ │
50+
│ │ GET /:id/skill │ │ .clear(sessionID) │ │
51+
│ └────────────────┘ └───────────┬────────────┘ │
52+
│ │ │
53+
│ prompt.ts │ SQL │
54+
│ ┌────────────────────┐ ▼ │
55+
│ │ createUserMessage() │ ┌──────────────────────────┐ │
56+
│ │ → extract SkillPart│ │ session_skills table │ │
57+
│ │ → synthetic log │ │ session_id | skill_name │ │
58+
│ │ │ │ added_at | token_est │ │
59+
│ │ loop() │ └──────────────────────────┘ │
60+
│ │ → SessionSkills │ │
61+
│ │ .list(sessionID) │ In-memory LRU cache (5-min TTL) │
62+
│ │ → LRU cache get │ ──▶ Skill.load(name) on miss │
63+
│ │ → wrap <skill> XML │ │
64+
│ │ → append to system │ sync channel: "session_skill" │
65+
│ │ prompt array │ ──▶ frontend reads via useSync() │
66+
│ └────────────────────┘ │
67+
│ Skill.available() ← UNCHANGED │
68+
│ SystemPrompt.skills() ← UNCHANGED │
69+
│ SkillTool ← UNCHANGED │
70+
└─────────────────────────────────────────────────────────────────┘
71+
```
72+
73+
### Key Decisions
74+
75+
| Decision | Choice | Reasoning |
76+
|----------|--------|-----------|
77+
| Caching strategy | In-memory LRU with 5-min TTL | Fast after first load, handles edits within 5 min, evicts on session end |
78+
| $ regex guard | Require whitespace/SOL before `$`, exclude `$$` | Prevents false positives with bash `$$` and `$VAR` in shell mode |
79+
| `$-removal` scope | Only removes user-added skills (session_skills table) | Don't interfere with AI auto-loaded skills |
80+
| Shortcut focus guard | `Cmd+Shift+S` only fires when prompt editor focused | Prevents accidental triggers from message history |
81+
82+
## Scope Decisions
83+
84+
| # | Proposal | Effort | Decision | Reasoning |
85+
|---|----------|--------|----------|-----------|
86+
| 1 | Skill preview tooltip (hover to see description) | S | ACCEPTED | 10 min CC, makes pills feel alive |
87+
| 2 | Recent skills section in popover (last 5 used) | S | ACCEPTED | Data free with Approach B, intelligent picker |
88+
| 3 | Keyboard shortcut `Cmd+Shift+S` | S | ACCEPTED | 10 min CC, keyboard-first UX |
89+
| 4 | Skill categories in popover (group by source) | S | DEFERRED | Flat list fine for v1 |
90+
| 5 | Context budget warning toast (>30K tokens) | S | ACCEPTED | Prevents subtle context cliff |
91+
| 6 | Empty state UX (no skills installed) | S | ACCEPTED | 5 min CC, design hygiene |
92+
93+
## Accepted Scope (added to plan)
94+
- Core: `$` prefix detection, skill popover, pill creation, badge strip, `$-removal` syntax
95+
- Core: Server-side persistence via SessionSkills Effect service + session_skills SQL table
96+
- Core: System prompt injection with `<skill>` XML tags + dedup with auto-loaded
97+
- Core: CLI `$name` prefix parsing
98+
- Expansion 1: Skill preview tooltip on hover (pills + badge strip)
99+
- Expansion 2: Recent skills section at top of popover (last 5 from session_skills)
100+
- Expansion 3: `Cmd+Shift+S` keyboard shortcut to open skill picker
101+
- Expansion 5: Context budget warning toast when estimated tokens exceed 30K
102+
- Expansion 6: Empty state UX in popover when no skills are installed
103+
- Fix: `$$` guard in regex, shell mode guard, focus guard on shortcut, ParseError handling
104+
105+
## Deferred to TODOS.md
106+
- Skill categories in popover (group by source directory) — revisit when skill count commonly exceeds 20
107+
- Skill presets (save/load skill combos) — Phase 2
108+
- Per-project skill profiles (`.opencode/skills.json`) — Phase 2
109+
- Skill marketplace / install-from-web — Phase 3
110+
- Skill analytics / usage patterns — Phase 3
111+
- Skill composition (skill A references skill B) — research needed
112+
- Refactor `handleInput()` conditional chain to dispatch table — separate PR
113+
114+
## Dream State Delta
115+
This plan gets us to **~40% of the 12-month ideal.** Foundation: user-initiated loading, server persistence, badge strip, removal, recent skills, tooltip, shortcut, budget warning, empty state. Remaining: presets, per-project profiles, marketplace, analytics, composition.
116+
117+
## Design Specifications (from /plan-design-review)
118+
119+
### Popover Layout
120+
```
121+
┌─────────────────────────────┐
122+
│ ⌕ Filter... │ ← search input (auto-focused)
123+
├─────────────────────────────┤
124+
│ RECENT │ ← text-color-dimmed header
125+
│ ★ brainstorming │
126+
│ ★ tdd │
127+
├─────────────────────────────┤
128+
│ ALL SKILLS │ ← text-color-dimmed header
129+
│ api-design │
130+
│ brainstorming │
131+
│ clean-code │
132+
│ ... │
133+
└─────────────────────────────┘
134+
Max-width: 400px. Skeleton shimmer (3 rows) on first load.
135+
```
136+
137+
### Empty State
138+
```
139+
┌─────────────────────────────┐
140+
│ 💡 No skills installed │
141+
│ │
142+
│ Skills customize how the │
143+
│ AI works — add them to │
144+
│ ~/.claude/skills/ │
145+
│ │
146+
│ 📚 Browse available skills │
147+
└─────────────────────────────┘
148+
```
149+
150+
### Interaction State Table
151+
```
152+
FEATURE | LOADING | EMPTY | ERROR | SUCCESS
153+
---------------------|-----------------|-----------------|-----------------|--------
154+
$ Popover | Skeleton shimmer| 💡 Empty state | N/A (local) | Skill list
155+
Badge strip | N/A | Hidden | N/A | [skill ×]
156+
Skill pill | N/A | N/A | N/A | $name pill
157+
Tooltip (hover) | "Loading..." | N/A | "Unavailable" | Rich popover
158+
Context warning | N/A | N/A | N/A | ⚠️ toast
159+
```
160+
161+
### Color Tokens
162+
- Skill pill text: `text-syntax-string` (warm/amber — distinct from file=property, agent=type)
163+
- Section headers: `text-color-dimmed`
164+
- Badge strip: matches steer queue badge styling
165+
- Popover: inherits `PromptPopover` theme
166+
167+
### Rich Tooltip Popover (on hover)
168+
- 300ms hover delay, disappears on mouse leave
169+
- Shows: skill name (bold), description (2-3 lines), source path (dimmed), token estimate (dimmed)
170+
- `role="tooltip"` + `aria-describedby` linking
171+
172+
### Accessibility
173+
- Badge `×` buttons: `aria-label="Remove skill {name}"`, min 44x44px touch target
174+
- Popover: `role="listbox"` + `aria-label="Select a skill"`
175+
- Keyboard: arrows navigate, Enter selects, Escape closes (inherited from PromptPopover)
176+
177+
## Review Status
178+
- CEO Review: CLEAR (2026-03-19, SCOPE EXPANSION, 0 critical gaps)
179+
- Eng Review: CLEAR (2026-03-19, FULL_REVIEW, 0 critical gaps)
180+
- Design Review: CLEAR (2026-03-19, 6/10 → 9/10, 2 decisions made)

0 commit comments

Comments
 (0)