You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Summary
Brings the plugin in line with where each host actually is today (Claude
Code, Codex CLI 0.125+, Cursor, Gemini CLI, OpenCode), and starts
pushing the install path through native marketplace commands instead of
shell scripts.
## What's in here
**Hooks**
The session-start hook used to be a single bash script that printed a
static banner. It's now split into a small detection library
(`hooks/lib/`) and a thin emitter, with PowerShell and Node ports so the
same logic runs on every host. The detector scans the project for
signals (`pyproject.toml` deps, Python imports, file globs) and injects
targeted reminders to use the relevant skill — `litestar`, `sqlspec`,
`advanced-alchemy`, `litestar-saq`, etc. The matcher map is data-only
(`hooks/lib/skill-map.json`) so new skills just add an entry.
`LITESTAR_SKILLS_HOOK_DISABLE=1` opts out.
**Codex plugin layout**
Codex 0.125 stopped accepting `source.path: \"./\"` for a marketplace,
so the plugin moved to a nested layout under
`.agents/plugins/plugins/litestar-skills/`. Marketplace config lives at
`.agents/plugins/marketplace.json`. `.gitignore` got a narrow carve-out
so just those two paths are tracked — the rest of `.agents/` stays
authoring-only.
**Subagents**
The four host-specific dialects (Claude / Codex / Gemini / OpenCode) of
`litestar-reviewer` were drifting whenever one was edited. They're now
generated from a single YAML source via `tools/generate-agents.py`, with
a CI check that fails on hand-edits. To change the agent: edit the YAML,
run `make agents`, commit both.
**OpenCode plugin**
The plugin file used to be an empty stub. It's now a real plugin that
injects skill reminders into the system prompt via
`experimental.chat.system.transform` and respects
`managedConfig.disabledPlugins` / `allowedPlugins` so org policy
actually takes effect.
**Policy & install docs**
Added `docs/policy.md` covering per-host allow/ask/deny grammar and
managed-settings paths, plus a drop-in
`templates/managed-settings/claude-code.json`. Gemini's `excludeTools`
now ships opinionated defaults blocking `sudo`, `rm -rf /*`, and `* |
sh`/`* | bash` patterns. Each host got its own `INSTALL.md` and the
README has a real support-tier matrix.
**Validation**
The Claude `userConfig` schema is now enforced (camelCase keys, valid
types, required `title`); deprecated `decision: approve|block` and
undocumented `${CLAUDE_PLUGIN_DATA}` are rejected. `make check`
validates the four hook manifests, mirrors flow's
`validate-codex-manifest.py`, and the agent generator drift gate.
**Distribution**
`docs/submission-tracker.md` lays out a 3-phase rollout (zero-gatekeeper
→ form/PR → async/blocked) so submissions to skills.sh, the Anthropic
community directory, openai/skills, and the various awesome-* lists are
tracked rather than ad-hoc. README points users at `npx skills add
litestar-org/litestar-skills`.
## Verification
- `make check` is clean (lint, type-check, 100 tests, manifest sync at
0.1.2 across 13 files, agent drift gate, Codex manifest validator).
- `claude plugin tag .claude-plugin --dry-run` accepts the manifest.
- `codex plugin marketplace add .` accepts the marketplace.
- Reference: same-author multi-host plugin at `~/code/c/flow` learned a
lot of these things the hard way; this PR ports the patterns over.
"description": "The Litestar Marketplace — opinionated first-party skills, plugins, subagents, commands, and MCP servers for Litestar and its ecosystem"
The `/plugin` commands run **inside** Claude Code — they cannot be automated from a shell. Claude prompts for any `userConfig` values on first install (none today), then enables the plugin.
Should show `litestar-skills` under enabled plugins. Open a Litestar project (one with `litestar` in `pyproject.toml`) and a fresh session — the SessionStart hook injects a context paragraph naming `litestar-skills:litestar` (plus any other detected skills).
57
+
58
+
## Restricting capabilities
59
+
60
+
Claude Code is the only host with a mature allow/ask/deny grammar. See [`docs/policy.md`](../docs/policy.md) for per-rule syntax and managed-settings paths. A drop-in template for org-managed installs lives at [`templates/managed-settings/claude-code.json`](../templates/managed-settings/claude-code.json).
-**`Unrecognized key: "displayName"`** — your local clone is on a stale revision. Pull main; root-level `displayName` was removed (it's only valid inside marketplace.json plugin entries, not in plugin.json).
75
+
-**Hook doesn't inject context** — ensure the session was started in a directory containing `pyproject.toml`. The hook short-circuits silently when no Litestar-ecosystem signals are detected. Override with `LITESTAR_SKILLS_HOOK_DISABLE=1` to confirm the hook is firing.
76
+
-**`/status` doesn't show the plugin** — `/plugin marketplace add` and `/plugin install` are separate steps. Run both.
Codex auto-discovers plugins in `~/.codex/plugins/`. The clone includes `.codex/agents/litestar-reviewer.toml` (pure-TOML custom agent; tools inherited from your session `config.toml`).
17
+
Enable `litestar-skills` from the list. The plugin manifest lives at `.agents/plugins/plugins/litestar-skills/.codex-plugin/plugin.json`; the marketplace catalog is `.agents/plugins/marketplace.json` at the repo root.
12
18
13
-
## Option 2: Repo-scoped marketplace (team)
19
+
## Option 2: Local marketplace (for development)
14
20
15
-
For a single project, clone into the repo's `plugins/` directory and register a local marketplace:
21
+
If you have the repo cloned and want Codex to pick up your local changes:
"description": "The Litestar Marketplace — opinionated first-party skills, plugins, subagents, commands, and MCP servers for Litestar and its ecosystem",
Codex reads `.agents/skills/` natively at session start.
35
+
Codex auto-discovers plugins under `~/.codex/plugins/`. Provided as a fallback for environments where `codex plugin marketplace add` is unavailable.
43
36
44
37
## Custom agents
45
38
46
-
Codex custom agents live in `.codex/agents/*.toml` and are discovered automatically when the plugin is installed. The repo ships `litestar-reviewer` — invoke with `$agent litestar-reviewer` inside Codex.
39
+
Codex custom agents live in `.codex/agents/*.toml` (pure TOML; tools inherited from session `config.toml`). The repo ships `litestar-reviewer` — invoke with `$agent litestar-reviewer` inside Codex.
40
+
41
+
The four host-dialect agent files are generated from canonical YAML sources at `tools/agent-sources/<name>.yaml`. Run `make agents` after editing the source.
The SessionStart hook (`hooks/session-start.sh`, dispatched via `hooks/hooks-codex.json`) should inject project-aware Litestar skill reminders into the session context.
65
+
66
+
## Disabling specific skills
64
67
65
68
Edit `~/.codex/config.toml`:
66
69
@@ -69,3 +72,13 @@ Edit `~/.codex/config.toml`:
69
72
path = "/path/to/skill/SKILL.md"
70
73
enabled = false
71
74
```
75
+
76
+
## Why the nested layout
77
+
78
+
Codex CLI 0.125.0+ requires local marketplace `source.path` to:
79
+
80
+
1. Start with `./`
81
+
2. Be a non-empty subdirectory (rejects `./` alone)
82
+
3. Contain no `..` traversal
83
+
84
+
That's why the plugin lives under `./plugins/litestar-skills` (relative to `.agents/plugins/marketplace.json`) instead of being collocated with the marketplace file.
Then search for `litestar-skills` (once the plugin is approved on the Cursor marketplace — submission is pending; see [docs/roadmap.md](../docs/roadmap.md)).
12
+
13
+
## Local-development install
14
+
15
+
Until the plugin lands on the Cursor marketplace, install it locally:
Cursor has no documented public deny grammar today. Restriction options:
43
+
44
+
- Uninstall via `/remove-plugin`
45
+
- Team / Enterprise plans support private team marketplaces with central governance — talk to your Cursor admin
46
+
47
+
See [`docs/policy.md`](../docs/policy.md) for the full per-host reference.
48
+
49
+
## Troubleshooting
50
+
51
+
-**Plugin not discovered** — ensure the symlink target points at the repo root (the directory containing `.cursor-plugin/plugin.json`), not at `.cursor-plugin/` itself.
52
+
-**Hook doesn't fire** — Cursor's SessionStart hook reads `./hooks/hooks-cursor.json`; ensure the `hooks` field in `.cursor-plugin/plugin.json` is present (it is, as of v0.2).
The hook manifest at `hooks/hooks.json` uses Gemini's `${extensionPath}${/}` substitution + a `bun || node || bash` multi-runtime fallback so the SessionStart hook works on any machine.
23
+
24
+
## Updating
25
+
26
+
```bash
27
+
gemini extensions update litestar-skills
28
+
```
29
+
30
+
## Verifying the install
31
+
32
+
In a Gemini session, ask: *"What Litestar skills are available?"* — Gemini should list the skills loaded from this extension. Or check the gallery:
33
+
34
+
```bash
35
+
gemini extensions list | grep litestar
36
+
```
37
+
38
+
## Restricting capabilities
39
+
40
+
Gemini ships a denylist via `excludeTools` in `gemini-extension.json`. The repo ships defenses against:
41
+
42
+
- All `sudo` invocations (bare, prefixed, semicolon-chained, embedded, piped)
43
+
- Destructive `rm -rf` against root, `$HOME`, and `~`
44
+
-`curl | sh`, `wget | sh`, and any `*|sh`/`*|bash` install-script piping
45
+
46
+
See [`docs/policy.md`](../docs/policy.md) for the full pattern list.
47
+
48
+
**Caveat:** Gemini's `excludeTools` does NOT apply to MCP servers bundled with the extension itself ([gemini-cli #8481](https://github.com/google-gemini/gemini-cli/issues/8481)). Treat it as belt-and-suspenders, not a hard guarantee.
49
+
50
+
## Troubleshooting
51
+
52
+
-**`gemini extensions install` fails on a fresh clone** — the manifest is `gemini-extension.json` at the repo root (sibling of `README.md`). If the file isn't present, your checkout may be on a pre-Gemini-support revision.
53
+
-**Hook doesn't inject context** — the hook short-circuits silently when no Litestar-ecosystem signals are detected in the cwd. Override with `LITESTAR_SKILLS_HOOK_DISABLE=1` to confirm it's firing. The hook scans `pyproject.toml`, Python imports (capped), and a curated set of file globs (`Dockerfile`, `Chart.yaml`, `*.tf`, etc.).
54
+
-**`bun`/`node` not found at hook time** — the multi-runtime fallback ends with `bash` so a system without Bun or Node still gets the hook.
0 commit comments