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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,9 @@ powershell -ExecutionPolicy Bypass -File install.ps1
```

Each fetches the release artifact for this platform, checks it against the
release's own `SHA256SUMS`, and places it at a predictable path: `~/.local/bin`
on Linux and macOS, `%LOCALAPPDATA%\Programs` on Windows. Neither needs
release's own `SHA256SUMS`, and places it at a predictable path:
`~/.local/bin/codex-setup-system` on Linux and macOS,
`%LOCALAPPDATA%\Programs\codex-setup-system\codex-setup-system.exe` on Windows. Neither needs
privilege and neither registers anything anywhere.

Somewhere else instead:
Expand Down
11 changes: 6 additions & 5 deletions SUPPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,6 @@ Configuration home as the product documents it: `~/.codex`.
| `prompts` | `command` | [source](https://learn.chatgpt.com/docs/custom-prompts) |
| `agents` | `agent` | [source](https://github.com/openai/codex/blob/rust-v0.151.0/codex-rs/agent-roles/src/discovery.rs) -- routing measured by running the 0.151.0 binary against a temporary CODEX_HOME |

A path routing no component kind is owned so a setup can carry it;
nothing compiles a component to it.

### A second target: `target_scope: user_root`

Expand All @@ -188,9 +186,12 @@ by a restore.

### A second target: `target_scope: project`

Rooted at `project root`, which is not the configuration home
above. A consumer reaches it by naming the scope on the request, and
every path below is relative to that root.
This scope's target is the workspace root rather than the
configuration home above; the scope record names its anchor
`project root`. A consumer reaches it by naming the scope on
the request, and every path below is relative to the workspace
root -- where the product owns a directory there, that directory
is part of the path.

| Path | Component kinds routed here | Decided by |
| --- | --- | --- |
Expand Down
6 changes: 3 additions & 3 deletions crates/codex-setup-system/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,10 @@ pub const CODEX: Harness = Harness {
// who else reads it is a question about behaviour rather than routing.
// The `user_root` skill question has the same shape.
],
// One scope. Codex's project surfaces live under `.codex/` in a workspace, which is a
// different root rather than a second scope of this target.
// Two scopes. Codex's project surfaces live under the workspace root --
// `AGENTS.md` at it, `.codex/hooks.json` keeping its product-owned parent --
// and the user-level `.agents` root is a third home entirely.
//
// Empty rather than absent: a harness that owns one target says so.
// The one root in this estate that belongs to a convention rather than to a
// product. `learn.chatgpt.com/docs/build-skills` names `$HOME/.agents/skills`
// as the user-level skills directory -- a *sibling* of `~/.codex`, not a
Expand Down
2 changes: 1 addition & 1 deletion crates/harness-runtime/src/catalog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub struct CatalogComponentRef {
/// per-harness: `minimal` means the same thing to someone moving from codex to
/// pi as it did before they moved.
///
/// A harness may carry more -- cursor and antigravity each ship a builder
/// A harness may carry more -- each of the seven also ships an `nddev-builder`
/// toolkit -- but never fewer.
pub const UNIVERSAL_SETUPS: &[&str] = &["baseline", "full-auto", "minimal"];

Expand Down
4 changes: 2 additions & 2 deletions crates/harness-runtime/src/facts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ pub struct Harness {
/// and one that can execute code the chosen setup never carried.
///
/// A fact rather than a conclusion, carrying how it was established, because
/// the five that are complete are not equally well established: three were
/// measured by asking the product what it resolved, one by making it write,
/// the five that are complete are not equally well established: two were
/// measured by asking the product what it resolved, two by making it write,
/// and one rests on a vendor page because no credential-free command of that
/// product writes its home.
pub launch_binding: LaunchBinding,
Expand Down
5 changes: 3 additions & 2 deletions crates/harness-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,9 @@ fn print_help(harness: &Harness) {
println!("something to return to. The pool rolls, so a long series of changes");
println!("eventually evicts the oldest: `hold` keeps one until `release` lets");
println!("it go, which is how a baseline survives more captures than the pool.");
println!("Over the wire, install and replace arrive as a bundle and refuse --");
println!("this build reads setups from its own catalog.");
println!("Over the wire a bundle arrives with install or replace, and this");
println!("build applies it; this human surface refuses bundles and reads");
println!("setups from its own catalog.");
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion crates/harness-runtime/src/software.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ pub(crate) fn launch(
// from one field here. Guessing produced a refusal that told cursor
// callers *"this build installs no software"* -- false, it installs
// and removes it, and the actual reason is that the product follows
// its variable for one of the eight surfaces this provider owns.
// its variable for one of the seven surfaces this provider owns.
format!(
"{} does not declare launch: {}",
harness.provider_id,
Expand Down
6 changes: 5 additions & 1 deletion crates/harness-runtime/src/surfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,11 @@ fn never_touch_is_disclaimed(harness: &Harness, baseline: &Value, found: &mut Ve
/// other direction: a namespace declared, owned, routing nothing, and written
/// to by nobody.
///
/// Three of them exist: claude's `rules`, opencode's `tui.json`, pi's `themes`.
/// Seventeen of them exist -- claude's `rules`, `workflows`, `output-styles`,
/// `routines` and `themes`; grok's `sandbox.toml`, `workflows`, `rules`,
/// `commands`, `personas` and `roles`; pi's `APPEND_SYSTEM.md`, `SYSTEM.md` and
/// `themes`; antigravity's `antigravity-cli/keybindings.json` and
/// `antigravity-cli/plugins`; opencode's `tui.json`.
/// Each is defensible -- claude's row explains that `instruction` already
/// routes to `CLAUDE.md` and the namespace is owned so a setup *could* carry a
/// rule -- and the point is not to remove them. It is that the answer should be
Expand Down
6 changes: 3 additions & 3 deletions references/codex-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@
"file": "config.toml",
"grammar": "toml",
"accepts_comments": true,
"note": "TOML, so `#` comments are part of the grammar. No JSON schema is possible for it and none is expected; the setups are checked by parsing instead.",
"note": "TOML, so `#` comments are part of the grammar. A JSON schema cannot be embedded in it, and none was expected when this was measured; the setups are checked by parsing instead.\n\n**Corrected 2026-09-29: the vendor does publish one.** A `config-schema.json` asset ships with each release and is recorded under `configuration_schema`; a TOML file carries no `$schema` line, which is what this sentence meant by 'possible', and the schema still answers whether a written key is a key the product has.",
"measured_at": "2026-08-28"
},
"projection_basis": {}
Expand Down Expand Up @@ -281,7 +281,7 @@
"version": "0.158.0",
"verified_at": "2026-09-28T14:26:56+00:00"
},
"setup_catalogue_digest": "sha256:38ea677a1b5ebbb65bd1347ac5e3ae22778eee45a2a3f8361f943c08500319a4",
"setup_catalogue_digest": "sha256:a366a07c80e41fd1980129989d0631a0028a95003f201410f73f8ee134d03c82",
"previous_software_artifacts": {
"command": "codex",
"shape": "gzip-tar",
Expand Down Expand Up @@ -330,7 +330,7 @@
"measured_at": "2026-09-27",
"measured_against": "0.157.1",
"evidence": "ran",
"source": "codex features list + codex doctor on the installed 0.157.1 build (the pinned version), 2026-09-27; registry source https://github.com/openai/codex/blob/rust-v0.157.1/codex-rs/features/src/lib.rs",
"source": "codex features list + codex doctor on the installed 0.157.1 build (the pin at that date; 0.158.0 now), 2026-09-27; registry source https://github.com/openai/codex/blob/rust-v0.157.1/codex-rs/features/src/lib.rs",
"registry_size": 150,
"stable": 47,
"stable_and_off_by_default": [
Expand Down
2 changes: 1 addition & 1 deletion scripts/evidence.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ def remove_the_program(
# Capture what the *same exposed command* says before removal. Not every
# vendor puts its release into `--version`: Pi's two Windows standalone
# builds both answer `0.0.0`, while their archive digests and provider
# manifests correctly distinguish 0.84.3 from 0.84.4. Requiring the
# manifests correctly distinguish 0.85.1 from 0.87.1. Requiring the
# expected version here tests the vendor's string, not whether removing
# an inactive tree moved our command.
launch_before = run_text(
Expand Down
10 changes: 6 additions & 4 deletions setups/full-auto/home/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ web_search = "live"
# Every capability this build ships as `Stage::Stable` and leaves off, minus
# one deliberate exception. Measured rather than chosen: the 0.157.1 feature
# registry carries 150 specs, 47 of them stable, and exactly four of those are
# `default_enabled: false` (`codex features list` on the pinned build,
# 2026-09-27). Three are enabled below; the fourth, `secret_auth_storage`, is
# `default_enabled: false` (`codex features list` on the 0.157.1 build,
# 2026-09-27; the pin has since moved to 0.158.0). Three are enabled below; the
# fourth, `secret_auth_storage`, is
# not: it moves CLI auth into an encrypted local-secrets backend, is
# `default_enabled` on Windows only by design (the 2560-byte Credential Manager
# blob limit does not exist here), and flipping a credential store is outside
Expand All @@ -31,8 +32,9 @@ web_search = "live"
# which set nothing at all on the 0.151.0 build, where `ToolsToml` had three
# members, no `view_image`, and serde carried no `deny_unknown_fields`, so the
# key parsed, was ignored, and left the file claiming a capability it never
# turned on. The schema has since changed twice: `ToolsToml` at this pin is
# `{ web_search, view_image }` *with* `deny_unknown_fields`, so the old line
# turned on. The schema has since changed twice: `ToolsToml` at the 0.157.1
# measurement is `{ web_search, view_image }` *with* `deny_unknown_fields`, so
# the old line
# now parses and sets a real key -- and would still change nothing, because
# `view_image` is `default_enabled: true`.
#
Expand Down
33 changes: 18 additions & 15 deletions setups/nddev-builder/home/agents/nddev-builder.toml
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,9 @@ Never change the running agent's active configuration in place.
| comments | **parse** |
| home moved by | `CODEX_HOME` |

TOML, so `#` comments are part of the grammar. No JSON schema is possible for it and none is expected; the setups are checked by parsing instead.
TOML, so `#` comments are part of the grammar. A JSON schema cannot be embedded in it, and none was expected when this was measured; the setups are checked by parsing instead.

**Corrected 2026-09-29: the vendor does publish one.** A `config-schema.json` asset ships with each release and is recorded under `configuration_schema`; a TOML file carries no `$schema` line, which is what this sentence meant by 'possible', and the schema still answers whether a written key is a key the product has.

## The same question on the other harnesses

Expand All @@ -452,8 +454,7 @@ TOML, so `#` comments are part of the grammar. No JSON schema is possible for it

**A comment is not a stylistic choice.** In a strict-JSON file a `//` is
a parse error, and the product does not start rather than starting
without your setting. Two of the seven take comments; the rest do not,
and one of those takes them at two spellings of the same file.
without your setting. Three of the seven take comments; the rest do not, and one of those takes them at two spellings of the same file.

## Before you write one

Expand All @@ -468,7 +469,7 @@ and one of those takes them at two spellings of the same file.
- **A value here may not be the effective one.** Where an administrator
layer exists it clamps everything below it, so a setup can install,
verify and restore cleanly on a managed machine and change nothing.
the `nddev-surfaces` prompt, and `codex-setup-system provider-info`, records which layers this product has and
The `nddev-surfaces` prompt and `codex-setup-system provider-info` record which layers this product has and
what was searched for the ones it does not.


Expand Down Expand Up @@ -503,10 +504,10 @@ This row stays `page` because **a path built by joining a directory to a name at
| `pi` | `AGENTS.md` | file |

**They are not interchangeable, and the difference is not only the
name.** One of the seven takes a *directory* of rules rather than a
name.** Two of the seven take a *directory* of rules rather than a
single document, so a file moved between the two is not a rename.

**Some products read a neighbour's.** the `nddev-surfaces` prompt, and `codex-setup-system provider-info`, records
**Some products read a neighbour's.** The `nddev-surfaces` prompt and `codex-setup-system provider-info` record
every such cross-read this estate has measured, on the declined rows:
a file written for one product can change what a second one sees, and
removing a setup can change what a third one sees. That is a property
Expand Down Expand Up @@ -550,15 +551,16 @@ is preserved, and re-applying identical bytes is a no-op.
as a mid-apply surprise.


# The second target this harness owns
# The scoped targets this harness owns

## `target_scope: user_root`, rooted at `~/.agents`

**`~/.agents` is not this product's configuration home.** It is a
different target, reached by a consumer naming the scope on the
request, and every path below is relative to that root rather than
to the home -- writing the root into the path again would nest it
twice, which is a mistake this estate has made and shipped.
request, and every path below is relative to that root rather
than to the home -- writing the root into the path again would
nest it twice, which is a mistake this estate has made and
shipped.

| path | routes | decided by | exercised by |
|---|---|---|---|
Expand Down Expand Up @@ -594,11 +596,12 @@ into a slot here and never reverted out of one.

## `target_scope: project`, rooted at `project root`

**`project root` is not this product's configuration home.** It is a
different target, reached by a consumer naming the scope on the
request, and every path below is relative to that root rather than
to the home -- writing the root into the path again would nest it
twice, which is a mistake this estate has made and shipped.
**This scope's target is the workspace root** (the record names
its anchor `project root`), not this product's configuration home.
It is a different target, reached by a consumer naming the
scope on the request, and every path below is relative to the
workspace root -- a product-owned directory stays part of the
path.

| path | routes | decided by | exercised by |
|---|---|---|---|
Expand Down
10 changes: 6 additions & 4 deletions setups/nddev-builder/home/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ web_search = "live"
# Every capability this build ships as `Stage::Stable` and leaves off, minus
# one deliberate exception. Measured rather than chosen: the 0.157.1 feature
# registry carries 150 specs, 47 of them stable, and exactly four of those are
# `default_enabled: false` (`codex features list` on the pinned build,
# 2026-09-27). Three are enabled below; the fourth, `secret_auth_storage`, is
# `default_enabled: false` (`codex features list` on the 0.157.1 build,
# 2026-09-27; the pin has since moved to 0.158.0). Three are enabled below; the
# fourth, `secret_auth_storage`, is
# not: it moves CLI auth into an encrypted local-secrets backend, is
# `default_enabled` on Windows only by design (the 2560-byte Credential Manager
# blob limit does not exist here), and flipping a credential store is outside
Expand All @@ -31,8 +32,9 @@ web_search = "live"
# which set nothing at all on the 0.151.0 build, where `ToolsToml` had three
# members, no `view_image`, and serde carried no `deny_unknown_fields`, so the
# key parsed, was ignored, and left the file claiming a capability it never
# turned on. The schema has since changed twice: `ToolsToml` at this pin is
# `{ web_search, view_image }` *with* `deny_unknown_fields`, so the old line
# turned on. The schema has since changed twice: `ToolsToml` at the 0.157.1
# measurement is `{ web_search, view_image }` *with* `deny_unknown_fields`, so
# the old line
# now parses and sets a real key -- and would still change nothing, because
# `view_image` is `default_enabled: true`.
#
Expand Down
Loading