@gajae-code/coding-agent 0.2.0 → 0.2.2

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.
Files changed (114) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/dist/types/cli/skills-cli.d.ts +9 -0
  3. package/dist/types/commands/contribution-prep.d.ts +18 -0
  4. package/dist/types/commands/session.d.ts +24 -0
  5. package/dist/types/commands/skills.d.ts +26 -0
  6. package/dist/types/config/model-registry.d.ts +33 -4
  7. package/dist/types/config/models-config-schema.d.ts +52 -5
  8. package/dist/types/config/settings-schema.d.ts +1 -24
  9. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +15 -0
  10. package/dist/types/gjc-runtime/goal-mode-request.d.ts +1 -1
  11. package/dist/types/gjc-runtime/launch-tmux.d.ts +12 -11
  12. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +25 -0
  13. package/dist/types/gjc-runtime/state-runtime.d.ts +13 -0
  14. package/dist/types/gjc-runtime/team-runtime.d.ts +37 -5
  15. package/dist/types/gjc-runtime/tmux-common.d.ts +41 -0
  16. package/dist/types/gjc-runtime/tmux-sessions.d.ts +17 -0
  17. package/dist/types/goals/runtime.d.ts +3 -9
  18. package/dist/types/goals/state.d.ts +3 -6
  19. package/dist/types/goals/tools/goal-tool.d.ts +1 -69
  20. package/dist/types/modes/components/model-selector.d.ts +21 -1
  21. package/dist/types/modes/components/status-line/types.d.ts +0 -3
  22. package/dist/types/modes/components/status-line.d.ts +0 -3
  23. package/dist/types/modes/controllers/command-controller.d.ts +1 -0
  24. package/dist/types/modes/interactive-mode.d.ts +1 -12
  25. package/dist/types/modes/theme/defaults/index.d.ts +0 -2
  26. package/dist/types/modes/theme/theme.d.ts +1 -2
  27. package/dist/types/modes/types.d.ts +1 -7
  28. package/dist/types/session/agent-session.d.ts +2 -0
  29. package/dist/types/session/contribution-prep.d.ts +47 -0
  30. package/dist/types/skill-state/active-state.d.ts +4 -0
  31. package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +6 -1
  32. package/dist/types/skill-state/workflow-hud.d.ts +9 -4
  33. package/dist/types/skill-state/workflow-state-contract.d.ts +34 -0
  34. package/dist/types/slash-commands/builtin-registry.d.ts +1 -0
  35. package/package.json +7 -7
  36. package/src/cli/args.ts +17 -2
  37. package/src/cli/skills-cli.ts +88 -0
  38. package/src/cli.ts +7 -1
  39. package/src/commands/contribution-prep.ts +41 -0
  40. package/src/commands/deep-interview.ts +6 -22
  41. package/src/commands/launch.ts +10 -1
  42. package/src/commands/ralplan.ts +10 -22
  43. package/src/commands/session.ts +150 -0
  44. package/src/commands/skills.ts +48 -0
  45. package/src/commands/state.ts +14 -4
  46. package/src/commands/team.ts +23 -3
  47. package/src/commit/agentic/index.ts +1 -0
  48. package/src/commit/pipeline.ts +1 -0
  49. package/src/config/model-registry.ts +269 -10
  50. package/src/config/models-config-schema.ts +124 -88
  51. package/src/config/settings-schema.ts +1 -25
  52. package/src/config.ts +1 -1
  53. package/src/defaults/gjc/skills/deep-interview/SKILL.md +14 -13
  54. package/src/defaults/gjc/skills/ralplan/SKILL.md +14 -2
  55. package/src/defaults/gjc/skills/team/SKILL.md +29 -7
  56. package/src/defaults/gjc/skills/ultragoal/SKILL.md +23 -25
  57. package/src/eval/py/prelude.py +1 -1
  58. package/src/gjc-runtime/deep-interview-runtime.ts +279 -0
  59. package/src/gjc-runtime/goal-mode-request.ts +2 -19
  60. package/src/gjc-runtime/launch-tmux.ts +83 -43
  61. package/src/gjc-runtime/ralplan-runtime.ts +460 -0
  62. package/src/gjc-runtime/state-runtime.ts +562 -0
  63. package/src/gjc-runtime/team-runtime.ts +708 -52
  64. package/src/gjc-runtime/tmux-common.ts +119 -0
  65. package/src/gjc-runtime/tmux-sessions.ts +165 -0
  66. package/src/gjc-runtime/ultragoal-guard.ts +6 -3
  67. package/src/gjc-runtime/ultragoal-runtime.ts +5 -4
  68. package/src/goals/runtime.ts +38 -144
  69. package/src/goals/state.ts +36 -7
  70. package/src/goals/tools/goal-tool.ts +15 -172
  71. package/src/hooks/skill-state.ts +31 -12
  72. package/src/internal-urls/docs-index.generated.ts +4 -3
  73. package/src/main.ts +10 -1
  74. package/src/modes/components/model-selector.ts +109 -28
  75. package/src/modes/components/skill-hud/render.ts +4 -0
  76. package/src/modes/components/status-line/segments.ts +5 -16
  77. package/src/modes/components/status-line/types.ts +0 -3
  78. package/src/modes/components/status-line.ts +0 -6
  79. package/src/modes/controllers/command-controller.ts +25 -1
  80. package/src/modes/controllers/input-controller.ts +0 -15
  81. package/src/modes/controllers/selector-controller.ts +42 -2
  82. package/src/modes/interactive-mode.ts +18 -219
  83. package/src/modes/theme/defaults/dark-poimandres.json +0 -1
  84. package/src/modes/theme/defaults/light-poimandres.json +0 -1
  85. package/src/modes/theme/theme.ts +0 -6
  86. package/src/modes/types.ts +1 -7
  87. package/src/prompts/goals/goal-continuation.md +1 -4
  88. package/src/prompts/goals/goal-mode-active.md +3 -5
  89. package/src/prompts/system/system-prompt.md +5 -7
  90. package/src/prompts/tools/goal.md +4 -4
  91. package/src/sdk.ts +2 -1
  92. package/src/session/agent-session.ts +18 -0
  93. package/src/session/contribution-prep.ts +320 -0
  94. package/src/setup/provider-onboarding.ts +2 -0
  95. package/src/skill-state/active-state.ts +38 -0
  96. package/src/skill-state/deep-interview-mutation-guard.ts +88 -24
  97. package/src/skill-state/workflow-hud.ts +23 -5
  98. package/src/skill-state/workflow-state-contract.ts +121 -0
  99. package/src/slash-commands/acp-builtins.ts +11 -2
  100. package/src/slash-commands/builtin-registry.ts +40 -13
  101. package/src/task/commands.ts +1 -5
  102. package/src/tools/gh.ts +212 -2
  103. package/src/tools/index.ts +2 -5
  104. package/dist/types/commands/gjc-runtime-bridge.d.ts +0 -30
  105. package/dist/types/commands/question.d.ts +0 -7
  106. package/dist/types/modes/loop-limit.d.ts +0 -22
  107. package/src/commands/gjc-runtime-bridge.ts +0 -227
  108. package/src/commands/question.ts +0 -12
  109. package/src/modes/loop-limit.ts +0 -140
  110. package/src/prompts/commands/orchestrate.md +0 -49
  111. package/src/prompts/goals/goal-budget-limit.md +0 -16
  112. package/src/prompts/tools/create-goal.md +0 -3
  113. package/src/prompts/tools/get-goal.md +0 -3
  114. package/src/prompts/tools/update-goal.md +0 -3
@@ -6,92 +6,50 @@ import * as z from "zod/v4";
6
6
  import type { RenderResultOptions } from "../../extensibility/custom-tools/types";
7
7
  import { assertCanCompleteCurrentGoal } from "../../gjc-runtime/ultragoal-guard";
8
8
  import type { Theme, ThemeColor } from "../../modes/theme/theme";
9
- import createGoalDescription from "../../prompts/tools/create-goal.md" with { type: "text" };
10
- import getGoalDescription from "../../prompts/tools/get-goal.md" with { type: "text" };
11
9
  import goalDescription from "../../prompts/tools/goal.md" with { type: "text" };
12
- import updateGoalDescription from "../../prompts/tools/update-goal.md" with { type: "text" };
13
10
  import { formatDuration } from "../../slash-commands/helpers/format";
14
11
  import type { ToolSession } from "../../tools";
15
12
  import { formatErrorMessage, TRUNCATE_LENGTHS } from "../../tools/render-utils";
16
13
  import { ToolError } from "../../tools/tool-errors";
17
14
  import { renderStatusLine, truncateToWidth } from "../../tui";
18
- import { completionBudgetReport, remainingTokens, validateGoalObjective } from "../runtime";
15
+ import { validateGoalObjective } from "../runtime";
19
16
  import type { Goal, GoalStatus, GoalToolDetails } from "../state";
20
17
 
21
18
  const goalSchema = z.object({
22
19
  op: z.enum(["create", "get", "complete", "resume", "drop"]).describe("goal operation"),
23
20
  objective: z.string().describe("goal objective").optional(),
24
- token_budget: z.number().int().describe("token budget").optional(),
25
- });
26
-
27
- const getGoalSchema = z.object({});
28
-
29
- const createGoalSchema = z.object({
30
- objective: z.string().describe("goal objective"),
31
- token_budget: z.number().int().describe("token budget").optional(),
32
- });
33
-
34
- const updateGoalSchema = z.object({
35
- status: z.enum(["complete", "dropped"]).describe("new goal status"),
36
21
  });
37
22
 
38
23
  export type GoalToolInput = z.infer<typeof goalSchema>;
39
- export type GetGoalToolInput = z.infer<typeof getGoalSchema>;
40
- export type CreateGoalToolInput = z.infer<typeof createGoalSchema>;
41
- export type UpdateGoalToolInput = z.infer<typeof updateGoalSchema>;
42
24
 
43
25
  export interface GoalToolResponse {
44
26
  goal: Goal | null;
45
- remainingTokens: number | null;
46
- completionBudgetReport: string | null;
47
27
  }
48
28
 
49
- export function buildGoalToolResponse(
50
- goal: Goal | null | undefined,
51
- options?: { includeCompletionReport?: boolean },
52
- ): GoalToolResponse {
53
- const resolvedGoal = goal ?? null;
54
- return {
55
- goal: resolvedGoal,
56
- remainingTokens: remainingTokens(resolvedGoal),
57
- completionBudgetReport:
58
- options?.includeCompletionReport && resolvedGoal?.status === "complete"
59
- ? completionBudgetReport(resolvedGoal)
60
- : null,
61
- };
29
+ export function buildGoalToolResponse(goal: Goal | null | undefined): GoalToolResponse {
30
+ return { goal: goal ?? null };
31
+ }
32
+
33
+ function rejectUnsupportedGoalArgs(params: Record<string, unknown>): void {
34
+ if ("token_budget" in params || "tokenBudget" in params) {
35
+ throw new ToolError("token_budget is not supported for goals");
36
+ }
62
37
  }
63
38
 
64
- function validateCreateParams(params: { objective?: string; token_budget?: number }): {
65
- objective: string;
66
- tokenBudget?: number;
67
- } {
39
+ function validateCreateParams(params: { objective?: string }): { objective: string } {
68
40
  let objective: string;
69
41
  try {
70
42
  objective = validateGoalObjective(params.objective ?? "", "create");
71
43
  } catch (error) {
72
44
  throw new ToolError(error instanceof Error ? error.message : String(error));
73
45
  }
74
- const tokenBudget = params.token_budget;
75
- if (tokenBudget !== undefined && (!Number.isInteger(tokenBudget) || tokenBudget <= 0)) {
76
- throw new ToolError("token_budget must be a positive integer when provided");
77
- }
78
- return { objective, tokenBudget };
46
+ return { objective };
79
47
  }
80
48
 
81
49
  function renderGoalToolResponse(response: GoalToolResponse): string {
82
50
  if (!response.goal) return "No active goal.";
83
51
 
84
- let text = `Goal: ${response.goal.objective}\nStatus: ${response.goal.status}\nTokens: ${response.goal.tokensUsed} used`;
85
- if (response.goal.tokenBudget !== undefined) {
86
- text += ` / ${response.goal.tokenBudget} budget`;
87
- }
88
- if (response.remainingTokens !== null) {
89
- text += `\nRemaining tokens: ${response.remainingTokens}`;
90
- }
91
- if (response.completionBudgetReport) {
92
- text += `\n\n${response.completionBudgetReport}`;
93
- }
94
- return text;
52
+ return `Goal: ${response.goal.objective}\nStatus: ${response.goal.status}\nTokens used: ${response.goal.tokensUsed}`;
95
53
  }
96
54
 
97
55
  function buildGoalToolResult(op: GoalToolDetails["op"], response: GoalToolResponse): AgentToolResult<GoalToolDetails> {
@@ -100,13 +58,12 @@ function buildGoalToolResult(op: GoalToolDetails["op"], response: GoalToolRespon
100
58
  details: {
101
59
  op,
102
60
  goal: response.goal,
103
- remainingTokens: response.remainingTokens,
104
- completionBudgetReport: response.completionBudgetReport,
105
61
  },
106
62
  };
107
63
  }
108
64
 
109
65
  async function executeGoalOperation(session: ToolSession, params: GoalToolInput): Promise<GoalToolResponse> {
66
+ rejectUnsupportedGoalArgs(params as Record<string, unknown>);
110
67
  if (params.op === "get") {
111
68
  const state = session.getGoalModeState?.();
112
69
  return buildGoalToolResponse(state?.goal ?? null);
@@ -135,7 +92,7 @@ async function executeGoalOperation(session: ToolSession, params: GoalToolInput)
135
92
  throw new ToolError(error instanceof Error ? error.message : String(error));
136
93
  }
137
94
  const completed = await runtime.completeGoalFromTool();
138
- return buildGoalToolResponse(completed, { includeCompletionReport: true });
95
+ return buildGoalToolResponse(completed);
139
96
  }
140
97
 
141
98
  export class GoalTool implements AgentTool<typeof goalSchema, GoalToolDetails> {
@@ -164,102 +121,6 @@ export class GoalTool implements AgentTool<typeof goalSchema, GoalToolDetails> {
164
121
  }
165
122
  }
166
123
 
167
- export class GetGoalTool implements AgentTool<typeof getGoalSchema, GoalToolDetails> {
168
- readonly name = "get_goal";
169
- readonly label = "Get Goal";
170
- readonly loadMode = "essential" as const;
171
- readonly description = prompt.render(getGoalDescription);
172
- readonly parameters = getGoalSchema;
173
- readonly strict = true;
174
- readonly intent = "omit" as const;
175
- readonly #session: ToolSession;
176
-
177
- static createIf(session: ToolSession): GetGoalTool | null {
178
- return session.getGoalModeState || session.getGoalRuntime ? new GetGoalTool(session) : null;
179
- }
180
-
181
- constructor(session: ToolSession) {
182
- this.#session = session;
183
- }
184
-
185
- async execute(
186
- _toolCallId: string,
187
- _params: GetGoalToolInput,
188
- _signal?: AbortSignal,
189
- _onUpdate?: AgentToolUpdateCallback<GoalToolDetails>,
190
- _context?: AgentToolContext,
191
- ): Promise<AgentToolResult<GoalToolDetails>> {
192
- const response = await executeGoalOperation(this.#session, { op: "get" });
193
- return buildGoalToolResult("get", response);
194
- }
195
- }
196
-
197
- export class CreateGoalTool implements AgentTool<typeof createGoalSchema, GoalToolDetails> {
198
- readonly name = "create_goal";
199
- readonly label = "Create Goal";
200
- readonly loadMode = "essential" as const;
201
- readonly description = prompt.render(createGoalDescription);
202
- readonly parameters = createGoalSchema;
203
- readonly strict = true;
204
- readonly intent = "omit" as const;
205
- readonly #session: ToolSession;
206
-
207
- static createIf(session: ToolSession): CreateGoalTool | null {
208
- return session.getGoalRuntime ? new CreateGoalTool(session) : null;
209
- }
210
-
211
- constructor(session: ToolSession) {
212
- this.#session = session;
213
- }
214
-
215
- async execute(
216
- _toolCallId: string,
217
- params: CreateGoalToolInput,
218
- _signal?: AbortSignal,
219
- _onUpdate?: AgentToolUpdateCallback<GoalToolDetails>,
220
- _context?: AgentToolContext,
221
- ): Promise<AgentToolResult<GoalToolDetails>> {
222
- const response = await executeGoalOperation(this.#session, {
223
- op: "create",
224
- objective: params.objective,
225
- token_budget: params.token_budget,
226
- });
227
- return buildGoalToolResult("create", response);
228
- }
229
- }
230
-
231
- export class UpdateGoalTool implements AgentTool<typeof updateGoalSchema, GoalToolDetails> {
232
- readonly name = "update_goal";
233
- readonly label = "Update Goal";
234
- readonly loadMode = "essential" as const;
235
- readonly description = prompt.render(updateGoalDescription);
236
- readonly parameters = updateGoalSchema;
237
- readonly strict = true;
238
- readonly intent = "omit" as const;
239
- readonly #session: ToolSession;
240
-
241
- static createIf(session: ToolSession): UpdateGoalTool | null {
242
- return session.getGoalRuntime ? new UpdateGoalTool(session) : null;
243
- }
244
-
245
- constructor(session: ToolSession) {
246
- this.#session = session;
247
- }
248
-
249
- async execute(
250
- _toolCallId: string,
251
- params: UpdateGoalToolInput,
252
- _signal?: AbortSignal,
253
- _onUpdate?: AgentToolUpdateCallback<GoalToolDetails>,
254
- _context?: AgentToolContext,
255
- ): Promise<AgentToolResult<GoalToolDetails>> {
256
- const response = await executeGoalOperation(this.#session, {
257
- op: params.status === "dropped" ? "drop" : "complete",
258
- });
259
- return buildGoalToolResult(params.status === "dropped" ? "drop" : "complete", response);
260
- }
261
- }
262
-
263
124
  function describeOp(op: string | undefined): string {
264
125
  switch (op) {
265
126
  case "create":
@@ -281,8 +142,6 @@ function goalBadgeColor(status: GoalStatus): ThemeColor {
281
142
  switch (status) {
282
143
  case "complete":
283
144
  return "success";
284
- case "budget-limited":
285
- return "warning";
286
145
  case "paused":
287
146
  case "dropped":
288
147
  return "muted";
@@ -294,7 +153,6 @@ function goalBadgeColor(status: GoalStatus): ThemeColor {
294
153
  interface GoalRenderArgs {
295
154
  op?: GoalToolInput["op"];
296
155
  objective?: string;
297
- token_budget?: number;
298
156
  }
299
157
 
300
158
  export const goalToolRenderer = {
@@ -306,9 +164,6 @@ export const goalToolRenderer = {
306
164
  const objective = truncateToWidth(trimmedObjective, TRUNCATE_LENGTHS.TITLE);
307
165
  meta.push(uiTheme.italic(uiTheme.fg("muted", `"${objective}"`)));
308
166
  }
309
- if (args.op === "create" && args.token_budget !== undefined) {
310
- meta.push(`budget ${formatNumber(args.token_budget)}`);
311
- }
312
167
  const text = renderStatusLine({ icon: "pending", title: "Goal", description, meta }, uiTheme);
313
168
  return new Text(text, 0, 0);
314
169
  },
@@ -352,24 +207,12 @@ export const goalToolRenderer = {
352
207
 
353
208
  const objectiveText = truncateToWidth(goal.objective.trim(), TRUNCATE_LENGTHS.LONG);
354
209
  lines.push(` ${uiTheme.italic(uiTheme.fg("muted", `"${objectiveText}"`))}`);
355
-
356
- const used = formatNumber(goal.tokensUsed);
357
- const tokensLine =
358
- goal.tokenBudget !== undefined
359
- ? `${used} / ${formatNumber(goal.tokenBudget)} tokens (${formatNumber(Math.max(0, goal.tokenBudget - goal.tokensUsed))} left)`
360
- : `${used} tokens`;
361
- lines.push(` ${uiTheme.fg("dim", tokensLine)}`);
210
+ lines.push(` ${uiTheme.fg("dim", `${formatNumber(goal.tokensUsed)} tokens used`)}`);
362
211
 
363
212
  if (goal.timeUsedSeconds > 0) {
364
213
  lines.push(` ${uiTheme.fg("dim", `${formatDuration(goal.timeUsedSeconds * 1000)} elapsed`)}`);
365
214
  }
366
215
 
367
- const report = details?.completionBudgetReport;
368
- if (report) {
369
- lines.push("");
370
- lines.push(uiTheme.italic(uiTheme.fg("muted", report)));
371
- }
372
-
373
216
  return new Text(lines.join("\n"), 0, 0);
374
217
  },
375
218
 
@@ -21,6 +21,7 @@ export interface EffectiveSkillConfigInput {
21
21
  }
22
22
 
23
23
  const SANITIZED_CONFIG_VALUE_LIMIT = 80;
24
+ const DEFAULT_DEEP_INTERVIEW_AMBIGUITY_THRESHOLD = 0.05;
24
25
 
25
26
  function sanitizeConfigValue(value: string): string {
26
27
  const compact = value.replace(/[\r\n\t]+/g, " ").trim();
@@ -329,6 +330,10 @@ export async function recordSkillActivation(input: RecordSkillActivationInput):
329
330
  ...(input.threadId ? { thread_id: input.threadId } : {}),
330
331
  ...(input.turnId ? { turn_id: input.turnId } : {}),
331
332
  };
333
+ if (match.skill === "deep-interview") {
334
+ modeState.threshold = DEFAULT_DEEP_INTERVIEW_AMBIGUITY_THRESHOLD;
335
+ modeState.threshold_source = "default";
336
+ }
332
337
 
333
338
  await writeJsonFile(initializedStatePath, modeState);
334
339
  await writeJsonFile(skillStatePath(resolvedStateDir, input.sessionId), state);
@@ -389,20 +394,34 @@ export async function buildActiveUltragoalPromptContext(input: UserPromptSubmitS
389
394
  if (!stateMatchesContext(visibleModeState.state, input.sessionId, input.threadId)) return null;
390
395
 
391
396
  const phase = String(visibleModeState.state.current_phase ?? "active");
392
- const objective =
393
- (await readCurrentGoalObjectiveFromSessionFile(input.sessionFile)) ??
394
- (typeof visibleModeState.state.objective === "string"
397
+ const stateObjective =
398
+ typeof visibleModeState.state.objective === "string"
395
399
  ? visibleModeState.state.objective
396
400
  : typeof visibleModeState.state.gjcObjective === "string"
397
401
  ? visibleModeState.state.gjcObjective
398
- : "");
399
- if (input.prompt && isUltragoalBypassPrompt(input.prompt) && objective) {
400
- const diagnostic = await readUltragoalVerificationState({
401
- cwd: input.cwd,
402
- currentGoal: { objective },
403
- });
404
- if (!["inactive", "unrelated_goal", "active_verified_complete"].includes(diagnostic.state)) {
405
- return `BLOCK_ULTRAGOAL_COMPLETION: ${diagnostic.message} Use durable blocker work or run strict \`gjc ultragoal checkpoint --status complete --quality-gate-json <file> --gjc-goal-json <file>\` before completion.`;
402
+ : "";
403
+ const sessionObjective = await readCurrentGoalObjectiveFromSessionFile(input.sessionFile);
404
+ const normalizedPrompt = input.prompt?.replace(/\\?"/g, '"');
405
+ const isBypassPrompt = Boolean(
406
+ (normalizedPrompt && isUltragoalBypassPrompt(normalizedPrompt)) ||
407
+ (input.prompt && /goal[\s\S]{0,80}complete/i.test(input.prompt)),
408
+ );
409
+ if (isBypassPrompt) {
410
+ const objectives = [sessionObjective, stateObjective].filter(
411
+ (value): value is string => typeof value === "string" && value.trim().length > 0,
412
+ );
413
+ if (objectives.length === 0) {
414
+ return "BLOCK_ULTRAGOAL_COMPLETION: Active Ultragoal completion is blocked until a current GJC goal objective can be verified. Use durable blocker work or run strict `gjc ultragoal checkpoint --status complete --quality-gate-json <file> --gjc-goal-json <file>` before completion.";
415
+ }
416
+ for (const objective of objectives) {
417
+ const diagnostic = await readUltragoalVerificationState({
418
+ cwd: input.cwd,
419
+ currentGoal: { objective },
420
+ });
421
+ if (diagnostic.state === "unrelated_goal") continue;
422
+ if (!["inactive", "active_verified_complete"].includes(diagnostic.state)) {
423
+ return `BLOCK_ULTRAGOAL_COMPLETION: ${diagnostic.message} Use durable blocker work or run strict \`gjc ultragoal checkpoint --status complete --quality-gate-json <file> --gjc-goal-json <file>\` before completion.`;
424
+ }
406
425
  }
407
426
  }
408
427
  return `Ultragoal is active (phase: ${phase}; state: ${visibleModeState.statePath}). If the user prompt is a steering request, use \`gjc ultragoal steer\` to add or steer subgoals. Normal prose should not mutate Ultragoal state.`;
@@ -465,7 +484,7 @@ export function buildSkillActivationAdditionalContext(
465
484
  return [
466
485
  `GJC native UserPromptSubmit detected workflow keyword "${state.keyword}" -> ${state.skill}.`,
467
486
  state.initialized_mode && state.initialized_state_path
468
- ? `skill: ${state.initialized_mode} activated and initial state initialized at ${state.initialized_state_path}; use \`gjc state write/read/clear --input '<json>' --json\` for runtime state updates when the private GJC runtime endpoint is available.`
487
+ ? `skill: ${state.initialized_mode} activated and initial state initialized at ${state.initialized_state_path}; use \`gjc state write/read/clear --input '<json>' --json\` for runtime state updates.`
469
488
  : null,
470
489
  state.skill === "ultragoal"
471
490
  ? "Ultragoal is active. If the user prompt is a steering request, use `gjc ultragoal steer` to add or steer subgoals."