diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json new file mode 100644 index 0000000..8094a00 --- /dev/null +++ b/.agents/plugins/marketplace.json @@ -0,0 +1,164 @@ +{ + "name": "devstefancho-claude-plugins", + "interface": { + "displayName": "Devstefancho Multi-Agent Plugins" + }, + "plugins": [ + { + "name": "stop-notification-plugin", + "source": { + "source": "local", + "path": "./stop-notification-plugin" + }, + "policy": { + "installation": "NOT_AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Productivity" + }, + { + "name": "test-commit-push-pr-clean-plugin", + "source": { + "source": "local", + "path": "./test-commit-push-pr-clean-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Coding" + }, + { + "name": "writing-specs-plugin", + "source": { + "source": "local", + "path": "./writing-specs-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Coding" + }, + { + "name": "writing-tasks-plugin", + "source": { + "source": "local", + "path": "./writing-tasks-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Coding" + }, + { + "name": "computer-use-plugin", + "source": { + "source": "local", + "path": "./computer-use-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Engineering" + }, + { + "name": "implement-with-test-plugin", + "source": { + "source": "local", + "path": "./implement-with-test-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Coding" + }, + { + "name": "brain-storm-plugin", + "source": { + "source": "local", + "path": "./brain-storm-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Coding" + }, + { + "name": "agent-team-plugin", + "source": { + "source": "local", + "path": "./agent-team-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Coding" + }, + { + "name": "llm-wiki-plugin", + "source": { + "source": "local", + "path": "./llm-wiki-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Productivity" + }, + { + "name": "hermes", + "source": { + "source": "local", + "path": "./hermes-gateway-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Engineering" + }, + { + "name": "split-work-plugin", + "source": { + "source": "local", + "path": "./split-work-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Coding" + }, + { + "name": "browser-walkthrough-plugin", + "source": { + "source": "local", + "path": "./browser-walkthrough-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Engineering" + }, + { + "name": "session-resume-plugin", + "source": { + "source": "local", + "path": "./session-resume-plugin" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Productivity" + } + ] +} diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 657d6a7..12cf3cf 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -64,6 +64,11 @@ "name": "browser-walkthrough-plugin", "source": "./browser-walkthrough-plugin", "description": "Headed browser walkthrough — step-by-step interactive flow for iframe/security-heavy sites. Requires playwright-cli skill" + }, + { + "name": "session-resume-plugin", + "source": "./session-resume-plugin", + "description": "Resume work from a previous Claude Code or Codex CLI session by reading the last N turns from its JSONL transcript" } ] } diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..2b75fd7 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,206 @@ +# AGENTS.md + +This file is the single source of truth for coding agents working in this repository — Claude Code, Codex CLI, Cursor, Amp, Jules, and others. `CLAUDE.md` is a one-line `@AGENTS.md` import so Claude Code reads the same content; other agents read this file directly. + +## Repository Purpose + +This repository is a **multi-agent plugins marketplace** containing reusable extensions that can be shared across projects and teams. It serves both: + +- **Claude Code** — via `.claude-plugin/marketplace.json` and per-plugin `.claude-plugin/plugin.json` +- **Codex CLI** — via `.agents/plugins/marketplace.json` and per-plugin `.codex-plugin/plugin.json` + +The actual plugin content (skills, agents, commands) is shared between both tools wherever the formats are compatible. + +## Plugin Layout + +Each plugin is self-contained and dual-published: + +``` +plugin-name/ +├── .claude-plugin/ +│ └── plugin.json # Claude Code manifest (required for Claude Code) +├── .codex-plugin/ +│ └── plugin.json # Codex CLI manifest (required for Codex) +├── commands/ # Slash commands — Claude Code primary +│ └── example.md +├── agents/ # Subagents — both tools +│ └── helper.md +├── skills/ # Agent Skills — both tools (SKILL.md format is shared) +│ └── my-skill/ +│ ├── SKILL.md +│ ├── PRINCIPLES.md +│ └── EXAMPLES.md +├── hooks/ # Event hooks (Claude Code format) +│ └── hooks.json +├── .mcp.json # MCP servers (Claude Code format) +├── codex.config.toml.snippet # MCP servers (Codex config.toml fragment, when applicable) +└── README.md # Usage for both tools +``` + +The required files are `.claude-plugin/plugin.json` and `.codex-plugin/plugin.json`. All other components are optional. + +## Component Compatibility Matrix + +| Component | Claude Code | Codex CLI | Notes | +|-----------|-------------|-----------|-------| +| Skills (`skills//SKILL.md`) | ✓ | ✓ | Same format — single source | +| Subagents (`agents/*.md`) | ✓ | ✓ | Same format — single source | +| Slash commands (`commands/*.md`) | ✓ | via skills only | Add a skill for any command that should work in Codex | +| Hooks (`hooks/hooks.json`) | ✓ | format differs | Claude Code only; mark hook-only plugins unavailable for Codex | +| MCP (`.mcp.json` / `config.toml`) | ✓ | ✓ | Distinct files; same servers | +| Plugin manifest | `.claude-plugin/plugin.json` | `.codex-plugin/plugin.json` | Mirror each other | +| Marketplace catalog | `.claude-plugin/marketplace.json` | `.agents/plugins/marketplace.json` | Mirror each other | + +## Adding or Updating a Plugin + +1. Create or update files in the plugin directory. +2. Update **both** manifests when metadata changes: + - `/.claude-plugin/plugin.json` + - `/.codex-plugin/plugin.json` +3. Bump the `version` in both manifests (semver). +4. If adding a new plugin, add an entry to **both** marketplace files: + - `.claude-plugin/marketplace.json` + - `.agents/plugins/marketplace.json` +5. If the plugin is Claude-only (for example hook-only), keep the Codex manifest but mark the Codex marketplace entry as `NOT_AVAILABLE`. +6. Run `scripts/sync-marketplace.sh` to regenerate the Codex marketplace from the Claude side. +7. Run `scripts/validate-plugins.sh` before committing to verify manifests and Codex marketplace schema stay in sync. + +## Installing Plugins + +### Claude Code + +```bash +# Inside Claude Code +/plugin marketplace add devstefancho/claude-plugins +/plugin install @devstefancho-claude-plugins +``` + +### Codex CLI + +```bash +# In your shell +codex plugin marketplace add devstefancho/claude-plugins +``` + +Codex CLI manages marketplaces with `codex plugin marketplace add|upgrade|remove`. Individual plugin enablement is handled by Codex's plugin UI/policy rather than a `codex plugin install` CLI subcommand. + +For local development with either tool, point the marketplace add command at the repo path instead of the GitHub shorthand (see below). + +## Local Plugin Development + +### Claude Code + +```bash +# From repository root +claude + +# Inside Claude Code +/plugin marketplace add . +/plugin install @devstefancho-claude-plugins +``` + +Restart Claude Code after install to activate the plugin. + +### Codex CLI + +```bash +# From repository root +codex plugin marketplace add . +``` + +Restart your Codex session and enable the plugin from Codex's plugin UI/policy to activate it. + +## Iterating on Plugin Components + +When updating a plugin during development, reinstall or refresh it so the tool picks up changes. + +**Claude Code:** + +```bash +/plugin uninstall @devstefancho-claude-plugins +/plugin install @devstefancho-claude-plugins +``` + +**Codex CLI:** + +```bash +codex plugin marketplace upgrade devstefancho-claude-plugins +``` + +## Plugin Components — Shared Conventions + +**Skills** (`skills//SKILL.md`) +- Required `SKILL.md` with metadata frontmatter and instructions. +- Optional supporting files (`PRINCIPLES.md`, `EXAMPLES.md`, `scripts/`, `references/`). +- Auto-loaded by both tools when relevant context is detected. + +**Subagents** (`agents/*.md`) +- One Markdown file per subagent. +- Both Claude Code and Codex understand subagent definitions in this directory. + +**Slash Commands** (`commands/*.md`) +- Markdown with frontmatter (`description`, `argument-hint`, `allowed-tools`). +- Native to Claude Code. For Codex, provide an equivalent `skills//SKILL.md`; Codex prompts are deprecated. + +**Event Hooks** (`hooks/hooks.json`) +- Currently Claude Code-specific. See `stop-notification-plugin/hooks/hooks.json` for an example. +- Codex's lifecycle hook format differs and is not auto-mirrored. + +**MCP Servers** +- Claude Code reads `.mcp.json` at the plugin root. +- Codex reads `~/.codex/config.toml` (`[mcp_servers.]`). Plugins shipping MCP servers should also include a `codex.config.toml.snippet` describing the equivalent block. + +## Maintenance Scripts + +Both scripts require [`jq`](https://jqlang.github.io/jq/). + +### `scripts/validate-plugins.sh` + +Checks consistency between the Claude and Codex copies, plus the Codex marketplace schema. Fails if anything is missing or has drifted. + +```bash +scripts/validate-plugins.sh +``` + +What it verifies: +- Every plugin with `.claude-plugin/plugin.json` also has `.codex-plugin/plugin.json`. +- `name`, `version`, and `description` agree between the two manifests of each plugin. +- Each Codex manifest declares `"skills": "./skills/"` when the plugin ships a `skills/` directory. +- `.claude-plugin/marketplace.json` and `.agents/plugins/marketplace.json` list the same plugin names. +- Each Codex marketplace entry uses the correct schema: `source.source = "local"`, `source.path` matches the Claude side, `policy.installation` ∈ {`AVAILABLE`, `NOT_AVAILABLE`, `INSTALLED_BY_DEFAULT`}, `policy.authentication` ∈ {`ON_INSTALL`, `ON_USE`}, and `category` is non-empty. +- Every `AVAILABLE` Codex plugin actually has at least one Codex-loadable component (`skills/`, `agents/`, `.app.json`, or `codex.config.toml.snippet`). + +Run this before pushing any change that touches manifests or the marketplace catalog. A failing run almost always means one of the paired files was edited without the other. + +### `scripts/sync-marketplace.sh` + +Generates the Codex marketplace mirror from the Claude one, applying Codex's marketplace schema (wrapping `source` as an object, attaching `policy` and `category`). + +```bash +scripts/sync-marketplace.sh # write .agents/plugins/marketplace.json from .claude-plugin/marketplace.json +scripts/sync-marketplace.sh --check # exit non-zero if the mirror is out of date (CI-friendly) +``` + +The Claude catalog remains the single source for plugin names and source paths; Codex-specific fields (`policy.installation`, `category`, `interface.displayName`) are derived inside the script. Edit the script's mapping table when you add a new plugin that needs a non-default policy or category. + +Recommended workflow when adding or removing a marketplace entry: + +1. Edit `.claude-plugin/marketplace.json` (the single source). +2. Run `scripts/sync-marketplace.sh` to update `.agents/plugins/marketplace.json`. +3. Run `scripts/validate-plugins.sh` to confirm the mirror, per-plugin manifests, and Codex schema are consistent. +4. Commit both files together. + +## Distribution + +Plugins are shared via: + +1. **Git Repository** — both tools support GitHub shorthand (`/`). +2. **Local Development** — point the tool's marketplace at a local path. +3. **Team Configuration** — use `.claude/settings.json` for Claude Code; Codex records configured marketplaces in `~/.codex/config.toml` after `codex plugin marketplace add`. + +## See Also + +- Per-plugin `README.md` files for usage details. +- Claude Code documentation: use the `claude-code-guide` subagent for up-to-date references. +- Codex documentation: +- AGENTS.md open standard: diff --git a/CLAUDE.md b/CLAUDE.md index 3538b1c..43c994c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,218 +1 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Repository Purpose - -This repository serves as a **Claude Code plugins marketplace** containing reusable extensions that can be shared across projects and teams. Plugins provide custom slash commands, Agent Skills, subagents, hooks, and MCP server integrations. - -## Plugin Development Workflow - -### Adding New Plugins - -Each plugin follows this standard structure: - -``` -plugin-name/ -├── .claude-plugin/ -│ └── plugin.json # Plugin metadata (required) -├── commands/ # Slash commands (optional) -│ └── example.md -├── agents/ # Subagents (optional) -│ └── helper.md -├── skills/ # Agent Skills (optional) -│ └── my-skill/ -│ ├── SKILL.md -│ ├── PRINCIPLES.md # Reference docs -│ └── EXAMPLES.md -├── hooks/ # Event handlers (optional) -│ └── hooks.json -├── .mcp.json # MCP servers (optional) -└── README.md # Usage documentation -``` - -The only required file is `.claude-plugin/plugin.json`. Add other components as needed. - -### Testing Plugins Locally - -```bash -# From repository root -claude - -# Within Claude Code -/plugin marketplace add . -/plugin install plugin-name@devstefancho-claude-plugins -``` - -After installation, restart Claude Code to activate the plugin. - -### Iterating on Plugin Components - -When developing or updating plugin components (skills, commands, hooks): - -1. Modify files within the plugin directory -2. Uninstall the plugin: `/plugin uninstall plugin-name@devstefancho-claude-plugins` -3. Reinstall to test changes: `/plugin install plugin-name@devstefancho-claude-plugins` -4. Restart Claude Code if needed - -## Plugin Architecture - -### Marketplace Configuration - -`.claude-plugin/marketplace.json` defines all available plugins: -- Lists plugin names and their source directories -- Metadata for discovery and installation -- Used by `/plugin install` commands - -### Plugin Metadata - -Each plugin requires `.claude-plugin/plugin.json`: -- `name`: Plugin identifier (kebab-case) -- `description`: Human-readable summary -- `version`: Semantic versioning (e.g., 1.0.0) -- `author`: Author information - -### Plugin Components - -**Slash Commands** (`commands/`) -- Markdown files with frontmatter metadata -- One file per command (e.g., `spec.md` defines `/spec`) -- Include `description` and `argument-hint` in frontmatter - -**Agent Skills** (`skills/`) -- Directory structure: `skills/skill-name/SKILL.md` -- Main skill definition in `SKILL.md` with metadata and instructions -- Supporting documentation in `PRINCIPLES.md` and `EXAMPLES.md` -- Skills are automatically available when plugin is installed - -**Subagents** (`agents/`) -- Custom agent definitions -- Extend Claude Code's agent capabilities - -**Event Hooks** (`hooks/`) -- Automation based on IDE events -- Defined in `hooks.json` - -**MCP Servers** (`.mcp.json`) -- External tool integration -- Provides LLM-compatible tool definitions - -## Key Directories - -- **`.claude-plugin/`** - Marketplace and plugin metadata - - `marketplace.json` - Marketplace catalog - - Plugin directories contain `.claude-plugin/plugin.json` - -- **Plugin directories** (e.g., `agent-team-plugin/`, `writing-specs-plugin/`) - - Each plugin is self-contained and independently installable - - Include README.md with installation and usage instructions - -## Adding New Content to Plugins - -When extending existing plugins or creating new ones: - -1. **For new slash commands**: Add markdown file to `plugin-name/commands/` -2. **For new skills**: Create directory under `plugin-name/skills/` -3. **For new subagents**: Add markdown file to `plugin-name/agents/` -4. **For MCP servers**: Add or update `.mcp.json` in plugin root -5. **For hooks**: Add to or update `plugin-name/hooks/hooks.json` - -After adding components, update the plugin's `.claude-plugin/plugin.json` version number. - -## Managing MCP Servers through Plugins - -### Plugin-based MCP Server Configuration - -Each plugin can include its own `.mcp.json` file at the plugin root to define MCP (Model Context Protocol) servers. This enables: - -- **Server Isolation**: Each plugin manages its own MCP servers independently -- **Dependency Management**: MCP servers are installed/removed with the plugin -- **Team Sharing**: Common MCP configurations can be distributed via plugins -- **Clean Separation**: No conflicts when multiple plugins define MCP servers - -### Creating a Plugin with MCP Servers - -When adding MCP servers to a plugin: - -1. Create `.mcp.json` in the plugin root directory -2. Define your MCP server configurations in the standard format: - -```json -{ - "mcpServers": { - "server-name": { - "command": "npx", - "args": ["server-package@latest"] - } - } -} -``` - -3. Document the MCP servers in the plugin's `README.md` -4. Update the plugin's `.claude-plugin/plugin.json` version number - -### Example: common-mcp-plugin - -The `common-mcp-plugin` provides shared MCP servers for the marketplace: - -``` -common-mcp-plugin/ -├── .claude-plugin/ -│ └── plugin.json -├── .mcp.json # Defines chrome-devtools, etc -└── README.md -``` - -When installed, all MCP servers defined in `common-mcp-plugin/.mcp.json` become available for use across Claude Code sessions. - -### Best Practices - -1. **Centralize common servers**: Use a dedicated plugin like `common-mcp-plugin` for widely-used MCP servers -2. **Plugin-specific servers**: Include specialized MCP servers directly in feature plugins -3. **Documentation**: Always document which MCP servers a plugin provides -4. **Version management**: Use semantic versioning and track MCP server updates in the plugin version - -## Distribution - -Plugins can be shared through: - -1. **Git Repository**: Commit to version control - ```bash - /plugin install plugin-name@your-org/claude-plugins - ``` - -2. **Local Development**: Reference repository path - ```bash - /plugin marketplace add ./path/to/repo - /plugin install plugin-name@your-local-marketplace - ``` - -3. **Team Repository Configuration**: Add to `.claude/settings.json` for automatic plugin installation across team projects - -## Common Commands - -```bash -# View all available plugins -/plugin - -# Add marketplace to local development -/plugin marketplace add . - -# Install a plugin -/plugin install plugin-name@devstefancho-claude-plugins - -# List installed plugins -/plugin - -# Uninstall a plugin -/plugin uninstall plugin-name@devstefancho-claude-plugins - -# View installed commands -/help -``` - -## See Also - -- Claude Code Plugins Documentation: use the `claude-code-guide` subagent for up-to-date references -- Individual plugin READMEs: Each plugin contains usage documentation -- Plugin Structure: refer to existing plugins as examples (e.g., `writing-specs-plugin/`) +@AGENTS.md diff --git a/README.md b/README.md index 3449926..d9ef73e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ -# Claude Code Plugins Marketplace +# Multi-Agent Plugins Marketplace -A collection of reusable [Claude Code](https://claude.ai/code) plugins — slash commands, agent skills, subagents, hooks, and MCP server integrations. +A collection of reusable plugins for AI coding agents — slash commands, agent skills, subagents, hooks, and MCP server integrations. Supports both **[Claude Code](https://claude.ai/code)** and **[Codex CLI](https://developers.openai.com/codex)**, sharing skill/agent content between them. ## Quick Start +### Claude Code + ```bash # 1. Add this marketplace /plugin marketplace add devstefancho/claude-plugins @@ -14,94 +16,98 @@ A collection of reusable [Claude Code](https://claude.ai/code) plugins — slash # 3. Restart Claude Code to activate ``` -## Available Plugins +### Codex CLI + +```bash +# 1. Add this marketplace +codex plugin marketplace add devstefancho/claude-plugins -### Code Quality +# 2. Enable available plugins from Codex's plugin UI/policy +``` -| Plugin | Description | -|--------|-------------| -| [code-style-plugin](./code-style-plugin) | Code review based on SRP, DRY, Simplicity First, YAGNI, and Type Safety | -| [code-quality-plugin](./code-quality-plugin) | Code quality review focusing on DRY, KISS, and Clean Code principles | -| [frontend-plugin](./frontend-plugin) | React/Next.js component design review | +## Available Plugins ### Spec-Driven Development -| Plugin | Description | -|--------|-------------| -| [writing-specs-plugin](./writing-specs-plugin) | Spec writing with conflict detection and reporting | -| [simple-sdd-plugin](./simple-sdd-plugin) | SDD workflow: spec → plan → tasks → implement | -| [implement-with-test-plugin](./implement-with-test-plugin) | Implement code with tests from specs or direct requests | -| [brain-storm-plugin](./brain-storm-plugin) | Brainstorm features and improvements with wireframes and HTML prototype previews | +| Plugin | Claude Code | Codex | Description | +|--------|-------------|-------|-------------| +| [writing-specs-plugin](./writing-specs-plugin) | Yes | Yes | Spec-driven development with search, conflict detection, and reporting | +| [writing-tasks-plugin](./writing-tasks-plugin) | Yes | Yes | Decompose specs into persistent task files with dependency graph and progress tracking | +| [implement-with-test-plugin](./implement-with-test-plugin) | Yes | Yes | Implement code with tests from specs or direct requests | +| [brain-storm-plugin](./brain-storm-plugin) | Yes | Yes | Brainstorm features and improvements, then generate standalone HTML previews | ### Git & Workflow -| Plugin | Description | -|--------|-------------| -| [git-worktree-plugin](./git-worktree-plugin) | Manage git worktrees for parallel branch work | -| [git-commit-plugin](./git-commit-plugin) | Auto-generate conventional commit messages | -| [smart-commit-plugin](./smart-commit-plugin) | Split uncommitted changes into logical commits | -| [pr-create-plugin](./pr-create-plugin) | Create GitHub PRs with auto-generated descriptions | -| [test-commit-push-pr-clean-plugin](./test-commit-push-pr-clean-plugin) | Automate lint, test, commit, push, PR, and worktree cleanup | +| Plugin | Claude Code | Codex | Description | +|--------|-------------|-------|-------------| +| [test-commit-push-pr-clean-plugin](./test-commit-push-pr-clean-plugin) | Yes | Yes | Automate lint, test, commit, push, PR, and worktree cleanup | +| [split-work-plugin](./split-work-plugin) | Yes | Yes | Split current project work into parallel-safe task groups | -### Testing & Reporting +### Testing & Browser -| Plugin | Description | -|--------|-------------| -| [computer-use-plugin](./computer-use-plugin) | App testing via Computer Use MCP with feedback reports | -| [session-reporter-plugin](./session-reporter-plugin) | Generate HTML reports for work sessions | -| [worktrace-plugin](./worktrace-plugin) | Extract work history and generate daily summaries | +| Plugin | Claude Code | Codex | Description | +|--------|-------------|-------|-------------| +| [computer-use-plugin](./computer-use-plugin) | Yes | Yes | Computer Use MCP app testing with scenario execution and feedback reporting | +| [browser-walkthrough-plugin](./browser-walkthrough-plugin) | Yes | Yes | Headed browser walkthrough for iframe/security-heavy sites | ### Agent & Automation -| Plugin | Description | -|--------|-------------| -| [agent-team-plugin](./agent-team-plugin) | Create and manage agent teams for worktree sessions | -| [hermes-gateway-plugin](./hermes-gateway-plugin) | Interact with Hermes Agent via local or SSH connection | -| [stop-notification-plugin](./stop-notification-plugin) | macOS TTS notification when Claude stops or needs attention | - -### Tooling - -| Plugin | Description | -|--------|-------------| -| [scaffold-claude-feature](./scaffold-claude-feature) | Generate Claude Code features with proper structure | -| [common-mcp-plugin](./common-mcp-plugin) | Common MCP servers for shared tools and integrations | -| [local-test-plugin](./local-test-plugin) | Symlink-based local plugin testing | - -### Deprecated - -| Plugin | Description | -|--------|-------------| -| [spec-manager-plugin](./spec-manager-plugin) | Replaced by `writing-specs-plugin` | +| Plugin | Claude Code | Codex | Description | +|--------|-------------|-------|-------------| +| [agent-team-plugin](./agent-team-plugin) | Yes | Yes | Agent team management for worktree sessions | +| [hermes-gateway-plugin](./hermes-gateway-plugin) | Yes | Yes | Interact with Hermes Agent via local or SSH-tunneled connection | +| [llm-wiki-plugin](./llm-wiki-plugin) | Yes | Yes | LLM-maintained personal wiki with ingest, query, lint, update operations | +| [session-resume-plugin](./session-resume-plugin) | Yes | Yes | Resume work from a previous Claude Code or Codex CLI session by reading the last N turns from its JSONL transcript | +| [stop-notification-plugin](./stop-notification-plugin) | Yes | No | Claude Code hook-based macOS TTS notification when Claude stops or needs attention | ## Plugin Structure -Each plugin follows this layout: +Each plugin ships parallel manifests. Plugins marked as Codex-compatible include Codex-loadable components such as skills: ```text plugin-name/ ├── .claude-plugin/ -│ └── plugin.json # Plugin metadata (required) -├── commands/ # Slash commands -├── skills/ # Agent skills -├── agents/ # Subagents -├── hooks/ # Event handlers -├── .mcp.json # MCP servers +│ └── plugin.json # Claude Code manifest +├── .codex-plugin/ +│ └── plugin.json # Codex CLI manifest (mirrors the Claude manifest) +├── commands/ # Slash commands (Claude Code primary) +├── skills/ # Agent skills (shared — same SKILL.md format) +├── agents/ # Subagents (shared) +├── hooks/ # Event handlers (Claude Code format) +├── .mcp.json # MCP servers (Claude Code) └── README.md ``` +The marketplace catalog is mirrored at two locations: + +- `.claude-plugin/marketplace.json` — Claude Code +- `.agents/plugins/marketplace.json` — Codex CLI + +Run `scripts/sync-marketplace.sh` after editing the Claude file to update the Codex mirror, and `scripts/validate-plugins.sh` to verify manifests and Codex marketplace schema. See [`AGENTS.md`](./AGENTS.md) for the full compatibility matrix. + ## Local Development ```bash -# Clone and add as local marketplace +# Clone the repo git clone https://github.com/devstefancho/claude-plugins.git cd claude-plugins -claude +``` + +**Claude Code:** +```bash +claude # Inside Claude Code /plugin marketplace add . /plugin install @devstefancho-claude-plugins ``` +**Codex CLI:** + +```bash +codex plugin marketplace add . +``` + ## License MIT diff --git a/agent-team-plugin/.codex-plugin/plugin.json b/agent-team-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..5f1e898 --- /dev/null +++ b/agent-team-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "agent-team-plugin", + "description": "Agent team management - create, expand, and cleanup teams for worktree sessions", + "version": "2.0.5", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/brain-storm-plugin/.codex-plugin/plugin.json b/brain-storm-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..0378f1c --- /dev/null +++ b/brain-storm-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "brain-storm-plugin", + "description": "Brainstorm future features and improvements, then generate standalone HTML previews for UI ideas", + "version": "1.2.4", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/browser-walkthrough-plugin/.codex-plugin/plugin.json b/browser-walkthrough-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..52a7003 --- /dev/null +++ b/browser-walkthrough-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "browser-walkthrough-plugin", + "description": "Headed browser walkthrough — step-by-step interactive flow with the user. Pairs with playwright-cli skill for iframe-heavy/security-program-heavy sites (홈택스, 정부24, banking).", + "version": "1.0.0", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/computer-use-plugin/.codex-plugin/plugin.json b/computer-use-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..0180437 --- /dev/null +++ b/computer-use-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "computer-use-plugin", + "description": "Computer Use MCP app testing with scenario execution and feedback reporting", + "version": "1.0.0", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/hermes-gateway-plugin/.codex-plugin/plugin.json b/hermes-gateway-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..e3fa5cd --- /dev/null +++ b/hermes-gateway-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "hermes", + "description": "Interact with Hermes Agent via local or SSH-tunneled connection", + "version": "1.0.1", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/implement-with-test-plugin/.codex-plugin/plugin.json b/implement-with-test-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..b8c63aa --- /dev/null +++ b/implement-with-test-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "implement-with-test-plugin", + "description": "Implement code with tests from specs or direct requests", + "version": "1.0.2", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/llm-wiki-plugin/.codex-plugin/plugin.json b/llm-wiki-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..86ae89c --- /dev/null +++ b/llm-wiki-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "llm-wiki-plugin", + "description": "LLM-maintained personal wiki with ingest, query, lint, update operations", + "version": "1.1.0", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/scripts/sync-marketplace.sh b/scripts/sync-marketplace.sh new file mode 100755 index 0000000..9b5b145 --- /dev/null +++ b/scripts/sync-marketplace.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +# Mirror .claude-plugin/marketplace.json into .agents/plugins/marketplace.json +# using Codex's marketplace schema. The Claude catalog remains the source of +# truth for plugin names and source paths; Codex-specific policy/category fields +# are derived here. +# +# Usage: +# scripts/sync-marketplace.sh # write Codex mirror from Claude source +# scripts/sync-marketplace.sh --check # exit 1 if mirrors are out of sync +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +CLAUDE_FILE="$REPO_ROOT/.claude-plugin/marketplace.json" +CODEX_FILE="$REPO_ROOT/.agents/plugins/marketplace.json" + +if ! command -v jq >/dev/null 2>&1; then + echo "error: jq is required (install with 'brew install jq' or 'apt-get install jq')" >&2 + exit 2 +fi + +if [[ ! -f "$CLAUDE_FILE" ]]; then + echo "error: $CLAUDE_FILE not found" >&2 + exit 2 +fi + +build_codex() { + jq ' + def installation_policy: + if .name == "stop-notification-plugin" then "NOT_AVAILABLE" else "AVAILABLE" end; + + def category: + if .name == "stop-notification-plugin" then "Productivity" + elif .name == "llm-wiki-plugin" then "Productivity" + elif .name == "session-resume-plugin" then "Productivity" + elif .name == "computer-use-plugin" then "Engineering" + elif .name == "hermes" then "Engineering" + elif .name == "browser-walkthrough-plugin" then "Engineering" + else "Coding" + end; + + { + name: .name, + interface: { + displayName: "Devstefancho Multi-Agent Plugins" + }, + plugins: [ + .plugins[] | { + name: .name, + source: { + source: "local", + path: .source + }, + policy: { + installation: installation_policy, + authentication: "ON_INSTALL" + }, + category: category + } + ] + } + ' "$CLAUDE_FILE" +} + +mkdir -p "$(dirname "$CODEX_FILE")" + +if [[ "${1:-}" == "--check" ]]; then + if [[ ! -f "$CODEX_FILE" ]]; then + echo "error: $CODEX_FILE missing — run scripts/sync-marketplace.sh" >&2 + exit 1 + fi + if ! diff -u <(build_codex) "$CODEX_FILE" >/dev/null; then + echo "error: $CODEX_FILE is out of sync with $CLAUDE_FILE" >&2 + diff -u <(build_codex) "$CODEX_FILE" || true + exit 1 + fi + echo "ok: marketplaces in sync" + exit 0 +fi + +build_codex > "$CODEX_FILE" +echo "wrote $CODEX_FILE" diff --git a/scripts/validate-plugins.sh b/scripts/validate-plugins.sh new file mode 100755 index 0000000..cee4822 --- /dev/null +++ b/scripts/validate-plugins.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +# Verify every plugin ships both Claude Code and Codex metadata, and that the +# Codex marketplace uses Codex's marketplace schema. Run after editing manifests +# or marketplace entries. +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$REPO_ROOT" + +if ! command -v jq >/dev/null 2>&1; then + echo "error: jq is required" >&2 + exit 2 +fi + +fail=0 +checked=0 +allowed_installation='^(NOT_AVAILABLE|AVAILABLE|INSTALLED_BY_DEFAULT)$' +allowed_authentication='^(ON_INSTALL|ON_USE)$' + +for claude_manifest in */.claude-plugin/plugin.json; do + [[ -f "$claude_manifest" ]] || continue + plugin_dir="${claude_manifest%/.claude-plugin/plugin.json}" + codex_manifest="$plugin_dir/.codex-plugin/plugin.json" + checked=$((checked + 1)) + + if [[ ! -f "$codex_manifest" ]]; then + echo "FAIL [$plugin_dir]: missing $codex_manifest" + fail=1 + continue + fi + + for field in name version description; do + claude_val=$(jq -r ".$field // \"\"" "$claude_manifest") + codex_val=$(jq -r ".$field // \"\"" "$codex_manifest") + if [[ "$claude_val" != "$codex_val" ]]; then + echo "FAIL [$plugin_dir]: $field mismatch" + echo " claude: $claude_val" + echo " codex: $codex_val" + fail=1 + fi + done + + if [[ -d "$plugin_dir/skills" ]]; then + codex_skills=$(jq -r '.skills // ""' "$codex_manifest") + if [[ "$codex_skills" != "./skills/" ]]; then + echo "FAIL [$plugin_dir]: .codex-plugin/plugin.json must declare skills: \"./skills/\"" + fail=1 + fi + fi +done + +# Also verify marketplace mirrors agree on plugin names and Codex schema. +claude_market=".claude-plugin/marketplace.json" +codex_market=".agents/plugins/marketplace.json" +if [[ ! -f "$claude_market" ]]; then + echo "FAIL [marketplace]: missing $claude_market" + fail=1 +elif [[ ! -f "$codex_market" ]]; then + echo "FAIL [marketplace]: missing $codex_market" + fail=1 +else + claude_names=$(jq -r '.plugins[].name' "$claude_market" | sort) + codex_names=$(jq -r '.plugins[].name' "$codex_market" | sort) + if [[ "$claude_names" != "$codex_names" ]]; then + echo "FAIL [marketplace]: plugin lists differ between Claude and Codex" + diff <(echo "$claude_names") <(echo "$codex_names") || true + fail=1 + fi + + while IFS=$'\t' read -r plugin_name claude_source; do + [[ -n "$plugin_name" ]] || continue + + codex_entry_count=$(jq --arg name "$plugin_name" '[.plugins[] | select(.name == $name)] | length' "$codex_market") + if [[ "$codex_entry_count" != "1" ]]; then + echo "FAIL [marketplace:$plugin_name]: expected exactly one Codex entry, found $codex_entry_count" + fail=1 + continue + fi + + source_type=$(jq -r --arg name "$plugin_name" '.plugins[] | select(.name == $name) | (.source | type)' "$codex_market") + source_kind=$(jq -r --arg name "$plugin_name" '.plugins[] | select(.name == $name) | .source.source // ""' "$codex_market") + source_path=$(jq -r --arg name "$plugin_name" '.plugins[] | select(.name == $name) | .source.path // ""' "$codex_market") + installation=$(jq -r --arg name "$plugin_name" '.plugins[] | select(.name == $name) | .policy.installation // ""' "$codex_market") + authentication=$(jq -r --arg name "$plugin_name" '.plugins[] | select(.name == $name) | .policy.authentication // ""' "$codex_market") + category=$(jq -r --arg name "$plugin_name" '.plugins[] | select(.name == $name) | .category // ""' "$codex_market") + + if [[ "$source_type" != "object" ]]; then + echo "FAIL [marketplace:$plugin_name]: source must be an object" + fail=1 + fi + if [[ "$source_kind" != "local" ]]; then + echo "FAIL [marketplace:$plugin_name]: source.source must be local" + fail=1 + fi + if [[ "$source_path" != "$claude_source" ]]; then + echo "FAIL [marketplace:$plugin_name]: source.path mismatch" + echo " claude: $claude_source" + echo " codex: $source_path" + fail=1 + fi + if [[ ! "$installation" =~ $allowed_installation ]]; then + echo "FAIL [marketplace:$plugin_name]: invalid policy.installation '$installation'" + fail=1 + fi + if [[ ! "$authentication" =~ $allowed_authentication ]]; then + echo "FAIL [marketplace:$plugin_name]: invalid policy.authentication '$authentication'" + fail=1 + fi + if [[ -z "$category" ]]; then + echo "FAIL [marketplace:$plugin_name]: missing category" + fail=1 + fi + + plugin_dir="${claude_source#./}" + if [[ ! -d "$plugin_dir" ]]; then + echo "FAIL [marketplace:$plugin_name]: source directory missing: $claude_source" + fail=1 + continue + fi + + codex_manifest="$plugin_dir/.codex-plugin/plugin.json" + if [[ ! -f "$codex_manifest" ]]; then + echo "FAIL [marketplace:$plugin_name]: missing $codex_manifest" + fail=1 + continue + fi + + codex_manifest_name=$(jq -r '.name // ""' "$codex_manifest") + if [[ "$codex_manifest_name" != "$plugin_name" ]]; then + echo "FAIL [marketplace:$plugin_name]: Codex manifest name mismatch" + echo " marketplace: $plugin_name" + echo " manifest: $codex_manifest_name" + fail=1 + fi + + if [[ "$installation" != "NOT_AVAILABLE" ]]; then + if [[ ! -d "$plugin_dir/skills" && ! -d "$plugin_dir/agents" && ! -f "$plugin_dir/.app.json" && ! -f "$plugin_dir/codex.config.toml.snippet" ]]; then + echo "FAIL [marketplace:$plugin_name]: AVAILABLE Codex plugin has no Codex-loadable component" + fail=1 + fi + fi + done < <(jq -r '.plugins[] | [.name, .source] | @tsv' "$claude_market") +fi + +if [[ $fail -eq 0 ]]; then + echo "ok: $checked plugin(s) validated" +else + exit 1 +fi diff --git a/session-resume-plugin/.claude-plugin/plugin.json b/session-resume-plugin/.claude-plugin/plugin.json new file mode 100644 index 0000000..07ca4b6 --- /dev/null +++ b/session-resume-plugin/.claude-plugin/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "session-resume-plugin", + "description": "Resume work from a previous Claude Code or Codex CLI session by reading the last N turns from its JSONL transcript", + "version": "1.0.0", + "author": { + "name": "Stefan Cho" + } +} diff --git a/session-resume-plugin/.codex-plugin/plugin.json b/session-resume-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..f29b188 --- /dev/null +++ b/session-resume-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "session-resume-plugin", + "description": "Resume work from a previous Claude Code or Codex CLI session by reading the last N turns from its JSONL transcript", + "version": "1.0.0", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/session-resume-plugin/README.md b/session-resume-plugin/README.md new file mode 100644 index 0000000..5d0b532 --- /dev/null +++ b/session-resume-plugin/README.md @@ -0,0 +1,53 @@ +# session-resume-plugin + +Resume work from a previous Claude Code or Codex CLI session by reading the last N turns from its JSONL transcript on disk. + +Useful when: + +- A session got context-saturated and you started a fresh one but want the last conversation as background. +- You jump back to a project after a few days and need a quick "what was I doing". +- You have a session UUID copied from another window and want to pick up where it left off. + +## How It Works + +The skill bundles a small bash helper that: + +1. **Finds the JSONL file** + - With a UUID argument: searches `~/.claude/projects/**/*.jsonl` and `~/.codex/sessions/**/rollout-*.jsonl`. + - Without an argument: picks the most recently modified session in the current `cwd` (Claude Code) plus the most recent Codex session globally, and uses whichever is newer. +2. **Extracts metadata** — tool, session ID, branch, original cwd, last activity timestamp. +3. **Prints the last N turns** (default 10), with each message truncated to 2000 characters. + +The helper never writes to or modifies session files. + +## Usage Inside Claude Code / Codex + +The skill auto-loads when the user mentions resuming a session, supplies a session UUID, or asks "what was I working on". Once loaded, the agent runs: + +```bash +bash "$CLAUDE_PLUGIN_ROOT/skills/session-resume/scripts/resume.sh" [SESSION_ID] [-n N] +``` + +Examples: + +```bash +# Most recent session in this cwd, last 10 messages +bash scripts/resume.sh + +# Specific session by UUID, last 20 messages +bash scripts/resume.sh 019e1048-8ab2-7600-a736-1dfc5db707aa -n 20 +``` + +## Storage Layouts the Helper Understands + +| Tool | Path | +|------|------| +| Claude Code | `~/.claude/projects//.jsonl` (cwd `/` → `-`) | +| Codex CLI | `~/.codex/sessions/YYYY/MM/DD/rollout-...-.jsonl` | + +Codex's JSONL schema may evolve. If structured extraction returns nothing, the helper falls back to printing the raw last N lines. + +## Requirements + +- `jq` available on `PATH` +- Read access to `~/.claude/projects/` and/or `~/.codex/sessions/` diff --git a/session-resume-plugin/skills/session-resume/SKILL.md b/session-resume-plugin/skills/session-resume/SKILL.md new file mode 100644 index 0000000..b91cc0c --- /dev/null +++ b/session-resume-plugin/skills/session-resume/SKILL.md @@ -0,0 +1,78 @@ +--- +name: session-resume +description: Use when the user wants to resume work from a previous Claude Code or Codex CLI session — phrases like "resume", "이어가자", "이전 세션 내용 보여줘", "what was I working on", or when the user provides a session UUID. Locates the session's JSONL transcript on disk and prints the last N turns plus metadata so the agent can pick up where the previous session left off. +allowed-tools: Bash, Read +--- + +# Session Resume + +Locate a previous Claude Code or Codex CLI session's JSONL transcript and surface the last N turns plus metadata (tool, branch, cwd, last-activity timestamp) so you can continue the work intelligently. + +## When to Use + +- User asks to continue/resume a previous session. +- User provides a session UUID like `019e1048-8ab2-7600-a736-1dfc5db707aa`. +- User asks "what was I working on?" or similar context-recovery questions. + +## Inputs + +- `$1` (optional): session UUID. If omitted, pick the most recent session in the current `cwd` (Claude Code) or globally most recent (Codex), and present the user with a short list if there is ambiguity. +- `-n N` (optional): how many of the last messages to print. Default 10. + +## Storage Layouts + +**Claude Code:** +- Path: `~/.claude/projects//.jsonl` +- `` is the absolute project path with `/` replaced by `-` (e.g. `/home/user/foo` → `-home-user-foo`). +- Filename is the session UUID. +- Each line is one event: `{type, message, timestamp, cwd, gitBranch, sessionId, uuid, parentUuid, ...}`. `type` is typically `user`, `assistant`, `summary`, or tool-related. + +**Codex CLI:** +- Path: `~/.codex/sessions/YYYY/MM/DD/rollout-YYYY-MM-DDTHH-MM-SS-.jsonl` +- Filename embeds the session UUID at the end. +- Each line carries `payload.role` and `payload.content`; first line is a session header. +- Schema may evolve — fall back to printing raw lines if jq cannot parse expected fields. + +## Workflow + +### Step 1 — Run the helper + +The plugin ships a script that handles discovery, metadata extraction, and pretty-printing. Run it from the skill directory: + +```bash +bash "$CLAUDE_PLUGIN_ROOT/skills/session-resume/scripts/resume.sh" [SESSION_ID] [-n N] +``` + +If `$CLAUDE_PLUGIN_ROOT` is not set (running outside Claude Code), invoke the script via its absolute path inside the installed plugin. + +Examples: + +```bash +# Most recent session in this cwd, last 10 messages +bash scripts/resume.sh + +# Specific Codex/Claude session by UUID, last 20 messages +bash scripts/resume.sh 019e1048-8ab2-7600-a736-1dfc5db707aa -n 20 +``` + +### Step 2 — Confirm intent before acting + +After printing the transcript, ask the user a short question before doing real work: + +> "이전 세션의 작업을 이어서 진행할까요? 이어간다면 어디부터 시작할지도 알려주세요." + +This avoids accidental action when the user just wanted to inspect the history. + +### Step 3 — Continue the work + +Once confirmed, treat the printed transcript as background context (not as instructions to re-execute). Prefer: + +- Re-reading current files referenced in the last few turns to confirm state. +- Checking `git status` and `git log` to verify whether any in-flight changes still exist. +- Asking clarifying questions if the prior session was interrupted mid-task. + +## Notes + +- The script only reads files; it never modifies session JSONL. +- Tool-use blocks and large attachments inside assistant messages are summarized rather than dumped verbatim. +- If multiple matching sessions exist (same UUID prefix, or many recent files), the script prints the candidates and exits — re-run with the full UUID. diff --git a/session-resume-plugin/skills/session-resume/scripts/resume.sh b/session-resume-plugin/skills/session-resume/scripts/resume.sh new file mode 100755 index 0000000..211fcea --- /dev/null +++ b/session-resume-plugin/skills/session-resume/scripts/resume.sh @@ -0,0 +1,191 @@ +#!/usr/bin/env bash +# Locate a previous Claude Code or Codex CLI session's JSONL transcript and +# print its last N turns plus metadata. +# +# Usage: +# resume.sh # most recent session in this cwd / globally +# resume.sh # specific session by UUID (or substring) +# resume.sh [-n N] # change number of messages to print (default 10) +# +# Reads ~/.claude/projects/*/*.jsonl and ~/.codex/sessions/**/rollout-*.jsonl. +# Never modifies any file. +set -euo pipefail + +if ! command -v jq >/dev/null 2>&1; then + echo "error: jq is required" >&2 + exit 2 +fi + +SID="" +N=10 + +while [[ $# -gt 0 ]]; do + case "$1" in + -n) + [[ $# -lt 2 ]] && { echo "error: -n requires a number" >&2; exit 2; } + N="$2"; shift 2 ;; + -h|--help) + awk '/^#!/{next} /^[^#]/{exit} /^#/{print}' "$0"; exit 0 ;; + *) + SID="$1"; shift ;; + esac +done + +CLAUDE_DIR="$HOME/.claude/projects" +CODEX_DIR="$HOME/.codex/sessions" + +# --------------------------------------------------------------------------- +# Discover candidate JSONL files +# --------------------------------------------------------------------------- +declare -a CANDIDATES=() + +if [[ -n "$SID" ]]; then + while IFS= read -r f; do + [[ -n "$f" ]] && CANDIDATES+=("$f") + done < <(find "$CLAUDE_DIR" "$CODEX_DIR" -name "*${SID}*.jsonl" 2>/dev/null) +else + encoded_cwd="$(pwd | sed 's:/:-:g')" + claude_proj_dir="$CLAUDE_DIR/${encoded_cwd}" + if [[ -d "$claude_proj_dir" ]]; then + latest_claude="$(ls -t "$claude_proj_dir"/*.jsonl 2>/dev/null | head -1 || true)" + [[ -n "$latest_claude" ]] && CANDIDATES+=("$latest_claude") + fi + if [[ -d "$CODEX_DIR" ]]; then + latest_codex="$(find "$CODEX_DIR" -name "rollout-*.jsonl" -printf "%T@ %p\n" 2>/dev/null \ + | sort -rn | head -1 | cut -d' ' -f2- || true)" + [[ -n "$latest_codex" ]] && CANDIDATES+=("$latest_codex") + fi +fi + +if [[ ${#CANDIDATES[@]} -eq 0 ]]; then + echo "no session found" + [[ -n "$SID" ]] && echo " (searched for *${SID}*.jsonl in $CLAUDE_DIR and $CODEX_DIR)" + exit 1 +fi + +# If multiple distinct candidates, list and exit so user can disambiguate. +if [[ ${#CANDIDATES[@]} -gt 1 && -n "$SID" ]]; then + echo "multiple sessions match '${SID}':" + for f in "${CANDIDATES[@]}"; do echo " $f"; done + echo "re-run with a longer/exact UUID." + exit 1 +fi + +# Pick the newest (handles auto-detect case where both Claude+Codex latest exist). +JSONL="$(printf '%s\n' "${CANDIDATES[@]}" \ + | xargs -I{} stat -c '%Y %n' "{}" 2>/dev/null \ + | sort -rn | head -1 | cut -d' ' -f2-)" + +# --------------------------------------------------------------------------- +# Determine tool and metadata +# --------------------------------------------------------------------------- +case "$JSONL" in + *"/.claude/projects/"*) TOOL="claude" ;; + *"/.codex/sessions/"*) TOOL="codex" ;; + *) TOOL="unknown" ;; +esac + +basename_jsonl="${JSONL##*/}" +mtime_epoch="$(stat -c '%Y' "$JSONL" 2>/dev/null || echo 0)" +mtime_human="$(date -d "@${mtime_epoch}" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || stat -c '%y' "$JSONL")" + +session_id="" +branch="" +cwd="" +if [[ "$TOOL" == "claude" ]]; then + hdr="$(head -1 "$JSONL")" + session_id="$(jq -r '.sessionId // ""' <<<"$hdr")" + branch="$(jq -r '.gitBranch // ""' <<<"$hdr")" + cwd="$(jq -r '.cwd // ""' <<<"$hdr")" +elif [[ "$TOOL" == "codex" ]]; then + hdr="$(head -1 "$JSONL")" + session_id="$(jq -r '.id // .session_id // ""' <<<"$hdr")" + cwd="$(jq -r '.cwd // .payload?.cwd // ""' <<<"$hdr")" +fi +[[ -z "$session_id" ]] && session_id="${basename_jsonl%.jsonl}" + +# --------------------------------------------------------------------------- +# Print header +# --------------------------------------------------------------------------- +echo "Session: $session_id" +echo "Tool: $TOOL" +echo "File: $JSONL" +echo "Last activity: $mtime_human" +[[ -n "$branch" ]] && echo "Branch: $branch" +[[ -n "$cwd" ]] && echo "cwd: $cwd" +echo +echo "— last $N messages —" +echo + +# --------------------------------------------------------------------------- +# Extract last N turns. Each message is truncated to ~2000 chars to keep +# transcript readable. +# --------------------------------------------------------------------------- +print_truncated() { + local text="$1" + local len="${#text}" + if (( len > 2000 )); then + printf '%s\n... [truncated %d more chars]\n' "${text:0:2000}" "$((len - 2000))" + else + printf '%s\n' "$text" + fi +} + +if [[ "$TOOL" == "claude" ]]; then + tail -n 800 "$JSONL" \ + | jq -c 'select(.type == "user" or .type == "assistant")' \ + | tail -n "$N" \ + | while IFS= read -r line; do + role="$(jq -r '.message.role // "?"' <<<"$line")" + ts="$(jq -r '.timestamp // ""' <<<"$line")" + content="$(jq -r ' + (.message.content // "") as $c | + if ($c | type) == "string" then $c + elif ($c | type) == "array" then + [ $c[]? | + if .type == "text" then .text + elif .type == "tool_use" then "[tool_use: \(.name // "?")]" + elif .type == "tool_result" then "[tool_result]" + else "[\(.type // "?")]" + end + ] | join("\n") + else ($c | tostring) + end + ' <<<"$line")" + printf '[%s %s]\n' "$role" "$ts" + print_truncated "$content" + echo + done +elif [[ "$TOOL" == "codex" ]]; then + tail -n 800 "$JSONL" \ + | jq -c 'select((.payload?.role // "") != "" or .type == "message")' 2>/dev/null \ + | tail -n "$N" \ + | while IFS= read -r line; do + role="$(jq -r '.payload.role // .role // "?"' <<<"$line")" + ts="$(jq -r '.timestamp // ""' <<<"$line")" + content="$(jq -r ' + (.payload.content // .content // "") as $c | + if ($c | type) == "string" then $c + elif ($c | type) == "array" then + [ $c[]? | + if .type == "input_text" or .type == "output_text" or .type == "text" then (.text // "") + else "[\(.type // "?")]" + end + ] | join("\n") + else ($c | tostring) + end + ' <<<"$line")" + printf '[%s %s]\n' "$role" "$ts" + print_truncated "$content" + echo + done + + # Fallback: if jq filter produced nothing useful, print raw last lines. + if [[ -z "$(tail -n 800 "$JSONL" | jq -c 'select((.payload?.role // "") != "" or .type == "message")' 2>/dev/null | head -1)" ]]; then + echo "(structured extraction returned nothing — printing raw last $N lines)" + tail -n "$N" "$JSONL" + fi +else + echo "(unknown tool layout — printing raw last $N lines)" + tail -n "$N" "$JSONL" +fi diff --git a/split-work-plugin/.codex-plugin/plugin.json b/split-work-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..c3c134d --- /dev/null +++ b/split-work-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "split-work-plugin", + "description": "Split current project work into parallel-safe task groups with worktree branch names and structured starting prompts", + "version": "1.0.1", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/stop-notification-plugin/.codex-plugin/plugin.json b/stop-notification-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..d90fd6f --- /dev/null +++ b/stop-notification-plugin/.codex-plugin/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "stop-notification-plugin", + "description": "macOS TTS voice notification with modal dialog and tmux navigation when Claude stops or needs attention", + "version": "2.0.0", + "author": { + "name": "Stefan Cho" + } +} diff --git a/stop-notification-plugin/README.md b/stop-notification-plugin/README.md index 9e05fca..64a152b 100644 --- a/stop-notification-plugin/README.md +++ b/stop-notification-plugin/README.md @@ -41,12 +41,18 @@ pip install edge-tts ## Installation +### Claude Code + ```bash /plugin install stop-notification-plugin@devstefancho-claude-plugins ``` Restart Claude Code after installation to activate. +### Codex + +This plugin is not installable in Codex from this marketplace because it depends on Claude Code's Stop and Notification hook events. Codex hook support uses a different format and is not mirrored automatically. + ## Uninstall ```bash diff --git a/test-commit-push-pr-clean-plugin/.codex-plugin/plugin.json b/test-commit-push-pr-clean-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..88f55e7 --- /dev/null +++ b/test-commit-push-pr-clean-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "test-commit-push-pr-clean-plugin", + "description": "Automates lint, test, commit, push, PR creation, and worktree cleanup workflow", + "version": "1.3.1", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/test-commit-push-pr-clean-plugin/README.md b/test-commit-push-pr-clean-plugin/README.md index 127b8f4..e351dfe 100644 --- a/test-commit-push-pr-clean-plugin/README.md +++ b/test-commit-push-pr-clean-plugin/README.md @@ -15,12 +15,24 @@ Automate the full workflow of testing, committing, pushing, creating PRs, and cl ## Installation +### Claude Code + ```bash /plugin install test-commit-push-pr-clean-plugin@devstefancho-claude-plugins ``` +### Codex + +Add this repository as a Codex plugin marketplace, then enable the plugin from Codex's plugin UI/policy: + +```bash +codex plugin marketplace add devstefancho/claude-plugins +``` + ## Usage +### Claude Code + ```bash # Run all steps /test-commit-push-pr-clean @@ -30,6 +42,14 @@ Automate the full workflow of testing, committing, pushing, creating PRs, and cl /test-commit-push-pr-clean --skip lint,test ``` +### Codex + +Ask Codex to use the `test-commit-push-pr-clean` skill. Include skip flags in the prompt when needed, for example: + +```text +Use test-commit-push-pr-clean and skip push, pr, and clean. +``` + ## Workflow Steps 1. **Branch Check** - Prevents running on main/master/develop diff --git a/test-commit-push-pr-clean-plugin/skills/test-commit-push-pr-clean/SKILL.md b/test-commit-push-pr-clean-plugin/skills/test-commit-push-pr-clean/SKILL.md new file mode 100644 index 0000000..aef77ea --- /dev/null +++ b/test-commit-push-pr-clean-plugin/skills/test-commit-push-pr-clean/SKILL.md @@ -0,0 +1,46 @@ +--- +name: test-commit-push-pr-clean +description: Run a branch-safe finish workflow: lint, test, commit, push, create a pull request, and clean merged worktrees. Use when the user asks to finish work, test and commit changes, push a branch, open a PR, or clean completed worktrees. +--- + +# Test Commit Push PR Clean + +Use this skill to finish feature-branch work in a repository. Respect user-provided skip flags such as `--skip lint,test,push,pr,clean`. + +## Workflow + +1. Inspect the current repository state with `git status`, `git branch --show-current`, `git worktree list`, and recent commits. +2. Stop before making commits if the current branch is a default branch such as `main`, `master`, or `develop`; tell the user to create a feature branch or worktree. +3. Unless skipped, run the project's lint or format checks when they are discoverable from package scripts or local tooling. +4. Unless skipped, run the project's tests. If coverage is configured, treat coverage regressions as failures to resolve before committing. +5. Group changes into logical commits. Keep unrelated user changes intact and never revert work you did not make. +6. Unless skipped, push the current branch to its upstream or to `origin`. +7. Unless skipped, create a pull request with `gh pr create`, following the repository's title and body conventions. +8. Unless skipped, inspect merged worktrees with `git worktree list` and remove only worktrees that are clearly merged and not the current working tree. + +## Skip Flags + +Available skip keys are: + +- `lint` +- `test` +- `push` +- `pr` +- `clean` + +Example: `--skip push,pr,clean`. + +## Commit Guidance + +Use conventional commit types: `feat`, `fix`, `refactor`, `chore`, `docs`, `test`, `style`, or `perf`. Prefer a concise Korean title when the repository convention is Korean. + +## Pull Request Guidance + +Write PR descriptions in Korean when no project-specific convention overrides it. Include: + +- user-facing summary +- implementation details grouped by area +- tests or checks that passed +- any deployment or manual verification still needed + +For the full Claude slash-command template, see `commands/test-commit-push-pr-clean.md`. diff --git a/writing-specs-plugin/.codex-plugin/plugin.json b/writing-specs-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..f3b0f25 --- /dev/null +++ b/writing-specs-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "writing-specs-plugin", + "description": "Spec-driven development with search, conflict detection, and reporting", + "version": "1.0.3", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +} diff --git a/writing-tasks-plugin/.codex-plugin/plugin.json b/writing-tasks-plugin/.codex-plugin/plugin.json new file mode 100644 index 0000000..e203b68 --- /dev/null +++ b/writing-tasks-plugin/.codex-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "writing-tasks-plugin", + "description": "Decompose specs into persistent task files with dependency graph, parallel lane suggestion, and dynamic progress tracking", + "version": "1.0.2", + "skills": "./skills/", + "author": { + "name": "Stefan Cho" + } +}