Skip to content
Open
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
19 changes: 19 additions & 0 deletions .agents/plugins/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "maister-plugins",
"interface": {
"displayName": "Maister"
},
"plugins": [
{
"name": "maister-codex",
"source": {
"source": "local",
"path": "./plugins/maister-codex"
},
"policy": {
"installation": "AVAILABLE"
},
"category": "Development"
}
]
}
8 changes: 8 additions & 0 deletions .github/workflows/build-copilot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20'
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: python -m pip install PyYAML==6.0.2

- name: Build Copilot CLI variant
run: make build

Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20'
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: python -m pip install PyYAML==6.0.2

- name: Build and validate
run: make build && make validate

Expand Down
25 changes: 25 additions & 0 deletions .github/workflows/validate-codex.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Validate Codex Port
on:
pull_request:
push:
branches: [master, beta, v2]
workflow_dispatch:

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install validation dependency
run: python -m pip install PyYAML==6.0.2
- name: Validate package and runtime contracts
run: make validate
29 changes: 29 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Maister repository guidance

This repository contains workflow plugins. Treat `plugins/maister/` as the Claude Code source and `plugins/maister-copilot/` as generated output; never edit the generated Copilot package directly.

The Codex port lives in `plugins/maister-codex/`. Keep it Codex-native: use `AGENTS.md` for durable project instructions, skills for reusable workflows, and `.codex/agents/*.toml` for project-scoped specialist subagents. Do not add Claude-only tool directives such as `AskUserQuestion`, `TaskCreate`, or `TaskUpdate` to the Codex port.

## Versioning

Releases keep all manifests at the same version (see `CLAUDE.md` "Beta Branch Management" for the branch workflow). Four manifests carry the version:

- `.claude-plugin/marketplace.json`
- `.agents/plugins/marketplace.json` (Codex-native catalog; lists `maister-codex` only, no version field)
- `plugins/maister/.claude-plugin/plugin.json`
- `plugins/maister-copilot/.claude-plugin/plugin.json`
- `plugins/maister-codex/.codex-plugin/plugin.json`

## Validation

Run `make validate` (includes `validate-codex`) before handoff. Additionally validate with the local Codex tooling when available (path is machine-specific):

```bash
python3 ~/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py plugins/maister-codex
```

Validate every changed skill with:

```bash
python3 ~/.codex/skills/.system/skill-creator/scripts/quick_validate.py <skill-directory>
```
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,11 @@ After `git merge --squash`, git doesn't record that beta's commits were merged.

### Manifest files to update

These three files need version/name changes during the merge workflow:
These four files need version/name changes during the merge workflow:
- `.claude-plugin/marketplace.json` — name + version + descriptions
- `plugins/maister/.claude-plugin/plugin.json` — version + description
- `plugins/maister-copilot/.claude-plugin/plugin.json` — version + description
- `plugins/maister-codex/.codex-plugin/plugin.json` — version + description

## Testing Changes

Expand Down
24 changes: 23 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build validate clean watch
.PHONY: build validate validate-codex clean watch

build:
bash platforms/copilot-cli/build.sh
Expand All @@ -17,6 +17,28 @@ validate:
@echo "Checking no maister: prefixes in copilot variant..."
@! grep -r 'maister:' plugins/maister-copilot/ --include="*.md" 2>/dev/null || (echo "FAIL: maister: prefix found" && exit 1)
@echo "All checks passed"
@$(MAKE) validate-codex

validate-codex:
@echo "Checking codex plugin manifest parses..."
@node -e "JSON.parse(require('fs').readFileSync('plugins/maister-codex/.codex-plugin/plugin.json','utf8'))" || (echo "FAIL: invalid plugin.json" && exit 1)
@echo "Checking codex hooks config parses..."
@node -e "JSON.parse(require('fs').readFileSync('plugins/maister-codex/hooks/hooks.json','utf8'))" || (echo "FAIL: invalid hooks.json" && exit 1)
@echo "Checking codex hook scripts..."
@for f in plugins/maister-codex/hooks/*.mjs; do node --check "$$f" || exit 1; done
@echo "Checking no Claude-only artifacts in codex skills..."
@! grep -rE 'AskUserQuestion|TaskCreate|TaskUpdate|SlashCommand|Skill tool|Task tool|CLAUDE_PLUGIN_ROOT|CLAUDE\.md|/maister:' plugins/maister-codex/skills/ 2>/dev/null || (echo "FAIL: Claude-only artifact found in codex skills" && exit 1)
@echo "Checking codex SKILL.md names match directories..."
@for d in plugins/maister-codex/skills/*/; do n=$$(basename $$d); grep -q "^name: $$n$$" "$$d/SKILL.md" || { echo "FAIL: $$d frontmatter name != $$n"; exit 1; }; done
@echo "Checking codex agent template names match filenames..."
@for f in plugins/maister-codex/skills/maister-init/assets/agents/*.toml; do b=$$(basename $$f .toml); grep -q "^name = \"$$b\"$$" "$$f" || { echo "FAIL: $$f name != $$b"; exit 1; }; done
@echo "Checking codex-native marketplace manifest parses..."
@node -e "const m=JSON.parse(require('fs').readFileSync('.agents/plugins/marketplace.json','utf8')); if(!m.plugins.some(p=>p.name==='maister-codex')) throw new Error('maister-codex missing')" || (echo "FAIL: invalid .agents/plugins/marketplace.json" && exit 1)
@node scripts/sync-codex-hooks.mjs
@python3 scripts/validate-codex.py
@python3 -B -m unittest discover -s tests -p 'test_*.py'
@node --test tests/*.test.mjs
@echo "Codex checks passed"

clean:
rm -rf plugins/maister-copilot/
Expand Down
38 changes: 38 additions & 0 deletions plugins/maister-codex/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "maister-codex",
"version": "2.2.3",
"description": "Structured, standards-aware development workflows for Codex",
"author": {
"name": "SkillPanel",
"email": "marek@skillpanel.com"
},
"license": "MIT",
"keywords": [
"development",
"standards",
"testing",
"workflow",
"migration",
"performance",
"research"
],
"skills": "./skills/",
"mcpServers": "./.mcp.json",
"interface": {
"displayName": "Maister Codex",
"shortDescription": "Standards-aware software delivery workflows.",
"longDescription": "Plan, implement, migrate, optimize, research, design, and verify software changes with project standards, explicit gates, resumable artifacts, browser checks, and focused Codex subagents.",
"developerName": "SkillPanel",
"category": "Development",
"capabilities": [
"Interactive",
"Write",
"Testing"
],
"defaultPrompt": [
"Use Maister to plan and implement this feature.",
"Use Maister to migrate or optimize this system.",
"Initialize Maister standards for this repository."
]
}
}
8 changes: 8 additions & 0 deletions plugins/maister-codex/.mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp@latest"]
}
}
}
13 changes: 13 additions & 0 deletions plugins/maister-codex/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Maister Codex plugin guidance

This directory is the Codex-native Maister plugin. Preserve the workflow principles from `plugins/maister/`: standards awareness, explicit phase gates, user-confirmed rollback, focused verification, and resumable task artifacts. Do not add Claude-only tool directives or treat `plugins/maister-copilot/` as a source.

Use skills for reusable workflows and compose them by loading the named skill and following its instructions. Use Codex subagents only when the user, repository guidance, or the active skill explicitly requests delegation. Keep durable project guidance in `AGENTS.md`; keep workflow state under `.maister/tasks/`.

At a required user decision gate, prefer `request_user_input` when available. Otherwise ask the equivalent concise question in the final response and pause. Use execution approval only for sensitive tool actions, never as a substitute for a product, scope, design, or workflow choice. Never infer approval for rollback, destructive recovery, scope expansion, or acceptance of critical findings.

Codex custom agents are project-scoped, not plugin components. Maintain their distributable templates under `skills/maister-init/assets/agents/`; `$maister-codex:maister-init` copies selected templates into a project's `.codex/agents/` without replacing existing files unless the user approves it.

Keep plugin lifecycle hooks in `hooks/hooks.json`, which Codex discovers by default. Hook commands are inlined with `node --input-type=module -e` because plugin-root path variables are not reliably expanded across harnesses. Edit the readable `hooks/*.mjs` sources, then run `node scripts/sync-codex-hooks.mjs --write` from the repository root; validation checks the generated commands for drift. Keep bundled MCP configuration in `.mcp.json` and declare it through `mcpServers` in `.codex-plugin/plugin.json`. The current repository validator does not accept a manifest `hooks` field, so do not add one while the default hook path is used.

Keep skills focused and self-contained. Put detailed reusable guidance in `references/`, deterministic helpers in `scripts/`, and templates in `assets/`; do not create a `README.md` inside a skill folder. Validate every changed skill and the plugin before handoff.
44 changes: 44 additions & 0 deletions plugins/maister-codex/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Maister for Codex

Maister provides Codex-native, standards-aware workflows for software delivery. It preserves resumable task artifacts, explicit approval gates, test-first implementation, focused verification, and user-confirmed rollback while leaving the Claude Code source package untouched.

## Workflows

- `$maister-codex:maister-work` classifies and routes software tasks, including resumes from existing `.maister/tasks/` directories.
- `$maister-codex:maister-development`, `$maister-codex:maister-performance`, `$maister-codex:maister-migration`, `$maister-codex:maister-research`, and `$maister-codex:maister-product-design` run full resumable workflows.
- `$maister-codex:maister-quick-dev`, `$maister-codex:maister-quick-plan`, and `$maister-codex:maister-quick-bugfix` handle focused work.
- `$maister-codex:maister-codebase-analysis`, `$maister-codex:maister-implementation-plan-executor`, `$maister-codex:maister-verify`, and `$maister-codex:maister-mockup-studio` provide reusable workflow stages.
- `$maister-codex:maister-reviews-code`, `$maister-codex:maister-reviews-pragmatic`, `$maister-codex:maister-reviews-production-readiness`, `$maister-codex:maister-reviews-reality-check`, and `$maister-codex:maister-reviews-spec-audit` provide focused read-only reviews.
- `$maister-codex:maister-init`, `$maister-codex:maister-docs-manager`, `$maister-codex:maister-standards-discover`, and `$maister-codex:maister-standards-update` initialize and maintain project guidance.

The plugin bundles Playwright MCP for browser verification, mockups, and screenshot-backed documentation. It also includes Node-based lifecycle hooks: reminders for explicit skill invocation and state recovery after compaction, plus a PreToolUse guard that denies common destructive shell commands (`git stash`, `git reset --hard`, `git clean`, force-push, `rm -rf`). The guard applies to the main agent and subagents alike because the hook payload does not guarantee agent identity. It is a heuristic guardrail, not a complete shell security boundary. For an explicitly authorized operation blocked by the guard, the user must review and disable that hook in `/hooks`; agents must not work around it with alternate syntax or tools. Codex asks you to review and trust plugin hooks before they run. Node.js is required for hooks, the HTML mockup companion, and Playwright MCP; no separate `jq` or Bash dependency is used.

## Specialist agents

`$maister-codex:maister-init` can copy 25 optional specialist templates into the current repository's `.codex/agents/` directory. This is the Codex-native distribution path for project-scoped custom agents; installing the plugin alone does not modify a repository's agent configuration. Existing templates are preserved unless you explicitly approve replacement. Maister workflows delegate to these agents by name when they are installed (for example `maister-task-group-implementer` during implementation waves, `maister-code-reviewer` during verification) and fall back to inline execution when they are absent.

## Installation

Install directly from GitHub:

```bash
codex plugin marketplace add SkillPanel/Maister
codex plugin add maister-codex@maister-plugins
```

Add `--ref <branch>` to install from a branch instead of the default one.

## Local testing

Repository validation requires Node.js 20+, Python 3.11+, and PyYAML (also used by the local Codex skill validators). Run `make validate` for metadata, state examples, hook/source consistency, and temporary-fixture regression tests. The runtime tests need permission to bind loopback ports 3847–3850. After changing a hook source, run `node scripts/sync-codex-hooks.mjs --write` before validation.

Register a local checkout as a marketplace, then install the plugin:

```bash
codex plugin marketplace add /absolute/path/to/Maister
codex plugin add maister-codex@maister-plugins
```

Codex reads the native catalog at `.agents/plugins/marketplace.json` (named `maister-plugins`), which lists only the Codex package; `.claude-plugin/marketplace.json` remains the Claude Code / Copilot catalog. Start a new Codex thread after installation, then invoke a skill with `$maister-codex:maister-init` or `$maister-codex:maister-work`.

Use `/hooks` to review bundled hooks and `/mcp verbose` to confirm the Playwright server. The first Playwright use may require `npx` to download `@playwright/mcp` under the active sandbox and network policy.
35 changes: 35 additions & 0 deletions plugins/maister-codex/hooks/block-destructive-commands.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Source of the inline `node -e` command in hooks.json (kept path-free there because
// plugin-root variables are not reliably expanded). Keep both in sync when editing.
// PreToolUse does not guarantee agent identity. Apply the same guard to all
// shell calls; missing identity must never imply a privileged main agent.

let input = '';
for await (const chunk of process.stdin) input += chunk;

let event = {};
try {
event = input.trim() ? JSON.parse(input) : {};
} catch {
event = {};
}

const command =
(event.tool_input && (event.tool_input.command || event.tool_input.cmd)) ||
(event.toolInput && (event.toolInput.command || event.toolInput.cmd)) ||
'';

const destructive =
/git\s+stash|git\s+reset\s+--hard|git\s+checkout\s+--\s+\.|git\s+checkout\s+\.\s*$|git\s+clean|git\s+push\s+(-f|--force)|rm\s+-rf/i;

if (typeof command === 'string' && destructive.test(command)) {
const payload = {
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'deny',
permissionDecisionReason: 'Destructive command blocked by the Maister shell guard. An explicitly authorized operation requires the user to review and disable this guard in /hooks; do not bypass it with alternate syntax or tools.',
},
};
process.stdout.write(`${JSON.stringify(payload)}\n`);
}

process.exit(0);
Loading
Loading