Skip to content

feat: add Codex host support#120

Open
andrewjordancampbell wants to merge 6 commits intogarrytan:mainfrom
andrewjordancampbell:codex/codex-host-support
Open

feat: add Codex host support#120
andrewjordancampbell wants to merge 6 commits intogarrytan:mainfrom
andrewjordancampbell:codex/codex-host-support

Conversation

@andrewjordancampbell
Copy link

@andrewjordancampbell andrewjordancampbell commented Mar 17, 2026

Summary

  • add Codex as a first-class gstack host without duplicating workflow logic
  • generate .agents/skills/gstack*/SKILL.md from the same .tmpl templates as Claude
  • make setup, browse discovery, tests, CI, and docs understand both Claude and Codex installs
  • harden the canonical Codex bootstrap path so installs land in ~/.codex/skills/ and browse resolves there first
  • add Codex-facing repo docs (AGENTS.md, agents/openai.yaml) and generated support links under .agents/skills/gstack

What Changed

  • scripts/gen-skill-docs.ts
    • adds --host codex
    • routes Codex output into .agents/skills/
    • injects Codex frontmatter (name, description)
    • keeps shared resolvers host-aware
    • rewrites skill invocation syntax to $gstack-* for Codex
  • shared templates
    • replace hardcoded helper-doc paths with minimal placeholders ({{SKILL_ROOT}}, {{LOCAL_SKILL_ROOT}}, {{REVIEW_ROOT}})
    • keep one template source for both hosts
  • install/runtime
    • setup now supports --host claude|codex|auto
    • bin/dev-setup and bin/dev-teardown cover the Codex support tree alongside Claude dev mode
    • Codex installs now link into ~/.codex/skills/, backed by the generated .agents/skills/ tree
    • browse/src/find-browse.ts and browse/bin/find-browse now prefer .codex, then .agents, then legacy Claude paths
  • quality gates
    • extend tests for Codex freshness/frontmatter/path safety
    • run Codex dry-run generation in CI
  • docs
    • add AGENTS.md
    • add agents/openai.yaml
    • update README/CONTRIBUTING for dual-host development
    • add user-facing CHANGELOG entry for Codex support

Testing

bash -n setup bin/dev-setup bin/dev-teardown
bun test
bun run gen:skill-docs --dry-run
bun run gen:skill-docs --host codex --dry-run
bun run skill:check
TMP_HOME=$(mktemp -d)
HOME="$TMP_HOME" ./setup --host codex
HOME="$TMP_HOME" "$TMP_HOME/.codex/skills/gstack/browse/bin/find-browse"

Pre-Landing Review

Pre-Landing Review: No issues found.

Notes

  • Codex skills are generated only. Do not hand-edit .agents/skills/*/SKILL.md.
  • Codex-generated markdown intentionally contains no .claude/skills paths.
  • The root Codex skill directory includes support symlinks (bin, browse, review, setup, etc.) so helper-doc lookups and browse setup work after ./setup --host codex.
  • .agents/skills/ remains the generated source tree in the repo; ~/.codex/skills/ is the active installed skill location.

Andrew Campbell and others added 6 commits March 16, 2026 23:50
Add host-aware skill generation so the shared templates produce Codex-native skill files under .agents alongside the existing Claude output.
Teach the install and development helpers how to wire Codex skill directories, and prefer .agents paths when locating the browse binary.
Extend the skill generation and validation checks so Codex outputs are exercised in tests and CI.
Document the Codex install path, contributor workflow, and repository metadata for the new host.
Co-Authored-By: GPT-5-Codex <noreply@openai.com>
Make ~/.codex/skills the canonical Codex install root, teach browse discovery to prefer it consistently, and update generated docs/tests so the bootstrap path works out of the box.
Copy link
Author

@andrewjordancampbell andrewjordancampbell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: feat: add Codex host support

Findings

1. pr-body.md committed to repo root

  • Severity: Non-blocking
  • Location: pr-body.md (new file, 56 lines)
  • Description: This file is a copy of the PR description committed as a standalone file in the repo root. PR descriptions are GitHub artifacts preserved in PR history — committing them as files creates maintenance burden and clutters the repo root.
  • Suggested Fix: Remove pr-body.md from the commit. The PR description on GitHub is the canonical source.

2. --host as last CLI argument produces unclear error

  • Severity: Non-blocking
  • Location: scripts/gen-skill-docs.ts — HOST argument parsing
  • Description: If a user runs bun run gen:skill-docs --host (without a value), process.argv[HOST_ARG_INDEX + 1] evaluates to undefined. The validation catches this, but the error message reads Invalid --host value: undefined — a dedicated check for a missing value would be clearer.
  • Suggested Fix: Check for undefined before the general validation and throw --host requires a value: "claude" or "codex".

3. setup auto mode silently no-ops when neither host is detected

  • Severity: Non-blocking
  • Location: setup — auto mode case branch
  • Description: When --host auto is used and neither $HOME/.codex nor $HOME/.claude directories exist, the script completes silently without creating any symlinks and without warning the user.
  • Suggested Fix: Add a fallback warning when no host environment is detected.

4. link_codex_global() doesn't validate SKILL.md presence

  • Severity: Non-blocking
  • Location: setuplink_codex_global() function
  • Description: link_claude_local() and link_claude_global() both check [ -f "$skill_dir/SKILL.md" ] || continue before creating symlinks, but link_codex_global() only checks [ -d "$skill_dir" ] || continue. Non-skill directories matching the gstack* glob would be symlinked.
  • Suggested Fix: Add the same [ -f "$skill_dir/SKILL.md" ] || continue guard to link_codex_global().

5. find-browse TypeScript uses existsSync but bash uses -x (executable check)

  • Severity: Non-blocking
  • Location: browse/src/find-browse.ts vs browse/bin/find-browse
  • Description: The bash script checks executability (-x), while the TypeScript implementation only checks existence (existsSync). A non-executable binary file would be returned by TypeScript but skipped by bash.
  • Suggested Fix: Use fs.accessSync(candidate, fs.constants.X_OK) in the TypeScript implementation, or document this as intentional.

6. Invocation rewriting transforms content inside code blocks

  • Severity: Non-blocking
  • Location: scripts/gen-skill-docs.tsreplaceInvocations()
  • Description: The regex operates on full template content including fenced code blocks. A literal /browse inside a code example would be transformed to $gstack-browse. Currently doesn't cause issues in existing templates, but is fragile for future template authors.
  • Suggested Fix: Consider skipping replacement inside fenced code blocks, or accept as intentional since Codex skills should always show $gstack-* syntax.

7. Test coverage gap: no explicit test for invocation syntax transformation

  • Severity: Non-blocking
  • Location: test/gen-skill-docs.test.ts
  • Description: Tests verify Codex output doesn't contain .claude/skills paths, but there's no explicit test verifying /browse is transformed to $gstack-browse. This is a core feature of the Codex generation pipeline.
  • Suggested Fix: Add a test verifying $gstack-* syntax appears and /skill syntax does not in Codex output.

Summary

Overall assessment: Ready to merge. No blocking issues found.

This is a well-architected PR that adds Codex as a first-class host without duplicating workflow logic. The key design decisions are sound:

  • Single template source with host-aware placeholder resolution keeps the two hosts in sync
  • Relative symlinks in .agents/skills/gstack/ correctly point back to repo root (3 levels up)
  • Path precedence (.codex > .agents > .claude) is consistently implemented across bash and TypeScript
  • CI validation runs both --dry-run and --host codex --dry-run to catch staleness
  • Path isolation is enforced — tests verify no .claude/skills paths leak into Codex output
  • replaceInvocations() uses proper regex with word boundaries to avoid false matches
  • Output directories are created with mkdirSync({ recursive: true }) before writing

The 7 non-blocking findings are minor improvements around edge case handling, test coverage, and a stray pr-body.md file. None affect correctness for the intended use cases.

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.

1 participant