Skip to content

Commit b2949ad

Browse files
committed
Restructure plugin layout to unlock Gemini-format hooks
1 parent f15a5bd commit b2949ad

85 files changed

Lines changed: 134 additions & 71 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/plugins/marketplace.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
{
88
"name": "cpln",
99
"source": {
10-
"source": "url",
11-
"url": "https://github.com/controlplane-com/ai-plugin.git"
10+
"source": "local",
11+
"path": "./plugins/cpln"
1212
},
1313
"policy": {
1414
"installation": "INSTALLED_BY_DEFAULT",

.claude-plugin/marketplace.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"name": "controlplane",
3+
"description": "Official Control Plane marketplace. Skills, agents, guardrails, and MCP configuration for deploying and managing containerized workloads across AWS, GCP, Azure, and private clouds.",
34
"owner": {
45
"name": "Control Plane",
56
"email": "support@controlplane.com"
@@ -9,7 +10,8 @@
910
"name": "cpln",
1011
"source": {
1112
"source": "github",
12-
"repo": "controlplane-com/ai-plugin"
13+
"repo": "controlplane-com/ai-plugin",
14+
"path": "plugins/cpln"
1315
},
1416
"description": "Control Plane AI workflows, skills, guardrails, and MCP configuration.",
1517
"version": "1.1.0",

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/) and this
88

99
### Added
1010

11+
- Gemini-format hook config at repo-root `hooks/hooks.json` (`BeforeTool` guards on `run_shell_command` for generic `cpln secret create` and `cpln apply` missing `--file`). Gemini auto-discovers it; Claude and Codex never see it because their plugin root now resolves to `plugins/cpln/`.
12+
1113
### Changed
1214

15+
- **Repo restructured.** All Claude + Codex plugin content (skills, agents, commands, rules, references, assets, hooks, `.claude-plugin/plugin.json`, `.codex-plugin/`, `.claude-mcp.json`, `.app.json`) moved into `plugins/cpln/`. Marketplaces (`.claude-plugin/marketplace.json`, `.agents/plugins/marketplace.json`) now point at `plugins/cpln`. Gemini extension manifest, marketplace JSONs, and contributor docs stay at repo root. Existing install commands are unchanged; users get the new layout on their next `/plugin upgrade` or marketplace re-add.
16+
- Claude + Codex hooks now ship in `plugins/cpln/hooks/cpln-hooks.json` and are declared explicitly via the `hooks` field in each plugin manifest, replacing the auto-discovered default path.
17+
1318
### Fixed
1419

1520
### Removed

CLAUDE.md

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,51 @@ For end-user installation, capabilities, and supported clients, see `README.md`.
44

55
## Repo layout
66

7+
The repo is split into two zones: **repo root** holds marketplace manifests, the Gemini extension, and contributor docs; **`plugins/cpln/`** holds the actual Claude + Codex plugin content. Both Claude and Codex resolve their plugin root to `plugins/cpln/` via their marketplace manifests; Gemini uses the repo root as its extension dir. This split exists because Gemini, Claude, and Codex all auto-discover `hooks/hooks.json` at their respective roots with incompatible schemas — keeping their roots distinct lets each tool ship its own hook config without cross-tool warnings or load failures. The Apr 27, 2026 audit confirmed this layout against each CLI's source.
8+
9+
### Repo root (marketplace + Gemini)
10+
11+
- `.claude-plugin/marketplace.json` — Claude marketplace entry. `source.path` points at `plugins/cpln`.
12+
- `.agents/plugins/marketplace.json` — Codex marketplace entry. `source` is `{local, path: "./plugins/cpln"}`.
13+
- `gemini-extension.json` — Gemini CLI extension manifest. Declares the `cpln` MCP server and points `contextFileName` at `GEMINI.md`. Gemini treats this directory (the repo root) as the extension dir.
14+
- `GEMINI.md` — Gemini runtime guardrails. Loaded for every Gemini session via `contextFileName`. Keep it short.
15+
- `hooks/hooks.json`**Gemini-only** hook config. Uses Gemini's schema (`BeforeTool`/`AfterTool`, matcher on `run_shell_command`, output `{decision:"deny", reason:"..."}`). Gemini auto-discovers this file from the extension dir; the path is hardcoded in `packages/cli/src/config/extension-manager.ts` and cannot be redirected via the manifest.
16+
- `README.md`, `CHANGELOG.md`, `CONTRIBUTING.md`, `LICENSE`, `SECURITY.md`, `CLAUDE.md` — contributor and end-user docs.
17+
18+
### `plugins/cpln/` (Claude + Codex plugin content)
19+
720
- `skills/` — Domain-knowledge skill modules. Each lives in its own subdirectory with a `SKILL.md` carrying frontmatter (`name`, `description`).
821
- `agents/` — Guided workflow agents. Each is a top-level `<agent>.md` with frontmatter. Companion reference docs that an agent loads on demand live under `references/<agent>/` (kept out of `agents/` so the loader doesn't try to register them as standalone agents).
9-
- `references/` — On-demand reference docs cited by agents (e.g., `references/workload-troubleshooter/diagnostics.md`). Plain markdown, no frontmatter required. Ships with the plugin install.
22+
- `references/` — On-demand reference docs cited by agents (e.g., `references/workload-troubleshooter/diagnostics.md`). Plain markdown, no frontmatter required.
1023
- `commands/` — Slash commands. Each command has a paired `<command>.md` (Claude) and `<command>.toml` (Gemini-style prompt template); keep them aligned.
11-
- `rules/` — Validation guardrails and manifest references. Files with `alwaysApply: true` in frontmatter (`cli-conventions.md`, `cpln-guardrails.md`) are concatenated and injected into every Claude Code session by the `SessionStart` entry in `hooks/hooks.json`. `alwaysApply` is **not** a native Claude Code field — the hook is what gives it meaning, so adding a new always-on rule means dropping a file with `alwaysApply: true` and nothing else. Treat changes to those files as broad-impact.
12-
- `hooks/hooks.json`**Claude-specific** PreToolUse guards on `cpln` Bash patterns plus the `SessionStart` rule injector. Gemini and Codex ignore this file; the Gemini-side equivalents live in `GEMINI.md`.
13-
- `assets/` — Logos and icons referenced by plugin/marketplace manifests.
14-
- `.claude-plugin/` — Claude plugin manifest (`plugin.json`) and marketplace entry (`marketplace.json`).
15-
- `.codex-plugin/plugin.json` — Codex plugin manifest.
16-
- `.agents/plugins/marketplace.json` — Codex marketplace entry.
17-
- `gemini-extension.json` — Gemini CLI extension manifest. Declares the `cpln` MCP server and points `contextFileName` at `GEMINI.md` (loaded for end users every session — keep it short).
18-
- `.claude-mcp.json`, `.codex-plugin/mcp.json`, MCP block in `gemini-extension.json` — three per-client MCP configs pointing at the same hosted server (`https://mcp.cpln.io/mcp`). Keep all three in sync when changing the server URL or auth shape. The Codex file lives inside `.codex-plugin/` (rather than at the repo root as `.mcp.json`) so Claude Code's cwd auto-discovery doesn't try to parse the Codex-format file as a project MCP config when developing in this repo.
24+
- `rules/` — Validation guardrails and manifest references. Files with `alwaysApply: true` in frontmatter (`cli-conventions.md`, `cpln-guardrails.md`) are concatenated and injected into every Claude **and Codex** session by the `SessionStart` entry in `hooks/cpln-hooks.json`. `alwaysApply` is not a native field — the hook is what gives it meaning. Codex works out of the box because it sets `CLAUDE_PLUGIN_ROOT` for OOTB compatibility (verified in `codex-rs/hooks/src/engine/discovery.rs`) and accepts the same `hookSpecificOutput.additionalContext` schema. Gemini gets the same rules content from `GEMINI.md` via `contextFileName`.
25+
- `hooks/cpln-hooks.json`Shared **Claude + Codex** hook config (`PreToolUse` Bash guards + `SessionStart` rule injector). Declared explicitly in `.claude-plugin/plugin.json` and `.codex-plugin/plugin.json` via the `hooks` field. Lives at a non-default name so neither tool's strict auto-discovery picks it up alongside the manifest declaration; Claude merges defaults with manifest hooks and Codex 0.x merges too in some paths, so an explicit path is the safest.
26+
- `assets/` — Logos and icons referenced by plugin manifests.
27+
- `.claude-plugin/plugin.json` — Claude plugin manifest. All paths in this file (`./skills/`, `./hooks/cpln-hooks.json`, etc.) are relative to `plugins/cpln/`.
28+
- `.codex-plugin/plugin.json` — Codex plugin manifest. Same path conventions.
29+
- `.codex-plugin/mcp.json` — Codex MCP config. Lives inside `.codex-plugin/` (rather than as a project-level `.mcp.json`) so Claude's cwd auto-discovery doesn't try to parse the Codex-format file as a project MCP config when developing.
30+
- `.claude-mcp.json`, `.codex-plugin/mcp.json`, MCP block in `gemini-extension.json` — three per-client MCP configs pointing at the same hosted server (`https://mcp.cpln.io/mcp`). Keep them in sync when changing the server URL or auth shape.
31+
- `.app.json`Codex app-level metadata.
1932

2033
## Authoring conventions
2134

2235
- File names: kebab-case (`workload-manifest-reference.md`, `setup-secret.md`).
23-
- Frontmatter on skills, agents, and commands: `name` and `description`. Don't add a `version:` field — Claude Code, Codex, and Gemini all ignore it, and the only version users see comes from the per-client manifests (`.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, `gemini-extension.json`). Rules use `description` plus `alwaysApply` when applicable.
36+
- Frontmatter on skills, agents, and commands: `name` and `description`. Don't add a `version:` field — Claude, Codex, and Gemini all ignore it, and the only version users see comes from the per-client manifests (`plugins/cpln/.claude-plugin/plugin.json`, `plugins/cpln/.codex-plugin/plugin.json`, `gemini-extension.json`). Rules use `description` plus `alwaysApply` when applicable.
2437
- Inside skill/rule examples, YAML uses uppercase placeholders: `WORKLOAD`, `GVC`, `ORG`.
2538
- MCP tool names in Claude-side examples use the `mcp__cpln__` prefix (Claude Code's convention); Gemini and Codex use the bare tool name.
26-
- **Never write a `cpln` command from memory** when authoring or editing examples in skills/agents/rules. Verify shape and flags with `cpln <command> --help` or `mcp__cpln__cpln_suggest`. `rules/cli-conventions.md` is the canonical CLI reference inside this repo; if you change CLI examples, cross-check against it.
39+
- **Never write a `cpln` command from memory** when authoring or editing examples in skills/agents/rules. Verify shape and flags with `cpln <command> --help` or `mcp__cpln__cpln_suggest`. `plugins/cpln/rules/cli-conventions.md` is the canonical CLI reference inside this repo; if you change CLI examples, cross-check against it.
2740

2841
## Local development
2942

3043
Two install paths — pick based on what you're doing.
3144

32-
**Fast iteration** — load the plugin directly from this working tree, no marketplace round-trip. This is the inner-loop workflow most edits use:
45+
**Fast iteration** — load the plugin directly from this working tree, no marketplace round-trip. The plugin lives in a subdirectory, so target it explicitly:
3346

3447
```bash
35-
claude --plugin-dir .
48+
claude --plugin-dir ./plugins/cpln
3649
```
3750

38-
`--plugin-dir` loads the plugin for that session only. Edits to skills, agents, commands, and rules pick up on `/reload-plugins`; edits to `plugin.json`, `hooks/hooks.json`, or MCP config files require restarting the session.
51+
`--plugin-dir` loads the plugin for that session only. Edits to skills, agents, commands, and rules pick up on `/reload-plugins`; edits to `plugin.json`, `hooks/cpln-hooks.json`, or MCP config files require restarting the session.
3952

4053
**Pre-release verification** — exercise the actual user-facing install path before tagging a release:
4154

@@ -49,24 +62,31 @@ Use this to catch install-time issues `--plugin-dir` skips: missing files in the
4962
### Validation
5063

5164
```bash
52-
claude plugin validate . # validates .claude-plugin/* manifests
53-
jq empty .claude-mcp.json .app.json \
54-
.claude-plugin/plugin.json .claude-plugin/marketplace.json \
55-
.codex-plugin/plugin.json .codex-plugin/mcp.json \
56-
gemini-extension.json hooks/hooks.json \
57-
.agents/plugins/marketplace.json
65+
claude plugin validate . # validates .claude-plugin/marketplace.json
66+
gemini extensions validate . # validates gemini-extension.json + hooks/hooks.json
67+
jq empty \
68+
.claude-plugin/marketplace.json \
69+
.agents/plugins/marketplace.json \
70+
gemini-extension.json \
71+
hooks/hooks.json \
72+
plugins/cpln/.claude-plugin/plugin.json \
73+
plugins/cpln/.codex-plugin/plugin.json \
74+
plugins/cpln/.codex-plugin/mcp.json \
75+
plugins/cpln/.claude-mcp.json \
76+
plugins/cpln/.app.json \
77+
plugins/cpln/hooks/cpln-hooks.json
5878
```
5979

80+
Codex has no native validator on the CLI; it validates implicitly at install/load. After `codex plugin marketplace add "$(pwd)"`, start a session and check `~/.codex/log/codex-tui.log` for `cpln` or `controlplane` warnings — none should appear.
81+
6082
### Debug plugin loading
6183

6284
```bash
63-
claude --debug
85+
claude --plugin-dir ./plugins/cpln --debug hooks
6486
```
6587

66-
Look for "loading plugin" messages and confirm each component directory (skills, agents, commands, hooks) appears. Use `--debug hooks` (or other category filters shown in `claude --help`) to narrow the output.
67-
68-
To exercise a hook, trigger the matching tool call (Bash for the current hooks) and watch for the `BLOCK:` stderr message; hook definitions live in `hooks/hooks.json`.
88+
Look for "loading plugin" messages and confirm each component directory (skills, agents, commands, hooks) appears. Use `--debug hooks` (or other category filters shown in `claude --help`) to narrow the output. To exercise a hook, trigger the matching tool call (Bash for the current hooks) and watch for the deny message — hook definitions for Claude/Codex live in `plugins/cpln/hooks/cpln-hooks.json` and the Gemini equivalents live in `hooks/hooks.json` at repo root.
6989

7090
## Versioning
7191

72-
Versions in `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, and `gemini-extension.json` must stay aligned. See `CONTRIBUTING.md` for the full release checklist.
92+
Versions in `plugins/cpln/.claude-plugin/plugin.json`, `plugins/cpln/.codex-plugin/plugin.json`, and `gemini-extension.json` must stay aligned. See `CONTRIBUTING.md` for the full release checklist.

CONTRIBUTING.md

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,24 @@
55
- Keep wording precise and operational, not promotional.
66
- Do not invent unsupported client features, marketplace listings, commands, or URLs.
77
- Prefer least-privilege and explicit-confirmation guidance for write-capable workflows.
8-
- Verify `cpln` CLI syntax against `rules/cli-conventions.md`, `skills/cpln/SKILL.md`, `cpln <command> --help`, or MCP suggestion tools.
8+
- Verify `cpln` CLI syntax against `plugins/cpln/rules/cli-conventions.md`, `plugins/cpln/skills/cpln/SKILL.md`, `cpln <command> --help`, or MCP suggestion tools.
99

1010
## Local Checks
1111

1212
Run checks that match the files you changed:
1313

1414
```bash
15-
jq empty .claude-mcp.json .app.json .claude-plugin/plugin.json .claude-plugin/marketplace.json .codex-plugin/plugin.json .codex-plugin/mcp.json gemini-extension.json hooks/hooks.json .agents/plugins/marketplace.json
15+
jq empty \
16+
.claude-plugin/marketplace.json \
17+
.agents/plugins/marketplace.json \
18+
gemini-extension.json \
19+
hooks/hooks.json \
20+
plugins/cpln/.claude-plugin/plugin.json \
21+
plugins/cpln/.codex-plugin/plugin.json \
22+
plugins/cpln/.codex-plugin/mcp.json \
23+
plugins/cpln/.claude-mcp.json \
24+
plugins/cpln/.app.json \
25+
plugins/cpln/hooks/cpln-hooks.json
1626
gemini extensions validate .
1727
```
1828

@@ -22,12 +32,12 @@ For Markdown-only changes, review links, tables, frontmatter, and command exampl
2232

2333
This repo follows [Semantic Versioning](https://semver.org/). The version lives in four manifests that must stay aligned:
2434

25-
| File | Path |
26-
| ----------------------------------- | ----------------------------- |
27-
| `.claude-plugin/plugin.json` | `.version` |
28-
| `.claude-plugin/marketplace.json` | `.plugins[0].version` |
29-
| `.codex-plugin/plugin.json` | `.version` |
30-
| `gemini-extension.json` | `.version` |
35+
| File | Path |
36+
| --------------------------------------------- | ----------------------------- |
37+
| `plugins/cpln/.claude-plugin/plugin.json` | `.version` |
38+
| `.claude-plugin/marketplace.json` | `.plugins[0].version` |
39+
| `plugins/cpln/.codex-plugin/plugin.json` | `.version` |
40+
| `gemini-extension.json` | `.version` |
3141

3242
Pick the bump based on what changed since the last tag:
3343

@@ -81,12 +91,12 @@ Run before tagging:
8191
- `CHANGELOG.md` `[Unreleased]` section is empty (everything moved into the new versioned section).
8292
- `README.md` install instructions match the published marketplace IDs.
8393
- No real secrets, service account tokens, or org-specific values in the diff.
84-
- `.codex-plugin/mcp.json` uses Codex MCP fields (`url`, `bearer_token_env_var`) and not raw auth headers.
85-
- `.claude-mcp.json` uses Claude Code MCP fields (`type`, `url`, `headers`) with environment interpolation.
94+
- `plugins/cpln/.codex-plugin/mcp.json` uses Codex MCP fields (`url`, `bearer_token_env_var`) and not raw auth headers.
95+
- `plugins/cpln/.claude-mcp.json` uses Claude Code MCP fields (`type`, `url`, `headers`) with environment interpolation.
8696
- `gemini-extension.json` MCP block uses Gemini CLI fields (`httpUrl`, `headers`) and declares any required extension settings.
8797
- `LICENSE`, `SECURITY.md`, `.env.example`, `.gitignore` are present.
8898
- `gemini extensions validate .` is clean.
89-
- `claude plugin validate .claude-plugin/plugin.json` is clean (or only the deliberate developer-CLAUDE.md warning).
99+
- `claude plugin validate .` is clean (or only the deliberate developer-CLAUDE.md warning).
90100

91101
## Pull Requests
92102

0 commit comments

Comments
 (0)