feat: a Skills tab per project, to review drafts and edit the skills a project has - #27
Merged
Merged
Conversation
…es are whole - `lifecycle.move_tier` removed a folder of the same name already in the target tier to make room. The cold and archive tiers are shared by every project, so archiving one project's `deploy` deleted another's. It now raises, and `skill-plus-plus tier` says so and exits 1. - The page passed a revision as `--instruction` and the text as two arguments, so an instruction such as `--shorter` was read as an unknown option and the run refused. It is one `--instruction=` argument now, as the draft note already was. - `install.read_settings` and `write_settings`: one strict reader for Claude Code settings files (an unparsable file raises instead of being written over), and a write through a temporary file and `os.replace`, since Claude Code reloads these files as they change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`skills` holds what the page and the upcoming `edit-skill` command both need about installed skills: `draft_dir`, `draft_files`, `digest`, `install_record`, `install_stale` and `changed_since_install`, plus `SAFE_NAME` and `NOT_SKILL_FILES`. Moved as they were; every call site in web.py now names `skills.<name>`, and the private copies are gone rather than kept as aliases. No behaviour changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ore it The backend for a Project skills tab, read side and the changes that need no agent: - `skills.list_project`: every folder in `<project>/.claude/skills/` with a SKILL.md, whoever made it, as a card: name (and the frontmatter name when it differs), description, files, who made it, the draft it was installed from and whether that draft is newer, usage, and whether it is on. Reads files only, so `/api/state` still starts no process. - `/api/skill/read`: a skill in full for a viewer. Text is shown up to a cap; binaries and links are named, never read or followed. - `/api/skill/off` and `/api/skill/on`: `skillOverrides` in the project's `.claude/settings.local.json`, the file Claude Code's own `/skills` menu writes (the main checkout's in a worktree). Other settings keep their order; an unparsable file is never written over; a file Skill++ creates gets one `.git/info/exclude` line so it is not committed; an "off" from the committed settings is shown and left alone. - `/api/skill/archive` and `/api/skill/restore`: the folder moves to `archive/<project key>/` under Skill++'s root and back. Nothing is ever replaced or deleted; a skill installed from a draft takes its install record along and is linked again on restore. - Which projects a request may name has one definition, `known_projects`, from the same entries the page lists. A request names a project and a folder, never a path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `skill-plus-plus edit-skill <folder> --project=DIR --instruction=TEXT`: the developer's agent edits a copy of the skill in a temp folder, and the result is kept under `<root>/edits/` as a proposal. The project is never written. Nothing is proposed when the agent changed nothing, declined, renamed the skill, removed SKILL.md, added a link, or when the project's copy changed while it ran. Linked skills and skills over 100 files or 1 MB are edited by hand instead. - The page runs it in the background (`/api/skill/edit`), shows the change as unified diffs with warnings about the frontmatter (`/api/skill/proposal`), and writes it only on Apply (`/api/skill/apply`), which is refused when the skill changed after the copy was taken; a failed write is rolled back. The replaced version goes to `history/`, the last 10 kept. `/api/skill/discard` drops Skill++'s copy. - A skill installed from a draft gets the same edit in its draft and new hashes in `installed.json`, so Update and Uninstall keep working. Update, Uninstall and Archive wait while an edit is running or waiting, and an edit waits while the draft is newer than the installed copy. - Every change to a project's skills and every job runs under one lock, `_jobs_lock`, now re-entrant, through a `@_locked` decorator. The job's freshness check is `_job_fresh`, shared with drafts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d archive The review page's third tab shows every skill each project has in `.claude/skills/`, three to a row (two, then one, on narrower screens), one gallery per project under All projects. - A card: name, description, badges (off for you or for the team, from a draft, update available, editing / edit ready / edit failed, linked, named differently from its folder), files and usage, and View, Edit, Turn off / Turn on and Archive. A button that cannot act says why. - The viewer, a `<dialog>`: the file list, SKILL.md rendered through the page's own escaped markdown (or as source), other files as text, binaries and links named. Its edit panel sends the agent the change, shows the running edit, then the proposal as per-file diffs with warnings, and Apply or Discard. Only the panel repaints while the page polls, so the file being read keeps its place. - Archived skills are listed under each gallery, with Restore. - In Drafts, "in <project>" opens the installed skill in the gallery, and Revise on an installed draft, which the server always refused, becomes "Edit under Project skills". - On a phone the header wraps instead of widening the page, and `.run` gets a colour that exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
usage.md gets a section on the tab (what Edit, Turn off and Archive do and where each writes), `edit-skill` in the commands table, a troubleshooting entry for a failed edit, and a note that deleting Skill++'s folder deletes archived skills too. README, CHANGELOG (Added, and the three fixes under Fixed), architecture.md and SECURITY.md follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drafts and installed skills share one tab, laid out per project: each project's drafts to review first, then its skills as plain cards (name, what it is for, and a label when it is off or an edit is running or waiting). Clicking a card opens its SKILL.md; Edit, Turn off/on and Close sit in its header, and the edit box shows only after Edit. A skill that is off is struck through and hatched, with a solid Off label. A failed edit can be dismissed. Removed: Uninstall, Just for me, Download, Archive and Restore, the personal gallery, Update, and `web --skills-dir`. A skill belongs to its project, and once installed its folder is the skill: nothing else is kept of the install (no installed.json), an edit changes only the folder, and deleting the folder takes the skill out and brings its draft back to review. Install never writes over a folder that is there, and clears an edit left waiting by a skill of the same name. `revise` refuses an installed draft and names the `edit-skill` command instead. The page asks its questions and shows its errors in a <dialog> of its own. The browser's confirm and alert boxes can be switched off, and Claude's in-app browser does: Ignore and Discard then did nothing, and errors never showed. Every test now gets a fake agent command by default, so a test that forgets to stub the agent fails at once instead of running `claude -p`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tory Right after Apply, the opened skill offers Undo, which puts the skill back as it was before that Apply. It lasts until the next action or a reload of the page: Apply hands the page a token, the page drops it at its next action and on a reload, and the next Apply replaces it. The copy Undo puts back is the one the edit was made on, kept in Skill++'s own edits folder and never in the project. Undo is refused once anything changed the skill since, so it never throws a later change away. A new server clears what an earlier one kept. The history of the last ten applied edits is gone with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Turn off and Turn on in the opened skill come out, and with them the Off label and the struck-through card, reading and writing Claude Code's `skillOverrides` in the project's settings, the line added to the clone's `.git/info/exclude`, the settings backup, and finding a worktree's main checkout. A card is the skill's name, what it is for, and a label while an edit is running or waiting. Turning a skill off comes back on a branch of its own, which can start by reverting this commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dictation (`/skill-plus-plus-new`, `skill-plus-plus dictate`) records the folder it runs in as its project, and is matched only against that project's dictated candidates. It used to record none, which is where every "No project" entry came from: captured work always has a folder. The review page shows only candidates that belong to a project. Its project menu has no "No project" any more, and the Skills tab no block for one. Older entries without a project stay in the ledger, off the page; `skill-plus-plus review --all` still lists them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The project menu has no All projects any more: a candidate and the skill made from it belong to one project, and nothing on the page is about several. One project is always chosen, even when it is the only one. The page opens on the project chosen last, or else the one `skill-plus-plus web` was started in, or else the first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
himanshu096
approved these changes
Sep 29, 2026
lucazagaia
force-pushed
the
feat/project-skills
branch
from
September 29, 2026 15:17
e27c314 to
0908b2a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Skill++ takes a candidate all the way to an installed skill, and then the review page had nothing for it. Revise refused installed skills while the Drafts tab still showed the button, skills made by hand never appeared, and a skill could only be changed by hand.
What it does
The Drafts tab becomes Skills, one block per project: that project's drafts to review first, then every skill in its
.claude/skills/, whoever made it, three cards to a row (two, then one, on narrower screens).SKILL.md, rendered through the page's own escaped markdown, and never read through a link.SKILL_PLUS_PLUS_AGENT,claude -pby default) edits a copy in a temp folder, and the result waits as a per-file diff until Apply or Discard. The project is never written before Apply, and Apply is refused if the skill changed after the copy was taken. Nothing is proposed when the agent changed nothing, declined, renamed the skill, added a link, or touched the project's copy while it ran.skill-plus-plus edit-skilldoes the same from the terminal..claude/skills/<name>/and keeps nothing else about it: from then on the folder is the skill. Deleting the folder takes it out, and its draft comes back to review.reviserefuses an installed draft and namesedit-skillinstead./skill-plus-plus-new) now records the folder it runs in; it used to record none, which is where every "No project" entry came from. The page shows only candidates with a project, so the project menu has no "No project" any more.skill-plus-plus webwas started in, or else the first.<dialog>of the page. The browser'sconfirmandalertcan be switched off, and Claude's in-app browser does: Ignore then did nothing, and errors never showed.A request names a project the page lists and a folder in it, never a path. Every change to a project's skills, and every background job, runs under one lock.
Removed
Uninstall, Just for me, Download, Update, the personal gallery and
web --skills-dir: a skill belongs to the project it was made from.Turning a skill off is left out on purpose. 86cc7d6 takes it out, and it comes back on a branch of its own, which can start by reverting that commit.
Also fixed on the way
tierno longer deletes a skill already in the target tier (the tiers are shared by every project).-(--shorter) reaches the agent.install.read_settings/write_settingswrite settings files whole.claude -p.Reading the history
The first six commits are the first design: a separate Project skills tab with View, Turn off and Archive. The last five reshape it into what is described above, so the whole diff reads better than commit by commit.
Developed on a stack of #25 and #26. After they merged,
mainwas byte-identical to that stack, so the first six commits were replayed ontomainwith no conflicts.Verified
edit-skill(dry run, copy only, rename, decline, workspace removed, writes into the project caught), the edit flow end to end with a stub agent, Undo (its token, only the last Apply, refused after a change, cleared by a new server), install and a hand-deleted folder, request safety, dictation's project, and the page code in node (galleries, the project menu, pop-ups, escaped diffs).scripts/leak_guard.py: 0 hits.Not verified here
claude -p(only a stub agent ran).docs/images/skill-installed.pnganddocs/images/draft-questions.pngstill show the old Drafts tab, and need retaking.