95 lines
5.0 KiB
Markdown
95 lines
5.0 KiB
Markdown
# Session Skills — Implementation Plan
|
|
|
|
Spec: `docs/superpowers/specs/2026-07-03-session-skills-design.md`
|
|
Approach: subagent-driven TDD (sonnet), build + test + commit per task, stage files by
|
|
path (never `git add -A`).
|
|
|
|
**Pre-flight (do first, before building anything):** manual smoke test — drop a skill
|
|
into a scratch worktree's `.claude/skills/` and run `claude -p` to confirm cwd skills are
|
|
discovered in headless mode. The whole feature rests on this. If it fails, stop and
|
|
redesign around `CLAUDE_CONFIG_DIR`.
|
|
|
|
---
|
|
|
|
## Task 1 — Data layer: columns + registry table + migration
|
|
|
|
- Add nullable `SessionSkills` (string, JSON array) to `TaskEntity`, `ListConfigEntity`,
|
|
`AppSettingsEntity`; map `session_skills` columns in their `*Configuration.cs`.
|
|
- New `SessionSkillEntity` (`name` PK, `source_url`, `pinned_ref`, `subpath`,
|
|
`description`, `added_at`) — one row per skill; a multi-skill repo writes N rows sharing
|
|
`source_url`/`pinned_ref` — + configuration + `session_skills` table.
|
|
- New `SessionSkillRepository` (async, CancellationToken): `ListAsync`, `GetAsync(name)`,
|
|
`UpsertAsync`, `DeleteAsync(name)`, `DeleteBySourceAsync(url)`, `ListBySourceAsync(url)`.
|
|
- EF migration `AddSessionSkills` (columns + table).
|
|
- **Tests (Data.Tests):** repository CRUD on real SQLite; JSON column round-trips a
|
|
name list.
|
|
|
|
## Task 2 — Registry service (install / update / remove)
|
|
|
|
- `Skills/SessionSkillRegistry` + `Skills/Interfaces/ISessionSkillRegistry`,
|
|
`IRepoCloner` (clone abstraction so tests inject a local source dir).
|
|
- `GitRepoCloner` (production) does `git clone` + resolves HEAD SHA.
|
|
- Install: clone → **detect layout** (`skills/*/SKILL.md` bundle → each subskill; else
|
|
root `SKILL.md` → single; else reject) → per skill parse YAML frontmatter (`name`,
|
|
`description`), copy its dir **flat** to `~/.todo-app/session-skills/<name>/`, upsert a
|
|
row with `subpath`. Reject collision with a skill from a different source; reinstalling
|
|
the same source refreshes.
|
|
- Update(sourceUrl) / Remove(sourceUrl) per spec (act on all of a source's skills).
|
|
- **Tests (Worker.Tests):** install a **multi-skill** fixture (fake cloner, mirrors
|
|
ponytail's `skills/*/SKILL.md`) → N rows + N flat dirs; install a root-`SKILL.md`
|
|
fixture → 1 row; neither → rejected; cross-source name collision rejected;
|
|
remove-by-source deletes all its dirs + rows. **No real network / no real claude CLI.**
|
|
|
|
## Task 3 — Resolution: union into ClaudeRunConfig
|
|
|
|
- Add `IReadOnlyList<string> SkillNames` to `ClaudeRunConfig` (default empty).
|
|
- In `TaskRunner.ResolveConfigAsync`: parse each level's `session_skills`, union + dedup,
|
|
filter to registry-existing names (drop + log missing).
|
|
- **Tests (Worker.Tests):** union across the three levels; dedup; unknown name dropped.
|
|
|
|
## Task 4 — Seeder
|
|
|
|
- `Skills/SessionSkillSeeder` + interface. `SeedAsync(cwd, skillNames, isWorktree, ct)`:
|
|
copy each installed skill dir → `<cwd>/.claude/skills/<name>/`; if worktree, append
|
|
`/.claude/skills/<name>/` to `git rev-parse --git-path info/exclude` target if absent.
|
|
- Wire into `TaskRunner` after run-dir resolution, before `ClaudeProcess.RunAsync`
|
|
(both worktree and sandbox paths).
|
|
- **Tests (Worker.Tests):** seeds into real temp dir; idempotent re-seed; worktree
|
|
exclude line written once and not duplicated; seeded path is git-ignored (real git
|
|
temp repo → `git status` clean for the seeded dir).
|
|
|
|
## Task 5 — Hub + DTOs + client
|
|
|
|
- `WorkerHub`: `GetSessionSkills`, `InstallSessionSkill(url)`, `UpdateSessionSkill(name)`,
|
|
`RemoveSessionSkill(name)`.
|
|
- New `SessionSkillDto`; extend `AppSettingsDto`, `ListConfigDto`, `UpdateListConfigDto`,
|
|
`UpdateTaskAgentSettingsDto` with skill-name lists; map in the update handlers.
|
|
- `IWorkerClient` + `WorkerClient` additions.
|
|
- **Update hand-rolled fakes** in Worker.Tests + Ui.Tests (memory
|
|
`iworkerclient_fakes_sync`).
|
|
- **Tests:** hub method round-trip via existing hub test harness where present.
|
|
|
|
## Task 6 — UI: registry tab + selectors
|
|
|
|
- `SessionSkillsSettingsTabViewModel` + a **Skills** tab in `SettingsModalView.axaml`:
|
|
installed list, Add (URL), Update, Remove, status line. Mirror
|
|
`FilesSettingsTabViewModel`.
|
|
- Global multi-select in General settings tab → `AppSettings.SessionSkills`.
|
|
- Skills multi-select in shared `AgentConfigEditor` (covers List + Task) with inheritance
|
|
badge, wired through `AgentConfigEditorViewModel`.
|
|
- Localization: add EN + DE keys in parity (Localization.Tests enforces).
|
|
- **Tests (Ui.Tests / Localization.Tests):** VM load/save of selections; locale parity.
|
|
- **Visual verification is Mika's** — flag the gaps.
|
|
|
|
## Task 7 — Wiring, build, end-to-end smoke
|
|
|
|
- DI registration (registry, cloner, seeder) in `Program.cs`.
|
|
- Build all touched projects `-c Release`; run Worker/Data/Ui/Localization test projects.
|
|
- Manual E2E: install ponytail via the UI, enable per-task, run a task, confirm the skill
|
|
is available to the agent and **not** committed and **not** in interactive sessions.
|
|
|
|
---
|
|
|
|
Commit per task with Conventional Commits (`feat(worker|ui|data): …`). Commit the
|
|
spec + plan docs first.
|