Skip to main content
Version: 0.8.9

Codex CLI Integration (Agent Skills spec)

Uses the Agent Skills adaptation (agentskills.io), not the native Claude skills spec. Codex discovers skills from a .codex/skills/ tree at the repository root — a hand-copied mirror of plugins/jira-sdlc/skills/ plus a per-skill agents/openai.yml that reproduces disable-model-invocation: true. The tree is gitignored and maintained by manual copy; nothing automates it.

Verified from a real Codex CLI run (Codex CLI 0.146.1, July 2026, workspace-write sandbox). Everything below is first-hand unless marked Unverified.

Prerequisites​

  • Jira auth configured — per-request Basic auth from .jst/jira-sdlc-tools.local.env, no login step (see jira-api-reference.md §9)
  • gh (GitHub CLI) authenticated
  • .jst/jira-sdlc-tools.env and .jst/jira-sdlc-tools.local.env in your project root — see project-config.md
  • .codex/config.toml at the repo root with network access and writable roots enabled (see Sandboxing in the caveats section below — without them, jira.sh cannot reach curl, gh auth login cannot write its config, and linked-worktree git operations cannot update the checkout metadata)

Install / Wire-up Steps​

1. Create the .codex/skills/ tree​

Copy the plugin's skill source into Codex's discovery path. The source is plugins/jira-sdlc/skills/ (the directory that ships the three SKILL.md files plus _shared/); the target is .codex/skills/ at the repository root:

# from the repository root
mkdir -p .codex/skills
cp -a plugins/jira-sdlc/skills/* .codex/skills/

cp -a preserves the executable bit on the shared scripts (see chmod below). If you use a plain cp -r or a file manager, the .sh scripts under .codex/skills/_shared/scripts/ can land non-executable and the skills will fail at their first bash …/statuscheck.sh call.

2. Add agents/openai.yml to each skill​

This file is not part of the Claude plugin source — it is the Codex adaptation that reproduces disable-model-invocation: true. Create one in each of the three skill directories:

for skill in jira-task-assigner jira-task-executor jira-task-reviewer; do
mkdir -p ".codex/skills/$skill/agents"
cat > ".codex/skills/$skill/agents/openai.yml" <<'EOF'
policy:
allow_implicit_invocation: false
EOF
done

3. Make the shared scripts executable​

chmod +x .codex/skills/_shared/scripts/*.sh .codex/skills/_shared/scripts/*.py

cp -a preserves the mode, but a sync from a tarball, a Windows checkout, or a non-preserving copy can strip the bit — run this after every copy to be safe. This was checked during the verification run — the scripts in .codex/skills/_shared/scripts/ were -rwxrwxr-x.

4. Add .codex/config.toml​

Codex's Jira workflow shells out to jira.sh, which in turn calls curl — both need outbound HTTPS to the Atlassian site. In the default workspace-write sandbox, network is blocked unless you opt in:

# .codex/config.toml
sandbox_mode = "workspace-write"

[sandbox_workspace_write]
network_access = true
# Absolute, host-specific paths: allow gh's session config, linked-worktree git metadata, and worktree creation.
writable_roots = ["<HOME>/.config/gh", "<REPO_ROOT>/.git", "<WORKTREES_DIR>"]

writable_roots is required alongside network_access: the first path lets gh auth login --with-token update ~/.config/gh/hosts.yml; the second lets git update the main checkout's .git metadata when this is a linked worktree; the third lets the assigner skill create worktree folders under it. Replace all three placeholders with absolute paths for the host running Codex.

First run, WORKTREES_DIR doesn't exist yet? Codex's sandbox can only grant write access to a path that already exists when the policy is applied — listing a not-yet-created <WORKTREES_DIR> in writable_roots doesn't make it writable. jst-install's own setup step tries to mkdir -p that directory, and under this sandbox that attempt fails. Create WORKTREES_DIR by hand (mkdir -p <path>) before running jst-install from a Codex sandbox.

⚠️ Needs re-verification under the REST client. The gap verified here was specific to the old Atlassian CLI's jira auth login step — a step that no longer exists: jira.sh/jira.ps1 authenticate per-request from .jst/jira-sdlc-tools.local.env, with nothing to log into first. Whether a bare jira.sh network call (e.g. statuscheck.sh's own jira whoami) succeeds in a session that just picked up this config, or still needs a fresh session, has not been re-tested against the REST client. Until it is, treat Codex's escalated execution (sandbox_permissions: "require_escalated") as the safe default for any jira.sh/jira.ps1 or script call that reaches the network. See Sandboxing in the caveats.

5. Gitignore the tree​

.codex/ is not committed. A .codex/.gitignore with a single * keeps the whole tree out of git (matching the .agent/ pattern used for the agentskills.io spec):

echo '*' > .codex/.gitignore

The tree is deliberately a local working copy, not a synced artifact. There is no sync script (decided in the parent issue — docs-only, manual copy).

Invoking the Three Skills​

Codex triggers skills with the $<skill-name> syntax (the dollar sign, not the / slash Claude Code uses). All three skills set allow_implicit_invocation: false (via agents/openai.yml), so Codex will not auto-load them from ambient context — you invoke them explicitly:

  • $jira-task-assigner — break down a task into Jira issues with branches + worktrees
  • $jira-task-executor — implement an issue end-to-end from its worktree
  • $jira-task-reviewer — review sub-task PRs from the parent issue's worktree

Verified: this very doc was written by a $jira-task-executor run — Codex loaded the skill from .codex/skills/jira-task-executor/SKILL.md and executed it step by step.

The skill bodies still contain /jira-sdlc:… cross-references (the Claude Code slash-command form). Under Codex these are instructions to the model to re-run a skill, not parseable triggers — read them as "invoke $<skill-name>" (e.g. $jira-task-executor). They are not auto-rewritten by the copy; the model interprets them.

Platform-Specific Caveats​

Sandboxing / approval policy​

This is the main reason Codex gets its own file (the sibling Antigravity doc covers the rest of mechanism B without these rules).

The skills shell out to gh, git, bash, and jira.sh (which itself calls curl). In Codex's default workspace-write sandbox:

  • Network (Jira): blocked without network_access = true. Whether a bare jira.sh call succeeds inside the sandbox with just that setting is unverified against the REST client — the verification run predates the migration off the old Atlassian CLI, whose auth-login step used to fail here even with the config set. The reliable approach is escalated execution (sandbox_permissions: "require_escalated") for any jira.sh/jira.ps1 call or script that calls it. The skill's own preamble says: "if the sandbox blocks Jira, request scoped network-capable execution."

  • Git metadata (read-only FS): git's worktree metadata (.git/ in a linked worktree) lives outside the sandbox's writable root. Every git write operation — git restore, git fetch, git merge, git add, git commit, git push — fails with fatal: … Read-only file system. Verified: each of these needed escalated execution to proceed. This is not a Jira-specific allowlist; it is the sandbox's file-write boundary applied to the worktree's own .git directory.

  • GitHub CLI config (read-only FS): gh auth login --with-token writes ~/.config/gh/hosts.yml, which is outside the workspace by default. Without a writable root for that directory, the gh_auth healthcheck row reports a read-only filesystem error that can look like a bad or expired PAT; the credential is not necessarily the problem. A failed gh auth logout can leave the operator's existing session untouched under the same restriction, but a writable global config lets the login overwrite it.

  • Isolated GitHub CLI config (alternative): set GH_CONFIG_DIR through Codex's shell environment policy to an absolute, writable directory under the worktrees root (for example, <WORKTREES_DIR>/.ghconfig). This keeps the skill's login/logout state out of the operator's global ~/.config/gh. For example:

    [shell_environment_policy]
    set = { GH_CONFIG_DIR = "<WORKTREES_DIR>/.ghconfig" }

    Landlock enforces the Linux sandbox and Seatbelt enforces the macOS one, so the exact host path and writable-root configuration are platform-specific; use placeholders in shared config examples. This alternative relocates gh only — the linked-worktree .git writable root remains required for git writes.

  • Execution timeout: Codex's Bash tool defaults to a short yield window. A jira.sh/jira.ps1 call (or a statuscheck.sh run) that runs long will be reported as still running. Poll the session for output rather than treating the first chunk as a failure — and set a generous yield_time_ms / timeout_ms (the skill preamble recommends timeout_ms: 300000, i.e. 5 minutes). Needs re-measurement: the verification run timed the old Atlassian CLI's jira auth login and jira workitem view commands at ~20 s each, both appearing as running sessions that needed one or two polls — those figures were measured against that CLI and have not been re-timed against the equivalent jira.sh REST calls.

  • File-mode loss: a plain copy (not cp -a) or a Windows checkout can strip the executable bit from *.sh / *.py under .codex/skills/_shared/scripts/. Run chmod +x after copying (step 3 above). Not directly observed failing — the scripts were executable in the verification run — but the failure mode is real and silent.

Drift — the copy is not synced​

.codex/skills/ is a manual copy of plugins/jira-sdlc/skills/. When the plugin updates (a skill gains a step, a shared script changes), the copied tree goes stale and the skills silently run the old version — there is no sync script and no version pin. The recovery step is: re-run the copy recipe from Install above (steps 1–3), then re-add the three agents/openai.yml files (step 2).

disable-model-invocation: true​

Reproduced via agents/openai.yml → policy: allow_implicit_invocation: false. Verified present in all three skill dirs; its runtime effect (longer context needed) was not directly tested. Mark as checked but not confirmed until a second skill invocation shows the gating behaviour.

What the .codex/skills/ tree contains that the plugin source does not​

plugins/jira-sdlc/skills/ has the three SKILL.md files and _shared/ (reference .md files + scripts). .codex/skills/ adds, per skill, agents/openai.yml. One script — statusboard.sh — was present in the .codex/ tree but not in the tracked plugin source at verification time; if you copy with cp -a and the plugin source doesn't have it yet, the install still works (the skills only call statuscheck.sh).

agentskills.io spec vs Codex runtime path​

The parent issue describes the mechanism as "the .agent/ manual copy" (agentskills.io). In practice, Codex's discovery path is .codex/skills/, not .agent/skills/ — .agent/ was the reference shape used during investigation, but Codex does not pick it up. Verified: this run loaded skills from .codex/skills/, and a Jira comment on this issue ("codex need .codex folder, .agent seems not discoverable") records the same finding. Use .codex/skills/ as the target.