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

Missing --evidence.

Error message

Missing --evidence.

What it means

Every structured steering proposal must carry non-empty evidence (why the mutation is justified) — enforced after parseSteeringProposal in the steer command. Both --evidence as a flag and evidence inside --after-json/--directive-json count; the guard uses evidence?.trim?.() so proposals lacking the field entirely also fail.

Source

Thrown at src/cli/ultragoal.ts:461

        console.log(`ultragoal added goal: ${result.goal.id}`);
        printStatus(result.plan);
      }
      return;
    }

    if (command === 'steer') {
      const proposalText = readValue(rest, '--proposal');
      const source = readValue(rest, '--source');
      if (proposalText) {
        const parsed = assertPlainObject(await readJsonInput(proposalText, '--proposal'), '--proposal');
        const proposal = normalizeSteeringProposal({ ...parsed, source: source ?? parsed.source }, proposalText);
        const result = await steerUltragoal(cwd, proposal, { directiveText: proposalText });
        printSteerResult(proposal, result, json);
        if (!result.accepted) process.exitCode = 1;
        return;
      }
      const proposal = await parseSteeringProposal(rest);
      if (!proposal.evidence?.trim?.()) throw new UltragoalError('Missing --evidence.');
      if (!proposal.rationale?.trim?.()) throw new UltragoalError('Missing --rationale.');
      proposal.source = parseSteeringSource(source, proposal.source);
      const result = await steerUltragoal(cwd, proposal, { directiveText: buildSteerDirectiveText(rest) });
      printSteerResult(proposal, result, json);
      if (!result.accepted) process.exitCode = 1;
      return;
    }

    if (command === 'record-review-blockers') {
      const goalId = readValue(rest, '--goal-id');
      const title = readValue(rest, '--title');
      const objective = readValue(rest, '--objective');
      const evidence = readValue(rest, '--evidence');
      if (!goalId) throw new UltragoalError('Missing --goal-id.');
      if (!title?.trim()) throw new UltragoalError('Missing --title.');
      if (!objective?.trim()) throw new UltragoalError('Missing --objective.');
      if (!evidence?.trim()) throw new UltragoalError('Missing --evidence.');
      const codexGoal = await parseCodexGoalJson(readValue(rest, '--codex-goal-json'));

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Add `--evidence "..."` citing concrete artifacts (test run, log, review link)
  2. If using --after-json/--directive-json, include a non-empty "evidence" string in the object

Example fix

# before
omx ultragoal steer --kind update_goal --goal-id g1 --status paused --rationale 'flaky'
# Error: Missing --evidence.

# after
omx ultragoal steer --kind update_goal --goal-id g1 --status paused --evidence 'ci run 1234 red' --rationale 'flaky'
Defensive patterns

Strategy: validation

Validate before calling

if (!evidence?.trim()) { console.error('steer requires non-empty --evidence'); process.exit(2); }

Type guard

function hasEvidence(p: { evidence?: string }): boolean {
  return typeof p.evidence === 'string' && p.evidence.trim().length > 0;
}

Prevention

When it happens

Trigger: `omx ultragoal steer --kind update_goal ...` with no --evidence and no evidence key in the JSON proposal; or evidence being only whitespace.

Common situations: Treating evidence as optional metadata; proposal JSON built programmatically that omits evidence; merging older proposal templates without the field.

Related errors


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