Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9bed078
feat(spend): require one writer lease per state directory for the spe…
lidge-jun Sep 19, 2026
192d0c5
fix(spend): bind journal mutations to a live lease, not to the handle
lidge-jun Sep 19, 2026
06fda1c
fix(spend): release the ledger singleton with the lease that owned it
lidge-jun Sep 19, 2026
4d6d896
fix(spend): prove exact ownership on every accounting read and change
lidge-jun Sep 19, 2026
20a959a
fix(spend): make ownership proof something only the owner module can …
lidge-jun Sep 19, 2026
6da37f4
fix(spend): key ownership proof on identity, not on a marker the toke…
lidge-jun Sep 19, 2026
7c47530
fix(spend): take ownership on demand instead of refusing to serve
lidge-jun Sep 19, 2026
64dae86
fix(spend): drop the implicit lease and own the directory in the fixt…
lidge-jun Sep 19, 2026
2c76301
test(spend): order the lease release ahead of each fixture's cleanup
lidge-jun Sep 19, 2026
4bb4d80
test(spend): let a failed lease release fail the case
lidge-jun Sep 19, 2026
567b673
test(spend): own the state directory in the six fixtures CI named
lidge-jun Sep 19, 2026
d3cca4e
test(spend): own the state directory in the merged send-budget count …
lidge-jun Sep 19, 2026
dba082c
test(spend): take the writer lease in every fixture that dispatches d…
lidge-jun Sep 19, 2026
d209eb8
test(spend): finish the lease migration and remove the image suite's …
lidge-jun Sep 19, 2026
afd9549
test(spend): make room for the lease in the five fixtures at their cap
lidge-jun Sep 19, 2026
4de35b4
test(spend): release each turn's body before the lease that served it
lidge-jun Sep 19, 2026
4231b27
test(spend): read the gateway attempt row's body before its lease is …
lidge-jun Sep 19, 2026
d2bc0d8
test(spend): repair the three failures the first hosted run found
lidge-jun Sep 19, 2026
92c2dae
test(spend): lease the four mixed fixtures the transitive audit found
lidge-jun Sep 19, 2026
a625141
test(spend): lease the websocket steering path at its shared fixture
lidge-jun Sep 19, 2026
b6328e8
test(spend): fix the audit batch and the two ownership-identity traps
lidge-jun Sep 19, 2026
6b5132b
test(codex): give the overlapping successor its own state directory
lidge-jun Sep 19, 2026
cf496e3
test(spend): wait for the turns to finish before giving the lease back
lidge-jun Sep 19, 2026
5591286
test(spend): track the wrapper each logged helper returns, not the ra…
lidge-jun Sep 19, 2026
70a86c7
test(routing): narrow the eager-relay platform claim to the relay dec…
lidge-jun Sep 19, 2026
58fb3bb
fix(spend): close three failure paths in the ledger's own storage
lidge-jun Sep 19, 2026
6842dcb
test(spend): prove the storage and rollback failure paths instead of …
lidge-jun Sep 19, 2026
c1644a2
test: repair the two source-anchor and platform assumptions CI found
lidge-jun Sep 19, 2026
be2563f
test(spend): close the three fixture gaps the review named
lidge-jun Sep 19, 2026
4d8493f
test: keep websocket teardown failure-safe and drain the store-defaul…
lidge-jun Sep 19, 2026
2711398
test: finish the websocket teardown so one failure cannot strand the …
lidge-jun Sep 19, 2026
9e789c1
test(server): fix the three late-batch failures the shard finally rea…
lidge-jun Sep 19, 2026
647dc67
test(spend): fix two macOS-only failures in my own storage regressions
lidge-jun Sep 19, 2026
a67cd9b
test(spend): make the contention matrix test the modes it names
lidge-jun Sep 19, 2026
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
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/fr/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Assistant de configuration interactif (`setup` est un alias de `init`). Il deman

### `ocx start [--port <port>] [--socks5 [host:port] | --socks5-off]`

Démarre le serveur proxy, de préférence sur le port `10100`. La commande écrit l’état du PID et du port d’exécution, et refuse de démarrer une deuxième instance active. Lorsque le port préféré est occupé, `start` interroge le processus qui l’occupe puis s’arrête dans tous les cas : elle refuse de démarrer si un processus opencodex y répond et signale sinon que le processus est inconnu. Elle ne déplace jamais l’écouteur vers un autre port d’elle-même, car cela laisserait le premier proxy en cours d’exécution et redirigerait Codex vers le second. Indiquez un autre port avec `--port`, ou définissez `port: 0` dans la configuration pour demander au système d’exploitation d’en attribuer un. Au démarrage, elle synchronise dans le catalogue Codex les modèles de chaque fournisseur. À l’arrêt, elle rétablit le fonctionnement natif de Codex, sauf si le proxy a été lancé comme service géré (`OCX_SERVICE=1`).
Démarre le serveur proxy, de préférence sur le port `10100`. La commande écrit l’état du PID et du port d’exécution, et refuse de démarrer une deuxième instance active. Lorsque le port préféré est occupé, `start` interroge le processus qui l’occupe puis s’arrête dans tous les cas : elle refuse de démarrer si un processus opencodex y répond et signale sinon que le processus est inconnu. Elle ne déplace jamais l’écouteur vers un autre port d’elle-même, car cela laisserait le premier proxy en cours d’exécution et redirigerait Codex vers le second. Un autre `--port` explicite est également refusé avec le même `OPENCODEX_HOME`, car les modes d’observation et de plafond écrivent tous deux dans le même journal de dépenses. Utilisez un `OPENCODEX_HOME` distinct pour une instance sœur indépendante ; `port: 0` ne sépare que l’attribution du port, pas l’état. Au démarrage, elle synchronise dans le catalogue Codex les modèles de chaque fournisseur. À l’arrêt, elle rétablit le fonctionnement natif de Codex, sauf si le proxy a été lancé comme service géré (`OCX_SERVICE=1`).

`--socks5` (par défaut `127.0.0.1:10808`) enregistre l’URL SOCKS5 dans `config.proxy` et achemine
les requêtes HTTP(S) sortantes dans un véritable tunnel SOCKS5. `--socks5-off` supprime uniquement
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/ja/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ description: セットアップ、開始、停止、サービス、診断、同

### `ocx start [--port <port>] [--socks5 [host:port] | --socks5-off]`

プロキシ サーバー (優先ポート `10100`) を起動します。PID/ランタイムポートの状態を書き込み、2 番目のライブインスタンスの起動を拒否します。優先ポートが使用中の場合、`start` はそのポートを使用しているプロセスを確認して、どちらの場合も停止します。opencodex が応答していれば起動を拒否し、それ以外は使用しているプロセスを特定できないと報告します。最初のプロキシを実行したまま Codex を 2 番目のプロキシへ向けることになるため、自動でリスナーを別のポートへ移すことはありません。別のポートは `--port` で指定するか、設定で `port: 0` を指定して OS に割り当てを依頼してください。開始時に、各プロバイダーのモデルを Codex のカタログに同期します。マネージド サービス (`OCX_SERVICE=1`) として起動されていない限り、シャットダウン時にネイティブ Codex が復元されます。
プロキシ サーバー (優先ポート `10100`) を起動します。PID/ランタイムポートの状態を書き込み、2 番目のライブインスタンスの起動を拒否します。優先ポートが使用中の場合、`start` はそのポートを使用しているプロセスを確認して、どちらの場合も停止します。opencodex が応答していれば起動を拒否し、それ以外は使用しているプロセスを特定できないと報告します。最初のプロキシを実行したまま Codex を 2 番目のプロキシへ向けることになるため、自動でリスナーを別のポートへ移すことはありません。同じ `OPENCODEX_HOME` では別の `--port` を明示しても拒否されます。監視のみの構成も上限を適用する構成も同じ支出ジャーナルへ書き込むためです。独立した sibling には別の `OPENCODEX_HOME` を使用してください。`port: 0` はポートだけを OS に割り当てさせ、状態を分離しません。開始時に、各プロバイダーのモデルを Codex のカタログに同期します。マネージド サービス (`OCX_SERVICE=1`) として起動されていない限り、シャットダウン時にネイティブ Codex が復元されます。

`--socks5`(デフォルト `127.0.0.1:10808`)は SOCKS5 URL を `config.proxy` に保存し、送信 HTTP(S) リクエストを実際の SOCKS5 トンネル経由で送信します。`--socks5-off` は保存された SOCKS5 プロキシだけを削除し、HTTP プロキシは削除しません。値は設定に保存されるため、`ocx update` 後も保持されます。URL にユーザー名とパスワードを含めることはできますが、起動ログでは非表示になります。

Expand Down
6 changes: 4 additions & 2 deletions docs-site/src/content/docs/ko/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ Codex 자동 시작 shim도 설치합니다.
인스턴스는 시작하지 않습니다. 권장 포트가 이미 사용 중이면 `start`가 점유자를 확인한 뒤 어느 경우든
실행을 멈춥니다. opencodex가 응답하면 시작을 거부하고, 그렇지 않으면 점유자를 식별할 수 없다고
알립니다. 첫 번째 프록시를 실행한 채 Codex가 두 번째 프록시를 가리키게 되므로, 리스너를 다른 포트로
자동 이동하지 않습니다. 다른 포트는 `--port`로 지정하거나, OS에 포트 할당을 요청하려면 구성에서
`port: 0`을 설정하세요. 시작할 때는 각 공급자의 모델을 Codex 카탈로그로 동기화합니다. 종료할 때는
자동 이동하지 않습니다. 활성 프록시와 같은 `OPENCODEX_HOME`을 사용하면 다른 `--port`를 명시해도
시작을 거부합니다. 관찰 전용과 제한 적용 모드 모두 같은 지출 저널에 기록하기 때문입니다. 독립된 형제
인스턴스에는 별도의 `OPENCODEX_HOME`을 사용하세요. `port: 0`은 포트만 OS에 맡기며 상태를 분리하지
않습니다. 시작할 때는 각 공급자의 모델을 Codex 카탈로그로 동기화합니다. 종료할 때는
기본 Codex를 복원합니다. 단, 관리형 서비스로 실행한 경우(`OCX_SERVICE=1`)는 예외입니다.

`--socks5`(기본값 `127.0.0.1:10808`)는 SOCKS5 URL을 `config.proxy`에 저장하고 실제 SOCKS5
Expand Down
10 changes: 6 additions & 4 deletions docs-site/src/content/docs/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ Start the proxy server (preferred port `10100`). It writes PID/runtime-port stat
start a second live instance. When the preferred port is occupied, `start` asks the holder who it
is and stops either way: it refuses outright when an opencodex answers there, and reports an
unidentified holder otherwise. It never moves the listener to another port on its own, because that
would leave the first proxy running and re-point Codex at the second. Name a different port with
`--port`, or set `port: 0` in the config to ask the OS for one. On start it syncs each provider's
models into Codex's catalog. On shutdown it restores native Codex — unless it was launched as a
managed service (`OCX_SERVICE=1`).
would leave the first proxy running and re-point Codex at the second. An explicit different
`--port` is still refused when the live proxy shares this `OPENCODEX_HOME`, because observe-only
and enforced spend accounting both write the same journal. Use a separate `OPENCODEX_HOME` for an
independent sibling; `port: 0` only asks the OS for that instance's port and does not separate its
state. On start it syncs each provider's models into Codex's catalog. On shutdown it restores
native Codex — unless it was launched as a managed service (`OCX_SERVICE=1`).

`--socks5` (default `127.0.0.1:10808`) saves `config.proxy` as a SOCKS5 URL and routes outbound
HTTP(S) through a real SOCKS5 tunnel. `--socks5-off` clears only that saved SOCKS5 proxy; it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ runs helper features around provider requests.
| `apiKeys?` | `OcxApiKey[]` | `[]` | Generated `ocx_…` data-plane admission credentials on non-loopback binds. They do not authorize management APIs; management access uses the separate credential documented in the [management reference](/reference/management-api/). Dashboard-managed. |
| `storageCleanupPolicy?` | `StorageCleanupPolicy` | disabled | Opt-in archived-session cleanup policy. Never enabled implicitly. |
| `appOwnedMemoryBudgetMb?` | `number` | `256` | Cap in MiB for evictable app-owned logs, caches, blobs, and continuation payloads. Range 64–4096; not an RSS cap. |
| `spend?` | `{ root?: { maxTokens?: number }; identity?: { maxTokens?: number }; pool?: { maxTokens?: number }; retentionDays?: number }` | unset | Durable token ceilings, off unless you write one. Each scope bounds settled spend plus in-flight reservations plus unresolved spend: `root` is one task including its whole fan-out, `identity` is one account across every task it serves, and `pool` is one provider pool. They intersect, so a request is admitted only when all three have room — which is what holds a ceiling against a client that mints a new task id per request. A reservation is the request's whole input plus its enforceable output ceiling, counted as if every cached prefix misses. Spend survives a restart, so it does not roll forward the way the send-count window does; raising or removing the value is what grants more. `maxTokens` must be a positive integer (0 would refuse everything), `retentionDays` is 1–365 and defaults to 7, and an unknown key in this section is rejected rather than ignored. A refusal is a local HTTP 429 carrying `x-opencodex-local-refusal: workflow_spend_exhausted`, and its message names the scope and the ceiling; no provider is contacted. |
| `spend?` | `{ root?: { maxTokens?: number }; identity?: { maxTokens?: number }; pool?: { maxTokens?: number }; retentionDays?: number }` | unset | Durable token ceilings, off unless you write one. Each scope bounds settled spend plus in-flight reservations plus unresolved spend: `root` is one task including its whole fan-out, `identity` is one account across every task it serves, and `pool` is one provider pool. They intersect, so a request is admitted only when all three have room — which is what holds a ceiling against a client that mints a new task id per request. A reservation is the request's whole input plus its enforceable output ceiling, counted as if every cached prefix misses. Observe-only mode still journals, so every server owns the state directory's single-writer lease; an explicit sibling must use a separate `OPENCODEX_HOME`. Spend survives an ordinary process restart when its writes reached the filesystem, but the journal does not promise survival across host power loss because each append is not fsynced. Raising or removing the value is what grants more. `maxTokens` must be a positive integer (0 would refuse everything), `retentionDays` is 1–365 and defaults to 7, and an unknown key in this section is rejected rather than ignored. A refusal is a local HTTP 429 carrying `x-opencodex-local-refusal: workflow_spend_exhausted`, and its message names the scope and the ceiling; no provider is contacted. |
| `codexAutoStart?` | `boolean` | `true` | Let the Codex shim run `ocx ensure` before launching Codex. False makes ensure a no-op. |
| `codexShimAutoRestore?` | `boolean` | `true` | Restore an installed shim after a completed external Codex update replaces it. Environment opt-out: `OPENCODEX_CODEX_SHIM_AUTO_RESTORE=0`. |
| `codexDesktopAuthless?` | `boolean` | `false` | Opt-in authless Codex Desktop routing on a loopback bind: inject the dedicated `opencodex` provider with `requires_openai_auth = false` so Desktop opens without a ChatGPT login. Ignored on non-loopback binds. `ocx system settings --desktop-authless on`. See [Codex integration](/guides/codex-integration/#authless-codex-desktop-opt-in). |
Expand Down
6 changes: 4 additions & 2 deletions docs-site/src/content/docs/ru/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ PID/runtime-port, а попытка поднять второй живой эк
занят, `start` проверяет, кто его удерживает, и в любом случае останавливается: он отказывается от
запуска, если там отвечает opencodex, а иначе сообщает о неопознанном владельце порта. Прокси
никогда сам не переносит listener на другой порт, поскольку тогда первый прокси продолжил бы
работать, а Codex был бы перенаправлен на второй. Укажите другой порт через `--port` или задайте
`port: 0` в конфигурации, чтобы порт назначила ОС. На старте прокси синхронизирует модели каждого
работать, а Codex был бы перенаправлен на второй. Явно указанный другой `--port` также отклоняется
при общем `OPENCODEX_HOME`: режим наблюдения и режим с лимитами оба пишут в один журнал расходов.
Для независимого соседнего экземпляра используйте отдельный `OPENCODEX_HOME`; `port: 0` поручает
ОС выбрать только порт и не разделяет состояние. На старте прокси синхронизирует модели каждого
провайдера в каталог Codex. При shutdown он восстанавливает native Codex — если только прокси не
был запущен как managed service (`OCX_SERVICE=1`).

Expand Down
8 changes: 5 additions & 3 deletions docs-site/src/content/docs/tr/reference/cli/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ durumunu yazar ve ikinci bir canlı örneği başlatmayı reddeder. Tercih edile
doluysa `start`, portu tutan süreci sorgular ve her iki durumda da durur: orada bir
opencodex yanıt veriyorsa başlatmayı reddeder, aksi halde portu tutan sürecin
tanımlanamadığını bildirir. İlk proxy'yi çalışır durumda bırakıp Codex'i ikinciye
yönlendireceği için dinleyiciyi kendiliğinden başka bir porta taşımaz. `--port` ile
farklı bir port belirtin veya işletim sisteminden bir port istemek için yapılandırmada
`port: 0` ayarlayın. Başlangıçta her sağlayıcının modellerini Codex'in kataloğuna
yönlendireceği için dinleyiciyi kendiliğinden başka bir porta taşımaz. Aynı
`OPENCODEX_HOME` kullanılırken farklı bir `--port` açıkça verilse de başlangıç reddedilir;
yalnızca gözlem ve sınır uygulama kiplerinin ikisi de aynı harcama günlüğüne yazar. Bağımsız
bir kardeş örnek için ayrı bir `OPENCODEX_HOME` kullanın. `port: 0` yalnızca port seçimini
işletim sistemine bırakır, durumu ayırmaz. Başlangıçta her sağlayıcının modellerini Codex'in kataloğuna
senkronize eder. Kapatıldığında — yönetilen bir servis olarak başlatılmadığı sürece
(`OCX_SERVICE=1`) — yerel Codex'i geri yükler.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ description: 安装、启动、停止、服务、诊断、同步和更新命令

### `ocx start [--port <port>] [--socks5 [host:port] | --socks5-off]`

启动代理服务器(首选端口 `10100`)。它会写入 PID/运行时端口状态,并拒绝启动第二个存活实例。当首选端口已被占用时,`start` 会探测占用者,并且无论结果如何都会停止:如果那里响应的是 opencodex,它会直接拒绝启动;否则会报告无法识别的占用者。它绝不会自行把监听地址移到其他端口,因为那会让第一个代理继续运行,并将 Codex 重新指向第二个代理。使用 `--port` 指定其他端口,或在配置中设置 `port: 0`,让操作系统分配端口。启动时,它会把每个提供方的模型同步到 Codex 的目录中。关闭时,它会恢复原生 Codex,除非它是作为受管服务启动的(`OCX_SERVICE=1`)。
启动代理服务器(首选端口 `10100`)。它会写入 PID/运行时端口状态,并拒绝启动第二个存活实例。当首选端口已被占用时,`start` 会探测占用者,并且无论结果如何都会停止:如果那里响应的是 opencodex,它会直接拒绝启动;否则会报告无法识别的占用者。它绝不会自行把监听地址移到其他端口,因为那会让第一个代理继续运行,并将 Codex 重新指向第二个代理。即使显式指定不同的 `--port`,共用同一个 `OPENCODEX_HOME` 时也会拒绝启动,因为仅观察模式和启用上限的模式都会写入同一个支出日志。独立的同级实例必须使用单独的 `OPENCODEX_HOME`;`port: 0` 只让操作系统分配端口,并不会隔离状态。启动时,它会把每个提供方的模型同步到 Codex 的目录中。关闭时,它会恢复原生 Codex,除非它是作为受管服务启动的(`OCX_SERVICE=1`)。

`--socks5`(默认 `127.0.0.1:10808`)会将 SOCKS5 URL 保存到 `config.proxy`,并通过真正的 SOCKS5 隧道转发出站 HTTP(S) 请求。`--socks5-off` 只会清除已保存的 SOCKS5 代理,不会删除 HTTP 代理。该值保存在配置中,因此会在 `ocx update` 后保留。URL 可以包含用户名和密码,但启动日志会将其隐藏。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ description: 安裝、啟動、停止、服務、診斷、同步與更新指令

### `ocx start [--port <port>] [--socks5 [host:port] | --socks5-off]`

啟動代理伺服器(偏好連接埠 `10100`)。它寫入 PID/runtime-port 狀態,並拒絕啟動第二個即時實例。偏好連接埠被佔用時,`start` 會探測佔用者,且無論結果如何都會停止:若回應的是 opencodex,它會直接拒絕啟動;否則會回報無法識別的佔用者。它絕不會自行將監聽位置移到其他連接埠,因為這會讓第一個代理繼續執行,並將 Codex 重新指向第二個代理。請用 `--port` 指定其他連接埠,或在設定中設為 `port: 0`,讓作業系統指派連接埠。啟動時它將每個供應商的模型同步到 Codex 目錄。關閉時它還原原生 Codex——除非它是作為受管服務啟動的(`OCX_SERVICE=1`)。
啟動代理伺服器(偏好連接埠 `10100`)。它寫入 PID/runtime-port 狀態,並拒絕啟動第二個即時實例。偏好連接埠被佔用時,`start` 會探測佔用者,且無論結果如何都會停止:若回應的是 opencodex,它會直接拒絕啟動;否則會回報無法識別的佔用者。它絕不會自行將監聽位置移到其他連接埠,因為這會讓第一個代理繼續執行,並將 Codex 重新指向第二個代理。即使明確指定不同的 `--port`,共用同一個 `OPENCODEX_HOME` 時仍會拒絕啟動,因為僅觀察模式和啟用上限的模式都會寫入同一份支出日誌。獨立的同層實例必須使用不同的 `OPENCODEX_HOME`;`port: 0` 只讓作業系統指派連接埠,不會隔離狀態。啟動時它將每個供應商的模型同步到 Codex 目錄。關閉時它還原原生 Codex——除非它是作為受管服務啟動的(`OCX_SERVICE=1`)。

`--socks5`(預設 `127.0.0.1:10808`)會將 SOCKS5 URL 儲存到 `config.proxy`,並透過真正的 SOCKS5 通道轉送對外 HTTP(S) 請求。`--socks5-off` 只會清除已儲存的 SOCKS5 代理,不會刪除 HTTP 代理。此值儲存在設定中,因此會在 `ocx update` 後保留。URL 可以包含使用者名稱和密碼,但啟動記錄會隱藏它們。

Expand Down
Loading
Loading