Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 27 additions & 14 deletions ai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,31 @@ setup remains managed by the adapters below.

`plugins/stephendolan` is a compatibility symlink for marketplace loaders that
require plugin roots beneath `plugins/`; `ai/` remains the canonical source.
For local setup, `skillset.json` is the declarative cross-agent allowlist and
`scripts/install-skills.py` installs it through skills.sh, plus any declared
token-gated upstream installer. A missing optional token prints a concise skip
and does not interrupt the remaining setup.
For local setup, `skillset.json` declares non-plugin skills for installation
through skills.sh, plus any declared token-gated upstream installer. The
personal `stephendolan` bundle remains installed through its marketplace plugin;
it is deliberately excluded from skills.sh so Codex sees only its namespaced
plugin skills rather than duplicate copies in shared paths such as
`~/.agents/skills`. A missing optional token prints a concise skip and does not
interrupt the remaining setup.

## Install

```text
/plugin marketplace add stephendolan/dotfiles
/plugin install stephendolan@dotfiles
```

Plugin users can access skills under their runtime's plugin namespace. Local
setup installs the skills declared in `skillset.json` through skills.sh. Codex
uses generated native roles; Cursor links Comment Sicko's canonical role directly.
Plugin users access the personal skills under their runtime's plugin namespace.
Local setup installs only the non-plugin skills declared in `skillset.json`
through skills.sh. Codex uses generated native roles; Cursor links Comment
Sicko's canonical role directly.

- Claude Code: `scripts/claude-code-setup.sh` adds the marketplace and installs
`stephendolan@dotfiles`.
- Codex: `scripts/codex-plugin-setup.sh` does the same and is run by `./install`.
- Cursor: install `stephendolan` at **user scope** from Customize → Plugins.
This is the supported account-synced route for Cursor and Cloud Agents; Cursor
does not provide a non-interactive plugin-install command. The repository's
`plugin.json` and `.cursor-plugin/plugin.json` supply the package metadata.

Do not install `stephendolan/dotfiles` through skills.sh or link `ai/skills`
into an agent skills directory: either route creates an unnamespaced second copy.
Amp loads the same skills from Stephen's personal skills repository, including
in orbs. Pushing this repository's `main` branch publishes the committed
`ai/skills` subtree to Amp.
Expand Down Expand Up @@ -77,8 +87,11 @@ Personal skills available across Stephen's agents:
| `mom-test` | Customer-discovery question and evidence review |
| `drama-triangle` | Communication and agency analysis |

`skillset.json` may omit `skills` to install every skill from a personal source,
or name selected third-party skills to keep the shared set intentionally small.
`skillset.json` may omit `skills` to install every non-plugin source, or name
selected third-party skills to keep the shared set intentionally small. Do not
add the personal `stephendolan/dotfiles` bundle here: its marketplace plugin is
the canonical installation path, and the installer rejects it to prevent
unnamespaced duplicates.

Model-invoked skills route natural-language requests into local tools or data:

Expand Down
5 changes: 5 additions & 0 deletions ai/scripts/install-skills.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

REPOSITORY_ROOT = Path(__file__).resolve().parents[2]
SKILLSET_PATH = REPOSITORY_ROOT / "ai" / "skillset.json"
MARKETPLACE_SOURCES = {"stephendolan/dotfiles"}


def load_skillset() -> tuple[list[str], list[dict[str, object]]]:
Expand All @@ -33,6 +34,10 @@ def load_skillset() -> tuple[list[str], list[dict[str, object]]]:
installer = entry.get("installer", "skills.sh")
if installer == "skills.sh" and not isinstance(entry.get("source"), str):
raise ValueError("skills.sh sources need a string source")
if entry.get("source") in MARKETPLACE_SOURCES:
raise ValueError(
f"{entry['source']} is installed through its marketplace plugin, not skills.sh"
)
if installer == "uidotsh" and not isinstance(entry.get("token_env"), str):
raise ValueError("ui.sh sources need a token_env")
if installer not in {"skills.sh", "uidotsh"}:
Expand Down
18 changes: 13 additions & 5 deletions ai/skillset.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@
"skills": ["design", "canonicalize-tailwind", "componentize"]
},
{
"source": "stephendolan/dotfiles"
},
{
"source": "stephendolan/private-skills"
"source": "stephendolan/private-skills",
"skills": [
"book-family-stay",
"cooking",
"notes-knowledge-base",
"order-daycare-lunch",
"troubleshoot-home-network"
]
},
{
"source": "mattpocock/skills",
"skills": ["grill-me"]
"skills": ["grill-me", "writing-for-agents"]
},
{
"source": "emilkowalski/skills",
Expand All @@ -34,6 +38,10 @@
{
"source": "shadcn/improve",
"skills": ["improve"]
},
{
"source": "EveryInc/compound-engineering-plugin",
"skills": ["ce-code-review"]
}
]
}
1 change: 1 addition & 0 deletions install.conf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
- [./scripts/brew-setup.sh, Setting up Homebrew and packages]
- command: python3 ./ai/scripts/install-skills.py
description: Installing declared agent skills
- [./scripts/codex-plugin-setup.sh, Setting up Codex plugins]
- [./ai/generate-mcp.sh, Generating MCP configs]
- [./scripts/claude-code-setup.sh, Setting up Claude Code]
- [./scripts/shell-setup.sh, Setting up default shell]
Expand Down
25 changes: 25 additions & 0 deletions scripts/codex-plugin-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -euo pipefail

MARKETPLACE="dotfiles"
MARKETPLACE_SOURCE="stephendolan/dotfiles"
PLUGIN="stephendolan@dotfiles"

if ! command -v codex >/dev/null 2>&1; then
echo "Codex CLI is not installed; skipping plugin setup."
exit 0
fi

if ! codex plugin marketplace list --json | jq -e --arg name "$MARKETPLACE" \
'.marketplaces[] | select(.name == $name)' >/dev/null; then
echo "Adding Codex marketplace: $MARKETPLACE_SOURCE"
codex plugin marketplace add "$MARKETPLACE_SOURCE"
fi

if ! codex plugin list --marketplace "$MARKETPLACE" --json | jq -e --arg id "$PLUGIN" \
'.installed[] | select(.pluginId == $id)' >/dev/null; then
echo "Installing Codex plugin: $PLUGIN"
codex plugin add "$PLUGIN"
fi

echo "Codex plugin setup complete!"
Loading