feat: add Codex plugin packaging (single-plugin, metadata-only) (#83)

* feat: add Codex plugin packaging (single-plugin, metadata-only)

Adds .codex-plugin/plugin.json with a skills array listing all public
skills, plus .agents/plugins/marketplace.json for one-command install:

  codex plugin marketplace add magnus919/agent-skills
  codex plugin install magnus919

Same pattern as mattpocock/skills — one plugin, explicit skill paths,
no dist/, no curation, no duplication. Bundle-internal helpers excluded
by the shared glob. CI check mode fails if the manifest drifts.

Closes #79

AI-assisted: yes (Jasper/Hermes Agent)

* chore: trigger CI

* chore: regenerate Codex plugin manifest to include neckbeard bundle
This commit is contained in:
Magnus Hedemark
2026-07-21 03:13:20 -04:00
committed by GitHub
parent e1677183cd
commit 0f2aaf1583
5 changed files with 260 additions and 9 deletions
+20
View File
@@ -0,0 +1,20 @@
{
"name": "magnus919",
"interface": {
"displayName": "Magnus Agent Skills"
},
"plugins": [
{
"name": "magnus919",
"source": {
"source": "local",
"path": "./"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Developer Tools"
}
]
}
+118
View File
@@ -0,0 +1,118 @@
{
"name": "magnus919",
"version": "1.0.0",
"description": "AI agent skills — reusable workflows, protocols, and knowledge packs for agentic systems.",
"author": {
"name": "Magnus Hedemark",
"url": "https://github.com/magnus919"
},
"homepage": "https://github.com/magnus919/agent-skills",
"repository": "https://github.com/magnus919/agent-skills",
"license": "MIT",
"keywords": [
"agent-skills",
"engineering",
"product",
"research",
"infrastructure",
"methodology"
],
"skills": [
"./adr-authoring",
"./agent-council",
"./agent-evals-and-observability",
"./agent-skills",
"./api-design-and-evolution",
"./artifact-pyramids",
"./autogen",
"./backend-engineering",
"./brand-designer",
"./c4-diagramming",
"./chief-of-staff-methodology",
"./cli-builder",
"./color-management",
"./confluence-cli",
"./crewai",
"./crowdsec",
"./daily-life-discovery",
"./data-architect",
"./data-engineering",
"./data-scientist",
"./de-spin",
"./docker-compose",
"./dspy",
"./epub",
"./esp32-development",
"./financial-modeling",
"./fireflies",
"./flaresolverr",
"./flaresolverr-cli",
"./forgejo-cli",
"./frontend-engineering",
"./ghost-cli",
"./github-runner",
"./go-to-market",
"./gutenberg",
"./haystack",
"./hugo-theme",
"./jellyfin-cli",
"./jira-cli",
"./jira-jql",
"./kanban-guru",
"./kubernetes",
"./langchain",
"./langgraph",
"./lastfm",
"./legal-strategy",
"./linear",
"./llamaindex",
"./mermaid-diagrams",
"./meshcore-packet-capture",
"./ml-engineering",
"./neckbeard",
"./nous-branding",
"./open-knowledge-format",
"./openlibrary-cli",
"./opensource-contributions",
"./operational-design",
"./org-design",
"./peertube",
"./platform-engineering",
"./product-design-and-ux",
"./product-discovery",
"./product-methodology",
"./product-strategy",
"./pydanticai",
"./qa-methodology",
"./raleigh",
"./remote-systems-administration",
"./research-and-vault",
"./research-methodology",
"./restic",
"./secure-software-engineering",
"./security-audit-methodology",
"./seo-audit",
"./site-reliability-engineering",
"./software-architecture-analysis",
"./spec-driven-development",
"./strategy-frameworks",
"./supabase",
"./systematic-debugging",
"./tailscale",
"./technical-documentation",
"./technology-radar",
"./tempest-cli",
"./three",
"./tmdb-cli",
"./traefik",
"./trakt",
"./transistor",
"./vercel-eve",
"./verification-methodology",
"./web-accessibility",
"./woodpecker-ci",
"./workflow-architect",
"./yc-default-alive-calculator",
"./yc-weekly-growth-compass"
]
}
+2
View File
@@ -24,6 +24,8 @@ jobs:
run: python3 scripts/check-artifacts.py
- name: Validate Claude Code marketplace
run: ruby scripts/gen-claude-marketplace.rb
- name: Validate Codex plugin packaging
run: ruby scripts/gen-codex-plugin.rb
- name: Build tracked Python packages
run: |
wheel_dir=$(mktemp -d)
+13 -9
View File
@@ -453,19 +453,23 @@ Tap skills install into `~/.hermes/skills/` like any other hub skill. Use `herme
### OpenAI Codex
Codex reads the same `SKILL.md` format directly — no conversion needed. Copy or symlink the skills you want into a directory Codex scans:
This repository ships a Codex plugin. Add the marketplace and install:
```bash
# Personal (all projects)
mkdir -p ~/.codex/skills
cp -r cli-builder ~/.codex/skills/
# Project-scoped (this repo only)
mkdir -p .codex/skills
cp -r systematic-debugging .codex/skills/
codex plugin marketplace add magnus919/agent-skills
codex plugin install magnus919
```
Codex detects new skills automatically (restart if one doesn't appear). Full details: [developers.openai.com/codex/skills](https://developers.openai.com/codex/skills).
All public skills are bundled in a single plugin. Codex discovers them from the `skills` array in `.codex-plugin/plugin.json`.
**Local/repo-scoped install** (for contributors or single-skill use):
```bash
mkdir -p .agents/skills
ln -s ../../systematic-debugging .agents/skills/systematic-debugging
```
Codex scans `.agents/skills/` in every directory from cwd up to the repo root.
### Generic / Other Frameworks
+107
View File
@@ -0,0 +1,107 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
# Generates and validates the Codex plugin packaging:
# .codex-plugin/plugin.json — single plugin manifest listing all public skills
# .agents/plugins/marketplace.json — one-entry marketplace pointing at repo root
#
# Usage:
# ruby scripts/gen-codex-plugin.rb # validate committed files are current
# ruby scripts/gen-codex-plugin.rb --write # regenerate both files
require "fileutils"
require "json"
require "yaml"
ROOT = File.expand_path("..", __dir__)
PLUGIN_JSON_PATH = File.join(ROOT, ".codex-plugin", "plugin.json")
MARKETPLACE_PATH = File.join(ROOT, ".agents", "plugins", "marketplace.json")
PLUGIN_NAME = "magnus919"
PLUGIN_VERSION = "1.0.0"
# Same glob as gen-claude-marketplace.rb: top-level skills + bundle entrypoints.
# Excludes bundle-internal helpers (bundles/<x>/skills/<sub>/SKILL.md).
PUBLIC_SKILLS = (Dir.glob("#{ROOT}/*/SKILL.md") + Dir.glob("#{ROOT}/bundles/*/SKILL.md")).sort
def build_plugin_json
skill_paths = PUBLIC_SKILLS.map do |skill|
"./#{File.basename(File.dirname(skill))}"
end.sort
{
"name" => PLUGIN_NAME,
"version" => PLUGIN_VERSION,
"description" => "AI agent skills — reusable workflows, protocols, and knowledge packs for agentic systems.",
"author" => {
"name" => "Magnus Hedemark",
"url" => "https://github.com/magnus919"
},
"homepage" => "https://github.com/magnus919/agent-skills",
"repository" => "https://github.com/magnus919/agent-skills",
"license" => "MIT",
"keywords" => %w[agent-skills engineering product research infrastructure methodology],
"skills" => skill_paths
}
end
def build_marketplace
{
"name" => PLUGIN_NAME,
"interface" => {
"displayName" => "Magnus Agent Skills"
},
"plugins" => [
{
"name" => PLUGIN_NAME,
"source" => {
"source" => "local",
"path" => "./"
},
"policy" => {
"installation" => "AVAILABLE",
"authentication" => "ON_INSTALL"
},
"category" => "Developer Tools"
}
]
}
end
def render(obj)
JSON.pretty_generate(obj) + "\n"
end
expected_plugin = render(build_plugin_json)
expected_marketplace = render(build_marketplace)
if ARGV.include?("--write")
FileUtils.mkdir_p(File.dirname(PLUGIN_JSON_PATH))
FileUtils.mkdir_p(File.dirname(MARKETPLACE_PATH))
File.write(PLUGIN_JSON_PATH, expected_plugin)
File.write(MARKETPLACE_PATH, expected_marketplace)
puts "Wrote .codex-plugin/plugin.json and .agents/plugins/marketplace.json (#{PUBLIC_SKILLS.length} skills)."
exit 0
end
errors = []
if !File.file?(PLUGIN_JSON_PATH)
errors << ".codex-plugin/plugin.json is missing."
elsif File.read(PLUGIN_JSON_PATH) != expected_plugin
errors << ".codex-plugin/plugin.json is out of date."
end
if !File.file?(MARKETPLACE_PATH)
errors << ".agents/plugins/marketplace.json is missing."
elsif File.read(MARKETPLACE_PATH) != expected_marketplace
errors << ".agents/plugins/marketplace.json is out of date."
end
if errors.empty?
puts "Codex plugin packaging is current (#{PUBLIC_SKILLS.length} skills)."
else
warn errors.join("\n")
warn "Run: ruby scripts/gen-codex-plugin.rb --write"
exit 1
end