-
Notifications
You must be signed in to change notification settings - Fork 110
Add agent-skills infrastructure and installer #940
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
MaxDall
wants to merge
1
commit into
master
Choose a base branch
from
add-skill-infrastructure
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -139,3 +139,6 @@ dmypy.json | |
|
|
||
| # Pyre type checker | ||
| .pyre/ | ||
|
|
||
| # Installed agent skills (see skills/install.py) | ||
| .claude/ | ||
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| # Agent skills | ||
|
|
||
| Playbooks and skills meant to be **executed by AI coding agents**, not human contributors. | ||
|
|
||
| The repo stays **agent-neutral**: we track the skill *sources* here, but we do **not** commit any | ||
| agent's config directory (`.claude/` is gitignored). Each developer installs the skills they want into | ||
| their own agent with the installer below. | ||
|
|
||
| ## Skills | ||
|
|
||
| | Skill | What it does | | ||
| |-------|--------------| | ||
| | [`review-publisher`](review-publisher/SKILL.md) | Reviews a publisher PR (new publisher or parser-version change): crawls live articles to verify the extracted `ArticleBody` mirrors the real article, checks `VALID_UNTIL` / version bumps / `validate=False` / `free_access`, and drafts a single GitHub review. | | ||
|
|
||
| `install.py` (the installer launcher) and the `installer/` package behind it, plus this | ||
| `README.md`, round out the folder. | ||
|
|
||
| ## Layout | ||
|
|
||
| Each skill is a **self-contained folder** — a `SKILL.md`, the `PLAYBOOK.md` it points at, and any helper | ||
| scripts under `scripts/` — so the whole thing can be copied anywhere and still work. The installer copies | ||
| the **entire folder**, so anything you drop in ships automatically; if the folder has a `requirements.txt` | ||
| at its root, the installer also pip-installs it into your current interpreter. Install is **atomic**: if | ||
| that pip step fails, the copied folder is rolled back (the cell flashes `!`, then shows `·`) so an install | ||
| never half-lands — `✓` always means the skill *and* its deps are in. | ||
|
|
||
| Two path conventions keep a copied folder working: | ||
|
|
||
| - `SKILL.md` links to `PLAYBOOK.md` as a **sibling**, so the link survives being copied into `.claude/`. | ||
| - **`${CLAUDE_SKILL_DIR}` is substituted by Claude Code in `SKILL.md` content only** — it is *not* an | ||
| environment variable, and other bundled files are read verbatim. So `SKILL.md` states the skill's own | ||
| directory once (via the placeholder) and tells the agent to substitute it into the `<skill>` paths | ||
| the `PLAYBOOK.md` commands use. A bare `scripts/…` path would wrongly assume the working dir is the | ||
| skill dir; a `${CLAUDE_SKILL_DIR}` outside SKILL.md would expand to nothing in a shell. | ||
|
|
||
| References from `PLAYBOOK.md` to *other* repo docs use **repo-root-relative** links | ||
| (e.g. `/docs/attribute_guidelines.md`): they resolve on GitHub and from the repo root, which is where | ||
| the review skill runs anyway. | ||
|
|
||
| ## Install | ||
|
|
||
| The installer is a full-screen **status dashboard**. Run it with no arguments: | ||
|
|
||
| ```bash | ||
| python skills/install.py | ||
| ``` | ||
|
|
||
| It shows a live matrix of *skills* × *scopes* for the selected agent. Each row is a skill; the | ||
| **Project** and **User** columns show whether it's installed (`✓`) or not (`·`). Move the cursor with | ||
| `↑`/`↓`, then toggle a scope to act on the highlighted skill — `p` for project, `u` for user. Toggling | ||
| installs the skill if it's absent and uninstalls it if it's present; the matrix updates in place, so you | ||
| never have to re-run. `r` refreshes from disk and `q` quits. | ||
|
|
||
| The two scopes: | ||
|
|
||
| - **project** installs to `./.claude/skills/`. The skill is scoped to this repo, where it's relevant, | ||
| and never pushed (`.claude/` is in the committed `.gitignore`). | ||
| - **user** installs to `~/.claude/skills/`, available in every project. Nothing touches the repo. (The | ||
| review skill references repo files, so it only makes sense while your working directory is the Fundus | ||
| repo regardless.) | ||
|
|
||
| The installer needs the `textual` package, which ships in the project's `dev` extra: | ||
|
|
||
| ```bash | ||
| pip install -e .[dev] | ||
| ``` | ||
|
|
||
| Re-install (toggle off, then on) after editing a skill source to refresh the installed copy. Restart | ||
| your agent so it picks up a newly installed skill. | ||
|
|
||
| ## Supported agents | ||
|
|
||
| | Agent | Status | Target | | ||
| |-------|--------|--------| | ||
| | **Claude Code** (`claude`) | supported | `.claude/skills/<name>/` | | ||
| | Codex, Cursor, … | not yet | no 1:1 `SKILL.md` concept; would be a best-effort mapping (e.g. a Codex prompt or a `.cursor/rules` file). Add to `available_agents()` in `installer/core.py` when wanted. | | ||
|
|
||
| ## Adding a skill | ||
|
|
||
| Create `skills/<name>/` with a `SKILL.md` (frontmatter `name`/`description`) and a `PLAYBOOK.md` | ||
| it links to as a sibling; put helper scripts under `scripts/`. The installer **discovers skills from | ||
| the folder layout** (any directory here containing a `SKILL.md`), so there is nothing to register — | ||
| run `python skills/install.py` and the new skill shows up as a row. If the skill needs packages | ||
| beyond Fundus, drop a `requirements.txt` at its root — the installer pip-installs it on install (and | ||
| leaves it in place on uninstall). | ||
|
|
||
| Keep the path conventions above: state the skill's own directory in `SKILL.md` via | ||
| `${CLAUDE_SKILL_DIR}` (it is substituted nowhere else), and point cross-doc links at repo-root paths | ||
| (`/docs/...`). | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| #!/usr/bin/env python3 | ||
| """Install Fundus agent skills into your coding agent's config directory. | ||
|
|
||
| The skill *sources* live under ``skills/``, tracked in the repo, so the repo itself stays | ||
| agent-neutral (we don't commit any agent's config dir). Each skill is a self-contained | ||
| folder (``SKILL.md`` + ``PLAYBOOK.md`` + any bundled ``scripts/``); installing copies the | ||
| whole folder into your agent's config dir, which is gitignored (project scope) or lives | ||
| outside the repo entirely (user scope). Re-install after editing a source to refresh the | ||
| installed copy. | ||
|
|
||
| Run it with no arguments for a full-screen status dashboard:: | ||
|
|
||
| python skills/install.py | ||
|
|
||
| The dashboard is a live matrix of *skills* × *scopes* for the selected agent — toggle a | ||
| scope on the highlighted skill to (un)install it in place. It needs the ``textual`` package | ||
| (it ships in the project's ``dev`` extra: ``pip install -e .[dev]``). | ||
|
|
||
| This file is a thin launcher; the install logic lives in the ``installer`` package next to | ||
| it (``installer/core.py`` is stdlib-only, ``installer/tui.py`` is the Textual dashboard). | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import sys | ||
| from pathlib import Path | ||
|
|
||
|
|
||
| def main() -> int: | ||
| # Allow `python skills/install.py` to find the sibling `installer` package regardless | ||
| # of the current working directory. | ||
| sys.path.insert(0, str(Path(__file__).resolve().parent)) | ||
| try: | ||
| from installer.tui import run | ||
| except ModuleNotFoundError as exc: | ||
| if exc.name in {"textual", "rich"}: | ||
| print( | ||
| "The skill installer dashboard needs the 'textual' package.\n" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: It might be more helpful to not selectively test for textual and one of it's dependencies here, but rather either:
|
||
| "Install the project's dev extra: pip install -e .[dev]", | ||
| file=sys.stderr, | ||
| ) | ||
| return 1 | ||
| raise | ||
| run() | ||
| return 0 | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| raise SystemExit(main()) | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| """Fundus skill installer. | ||
|
|
||
| :mod:`installer.core` is stdlib-only (discovery + install logic); :mod:`installer.tui` adds | ||
| the Textual dashboard. Importing this package pulls in only the core, so it stays usable | ||
| without textual installed. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from .core import ( | ||
| REPO_ROOT, | ||
| SCOPES, | ||
| SKILLS_DIR, | ||
| Agent, | ||
| InstallResult, | ||
| Skill, | ||
| available_agents, | ||
| discover_skills, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "REPO_ROOT", | ||
| "SCOPES", | ||
| "SKILLS_DIR", | ||
| "Agent", | ||
| "InstallResult", | ||
| "Skill", | ||
| "available_agents", | ||
| "discover_skills", | ||
| ] |
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having not too much experience with Markdown, I didn't know what exactly you meant with frontmatter until looking into the review-skill PR. Maybe a template or short example might make adding the first skill simpler.