| name | maintain-dual-target |
| description | Continuous maintenance workflow for plugins that target both Claude Code and Codex. Use when a plugin's commands, skills, or agents have changed and the Codex target needs updating. |
| version | 0.1.0 |
Maintain Dual-Target Plugin
Keep attached plugins synchronized between Claude Code and Codex after
incremental changes.
Source of truth
Source of truth is explicit:
.plugin-cross-port.marketplace.json records the canonical marketplace.
- Each plugin
.plugin-cross-port.json records plugin-level source_of_truth.
- Mixed repositories are valid: one plugin can be Claude Code-first and another
Codex-first.
- Generated-side staged edits are rejected unless explicitly marked
manually_maintained.
When to activate
- Commands were added, removed, or edited in
commands/
- New skills were added to
skills/
agents/ changed (new agent, description update)
- Hooks changed in
plugin.json
- User says "sync Codex", "update dual-target", "re-run cross-port"
Workflow
Step 1 — Read state
- Read
.plugin-cross-port.marketplace.json
- Read
<plugin-path>/.plugin-cross-port.json
- Read the authoritative manifest for the plugin source
- Run marketplace check before switching source
Step 2 — Diff commands
Prefer the deterministic CLI:
python3 plugins/plugin-cross-port/scripts/cross_port.py marketplace sync
python3 plugins/plugin-cross-port/scripts/cross_port.py marketplace check
python3 plugins/plugin-cross-port/scripts/cross_port.py \
plugin attach plugins/example --source codex
python3 plugins/plugin-cross-port/scripts/cross_port.py \
plugin switch-source plugins/example --to claude-code
Step 3 — Check manually_maintained
If .plugin-cross-port.json lists a generated file as manually_maintained,
skip overwriting it. Emit a reminder: "Manually maintained: - review
manually."
Step 4 — Strict mode check
Agents are auto-converted to skills/generated-from-agents/, so only hooks can
be unresolved. If --strict or the user said "strict mode":
- Any unresolved hook that has no Codex equivalent causes a hard stop:
"Strict mode: unresolved hooks detected — update .plugin-cross-port.json decisions before continuing."
Otherwise emit warnings only.
Step 5 — Update .plugin-cross-port.json
Update plugin status after sync. The converters write this file as JSON via
plugin_state, and it is read back the same way — keep it JSON so it round-trips
across re-runs.
Step 6 — Validate Codex manifest
Re-read .codex-plugin/plugin.json. Verify:
hooks key is absent from Codex manifests
skills points to ./skills/
version matches .claude-plugin/plugin.json
If version mismatch, update .codex-plugin/plugin.json version to match.
Step 7 — Summary
Report what changed:
- N commands re-generated / deleted / added
- N agents re-generated / deleted / added
- Warnings for hooks
Pre-commit integration
See references/continuous-mode.md for full details.
The hook at .githooks/pre-commit runs automatically:
- Developer modifies authoritative files and stages the changes
- Pre-commit hook runs
cross_port.py marketplace sync --changed-only ... --stage
- Generated files and deletions are staged in the same commit automatically
- Generated-side edits are rejected based on plugin-level state
Generated vs manually maintained
Files in skills/generated-from-commands/ are generated by default.
To mark a file as manually maintained (e.g., after heavy customization):
manually_maintained:
- skills/generated-from-commands/my-command/SKILL.md
The converter will skip overwriting files listed here.
Semantic adaptation workflow
Use this when hooks, permission behavior, tool IDs, or ecosystem-specific paths
cannot be resolved mechanically:
python3 plugins/plugin-cross-port/scripts/cross_port.py plugin adapt plugins/example
python3 plugins/plugin-cross-port/scripts/cross_port.py plugin adapt plugins/example --apply
Review plugins/example/.plugin-cross-port/adaptation-plan.md before applying.
If source files change after planning, rerun plugin adapt.
Publication and deletion
Codex failed or review-required targets are published as
policy.installation: "NOT_AVAILABLE". Failed Claude Code targets are omitted
from the Claude Code marketplace.
When a canonical marketplace entry is removed, sync removes the whole
plugins/<name>/ directory only after validating that the path is local,
inside plugins_dir, and has a basename matching the plugin name. Use Git for
recovery.