Contributing
July 14, 2026 ยท View on GitHub
Thanks for helping improve codex-profiles.
Local setup
git clone https://github.com/Ducksss/codex-profiles.git
cd codex-profiles
make check
make check is the canonical local gate: it runs syntax validation, all Bash
and Node behavior suites, and ShellCheck from one deterministic file inventory.
If ShellCheck is unavailable, run make test and state the missing lint result
explicitly in the pull request.
Product contract
Changes must preserve the distinction between two scopes:
cli,login,env, anduseselect Codex-local state throughCODEX_HOME. They do not switch ChatGPT Desktop.app defaultpreserves the stock ChatGPT session and uses~/.codex.- A named
app <profile>launch uses matchingCODEX_HOMEand separate Electron state for that named ChatGPT window across Chat, Work, and Codex. - The tool does not inspect or claim equality between CLI and Desktop accounts.
- Local-state separation is not an account, OS, or server-side boundary.
The Desktop launcher must use the original signed application. Do not add app cloning, bundle patching, ad-hoc signing, global app quitting, broad process killing, token copying, or cookie migration.
Development guidelines
- Keep the distributed CLI dependency-free: Bash plus standard macOS/POSIX tools only.
- Keep macOS-only behavior inside the Desktop launcher.
- Preserve
default -> ~/.codexand<name> -> ~/.codex-<name>. - Treat
--instance,--rebuild, andapp-instanceas compatibility spellings, not distinct launch modes. - Do not read, copy, print, parse, upload, compare, or migrate authentication tokens or ChatGPT cookies. Do not inspect or compare account identifiers.
- Keep human and JSON output explicit about whether a fact concerns Codex-local state or a ChatGPT Desktop window.
- Add regression tests for every observable behavior change.
- Update CLI help, README, completions,
docs/llms.txt, structured data, andCHANGELOG.mdtogether when the public surface changes. - Keep
bin/codex-profile, npm/package-lock, docs, PKGBUILD, and.SRCINFOversions in sync. A release also requires a dated changelog section.
Repository automation and test placement
- Keep installed behavior in the single
bin/codex-profilefile. Repository automation belongs underscripts/and must not enter the npm package. scripts/checkowns source and test discovery. Make, npm, CI, and release verification delegate to it rather than copying file lists.- Put tests beside their responsibility:
test/cli,test/install,test/packaging,test/release,test/site, ortest/outreach. - Put only reusable test infrastructure in
test/lib; product expectations stay in the owning suite. Tests must be independently runnable and use disposable state. - Keep GitHub workflow files focused on permissions, secrets, runner setup, and
sequencing. Release behavior belongs in directly tested
scripts/releasecommands. scripts/aur/prepare.shandscripts/aur/verify.shnever publish. The AUR credential, reviewed commit, and push remain maintainer-owned steps in the AUR runbook.
Useful focused commands include:
bash test/cli/workspace-test.sh
bash test/release/npm-test.sh
node test/packaging/aur-test.mjs
node test/site/geo-test.mjs
scripts/check list
Testing Desktop changes
Automated tests should use disposable fake app bundles and temporary homes. They must assert exact arguments and environment without opening or modifying a real installed app.
The following six-case matrix is required before every live release. Test the current signed ChatGPT app with non-sensitive accounts:
- Confirm
app defaultkeeps the existing stock session. - Confirm a named profile persists across relaunches.
- Confirm two different names can run concurrently without state crossover.
- Confirm Chat, Work, and Codex remain in the same named window context.
- Confirm CLI actions do not switch any open Desktop window.
- Confirm the installed app bundle remains byte-for-byte untouched by the launcher.
Never publish screenshots, logs, account names, histories, or tokens from this test without explicit sanitization.
Release rehearsal and attestation
Dispatch the Release workflow from the current main commit with the exact
tracked version. Its default dry_run: true path requires no Desktop
attestation and makes no tag, registry, release, tap, or Pages changes. The
always-run rehearsal invokes the same canonical make check gate used locally,
then requires a clean checkout with no unstaged, staged, or untracked artifacts.
This verification job has read-only repository permissions, and its checkout
does not persist a GitHub credential.
Only after the six cases above pass may a maintainer dispatch with
dry_run: false. The desktop_smoke_attestation value may contain exactly two
public app facts, in this form:
ChatGPT version 1.2026.168; bundle ID com.openai.codex
Substitute the installed public values. The version must have two or three
dot-separated numeric components. The bundle ID must begin com.openai. and
use only alphanumeric segments separated by dots or hyphens. Leading or trailing
whitespace, newlines, and extra text are rejected. Do not add an account name or
identifier, email address, screenshot, token, cookie, history, log, private
path, or other account data. The workflow converts the validated value to a
single escaped summary line and rejects a missing or malformed attestation
before any live release step.
The separate live-only job receives the write permissions. Before its first
external mutation, it checks out the verified commit again, preflights the npm
token's owner identity and the tap token's reported GitHub account access, then
re-fetches the current origin/main tip and exact remote tag state immediately
before tagging. Stale verification outputs cannot authorize a release after
either has moved. These read-only identity checks cannot prove a granular
token's write scope: configure NPM_TOKEN for codex-profile publication and
use a dedicated fine-grained TAP_TOKEN limited to Ducksss/homebrew-tap with
Contents read/write. Do not reuse a broad personal or organization token; the
actual npm publish and tap push remain the authoritative write checks.
After publication, the workflow retries npm installation with bounded backoff
into a fresh prefix and checks help and version through both command aliases.
It then verifies the exact GitHub Release tag, downloads install.sh from that
immutable tag, and exercises its public releases/latest path in fresh prefixes
until both aliases report the exact version and the plural alias is the expected
relative symlink. The workflow also requires a newly created Pages run from the
tag to succeed and polls the public site for the exact visible version. Homebrew
formula validation completes before the tap push. Tracked AUR metadata and
tagged files are validated fail-closed here, but publication to the external
AUR repository remains a maintainer action.
Maintainers performing that handoff must follow the
AUR publication and update runbook, including its
dedicated-key, immutable-tag, clean-build, and public-verification requirements.
Pull requests
Before opening a pull request:
make check
If ShellCheck is unavailable, state that clearly. The pull request must include what changed, why it changed, tests run, supported platforms, and any migration or compatibility impact. Use the repository template and identify whether the change affects Codex-local state, Desktop state, or both.
Security
Do not paste real auth files, access tokens, OAuth codes, cookies, connector credentials, private logs, or account identifiers into issues, discussions, pull requests, or test fixtures. Follow SECURITY.md for private vulnerability reporting.