@maestrofrontier/frontier 1.4.4 → 1.4.5

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 CHANGED
@@ -17,15 +17,20 @@
17
17
  <a href="#the-frontier-engine"><img src="https://img.shields.io/badge/Frontier-fusion%20engine-f59e0b" alt="Frontier fusion engine"></a>
18
18
  <img src="https://img.shields.io/badge/agents-Claude%20Code%20%7C%20Gemini%20%7C%20Codex%20%7C%20Cursor-5b82d6" alt="Claude Code | Gemini | Codex | Cursor">
19
19
  <img src="https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey" alt="macOS | Linux | Windows">
20
- <img src="https://img.shields.io/badge/install-2%20lines-blueviolet" alt="2-line plugin install">
20
+ <img src="https://img.shields.io/badge/install-plugins%20%2B%20portable-blueviolet" alt="Native plugins and portable installs">
21
21
  <a href="#contributing"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen" alt="PRs welcome"></a>
22
22
  </p>
23
23
 
24
24
  <p align="center">
25
- <sub>13 fixture tasks &middot; 123 valid A/B runs &middot; 11 voids excluded &amp; re-run &middot; 6 hooks, all tested &middot; ~8 KB always-on kernel &middot; 2-line plugin install</sub>
25
+ <sub>13 fixture tasks &middot; 123 valid A/B runs &middot; 11 voids excluded &amp; re-run &middot; 6 hooks, all tested &middot; ~8 KB always-on kernel &middot; plugin + portable installs</sub>
26
26
  </p>
27
27
 
28
- > **Install — run the one line for your tool, inside that tool.** Each installs only that tool's setup (the portable `AGENTS.md` doctrine, that tool's adapter, `docs/orchestration.md`, the Frontier engine, and that tool's `/frontier` command) — **append-only; it never overwrites or deletes your files.**
28
+ > **Install — run the command block for your tool, inside that tool.**
29
+ > Claude Code and Codex use native plugins. Cursor, Gemini, Cline,
30
+ > Windsurf, and other CLIs use the portable installer, which copies
31
+ > Maestro's runtime-agnostic files into the current project/workspace by
32
+ > default. Global/user installs are optional when you intentionally want
33
+ > cross-project behavior.
29
34
 
30
35
  **Claude Code / Desktop** — native plugin (enforcement hooks, `/maestro:*` commands, skills, status line, Frontier auto-run):
31
36
 
@@ -34,22 +39,75 @@
34
39
  /plugin install maestro@maestro
35
40
  ```
36
41
 
37
- **Every other CLI / Desktop app** — run its line in that tool's terminal, or just ask its agent to run it. It auto-targets that tool and installs nothing for the others:
42
+ **Codex CLI / Desktop** — native Codex plugin via the Maestro repo
43
+ marketplace (skills, trusted hooks, and Frontier auto-run after you review
44
+ and trust the hooks):
45
+
46
+ ```text
47
+ codex plugin marketplace add mbanderas/maestro
48
+ codex plugin add maestro@maestro
49
+ ```
50
+
51
+ Start a new Codex thread after installing or changing plugin trust so the
52
+ bundled skills and hooks reload.
53
+
54
+ **Portable installs for other CLI / Desktop apps** — run the matching line
55
+ in that tool's terminal, or ask its agent to run it. These integrations are
56
+ prompt/skill/workflow shortcuts around the portable CLI unless the tool has
57
+ native hook support.
38
58
 
39
59
  | Tool | Install (run inside the tool) |
40
60
  |------|-------------------------------|
41
- | Codex (CLI / Desktop) | `npx github:mbanderas/maestro install --target codex` |
42
61
  | Cursor | `npx github:mbanderas/maestro install --target cursor` |
43
62
  | Gemini CLI | `npx github:mbanderas/maestro install --target gemini` |
44
63
  | Cline | `npx github:mbanderas/maestro install --target cline` |
45
64
  | Windsurf / Devin | `npx github:mbanderas/maestro install --target windsurf` |
46
65
  | Not sure / auto-detect | `npx github:mbanderas/maestro install --target auto` |
47
66
 
48
- Per tool it lays down `AGENTS.md` + that tool's adapter (`CLAUDE.md` / `GEMINI.md` / `.cursorrules`; Codex, Cline, and Windsurf read `AGENTS.md` directly), `docs/orchestration.md`, the zero-dependency Frontier engine, and that tool's `/frontier` command. Confirm with `maestro frontier status` (or `node bin/maestro.cjs frontier status` if `maestro` is not on PATH). Once published, swap `github:mbanderas/maestro` for `@maestrofrontier/frontier`.
67
+ Portable installs lay down `AGENTS.md` plus that tool's adapter or
68
+ integration file, `docs/orchestration.md`, the zero-dependency Frontier
69
+ engine, and the relevant command/skill files. Codex does not need that copy
70
+ path for normal use: the repo is its marketplace
71
+ (`.agents/plugins/marketplace.json`) and plugin
72
+ (`.codex-plugin/plugin.json`), bundling the Codex skills, hooks, Frontier
73
+ engine, settings CLI, commands, and `docs/codex.md`. The older
74
+ `maestro install --target codex` path remains a manual fallback when you
75
+ intentionally want project files instead of the plugin. Once published, swap
76
+ `github:mbanderas/maestro` for `@maestrofrontier/frontier` for portable npm
77
+ installs.
78
+
79
+ > **Want the bare `maestro` command on your `PATH`?** Native plugins can run
80
+ > the bundled engine from their plugin cache, and portable installs can run
81
+ > `node bin/maestro.cjs frontier ...` from the installed project root. Install
82
+ > globally only if you want to type `maestro` from any shell:
83
+ > `npm install -g github:mbanderas/maestro` (swap for
84
+ > `@maestrofrontier/frontier` once published), then fully restart the tool so
85
+ > it picks up the new `PATH`.
86
+
87
+ Frontier stays **off** until you arm it, then normal prompts auto-route until
88
+ disabled in runtimes with trusted hooks.
89
+
90
+ - Claude Code: `/maestro:frontier fusion opus-gpt` (or
91
+ `/maestro:frontier off`).
92
+ - Codex: after installing the plugin and trusting hooks, ask the bundled
93
+ `maestro-frontier` skill to arm the project scope, for example "Use
94
+ Maestro Frontier with ChatGPT duo", "Show Maestro Frontier status", or
95
+ "Turn Maestro Frontier off." The skill runs the plugin-bundled engine; no
96
+ `npx` or global `maestro` binary is required.
97
+ - Shell/advanced: from a checkout or global install, the equivalent CLI form
98
+ is:
49
99
 
50
- > **Want the bare `maestro` command (and the `/frontier` command it powers) on your `PATH`?** The `npx … install` above copies files into the project but does **not** register a global `maestro` binary — so the dropped `/frontier` command and the Codex skills, which call a bare `maestro`, will report `maestro: not recognized` until you add it. Install it once globally — `npm install -g github:mbanderas/maestro` (swap for `@maestrofrontier/frontier` once published) — then fully restart the tool so it picks up the new `PATH`. Without the global install, drive the engine with the `node bin/maestro.cjs frontier …` form from the project root instead.
100
+ ```text
101
+ maestro frontier mode fusion --preset chatgpt-duo --scope codex-project
102
+ maestro frontier mode fusion --preset frontier-trio --judge chatgpt --synth chatgpt --scope codex-project
103
+ maestro frontier mode off --scope codex-project
104
+ ```
51
105
 
52
- Frontier stays **off** until you arm it: `/maestro:frontier fusion opus-gpt` (Claude Code) or `maestro frontier mode fusion --preset opus-gpt --scope <tool>` elsewhere (armed state stays per-CLI-global; `--scope codex`/`cursor`/`gemini`/`cline`/`windsurf`).
106
+ Use `node bin/maestro.cjs frontier ...` in place of `maestro frontier ...`
107
+ when the binary is not on `PATH`. `codex-project` expands to the repo's
108
+ `codex-<8hex>` workspace scope, matching the trusted Codex plugin hook.
109
+ `maestro frontier run "<prompt>" ...` is still available for advanced/debug
110
+ one-offs, but arming mode is the normal autorun flow.
53
111
 
54
112
  ---
55
113
 
@@ -70,12 +128,14 @@ members — fusing the CLIs you already run buys frontier-tier results. It
70
128
  is the project's new default identity; the doctrine, hooks, skills, and
71
129
  benchmarks are unchanged; the discipline layer is its foundation.
72
130
 
73
- It ships with the plugin and is driven by `/maestro:frontier`. Three
74
- modes, switched at will, **`off` by default** so installing or
75
- upgrading changes nothing until you opt in. **Arming it `single` or
76
- `fusion` makes it auto-run on every prompt**: a `UserPromptSubmit`
77
- hook routes each prompt through the engine and the live session relays
78
- the synthesized answer. `off` is the disable path.
131
+ It ships with the native plugins. Claude Code drives it with
132
+ `/maestro:frontier`, Codex drives it with the `maestro-frontier` skill, and
133
+ other CLIs can use `maestro frontier ...` or the `node bin/maestro.cjs
134
+ frontier ...` fallback. Three modes, switched at will, **`off` by default**
135
+ so installing or upgrading changes nothing until you opt in. **Arming it —
136
+ `single` or `fusion` makes it auto-run on every prompt**: a
137
+ `UserPromptSubmit` hook routes each prompt through the engine and the live
138
+ session relays the synthesized answer. `off` is the disable path.
79
139
 
80
140
  | Mode | Behavior |
81
141
  |---|---|
@@ -83,6 +143,8 @@ the synthesized answer. `off` is the disable path.
83
143
  | `single <model>` | Auto-runs every prompt through one local CLI and relays its answer. No panel, no judge, no synth. |
84
144
  | `fusion <preset>` | Auto-runs every prompt through your panel -> a judge model's analysis -> a grounded synthesis, with graceful degradation and one-level recursion bounds. |
85
145
 
146
+ Claude Code examples:
147
+
86
148
  ```text
87
149
  /maestro:frontier status # show current mode
88
150
  /maestro:frontier single opus # arm one-CLI auto-run
@@ -91,12 +153,16 @@ the synthesized answer. `off` is the disable path.
91
153
  /maestro:frontier off # disable auto-run; back to normal Maestro
92
154
  ```
93
155
 
156
+ In Codex, ask the bundled `maestro-frontier` skill for the same status,
157
+ single, fusion, run, or off operation; it resolves the plugin-bundled engine
158
+ when the bare `maestro` command is not on `PATH`.
159
+
94
160
  Presets define the panel; the judge and synthesizer default to Opus 4.8
95
161
  (`claude -p`), and you override either with `--judge` / `--synth`:
96
162
 
97
163
  - **`opus-duo`**: two independent Opus runs, isolating the synthesis lift.
98
164
  - **`opus-gpt`**: Opus + GPT-5.5 (via `codex exec`); the recommended default for bounded spend.
99
- - **`gpt-duo`**: two GPT-5.5 runs whose judge and synthesizer also run on GPT-5.5: a Codex-only fusion that needs no `claude`.
165
+ - **`chatgpt-duo`** (`gpt-duo` alias): two ChatGPT/Codex runs whose judge and synthesizer also run on ChatGPT/Codex: a Codex-only fusion that needs no `claude`.
100
166
  - **`frontier-trio`**: Opus + GPT-5.5 + Gemini 3.1 Pro (via `gemini -p`).
101
167
  - **`custom`**: 1-8 of the known models.
102
168
 
@@ -114,7 +180,7 @@ failure synthesizes from the raw responses; a hard failure returns a typed
114
180
  Honest scope, measured rather than implied: the **engine is built,
115
181
  unit-tested (degradation, recursion, budget, anti-majority all covered),
116
182
  and verified end-to-end on real runs of `single` mode and the
117
- `opus-gpt`, `opus-duo`, and `frontier-trio` presets**. The `gpt-duo`
183
+ `opus-gpt`, `opus-duo`, and `frontier-trio` presets**. The `chatgpt-duo`
118
184
  preset and `--judge`/`--synth` selection share that same code path and
119
185
  are unit-tested, but not yet live-run. The quality *lift* of local fusion
120
186
  is **measured, not asserted**: on a 100-task suite (93 scored) every
@@ -178,7 +244,18 @@ Maestro separates **portable orchestration doctrine** from **runtime-specific ad
178
244
  | `.cursorrules` | Cursor adapter | Kernel copy (Cursor does not support imports); full S2-S6 in docs/orchestration.md |
179
245
  | [`docs/codex.md`](docs/codex.md) | Codex guide | AGENTS.md precedence and 32 KiB cap, Codex subagent mapping, Automations long-horizon mapping (Codex reads `AGENTS.md` natively) |
180
246
 
181
- Maestro's tools run on **both Claude Code and Codex** — in Claude Code as `/maestro:*` slash commands, and in Codex as installable skills, with the portable `node settings/cli.cjs` and `maestro frontier ...` CLIs working on any other agent too. The Codex skills (`frontier`, `terse`, `settings`, `update`) are installed to `.agents/skills/<name>/SKILL.md` by `maestro install --target codex`. When Frontier mode is on, the `frontier` skill leads each Codex reply with `Maestro Frontier ON (<label>)` (`single · <model>` or `fusion · <preset>`) — the Codex analog of Claude Code's armed Frontier indicator; run `maestro frontier status --scope codex` to check. This indicator is Codex-scoped only.
247
+ Maestro's tools run on **both Claude Code and Codex** — in Claude Code as
248
+ `/maestro:*` slash commands, and in Codex as plugin-bundled skills plus
249
+ trusted hooks. The portable `node settings/cli.cjs` and `maestro frontier ...`
250
+ CLIs also work on any other agent. The Codex skills
251
+ (`maestro-frontier`, `maestro-terse`, `maestro-settings`, `maestro-update`)
252
+ ship from the Maestro plugin; the older `maestro install --target codex` path
253
+ still works for manual project copies. When Frontier mode is on, the
254
+ `maestro-frontier` skill leads each Codex reply with `Maestro Frontier ON
255
+ (<label>)` (`single · <model>` or `fusion · <preset>`) — the Codex analog of
256
+ Claude Code's armed Frontier indicator; ask the skill to show status, or run
257
+ `maestro frontier status --scope codex-project` from a shell when using the
258
+ CLI directly.
182
259
 
183
260
  GitHub Copilot, Cline, and Windsurf read `AGENTS.md` directly, so the portable core works there with no adapter. Maestro's always-on kernel (`AGENTS.md`) is ~8 KB, under Windsurf's 12,000-character limit and roughly a quarter of Codex's 32 KiB budget; the full multi-agent protocol loads on demand from `docs/orchestration.md`.
184
261
 
@@ -202,7 +279,9 @@ Optional Claude Code machinery; full install steps in the linked docs.
202
279
 
203
280
  ## Commands & Settings
204
281
 
205
- Every Maestro slash command in Claude Code is namespaced `/maestro:<name>`. The same tools run on Codex as installed skills (`.agents/skills/<name>/SKILL.md`, via `maestro install --target codex`); on any CLI the same actions also run through the portable scripts noted below.
282
+ Every Maestro slash command in Claude Code is namespaced `/maestro:<name>`.
283
+ The same tools run on Codex as plugin-bundled skills; on any CLI the same
284
+ actions also run through the portable scripts noted below.
206
285
 
207
286
  | Command | What it does | Usage |
208
287
  |---|---|---|
@@ -219,14 +298,15 @@ Every Maestro slash command in Claude Code is namespaced `/maestro:<name>`. The
219
298
  | Toggle | Values | What it controls |
220
299
  |---|---|---|
221
300
  | `terse` | `off`, `lite`, `full`, `ultra` | Output-token reduction. Shows an amber level badge (`ULTRA`) on the status bar. |
222
- | `frontier` | `off`; `single:` `opus` / `gpt-5.5` / `gemini`; `fusion:` `opus-duo` / `opus-gpt` / `gpt-duo` / `frontier-trio` / `custom`, each with optional `--judge` / `--synth` | The local fusion engine. When armed it auto-runs on every prompt. The blue `f` panel badge means auto-run is on: `fO+C`, `fO+C+G`, `f*3` (`O`=Opus, `C`=ChatGPT/GPT-5.5, `G`=Gemini). |
301
+ | `frontier` | `off`; `single:` `opus` / `gpt-5.5` / `gemini`; `fusion:` `opus-duo` / `opus-gpt` / `chatgpt-duo` / `frontier-trio` / `custom`, each with optional `--judge` / `--synth` | The local fusion engine. When armed it auto-runs on every prompt. The blue `f` panel badge means auto-run is on: `fO+C`, `fO+C+G`, `f*3` (`O`=Opus, `C`=ChatGPT/GPT-5.5, `G`=Gemini). |
223
302
  | `context-bar` | `on`, `off` | The status-line context-window progress bar. |
224
303
 
225
- Portable everywhere, Codex included: `node settings/cli.cjs status | list | help | set <key> <value>` (frontier also takes `--judge`, `--synth`, `--models a,b,c`). Full references: [`docs/settings.md`](docs/settings.md) and [`docs/context-bar.md`](docs/context-bar.md).
304
+ Portable everywhere, Codex included: `node settings/cli.cjs status | list | help | set <key> <value>` (frontier also takes `--judge`, `--synth`, `--models a,b,c`, and `--scope <scope>`). Full references: [`docs/settings.md`](docs/settings.md) and [`docs/context-bar.md`](docs/context-bar.md).
226
305
 
227
306
  ## Updating Maestro
228
307
 
229
- Maestro no longer pins a plugin version. The marketplace always resolves to the latest `main`, so updating is a single refresh no version bump needed in any file.
308
+ Maestro's marketplaces track `main`, so updating is a refresh rather than a
309
+ manual version edit.
230
310
 
231
311
  ### Claude Code
232
312
 
@@ -245,7 +325,17 @@ It can't run the reload for you (a slash command can't invoke another slash comm
245
325
 
246
326
  `/reload-plugins` applies the update in the running session; if Claude Code warns that a restart is required, restart it. Non-interactive equivalent of the pull: `claude plugin marketplace update maestro`.
247
327
 
248
- ### Codex / Cursor (portable installs, no plugin system)
328
+ ### Codex
329
+
330
+ ```text
331
+ codex plugin marketplace upgrade maestro
332
+ codex plugin add maestro@maestro
333
+ ```
334
+
335
+ Open a new thread after reinstalling so Codex reloads bundled skills and hook
336
+ definitions.
337
+
338
+ ### Cursor / Portable Installs
249
339
 
250
340
  - **Git clone:** `git pull` inside the Maestro clone directory.
251
341
  - **Downloaded copy:** re-run `npx github:mbanderas/maestro install --target auto --project .` from the project root, or re-download the tarball and re-copy `frontier/`, `bin/maestro.cjs`, plus your integration command file from the latest `main`.
package/docs/codex.md CHANGED
@@ -4,6 +4,8 @@ Codex reads `AGENTS.md` natively, no adapter file needed. This page
4
4
  maps Maestro's concepts onto Codex specifics. All behavior below was
5
5
  verified against the official Codex docs
6
6
  ([AGENTS.md guide](https://developers.openai.com/codex/guides/agents-md),
7
+ [config reference](https://developers.openai.com/codex/config-reference#configtoml),
8
+ [plugin-bundled hooks](https://developers.openai.com/codex/hooks#plugin-bundled-hooks),
7
9
  [Automations](https://developers.openai.com/codex/app/automations.md),
8
10
  [Subagents](https://developers.openai.com/codex/subagents.md))
9
11
  on 2026-06-12.
@@ -38,6 +40,40 @@ Practical consequences for Maestro:
38
40
  the doctrine to every project; per-repo files then layer on top and
39
41
  win where they conflict.
40
42
 
43
+ ## Config, hooks, and trust
44
+
45
+ Codex user config lives at `~/.codex/config.toml`. Project overrides can
46
+ live in `.codex/config.toml`, but Codex loads project-local config,
47
+ hooks, and rules only for trusted projects. Untrusted projects skip
48
+ those local surfaces.
49
+
50
+ Codex also supports plugin-bundled lifecycle hooks. Enabled plugins can
51
+ ship hooks alongside user, project, and managed hooks; the default plugin
52
+ hook file is `hooks/hooks.json`, and manifests can reference `./` paths
53
+ or inline hook definitions. Treat plugin hooks as executable code:
54
+ review and trust the plugin before enabling them. Codex sets
55
+ `PLUGIN_ROOT` and `PLUGIN_DATA` for plugin hooks, and also sets
56
+ `CLAUDE_PLUGIN_ROOT` and `CLAUDE_PLUGIN_DATA` for compatibility.
57
+
58
+ For Codex CLI/Desktop, install Maestro as a native Codex plugin:
59
+
60
+ ```text
61
+ codex plugin marketplace add mbanderas/maestro
62
+ codex plugin add maestro@maestro
63
+ ```
64
+
65
+ The repo is a Codex marketplace because it ships
66
+ `.agents/plugins/marketplace.json`; the plugin itself is described by
67
+ `.codex-plugin/plugin.json`. That manifest points at the plugin-bundled Codex
68
+ skills (`./skills/`); the hook bundle lives at Codex's default plugin hook path
69
+ `./hooks/hooks.json`, so Codex can install the plugin without `npx`. Restart
70
+ Codex or start a new thread after changing plugin installation/trust state,
71
+ then review and trust the bundled hooks before expecting autorun.
72
+
73
+ `maestro install --target codex` remains as a portable/manual fallback when
74
+ you specifically want to copy files into a project instead of installing the
75
+ Codex plugin.
76
+
41
77
  ## Multi-agent routing (S2-S6 mapping)
42
78
 
43
79
  Codex supports subagent workflows in the CLI and app, but current Codex
@@ -75,24 +111,57 @@ memory), and an explicit final report instead of a zombie loop. For
75
111
  project-scoped automations note the Codex requirement that the local
76
112
  app is running and the project is on disk.
77
113
 
78
- ## What does not transfer
114
+ ## Frontier autorun and scope
79
115
 
80
- Codex has no user-hook system equivalent to Claude Code's, so Maestro's
81
- structural enforcement pack (subagent guard, loop guard, phase-scope
82
- guard, gate telemetry) does not run on Codex. The prose doctrine in
83
- `AGENTS.md` is the enforcement surface; S7.3's verification gate relies
84
- on the model honoring it rather than on a hook.
116
+ Frontier is off until you arm it. For Codex, the normal workflow is:
85
117
 
86
- The Maestro context bar also does not apply: Codex CLI ships a native
118
+ ```text
119
+ maestro frontier mode fusion --preset chatgpt-duo --scope codex-project
120
+ maestro frontier mode fusion --preset frontier-trio --judge chatgpt --synth chatgpt --scope codex-project
121
+ maestro frontier mode off --scope codex-project
122
+ ```
123
+
124
+ Once the Maestro Codex plugin hook is installed, enabled, and trusted,
125
+ normal Codex prompts route through Frontier until you turn it off.
126
+ `maestro frontier run "<prompt>" ...` remains available for advanced/debug
127
+ one-offs, but it is not the everyday Codex flow.
128
+
129
+ Project/workspace scope is the recommended default for repo installs:
130
+ it keeps one repository's armed state from leaking into another. In a
131
+ Codex plugin context Maestro resolves this automatically to a
132
+ `codex-<8hex>` workspace scope. From a shell in the repo, pass
133
+ `--scope codex-project` (or `codex-workspace`) to resolve the same project
134
+ scope. Global/user scope is optional: choose an explicit name such as
135
+ `--scope codex-global` only when you deliberately want the same state across
136
+ projects.
137
+
138
+ Use the same active scope for all lifecycle commands:
139
+
140
+ ```text
141
+ maestro frontier status --scope codex-project
142
+ maestro frontier mode off --scope codex-project
143
+ maestro frontier mode fusion --preset chatgpt-duo --scope codex-project
144
+ maestro frontier mode fusion --preset frontier-trio --judge chatgpt --synth chatgpt --scope codex-project
145
+ ```
146
+
147
+ ## What differs from Claude Code
148
+
149
+ Claude Code-specific UI such as the Maestro context bar does not apply:
150
+ Codex CLI ships a native
87
151
  context-usage indicator (`/statusline` picker, or `context` in
88
152
  `[tui].status_line` in `~/.codex/config.toml`).
89
153
 
90
154
  ## Skills and the Frontier ON indicator
91
155
 
92
- `maestro install --target codex` installs the `frontier`, `terse`, `settings`,
93
- and `update` Maestro commands as Codex skills (no-clobber) to
94
- `.agents/skills/<name>/SKILL.md` (per-repo) or `~/.agents/skills/<name>/SKILL.md`
95
- (global). When `maestro frontier status --scope codex` reports mode != off, the
96
- `frontier` skill instructs Codex to lead its reply with
156
+ Codex skills can live in personal `$HOME/.agents/skills`, repo
157
+ `.agents/skills`, or installed plugins. The normal Codex path is the Maestro
158
+ plugin, which bundles `maestro-frontier`, `maestro-settings`, `maestro-terse`,
159
+ and `maestro-update` from `./skills/`. The portable
160
+ `maestro install --target codex` fallback still installs those same skills to
161
+ `.agents/skills/<name>/SKILL.md` for project installs or
162
+ `~/.agents/skills/<name>/SKILL.md` for global/user installs.
163
+
164
+ When `maestro frontier status --scope codex-project` reports mode != off,
165
+ the `maestro-frontier` skill instructs Codex to lead its reply with
97
166
  `Maestro Frontier ON (<label>)` — `single · <model>` or `fusion · <preset>`. When
98
167
  mode is off, no indicator line appears.
package/frontier/cli.cjs CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  const fs = require('fs');
7
7
  const { DEFAULTS, loadState, saveState, resolveScope, validateMode, validatePreset, validateModel, adoptLegacyState } = require('./config.cjs');
8
- const { runFrontier } = require('./run.cjs');
8
+ const { runFrontier, canonicalModelId, canonicalPresetId } = require('./run.cjs');
9
9
 
10
10
  // ---------- arg helpers ----------
11
11
 
@@ -63,7 +63,8 @@ function cmdMode(argv, scope) {
63
63
  if (newMode === 'off') {
64
64
  state = { mode: 'off' };
65
65
  } else if (newMode === 'single') {
66
- const model = getFlag(argv, '--model');
66
+ const rawModel = getFlag(argv, '--model');
67
+ const model = rawModel && canonicalModelId(rawModel);
67
68
  if (!model) {
68
69
  process.stderr.write('ERROR: --model required for single mode\n');
69
70
  process.exit(2);
@@ -75,7 +76,8 @@ function cmdMode(argv, scope) {
75
76
  state = { mode: 'single', model };
76
77
  } else {
77
78
  // fusion
78
- const preset = getFlag(argv, '--preset');
79
+ const rawPreset = getFlag(argv, '--preset');
80
+ const preset = rawPreset && canonicalPresetId(rawPreset);
79
81
  if (!preset) {
80
82
  process.stderr.write('ERROR: --preset required for fusion mode\n');
81
83
  process.exit(2);
@@ -90,7 +92,7 @@ function cmdMode(argv, scope) {
90
92
  process.stderr.write('ERROR: --models required for custom preset\n');
91
93
  process.exit(2);
92
94
  }
93
- const models = modelsRaw.split(',').map(m => m.trim()).filter(Boolean);
95
+ const models = modelsRaw.split(',').map(m => canonicalModelId(m.trim())).filter(Boolean);
94
96
  state = { mode: 'fusion', preset: 'custom', models };
95
97
  } else {
96
98
  state = { mode: 'fusion', preset };
@@ -99,7 +101,8 @@ function cmdMode(argv, scope) {
99
101
  // Optional judge/synth model overrides — apply to any fusion preset so
100
102
  // users can mix freely (e.g. --judge opus --synth gpt-5.5). Unset =
101
103
  // the preset's own stage model (presetStages) or the global default.
102
- const judge = getFlag(argv, '--judge');
104
+ const rawJudge = getFlag(argv, '--judge');
105
+ const judge = rawJudge !== null ? canonicalModelId(rawJudge) : null;
103
106
  if (judge !== null) {
104
107
  if (!validateModel(judge)) {
105
108
  process.stderr.write('ERROR: unknown judge model: ' + judge + '\n');
@@ -107,7 +110,8 @@ function cmdMode(argv, scope) {
107
110
  }
108
111
  state.judgeModel = judge;
109
112
  }
110
- const synth = getFlag(argv, '--synth');
113
+ const rawSynth = getFlag(argv, '--synth');
114
+ const synth = rawSynth !== null ? canonicalModelId(rawSynth) : null;
111
115
  if (synth !== null) {
112
116
  if (!validateModel(synth)) {
113
117
  process.stderr.write('ERROR: unknown synth model: ' + synth + '\n');
@@ -71,26 +71,50 @@ function sanitizeScope(v) {
71
71
  return s.length > 0 ? s : 'default';
72
72
  }
73
73
 
74
+ function workspaceCwd(opts) {
75
+ return (opts && opts.cwd) || process.env.CLAUDE_PROJECT_DIR || process.env.CODEX_PROJECT_DIR || process.cwd();
76
+ }
77
+
78
+ function resolveScopeAlias(scope, opts) {
79
+ const clean = sanitizeScope(scope);
80
+ if (['codex-project', 'codex-workspace', 'codex-repo'].includes(clean)) {
81
+ return 'codex-' + workspaceHash(workspaceCwd(opts));
82
+ }
83
+ if (['claude-project', 'claude-workspace', 'cc-project', 'cc-workspace'].includes(clean)) {
84
+ return 'cc-' + workspaceHash(workspaceCwd(opts));
85
+ }
86
+ return clean;
87
+ }
88
+
74
89
  /**
75
90
  * Resolve the active scope from argv + environment. Precedence:
76
91
  * 1. --scope <value> flag in argv
77
92
  * 2. process.env.MAESTRO_SCOPE
78
- * 3. Autodetect: CLAUDE_PLUGIN_ROOT || CLAUDECODE truthy -> 'cc-<8hex>'
93
+ * 3. Autodetect: PLUGIN_ROOT truthy -> 'codex-<8hex>'
94
+ * 4. Autodetect: CLAUDE_PLUGIN_ROOT || CLAUDECODE truthy -> 'cc-<8hex>'
95
+ * 5. Autodetect: PLUGIN_DATA truthy -> 'codex-<8hex>'
79
96
  * where <8hex> is derived from the workspace root (opts.cwd,
80
- * CLAUDE_PROJECT_DIR, or process.cwd()) via workspaceHash().
81
- * 4. 'default'
82
- * The chosen value for steps 1-2 is always passed through sanitizeScope.
97
+ * CLAUDE_PROJECT_DIR, CODEX_PROJECT_DIR, or process.cwd()) via
98
+ * workspaceHash().
99
+ * 6. 'default'
100
+ * The chosen value for steps 1-2 is sanitized, and project aliases such as
101
+ * codex-project/codex-workspace are expanded to per-workspace scopes.
83
102
  * @param {string[]} argv
84
103
  * @param {{ cwd?: string }} [opts]
85
104
  * @returns {string}
86
105
  */
87
106
  function resolveScope(argv, opts) {
88
107
  const flagVal = getFlag(argv, '--scope');
89
- if (flagVal !== null) return sanitizeScope(flagVal);
90
- if (process.env.MAESTRO_SCOPE) return sanitizeScope(process.env.MAESTRO_SCOPE);
108
+ if (flagVal !== null) return resolveScopeAlias(flagVal, opts);
109
+ if (process.env.MAESTRO_SCOPE) return resolveScopeAlias(process.env.MAESTRO_SCOPE, opts);
110
+ if (process.env.PLUGIN_ROOT) {
111
+ return 'codex-' + workspaceHash(workspaceCwd(opts));
112
+ }
91
113
  if (process.env.CLAUDE_PLUGIN_ROOT || process.env.CLAUDECODE) {
92
- const cwd = (opts && opts.cwd) || process.env.CLAUDE_PROJECT_DIR || process.cwd();
93
- return 'cc-' + workspaceHash(cwd);
114
+ return 'cc-' + workspaceHash(workspaceCwd(opts));
115
+ }
116
+ if (process.env.PLUGIN_DATA) {
117
+ return 'codex-' + workspaceHash(workspaceCwd(opts));
94
118
  }
95
119
  return 'default';
96
120
  }
@@ -111,6 +135,7 @@ function legacyStatePath() {
111
135
  */
112
136
  function statePath(scope) {
113
137
  if (scope === undefined) scope = resolveScope([]);
138
+ else scope = resolveScopeAlias(scope);
114
139
  if (scope === 'default') return path.join(configDir(), 'frontier-state.json');
115
140
  return path.join(configDir(), 'frontier-state.' + scope + '.json');
116
141
  }
@@ -163,25 +188,26 @@ function _readValidatedStateFile(p) {
163
188
 
164
189
  /**
165
190
  * Load frontier state for the given scope.
166
- * D3 MIGRATION: if scope !== 'default' and scope does NOT match /^cc-/
191
+ * D3 MIGRATION: if scope !== 'default' and scope does NOT match /^(cc|codex)-/
167
192
  * and the scoped file does NOT exist AND the legacy frontier-state.json
168
193
  * DOES exist, seed from the legacy file (read-only — never write during
169
- * load). Same symlink/parse guards apply. cc-* scopes are excluded from
170
- * migration because they are per-workspace and must not inherit global
171
- * legacy state. Named scopes (e.g. 'codex', 'cursor') still migrate.
194
+ * load). Same symlink/parse guards apply. cc-* and codex-* scopes are
195
+ * excluded from migration because they are per-workspace and must not inherit
196
+ * global legacy state. Named scopes (e.g. 'codex', 'cursor') still migrate.
172
197
  * Falls back to {mode:'off'} on any failure.
173
198
  * @param {string} [scope] Omit to autodetect the runtime scope via resolveScope([]).
174
199
  * @returns {object}
175
200
  */
176
201
  function loadState(scope) {
177
202
  if (scope === undefined) scope = resolveScope([]);
203
+ else scope = resolveScopeAlias(scope);
178
204
  try {
179
205
  const p = statePath(scope);
180
206
  const result = _readStateFile(p);
181
207
  if (result !== null) return result;
182
208
 
183
- // File absent. For non-default, non-cc-* scopes attempt migration from legacy file.
184
- if (scope !== 'default' && !/^cc-/.test(scope)) {
209
+ // File absent. For non-default, non-workspace scopes attempt migration from legacy file.
210
+ if (scope !== 'default' && !/^(cc|codex)-/.test(scope)) {
185
211
  const legacyResult = _readStateFile(legacyStatePath());
186
212
  if (legacyResult !== null) return legacyResult;
187
213
  }
@@ -201,6 +227,7 @@ function loadState(scope) {
201
227
  */
202
228
  function saveState(state, scope) {
203
229
  if (scope === undefined) scope = resolveScope([]);
230
+ else scope = resolveScopeAlias(scope);
204
231
  try {
205
232
  const p = statePath(scope);
206
233
  const dir = path.dirname(p);
package/frontier/run.cjs CHANGED
@@ -17,6 +17,37 @@ const dispatch = require('./dispatch.cjs');
17
17
  const judge = require('./judge.cjs');
18
18
  const synthesize = require('./synthesize.cjs');
19
19
 
20
+ const MODEL_ALIASES = {
21
+ chatgpt: 'gpt-5.5',
22
+ };
23
+
24
+ const PRESET_ALIASES = {
25
+ 'chatgpt-duo': 'gpt-duo',
26
+ };
27
+
28
+ /** @param {string} model @returns {string} */
29
+ function canonicalModelId(model) {
30
+ return MODEL_ALIASES[model] || model;
31
+ }
32
+
33
+ /** @param {string} preset @returns {string} */
34
+ function canonicalPresetId(preset) {
35
+ return PRESET_ALIASES[preset] || preset;
36
+ }
37
+
38
+ /** @param {object} state @returns {object} */
39
+ function normalizeStateAliases(state) {
40
+ const normalized = { ...state };
41
+ if (normalized.model) normalized.model = canonicalModelId(normalized.model);
42
+ if (normalized.preset) normalized.preset = canonicalPresetId(normalized.preset);
43
+ if (Array.isArray(normalized.models)) {
44
+ normalized.models = normalized.models.map(canonicalModelId);
45
+ }
46
+ if (normalized.judgeModel) normalized.judgeModel = canonicalModelId(normalized.judgeModel);
47
+ if (normalized.synthModel) normalized.synthModel = canonicalModelId(normalized.synthModel);
48
+ return normalized;
49
+ }
50
+
20
51
  /**
21
52
  * @param {{ prompt:string, state:object, cfg?:object, deps?:object }} opts
22
53
  * @returns {Promise<object>}
@@ -24,6 +55,7 @@ const synthesize = require('./synthesize.cjs');
24
55
  async function runFrontier({ prompt, state, cfg, deps }) {
25
56
  cfg = cfg || DEFAULTS;
26
57
  deps = deps || {};
58
+ state = normalizeStateAliases(state || {});
27
59
 
28
60
  const spawnOne = deps.spawnOne || dispatch.spawnOne;
29
61
  const fanOut = deps.fanOut || dispatch.fanOut;
@@ -145,4 +177,4 @@ async function runFrontier({ prompt, state, cfg, deps }) {
145
177
  return { status: 'error', mode: state.mode, error: 'unknown mode', failure_reason: 'unexpected_error' };
146
178
  }
147
179
 
148
- module.exports = { runFrontier };
180
+ module.exports = { runFrontier, canonicalModelId, canonicalPresetId, normalizeStateAliases };
@@ -45,12 +45,8 @@ if (Number.isFinite(fusionDepth) && fusionDepth >= 1) noop();
45
45
  let state;
46
46
  try {
47
47
  const cfg = require('../frontier/config.cjs');
48
- const cwd = data.cwd || process.env.CLAUDE_PROJECT_DIR || process.cwd();
49
- // This hook only ever runs under Claude Code, so force a per-workspace
50
- // scope; resolveScope honors --scope/MAESTRO_SCOPE first, then we ensure
51
- // we never fall back to the shared legacy 'default' file.
52
- let scope = cfg.resolveScope([], { cwd });
53
- if (scope === 'default') scope = 'cc-' + cfg.workspaceHash(cwd);
48
+ const cwd = data.cwd || process.env.CLAUDE_PROJECT_DIR || process.env.CODEX_PROJECT_DIR || process.cwd();
49
+ const scope = cfg.resolveScope([], { cwd });
54
50
  state = cfg.loadState(scope);
55
51
  } catch {
56
52
  noop();
package/hooks/hooks.json CHANGED
@@ -40,7 +40,7 @@
40
40
  },
41
41
  {
42
42
  "type": "command",
43
- "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/frontier-autorun.cjs\"",
43
+ "command": "node -e \"require(require('path').join(process.env.CLAUDE_PLUGIN_ROOT || process.env.PLUGIN_ROOT, 'hooks', 'frontier-autorun.cjs'))\"",
44
44
  "timeout": 300
45
45
  }
46
46
  ]