Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ It is community-maintained and is **not** an official OpenAI project.
- `raycast/` — optional Raycast extension (TypeScript, its own npm
dependencies); delegates every profile operation to the `codex-profile` CLI
(a standalone install or the menu-bar app's bundled copy) and never reads
auth data. Background calls use argument lists; Terminal launches go through
the user's shell with AppleScript `quoted form of`. It is outside the npm
auth data. Background calls use argument lists; Terminal launches pass the
user's shell one command whose values are single-quoted so sh, bash, zsh
and fish all read them literally (AppleScript `quoted form of` is not
fish-safe). It is outside the npm
package and `make check`; verify it with `npm run typecheck`, `npm test` and
`npx prettier --check .` inside `raycast/`. `npm run lint` fails until
`author` in `raycast/package.json` is a real Raycast username, so use
Expand Down Expand Up @@ -97,9 +99,10 @@ Profile-to-path mapping: `default -> ~/.codex`; any other name `<x> -> ~/.codex-
Shared test helpers must provide infrastructure rather than product policy.
- Match the existing Bash style in `bin/codex-profile`: `set -euo pipefail`,
`command_*` functions for subcommands, and the `die`/`note` helpers.
- If you change the command surface, update `usage()` in `bin/codex-profile`,
the README command reference, the shell completion generators, and
`docs/llms.txt` so all four stay in sync.
- If you change the command surface, update `usage()` and the per-command help
in `bin/codex-profile`, the command reference in `USAGE.md` (the README only
links to it), the shell completion generators, and `docs/llms.txt` so they
stay in sync.
- Bump the version together in `bin/codex-profile`, `package.json`, both
`package-lock.json` version fields, `docs/index.html`,
`packaging/aur/PKGBUILD`, and `packaging/aur/.SRCINFO`. CI and the GEO test
Expand Down Expand Up @@ -140,7 +143,8 @@ link.
per-profile Electron user data. The tool never reads, copies, prints, parses,
compares, or migrates `auth.json` tokens or ChatGPT cookies.
- `clone-config` copies only an allowlist of non-secret root config files and
refuses sensitive-looking key names.
refuses any file containing sensitive-looking text (key, token, secret and
similar words, URL credentials, common token prefixes).
- `init --share-with` links only the documented configuration allowlist. It
keeps auth, sessions, logs, Electron data, caches, skills, and connector/app
state separate and never reads or copies authentication data; linked config
Expand Down
72 changes: 72 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,78 @@ and this project follows semantic versioning for tagged releases.
percent sign. Hover and keyboard selection use an inset rounded plate, rules
start at the title column and step aside beside it, and space rather than
rules separates groups.
- The npm package no longer ships the unused `docs/welcome.svg`.

### Fixed

- `status --json` stays valid JSON when a profile's status fails or the Codex
CLI is missing, and rejects invalid profile names instead of reporting them.
Plain `status` reports a missing Codex CLI once instead of running an empty
command for every profile.
- `launcher create` no longer reports success when a build step fails, for
example from a copy that is not executable. Its default name now fits profile
names that end in `.`, `-` or `_` or are very long; `--force` can change only
the letter case of a name on a case-insensitive volume; and an interrupt no
longer leaves a half-built bundle in `~/Applications`.
- `remove` refuses a differently cased spelling of a profile on a
case-insensitive volume, which skipped its shared-configuration and
workspace-binding checks.
- An exported `CDPATH` no longer breaks relative workspace paths. `workspace
unbind` resolves a deleted folder through its surviving parent, as `bind`
recorded it (for example `/tmp` or a symlinked projects folder). `app` never
passes a workspace starting with `-` to `open` as an option, and
`app-instance` or `app --instance` without a profile opens the picker as
documented.
- `doctor --json` reports unreadable workspace state instead of exiting with
no output.
- Two commands reclaiming the same stale state lock can no longer both
proceed, and a lock with no recorded owner explains how to recover.
- `env` and `use` refuse a symlinked profile home, as every other command does.
- The Bash and Zsh `--prompt` indicator removes stale `[codex:…]` prefixes
that tools such as Python venv restore with their saved prompt.
- `upgrade --prefix` resolves a relative prefix from the current directory
instead of the upgrade cache, and `upgrade --ref` refuses a name that is not
a commit instead of restoring a path with that name.
- Zsh completions saved as `_codex-profile` complete on every Tab instead of
every other one, and `doctor` completion offers `-j`. Help lists the
update-check environment variables.
- Menu-bar low-quota alerts no longer take a reading that is still refreshing
as the baseline when another profile's reading arrives first, which could
notify as soon as alerts were turned on.
- Raycast: a usage timeout is reported as a timeout, Open Workspace clears a
profile filter whose last binding was removed, and copied commands use the
`codex-profile` the extension found, including the menu-bar app's copy.
- Release automation: the AUR clean build now fails on namcap errors, and the
Pages check reads the whole site before searching it. The outreach tracker
accepts plain HTTP only for exactly `127.0.0.1`, and `list --owned false`
lists unowned targets.

### Security

- Terminal launches from the menu-bar app and Raycast quote profile names and
folder paths so fish reads them literally. AppleScript's `quoted form of` is
POSIX-only, so under fish a folder name containing a backslash and a quote
could run the rest of the name as commands.
- `clone-config` also refuses files with names such as `BRAVE_KEY` or
`GITHUB_PAT`, `key` or `dsn` entries, credentials in URLs and common token
prefixes, and its message and documentation now say it matches text anywhere
in the file.
- `scripts/release/set-npm-token.sh` hands the token to npm on standard input
instead of `env`'s argument list, where `ps` and exec audit logs could see it.

### Documented

- The network model now includes the GitHub Releases request that `upgrade`
and `upgrade --dry-run` make, and the update check is described by whether
output is a terminal. Corrected the `setup` defaults, plain `doctor` exit
status, `list` output, launcher target and `usage` exit status, added
maintenance commands to `llms.txt`, named the `USAGE.md` command reference in
the sync rules, and noted that `main` must not move during a release.

### Tests

- Native tests tag their throwaway defaults suites and remove them afterwards,
instead of leaving an empty plist in `~/Library/Preferences` on every run.

## 1.3.0 - 2026-10-12

Expand Down
10 changes: 7 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ killing, token copying, or cookie migration.
- 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, and
`CHANGELOG.md` together when the public surface changes.
- Update CLI help, the `USAGE.md` command reference, README, completions,
`docs/llms.txt`, structured data, and `CHANGELOG.md` together when the
public surface changes.
- Keep `bin/codex-profile`, npm/package-lock, docs, PKGBUILD, and `.SRCINFO`
versions in sync. A release also requires a dated changelog section.

Expand Down Expand Up @@ -162,7 +163,10 @@ the release artifact. Installation verification uses a fresh prefix and checks
`help` and `version` through both command aliases. On either timeout, investigate
npm review notifications and registry status, then rerun the same immutable
release once the exact artifact is publicly installable. Never bypass checks or
move tags to recover.
move tags to recover. Because every rerun also requires `origin/main` to still
be the verified commit, do not merge to `main` until the release finishes; if
`main` moves after the tag is pushed, the rerun stops at that check and the
remaining channels need a new patch release.

The workflow then verifies the exact GitHub Release tag, downloads `install.sh`
from that immutable tag, and exercises its public `releases/latest` path in
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ codex-profile cli work
```

`setup` guides you through profile creation and offers sign-in, project
binding and shell integration. Optional extras default to no, and shell
startup changes are shown for approval first. For scripts, use `init`,
binding, a macOS launcher and shell integration. Sign-in defaults to yes and
the others to no; shell startup changes are shown for approval first. For scripts, use `init`,
`login` and `cli` separately.

Install **`codex-profile`** (singular). It provides both `codex-profile` and
Expand Down
23 changes: 14 additions & 9 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ regulated, privileged, or adversarial separation.

`clone-config` considers only an allowlist of root-level non-auth files. It
never copies `auth.json`, sessions, plugins, logs, caches, Electron data, or
directories, and it refuses sensitive-looking keys. The heuristic is a safety
guard, not a proof that arbitrary text is non-secret. Review source files
directories, and it refuses a file containing sensitive-looking text anywhere,
prose included: words such as auth, token, secret, password or key, credentials
in URLs, and common token prefixes. The heuristic is a safety guard, not a
proof that arbitrary text is non-secret. Review source files
before copying them between trust domains.

## Configuration linking
Expand All @@ -98,13 +100,16 @@ trust domains.
The wrapper itself performs network access only for these project-maintenance
features:

- `upgrade` fetches the configured source repository. A non-default repository
can execute code during installation; use only sources you trust and inspect
`upgrade --dry-run` first.
- Interactive terminal runs may make one anonymous HTTPS request to the npm
registry at most once per day to compare versions. Scripts, pipes, CI, and
JSON output do not perform this check. Disable it with
`CODEX_PROFILE_NO_UPDATE_CHECK=1` or `DO_NOT_TRACK=1`.
- `upgrade` without `--ref`, including `upgrade --dry-run`, first asks the
GitHub Releases API for the latest release, then fetches the configured
source repository. A non-default repository can execute code during
installation; use only sources you trust and inspect `upgrade --dry-run`
first.
- Runs whose standard output is a terminal may make one anonymous HTTPS
request to the npm registry at most once per day to compare versions. Pipes,
captured output, runs without a terminal such as most CI, and JSON output do
not perform this check. Disable it with `CODEX_PROFILE_NO_UPDATE_CHECK=1` or
`DO_NOT_TRACK=1`.

Codex CLI and the ChatGPT app make their own network requests under OpenAI's
behavior and policies. Those requests are outside this wrapper's network
Expand Down
22 changes: 14 additions & 8 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,9 @@ when not `ok`, and `windows` with `duration_mins`, `used_percent`,
`remaining_percent` and `resets_at` (Unix seconds); durations and reset times
may be `null`. The command reports quota only: it never switches profiles.

Ordinary `doctor` remains informational. `doctor --check` exits nonzero when
Ordinary `doctor` does not fail on unhealthy local state; it exits nonzero only
when a profile's `codex login status` fails unexpectedly, as `status` does.
`doctor --check` exits nonzero when
the CLI is missing, status collection fails, workspace state is invalid or
stale, or private profile state is linked; JSON includes top-level `healthy`
and workspace `schema_version` fields for automation.
Expand Down Expand Up @@ -392,9 +394,10 @@ set `CODEX_PROFILE_LAUNCHER_ROOT` to use another directory. Creation derives a
deterministically tinted icon from the installed ChatGPT artwork on the local
Mac. The project does not redistribute that artwork.

Each generated app is a small unsigned shell launcher. It calls
`codex-profile app <profile>` and leaves the installed, signed ChatGPT bundle
untouched. Its custom name and icon appear on the launcher in Finder,
Each generated app is a small unsigned shell launcher. It runs `app <profile>`
through the absolute path of the `codex-profile` that created it (recreate it
with `--force` after moving or reinstalling `codex-profile` elsewhere) and
leaves the installed, signed ChatGPT bundle untouched. Its custom name and icon appear on the launcher in Finder,
Launchpad, and when pinned to the Dock. After launch, the active ChatGPT process
keeps ChatGPT's native name and icon because macOS is running the original
signed app.
Expand Down Expand Up @@ -588,7 +591,9 @@ codex-profile clone-config personal work --force

Only root-level `config.toml` and `AGENTS.md` are eligible. The command never
copies `auth.json`, sessions, plugins, logs, caches, Electron data, or
directories, and it refuses sensitive-looking configuration keys.
directories, and it refuses a file containing sensitive-looking text anywhere,
including prose: words such as auth, token, secret, password or key,
credentials in URLs, and common token prefixes.

### Upgrade a source installation

Expand Down Expand Up @@ -767,8 +772,9 @@ codex-profile cli work --help

## Update checks

Interactive terminal runs check the npm registry at most once per day and use
a local cache. Scripts, pipes, CI, and JSON output remain quiet. The request
Runs whose standard output is a terminal check the npm registry at most once
per day and use a local cache. Pipes, captured output, runs without a terminal
such as most CI, and JSON output remain quiet. The request
contains no profile data; disable it with `CODEX_PROFILE_NO_UPDATE_CHECK=1` or
`DO_NOT_TRACK=1`. See [SECURITY.md](SECURITY.md) for the complete network model.

Expand All @@ -777,7 +783,7 @@ contains no profile data; disable it with `CODEX_PROFILE_NO_UPDATE_CHECK=1` or
CLI-oriented commands and launcher inspection are tested on macOS and Ubuntu/Linux:

```text
cli login init setup detach remove workspace run status path env use logs clone-config list doctor completions shell-init upgrade version help
cli login init setup detach remove workspace run status usage path env use logs clone-config list doctor completions shell-init upgrade version help
```

`app` and `launcher create` are macOS-only. They detect the installed integrated `ChatGPT.app` and
Expand Down
Loading
Loading