cdx-manager 0.12.4 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +214 -19
- package/changelogs/CHANGELOGS_0_14_0.md +146 -0
- package/changelogs/CHANGELOGS_0_15_0.md +139 -0
- package/checksums/release-archives.json +12 -0
- package/package.json +3 -3
- package/pyproject.toml +1 -1
- package/src/cli.py +64 -4
- package/src/cli_args.py +324 -39
- package/src/cli_commands.py +251 -3049
- package/src/cli_helpers.py +190 -2
- package/src/cli_render.py +17 -0
- package/src/commands/__init__.py +6 -0
- package/src/commands/auth.py +224 -0
- package/src/commands/backup.py +112 -0
- package/src/commands/context_memory.py +341 -0
- package/src/commands/launch.py +218 -0
- package/src/commands/lifecycle.py +154 -0
- package/src/commands/maintenance.py +723 -0
- package/src/commands/runs.py +849 -0
- package/src/commands/settings.py +107 -0
- package/src/commands/status.py +713 -0
- package/src/config.py +70 -0
- package/src/errors.py +17 -0
- package/src/health.py +151 -3
- package/src/notify.py +11 -5
- package/src/provider_background.py +263 -0
- package/src/provider_runtime.py +142 -15
- package/src/run_command.py +112 -4
- package/src/run_failover.py +221 -0
- package/src/run_registry.py +127 -2
- package/src/session_backup.py +343 -0
- package/src/session_helpers.py +179 -0
- package/src/session_ranking.py +259 -0
- package/src/session_service.py +698 -1426
- package/src/session_status.py +550 -0
- package/src/status_source.py +45 -0
- package/src/status_view.py +15 -34
package/README.md
CHANGED
|
@@ -1,20 +1,52 @@
|
|
|
1
1
|
# CDX Manager
|
|
2
2
|
|
|
3
|
-
[](LICENSE) ](LICENSE)  
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Stop guessing which AI account still has quota.** `cdx` tracks the rate-limit window of every Codex and Claude account you own, tells you which one is usable right now, and launches it with isolated auth — in one command.
|
|
6
6
|
|
|
7
|
-
If you
|
|
7
|
+
If you pay for several AI coding subscriptions, you know the dance: you hit a 5-hour limit mid-task, guess which other account still has room, re-authenticate, and lose your context on the way. `cdx` turns that into `cdx next`.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+

|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g cdx-manager
|
|
17
|
+
|
|
18
|
+
cdx add codex work # register an isolated Codex profile named "work"
|
|
19
|
+
cdx add claude perso # and a Claude one
|
|
20
|
+
cdx status # every account's remaining quota, side by side
|
|
21
|
+
cdx next # which account should I use right now?
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Supported providers: `codex`, `claude`, `antigravity`, `ollama`.
|
|
25
|
+
|
|
26
|
+
`cdx next` answers the question you actually have, and prints the command to run:
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## The Core Five
|
|
33
|
+
|
|
34
|
+
Everything else is optional. These five cover the daily loop:
|
|
35
|
+
|
|
36
|
+
| Command | What it gives you |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `cdx add <provider> <name>` | An isolated account profile — its own auth, its own home |
|
|
39
|
+
| `cdx <name>` | Launch that account, auth checked first |
|
|
40
|
+
| `cdx status` | Remaining 5-hour and weekly quota for every account at once |
|
|
41
|
+
| `cdx next` | The account you should use right now, and why |
|
|
42
|
+
| `cdx run --prompt ... --json` | The same routing, headless, for scripts and agents |
|
|
13
43
|
|
|
14
44
|
---
|
|
15
45
|
|
|
16
46
|
## Table of Contents
|
|
17
47
|
|
|
48
|
+
- [Quick Start](#quick-start)
|
|
49
|
+
- [The Core Five](#the-core-five)
|
|
18
50
|
- [What it does](#what-it-does)
|
|
19
51
|
- [Technical Overview](#technical-overview)
|
|
20
52
|
- [Getting Started](#getting-started)
|
|
@@ -32,24 +64,58 @@ One command to launch any session. Zero auth juggling.
|
|
|
32
64
|
|
|
33
65
|
## What it does
|
|
34
66
|
|
|
67
|
+
### Quota-aware routing
|
|
68
|
+
|
|
69
|
+
The reason `cdx` exists: knowing, across every account you own, which one you can actually use.
|
|
70
|
+
|
|
71
|
+
- **Usage at a glance.** `cdx status` shows token usage, 5-hour window quota, weekly quota, last-updated timestamps, priority guidance, and the last launched session in one aligned table.
|
|
72
|
+
- **Pick for me.** `cdx next` selects the best available assistant from your pinned priorities and the live quota picture, shows the reason, and prints the exact command to run.
|
|
73
|
+
- **Next-ready notification.** `cdx ready` schedules a native system notification for the next assistant that comes back from cooldown, then returns immediately. `cdx notify` covers reset times and scheduled wake-ups.
|
|
74
|
+
- **Passive status resolution.** Codex status is read from the local Codex app-server rate-limit API when available, with legacy transcript/history parsing kept as a fallback.
|
|
75
|
+
- **Banked reset visibility.** Eligible Codex accounts show the number of manually redeemable bonus resets in `cdx status` and expose reset details in JSON output.
|
|
76
|
+
|
|
77
|
+
### Isolated multi-account sessions
|
|
78
|
+
|
|
79
|
+

|
|
80
|
+
|
|
35
81
|
- **Multiple providers, one tool.** Register as many Codex, Claude, Antigravity, or Ollama sessions as you need. Codex and Claude get isolated auth environments; Antigravity is launchable through `agy` with OS-keyring auth; Ollama runs local models through `ollama run`.
|
|
36
82
|
- **Instant launch.** `cdx work` opens your "work" session. `cdx personal` opens another. No config files to edit mid-flow.
|
|
37
83
|
- **Quick relaunch.** `cdx last` reopens the most recently launched assistant profile.
|
|
84
|
+
- **Resume by identity, not by recency.** Each session records the provider's own conversation id — imposed at launch for Claude, read back from the rollout for Codex — so `cdx resume <name>` reopens *that* conversation regardless of your working directory or of which session ran last. `cdx can-resume --json` reports the strategy and where the id came from, so an automated caller can tell a named resume from a best-effort one.
|
|
38
85
|
- **Auth guardrails.** `cdx` checks authentication before launching. If a session is not logged in, it tells you exactly what to run — no silent failures.
|
|
39
|
-
- **Optional session labels.** `cdx label <name> <label>` adds a short human label; list and full status tables show a `LABEL` column only when at least one session has one.
|
|
40
|
-
- **Usage at a glance.** `cdx status` shows token usage, 5-hour window quota, weekly quota, last-updated timestamps, priority guidance, and the last launched session in one aligned table.
|
|
41
|
-
- **Next-ready notification.** `cdx ready` schedules a native system notification for the next assistant that comes back from cooldown, then returns immediately.
|
|
42
|
-
- **Session control.** Disable a session without deleting it when an account is temporarily out of credits; disabled sessions remain visible and sort last.
|
|
43
86
|
- **Persistent launch settings.** Pin per-session power, permission, and fast-mode preferences once; `cdx` reapplies them on every launch until you unset them.
|
|
87
|
+
- **Spend ceiling and model fallback.** `cdx set <name> --budget 5` caps what a headless run may spend, and `--fallback-model sonnet,haiku` lets a run continue on the next model when the first is overloaded. Both are Claude Code flags that the provider accepts with `--print` only, so they apply to `cdx run` and not to interactive launches; `cdx configs` says so.
|
|
88
|
+
- **Session control.** Disable a session without deleting it when an account is temporarily out of credits; disabled sessions remain visible and sort last.
|
|
89
|
+
- **Optional session labels.** `cdx label <name> <label>` adds a short human label; list and full status tables show a `LABEL` column only when at least one session has one.
|
|
90
|
+
- **Clean removal.** `cdx rmv` wipes a session and its entire auth directory. No orphaned files, no stale credentials.
|
|
91
|
+
|
|
92
|
+
### Headless automation
|
|
93
|
+
|
|
94
|
+
- **One task, one JSON result.** `cdx run` executes a prompt against a chosen or auto-selected session and returns a stable payload; `--detach` returns a `run_id` immediately.
|
|
95
|
+
- **Survives a rate limit.** `cdx run --failover` notices that a run stopped because its account ran out, moves the task to the next account the ranking allows, and carries on — one `run_id` for the whole task, with every account it occupied listed in `cdx run-report`. A spent account is always confirmed against its own refreshed quota first, so a healthy account is never abandoned. From there two routes migrate a run: the provider said so in words cdx recognises, or — since that wording differs between an enterprise workspace out of credits, a personal plan hitting its 5-hour window, and Claude's own phrasing — simply that the account's quota is gone and the run failed. `cdx run-report` names which route applied. Exhausting every account reports `failover_exhausted`, which a caller can tell apart from the task itself failing.
|
|
96
|
+
- **Native background delegation (opt-in).** With `CDX_EXPERIMENTAL_NATIVE_BG=1`, `cdx run --detach` hands the run to Claude Code's own background agents (`--bg`) instead of cdx's detached launcher. The run keeps its cdx `run_id`, closes out with its token usage and final answer read from the provider's own session transcript, and the parked session is stopped once its task is done. Off by default for one release while it settles; the in-house launcher is unchanged and is what every run takes otherwise. Codex keeps the in-house path while its `cloud`/`exec-server` surfaces are marked experimental.
|
|
97
|
+
- **Observable runs.** `cdx run-status`, `cdx run-tail`, `cdx run-report`, and `cdx runs --since` follow a run while it happens and after it ends.
|
|
98
|
+
- **Selection without launching.** `cdx select --provider ... --require-ready --json` answers "which session should this job use?" for orchestrators.
|
|
99
|
+
- **Escape hatch for unmapped flags.** `cdx set <name> --extra-args "--add-dir ../shared"` passes provider arguments cdx does not model straight through, so a flag your provider shipped last week never forces you to abandon cdx. These arguments are explicitly unvalidated: cdx does not parse or verify them, `cdx schema --json` lists them under `unvalidated` rather than describing them, and `cdx doctor --check-provider-flags` ignores them. They are split into literal argv entries and never passed through a shell.
|
|
100
|
+
- **Validated contract.** `cdx schema --json` publishes the enums, mutually-exclusive argument groups, and error codes programmatic callers should validate against.
|
|
101
|
+
|
|
102
|
+
### Context handoff
|
|
103
|
+
|
|
104
|
+
- **Shared handoff context.** Keep a per-workspace Markdown context, or build one from a source session transcript, and install it into another assistant session before switching providers or accounts.
|
|
105
|
+
- **Session transcript capture.** Every launch is recorded to a local log file via `script`, giving you a full terminal transcript for each session.
|
|
106
|
+
|
|
107
|
+
### Maintenance
|
|
108
|
+
|
|
44
109
|
- **Launch history.** Inspect recent launches with provider, result, duration, working directory, launch settings, and transcript path.
|
|
110
|
+
- **Aggregate usage.** `cdx stats` totals runs, token usage, and time spent per session over any period.
|
|
111
|
+
|
|
112
|
+

|
|
113
|
+
|
|
45
114
|
- **Disk usage and cleanup.** `cdx disk` reports `CDX_HOME` usage, `cdx disk profiles --candidates` identifies reclaimable profile caches/logs with evidence, and `cdx clean profiles ...` applies explicit cleanup actions.
|
|
115
|
+
- **Health and repair.** `cdx doctor` inspects dependencies, permissions, and orphan profiles; `cdx repair` plans or applies safe fixes.
|
|
116
|
+
- **Portable bundles.** `cdx export` / `cdx import` move sessions between machines, with passphrase-encrypted auth data when you ask for it.
|
|
46
117
|
- **Update prompts.** Periodic update checks surface `cdx update` directly in the `cdx`, `cdx status`, and launch output when a newer release is available. When `logics-manager` is installed, `cdx` can also suggest `logics-manager self-update`.
|
|
47
118
|
- **Logics viewer shortcut.** `cdx view` opens the Logics browser/focus viewer through `logics-manager view` when the companion CLI is installed. All viewer flags are forwarded: `--lan`, `--lan-rw`, `--focus <ref>`, `--read`, `--port`, `--host`, `--refresh-interval`, `--tls`, `--tls-cert`, `--tls-key`, `--open`, `--no-open`. `cdx view --json` reports availability and update diagnostics without opening the viewer.
|
|
48
|
-
- **Shared handoff context.** Keep a per-workspace Markdown context, or build one from a source session transcript, and install it into another assistant session before switching providers or accounts.
|
|
49
|
-
- **Passive status resolution.** Codex status is read from the local Codex app-server rate-limit API when available, with legacy transcript/history parsing kept as a fallback.
|
|
50
|
-
- **Banked reset visibility.** Eligible Codex accounts show the number of manually redeemable bonus resets in `cdx status` and expose reset details in JSON output.
|
|
51
|
-
- **Session transcript capture.** Every launch is recorded to a local log file via `script`, giving you a full terminal transcript for each session.
|
|
52
|
-
- **Clean removal.** `cdx rmv` wipes a session and its entire auth directory. No orphaned files, no stale credentials.
|
|
53
119
|
|
|
54
120
|
---
|
|
55
121
|
|
|
@@ -357,8 +423,8 @@ cdx history --summary --from 2026-05-01 --to 2026-05-28
|
|
|
357
423
|
| `cdx config <name> [--json]` | Show persistent launch settings for a session |
|
|
358
424
|
| `cdx configs [--json]` | Show persistent launch settings for all sessions in one table |
|
|
359
425
|
| `cdx power\|perm\|fast\|model <name\|all\|provider:PROVIDER\|a,b> <value\|default> [--json]` | Shortcut commands for setting or clearing one launch setting |
|
|
360
|
-
| `cdx set <name>\|--sessions all\|a,b\|--provider PROVIDER [--power minimal\|low\|medium\|high\|xhigh] [--permission review\|default\|auto\|full] [--fast on\|off] [--rtk on\|off] [--logics on\|off] [--model MODEL] [--priority 0..100] [--json]` | Persist launch settings for one or more sessions |
|
|
361
|
-
| `cdx unset <name>\|--sessions all\|a,b\|--provider PROVIDER (--power\|--permission\|--fast\|--rtk\|--logics\|--model\|--priority\|--all) [--json]` | Remove persisted launch settings and fall back to provider defaults |
|
|
426
|
+
| `cdx set <name>\|--sessions all\|a,b\|--provider PROVIDER [--power minimal\|low\|medium\|high\|xhigh] [--permission review\|default\|auto\|full] [--fast on\|off] [--rtk on\|off] [--logics on\|off] [--model MODEL] [--fallback-model MODEL[,MODEL...]] [--budget USD] [--extra-args 'ARGS'] [--priority 0..100] [--json]` | Persist launch settings for one or more sessions |
|
|
427
|
+
| `cdx unset <name>\|--sessions all\|a,b\|--provider PROVIDER (--power\|--permission\|--fast\|--rtk\|--logics\|--model\|--fallback-model\|--budget\|--extra-args\|--priority\|--all) [--json]` | Remove persisted launch settings and fall back to provider defaults |
|
|
362
428
|
| `cdx history [name] [--limit N] [--summary] [--since 7d\|today\|DATE] [--from DATE] [--to DATE] [--json]` | Show recent launch history or aggregate total launch time per assistant, optionally filtered by period |
|
|
363
429
|
| `cdx last [--json]` | Launch the most recent existing session from launch history |
|
|
364
430
|
| `cdx resume <name> [--json]` | Resume the provider-native conversation for a session using the named command form |
|
|
@@ -374,7 +440,7 @@ cdx history --summary --from 2026-05-01 --to 2026-05-28
|
|
|
374
440
|
| `cdx reset <name> [--yes] [--json]` | Explicitly consume one available banked Codex rate-limit reset; confirmation is required unless `--yes` is supplied |
|
|
375
441
|
| `cdx export <file> [--include-auth] [--sessions a,b] [--passphrase-env VAR\|--passphrase-stdin] [--force] [--json]` | Export sessions to a portable bundle; `--include-auth` encrypts auth data with a passphrase |
|
|
376
442
|
| `cdx import <file> [--sessions a,b] [--passphrase-env VAR\|--passphrase-stdin] [--force\|--merge] [--allow-authless-force] [--json]` | Import sessions from a bundle into the current `CDX_HOME` |
|
|
377
|
-
| `cdx doctor [--severity OK|WARN|FAIL[,OK|WARN|FAIL...]] [--json]` | Inspect CLI dependencies, provider CLI versions/capability hints, CDX_HOME permissions, missing state, orphan profiles, and pending quarantines; optionally filter issue severities |
|
|
443
|
+
| `cdx doctor [--severity OK|WARN|FAIL[,OK|WARN|FAIL...]] [--check-provider-flags] [--json]` | Inspect CLI dependencies, provider CLI versions/capability hints, CDX_HOME permissions, missing state, orphan profiles, and pending quarantines; optionally filter issue severities. `--check-provider-flags` additionally verifies that the CLI flags cdx maps for each permission are actually accepted by each provider's installed CLI |
|
|
378
444
|
| `cdx repair [--dry-run] [--force] [--json]` | Plan or apply safe repairs for missing state files, quarantines, and orphan profiles |
|
|
379
445
|
| `cdx view [--json] [--lan] [--lan-rw] [--focus <ref>] [--read] [--port <port>] [--host <host>] [--refresh-interval <s>] [--tls] [--tls-cert <path>] [--tls-key <path>] [--open] [--no-open]` | Open the Logics browser/focus viewer by delegating to `logics-manager view`; all viewer flags are forwarded; JSON mode reports diagnostics without launching it |
|
|
380
446
|
| `cdx update [--check] [--yes] [--json] [--version TAG]` | Update cdx-manager using the installer that matches how it was installed |
|
|
@@ -384,7 +450,12 @@ cdx history --summary --from 2026-05-01 --to 2026-05-28
|
|
|
384
450
|
| `cdx notify --next-ready [--poll seconds] [--once] [--schedule] [--refresh] [--json]` | Wait until the recommended session is usable, or schedule the next known reset notification |
|
|
385
451
|
| `cdx next [--json] [--refresh]` | Select the best next assistant using the same priority logic as `cdx status` |
|
|
386
452
|
| `cdx select --provider PROVIDER [--min-reasoning-effort minimal\|low\|medium\|high\|xhigh] [--min-power minimal\|low\|medium\|high\|xhigh] [--require-ready] [--refresh] --json` | Select a suitable session for headless automation |
|
|
387
|
-
| `cdx run [session] --cwd PATH (--prompt-file PATH\|--prompt TEXT) [--provider PROVIDER] [--model MODEL] [--reasoning-effort minimal\|low\|medium\|high\|xhigh] [--power minimal\|low\|medium\|high\|xhigh] [--permission MODE] [--timeout-seconds N] --json` | Run one headless task and return a stable JSON result |
|
|
453
|
+
| `cdx run [session] --cwd PATH (--prompt-file PATH\|--prompt TEXT\|--prompt-file -) [--provider PROVIDER] [--model MODEL] [--reasoning-effort minimal\|low\|medium\|high\|xhigh] [--power minimal\|low\|medium\|high\|xhigh] [--permission MODE] [--timeout-seconds N] [--detach] [--failover] [--refresh] --json` | Run one headless task and return a stable JSON result; `--detach` returns the `run_id` at launch without waiting, `--failover` continues the task on the next account when this one hits its rate limit, `--prompt-file -` reads the prompt from stdin |
|
|
454
|
+
| `cdx run-report <run_id> --json` | Full report, transcript metadata, and final payload for a run |
|
|
455
|
+
| `cdx run-status <run_id> --json` | Status of one run by id |
|
|
456
|
+
| `cdx run-tail <run_id> [--lines N] --json` | Last lines of a run's own output, while it is still running or after it finished |
|
|
457
|
+
| `cdx runs [--limit N] [--since 7d\|today\|DATE] --json` | List recent runs; `--since` returns every run completed after the cursor and ignores `--limit` |
|
|
458
|
+
| `cdx schema --json` | Publish the enums, mutually-exclusive argument groups, and error codes programmatic callers should validate against |
|
|
388
459
|
| `cdx stats [name] [--since 7d\|today\|DATE] [--from DATE] [--to DATE] [--json]` | Aggregate launch counts, duration, and known headless token usage by session |
|
|
389
460
|
| `cdx status [--json] [--refresh\|--cached] [--timeout SECONDS]` | Show token usage table for all sessions; `--cached` skips live provider probes and returns only stored status |
|
|
390
461
|
| `cdx status --small [--refresh\|--cached] [--timeout SECONDS]` / `cdx status -s [--refresh\|--cached] [--timeout SECONDS]` | Show compact token usage table without provider, blocking quota, credits, and updated columns |
|
|
@@ -506,6 +577,130 @@ cdx stats work
|
|
|
506
577
|
cdx select --provider codex --min-reasoning-effort low --require-ready --json
|
|
507
578
|
```
|
|
508
579
|
|
|
580
|
+
### How cdx picks a session
|
|
581
|
+
|
|
582
|
+
`cdx select`, `cdx run --provider`, `cdx next`, the `cdx status` recommendation, and `cdx ready` all use one ranking. They used to use two that disagreed, so the answer depended on which command you asked.
|
|
583
|
+
|
|
584
|
+
**Candidate filters** exclude sessions before any ordering happens: disabled sessions, logged-out sessions (they cannot serve work), sessions of another provider when one is requested, sessions below a requested `--min-reasoning-effort`, and — when readiness is required — sessions with no availability left.
|
|
585
|
+
|
|
586
|
+
**Ordering** compares the remaining candidates factor by factor:
|
|
587
|
+
|
|
588
|
+
1. **Usability** — usable now, then blocked with a known upcoming reset, then reset known, then nothing known.
|
|
589
|
+
2. **Priority** — the `--priority` you set with `cdx set <name> --priority 0..100`, highest first.
|
|
590
|
+
3. Then, for a session you can use now: **credits** (sessions *without* credits first, so included quota is spent before paid credits), **availability**, **reset time**. For a session you cannot use now the order is **reset time** first, then credits and availability — when you cannot use it, what matters is when it comes back.
|
|
591
|
+
4. **Reasoning effort** — the lowest configured effort that still clears any requested floor, leaving stronger sessions free for work that needs them.
|
|
592
|
+
5. **Session name**, so the order is deterministic.
|
|
593
|
+
|
|
594
|
+
`--priority` ranks sessions *within* a usability class, never across one. A high-priority session with no quota left does not outrank a usable one: priority expresses which usable session to prefer, not a way to route work somewhere it will fail.
|
|
595
|
+
|
|
596
|
+
`cdx select --json` reports `selection_policy` (built from the ranking itself, so it cannot describe an order the code does not apply) and `deciding_factor`/`reason`, naming the factor that actually separated the winner from the runner-up for that call — or reporting that it was the only candidate. Do not treat `selection_policy` as a stable identifier; it changes when the ranking changes, which is the point.
|
|
597
|
+
|
|
598
|
+
`cdx run --provider` selects from cached status by default. Pass `--refresh` to fetch status first. When a session is auto-selected without any recorded availability, the run payload carries a `session_selected_without_status` warning — that is different from a session known to be low, and on a freshly imported or long-idle set of sessions it is the ordinary case.
|
|
599
|
+
|
|
600
|
+
### Verifying provider flag mappings
|
|
601
|
+
|
|
602
|
+
cdx translates each `--permission` value into concrete provider CLI flags. Those mappings are declarations about someone else's CLI, and a provider can drop or rename a flag without cdx noticing — which is exactly what happened with an `--experimental-yolo` flag mapped for ollama that the ollama CLI never had.
|
|
603
|
+
|
|
604
|
+
`cdx doctor --check-provider-flags` verifies them against the installed provider CLIs:
|
|
605
|
+
|
|
606
|
+
```bash
|
|
607
|
+
cdx doctor --check-provider-flags --json
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
For each configured provider it reports, per permission, whether every mapped flag is accepted. A rejected flag is a `FAIL` naming the provider, the permission, and the flag. A provider whose CLI is not installed, or whose help cannot be read, is a `WARN` — never an `OK`: "could not verify" is precisely the state a stale mapping hides in. A provider that maps no flags at all, such as ollama, reports `OK` with an empty mapping, so having nothing to check is distinguishable from having failed to check.
|
|
611
|
+
|
|
612
|
+
It is opt-in because it costs one provider CLI invocation per configured provider. When it is not requested, the default `cdx doctor` report says so with a `provider_permission_flags_unchecked` warning rather than omitting it, so a green report never implies the mappings were verified.
|
|
613
|
+
|
|
614
|
+
### Programmatic Callers
|
|
615
|
+
|
|
616
|
+
`cdx run` blocks until the provider finishes, which suits a supervisor that can wait. Agents, MCP servers, and watchdogs usually cannot, so the surface below exists specifically for them: launch without waiting, watch progress, react to failures by code, and discover valid values instead of hard-coding them.
|
|
617
|
+
|
|
618
|
+
**Launch without waiting.** `--detach` returns as soon as the run is registered, with the `run_id` already assigned:
|
|
619
|
+
|
|
620
|
+
```bash
|
|
621
|
+
cdx run work --cwd /path/to/repo --prompt-file task.md --detach --json
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
The payload carries `detached: true`, `run_id`, `pid`, and the artifact paths — but no `exit_code`, `duration_seconds`, or `usage`, since the run has not finished. The detached process is put in its own session, so it survives the launcher exiting, including when cdx was invoked over an SSH command that returns immediately. It transitions its own registry entry to a terminal status, so `cdx runs` and `cdx run-status` stay accurate with nobody supervising.
|
|
625
|
+
|
|
626
|
+
Authentication is still resolved before the launch returns, so a login problem surfaces synchronously rather than silently in the background.
|
|
627
|
+
|
|
628
|
+
**Watch a run in progress.** `cdx run-status` reports only running/succeeded/failed; `run-tail` shows what the run is actually doing:
|
|
629
|
+
|
|
630
|
+
```bash
|
|
631
|
+
cdx run-tail <run_id> --lines 50 --json
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
It returns the last lines of the run's own `stdout_path` plus its current status, whether the run is still going or already finished. Lines are raw provider output, not summarized. Undecodable bytes come back with replacement characters rather than failing the call.
|
|
635
|
+
|
|
636
|
+
**Pipe an untrusted prompt.** `--prompt-file -` reads the prompt from standard input, so arbitrary text never has to reach a command line or a temporary file the caller must clean up:
|
|
637
|
+
|
|
638
|
+
```bash
|
|
639
|
+
echo "$UNTRUSTED_PROMPT" | cdx run work --cwd /path/to/repo --prompt-file - --json
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
It fails immediately if standard input is a terminal, rather than blocking at a silent prompt.
|
|
643
|
+
|
|
644
|
+
**Poll for completions with a cursor.** `cdx runs --since` returns every run that completed after the cursor, using the same cursor forms as `cdx history --since`:
|
|
645
|
+
|
|
646
|
+
```bash
|
|
647
|
+
cdx runs --since 15m --json
|
|
648
|
+
cdx runs --since 2026-08-07T09:00:00Z --json
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
A cursor is bounded by time, not by row count: `--limit` is ignored when `--since` is given (and says so in `warnings`). That is deliberate — capping a cursor query by row count would silently drop completions a caller had not yet seen, which is exactly the miss the cursor removes. Runs still in flight are not returned; they appear once they complete. Callers do not need to keep their own set of already-reported run ids.
|
|
652
|
+
|
|
653
|
+
**React to failures by code, not by message.** Argument failures report a specific `error.code` and name the offending arguments as data:
|
|
654
|
+
|
|
655
|
+
| `error.code` | Raised when |
|
|
656
|
+
| --- | --- |
|
|
657
|
+
| `missing_required_argument` | A required argument is absent |
|
|
658
|
+
| `mutually_exclusive_arguments` | Two arguments that cannot be combined were both given |
|
|
659
|
+
| `invalid_argument_value` | A constrained option got a value outside its accepted set |
|
|
660
|
+
| `argument_value_out_of_range` | A numeric argument fell outside its accepted range |
|
|
661
|
+
| `unknown_argument` | An unrecognized flag |
|
|
662
|
+
|
|
663
|
+
```json
|
|
664
|
+
{
|
|
665
|
+
"ok": false,
|
|
666
|
+
"error": {
|
|
667
|
+
"code": "mutually_exclusive_arguments",
|
|
668
|
+
"message": "cdx run: cannot specify both a session name and --provider.",
|
|
669
|
+
"arguments": ["session", "--provider"],
|
|
670
|
+
"allowed_values": null
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
Never branch on `error.message`; it is written for a human reading a terminal and may be reworded.
|
|
676
|
+
|
|
677
|
+
**Discover valid values.** `cdx schema --json` publishes the enums and argument constraints the parser itself validates against:
|
|
678
|
+
|
|
679
|
+
```bash
|
|
680
|
+
cdx schema --json
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
It returns accepted values for `permission` (with its aliases and canonical forms), `reasoning_effort`/`power`, `kind`, and `provider`, plus the declared mutually-exclusive argument groups and the error codes above. Validate against this rather than copying the lists into your own code — a hand-maintained copy drifts, and cdx will not tell you when it does.
|
|
684
|
+
|
|
685
|
+
**Surface run warnings.** The run payload's `warnings` list reports degradations a zero exit code would otherwise hide, on the successful path as much as the failing one:
|
|
686
|
+
|
|
687
|
+
```json
|
|
688
|
+
{
|
|
689
|
+
"ok": true,
|
|
690
|
+
"exit_code": 0,
|
|
691
|
+
"warnings": [
|
|
692
|
+
{
|
|
693
|
+
"code": "network_disabled_by_permission",
|
|
694
|
+
"message": "codex runs at permission 'review' inside a sandbox with no network access, ...",
|
|
695
|
+
"provider": "codex",
|
|
696
|
+
"permission": "review"
|
|
697
|
+
}
|
|
698
|
+
]
|
|
699
|
+
}
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
Codex ties network access to its sandbox, so any permission below `full` leaves the run unable to resolve DNS — `gh`, `curl`, and package installs fail inside an otherwise successful run. Show these warnings to whoever reads your output rather than discarding them; a run that succeeds while quietly doing less is the case they exist for.
|
|
703
|
+
|
|
509
704
|
---
|
|
510
705
|
|
|
511
706
|
## Backup And Restore
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# CDX Manager 0.14.0
|
|
2
|
+
|
|
3
|
+
> 0.13.0 was prepared but never published. Everything it contained ships here,
|
|
4
|
+
> so this release covers two versions' worth of work: the programmatic CLI
|
|
5
|
+
> surface for non-interactive callers, and the unification of session selection
|
|
6
|
+
> and accepted values.
|
|
7
|
+
|
|
8
|
+
## Highlights
|
|
9
|
+
|
|
10
|
+
- `cdx run --detach` launches a run without waiting and returns its `run_id` immediately; `cdx run-tail` shows a run's live output.
|
|
11
|
+
- `cdx schema --json` publishes the enums, constraints, and error codes callers should validate against, instead of forcing them to copy lists that drift.
|
|
12
|
+
- Every command that picks a session now uses one ranking, and `--priority` finally counts in all of them.
|
|
13
|
+
- `cdx set --permission workspace-write` works, matching what `cdx run --permission` always accepted.
|
|
14
|
+
- New `cdx doctor --check-provider-flags` verifies that the CLI flags cdx maps for each permission actually exist in the provider CLIs.
|
|
15
|
+
|
|
16
|
+
## Changes
|
|
17
|
+
|
|
18
|
+
### Detached runs
|
|
19
|
+
|
|
20
|
+
`cdx run --detach --json` registers the run, starts the provider detached from the invoking process, and returns straight away with `detached: true`, the assigned `run_id`, `pid`, and the artifact paths. The child is placed in its own session so it outlives the launcher, including when cdx was invoked over an SSH command that returns immediately, and it transitions its own registry entry to a terminal status so `cdx runs` and `cdx run-status` stay accurate with nobody supervising. Authentication is still resolved before the launch returns, so a login problem surfaces synchronously rather than in the background.
|
|
21
|
+
|
|
22
|
+
Callers no longer have to poll `cdx runs` and guess which row belongs to the run they just started.
|
|
23
|
+
|
|
24
|
+
### Live run output
|
|
25
|
+
|
|
26
|
+
`cdx run-tail <run_id> [--lines N] --json` returns the last lines of a run's recorded `stdout_path` plus its current status, while the run is still going or after it finished. Undecodable provider bytes are returned with replacement characters rather than failing the call. A run with no recorded output path reports `run_output_unavailable`, distinct from an unreadable one.
|
|
27
|
+
|
|
28
|
+
### Specific argument error codes
|
|
29
|
+
|
|
30
|
+
Argument and usage failures previously collapsed into `invalid_request` carrying the full human usage line, so a missing `--cwd` was indistinguishable from passing a session name and `--provider` together. They now report `missing_required_argument`, `mutually_exclusive_arguments`, `invalid_argument_value`, `argument_value_out_of_range`, or `unknown_argument`, and the error object gained `arguments` and `allowed_values` fields naming the offending arguments as data. The human-readable message and the exit codes are unchanged.
|
|
31
|
+
|
|
32
|
+
`invalid_reasoning_effort` is kept for an unsupported `--reasoning-effort`/`--power` value; supplying two conflicting values now reports `mutually_exclusive_arguments`, since the two flags are aliases of one setting.
|
|
33
|
+
|
|
34
|
+
### Schema discovery
|
|
35
|
+
|
|
36
|
+
`cdx schema --json` publishes the accepted values for `permission` (with aliases and canonical forms), `reasoning_effort`/`power`, `kind`, and `provider`, the declared mutually-exclusive argument groups, and the argument error codes. Values are read from the same definitions the parser validates against, and a test fails if the two disagree, so downstream callers can stop maintaining copies that drift.
|
|
37
|
+
|
|
38
|
+
### Prompts on standard input
|
|
39
|
+
|
|
40
|
+
`cdx run --prompt-file -` reads the prompt from standard input, so a caller relaying arbitrary text no longer has to stage and clean up a temporary file or place the text on a command line. It fails immediately with `invalid_argument_value` if standard input is a terminal.
|
|
41
|
+
|
|
42
|
+
### Completion cursor for runs
|
|
43
|
+
|
|
44
|
+
`cdx runs --since <cursor> --json` returns every run that completed after the cursor, accepting the same cursor forms as `cdx history --since`. The cursor bounds the result by time rather than row count: `--limit` is ignored when `--since` is given, and the payload says so in `warnings`. Capping a cursor query by row count would silently drop completions a polling caller had not yet seen. Runs still in flight are excluded until they complete.
|
|
45
|
+
|
|
46
|
+
### Run warnings
|
|
47
|
+
|
|
48
|
+
The run payload's `warnings` list was declared in the contract but hardcoded empty. It is now populated, on the successful path as much as the failing one. The first warning, `network_disabled_by_permission`, fires when a Codex-backed run uses a permission below `full`: Codex ties network access to its sandbox, so the run cannot resolve DNS and network-dependent tooling fails inside a run that still exits zero. The condition is read from the same permission-to-flag mapping the launch spec uses, so adding a permission cannot leave it behind.
|
|
49
|
+
|
|
50
|
+
### One session selection rule
|
|
51
|
+
|
|
52
|
+
`cdx select`, `cdx run --provider`, `cdx next`, the `cdx status` recommendation, and `cdx ready` used two independent rankings that disagreed. Each knew something the other did not: the headless one filtered by provider and honored `--priority`, the recommendation one understood credits and reset scheduling. Which session you got depended on which command you asked.
|
|
53
|
+
|
|
54
|
+
They are now one function in `src/session_ranking.py`, parameterized by what each caller needs. Candidate filters (disabled, logged out, provider, effort floor, readiness) are kept separate from ordering, because describing a filter as a sort stage is part of what made the old published policy wrong.
|
|
55
|
+
|
|
56
|
+
The merged ordering is: usability class, then `--priority`, then — for a usable session — credits, availability and reset; for a session that is not usable now, reset first, since when it comes back is what matters. Reasoning effort and session name break the remaining ties.
|
|
57
|
+
|
|
58
|
+
### The priority setting counts everywhere
|
|
59
|
+
|
|
60
|
+
`cdx set <name> --priority 90` previously affected only `cdx select` and `cdx run --provider`. Status rows now carry the configured priority and effort, so `cdx next`, `cdx status`, and `cdx ready` honor it too.
|
|
61
|
+
|
|
62
|
+
Priority ranks sessions *within* a usability class, never across one: a high-priority session with no quota left does not outrank a usable one. Priority says which usable session to prefer, not where to send work that will fail there.
|
|
63
|
+
|
|
64
|
+
The `cdx status` recommendation line is now labelled `Recommended:` rather than `Priority:`. The old label named the whole recommendation after one of its inputs, so tuning `--priority` and seeing no change read as the setting being broken when availability or resets had decided instead.
|
|
65
|
+
|
|
66
|
+
### Truthful selection reporting
|
|
67
|
+
|
|
68
|
+
`cdx select --json` built its `selection_policy` from a hardcoded string that omitted the reasoning-effort tie-break and described the readiness filter as a sort stage, and a `reason` that claimed availability decided even when priority or the alphabetical fallback did.
|
|
69
|
+
|
|
70
|
+
Both are now derived. `selection_policy` is built from the ranking itself and reports factors and filters separately; `deciding_factor` and `reason` name the factor that actually separated the winner from the runner-up for that call, or report that it was the only candidate. Do not treat `selection_policy` as a stable identifier — it changes when the ranking does, which is the point.
|
|
71
|
+
|
|
72
|
+
### Selecting on fresh or missing status
|
|
73
|
+
|
|
74
|
+
`cdx run --provider` now accepts `--refresh` to fetch status before auto-selecting. Cached status remains the default, so ordinary runs do not each pay for a provider probe.
|
|
75
|
+
|
|
76
|
+
When auto-selection picks a session with no recorded availability, the run payload carries a `session_selected_without_status` warning. That is distinct from a session known to be low: on a freshly imported or long-idle set of sessions, choosing with no data at all is the ordinary case, and it was previously invisible.
|
|
77
|
+
|
|
78
|
+
### One definition of the values cdx accepts
|
|
79
|
+
|
|
80
|
+
The reasoning-effort enum was defined in four places (two of them identical, one line apart in the same module) and the permission enum in two, with `cdx set` validating against one pair and `cdx run` against another. `config.py` now owns both, and every validator, normalizer, and `cdx schema --json` derives from them. One test asserts identity rather than equality; another fails if any module restates one of these sets.
|
|
81
|
+
|
|
82
|
+
### Permission aliases work in cdx set
|
|
83
|
+
|
|
84
|
+
`cdx run --permission workspace-write` was accepted and normalized to `default`, while `cdx set <name> --permission workspace-write` failed with `Unsupported permission`. The same applied to `read-only` and `danger-full-access`, which are the provider-native spellings a user is most likely to have in hand, and `cdx schema --json` published the aliases without saying they applied to one command only.
|
|
85
|
+
|
|
86
|
+
`cdx set` and the `perm` alias command now accept them, storing the canonical value so nothing downstream has to learn aliases exist. They were added to `set` rather than removed from `run`, since removing them would break callers passing provider-native spellings today.
|
|
87
|
+
|
|
88
|
+
### Verifying provider flag mappings
|
|
89
|
+
|
|
90
|
+
cdx maps each permission to concrete provider CLI flags, and nothing verified those mappings. GitHub issue #8 was exactly that: an `--experimental-yolo` flag mapped for ollama that the ollama CLI never had, undetected until a user hit it.
|
|
91
|
+
|
|
92
|
+
`cdx doctor --check-provider-flags` checks each configured provider's installed CLI for the flags cdx maps. A rejected flag is a `FAIL` naming the provider, the permission, and the flag. An uninstalled CLI or unreadable help is a `WARN`, never an `OK` — "could not verify" is the state that bug lived in. A provider that maps nothing, such as ollama, reports `OK` with an empty mapping, so having nothing to check is distinguishable from having failed to check.
|
|
93
|
+
|
|
94
|
+
It is opt-in because it costs a provider CLI invocation per provider, and the default report carries a `provider_permission_flags_unchecked` warning rather than omitting it, so a green doctor never implies the mappings were verified.
|
|
95
|
+
|
|
96
|
+
Antigravity and ollama permission mappings also moved out of inline branches into `LAUNCH_PERMISSION_ARGS`, so every provider's mapping is declared in one table the check can read. Ollama's entry is deliberately empty.
|
|
97
|
+
|
|
98
|
+
## Internal structure
|
|
99
|
+
|
|
100
|
+
No behavior change, listed because the source layout is different if you have a patch in flight.
|
|
101
|
+
|
|
102
|
+
`cli_commands.py` (3313 lines) became nine per-domain modules under `src/commands/`, and `session_service.py` (1690 lines) became `session_service`, `session_helpers`, `session_status`, and `session_backup`. `create_session_service` went from a 1153-line factory holding 46 closures to 56 lines of assembly, with dependencies passed explicitly rather than captured.
|
|
103
|
+
|
|
104
|
+
Both original modules remain the import location for everything they exposed, so no caller changed. The split followed a coupling measurement in each case, and stopped where the measurement stopped: the session service's runtime and auth groups have no helpers of their own, so they were left in place rather than turned into files that would only re-import from elsewhere. That reasoning is recorded in `session_service`'s docstring, with a test that fails if someone finishes the job by instinct.
|
|
105
|
+
|
|
106
|
+
## Behavior changes
|
|
107
|
+
|
|
108
|
+
- **`--priority` now outranks availability.** It previously sat below availability in the headless sort, so it only broke exact ties and was effectively inert. A session with lower availability but higher priority now wins within the same usability class. This is the change that makes the setting mean anything.
|
|
109
|
+
- **Ties on session name now sort ascending everywhere.** The recommendation ranking sorted names descending as a side effect of reversing its whole sort tuple, disagreeing with the headless ranking. The ascending order is kept.
|
|
110
|
+
- **Logged-out sessions are never selection candidates.** `cdx select` without `--require-ready` could previously return one. `--require-ready` remains stricter still: it requires a confirmed `authenticated` state, so a session whose auth has never been checked is not offered to `cdx run --provider`.
|
|
111
|
+
- `cdx status`'s recommendation line is labelled `Recommended:` instead of `Priority:`.
|
|
112
|
+
- `cdx select --json`'s `selection_policy` is now a structured object rather than an underscore-joined string.
|
|
113
|
+
|
|
114
|
+
## Fixes
|
|
115
|
+
|
|
116
|
+
- `cdx --version` reported a stale release. `src/cli.py` restated the version as a fourth hardcoded copy alongside `VERSION`, `package.json`, and `pyproject.toml`, and nothing kept the four in step — it had been left at 0.12.4. The version is now resolved from the `VERSION` file in a checkout and from installed package metadata otherwise, and a test fails if any of the four (plus the README badge) disagree.
|
|
117
|
+
- The release validator was left scraping a `VERSION = "..."` literal out of `src/cli.py`, which the fix above had removed. It resolved an empty string and rejected every release with "Missing release version in: src/cli.py" — inside the publish workflow, after the tag was already public. It now reads the resolved version, and a test fails if any declaration site stops yielding one.
|
|
118
|
+
- Two tests still asserted the `--experimental-yolo` flag removed from ollama launches in 0.12.4 (GitHub issue #8); the launch behavior was already correct, the stale expectations are now aligned.
|
|
119
|
+
- `format_json_error` honors an error's declared code instead of always re-deriving one from the message prefix, so structured argument errors keep their code when they reach the CLI entry point.
|
|
120
|
+
- The detached-run test asserted the POSIX `start_new_session` unconditionally, so the Windows CI job failed on a code path that was correct. The assertion is now platform-aware, and Windows CI exercises the `creationflags` branch for the first time.
|
|
121
|
+
|
|
122
|
+
## Review fixes
|
|
123
|
+
|
|
124
|
+
Found by a review pass over the programmatic CLI work, before release:
|
|
125
|
+
|
|
126
|
+
- The detached child's `CDX_RUN_ID` is consumed rather than read, so it is no longer inherited by the provider process. Left set, an agent making its own nested `cdx run` would have claimed the outer run's id, deleting its registry record and truncating its stdout, stderr, and transcript files.
|
|
127
|
+
- The detached child receives the resolved absolute `--cwd`; a relative path would have resolved against the child's own working directory.
|
|
128
|
+
- `--detach` now detaches correctly on Windows (`DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP`), and always re-invokes through `sys.executable -m` rather than `sys.argv[0]`, which is not reliably executable there.
|
|
129
|
+
- `network_disabled_by_permission` now fires when no `--permission` is given at all — the most common invocation, where `codex exec` still applies its own sandboxed default. It previously exempted exactly the case it was written for.
|
|
130
|
+
- `cdx run-tail` on a run that has not written its first byte returns `lines: []` instead of failing, so the launch-then-tail flow does not report a fatal error during that window. A missing output file on a *finished* run is still an error.
|
|
131
|
+
- `run-tail` drops a partial leading line when the read window opens mid-line, rather than returning a fragment as if it were a whole line.
|
|
132
|
+
- `cdx schema --json` publishes every error code the run commands emit, grouped by area, plus the warning codes; and `--reasoning-effort`/`--power` moved from `mutually_exclusive` to a new `must_match` group, since cdx accepts both when they agree.
|
|
133
|
+
- An empty `--power ""` blames `--power` instead of `--reasoning-effort`.
|
|
134
|
+
- `format_json_error` emits the same error field set as the run payload, so callers do not need two shapes.
|
|
135
|
+
- The prompt a detached launch stages for its child is deleted once the child reads it, instead of leaving a permanent cleartext copy in the session log directory.
|
|
136
|
+
|
|
137
|
+
## Validation
|
|
138
|
+
|
|
139
|
+
- `npm run lint`
|
|
140
|
+
- `npm test` — 565 tests.
|
|
141
|
+
- CI green on ubuntu-latest and windows-latest.
|
|
142
|
+
- End-to-end: detached launch returning `run_id`, `run-tail` against the in-flight run after the launcher exited, terminal status reached without a supervisor, and `runs --since` reporting the completion.
|
|
143
|
+
- End-to-end: with one session at 80% availability and priority 0 and another at 40% and priority 90, `cdx select`, `cdx next`, and `cdx status` all name the second, and `cdx select` reports `decided on priority`.
|
|
144
|
+
- The issue #8 condition reproduced against the new provider flag check: mapping `--experimental-yolo` for codex fails the check by name. All four provider CLIs verified against their real binaries.
|
|
145
|
+
- `logics-manager lint --require-status`
|
|
146
|
+
- `logics-manager audit --group-by-doc` — 0 blocking, 0 warnings.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# CDX Manager 0.15.0
|
|
2
|
+
|
|
3
|
+
> Quota awareness stops being advice. A headless run that hits a rate limit now
|
|
4
|
+
> continues on an account that still has quota, and `cdx resume` reopens the
|
|
5
|
+
> conversation cdx named rather than whatever ran here last.
|
|
6
|
+
|
|
7
|
+
## Read this first
|
|
8
|
+
|
|
9
|
+
Two defaults change for existing sessions.
|
|
10
|
+
|
|
11
|
+
- **`cdx resume <name>` changes meaning.** It used to run `codex resume --last`
|
|
12
|
+
or `claude --continue`, both of which mean "the most recent conversation in
|
|
13
|
+
this directory". It now names the provider's own conversation id, so it
|
|
14
|
+
reopens the conversation *that session* last had, regardless of your working
|
|
15
|
+
directory or of what ran since. Sessions with no recorded id keep the old
|
|
16
|
+
behaviour; `cdx can-resume --json` tells you which applies.
|
|
17
|
+
- **Every Claude launch now carries `--session-id`.** cdx mints the id and
|
|
18
|
+
passes it, which is what makes the above possible.
|
|
19
|
+
|
|
20
|
+
## Highlights
|
|
21
|
+
|
|
22
|
+
- `cdx run --failover` continues a task on the next eligible account when the
|
|
23
|
+
one it started on runs out, keeping one `run_id` for the whole task.
|
|
24
|
+
- `cdx set --budget` caps what a headless run may spend; `--fallback-model`
|
|
25
|
+
lets it continue on another model when the first is unavailable.
|
|
26
|
+
- `cdx set --extra-args` passes provider flags cdx does not model straight
|
|
27
|
+
through, so a flag your provider shipped last week no longer forces you out
|
|
28
|
+
of cdx.
|
|
29
|
+
- Resume and handoff are anchored on a provider-native conversation id instead
|
|
30
|
+
of on recency.
|
|
31
|
+
- Opt-in delegation of `cdx run --detach` to Claude Code's own background
|
|
32
|
+
agents, behind `CDX_EXPERIMENTAL_NATIVE_BG=1`.
|
|
33
|
+
|
|
34
|
+
## Changes
|
|
35
|
+
|
|
36
|
+
### Failover across accounts
|
|
37
|
+
|
|
38
|
+
`cdx run --failover` detects that a run stopped because its account is spent,
|
|
39
|
+
re-ranks the remaining sessions through the same ranking `cdx next` uses,
|
|
40
|
+
carries the task across, and continues. The whole task keeps one `run_id`;
|
|
41
|
+
`cdx run-report` lists every session it occupied, in order, with the reason for
|
|
42
|
+
each transition, and `cdx runs` shows it once.
|
|
43
|
+
|
|
44
|
+
Migration requires the account's own refreshed rate-limit status to confirm it
|
|
45
|
+
is spent, because the two ways of being wrong are not symmetric: missing a rate
|
|
46
|
+
limit costs nothing new, while inventing one would move a healthy run off a
|
|
47
|
+
working account and spend a second account's quota redoing it.
|
|
48
|
+
|
|
49
|
+
Two routes trigger it. `provider_reported_exhaustion` when the provider says so
|
|
50
|
+
in words cdx recognises, and `account_status_exhausted` when the quota is gone
|
|
51
|
+
and the run failed, whatever the wording. The second exists because the wording
|
|
52
|
+
is not one thing — an enterprise workspace out of credits, a personal plan
|
|
53
|
+
hitting its 5-hour window, and Claude's own phrasing are different sentences,
|
|
54
|
+
and only the first has been observed.
|
|
55
|
+
|
|
56
|
+
Exhausting every eligible account reports `failover_exhausted`, and hitting the
|
|
57
|
+
transition bound reports `failover_limit_reached`; both are distinct from the
|
|
58
|
+
task itself failing. `--failover` and `--detach` are mutually exclusive:
|
|
59
|
+
failover has to watch the run to react.
|
|
60
|
+
|
|
61
|
+
### Spend ceiling and model fallback
|
|
62
|
+
|
|
63
|
+
`cdx set <name> --budget 5` and `--fallback-model sonnet,haiku` persist like
|
|
64
|
+
every other launch setting. Both are Claude Code flags the provider accepts
|
|
65
|
+
only alongside `--print`, so they apply to `cdx run` and to nothing else;
|
|
66
|
+
`cdx configs` says so rather than letting a launch fail. `--fallback-model`
|
|
67
|
+
takes a comma-separated list, tried in order.
|
|
68
|
+
|
|
69
|
+
### Resume by identity
|
|
70
|
+
|
|
71
|
+
Sessions record the provider's own conversation id and where it came from.
|
|
72
|
+
Claude accepts a caller-supplied id, so cdx mints it at launch — provenance
|
|
73
|
+
`imposed`. Codex mints its own, so cdx reads it back from the rollout after a
|
|
74
|
+
run — provenance `observed`, and legitimately absent until the session has run
|
|
75
|
+
once. `cdx can-resume --json` reports the strategy, the id, and its provenance,
|
|
76
|
+
so an automated caller can tell a named resume from a best-effort one.
|
|
77
|
+
|
|
78
|
+
### Passthrough for unmapped provider flags
|
|
79
|
+
|
|
80
|
+
`cdx set <name> --extra-args "--add-dir ../shared"` reaches the provider
|
|
81
|
+
command line unmodified, after the arguments cdx maps itself, so a passthrough
|
|
82
|
+
value overrides the setting it duplicates. These arguments are explicitly
|
|
83
|
+
unvalidated: `cdx schema --json` lists them under `unvalidated` rather than
|
|
84
|
+
describing them, and `cdx doctor --check-provider-flags` ignores them. They are
|
|
85
|
+
split into literal argv entries and never passed through a shell.
|
|
86
|
+
|
|
87
|
+
### Background delegation (opt-in)
|
|
88
|
+
|
|
89
|
+
With `CDX_EXPERIMENTAL_NATIVE_BG=1`, `cdx run --detach` hands the run to Claude
|
|
90
|
+
Code's background agents. The run keeps its cdx `run_id`, closes out with the
|
|
91
|
+
token usage and final answer read from the provider's own session transcript,
|
|
92
|
+
and the parked session is stopped once its task is done. Off by default for
|
|
93
|
+
this release: it works, but it has been exercised far less than the in-house
|
|
94
|
+
launcher every run takes today. Codex keeps the in-house path while its
|
|
95
|
+
`cloud` and `exec-server` surfaces are marked experimental.
|
|
96
|
+
|
|
97
|
+
### Onboarding and docs
|
|
98
|
+
|
|
99
|
+
`cdx` with no sessions registered now points at `cdx add` instead of listing
|
|
100
|
+
ten commands that all return nothing. The README leads with the quota routing
|
|
101
|
+
rather than with session management, and its screenshots are generated from a
|
|
102
|
+
synthetic home (`scripts/seed_demo_home.py`) so they carry no account names.
|
|
103
|
+
|
|
104
|
+
### Fixes
|
|
105
|
+
|
|
106
|
+
- A status merge adopted the candidate's timestamp even when it was older,
|
|
107
|
+
dating a record by its stalest contributor. Since `updated_at` drives the
|
|
108
|
+
freshness check, a just-resolved status read as expired and re-probed the
|
|
109
|
+
provider on every call.
|
|
110
|
+
|
|
111
|
+
## Validation
|
|
112
|
+
|
|
113
|
+
- `npm run lint`
|
|
114
|
+
- `npm test` — 629 tests.
|
|
115
|
+
- CI green on ubuntu-latest and windows-latest.
|
|
116
|
+
- Also run on a physical Windows machine: 623 passed, 5 skipped. One failure,
|
|
117
|
+
`test_concurrent_starts_do_not_lose_records`, reproduces identically on the
|
|
118
|
+
`v0.14.0` tag on that machine and passes in CI — a pre-existing contention
|
|
119
|
+
flake in the registry lock, not a regression.
|
|
120
|
+
- End-to-end across eleven live sessions and both providers: fourteen real
|
|
121
|
+
runs, usage extracted on every one, six Codex accounts each recording a
|
|
122
|
+
distinct conversation id and five Claude accounts recording theirs.
|
|
123
|
+
- End-to-end failover on a genuinely exhausted account: `work6` migrated to
|
|
124
|
+
`work1` and the task succeeded, recorded as one run.
|
|
125
|
+
- End-to-end resume by identity: a minted id accepted as `--session-id`, then
|
|
126
|
+
`--resume` on that id recalling the previous turn's answer.
|
|
127
|
+
- `--extra-args` and the budget/fallback settings exercised against real
|
|
128
|
+
provider CLIs, not only in tests.
|
|
129
|
+
- `logics-manager lint --require-status`
|
|
130
|
+
- `logics-manager audit --group-by-doc` — 0 blocking, 0 warnings.
|
|
131
|
+
|
|
132
|
+
## Known gaps
|
|
133
|
+
|
|
134
|
+
- The rate-limit wording of a personal-plan Codex account and of Claude has not
|
|
135
|
+
been observed; only an enterprise workspace out of credits has. The
|
|
136
|
+
`account_status_exhausted` route covers the unobserved cases, so this costs
|
|
137
|
+
the precise reason rather than the failover itself.
|
|
138
|
+
- Background delegation has been exercised on one account with one prompt
|
|
139
|
+
shape, which is why it is opt-in.
|
|
@@ -160,6 +160,18 @@
|
|
|
160
160
|
"v0.12.2": {
|
|
161
161
|
"github_tarball_sha256": "5214f9f85f6bdc2c53bded938c91e28411de3c573bbcff81ebecb20dea6d99c2",
|
|
162
162
|
"github_zip_sha256": "8f447cdea9e921f7428c1c72db5a19f40f447a877bb2bc8dc1c8bd5e34daf070"
|
|
163
|
+
},
|
|
164
|
+
"v0.12.3": {
|
|
165
|
+
"github_tarball_sha256": "b41cf8a99c36d3f03a3556db604316dcfdf14e2eb9090c86f25190b8a0db866a",
|
|
166
|
+
"github_zip_sha256": "6a8e384a88e736607dbc0b6e9953fb61192e77ded259fac2de35b03ad2fa71bd"
|
|
167
|
+
},
|
|
168
|
+
"v0.12.4": {
|
|
169
|
+
"github_tarball_sha256": "877e54c9f435acb41947c43c8618c84d88e0dc0c7cb77c5dd5dc56e13ee80b7f",
|
|
170
|
+
"github_zip_sha256": "7db7f28ab8b295446ba0a38e6e3cbbcc8855dd7333ebc9877917d14b4caaf903"
|
|
171
|
+
},
|
|
172
|
+
"v0.14.0": {
|
|
173
|
+
"github_tarball_sha256": "5da107556442d3566a7b0787708ae700e38afdf99e74209fffd2484ce3a33d94",
|
|
174
|
+
"github_zip_sha256": "bd4e070582bfc641e6176a8b8be8d7afd1ce9d76fc59c1dbeb238bae548bc699"
|
|
163
175
|
}
|
|
164
176
|
}
|
|
165
177
|
}
|