Yeachan-Heo/oh-my-codex · error · UltragoalError

Invalid --codex-goal-mode; expected aggregate or per-story.

Error message

Invalid --codex-goal-mode; expected aggregate or per-story.

What it means

The --codex-goal-mode flag for `omx ultragoal create` accepts only the strings 'aggregate', 'per-story', or 'per_story'. normalizeCodexGoalMode throws UltragoalError for anything else, including common guesses like 'perStory' or 'story'.

Source

Thrown at src/cli/ultragoal.ts:140

  const words: string[] = [];
  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    if (valueTaking.has(arg)) { i += 1; continue; }
    if (arg.startsWith('--')) continue;
    words.push(arg);
  }
  return words.join(' ').trim();
}

function printJson(value: unknown): void {
  console.log(JSON.stringify(value, null, 2));
}

function normalizeCodexGoalMode(raw: string | undefined): 'aggregate' | 'per_story' | undefined {
  if (!raw) return undefined;
  if (raw === 'aggregate') return 'aggregate';
  if (raw === 'per-story' || raw === 'per_story') return 'per_story';
  throw new UltragoalError('Invalid --codex-goal-mode; expected aggregate or per-story.');
}

function printStatus(plan: Awaited<ReturnType<typeof readUltragoalPlan>>): void {
  const summary = summarizeUltragoalPlan(plan);
  if (summary.aggregateComplete) {
    console.log('ultragoal aggregate product: complete');
    console.log(`microgoal ledger bookkeeping (progress-only): ${summary.complete}/${summary.total} complete, ${summary.pending} pending, ${summary.inProgress} in progress, ${summary.failed} failed, ${summary.reviewBlocked} review-blocked, ${summary.needsUserDecision} needs-user-decision`);
  } else if (summary.artifactComplete) {
    console.log('ultragoal artifact goals: complete');
    console.log(`codex goal reconciliation: not recorded in OMX aggregateCompletion; status is artifact-backed until a fresh Codex goal snapshot is available.`);
    console.log(`microgoal ledger: ${summary.complete}/${summary.total} complete, ${summary.pending} pending, ${summary.inProgress} in progress, ${summary.failed} failed, ${summary.reviewBlocked} review-blocked, ${summary.needsUserDecision} needs-user-decision`);
  } else {
    console.log(`ultragoal: ${summary.complete}/${summary.total} complete, ${summary.pending} pending, ${summary.inProgress} in progress, ${summary.failed} failed, ${summary.reviewBlocked} review-blocked, ${summary.needsUserDecision} needs-user-decision`);
  }
  for (const goal of plan.goals) {
    const marker = goal.id === plan.activeGoalId ? '*' : '-';
    console.log(`${marker} ${goal.id} [${goal.status}] ${goal.title}`);
  }

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Use exactly `--codex-goal-mode aggregate` or `--codex-goal-mode per-story` (underscore `per_story` also accepted)
  2. Omit the flag entirely if you want the default mode
  3. Check `omx ultragoal --help` for the current enum values on your version

Example fix

# before
omx ultragoal create --brief b.txt --codex-goal-mode perStory
# Error: Invalid --codex-goal-mode; expected aggregate or per-story.

# after
omx ultragoal create --brief b.txt --codex-goal-mode per-story
Defensive patterns

Strategy: type-guard

Validate before calling

const MODES = new Set(['aggregate', 'per-story', 'per_story'] as const);
const mode = process.env.UG_MODE;
if (mode && !MODES.has(mode as any)) throw new Error(`bad mode ${mode}`);

Type guard

function isCodexGoalMode(v: string): v is 'aggregate' | 'per-story' | 'per_story' {
  return v === 'aggregate' || v === 'per-story' || v === 'per_story';
}

Prevention

When it happens

Trigger: Passing `--codex-goal-mode perStory` / `stories` / `none` / any string other than the three accepted spellings to `omx ultragoal create` (or create-goals).

Common situations: Guessing flag values from camelCase habit; typo 'per_story' vs 'per-store'; docs/README examples out of sync with the CLI's accepted enum.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/7b38d2b85f242bc1. Report an issue: GitHub.