dsh-codex-subs-plugin User Guide
August 14, 2026 · View on GitHub
中文 | English
dsh-codex-subs-plugin User Guide
This guide starts with an unconfigured DeepSeek Harness (DSH) environment and completes the following end-to-end path:
Build the plugin
→ install it into the web and headless profiles separately
→ sign in with ChatGPT OAuth
→ select codex-subscription / gpt-5.5
→ make a real CLI request
→ start the Web UI
→ select a workspace and model
→ make a real Web request
If you only need the shortest path, go directly to Quick Start. Before using this in production, also read Security Boundaries and Troubleshooting.
1. Scope
This plugin registers the Codex subscription capability of a ChatGPT account as a primary DSH LLM route:
provider: codex-subscription
It is not either of the following:
- It is not an OpenAI Platform API-key adapter. OpenAI defines “Sign in with ChatGPT for subscription access” and “API key for usage-based access” as two separate authentication paths; see OpenAI authentication.
- It is not DSH's built-in
@deepseek-ai/dsh-subagent-codex. That package uses the officialcodex app-serveras a Codex subagent; this plugin connects Codex to DSH's primary-model route.
This project depends on non-public, non-stable contracts such as the auth.openai.com device-code endpoints, ChatGPT-Account-Id, and chatgpt.com/backend-api/codex. Server-side changes may break the plugin, and a subscription does not imply unlimited usage.
2. Verified Baseline
A live verification was completed on 2026-08-14 with the following environment:
- macOS
- Node.js
24.13.1 - DSH
0.1.0-rc.6 - Plugin
0.1.0 - Valid browser-OAuth credentials
gpt-5.5withreasoningEffort: medium
Verification results:
Headless: codex-subscription-ok
Web: codex-web-ok
No token, refresh token, account ID, or proxy address was printed or recorded in this document during verification. Model and account entitlements are determined dynamically by the server; these results prove only that this account and network path worked at the time of the test.
3. Prerequisites
3.1 Software
The plugin requires:
Node.js ^22.19.0 or >=24.0.0
pnpm
dsh CLI
Check the versions:
node --version
pnpm --version
dsh --version
On a new machine, you can install the versions verified by this guide:
npm install --global pnpm@11
npm install --global @deepseek-ai/dsh@0.1.0-rc.6
DSH is still in developer preview. After upgrading to another version, repeat the profile, doctor, headless, and Web acceptance checks in this guide.
DSH can also be launched directly through npm:
npx @deepseek-ai/dsh web
The remainder of this guide assumes dsh is already on PATH. If you do not have a global command, replace each dsh with a pinned npx --yes @deepseek-ai/dsh@<version> invocation.
3.2 Use One Fixed DSH_HOME
DSH profiles, settings, and this plugin's credentials all depend on DSH_HOME. Installation, login, diagnostics, headless operation, and Web operation must use the same value.
When unset, it defaults to:
~/.dsh
To set it explicitly:
export DSH_HOME="$HOME/.dsh"
Both DSH_HOME and DSH_CODEX_SUBS_AUTH_FILE should use absolute paths. The CLI converts a relative --auth-file path to an absolute path, but the adapter rejects a relative auth path. Mixing the two behaviors can produce a state where the CLI reports a successful login while the runtime still cannot find the credentials.
Key files:
| File | Purpose |
|---|---|
$DSH_HOME/settings.yaml | Runtime settings and default model shared across profiles |
$DSH_HOME/codex-subs/auth.json | This plugin's default OAuth credentials |
$DSH_HOME/profiles/web/package.json | Web-profile dependencies and bundle list |
$DSH_HOME/profiles/web/cordis.patch.yml | Web-profile-specific plugin overrides |
$DSH_HOME/profiles/headless/package.json | Headless-profile dependencies and bundle list |
$DSH_HOME/profiles/headless/cordis.patch.yml | Headless-profile-specific plugin overrides |
web and headless are separate profiles. The plugin must be installed into each profile separately. The OAuth file and settings.yaml are shared by default, so you normally sign in once and configure the default model once.
4. Quick Start
Run the following commands from the plugin repository root:
pnpm install
pnpm run check
dsh plugin --profile web add .
dsh plugin --profile headless add .
Sign in:
dsh plugin --profile web exec dsh-codex-subs login
Login prints the complete authorization URL. If the credentials contain the corresponding metadata, a successful login also prints the email address and account ID. Run it only in your own terminal; do not run it in CI, a shared terminal, a screen recording, tee, or a shell trace.
If no graphical browser is available:
Device-code login is currently a beta feature and must be enabled first. For a personal account, enable device-code login under ChatGPT Settings → Security. For a managed workspace, an administrator must enable it in workspace permissions. If it is not enabled, use the browser login above. See OpenAI authentication.
dsh plugin --profile web exec dsh-codex-subs login --headless
Headless login prints a one-time user code. Do not share or record it.
Merge the following content into $DSH_HOME/settings.yaml; do not overwrite other namespaces already in the file:
agent-default-model:
provider: codex-subscription
model: gpt-5.5
reasoningEffort: medium
Run diagnostics and one headless request:
dsh plugin --profile web exec dsh-codex-subs doctor
dsh plugin --profile headless exec dsh-codex-subs doctor
dsh --profile headless "Reply only: codex-subscription-ok"
Start the Web UI:
cd /absolute/path/to/your/project
dsh web
Open the URL printed in the terminal. The default is:
http://127.0.0.1:3080
Then:
- Select or add the project workspace.
- Create a new session.
- Click the current model in the composer.
- Open Model.
- Select OpenAI Codex Subscription → GPT-5.5.
- Confirm that Effort is Medium.
- Send
Reply only: codex-web-ok.
When the page returns codex-web-ok, the complete Web path is verified.
5. Build and Install
5.1 Install from the Current Checkout
cd /absolute/path/to/dsh-codex-subs-plugin
pnpm install
pnpm run check
pnpm pack --dry-run
Install into the Web profile:
dsh plugin --profile web add .
If you also want to run the headless CLI smoke test, install it into the headless profile:
dsh plugin --profile headless add .
add . must be run from the plugin repository root. You can also use an absolute path:
dsh plugin --profile web add /absolute/path/to/dsh-codex-subs-plugin
dsh plugin --profile headless add /absolute/path/to/dsh-codex-subs-plugin
5.2 Verify CLI Installation
Check each profile separately:
dsh plugin --profile web exec dsh-codex-subs --help
dsh plugin --profile headless exec dsh-codex-subs --help
You should see:
Usage: dsh-codex-subs <command> [options]
If Web is already running, restart dsh web after installing or upgrading a profile bundle.
5.3 What --dump-config Proves
dsh --profile web --dump-config
dsh --profile headless --dump-config
The following lines in the output prove only that the plugin bundle has entered the Cordis composition tree:
- id: llm-codex-subscription
name: dsh-codex-subs-plugin
--dump-config does not start the plugin, read $DSH_HOME/settings.yaml, or verify OAuth, proxy routing, model entitlement, or the actual runtime route. It is normal for the composed configuration to continue showing the DeepSeek default.
6. Proxy Configuration
Proxy variables must be set before running login, a headless request, or dsh web:
export HTTPS_PROXY=http://proxy.example:8080
export HTTP_PROXY=http://proxy.example:8080
export NO_PROXY=localhost,127.0.0.1
Supported variables:
HTTP_PROXY/http_proxyHTTPS_PROXY/https_proxyNO_PROXY/no_proxy
When both upper- and lower-case forms of the same variable are set, the lower-case form takes precedence. When HTTPS_PROXY is unset, the transport uses HTTP_PROXY as the fallback proxy for HTTPS.
Notes:
- The current transport does not read
ALL_PROXY. - The plugin uses a private Undici
EnvHttpProxyAgentand does not depend on Node 24'sNODE_USE_ENV_PROXY=1. - The browser authorization page uses the browser or operating-system network path. CLI code exchange, device flow, refresh, and Responses requests use the plugin transport. The two paths may have different public egress addresses.
- It is generally wise to keep loopback in
NO_PROXYso other environment clients do not proxy local traffic. However, the browser →127.0.0.1callback does not use this plugin's transport, and changing only the plugin's proxy variables cannot repair a browser callback. Do not accidentally addauth.openai.comorchatgpt.comtoNO_PROXYand bypass a required CLI proxy. - Do not run
set -x,printenv,env, orcurl -v, and do not paste a proxy URL containing a username or password into logs.
Check presence without printing values:
dsh plugin --profile web exec dsh-codex-subs doctor
You should see output similar to:
Proxy variables detected: yes
Plugin env proxy transport: enabled (independent of Node env proxy)
7. OAuth Login and Credentials
7.1 Browser PKCE Login
dsh plugin --profile web exec dsh-codex-subs login
This command prints the complete authorization URL. If the credentials contain the corresponding metadata, successful output also prints the email address and complete account ID. Do not run it in CI, a shared terminal, a screen recording, tee, set -x, or any other shell trace.
The flow:
- Starts a local callback on
127.0.0.1:1455. - Prints and attempts to open the OpenAI authorization URL.
- Validates OAuth state.
- Exchanges the PKCE authorization code for tokens.
- Shows success in the browser only after the atomic credential write has completed.
The browser flow has an overall timeout of five minutes. If the port is occupied, the browser cannot call back, or the machine has no desktop environment, use the device flow.
7.2 Headless Device Flow
Device-code login is currently a beta feature. A personal account must first enable device-code login under ChatGPT Settings → Security. A managed workspace requires an administrator to enable it in workspace permissions. If it is not enabled, use the browser PKCE flow instead. See OpenAI authentication for the official prerequisite.
dsh plugin --profile web exec dsh-codex-subs login --headless
The CLI displays an authorization URL and a one-time user code. The entire flow has a 15-minute timeout. The user code is sensitive while valid; do not record it or paste it into a shared chat.
7.3 Credential Path
Default path precedence:
$DSH_CODEX_SUBS_AUTH_FILE
> $DSH_HOME/codex-subs/auth.json
> ~/.dsh/codex-subs/auth.json
The file contains a bearer access token and a refresh token. It is not stored in Keychain and has no application-layer encryption. When creating storage, the plugin requests mode 0700 for the directory and 0600 for the file, and uses a temporary file, fsync, and an atomic rename.
The file may also contain an email address and account ID. mkdir(..., mode: 0700) does not automatically tighten an existing parent directory with broader permissions. Before first use, confirm that only you can access $DSH_HOME and the parent directory of any custom auth file.
Do not inspect or copy the auth JSON contents, and do not add the file to Git, a CI artifact, a log, an issue, or a chat.
7.4 status and doctor
Inspect local status:
dsh plugin --profile web exec dsh-codex-subs status
status does not make a network request or refresh a token. It prints the complete auth-file path and, when the credentials contain the corresponding metadata, the email address and complete account ID. Use it only in your own local terminal; do not share its output directly.
It exits with 0 when the credential exists and is unexpired according to the local clock. It exits with 1 when the credential is missing or locally expired. A nonzero exit does not mean that refresh has already been attempted.
Redacted diagnostics:
dsh plugin --profile web exec dsh-codex-subs doctor
doctor does not make a network request or refresh credentials. It reports only:
- whether auth is present, active, or expired;
- whether an account ID is present, without printing its value;
- whether the plugin is detected in the current profile;
- the provider/model declared in settings;
- whether proxy variables are present, without printing their values;
- the fixed endpoint.
active means only that the local file format is valid and expiresAt has not been reached. It does not prove that the token is still accepted remotely or that the account has entitlement to a model. Installation detection only checks whether package.json in the current working directory contains both the dependency and bundle; it does not prove that the adapter has started.
Account ID is optional metadata. The plugin sends the corresponding request header only when the value exists in the credentials. A missing account ID in doctor is not enough by itself to classify login or routing as failed; use a minimal real request as the deciding check.
doctor reads only the default $DSH_HOME/settings.yaml; it does not compose a custom settings file or the complete Cordis patch. Its displayed Provider is also fixed to the default value codex-subscription and does not resolve a custom route ID from the profile. When using advanced overrides, rely on the actual profile patch, the Web model selector, and a minimal real request.
When a report is generated successfully, diagnostic states such as missing, expired, or invalid currently do not change the exit code; all return 0. Argument errors, profile/bin execution failures, or unexpected exceptions can still return nonzero. Automation should check both the command exit code and the Auth status field in the output. Default output does not contain token values, identity values, or proxy values, but custom settings provider/model identifiers are printed as-is. Manually review the complete output before sharing it.
7.5 Custom Auth File
Use only an absolute path, and point the adapter and CLI to the same file.
In $DSH_HOME/profiles/<profile>/cordis.patch.yml for the target profile:
- id: llm-codex-subscription
config:
authFile: /absolute/private/path/codex-auth.json
Use the corresponding path for login and diagnostics:
dsh plugin --profile web exec dsh-codex-subs login \
--auth-file /absolute/private/path/codex-auth.json
dsh plugin --profile web exec dsh-codex-subs doctor \
--auth-file /absolute/private/path/codex-auth.json
dsh plugin --profile web exec dsh-codex-subs status \
--auth-file /absolute/private/path/codex-auth.json
dsh plugin --profile web exec dsh-codex-subs logout \
--auth-file /absolute/private/path/codex-auth.json
If both Web and headless use this path, apply the same plugin configuration to both profiles.
See the previous section for doctor limitations with custom providers and settings paths. If you change the route ID, you must also update agent-default-model.provider.
8. Select the Default Model
The plugin only registers a provider; it does not silently replace DSH's DeepSeek default model. You must select a model explicitly.
8.1 Edit settings.yaml Directly
Merge the following namespace into $DSH_HOME/settings.yaml:
agent-default-model:
provider: codex-subscription
model: gpt-5.5
reasoningEffort: medium
If the file already contains ui-onboarding, another provider, or UI settings, preserve them. Do not use shell redirection that overwrites the entire file.
Supported default reasoning efforts:
off | low | medium | high | xhigh
8.2 Save Through the Web Session Selector
You can avoid editing YAML manually:
- Start Web and select a workspace.
- In a normal session composer, click the current model or Select model.
- Open Model.
- Select a model in the OpenAI Codex Subscription group.
- Open Effort and select a reasoning effort.
The Web selection applies to the next request in the current session and attempts to save the choice as the global default for future new sessions.
Do not configure this plugin by entering an API key under Settings → Models. That page is for settings-backed/API-key providers. This plugin must complete OAuth through dsh-codex-subs login, after which it appears in the session model selector.
8.3 Current Catalog
Current advisory catalog:
gpt-5.3-codex-spark
gpt-5.4
gpt-5.4-mini
gpt-5.5
This is only a UI-selection snapshot, not an entitlement allowlist. An unlisted model ID is still sent through unchanged at the lower layer, and the server may accept or reject it. Public OpenAI API model capabilities also do not prove that the private ChatGPT Codex backend exposes the same model or context window to the current account.
8.4 Session Model Semantics
- A new session reads the latest
agent-default-model. - Switching models in Web takes effect on the current session's next request.
- An in-progress step does not switch models midway through generation.
- An older session that has already sent requests retains the model recorded in its log. Changing the global default does not automatically rewrite older sessions.
- If saving settings fails, the current session switch may still succeed, but the default will be lost after restart. Check
doctor, then create a new session to confirm inheritance.
9. Headless Verification
Prerequisites: the plugin is installed into the headless profile, and settings select codex-subscription.
Static check:
dsh plugin --profile headless exec dsh-codex-subs doctor
Real online request:
dsh --profile headless "Reply only: codex-subscription-ok"
Expected output:
codex-subscription-ok
Together, this step verifies:
settings runtime selection
→ provider route
→ OAuth access/refresh
→ environment proxy
→ fixed Codex Responses endpoint
→ SSE translation
→ DSH output
It consumes subscription usage and writes a local DSH session log. The request is sent to OpenAI and processed under the ChatGPT workspace's retention, residency, and data-handling policies. Neither terminal redirection nor store:false should be interpreted as “zero server retention.”
If you only need a shareable success/failure status without model output or raw errors:
set +x
if dsh --profile headless "Reply only: codex-subscription-ok" >/dev/null 2>&1; then
printf '%s\n' '{"onlineSmoke":"ok"}'
else
smoke_rc=$?
printf '{"onlineSmoke":"failed","exitCode":%d}\n' "$smoke_rc"
exit "$smoke_rc"
fi
This still sends a request, consumes subscription usage, and writes a session log. During troubleshooting, inspect raw stderr only in your own terminal, then redact it manually before sharing.
10. Complete Web Flow
10.1 Start
Run from the project directory you want to use as a workspace:
cd /absolute/path/to/your/project
dsh web
Equivalent command:
dsh --profile web
Default bind address:
127.0.0.1:3080
Treat the terminal output as authoritative:
dsh web: http://127.0.0.1:3080
Change the port:
dsh web --port 3081
Select an available port automatically:
dsh web --port 0
The current DSH version explicitly rejects --host 0.0.0.0. Do not expose the Web UI to the public internet. --trusted-host configures browser Host/authority trust; it is not a remote-listening switch.
10.2 Add a Workspace
The composer is unavailable on first entry until you select a workspace:
- Click Choose workspace in the center of the page, or Add workspace in the sidebar.
- In the Select Workspace Directory dialog, click Edit path.
- Enter the project's absolute path.
- Press Enter to navigate to the directory.
- Click Open.
If the sidebar is collapsed, click Open sidebar first, then use Add workspace.
10.3 Select Codex
- Create a normal new session.
- Click the current-model button below the composer.
- Click Model in the menu.
- Find the OpenAI Codex Subscription provider group.
- Select GPT-5.5.
- Open the menu again and select Medium under Effort.
You can also enter /model in the composer to open the same model catalog.
When loaded correctly, the model catalog should contain:
OpenAI Codex Subscription
GPT-5.3 Codex Spark
GPT-5.4
GPT-5.4 Mini
GPT-5.5
10.4 Web Online Smoke Test
In a text-only session, send:
Reply only: codex-web-ok
Expected response:
codex-web-ok
Then click New session and confirm that the model button still shows:
GPT-5.5 · Medium
This also verifies that the Web model selection was persisted as the default for new sessions.
The current adapter declares text input only. Do not attach images during the smoke test; a request containing an image is rejected before it is sent.
11. Advanced Plugin Configuration
11.1 Configuration Merge Order
Every time DSH starts a profile, it composes Cordis configuration in the following order. Later layers take precedence:
- Bundle patches declared in
dsh.profile.bundlesinside$DSH_HOME/profiles/<profile>/package.json; $DSH_HOME/profiles/<profile>/cordis.patch.yml;$DSH_HOME/cordis.patch.yml, shared across profiles;--patch <path>overlays supplied on the command line, in order.
For the same id, a later layer's config replaces the entire earlier config; it is not recursively deep-merged. When overriding an existing complex plugin, carry forward every field that must be retained.
$DSH_HOME/settings.yaml is not part of the Cordis patch stack above. It is read by the running settings provider, which overlays user settings such as agent-default-model on the composed defaults. This is why --dump-config cannot show the runtime default model.
11.2 Plugin Fields
Each profile has a separate override file:
$DSH_HOME/profiles/web/cordis.patch.yml
$DSH_HOME/profiles/headless/cordis.patch.yml
Example:
- id: llm-codex-subscription
config:
provider: codex-subscription
displayName: OpenAI Codex Subscription
authFile: /absolute/private/path/codex-auth.json
reasoningEffort: medium
textVerbosity: low
streamIdleTimeoutMs: 300000
models:
- id: gpt-5.5
name: GPT-5.5
Configuration fields:
| Field | Meaning |
|---|---|
provider | DSH route ID; after renaming it, also update agent-default-model.provider |
displayName | Web model-group display name |
authFile | Absolute path to the OAuth file; the CLI must use the same --auth-file |
reasoningEffort | Default reasoning effort when the caller does not specify one |
textVerbosity | Default Responses text verbosity |
streamIdleTimeoutMs | Timeout when the provider sends no events; default 300000 ms |
models | Web/DSH advisory catalog, not a server entitlement allowlist |
There is no baseURL or endpoint setting. The fixed endpoint is a security boundary that prevents the ChatGPT bearer token from being sent to a user-configured address.
If you use both Web and headless, add the required profile-specific configuration to both files. Do not assume that one profile's patch automatically applies to another profile.
12. Verification Levels
| Check | What it proves | What it does not prove |
|---|---|---|
dsh-codex-subs --help | The executable CLI is installed in the current profile | The adapter has started or auth is valid |
--dump-config | The bundle is in the Cordis composition | Settings defaults, OAuth, or remote entitlement |
doctor | Local auth/settings/proxy presence and the cwd-manifest installation heuristic | The adapter has started, effective fallback, or remote entitlement |
| Web model selector | The adapter is registered in the Web host and can list its catalog | The current model is necessarily allowed by the server |
| Minimal real prompt | The route, auth, network, endpoint, and stream work now | Long-term stability or availability of every model |
Recommended acceptance order:
dsh plugin --profile web exec dsh-codex-subs --help
dsh plugin --profile web exec dsh-codex-subs doctor
dsh --profile web --dump-config
dsh plugin --profile headless exec dsh-codex-subs --help
dsh plugin --profile headless exec dsh-codex-subs doctor
dsh --profile headless "Reply only: codex-subscription-ok"
dsh web
Finally, complete workspace selection, model selection, and the codex-web-ok request in Web.
13. Troubleshooting
| Symptom | Cause | Resolution |
|---|---|---|
dsh-codex-subs: command not found | The plugin is not installed in the current profile, or has not been built | Run pnpm run build, then run dsh plugin --profile <name> add . for the target profile |
--help prints nothing | The profile still references an old build containing the early .bin symlink entry-point bug | Rebuild and reinstall into that profile; --help must print Usage |
| pnpm blocks prepare/build | The profile's pnpm security policy has not allowed the build | Allowlist only the exact package named by pnpm, then run the installation again |
OAuth callback EADDRINUSE | 127.0.0.1:1455 is occupied | Stop the process using the port, or use login --headless |
| Browser login succeeds but token exchange fails | The browser and CLI use different egress paths, or the CLI is not using the correct proxy | Set HTTPS_PROXY/HTTP_PROXY before login, then check case conflicts and NO_PROXY |
UNSUPPORTED_COUNTRY_REGION_TERRITORY | The CLI's public egress, account, or workspace does not satisfy the server's region policy | Check the official supported regions and confirm a compliant egress path. That API page does not guarantee private ChatGPT Codex backend eligibility; server/workspace policy is authoritative |
Auth status: missing | Different DSH_HOME or authFile values were used | Fix DSH_HOME; for custom auth, make the plugin config and CLI --auth-file exactly match |
Auth status: expired | Local expiresAt has passed; doctor/status did not attempt refresh | Send one minimal real request to trigger refresh; sign in again only if refresh fails |
Login succeeds but DeepSeek still reports MISSING_CREDENTIAL | The default model is still the base DeepSeek model | Update settings.yaml, or select Codex in the Web session model selector |
no adapter registered for provider codex-subscription | The plugin is not installed in the current profile, Web was not restarted, or a renamed provider does not match | Check the target profile, restart Web, and synchronize agent-default-model.provider |
| The dump still shows DeepSeek | The dump does not read runtime settings | Inspect the settings override in doctor, check the Web model button, and send a real prompt |
doctor shows not-detected | It was run from the wrong profile/cwd, or the manifest is incomplete | Use dsh plugin --profile <target> exec ... doctor; inspect web and headless separately |
| No Codex OAuth card appears under Settings → Models | This is expected | Use CLI login, then select Codex in the session composer's model selector |
| The Web model menu has no OpenAI Codex Subscription group | The Web profile did not load the plugin or was not restarted | Run dsh plugin --profile web add ., confirm the dump, then restart dsh web |
| The Web composer is disabled | No workspace is selected, or the current provider/model cannot be routed | Add a workspace first, then select a Codex model |
| An old session still uses the old model after changing the default | Old sessions retain the provider/model in their logs | Switch it manually in the old session, or create a new session |
| Web selection succeeds but is lost after restart | $DSH_HOME/settings.yaml is not writable or settings persistence failed | Check file permissions, confirm the override with doctor, then create a new session |
| 401 | The adapter already refreshed automatically and retried once, but still failed | Sign in again; do not retry in a loop |
| 403 / model unavailable | Account entitlement, workspace policy, or server state | Choose a model available to the account, and contact the workspace administrator or OpenAI Support |
429 / usage_not_included | Subscription quota or rate limit | Wait for quota recovery or check the subscription plan; do not treat it as a proxy failure |
| Stream idle timeout | The proxy tunnel or network sent no events for too long | Check the proxy, NO_PROXY, and network stability; raise streamIdleTimeoutMs if necessary |
| Image rejected before sending | The current adapter is text-only | Create a text-only session; catalog spoofing cannot bypass modality validation |
EADDRINUSE: 3080 | The Web port is occupied | Use dsh web --port 3081 or --port 0 |
| Occasional refresh conflicts with multiple DSH processes | Refresh single-flight is shared only within one process; there is no cross-process file lock | Stop other processes, sign in again, and avoid simultaneous refreshes from multiple processes |
When diagnosing a region error, do not spoof the client ID, endpoint, or account ID, and do not copy another person's credentials. The server makes the final eligibility decision for the private Codex backend.
14. Upgrade, Uninstall, and Logout
14.1 Rebuild an Updated Local Checkout
First use your own Git workflow to update the checkout to the target revision; pnpm install does not pull new source code. Then run:
cd /absolute/path/to/dsh-codex-subs-plugin
pnpm install
pnpm run check
dsh plugin --profile web add .
dsh plugin --profile headless add .
Then restart dsh web.
14.2 Logout
Before uninstalling the plugin, run:
dsh plugin --profile web exec dsh-codex-subs logout
If the profile uses custom auth:
dsh plugin --profile web exec dsh-codex-subs logout \
--auth-file /absolute/private/path/codex-auth.json
logout only deletes this plugin's local auth file. It does not call an OpenAI revocation endpoint and does not sign out of ChatGPT, Codex CLI, or OpenCode.
The default auth file is shared by Web and headless, so one logout removes local credentials for both profiles. Custom auth must use the same --auth-file; deleting the default file does not delete a custom file.
Deleting the local file also does not remotely invalidate a refresh token that has already been copied or leaked. If credential exposure is suspected, do not treat local logout as complete incident response. Use the appropriate OpenAI account/workspace security controls, or contact the workspace administrator and OpenAI Support.
14.3 Uninstall
First change agent-default-model in $DSH_HOME/settings.yaml to a provider/model that will remain available, or remove the override. Otherwise, new sessions will continue to point to a route that no longer exists.
Then remove the plugin from each profile:
dsh plugin --profile web remove dsh-codex-subs-plugin
dsh plugin --profile headless remove dsh-codex-subs-plugin
Restart Web.
15. Security Boundaries
- The OAuth file contains a long-lived refresh token. Allow only the current user to read it, and never submit it to a repository, CI artifact, chat, or issue.
- Successful
loginoutput andstatusshow the complete auth path and may show an email address/account ID. Use onlydoctorfor shared diagnostics, and manually review custom provider/model identifiers before sharing. - Do not disclose the authorization URL, device user code, complete request headers,
Authorization, proxy URL, or raw error logs. - An online smoke test consumes ChatGPT Codex subscription usage. When the token is close to expiry or after the first 401, it may refresh, rotate, and write credentials back to the local file.
- DSH saves session logs. Requests are also sent to the ChatGPT service and processed under the applicable workspace's retention, residency, and data-handling policies. Redirecting terminal output to
/dev/nullor settingstore: falsein the request does not mean zero retention. - The adapter always sends requests to
https://chatgpt.com/backend-api/codex/responsesand does not support a user-configured endpoint. - Web binds only to loopback by default. Do not expose an authenticated proxy or the Web UI to the public internet for convenience.
- This plugin follows a private compatibility surface. Do not treat one successful smoke test as a guarantee of permanent compatibility or entitlement for every account.
16. Final Acceptance Checklist
- Node, pnpm, and DSH versions meet the requirements, and every command uses the same
DSH_HOME. - Proxy variables are set before login, headless, and Web startup; logs contain no proxy values or credentials.
-
pnpm run checkandpnpm pack --dry-runpass. - The Web profile's
--helpanddoctorwork. - If headless is used, the headless profile's
--helpanddoctorwork. -
doctorshows the expected local auth/settings state. When an account ID exists it appears only as present; a missing value is not by itself a failure, so use a minimal real request as the deciding check. - Dumps for both target profiles contain
llm-codex-subscription. - The minimal headless request returns
codex-subscription-ok. -
dsh webprints a loopback URL and the browser can connect. - A workspace is selected and the composer is enabled.
- The model menu contains
OpenAI Codex Subscription, and the current model isGPT-5.5 · Medium. - The minimal Web request returns
codex-web-ok. - A new session inherits
GPT-5.5 · Medium. - Shared diagnostics contain no token, email address, account ID, Authorization header, or proxy URL.
For implementation details, upstream OpenCode evidence, and compatibility risks, see docs/opencode-codex-subscription.en.md.