Skip to content

feat(codex-plugin): add @hyperframes/codex-plugin package#387

Merged
jrusso1020 merged 7 commits intomainfrom
feat/codex-plugin
Apr 21, 2026
Merged

feat(codex-plugin): add @hyperframes/codex-plugin package#387
jrusso1020 merged 7 commits intomainfrom
feat/codex-plugin

Conversation

@jrusso1020
Copy link
Copy Markdown
Collaborator

@jrusso1020 jrusso1020 commented Apr 21, 2026

What

Add HyperFrames as an OpenAI Codex plugin using the existing repo-root skills/ directory as-is, with a new .codex-plugin/plugin.json manifest and assets/icon.png + assets/logo.png at repo root.

This PR packages the plugin itself. It does not turn this repo into a Codex marketplace source.

Why

OpenAI reached out asking HeyGen to publish the HyperFrames skills as a Codex plugin so they can list it in their plugin directory.

The structure keeps skills/ as the single source of truth — no copy, no build step, no drift to guard against. .codex-plugin/plugin.json sits at repo root and references the canonical skills/ directly via "skills": "./skills/".

How

Repo-root layout (3 files added):

.codex-plugin/plugin.json     # Codex manifest (skills: "./skills/", assets paths)
assets/icon.png               # 512x512, from docs/logo/symbol-dark.svg
assets/logo.png               # 1024x308, from docs/logo/light.svg
skills/                       # unchanged — single source of truth

Manifest follows OpenAI's plugin spec: name: hyperframes, category: Design, Apache-2.0, brandColor: #0a0a0a (from docs/docs.json primary), homepage: hyperframes.heygen.com. Points at ./skills/ and ships composerIcon + logo assets.

Assetsicon.png and logo.png rendered from the existing docs/logo/*.svg files via puppeteer (one-time; not part of any build).

No build step, no drift check. The plugin doesn't need one — skills/ IS the plugin's skills/ dir. Any skill edit is a plugin edit automatically.

Testing / Local Iteration

Current Codex CLI behavior distinguishes between:

  • a plugin package, which contains .codex-plugin/plugin.json
  • a marketplace source, which is a catalog of one or more plugins

So the correct local iterative test flow for this PR is:

  1. Expose the plugin through a local marketplace file such as .agents/plugins/marketplace.json
  2. Point that marketplace entry at this plugin directory
  3. Run codex plugin marketplace add <local-marketplace-root>
  4. Restart Codex and install the plugin from that marketplace

For this reason, this PR does not claim that the following works by itself today:

codex plugin marketplace add heygen-com/hyperframes --sparse .codex-plugin --sparse skills --sparse assets

That direct owner/repo install flow depends on a separate marketplace/catalog entry that points at this plugin.

Plugin-scoped local testing notes now live in .codex-plugin/TESTING.md.

Test plan

  • oxlint . passes
  • oxfmt --check README.md .codex-plugin/plugin.json .codex-plugin/TESTING.md passes for the plugin-related docs/files
  • All plugin.json paths resolve: ./skills/ exists, ./assets/icon.png exists, ./assets/logo.png exists
  • Icon + logo PNGs rasterized cleanly at expected sizes: 512x512 and 1024x308
  • Local Codex marketplace install succeeds when this plugin is exposed through a local marketplace root
  • The existing skills/ directory + its subtree remain the single source of truth

Follow-ups (not in this PR)

  • PR to openai/plugins or equivalent marketplace/catalog entry adding a discoverable install surface for this plugin
  • Optional: rendered template screenshots for interface.screenshots — the spec allows it but no plugin in the current OpenAI directory ships any, so skipping for v0.1

History

Initial revision had packages/codex-plugin/ as a build target that copied skills/ into a plugin layout; per PR feedback, moved the plugin root to repo root instead. Deleted ~6800 lines of build/sync infrastructure and the duplicated skill files. See commit 2a004d8.

Bundles the 5 hyperframes skills (hyperframes, hyperframes-cli,
hyperframes-registry, gsap, website-to-hyperframes) as an OpenAI Codex
plugin per developers.openai.com/codex/plugins/build.

Users can install directly:
  codex plugin marketplace add heygen-com/hyperframes --sparse packages/codex-plugin

The skills/ directory under packages/codex-plugin/ is a built copy of
the repo-root skills/. A lefthook pre-commit hook auto-rebuilds when
any skill file changes, and `bun run lint` runs a drift check so CI
fails if the committed plugin copy diverges.
Review findings from /simplify:

- Replace execSync('diff -r') with in-process tree compare. Removes the
  POSIX diff dependency, eliminates the temp-dir dance, and yields a
  structured drift list (changed/missing/extra per path) instead of a
  2000-char-truncated blob.
- Use fileURLToPath for __dirname so paths work on Windows.
- Replace existsSync+statSync TOCTOU with a single statSync in try/catch,
  and fix the error message for the non-directory case.
- Switch readdirSync to { withFileTypes: true } to avoid per-entry
  statSync when scanning for extras.
- lefthook: exclude packages/codex-plugin/skills/** from the
  codex-plugin-sync glob. Without this, editing the built copy (e.g.
  during a conflict resolution) would trigger the hook to rebuild and
  overwrite the user's edit.
Both sync-schemas.ts and packages/codex-plugin/build.mts were hand-rolling
the same "compare source to target, print drift, exit 1 in --check mode"
pattern with slightly different output shapes. Extract:

- walkFiles(root, filter?) — recursive relative-path lister shared with
  the codex-plugin drift checker
- reportAndExit(drifted, { checkMode, label, fixCommand }) — prints a
  unified ✓/✗ summary, caps drift list, exits non-zero in check mode

Both callers now produce the same output shape so contributors see the
same UI whether they're syncing schemas or the codex plugin:

  ✗ <label> is out of sync:
    changed <path>
    missing <path>
    extra   <path>
  Run `<fix command>` and commit the result.

Verified: lint, format:check, sync-schemas:check, check:codex-plugin all
pass. Drift injection tests pass on both sync paths. Pre-commit hook still
auto-rebuilds the plugin skills/ copy on source changes and correctly
skips when only the plugin copy is edited (no clobber cycle).
CI lint failed on PR #387 because root .gitignore has `examples/` for test
artifacts, and that rule also matched packages/codex-plugin/skills/
hyperframes-registry/examples/. The two add-block.md + add-component.md
files in the plugin copy were silently skipped by `git add`, so local
--check passed (files exist on disk) but CI drift check failed (files
missing from the committed tree).

- Add a targeted negation so the plugin copy can commit `examples/` dirs:
    !packages/codex-plugin/skills/**/examples/
    !packages/codex-plugin/skills/**/examples/**
- Re-stage the two rescued files.
- Add a build-time guard: `build.mts` now runs `git check-ignore --stdin
  --no-index` on every file in the plugin copy. If any file would be
  gitignored, the build (and --check) fail fast with the conflicting path
  and a hint to add a negation. Prevents this class of silent commit loss
  for any future skill content that collides with a root ignore rule.
@vanceingalls
Copy link
Copy Markdown
Collaborator

vanceingalls commented Apr 21, 2026

Feedback: eliminate the skills/ copy by moving the plugin root to repo root

The current structure commits 60 files copied from skills/ into packages/codex-plugin/skills/, maintained by a build script, a CI drift check, and a .gitignore negation hack for examples/. Every skill edit requires remembering to run bun run --cwd packages/codex-plugin build — the failure mode is silent until CI catches it.

Proposed restructure

Move the plugin identity to the repo root so skills/ is referenced in-place with no copy:

# repo root
.codex-plugin/
  plugin.json          ← "skills": "./skills/"
assets/                ← icon.png, logo.png (moved from packages/codex-plugin/assets/)
skills/                ← already here, single source of truth
  hyperframes/
  gsap/
  hyperframes-cli/
  hyperframes-registry/
  website-to-hyperframes/

Install command

Before:

codex plugin marketplace add heygen-com/hyperframes --sparse packages/codex-plugin

After:

codex plugin add heygen-com/hyperframes --sparse .codex-plugin --sparse skills --sparse assets

Note: the repo doesn't have a marketplace.json yet, so the current "before" command wouldn't work via the marketplace flow either. Worth confirming how users are actually installing the plugin today before changing the sparse layout.

What this deletes

  • packages/codex-plugin/skills/ (60 duplicated files)
  • packages/codex-plugin/build.mts (copy + drift check script)
  • packages/codex-plugin/package.json (only existed for the build script)
  • The CI --check drift job
  • The .gitignore negation for !packages/codex-plugin/skills/**/examples/
  • scripts/lib/sync.ts shared helpers (if only used by this build)

Why it works

--sparse is just git sparse-checkout set — no structural requirements on the path. The Codex plugin system only needs .codex-plugin/plugin.json at the plugin root. Since skills already live at skills/ in the repo root, pointing "skills": "./skills/" from a root-level plugin.json references them directly.

Tradeoff

Two small files at repo root (.codex-plugin/plugin.json + assets/) instead of a packages/codex-plugin/ subtree. Net deletion of ~150 lines of build/sync infrastructure and 60 duplicated skill files.

…eline

Per PR feedback: eliminate the skills/ copy by making the repo root the
plugin root. `.codex-plugin/plugin.json` and `assets/` move from
packages/codex-plugin/ to repo root; the existing `skills/` directory is
referenced in place via `"skills": "./skills/"`. One source of truth.

Install with multi-sparse checkout:

  codex plugin marketplace add heygen-com/hyperframes \
    --sparse .codex-plugin --sparse skills --sparse assets

Deleted:
- packages/codex-plugin/ (60 duplicated skill files, build.mts, package.json)
- scripts/lib/sync.ts (was only used by the codex-plugin build)

Reverted to pre-plugin state (no longer needed without the copy):
- scripts/sync-schemas.ts (restored to its original shape)
- lefthook.yml (no auto-sync hook)
- .gitignore (no examples/ negation — nothing collides anymore)
- package.json (lint no longer chains check:codex-plugin; removed
  build:codex-plugin + check:codex-plugin scripts)

Net: -6831 / +19 lines. The plugin is now just 3 tracked additions at
repo root (.codex-plugin/plugin.json, assets/icon.png, assets/logo.png)
plus one README paragraph documenting the install command.
@jrusso1020
Copy link
Copy Markdown
Collaborator Author

Done — restructure pushed in 2a004d8.

The plugin now lives at repo root: .codex-plugin/plugin.json + assets/ + the existing canonical skills/. Install command:

codex plugin marketplace add heygen-com/hyperframes --sparse .codex-plugin --sparse skills --sparse assets

(Verified in the Codex docs: --sparse can be repeated.)

Deleted:

  • packages/codex-plugin/ — the 60 copied skill files, build.mts, package.json, README
  • scripts/lib/sync.ts — was only used by the codex-plugin build

Reverted to pre-plugin state (no longer needed without the copy):

  • scripts/sync-schemas.ts — back to its original shape
  • lefthook.yml — no auto-sync hook
  • .gitignore — no examples/ negation (nothing to collide)
  • package.jsonlint no longer chains check:codex-plugin; removed build:codex-plugin + check:codex-plugin

Net: -6831 / +19 lines. The plugin is now 3 tracked additions at repo root (manifest, icon, logo) plus one README paragraph. No drift to manage, no build step, no CI check.

I'll update the PR description to reflect the new structure.

@jrusso1020 jrusso1020 merged commit 4ce1792 into main Apr 21, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants