Yeachan-Heo/oh-my-codex · error · UltragoalError
Missing --title.
Error message
Missing --title.
What it means
The add-goal subcommand requires --title (trimmed non-empty) so every goal has a human-readable name. Omitting the flag or passing whitespace triggers this immediate validation before addUltragoalGoal runs.
Source
Thrown at src/cli/ultragoal.ts:438
status: 'codex_goal_reconciliation_unavailable',
reason: reconciliation.snapshot.unavailableReason,
message: 'Codex goal DB/schema/context is unavailable; artifact-backed Ultragoal status remains available, but strict Codex goal completion reconciliation is deferred.',
}
: undefined;
if (json) printJson({ plan, summary: summarizeUltragoalPlan(plan), reconciliation, codexGoalFallback });
else {
printStatus(plan);
if (codexGoalFallback) console.log(`codex goal fallback: ${codexGoalFallback.message}`);
if (reconciliation && !reconciliation.ok) console.log(`codex goal warning: ${formatCodexGoalReconciliation(reconciliation)}`);
else if (reconciliation?.warnings.length) console.log(`codex goal warning: ${formatCodexGoalReconciliation(reconciliation)}`);
}
return;
}
if (command === 'add-goal') {
const title = readValue(rest, '--title');
const objective = readValue(rest, '--objective');
if (!title?.trim()) throw new UltragoalError('Missing --title.');
if (!objective?.trim()) throw new UltragoalError('Missing --objective.');
const result = await addUltragoalGoal(cwd, { title, objective, evidence: readValue(rest, '--evidence') });
if (json) printJson({ ok: true, plan: result.plan, addedGoal: result.goal, summary: summarizeUltragoalPlan(result.plan) });
else {
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);View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Add a concise `--title "Goal name"`
- Quote shell variables and default them: `--title "${TITLE:?set TITLE}"`
Example fix
# before omx ultragoal add-goal --objective 'migrate db' # Error: Missing --title. # after omx ultragoal add-goal --title 'DB migration' --objective 'migrate db to v2'
Defensive patterns
Strategy: validation
Validate before calling
if (!title?.trim()) { console.error('--title required'); process.exit(2); } Type guard
function isNonEmptyString(v: string | undefined | null): v is string {
return typeof v === 'string' && v.trim().length > 0;
} Prevention
- Use `${TITLE:?}` shell guards for flag values sourced from env
- Keep a checklist of required flags for add-goal: title + objective
When it happens
Trigger: `omx ultragoal add-goal --objective 'do x'` without --title; or `--title " "`.
Common situations: Assuming title is derived from objective; flag renamed between versions; whitespace from unquoted shell variable expansion (`--title "$TITLE"` with empty var).
Related errors
- Missing --kind for structured ultragoal steer.
- Missing brief text. Pass --brief, --brief-file, --from-stdin
- Missing --objective.
- Missing --evidence.
- Missing --rationale.
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/4ef8cdddc3cdf593.
Report an issue: GitHub.