From ai_dev
Reviews cross-agent-harness and cross-OS portability for runtime artefacts in skills and plugins. For shell scripts, Python/Node helpers, hooks, MCP servers, agent definitions, and configuration that must work across Codex, Claude, Cursor, Gemini CLI, macOS, and Linux.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ai_dev:harness_portabilityThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
<harness_portability>
<harness_portability> Keep bundled skill and plugin runtime artefacts portable across agent harnesses and operating systems. Apply this skill whenever a change creates or edits scripts, hooks, agent definitions, MCP helpers, command wrappers, setup flows, or the skill/plugin wording that tells future agents how to execute, initialize, or configure those artefacts.
Apply these rules to Bash, POSIX shell, Python, JavaScript, TypeScript, Node.js, and other executable files shipped inside skills, agents, commands, hooks, MCP servers, plugin directories, and their supporting resources. Apply them equally to prose that wires those files into agent workflows, and to agent and subagent definition files themselves, whose frontmatter and body each harness parses under its own schema. Treat OpenAI Codex and Anthropic Claude as the primary provider targets for every surface, and include Cursor and Gemini CLI for the agent-definition surface their native loaders exercise. Add further harnesses as concrete practice reveals new compatibility requirements. Support macOS and Linux by default. Use portable APIs and runtime feature detection when behavior differs between the two systems. Design scripts and wiring for the harness that will run the published skill or plugin, not only for the harness currently doing the implementation work. Use official provider documentation before encoding provider-specific behavior for OpenAI Codex, Anthropic Claude, or another targeted harness. Prefer current official docs over memory, observed behavior in one session, or assumptions from another agent surface. State the provider documentation source or the verification gap when a change depends on harness-specific execution, initialization, configuration, filesystem, environment, permission, or tool-discovery behavior. Compose cross-harness behavior as a union of native fields: when one harness reads a field the others ignore — Claude reads a `tools:` allowlist, Codex reads `sandbox_mode` — carry each harness's native field side by side in the shared artefact and let every other harness ignore the foreign ones. Verify unknown-field tolerance on every target first, and reach a strict-schema target through a generated variant instead of the shared file. Scope a behavior or prose rule to a single harness as a sanctioned cross-harness-compatibility mechanism — the behavior-and-prose sibling of the rule that composes cross-harness behavior as a union of native fields. Where that rule carries each harness's native config fields side by side, this one scopes an instruction to the one harness needing special attention — a missing tool, a divergent execution model, a different default — so every other harness keeps the shared instruction and its UX while the special harness avoids an error or degraded behavior. The carve-out serves both compatibility goals at once: roughly equivalent UX across the supported harnesses, and error-or-degradation avoidance in the single harness that needs the special handling. Key the carve-out on the agent's actual capability rather than the harness identity when the triggering harness property is itself changing across versions — a tool being added or removed — so the clause stays correct as the harness evolves; keying on the harness identity is acceptable when that property is stable. Treat agent and subagent definition files as their own portability surface: confirm each target harness's frontmatter schema tolerance, tool naming, and agent registration mechanism before shipping a shared definition, and keep role-critical policy in the agent body so it survives harnesses that run the role inline. Model hook wiring as a layered runtime surface. Identify every hook source the target harness can load, then choose one intentional activation path for each hook behavior unless duplicate execution is deliberate. Use provider-specific hook configuration files for provider-specific schemas, and keep the executable hook script shared when the same policy should run in multiple harnesses. Confirm a target harness loads plugin-bundled hooks at runtime before shipping a blocking or lifecycle hook inside a plugin, and document the trust, enablement, or reload step that makes the hook active. Use POSIX shell features for shell scripts unless the script declares and checks for a stronger shell requirement such as Bash. Use Python standard-library APIs for path, JSON, subprocess, temporary-file, and filesystem operations when they are more portable than shell pipelines. Resolve paths relative to the script, skill, plugin, or explicit user-provided root. Use environment variables and documented harness inputs for configuration; keep user-specific absolute paths out of published artefacts. Handle spaces, quotes, newlines, and special characters in file paths and user-provided values. Quote shell expansions, pass subprocess arguments as arrays where the language supports it, and keep data separate from command strings. Use feature detection for external commands, optional tools, shells, package managers, and OS-specific utilities. Provide a clear error message or documented fallback when a required dependency is unavailable. Treat GNU-only flags, BSD-only flags, macOS-only commands, Linux-only paths, current-user paths, and current-harness internals as portability risks. Add guards, alternative implementations, or documentation when the implementation truly depends on one of them. Keep non-interactive automation paths deterministic. Accept parameters, environment variables, or documented config files for inputs that scripts need in agent-driven workflows. Write skill and plugin instructions so future agents can execute the artefact in Codex and Claude without relying on hidden thread state, local shell aliases, current working-directory accidents, or undocumented plugin-cache layout.<hook_portability>
<codex_hook_layers>
Treat Codex hook sources as additive layers. Codex can load user hooks from ~/.codex/hooks.json or inline [hooks] in ~/.codex/config.toml, project hooks from <repo>/.codex/hooks.json or inline [hooks] in <repo>/.codex/config.toml, managed hooks from managed configuration, and plugin-bundled hooks from enabled plugins. Higher-precedence configuration layers do not replace lower-precedence hooks; all matching hooks run. If the same command is present in a plugin hook and a project or user hook, expect duplicate reviews and duplicate execution.
</codex_hook_layers>
<codex_project_hooks>
Use project .codex/ hooks for repository-local activation without plugin installation, for quick experiments before packaging, or for a project that intentionally owns its own hook policy. Keep project .codex/ hooks out of plugin source repositories when the normal goal is to install the plugin; the installed plugin already contributes the hook and a committed project hook usually creates a second active source.
</codex_project_hooks>
<codex_plugin_hooks>
Treat plugin-root hooks/hooks.json as Codex's default plugin hook file. Use a .codex-plugin/plugin.json hooks entry to override that default with a Codex-native hook file, an empty hook file containing only {"hooks": {}}, multiple hook files, or inline hook objects. Resolve manifest hook paths relative to the plugin root, keep them inside the plugin root, and start file paths with ./.
</codex_plugin_hooks>
<codex_hook_schema>
Keep Codex-consumed hook JSON strict and minimal: the top-level key is hooks, event names map to matcher groups, and matcher groups contain one or more handlers. Put descriptive prose in the plugin manifest, README, skill prose, or provider-specific documentation instead of adding custom top-level fields such as description to Codex hook JSON. Use one matcher group with a regex such as ^(apply_patch|Bash)$ when the same handler, timeout, and status message apply to multiple tools; use separate matcher groups when behavior, command arguments, timeout, status text, or policy differs.
</codex_hook_schema>
<codex_trust_and_cache>
Account for Codex trust and cache behavior when validating hooks. Non-managed command hooks are listed but skipped until the user reviews and trusts the current hook definition. Trust is tied to the current hook definition, so edits require review again. After editing a marketplace-installed plugin, refresh the installed Codex plugin cache with codex plugin add <plugin>@<marketplace> or the matching marketplace workflow, then inspect ~/.codex/plugins/cache/<marketplace>/<plugin>/<version>/; restarting Codex alone can reuse stale cached plugin files.
</codex_trust_and_cache>
<claude_plugin_hooks>
Treat Claude plugin hooks as plugin-root components that live at hooks/hooks.json or inline in the Claude plugin manifest. Claude command hooks receive event JSON on stdin and commonly resolve plugin files through ${CLAUDE_PLUGIN_ROOT}. Reload or restart the Claude plugin surface after changing plugin hooks so the active session sees hook, MCP, agent, and other plugin component changes.
</claude_plugin_hooks>
<dual_harness_layout>
Keep Claude and Codex hook configuration parallel rather than shared when their schemas, event coverage, matcher names, trust model, or command environment differ. A practical dual-harness plugin can use hooks/hooks.json for Claude, .codex-plugin/plugin.json pointing to ./hooks/codex-plugin-hooks.json for Codex, and an optional separate hook JSON such as ./hooks/codex-custom-deploy-hooks.json, kept outside the manifest, for users who explicitly merge it into their user- or project-level Codex config layers. Use an empty Codex hook file when a Claude hook exists but no Codex-equivalent behavior is ready yet.
</dual_harness_layout>
<shared_hook_scripts>
Share executable hook scripts across Codex and Claude when the policy is the same, but make the script harness-neutral. Read event input from stdin when available, tolerate missing or extra JSON fields, detect the active harness through documented environment variables, and resolve the plugin root from ${PLUGIN_ROOT} or ${CLAUDE_PLUGIN_ROOT} with a script-relative fallback. Emit blocking decisions and diagnostics in the format expected by the harness that invoked the script.
</shared_hook_scripts>
<duplicate_diagnosis>
Diagnose duplicate or surprising hook counts by enumerating active sources before changing scripts. Check the plugin manifest hook path, plugin-root hooks/hooks.json, user and project hooks.json, inline [hooks] tables, managed policy, installed plugin cache, and the hook review UI. A displayed count can reflect separate sources, separate matcher groups, parse errors plus valid hooks, or stale cached plugin files.
</duplicate_diagnosis>
</hook_portability>
<agent_portability>
<agent_definition_surfaces>
Treat agent and subagent definitions as a per-harness surface with distinct formats, locations, and loaders; the facts below were verified against provider documentation, loader source, and on-disk harness state in July 2026 — re-verify against current official docs before encoding new behavior. Anthropic Claude reads markdown agents with YAML frontmatter, loads plugin-bundled agents/*.md natively from installed plugins, and silently ignores unknown frontmatter keys; plugin-delivered agents additionally have hooks, mcpServers, and permissionMode ignored for security. Cursor reads markdown agents from .cursor/agents/, .claude/agents/, and .codex/agents/ in both project and user variants (.cursor wins name conflicts) and recognizes name, description, model, readonly, and is_background. OpenAI Codex registers spawnable roles only from standalone TOML files under ~/.codex/agents/ or <repo>/.codex/agents/ (name, description, developer_instructions required; model, model_reasoning_effort, sandbox_mode, mcp_servers optional); the Codex plugin schema carries no agent component, so plugin-bundled markdown agents land in the plugin cache without ever becoming spawnable roles. Gemini CLI reads markdown agents from .gemini/agents/ and ~/.gemini/agents/ under a strict schema limited to kind, name, description, display_name, tools, mcp_servers, model, temperature, max_turns, and timeout_mins.
</agent_definition_surfaces>
<codex_model_inheritance>
Express Codex custom-agent model inheritance by omitting the model key from the generated TOML. Codex inherits optional fields such as model, model_reasoning_effort, and sandbox_mode from the parent session or default configuration when the key is absent. When a shared markdown agent source expresses inheritance with a sentinel value such as model: inherit — a value Claude and Cursor understand natively — translate that sentinel to key omission while generating the Codex TOML; explicit concrete model pins still pass through as model = "...". Treat model = "inherit" in generated Codex TOML as invalid output because Codex interprets it as a literal model name, and ChatGPT-backed Codex sessions can reject it before the agent starts.
</codex_model_inheritance>
<reasoning_effort_portability>
Let sub-agents inherit the spawning session's reasoning depth by omitting the effort keys from shared agent definitions — inheritance by omission works on both major harnesses and keeps the user's session setting as the single knob. Claude Code subagents inherit the parent session's extended-thinking state and effort level since 2.1.198, with frontmatter effort (low | medium | high | xhigh | max) acting as a per-agent override when present; releases before 2.1.198 spawn subagents without extended thinking regardless of frontmatter. Codex inherits model_reasoning_effort, like model, from the parent session when the agent TOML omits the key, and a role-pinned effort is locked against per-spawn changes. Reserve a pin for an agent that must run at a fixed depth regardless of session settings, and express it as a union of native keys in the shared source: Claude reads frontmatter effort, the Codex TOML key is model_reasoning_effort, and the two names are disjoint, so both sit side by side in one markdown file — each tolerant harness ignores the foreign key, whatever generates the Codex TOML carries the model_reasoning_effort value through, and a strict-schema Gemini variant strips both. Pin Codex at xhigh at most — the ceiling every current first-party Codex model advertises (verified July 2026): the max and ultra tiers above it are accepted only by preview models, and Codex applies an agent-TOML effort pin without spawn-time validation, so an unsupported pin surfaces as API errors on the child agent's turns rather than a clamp or fallback.
</reasoning_effort_portability>
<frontmatter_schema_tolerance>
Classify every target harness as ignore-unknown or strict-schema before sharing one agent file across harnesses. Claude and Cursor tolerate foreign keys, which is what lets one markdown file carry several harnesses' native fields side by side. Gemini CLI validates strictly: a single unrecognized key — version:, background:, effort:, or any vendor-prefixed field — fails validation, and that agent stays unloaded while the CLI keeps running. Confirm tolerance from the docs or the loader source, and treat "the other harness will ignore it" as a claim to verify per harness rather than a default assumption.
</frontmatter_schema_tolerance>
<tool_name_namespaces>
Treat tool allowlists as harness-specific in both value shape and tool naming. Claude's tools: takes a comma-separated string of capitalized names (Read, Grep, Glob, Bash), and omitting the field inherits every tool. Gemini's tools: requires a YAML array of lowercase slugs validated against its registry (read_file, grep_search, glob, run_shell_command); a comma string fails as "Expected array, received string", and Claude-cased names fail as invalid tool names. Cursor exposes no tools field at all — its current identifiers are Shell, Read, Grep, Glob, LS, StrReplace, and Write, with the shell tool named Shell rather than Bash — and Codex offers no per-agent tool allowlist. Because the namespaces are disjoint, one tools: value cannot satisfy Claude and Gemini simultaneously: a shared file carries at most one harness's tools: and reaches the others through their own fields or a generated per-harness variant.
</tool_name_namespaces>
<readonly_agent_enforcement>
Enforce a read-only agent role with each harness's native lever, unioned in one source file where key tolerance allows: a tools: allowlist of read-only tools for Claude, readonly: true for Cursor (restricted write permissions), sandbox_mode = "read-only" in the generated TOML for Codex, and a Gemini-named tools array reachable only through a per-harness generated variant because of Gemini's strict schema. Account for Codex read-only semantics gating command execution behind approval, so a read-only agent that needs git log-style commands may pause for confirmation there. Keep the prompt-level prohibition — edit no files, stamp no frontmatter — stated in the agent body as the universal floor: frontmatter enforcement binds only where the agent actually spawns as a separate agent, while the body contract also governs harnesses that degrade the role to inline execution.
</readonly_agent_enforcement>
<spawn_registration_and_inline_degradation>
Confirm where a named agent actually registers before relying on its definition file for any guarantee. A harness without the registered role usually keeps the orchestrating skill working — the main agent performs the role inline, where agent-file enforcement never applies. Verify registration on the target itself: the harness agent directory, the installed plugin cache, and the spawnable-role list the harness advertises (Codex builds its spawn_agent roles from the TOML agent directory plus built-ins such as default, explorer, and worker). Write orchestrating skills so their policy survives inline degradation instead of assuming a sub-agent boundary exists everywhere.
</spawn_registration_and_inline_degradation>
<native_fields_and_deploy_bridges>
Author shared agent sources with each harness's native field names, and reserve deploy-time transforms for format bridges. A native plugin or marketplace install reads the raw file, so a deploy-only convention — a vendor-prefixed key such as CLAUDE_tools:, or a readonly: to sandbox_mode mapping — takes effect only on machines where that deployment step ran and is invisible on every native install path. Use a generation step in two situations: where the target reads a different format entirely — markdown to Codex TOML is the required bridge, and it is also the only path by which a plugin-distributed agent reaches Codex as a spawnable role — and where the target validates a strict schema, which the shared file can never satisfy. For a strict-schema target, generate a variant that whitelists the target's allowed keys and maps near-equivalent values to the target's vocabulary: a Gemini variant generator reduces frontmatter to Gemini's schema, translates Claude tool names to Gemini slugs as a YAML array (Read to read_file, Bash to run_shell_command), drops the field when a name has no valid mapping, and drops every other key so the agent passes validation instead of silently failing to load.
</native_fields_and_deploy_bridges>
</agent_portability>
<review_checklist>
<paths_and_locations>Paths resolve from documented roots and support spaces or special characters.</paths_and_locations>
<shell_portability>Shell syntax, utilities, and flags work on macOS and Linux or are guarded with fallbacks.</shell_portability>
<language_runtime>Python, Node.js, or other runtime code uses portable standard APIs for filesystem, process, encoding, and temporary-file behavior.</language_runtime>
<harness_wiring>Skill/plugin prose explains execution and configuration through documented harness behavior rather than current-session implementation details.</harness_wiring>
<behavior_carveouts>A behavior or prose rule that special-cases one harness is scoped to the harness or capability that needs the special attention and leaves every other harness on the shared instruction and its UX; where the triggering harness property changes across versions, the carve-out keys on the agent's capability rather than the harness identity.</behavior_carveouts>
<plugin_hook_runtime>A blocking or lifecycle hook shipped inside a plugin is verified to load at runtime on each target harness, with explicit Codex manifest overrides when hooks/hooks.json is Claude-only and with config-layer registration where the harness does not execute plugin-bundled hooks.</plugin_hook_runtime>
<hook_layering>Codex hook behavior has exactly the intended active sources across plugin, user, project, managed, and deploy-generated layers; duplicate execution is either removed or documented as intentional.</hook_layering>
<dual_harness_hooks>Claude and Codex hook configuration files are separated when schemas differ, while shared shell scripts remain portable across both harnesses.</dual_harness_hooks>
<agent_definitions>Shared agent frontmatter carries only keys every target harness tolerates, tool allowlists use each harness's exact tool names and value shape, read-only roles pair frontmatter enforcement with a body-level policy that survives inline execution, and the definition is verified to register on each harness expected to spawn it.</agent_definitions>
<provider_docs>Provider-specific claims are checked against official OpenAI Codex, Anthropic Claude, or other targeted provider documentation.</provider_docs>
<failure_modes>Missing dependency, unsupported OS, unsupported shell, and missing config errors are actionable for a future agent.</failure_modes>
Verification covers the touched runtime path, or the remaining unverified surfaces are named explicitly.
</review_checklist>
<output_contract> When reporting the work, summarize the portability surface touched, the official provider documentation checked when applicable, the verification performed, and any remaining harness or OS gaps. The final artefact can be understood and executed by a future Codex or Claude agent from the published skill/plugin files without relying on the implementation session's private state. </output_contract> </harness_portability>
npx claudepluginhub theafh/ai-modules --plugin ai_devQuick-reference for editing Claude Code skills, agents, slash commands, hooks, plugins, and configs. Triggers on YAML frontmatter, .claude/ files, Task tools, hook debugging.
Knowledge base on Claude Code formats, patterns, and configurations for commands, agents, skills, hooks, memory, plugins, settings. Use for creating, improving, auditing components.
Provides Codex CLI conventions for writing and scoring artifacts: SKILL.md layout, config.toml schema, plugin.json, hooks, AGENTS.md hierarchy, marketplace.json, and OpenAI YAML sidecars.