Yeachan-Heo/oh-my-codex · error · UltragoalError
Missing --kind for structured ultragoal steer.
Error message
Missing --kind for structured ultragoal steer.
What it means
Structured ultragoal steering mutations require an explicit --kind naming the mutation type (the set ULTRAGOAL_STEERING_MUTATION_KINDS). parseSteeringKind throws immediately when --kind is absent, because the engine cannot infer which mutation you intend from flags alone.
Source
Thrown at src/cli/ultragoal.ts:223
const persistedRoleRoutingMarker = scope.sessionId
? readRoleRoutingMarker(scope.baseStateDir, { cwd: scope.cwd, sessionId: scope.sessionId })
: null;
return resolveNativeSubagentSupportStatus({
persistedSupportBlocker,
persistedRoleRoutingMarker,
persistedCapacityBlocker,
cwd: scope.cwd,
sessionId: scope.sessionId,
});
}
const STEERING_KINDS = new Set<UltragoalSteeringMutationKind>(ULTRAGOAL_STEERING_MUTATION_KINDS);
const STEERING_SOURCES = new Set<UltragoalSteeringSource>(ULTRAGOAL_STEERING_SOURCES);
type CliSteerResult = Awaited<ReturnType<typeof steerUltragoal>>;
function parseSteeringKind(raw: string | undefined): UltragoalSteeringMutationKind {
if (!raw) throw new UltragoalError('Missing --kind for structured ultragoal steer.');
if (!STEERING_KINDS.has(raw as UltragoalSteeringMutationKind)) throw new UltragoalError(`Invalid --kind: ${raw}. Expected one of ${Array.from(STEERING_KINDS).join(', ')}.`);
return raw as UltragoalSteeringMutationKind;
}
function parseSteeringSource(raw: string | undefined, fallback: UltragoalSteeringSource = 'cli'): UltragoalSteeringSource {
if (!raw) return fallback;
if (!STEERING_SOURCES.has(raw as UltragoalSteeringSource)) throw new UltragoalError(`Invalid --source: ${raw}. Expected one of ${Array.from(STEERING_SOURCES).join(', ')}.`);
return raw as UltragoalSteeringSource;
}
function assertPlainObject(value: unknown, label: string): Record<string, unknown> {
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new UltragoalError(`${label} must be a JSON object.`);
return value as Record<string, unknown>;
}
function normalizeTargetGoalId(raw: Record<string, unknown>): string | undefined {
if (typeof raw.targetGoalId === 'string' && raw.targetGoalId.trim()) return raw.targetGoalId.trim();
if (Array.isArray(raw.targetGoalIds)) return raw.targetGoalIds.find((id): id is string => typeof id === 'string' && id.trim().length > 0)?.trim();View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Add `--kind <mutation>` matching one of ULTRAGOAL_STEERING_MUTATION_KINDS (see the error's sibling message which lists them, or --help)
- Alternatively pass a complete proposal via --directive-json which includes kind inside the object
Example fix
# before omx ultragoal steer --evidence 'tests fail' --rationale 'pause goal' # Error: Missing --kind for structured ultragoal steer. # after omx ultragoal steer --kind add_goal --evidence 'tests fail' --rationale 'pause goal' --title g --objective o
Defensive patterns
Strategy: validation
Validate before calling
const KINDS: string[] = ['add_goal','update_goal','record_blocker' /* mirror ULTRAGOAL_STEERING_MUTATION_KINDS */];
if (!kind) throw new Error('steer requires --kind or --directive-json');
if (!KINDS.includes(kind)) throw new Error(`unknown kind ${kind}`); Type guard
function isSteeringKind(v: string | undefined, kinds: Set<string>): v is string {
return !!v && kinds.has(v);
} Prevention
- Keep a shared constants module for steering kinds used by scripts and the CLI
- Prefer --directive-json for compound proposals so kind lives in one document
When it happens
Trigger: Running `omx ultragoal steer --evidence e --rationale r` without --kind and without --directive-json (directive-json bypasses this path).
Common situations: Copy-pasting a steer example that predates structured kinds; assuming --after-json alone identifies the kind; forgetting the flag when migrating from freeform natural-language steering (which error 490 says is rejected).
Related errors
- Missing --evidence.
- Missing --rationale.
- omx ultragoal steer rejects broad natural-language mutation
- Missing brief text. Pass --brief, --brief-file, --from-stdin
- Missing --title.
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/1ac63008761a75dc.
Report an issue: GitHub.