@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.
@@ -11,6 +11,7 @@
11
11
  const fs = require('fs');
12
12
  const os = require('os');
13
13
  const path = require('path');
14
+ const crypto = require('crypto');
14
15
 
15
16
  // ---- constants ----
16
17
 
@@ -25,7 +26,7 @@ const WRAPPER_MAP = {
25
26
  codex: {
26
27
  src: 'integrations/codex/prompts/frontier.md',
27
28
  proj: '.codex/prompts/frontier.md',
28
- user: path.join(os.homedir(), '.codex', 'prompts', 'frontier.md'),
29
+ user: () => path.join(homeDir(), '.codex', 'prompts', 'frontier.md'),
29
30
  },
30
31
  cursor: {
31
32
  src: 'integrations/cursor/commands/frontier.md',
@@ -35,24 +36,252 @@ const WRAPPER_MAP = {
35
36
  gemini: {
36
37
  src: 'integrations/gemini/commands/frontier.toml',
37
38
  proj: '.gemini/commands/frontier.toml',
38
- user: path.join(os.homedir(), '.gemini', 'commands', 'frontier.toml'),
39
+ user: () => path.join(homeDir(), '.gemini', 'commands', 'frontier.toml'),
39
40
  },
40
41
  cline: {
41
42
  src: 'integrations/cline/skills/frontier/SKILL.md',
42
43
  proj: '.cline/skills/frontier/SKILL.md',
43
- user: path.join(os.homedir(), '.cline', 'skills', 'frontier', 'SKILL.md'),
44
+ user: () => path.join(homeDir(), '.cline', 'skills', 'frontier', 'SKILL.md'),
44
45
  },
45
46
  windsurf: {
46
47
  src: 'integrations/windsurf/workflows/frontier.md',
47
48
  proj: '.windsurf/workflows/frontier.md',
48
- user: path.join(os.homedir(), '.codeium', 'windsurf', 'global_workflows', 'frontier.md'),
49
+ user: () => path.join(homeDir(), '.codeium', 'windsurf', 'global_workflows', 'frontier.md'),
49
50
  },
50
51
  };
51
52
 
52
53
  // Codex skill templates installed alongside the deprecated codex wrapper.
53
54
  // Codex loads skills from <project>/.agents/skills/<name>/SKILL.md (project)
54
- // or ~/.agents/skills/<name>/SKILL.md (global). No-clobber, like wrappers.
55
- const CODEX_SKILLS = ['frontier', 'terse', 'settings', 'update'];
55
+ // or ~/.agents/skills/<name>/SKILL.md (global). Maestro-owned skills are
56
+ // refreshed when still managed; user-edited copies are preserved.
57
+ const CODEX_SKILLS = [
58
+ { name: 'maestro-frontier', legacy: 'frontier' },
59
+ { name: 'maestro-terse', legacy: 'terse' },
60
+ { name: 'maestro-settings', legacy: 'settings' },
61
+ { name: 'maestro-update', legacy: 'update' },
62
+ ];
63
+
64
+ const LEGACY_CODEX_SKILL_TEMPLATES = {
65
+ frontier: `---
66
+ name: frontier
67
+ description: Maestro Frontier local multi-CLI fusion engine — switch mode, or run a prompt through the panel
68
+ ---
69
+
70
+ Drive the **Maestro Frontier** engine — a zero-dependency local multi-CLI fusion
71
+ engine (a parallel panel of local CLIs → a judge model's analysis → a grounded
72
+ synthesis). It is the same engine the Claude Code plugin ships; here it runs
73
+ through the \`maestro\` CLI with \`--scope codex\`.
74
+
75
+ **This is a typing shortcut, not a prompt hook.** Codex has no automatic
76
+ prompt hook, so arming a mode does **not** auto-run the engine on later prompts —
77
+ it only persists the mode. To actually fuse a prompt, invoke \`run\` explicitly
78
+ (step 3).
79
+
80
+ Map the user's request to one engine CLI call and run it from the repo root.
81
+ Do not edit the engine's state file by hand.
82
+
83
+ ## 1. Switch mode
84
+
85
+ Persists to \`~/.config/maestro/frontier-state.codex.json\`; default \`off\`.
86
+ \`--scope codex\` keeps Codex's armed mode independent from Claude Code, Cline,
87
+ Cursor, and Gemini on the same machine:
88
+
89
+ \`\`\`bash
90
+ maestro frontier mode off --scope codex
91
+ maestro frontier mode single --model <model> --scope codex
92
+ maestro frontier mode fusion --preset <preset> --scope codex
93
+ maestro frontier mode fusion --preset custom --models <a,b,c> --scope codex
94
+ maestro frontier mode fusion --preset <preset> --judge <model> --synth <model> --scope codex
95
+ \`\`\`
96
+
97
+ Models: \`opus\` (Claude Opus 4.8, needs \`claude\`), \`gpt-5.5\` (needs \`codex\`),
98
+ \`gemini\` (needs \`gemini\`). Presets: \`opus-duo\`, \`opus-gpt\`, \`gpt-duo\`,
99
+ \`frontier-trio\`, \`custom\`. Judge + synth default to Opus; \`--judge\`/\`--synth\`
100
+ override for any preset (e.g. \`--judge opus --synth gpt-5.5\`). \`gpt-duo\` runs
101
+ judge + synth on GPT-5.5 — a Codex-only fusion that needs no \`claude\`.
102
+
103
+ ## 2. Show current mode/preset
104
+
105
+ \`\`\`bash
106
+ maestro frontier status --scope codex
107
+ \`\`\`
108
+
109
+ ## 3. Run a prompt through the current mode
110
+
111
+ This is the action that actually fuses, since nothing auto-runs here. Set a
112
+ mode first (step 1), then:
113
+
114
+ \`\`\`bash
115
+ maestro frontier run "<prompt>" --scope codex
116
+ \`\`\`
117
+
118
+ - \`off\`: prints a notice, spawns nothing.
119
+ - \`single\`: dispatches the one selected CLI, prints its answer.
120
+ - \`fusion\`: runs the panel in parallel → judge → synthesizer; prints the final
121
+ answer (a one-line run meta goes to stderr). Report stdout verbatim.
122
+
123
+ On error the engine prints \`ERROR [<reason>]: <detail>\` to stderr and exits
124
+ non-zero — relay the reason.
125
+
126
+ ## Indicator instruction
127
+
128
+ <!-- INDICATOR INSTRUCTION — apply every turn while this skill is active -->
129
+
130
+ Before composing your first reply each turn, run:
131
+
132
+ \`\`\`bash
133
+ maestro frontier status --scope codex
134
+ \`\`\`
135
+
136
+ Parse the returned JSON \`mode\` field:
137
+
138
+ - If \`mode\` is not \`off\`, make the **first line** of your reply exactly:
139
+ \`Maestro Frontier ON (<label>)\`
140
+ where \`<label>\` is formed as follows:
141
+ - single mode → \`single · <model>\` (e.g. \`single · opus\`)
142
+ - fusion mode → \`fusion · <preset>\` (e.g. \`fusion · frontier-trio\`);
143
+ for a custom preset use \`fusion · custom (<model1>, <model2>, ...)\`
144
+ - If \`mode\` is \`off\`, output no indicator line.
145
+
146
+ <!-- END INDICATOR INSTRUCTION -->
147
+
148
+ ## Notes
149
+
150
+ - Real \`single\`/\`fusion\` runs spawn local CLIs and cost tokens; use small prompts.
151
+ \`off\` is free.
152
+ - Each model's CLI must be on \`PATH\`, or point at a specific build with
153
+ \`MAESTRO_CLAUDE_BIN\` / \`MAESTRO_CODEX_BIN\` / \`MAESTRO_GEMINI_BIN\`.
154
+ - Requires \`maestro\` on \`PATH\` (installed during Maestro setup). If it is
155
+ missing, install Maestro first.
156
+ `,
157
+ terse: `---
158
+ name: terse
159
+ description: Toggle Maestro terse output level (lite, full, ultra, off) via the settings CLI
160
+ ---
161
+
162
+ Toggle the **Maestro terse** output level for this environment. Terse mode
163
+ condenses agent replies; levels range from \`off\` (default verbosity) through
164
+ \`lite\`, \`full\`, and \`ultra\` (most compressed).
165
+
166
+ When the user invokes this skill, run the settings CLI to read or change the
167
+ terse level. Do not edit settings files by hand.
168
+
169
+ ## Check current terse level
170
+
171
+ \`\`\`bash
172
+ node settings/cli.cjs --help
173
+ \`\`\`
174
+
175
+ Consult the help output for the exact read subcommand, then run it. If
176
+ \`settings/cli.cjs\` is not present, run \`maestro --help\` to discover the
177
+ correct path.
178
+
179
+ ## Set terse level
180
+
181
+ \`\`\`bash
182
+ node settings/cli.cjs terse <level>
183
+ \`\`\`
184
+
185
+ Valid levels: \`off\` | \`lite\` | \`full\` | \`ultra\`
186
+
187
+ Examples:
188
+
189
+ \`\`\`bash
190
+ node settings/cli.cjs terse off
191
+ node settings/cli.cjs terse lite
192
+ node settings/cli.cjs terse full
193
+ node settings/cli.cjs terse ultra
194
+ \`\`\`
195
+
196
+ If the CLI rejects an argument or the subcommand name differs, run
197
+ \`node settings/cli.cjs --help\` first and follow the printed usage.
198
+
199
+ ## Notes
200
+
201
+ - The change persists in Maestro's settings store; it applies to subsequent
202
+ agent turns in this project.
203
+ - Requires \`node\` on \`PATH\` and Maestro installed in the project root. If
204
+ \`settings/cli.cjs\` is missing, re-run the Maestro installer:
205
+ \`npx github:mbanderas/maestro install --target codex\`
206
+ `,
207
+ settings: `---
208
+ name: settings
209
+ description: View and change Maestro toggles (terse, frontier, context-bar) via the settings CLI
210
+ ---
211
+
212
+ View or change **Maestro settings** for this project. The settings CLI manages
213
+ the three primary toggles: \`terse\`, \`frontier\`, and \`context-bar\`.
214
+
215
+ When the user invokes this skill, run the settings CLI from the repo root.
216
+ Do not edit settings files by hand.
217
+
218
+ ## Discover available commands
219
+
220
+ \`\`\`bash
221
+ node settings/cli.cjs --help
222
+ \`\`\`
223
+
224
+ If \`settings/cli.cjs\` is not present, run \`maestro --help\` to locate the
225
+ correct entry point.
226
+
227
+ ## Common operations
228
+
229
+ List current settings:
230
+
231
+ \`\`\`bash
232
+ node settings/cli.cjs
233
+ \`\`\`
234
+
235
+ Set a toggle:
236
+
237
+ \`\`\`bash
238
+ node settings/cli.cjs terse <off|lite|full|ultra>
239
+ node settings/cli.cjs frontier <off|single|fusion>
240
+ node settings/cli.cjs context-bar <on|off>
241
+ \`\`\`
242
+
243
+ If a subcommand name or argument differs from the above, follow the usage
244
+ printed by \`--help\` — do not guess flags.
245
+
246
+ ## Notes
247
+
248
+ - Changes persist in Maestro's settings store and apply to subsequent agent
249
+ turns in this project.
250
+ - Requires \`node\` on \`PATH\` and Maestro installed in the project root. If
251
+ \`settings/cli.cjs\` is missing, re-run the installer:
252
+ \`npx github:mbanderas/maestro install --target codex\`
253
+ `,
254
+ update: `---
255
+ name: update
256
+ description: Update Maestro to the latest version by re-running the installer for Codex
257
+ ---
258
+
259
+ Update **Maestro** to the latest marketplace code. This re-runs the installer,
260
+ which pulls the current release and overwrites the local Maestro files in place.
261
+
262
+ When the user invokes this skill, run the installer from the repo root:
263
+
264
+ \`\`\`bash
265
+ npx github:mbanderas/maestro install --target codex
266
+ \`\`\`
267
+
268
+ The installer is idempotent — it is safe to re-run against an existing
269
+ installation. It will:
270
+
271
+ - Pull the latest Maestro source from the repository.
272
+ - Overwrite skills, hooks, and settings scaffolding with the new versions.
273
+ - Leave project-local configuration (state files, secrets) untouched.
274
+
275
+ ## Notes
276
+
277
+ - Requires \`node\` and \`npx\` on \`PATH\`.
278
+ - Run from the project root so the installer targets the correct directory.
279
+ - After the installer completes, restart the Codex session (or reload the
280
+ project) so updated skills and hooks take effect.
281
+ - If \`npx\` is unavailable, clone \`https://github.com/mbanderas/maestro\`
282
+ manually and follow the repository's install instructions.
283
+ `,
284
+ };
56
285
 
57
286
  // Runtime adapter per target. The adapter imports @AGENTS.md (Cursor has no
58
287
  // imports, so .cursorrules embeds the kernel). codex/cline/windsurf read
@@ -132,6 +361,54 @@ function safeWrite(dest, content) {
132
361
  }
133
362
  }
134
363
 
364
+ function homeDir() {
365
+ return process.platform === 'win32'
366
+ ? (process.env.USERPROFILE || os.homedir())
367
+ : (process.env.HOME || os.homedir());
368
+ }
369
+
370
+ function sha256(content) {
371
+ return crypto.createHash('sha256').update(content, 'utf8').digest('hex');
372
+ }
373
+
374
+ function codexSkillManagedContent(name, srcContent) {
375
+ const body = srcContent.trimEnd() + '\n';
376
+ return `${body}\n<!-- maestro-managed:codex-skill name=${name} sha256=${sha256(body)} -->\n`;
377
+ }
378
+
379
+ function splitCodexSkillMarker(content) {
380
+ const marker = /\n?<!-- maestro-managed:codex-skill name=([^\s]+) sha256=([a-f0-9]+|0000) -->\s*$/i.exec(content);
381
+ if (!marker) return null;
382
+ return {
383
+ name: marker[1],
384
+ hash: marker[2].toLowerCase(),
385
+ body: content.slice(0, marker.index).trimEnd() + '\n',
386
+ };
387
+ }
388
+
389
+ function isManagedCodexSkillContent(content, expectedName, managedBodies) {
390
+ const marker = splitCodexSkillMarker(content);
391
+ if (marker && marker.name === expectedName) {
392
+ return marker.hash === '0000' || marker.hash === sha256(marker.body);
393
+ }
394
+ if (content.includes(`maestro-managed:codex-skill name=${expectedName} sha256=0000`)) {
395
+ return true;
396
+ }
397
+ return managedBodies.some((body) => content.trimEnd() === body.trimEnd());
398
+ }
399
+
400
+ function legacyCodexSkillContent(legacyName, namespacedName) {
401
+ const body = `---\nname: ${legacyName}\ndescription: Legacy Maestro compatibility skill for ${namespacedName}\n---\n\nThis legacy Maestro skill has moved to \`${namespacedName}\`.\n\nUse the \`${namespacedName}\` skill for current Maestro behavior. This compatibility skill is kept only for existing Codex installs that still reference \`${legacyName}\`.\n`;
402
+ return codexSkillManagedContent(legacyName, body);
403
+ }
404
+
405
+ function legacyGenericCodexTemplate(srcContent, legacyName, namespacedName) {
406
+ return srcContent.replace(
407
+ new RegExp(`(^---\\r?\\nname: )${namespacedName}(\\r?\\n)`, 'm'),
408
+ `$1${legacyName}$2`
409
+ );
410
+ }
411
+
135
412
  // ---- parse argv ----
136
413
 
137
414
  /**
@@ -361,7 +638,7 @@ function copyDirRecursive(srcDir, destDir, dryRun, log) {
361
638
  }
362
639
 
363
640
  /**
364
- * Install engine files (frontier/ dir + bin/maestro.cjs).
641
+ * Install engine files (frontier/ dir + settings/ dir + bin/maestro.cjs).
365
642
  * @param {string} projectRoot
366
643
  * @param {boolean} dryRun
367
644
  * @param {(msg: string) => void} log
@@ -370,10 +647,13 @@ function copyDirRecursive(srcDir, destDir, dryRun, log) {
370
647
  function installEngine(projectRoot, dryRun, log) {
371
648
  const srcFrontier = path.join(PKG_ROOT, 'frontier');
372
649
  const destFrontier = path.join(projectRoot, 'frontier');
650
+ const srcSettings = path.join(PKG_ROOT, 'settings');
651
+ const destSettings = path.join(projectRoot, 'settings');
373
652
  const srcBin = path.join(PKG_ROOT, 'bin', 'maestro.cjs');
374
653
  const destBin = path.join(projectRoot, 'bin', 'maestro.cjs');
375
654
 
376
655
  let ok = copyDirRecursive(srcFrontier, destFrontier, dryRun, log);
656
+ if (!copyDirRecursive(srcSettings, destSettings, dryRun, log)) ok = false;
377
657
 
378
658
  // bin/maestro.cjs
379
659
  if (dryRun) {
@@ -500,7 +780,7 @@ function installWrapper(target, projectRoot, userGlobal, dryRun, log) {
500
780
  log(`[wrapper] --user not supported for target ${target} — writing to project instead`);
501
781
  dest = path.join(projectRoot, mapping.proj);
502
782
  } else {
503
- dest = mapping.user;
783
+ dest = mapping.user();
504
784
  }
505
785
  } else {
506
786
  dest = path.join(projectRoot, mapping.proj);
@@ -510,7 +790,8 @@ function installWrapper(target, projectRoot, userGlobal, dryRun, log) {
510
790
  }
511
791
 
512
792
  /**
513
- * Install the Codex skill templates (no-clobber) alongside the codex wrapper.
793
+ * Install the Codex skill templates alongside the codex wrapper. Maestro-owned
794
+ * skill files refresh in place; user-edited copies are preserved.
514
795
  * Project mode -> <project>/.agents/skills/<name>/SKILL.md; --user/global mode
515
796
  * -> ~/.agents/skills/<name>/SKILL.md (mirrors installWrapper's dest logic).
516
797
  * @param {string} projectRoot
@@ -519,16 +800,139 @@ function installWrapper(target, projectRoot, userGlobal, dryRun, log) {
519
800
  * @param {(msg: string) => void} log
520
801
  * @returns {boolean}
521
802
  */
803
+ function installManagedCodexSkill(src, dest, name, legacyName, dryRun, log) {
804
+ let srcContent;
805
+ try {
806
+ srcContent = fs.readFileSync(src, 'utf8');
807
+ } catch (err) {
808
+ log(`ERROR: cannot read template ${src}: ${err.message}`);
809
+ return false;
810
+ }
811
+
812
+ const managedContent = codexSkillManagedContent(name, srcContent);
813
+ const managedBodies = [srcContent, managedContent];
814
+
815
+ let destStat;
816
+ try { destStat = fs.lstatSync(dest); } catch { destStat = null; }
817
+
818
+ if (destStat) {
819
+ if (destStat.isSymbolicLink()) {
820
+ log(`ERROR: codex-skill dest is a symlink — refusing: ${dest}`);
821
+ return false;
822
+ }
823
+
824
+ let existing;
825
+ try { existing = fs.readFileSync(dest, 'utf8'); } catch (err) {
826
+ log(`ERROR: cannot read existing Codex skill ${dest}: ${err.message}`);
827
+ return false;
828
+ }
829
+
830
+ if (!isManagedCodexSkillContent(existing, name, managedBodies)) {
831
+ log(`[codex-skill] preserved user-edited Codex skill: ${dest}`);
832
+ log(`[codex-skill] next step: compare with integrations/codex/skills/${name}/SKILL.md and manually merge if desired`);
833
+ return true;
834
+ }
835
+
836
+ if (existing === managedContent) {
837
+ log(`[codex-skill] up to date: ${dest}`);
838
+ return true;
839
+ }
840
+
841
+ if (dryRun) {
842
+ log(`[dry-run] would refresh managed Codex skill ${dest}`);
843
+ return true;
844
+ }
845
+
846
+ const res = safeWrite(dest, managedContent);
847
+ if (!res.ok) {
848
+ log(`ERROR: failed to refresh codex-skill ${dest}: ${res.reason}`);
849
+ return false;
850
+ }
851
+ log(`[codex-skill] refreshed managed Codex skill: ${dest}`);
852
+ return true;
853
+ }
854
+
855
+ if (dryRun) {
856
+ log(`[dry-run] would create ${dest}`);
857
+ return true;
858
+ }
859
+
860
+ if (!safeMkdirp(dest)) {
861
+ log(`ERROR: could not create parent dir for ${dest}`);
862
+ return false;
863
+ }
864
+
865
+ const res = safeWrite(dest, managedContent);
866
+ if (!res.ok) {
867
+ log(`ERROR: failed to write codex-skill ${dest}: ${res.reason}`);
868
+ return false;
869
+ }
870
+ log(`[codex-skill] wrote ${dest}`);
871
+ return true;
872
+ }
873
+
874
+ function migrateLegacyCodexSkill(dest, legacyName, namespacedName, knownTemplate, dryRun, log) {
875
+ let destStat;
876
+ try { destStat = fs.lstatSync(dest); } catch { return true; }
877
+
878
+ if (destStat.isSymbolicLink()) {
879
+ log(`ERROR: legacy codex-skill dest is a symlink — refusing: ${dest}`);
880
+ return false;
881
+ }
882
+
883
+ let existing;
884
+ try { existing = fs.readFileSync(dest, 'utf8'); } catch (err) {
885
+ log(`ERROR: cannot read legacy Codex skill ${dest}: ${err.message}`);
886
+ return false;
887
+ }
888
+
889
+ const shim = legacyCodexSkillContent(legacyName, namespacedName);
890
+ const managedBodies = [
891
+ knownTemplate,
892
+ legacyGenericCodexTemplate(knownTemplate, legacyName, namespacedName),
893
+ LEGACY_CODEX_SKILL_TEMPLATES[legacyName],
894
+ shim,
895
+ ].filter(Boolean);
896
+ if (!isManagedCodexSkillContent(existing, legacyName, managedBodies)) {
897
+ log(`[codex-skill] preserved user-edited legacy Codex skill: ${dest}`);
898
+ log(`[codex-skill] next step: rename or merge it into .agents/skills/${namespacedName}/SKILL.md if you still need custom behavior`);
899
+ return true;
900
+ }
901
+
902
+ if (existing === shim) {
903
+ log(`[codex-skill] legacy compatibility up to date: ${dest}`);
904
+ return true;
905
+ }
906
+
907
+ if (dryRun) {
908
+ log(`[dry-run] would migrate legacy Codex skill ${dest}`);
909
+ return true;
910
+ }
911
+
912
+ const res = safeWrite(dest, shim);
913
+ if (!res.ok) {
914
+ log(`ERROR: failed to migrate legacy codex-skill ${dest}: ${res.reason}`);
915
+ return false;
916
+ }
917
+ log(`[codex-skill] migrated legacy Codex skill to compatibility shim: ${dest}`);
918
+ return true;
919
+ }
920
+
522
921
  function installCodexSkills(projectRoot, userGlobal, dryRun, log) {
523
922
  const skillsRoot = userGlobal
524
- ? path.join(os.homedir(), '.agents', 'skills')
923
+ ? path.join(homeDir(), '.agents', 'skills')
525
924
  : path.join(projectRoot, '.agents', 'skills');
526
925
 
527
926
  let ok = true;
528
- for (const name of CODEX_SKILLS) {
529
- const src = path.join(PKG_ROOT, 'integrations', 'codex', 'skills', name, 'SKILL.md');
530
- const dest = path.join(skillsRoot, name, 'SKILL.md');
531
- if (!installNoClobberFile(src, dest, 'codex-skill', dryRun, log)) ok = false;
927
+ for (const skill of CODEX_SKILLS) {
928
+ const src = path.join(PKG_ROOT, 'integrations', 'codex', 'skills', skill.name, 'SKILL.md');
929
+ const dest = path.join(skillsRoot, skill.name, 'SKILL.md');
930
+ if (!installManagedCodexSkill(src, dest, skill.name, skill.legacy, dryRun, log)) ok = false;
931
+
932
+ let legacyTemplate = '';
933
+ try { legacyTemplate = fs.readFileSync(src, 'utf8'); } catch {}
934
+ const legacyDest = path.join(skillsRoot, skill.legacy, 'SKILL.md');
935
+ if (!migrateLegacyCodexSkill(legacyDest, skill.legacy, skill.name, legacyTemplate, dryRun, log)) ok = false;
532
936
  }
533
937
  return ok;
534
938
  }
@@ -602,4 +1006,9 @@ if (require.main === module) {
602
1006
  process.exit(code);
603
1007
  }
604
1008
 
605
- module.exports = { run };
1009
+ module.exports = {
1010
+ run,
1011
+ _test: {
1012
+ LEGACY_CODEX_SKILL_TEMPLATES,
1013
+ },
1014
+ };
package/settings/cli.cjs CHANGED
@@ -109,7 +109,7 @@ function usageText() {
109
109
  ' terse <off|lite|full|ultra>\n' +
110
110
  ' frontier <off | single:<model> | fusion:<preset>>\n' +
111
111
  ' context-bar <on|off>\n' +
112
- ' --scope targets a named frontier state (e.g. codex, cursor); omit to autodetect (Claude Code => per-workspace cc-<hash>)\n'
112
+ ' --scope targets a frontier state; use codex-project/codex-workspace for Codex repo scope, or an explicit name such as codex-global for shared state\n'
113
113
  );
114
114
  }
115
115
 
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: maestro-frontier
3
+ description: Maestro Frontier local multi-CLI fusion engine - arm, disarm, inspect, or debug-run the panel
4
+ ---
5
+
6
+ Drive the **Maestro Frontier** engine: a zero-dependency local multi-CLI fusion
7
+ engine where a parallel panel of local CLIs feeds a judge model's analysis and a
8
+ grounded synthesis.
9
+
10
+ When the Maestro Codex plugin hook is installed, enabled, and trusted, arming a
11
+ non-`off` mode makes normal later Codex prompts auto-run through Frontier until
12
+ you turn it off. Users should not need to type `maestro frontier run "<prompt>"`
13
+ for normal use.
14
+
15
+ Map the user's request to one engine CLI call and run it from the repo root.
16
+ Do not edit the engine's state file by hand.
17
+
18
+ ## Command launcher
19
+
20
+ Use `maestro` when it is on `PATH`. If it is not, and this skill is loaded
21
+ from the Maestro Codex plugin, locate the plugin root by walking up from this
22
+ `SKILL.md` until `.codex-plugin/plugin.json` is present, then run:
23
+
24
+ ```bash
25
+ node "<maestro-plugin-root>/bin/maestro.cjs" frontier ...
26
+ ```
27
+
28
+ In the examples below, `maestro frontier ...` means either the bare command or
29
+ that plugin-root `node .../bin/maestro.cjs frontier ...` form.
30
+
31
+ ## 1. Switch mode
32
+
33
+ Project/workspace scope is the default recommendation. Use `--scope
34
+ codex-project` from the repository root; the CLI expands it to the same
35
+ `codex-<8hex>` workspace scope the Codex plugin hook resolves from
36
+ `PLUGIN_ROOT` / `PLUGIN_DATA`. Default mode is `off`.
37
+
38
+ ```bash
39
+ maestro frontier mode off --scope codex-project
40
+ maestro frontier mode single --model <model> --scope codex-project
41
+ maestro frontier mode fusion --preset chatgpt-duo --scope codex-project
42
+ maestro frontier mode fusion --preset frontier-trio --judge chatgpt --synth chatgpt --scope codex-project
43
+ maestro frontier mode fusion --preset custom --models <a,b,c> --scope codex-project
44
+ ```
45
+
46
+ Models: `opus` (Claude Opus 4.8, needs `claude`), `gpt-5.5` (needs `codex`),
47
+ `gemini` (needs `gemini`). Presets: `opus-duo`, `opus-gpt`, `gpt-duo`,
48
+ `frontier-trio`, `custom`. Friendly aliases are accepted: `chatgpt` maps to
49
+ `gpt-5.5`, and `chatgpt-duo` maps to `gpt-duo`.
50
+
51
+ Judge + synth default to Opus except for presets with explicit stage defaults.
52
+ Override them for mixed panels with `--judge <model>` and `--synth <model>`;
53
+ for example, `--judge chatgpt --synth chatgpt`.
54
+
55
+ ## 2. Show current mode/preset
56
+
57
+ ```bash
58
+ maestro frontier status --scope codex-project
59
+ ```
60
+
61
+ If you intentionally want one shared Codex state across unrelated repos, choose
62
+ an explicit global name such as `--scope codex-global`. Do not use global scope
63
+ unless that cross-repo behavior is what you want.
64
+
65
+ ## 3. Normal use after arming
66
+
67
+ After mode is non-`off`, type ordinary Codex prompts. The trusted Codex hook
68
+ auto-runs Frontier and injects the synthesized answer as context for the live
69
+ reply. Turn it off with:
70
+
71
+ ```bash
72
+ maestro frontier mode off --scope codex-project
73
+ ```
74
+
75
+ ## 4. Advanced/debug one-off run
76
+
77
+ Manual one-off execution remains available for debugging:
78
+
79
+ ```bash
80
+ maestro frontier run "<prompt>" --scope codex-project
81
+ ```
82
+
83
+ - `off`: prints a notice, spawns nothing.
84
+ - `single`: dispatches the one selected CLI, prints its answer.
85
+ - `fusion`: runs the panel in parallel, then judge, then synthesizer; prints
86
+ the final answer (a one-line run meta goes to stderr). Report stdout verbatim.
87
+
88
+ On error the engine prints `ERROR [<reason>]: <detail>` to stderr and exits
89
+ non-zero; relay the reason.
90
+
91
+ ## Indicator instruction
92
+
93
+ <!-- INDICATOR INSTRUCTION - apply every turn while this skill is active -->
94
+
95
+ Before composing your first reply each turn, run:
96
+
97
+ ```bash
98
+ maestro frontier status --scope codex-project
99
+ ```
100
+
101
+ Parse the returned JSON `mode` field:
102
+
103
+ - If `mode` is not `off`, make the **first line** of your reply exactly:
104
+ `Maestro Frontier ON (<label>)`
105
+ where `<label>` is formed as follows:
106
+ - single mode -> `single - <model>` (e.g. `single - opus`)
107
+ - fusion mode -> `fusion - <preset>` (e.g. `fusion - frontier-trio`);
108
+ for a custom preset use `fusion - custom (<model1>, <model2>, ...)`
109
+ - If `mode` is `off`, output no indicator line.
110
+
111
+ <!-- END INDICATOR INSTRUCTION -->
112
+
113
+ ## Notes
114
+
115
+ - Real `single`/`fusion` runs spawn local CLIs and cost tokens; `off` is free.
116
+ - The autorun hook no-ops when `FUSION_DEPTH >= 1`, so child `codex`, `claude`,
117
+ and `gemini` panel processes do not recursively run Frontier.
118
+ - Each model's CLI must be on `PATH`, or point at a specific build with
119
+ `MAESTRO_CLAUDE_BIN` / `MAESTRO_CODEX_BIN` / `MAESTRO_GEMINI_BIN`.
120
+ - Requires `node` on `PATH`. The bare `maestro` command is optional when the
121
+ skill is loaded from the Maestro Codex plugin; use the plugin-root launcher
122
+ above.