@maestrofrontier/frontier 1.4.3 → 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/.agents/plugins/marketplace.json +21 -0
- package/.codex-plugin/plugin.json +29 -0
- package/AGENTS.md +214 -214
- package/CLAUDE.md +29 -29
- package/README.md +113 -23
- package/docs/codex.md +81 -12
- package/frontier/cli.cjs +10 -6
- package/frontier/config.cjs +41 -14
- package/frontier/run.cjs +33 -1
- package/hooks/frontier-autorun.cjs +2 -6
- package/hooks/hooks.json +1 -1
- package/integrations/README.md +51 -34
- package/integrations/codex/prompts/frontier.md +22 -18
- package/integrations/codex/prompts/update.md +3 -0
- package/integrations/codex/skills/maestro-frontier/SKILL.md +122 -0
- package/integrations/codex/skills/{settings → maestro-settings}/SKILL.md +15 -6
- package/integrations/codex/skills/{terse → maestro-terse}/SKILL.md +15 -6
- package/integrations/codex/skills/maestro-update/SKILL.md +31 -0
- package/package.json +4 -1
- package/scripts/install.cjs +424 -15
- package/settings/cli.cjs +1 -1
- package/skills/maestro-frontier/SKILL.md +122 -0
- package/skills/maestro-settings/SKILL.md +55 -0
- package/skills/maestro-terse/SKILL.md +58 -0
- package/skills/maestro-update/SKILL.md +31 -0
- package/skills/terse/SKILL.md +74 -0
- package/integrations/codex/skills/frontier/SKILL.md +0 -91
- package/integrations/codex/skills/update/SKILL.md +0 -29
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-
|
|
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 · 123 valid A/B runs · 11 voids excluded & re-run · 6 hooks, all tested · ~8 KB always-on kernel ·
|
|
25
|
+
<sub>13 fixture tasks · 123 valid A/B runs · 11 voids excluded & re-run · 6 hooks, all tested · ~8 KB always-on kernel · plugin + portable installs</sub>
|
|
26
26
|
</p>
|
|
27
27
|
|
|
28
|
-
> **Install — run the
|
|
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,20 +39,75 @@
|
|
|
34
39
|
/plugin install maestro@maestro
|
|
35
40
|
```
|
|
36
41
|
|
|
37
|
-
**
|
|
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
|
-
|
|
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:
|
|
99
|
+
|
|
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
|
+
```
|
|
49
105
|
|
|
50
|
-
|
|
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.
|
|
51
111
|
|
|
52
112
|
---
|
|
53
113
|
|
|
@@ -68,12 +128,14 @@ members — fusing the CLIs you already run buys frontier-tier results. It
|
|
|
68
128
|
is the project's new default identity; the doctrine, hooks, skills, and
|
|
69
129
|
benchmarks are unchanged; the discipline layer is its foundation.
|
|
70
130
|
|
|
71
|
-
It ships with the
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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.
|
|
77
139
|
|
|
78
140
|
| Mode | Behavior |
|
|
79
141
|
|---|---|
|
|
@@ -81,6 +143,8 @@ the synthesized answer. `off` is the disable path.
|
|
|
81
143
|
| `single <model>` | Auto-runs every prompt through one local CLI and relays its answer. No panel, no judge, no synth. |
|
|
82
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. |
|
|
83
145
|
|
|
146
|
+
Claude Code examples:
|
|
147
|
+
|
|
84
148
|
```text
|
|
85
149
|
/maestro:frontier status # show current mode
|
|
86
150
|
/maestro:frontier single opus # arm one-CLI auto-run
|
|
@@ -89,12 +153,16 @@ the synthesized answer. `off` is the disable path.
|
|
|
89
153
|
/maestro:frontier off # disable auto-run; back to normal Maestro
|
|
90
154
|
```
|
|
91
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
|
+
|
|
92
160
|
Presets define the panel; the judge and synthesizer default to Opus 4.8
|
|
93
161
|
(`claude -p`), and you override either with `--judge` / `--synth`:
|
|
94
162
|
|
|
95
163
|
- **`opus-duo`**: two independent Opus runs, isolating the synthesis lift.
|
|
96
164
|
- **`opus-gpt`**: Opus + GPT-5.5 (via `codex exec`); the recommended default for bounded spend.
|
|
97
|
-
- **`gpt-duo
|
|
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`.
|
|
98
166
|
- **`frontier-trio`**: Opus + GPT-5.5 + Gemini 3.1 Pro (via `gemini -p`).
|
|
99
167
|
- **`custom`**: 1-8 of the known models.
|
|
100
168
|
|
|
@@ -112,7 +180,7 @@ failure synthesizes from the raw responses; a hard failure returns a typed
|
|
|
112
180
|
Honest scope, measured rather than implied: the **engine is built,
|
|
113
181
|
unit-tested (degradation, recursion, budget, anti-majority all covered),
|
|
114
182
|
and verified end-to-end on real runs of `single` mode and the
|
|
115
|
-
`opus-gpt`, `opus-duo`, and `frontier-trio` presets**. The `
|
|
183
|
+
`opus-gpt`, `opus-duo`, and `frontier-trio` presets**. The `chatgpt-duo`
|
|
116
184
|
preset and `--judge`/`--synth` selection share that same code path and
|
|
117
185
|
are unit-tested, but not yet live-run. The quality *lift* of local fusion
|
|
118
186
|
is **measured, not asserted**: on a 100-task suite (93 scored) every
|
|
@@ -176,7 +244,18 @@ Maestro separates **portable orchestration doctrine** from **runtime-specific ad
|
|
|
176
244
|
| `.cursorrules` | Cursor adapter | Kernel copy (Cursor does not support imports); full S2-S6 in docs/orchestration.md |
|
|
177
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) |
|
|
178
246
|
|
|
179
|
-
Maestro's tools run on **both Claude Code and Codex** — in Claude Code as
|
|
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.
|
|
180
259
|
|
|
181
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`.
|
|
182
261
|
|
|
@@ -200,7 +279,9 @@ Optional Claude Code machinery; full install steps in the linked docs.
|
|
|
200
279
|
|
|
201
280
|
## Commands & Settings
|
|
202
281
|
|
|
203
|
-
Every Maestro slash command in Claude Code is namespaced `/maestro:<name>`.
|
|
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.
|
|
204
285
|
|
|
205
286
|
| Command | What it does | Usage |
|
|
206
287
|
|---|---|---|
|
|
@@ -217,16 +298,17 @@ Every Maestro slash command in Claude Code is namespaced `/maestro:<name>`. The
|
|
|
217
298
|
| Toggle | Values | What it controls |
|
|
218
299
|
|---|---|---|
|
|
219
300
|
| `terse` | `off`, `lite`, `full`, `ultra` | Output-token reduction. Shows an amber level badge (`ULTRA`) on the status bar. |
|
|
220
|
-
| `frontier` | `off`; `single:` `opus` / `gpt-5.5` / `gemini`; `fusion:` `opus-duo` / `opus-gpt` / `
|
|
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). |
|
|
221
302
|
| `context-bar` | `on`, `off` | The status-line context-window progress bar. |
|
|
222
303
|
|
|
223
|
-
Portable everywhere, Codex included: `node settings/cli.cjs status | list | help | set <key> <value>` (frontier also takes `--judge`, `--synth`, `--models a,b,c
|
|
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).
|
|
224
305
|
|
|
225
306
|
## Updating Maestro
|
|
226
307
|
|
|
227
|
-
Maestro
|
|
308
|
+
Maestro's marketplaces track `main`, so updating is a refresh rather than a
|
|
309
|
+
manual version edit.
|
|
228
310
|
|
|
229
|
-
### Claude Code
|
|
311
|
+
### Claude Code
|
|
230
312
|
|
|
231
313
|
`/maestro:update` is the one-command path — it pulls the latest marketplace code, reports what changed, and tells you when to reload:
|
|
232
314
|
|
|
@@ -243,9 +325,17 @@ It can't run the reload for you (a slash command can't invoke another slash comm
|
|
|
243
325
|
|
|
244
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`.
|
|
245
327
|
|
|
246
|
-
|
|
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.
|
|
247
337
|
|
|
248
|
-
###
|
|
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
|
-
##
|
|
114
|
+
## Frontier autorun and scope
|
|
79
115
|
|
|
80
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
`
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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');
|
package/frontier/config.cjs
CHANGED
|
@@ -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:
|
|
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
|
|
81
|
-
*
|
|
82
|
-
*
|
|
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
|
|
90
|
-
if (process.env.MAESTRO_SCOPE) return
|
|
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
|
-
|
|
93
|
-
|
|
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
|
|
170
|
-
* migration because they are per-workspace and must not inherit
|
|
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-
|
|
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
|
-
|
|
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 \"
|
|
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
|
]
|