import { createHash, randomUUID } from 'node:crypto'; import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent'; const STATE_ENTRY_TYPE = 'mosaic-goal-state'; const CONTEXT_MESSAGE_TYPE = 'mosaic-goal-context'; const CONTINUATION_MESSAGE_TYPE = 'mosaic-goal-continuation'; const GOAL_REPORT_TOOL = 'mosaic_goal_report'; const STATUS_KEY = 'mosaic-goal'; const STATE_VERSION = 1 as const; const MAX_STATEMENT_LENGTH = 8_000; const MAX_SUMMARY_LENGTH = 2_000; const MAX_EVIDENCE_ITEMS = 20; const MAX_EVIDENCE_LENGTH = 1_000; const MAX_NEXT_STEP_LENGTH = 2_000; const DEFAULT_MAX_TURNS = 40; const DEFAULT_MAX_NO_PROGRESS = 6; const REQUIRED_VERIFICATION_PASSES = 2; const DEFERRED_CONTINUATION_MS = 10; const REDACTED_SECRET = '[REDACTED-SECRET]'; const PRIVATE_KEY_PATTERN = /-----BEGIN(?: [A-Z0-9]+)* PRIVATE KEY(?: BLOCK)?-----[\s\S]*?(?:-----END(?: [A-Z0-9]+)* PRIVATE KEY(?: BLOCK)?-----|$)/g; const CREDENTIAL_URL_PATTERN = /\b([A-Za-z][A-Za-z0-9+.-]*:\/\/)[^\s/:]+:[^\s/@]+@/g; const AUTHORIZATION_PATTERN = /(\b(?:authorization|proxy-authorization)\s*[:=]\s*)(bearer|basic)\s+[^\s,;]+/gi; const STANDALONE_AUTH_PATTERN = /\b(bearer|basic)\s+[A-Za-z0-9._~+/=-]{16,}/gi; const JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g; const KNOWN_SECRET_PATTERN = /\b(?:AKIA[0-9A-Z]{16}|ASIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,}|glpat-[A-Za-z0-9_-]{20,}|npm_[A-Za-z0-9]{20,}|sk-(?:ant-(?:api\d{2}-)?|proj-)?[A-Za-z0-9_-]{20,}|(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}|xox[baprs]-[A-Za-z0-9-]{10,}|hf_[A-Za-z0-9]{20,})\b/g; const SENSITIVE_ASSIGNMENT_PATTERN = /((?:["']?(?:[a-z0-9]+[_-])*(?:api[_-]?key|access[_-]?token|auth(?:orization)?[_-]?token|client[_-]?secret|password|passwd|secret(?:[_-]?access[_-]?key)?|private[_-]?key|database[_-]?url|token|cookie|set[_-]?cookie)["']?)\s*)((?:=|:)\s*)("[^"\r\n]*"|'[^'\r\n]*'|[^\s,;]+)/gi; const GOAL_PHASES = [ 'active', 'verifying', 'paused', 'blocked', 'achieved', 'cancelled', 'exhausted', ] as const; const REPORT_STATUSES = ['continue', 'achieved', 'blocked'] as const; const CHECK_SOURCES = ['command', 'turn', 'compact', 'restore', 'report'] as const; type GoalPhase = (typeof GOAL_PHASES)[number]; type GoalReportStatus = (typeof REPORT_STATUSES)[number]; type GoalCheckSource = (typeof CHECK_SOURCES)[number]; interface GoalReport { status: GoalReportStatus; summary: string; evidence: string[]; nextStep?: string; fingerprint: string; reportedAt: string; } interface GoalState { version: typeof STATE_VERSION; goalId: string; statement: string; phase: GoalPhase; startedAt: string; updatedAt: string; turnCount: number; reportCount: number; verificationPasses: number; requiredVerificationPasses: number; noProgressReports: number; maxTurns: number; maxNoProgressReports: number; compactionCount: number; lastCheckSource: GoalCheckSource; lastCheckAt: string; lastCheckOutcome: string; lastProgressFingerprint?: string; lastReport?: GoalReport; stopReason?: string; } interface GoalReportInput { status: GoalReportStatus; summary: string; evidence: string[]; nextStep?: string; } interface GoalLimits { maxTurns: number; maxNoProgressReports: number; } interface GoalCommand { action: 'set' | 'status' | 'pause' | 'resume' | 'cancel' | 'help'; value: string; } const GoalReportParameters = { type: 'object', properties: { status: { type: 'string', enum: REPORT_STATUSES, description: 'continue while work remains, achieved only with completion evidence, or blocked', }, summary: { type: 'string', minLength: 1, maxLength: MAX_SUMMARY_LENGTH, description: 'Concise progress or completion assessment', }, evidence: { type: 'array', items: { type: 'string', minLength: 1, maxLength: MAX_EVIDENCE_LENGTH }, maxItems: MAX_EVIDENCE_ITEMS, description: 'Concrete observations, commands, tests, or artifacts supporting the status', }, nextStep: { type: 'string', minLength: 1, maxLength: MAX_NEXT_STEP_LENGTH, description: 'The next concrete action when work remains', }, }, required: ['status', 'summary', 'evidence'], additionalProperties: false, } as const; function nowIso(): string { return new Date().toISOString(); } function shouldRedactSensitiveAssignment(separator: string, rawValue: string): boolean { if (separator.trim() === '=') return true; const quoted = (rawValue.startsWith('"') && rawValue.endsWith('"')) || (rawValue.startsWith("'") && rawValue.endsWith("'")); if (quoted || rawValue.includes('://')) return true; if (/^[a-f0-9]{20,}$/i.test(rawValue)) return true; return ( rawValue.length >= 20 && /[A-Za-z]/.test(rawValue) && /\d/.test(rawValue) && /[-_./+=]/.test(rawValue) ); } function redactSensitiveText(value: string): string { let redacted = value.replace(PRIVATE_KEY_PATTERN, REDACTED_SECRET); redacted = redacted.replace( CREDENTIAL_URL_PATTERN, (_match: string, prefix: string): string => `${prefix}${REDACTED_SECRET}@`, ); redacted = redacted.replace( AUTHORIZATION_PATTERN, (_match: string, prefix: string, scheme: string): string => `${prefix}${scheme} ${REDACTED_SECRET}`, ); redacted = redacted.replace( STANDALONE_AUTH_PATTERN, (_match: string, scheme: string): string => `${scheme} ${REDACTED_SECRET}`, ); redacted = redacted.replace(JWT_PATTERN, REDACTED_SECRET); redacted = redacted.replace(KNOWN_SECRET_PATTERN, REDACTED_SECRET); return redacted.replace( SENSITIVE_ASSIGNMENT_PATTERN, (_match: string, prefix: string, separator: string, rawValue: string): string => shouldRedactSensitiveAssignment(separator, rawValue) ? `${prefix}${separator}${REDACTED_SECRET}` : _match, ); } function isRecord(value: unknown): value is Record { return typeof value === 'object' && value !== null && !Array.isArray(value); } function isOneOf( value: unknown, allowed: readonly TValue[], ): value is TValue { return ( typeof value === 'string' && allowed.some((candidate: TValue): boolean => candidate === value) ); } function parseBoundedInteger( value: string | undefined, fallback: number, minimum: number, maximum: number, ): number { if (value === undefined || !/^\d+$/.test(value.trim())) return fallback; const parsed = Number.parseInt(value, 10); if (!Number.isSafeInteger(parsed) || parsed < minimum || parsed > maximum) return fallback; return parsed; } function readGoalLimits(env: NodeJS.ProcessEnv): GoalLimits { return { maxTurns: parseBoundedInteger(env['MOSAIC_GOAL_MAX_TURNS'], DEFAULT_MAX_TURNS, 1, 500), maxNoProgressReports: parseBoundedInteger( env['MOSAIC_GOAL_MAX_NO_PROGRESS'], DEFAULT_MAX_NO_PROGRESS, 1, 100, ), }; } function parseStringArray(value: unknown): string[] | undefined { if (!Array.isArray(value) || value.length > MAX_EVIDENCE_ITEMS) return undefined; const result: string[] = []; for (const item of value) { if (typeof item !== 'string') return undefined; const normalized = item.trim(); if (normalized.length === 0 || normalized.length > MAX_EVIDENCE_LENGTH) return undefined; result.push(normalized); } return result; } function parseGoalReport(value: unknown): GoalReport | undefined { if (!isRecord(value)) return undefined; if (!isOneOf(value['status'], REPORT_STATUSES)) return undefined; if ( typeof value['summary'] !== 'string' || value['summary'].length === 0 || value['summary'].length > MAX_SUMMARY_LENGTH ) { return undefined; } const evidence = parseStringArray(value['evidence']); if (evidence === undefined) return undefined; if (typeof value['fingerprint'] !== 'string' || !/^[a-f0-9]{64}$/.test(value['fingerprint'])) { return undefined; } if ( typeof value['reportedAt'] !== 'string' || value['reportedAt'].length === 0 || value['reportedAt'].length > 64 ) { return undefined; } const nextStepValue = value['nextStep']; let nextStep: string | undefined; if (nextStepValue !== undefined) { if ( typeof nextStepValue !== 'string' || nextStepValue.length === 0 || nextStepValue.length > MAX_NEXT_STEP_LENGTH ) { return undefined; } nextStep = nextStepValue; } return { status: value['status'], summary: value['summary'], evidence, ...(nextStep === undefined ? {} : { nextStep }), fingerprint: value['fingerprint'], reportedAt: value['reportedAt'], }; } function readIntegerField( value: Record, field: string, minimum: number, maximum: number = Number.MAX_SAFE_INTEGER, ): number | undefined { const candidate = value[field]; if ( !Number.isSafeInteger(candidate) || typeof candidate !== 'number' || candidate < minimum || candidate > maximum ) { return undefined; } return candidate; } function parseGoalState(value: unknown): GoalState | undefined { if (!isRecord(value) || value['version'] !== STATE_VERSION) return undefined; if ( typeof value['goalId'] !== 'string' || value['goalId'].length === 0 || value['goalId'].length > 128 ) { return undefined; } if ( typeof value['statement'] !== 'string' || value['statement'].length === 0 || value['statement'].length > MAX_STATEMENT_LENGTH ) { return undefined; } if (!isOneOf(value['phase'], GOAL_PHASES)) return undefined; if (!isOneOf(value['lastCheckSource'], CHECK_SOURCES)) return undefined; if ( typeof value['startedAt'] !== 'string' || value['startedAt'].length > 64 || typeof value['updatedAt'] !== 'string' || value['updatedAt'].length > 64 ) { return undefined; } if ( typeof value['lastCheckAt'] !== 'string' || value['lastCheckAt'].length > 64 || typeof value['lastCheckOutcome'] !== 'string' || value['lastCheckOutcome'].length > 256 ) { return undefined; } const turnCount = readIntegerField(value, 'turnCount', 0, 500); const reportCount = readIntegerField(value, 'reportCount', 0, 100_000); const verificationPasses = readIntegerField( value, 'verificationPasses', 0, REQUIRED_VERIFICATION_PASSES, ); const requiredVerificationPasses = readIntegerField( value, 'requiredVerificationPasses', REQUIRED_VERIFICATION_PASSES, REQUIRED_VERIFICATION_PASSES, ); const noProgressReports = readIntegerField(value, 'noProgressReports', 0, 100); const maxTurns = readIntegerField(value, 'maxTurns', 1, 500); const maxNoProgressReports = readIntegerField(value, 'maxNoProgressReports', 1, 100); const compactionCount = readIntegerField(value, 'compactionCount', 0, 100_000); if ( turnCount === undefined || reportCount === undefined || verificationPasses === undefined || requiredVerificationPasses === undefined || noProgressReports === undefined || maxTurns === undefined || maxNoProgressReports === undefined || compactionCount === undefined ) { return undefined; } const lastReportValue = value['lastReport']; const lastReport = lastReportValue === undefined ? undefined : parseGoalReport(lastReportValue); if (lastReportValue !== undefined && lastReport === undefined) return undefined; const lastProgressFingerprintValue = value['lastProgressFingerprint']; let lastProgressFingerprint: string | undefined; if (lastProgressFingerprintValue !== undefined) { if ( typeof lastProgressFingerprintValue !== 'string' || !/^[a-f0-9]{64}$/.test(lastProgressFingerprintValue) ) { return undefined; } lastProgressFingerprint = lastProgressFingerprintValue; } const stopReasonValue = value['stopReason']; let stopReason: string | undefined; if (stopReasonValue !== undefined) { if (typeof stopReasonValue !== 'string' || stopReasonValue.length > MAX_SUMMARY_LENGTH) { return undefined; } stopReason = stopReasonValue; } return { version: STATE_VERSION, goalId: value['goalId'], statement: value['statement'], phase: value['phase'], startedAt: value['startedAt'], updatedAt: value['updatedAt'], turnCount, reportCount, verificationPasses, requiredVerificationPasses, noProgressReports, maxTurns, maxNoProgressReports, compactionCount, lastCheckSource: value['lastCheckSource'], lastCheckAt: value['lastCheckAt'], lastCheckOutcome: value['lastCheckOutcome'], ...(lastProgressFingerprint === undefined ? {} : { lastProgressFingerprint }), ...(lastReport === undefined ? {} : { lastReport }), ...(stopReason === undefined ? {} : { stopReason }), }; } function copyReport(report: GoalReport): GoalReport { return { ...report, evidence: [...report.evidence], }; } function copyState(state: GoalState): GoalState { return { ...state, ...(state.lastReport === undefined ? {} : { lastReport: copyReport(state.lastReport) }), }; } function parseGoalReportInput(value: unknown): GoalReportInput { if (!isRecord(value) || !isOneOf(value['status'], REPORT_STATUSES)) { throw new Error('Goal report status must be continue, achieved, or blocked.'); } if (typeof value['summary'] !== 'string') throw new Error('Goal report summary is required.'); const summary = value['summary'].trim(); if (summary.length === 0 || summary.length > MAX_SUMMARY_LENGTH) { throw new Error(`Goal report summary must be 1-${MAX_SUMMARY_LENGTH} characters.`); } const evidence = parseStringArray(value['evidence']); if (evidence === undefined) throw new Error('Goal report evidence is invalid.'); if (value['status'] === 'achieved' && evidence.length === 0) { throw new Error('An achieved goal report requires concrete evidence.'); } const rawNextStep = value['nextStep']; if (rawNextStep !== undefined && typeof rawNextStep !== 'string') { throw new Error('Goal report nextStep must be text.'); } const nextStep = typeof rawNextStep === 'string' ? rawNextStep.trim() : undefined; if (nextStep !== undefined && (nextStep.length === 0 || nextStep.length > MAX_NEXT_STEP_LENGTH)) { throw new Error(`Goal report nextStep must be 1-${MAX_NEXT_STEP_LENGTH} characters.`); } return redactGoalReportInput({ status: value['status'], summary, evidence, ...(nextStep === undefined ? {} : { nextStep }), }); } function reportFingerprint(report: GoalReportInput): string { const normalized = JSON.stringify({ summary: report.summary.trim().toLowerCase(), evidence: report.evidence.map((item: string): string => item.trim().toLowerCase()), nextStep: report.nextStep?.trim().toLowerCase() ?? '', }); return createHash('sha256').update(normalized).digest('hex'); } function redactGoalReportInput(report: GoalReportInput): GoalReportInput { return { status: report.status, summary: redactSensitiveText(report.summary), evidence: report.evidence.map(redactSensitiveText), ...(report.nextStep === undefined ? {} : { nextStep: redactSensitiveText(report.nextStep) }), }; } function redactGoalReport(report: GoalReport): GoalReport { const redactedInput = redactGoalReportInput(report); return { ...redactedInput, fingerprint: reportFingerprint(redactedInput), reportedAt: report.reportedAt, }; } function redactGoalState(state: GoalState): GoalState { const lastReport = state.lastReport === undefined ? undefined : redactGoalReport(state.lastReport); const lastProgressFingerprint = lastReport !== undefined && state.lastProgressFingerprint === state.lastReport?.fingerprint ? lastReport.fingerprint : state.lastProgressFingerprint; return { ...state, statement: redactSensitiveText(state.statement), ...(lastReport === undefined ? {} : { lastReport }), ...(lastProgressFingerprint === undefined ? {} : { lastProgressFingerprint }), ...(state.stopReason === undefined ? {} : { stopReason: redactSensitiveText(state.stopReason) }), }; } function goalStateContainsSensitiveText(state: GoalState): boolean { const textValues = [state.statement]; if (state.stopReason !== undefined) textValues.push(state.stopReason); if (state.lastReport !== undefined) { textValues.push(state.lastReport.summary, ...state.lastReport.evidence); if (state.lastReport.nextStep !== undefined) textValues.push(state.lastReport.nextStep); } return textValues.some((value: string): boolean => redactSensitiveText(value) !== value); } function isContinuingPhase(phase: GoalPhase): boolean { return phase === 'active' || phase === 'verifying'; } function canReplaceGoal(state: GoalState | undefined): boolean { return state === undefined || state.phase === 'achieved' || state.phase === 'cancelled'; } function parseGoalCommand(args: string): GoalCommand { const trimmed = args.trim(); if (trimmed.length === 0) return { action: 'help', value: '' }; const separator = trimmed.indexOf(' '); const first = (separator === -1 ? trimmed : trimmed.slice(0, separator)).toLowerCase(); const value = separator === -1 ? '' : trimmed.slice(separator + 1).trim(); if (first === 'set') return { action: 'set', value }; if (first === 'status') return { action: 'status', value }; if (first === 'pause') return { action: 'pause', value }; if (first === 'resume') return { action: 'resume', value }; if (first === 'cancel' || first === 'clear') return { action: 'cancel', value }; if (first === 'help') return { action: 'help', value }; return { action: 'set', value: trimmed }; } function formatStatus(state: GoalState | undefined): string { if (state === undefined) return 'No Mosaic goal is set. Use /goal set .'; const lines = [ `Goal ${state.goalId}`, `Phase: ${state.phase}`, `Turns: ${state.turnCount}/${state.maxTurns}`, `Verification: ${state.verificationPasses}/${state.requiredVerificationPasses}`, `No-progress reports: ${state.noProgressReports}/${state.maxNoProgressReports}`, `Compactions checked: ${state.compactionCount}`, `Goal: ${state.statement}`, ]; if (state.lastReport !== undefined) { lines.push(`Latest report: ${state.lastReport.status} — ${state.lastReport.summary}`); if (state.lastReport.evidence.length > 0) { lines.push( 'Evidence:', ...state.lastReport.evidence.map((item: string): string => `- ${item}`), ); } if (state.lastReport.nextStep !== undefined) { lines.push(`Next step: ${state.lastReport.nextStep}`); } } if (state.stopReason !== undefined) lines.push(`Stopped: ${state.stopReason}`); return lines.join('\n'); } function buildGoalContract(state: GoalState): string { const latest = state.lastReport; const verificationInstruction = state.phase === 'verifying' ? 'This is a verification pass. Re-inspect the actual result and rerun relevant checks; do not rely only on the prior claim.' : 'Continue making concrete progress toward the goal.'; const lines = [ '[MOSAIC GOAL LOOP v1]', `Goal ID: ${state.goalId}`, `Goal: ${state.statement}`, `Phase: ${state.phase}`, `Budget: turn ${state.turnCount}/${state.maxTurns}; repeated no-progress reports ${state.noProgressReports}/${state.maxNoProgressReports}.`, verificationInstruction, '', 'Completion protocol:', `- Before ending the work cycle, call ${GOAL_REPORT_TOOL} as the only tool call in the final assistant response.`, '- Use status=continue whenever any requirement remains and provide the next concrete step.', '- Use status=achieved only when concrete evidence covers the entire stated goal.', '- Use status=blocked only for a genuine blocker that prevents meaningful progress.', `- Achievement requires ${state.requiredVerificationPasses} consecutive evidence-bearing reports; the first claim starts a separate verification pass.`, '- Never include secrets, tokens, credentials, private keys, or raw sensitive output in a report.', '- Do not ask routine permission to continue. The operator can pause or cancel with /goal.', ]; if (latest !== undefined) { lines.push('', `Previous report: ${latest.status} — ${latest.summary}`); if (latest.nextStep !== undefined) lines.push(`Previous next step: ${latest.nextStep}`); } return lines.join('\n'); } function continuationText(state: GoalState, reason: string): string { if (state.phase === 'verifying') { return `Goal ${state.goalId} requires a verification pass after ${reason}. Recheck the complete goal and report fresh evidence with ${GOAL_REPORT_TOOL}.`; } return `Goal remains active after ${reason}. Continue from the latest evidence and finish by calling ${GOAL_REPORT_TOOL}.`; } function toolResultIncludesGoalReport(toolResults: unknown): boolean { if (!Array.isArray(toolResults)) return false; return toolResults.some( (result: unknown): boolean => isRecord(result) && result['toolName'] === GOAL_REPORT_TOOL, ); } function toolResultCount(toolResults: unknown): number { return Array.isArray(toolResults) ? toolResults.length : 0; } export default function registerGoalExtension(pi: ExtensionAPI): void { const limits = readGoalLimits(process.env); let state: GoalState | undefined; let continuationQueued = false; let deferredTimer: ReturnType | undefined; let lifecycleGeneration = 0; let reportRollbackState: GoalState | undefined; function updateStatus(ctx: ExtensionContext): void { if (state === undefined || state.phase === 'cancelled') { ctx.ui.setStatus(STATUS_KEY, undefined); return; } ctx.ui.setStatus(STATUS_KEY, `🎯 ${state.phase} ${state.turnCount}/${state.maxTurns}`); } function persist(nextState: GoalState, ctx: ExtensionContext): void { const redactedState = redactGoalState(nextState); state = copyState(redactedState); pi.appendEntry(STATE_ENTRY_TYPE, copyState(redactedState)); updateStatus(ctx); } function clearDeferredTimer(): void { if (deferredTimer !== undefined) clearTimeout(deferredTimer); deferredTimer = undefined; } function queueContinuation( ctx: ExtensionContext, reason: string, trackDuplicate: boolean = true, ): void { if (state === undefined || !isContinuingPhase(state.phase)) return; if (ctx.hasPendingMessages()) return; if (trackDuplicate && continuationQueued) return; if (trackDuplicate) continuationQueued = true; const options = ctx.isIdle() ? { triggerTurn: true as const } : { triggerTurn: true as const, deliverAs: 'followUp' as const }; pi.sendMessage( { customType: CONTINUATION_MESSAGE_TYPE, content: continuationText(state, reason), display: true, }, options, ); } function scheduleIdleContinuation(ctx: ExtensionContext, reason: string): void { clearDeferredTimer(); const scheduledGeneration = lifecycleGeneration; deferredTimer = setTimeout((): void => { deferredTimer = undefined; if (scheduledGeneration !== lifecycleGeneration || !ctx.isIdle()) return; queueContinuation(ctx, reason); }, DEFERRED_CONTINUATION_MS); } function restoreState(ctx: ExtensionContext): void { state = undefined; let rejectedSensitiveState = false; for (const entry of ctx.sessionManager.getBranch()) { if (entry.type !== 'custom' || entry.customType !== STATE_ENTRY_TYPE) continue; const restoredState = parseGoalState(entry.data); if (restoredState === undefined) { state = undefined; } else if (goalStateContainsSensitiveText(restoredState)) { state = undefined; rejectedSensitiveState = true; } else if (rejectedSensitiveState) { state = undefined; } else { state = redactGoalState(restoredState); } } continuationQueued = false; updateStatus(ctx); if (rejectedSensitiveState) { ctx.ui.notify( 'Mosaic goal state was not restored because persisted text matched a credential pattern. Remove the affected Pi session if it may contain a real secret, then set a new goal.', 'warning', ); } } function createGoal(statement: string, ctx: ExtensionContext): void { if (!canReplaceGoal(state)) { ctx.ui.notify( 'A Mosaic goal already exists. Use /goal cancel before replacing it.', 'warning', ); return; } if (statement.length === 0 || statement.length > MAX_STATEMENT_LENGTH) { ctx.ui.notify( `Usage: /goal set (${MAX_STATEMENT_LENGTH.toLocaleString()} characters maximum).`, 'warning', ); return; } const timestamp = nowIso(); const redactedStatement = redactSensitiveText(statement); persist( { version: STATE_VERSION, goalId: randomUUID(), statement: redactedStatement, phase: 'active', startedAt: timestamp, updatedAt: timestamp, turnCount: 0, reportCount: 0, verificationPasses: 0, requiredVerificationPasses: REQUIRED_VERIFICATION_PASSES, noProgressReports: 0, maxTurns: limits.maxTurns, maxNoProgressReports: limits.maxNoProgressReports, compactionCount: 0, lastCheckSource: 'command', lastCheckAt: timestamp, lastCheckOutcome: 'set', }, ctx, ); ctx.ui.notify(`Mosaic goal started: ${redactedStatement}`, 'info'); if (ctx.isIdle()) queueContinuation(ctx, 'goal start', false); } pi.registerCommand('goal', { description: 'Set or control a persistent Mosaic goal loop', handler: async (args, ctx): Promise => { const command = parseGoalCommand(args); if (command.action === 'help') { ctx.ui.notify( [ 'Mosaic goal commands:', '/goal set (or /goal )', '/goal status', '/goal pause [reason]', '/goal resume', '/goal cancel', ].join('\n'), 'info', ); return; } if (command.action === 'status') { ctx.ui.notify(formatStatus(state), 'info'); return; } if (command.action === 'set') { createGoal(command.value, ctx); return; } if (state === undefined) { ctx.ui.notify('No Mosaic goal is set.', 'warning'); return; } const timestamp = nowIso(); if (command.action === 'pause') { if (!isContinuingPhase(state.phase)) { ctx.ui.notify(`Goal cannot be paused from phase ${state.phase}.`, 'warning'); return; } persist( { ...state, phase: 'paused', updatedAt: timestamp, lastCheckSource: 'command', lastCheckAt: timestamp, lastCheckOutcome: 'paused', stopReason: command.value || 'Paused by operator.', }, ctx, ); clearDeferredTimer(); continuationQueued = false; if (!ctx.isIdle()) ctx.abort(); ctx.ui.notify('Mosaic goal paused.', 'info'); return; } if (command.action === 'cancel') { persist( { ...state, phase: 'cancelled', updatedAt: timestamp, lastCheckSource: 'command', lastCheckAt: timestamp, lastCheckOutcome: 'cancelled', stopReason: 'Cancelled by operator.', }, ctx, ); clearDeferredTimer(); continuationQueued = false; if (!ctx.isIdle()) ctx.abort(); ctx.ui.notify('Mosaic goal cancelled.', 'info'); return; } if (command.action === 'resume') { if (state.phase !== 'paused' && state.phase !== 'blocked' && state.phase !== 'exhausted') { ctx.ui.notify(`Goal cannot be resumed from phase ${state.phase}.`, 'warning'); return; } persist( { ...state, phase: 'active', updatedAt: timestamp, turnCount: 0, verificationPasses: 0, noProgressReports: 0, lastProgressFingerprint: undefined, lastCheckSource: 'command', lastCheckAt: timestamp, lastCheckOutcome: 'resumed', stopReason: undefined, }, ctx, ); continuationQueued = false; ctx.ui.notify('Mosaic goal resumed with fresh bounded counters.', 'info'); if (ctx.isIdle()) queueContinuation(ctx, 'operator resume', false); } }, }); pi.registerTool({ name: GOAL_REPORT_TOOL, label: 'Mosaic Goal Report', description: 'Report structured progress for the active Mosaic /goal loop. Call it as the sole final tool when a work cycle is ready to stop, continue, verify, or block.', promptSnippet: 'Report evidence-backed status for the active Mosaic goal loop', promptGuidelines: [ 'When a Mosaic goal is active, call mosaic_goal_report as the sole tool in the final assistant response for each work cycle.', 'Use mosaic_goal_report status=achieved only when concrete evidence covers the entire active goal.', ], parameters: GoalReportParameters, async execute(_toolCallId, params, _signal, _onUpdate, ctx) { if (state === undefined || !isContinuingPhase(state.phase)) { throw new Error( 'No active Mosaic goal can accept a report. Use /goal set or /goal resume.', ); } const input = parseGoalReportInput(params); const fingerprint = reportFingerprint(input); const timestamp = nowIso(); const report: GoalReport = { ...input, fingerprint, reportedAt: timestamp, }; reportRollbackState = copyState(state); let nextState: GoalState; if (input.status === 'continue') { const noProgressReports = fingerprint === state.lastProgressFingerprint ? state.noProgressReports + 1 : 1; const exhausted = noProgressReports >= state.maxNoProgressReports; nextState = { ...state, phase: exhausted ? 'exhausted' : 'active', updatedAt: timestamp, reportCount: state.reportCount + 1, verificationPasses: 0, noProgressReports, lastProgressFingerprint: fingerprint, lastReport: report, lastCheckSource: 'report', lastCheckAt: timestamp, lastCheckOutcome: exhausted ? 'no-progress-limit' : 'continue', ...(exhausted ? { stopReason: `Repeated no-progress report limit reached (${state.maxNoProgressReports}).`, } : { stopReason: undefined }), }; } else if (input.status === 'achieved') { const verificationPasses = state.phase === 'verifying' ? state.verificationPasses + 1 : 1; const achieved = verificationPasses >= state.requiredVerificationPasses; nextState = { ...state, phase: achieved ? 'achieved' : 'verifying', updatedAt: timestamp, reportCount: state.reportCount + 1, verificationPasses, noProgressReports: 0, lastProgressFingerprint: fingerprint, lastReport: report, lastCheckSource: 'report', lastCheckAt: timestamp, lastCheckOutcome: achieved ? 'verified-achieved' : 'provisional-achieved', stopReason: undefined, }; } else { nextState = { ...state, phase: 'blocked', updatedAt: timestamp, reportCount: state.reportCount + 1, verificationPasses: 0, noProgressReports: 0, lastProgressFingerprint: fingerprint, lastReport: report, lastCheckSource: 'report', lastCheckAt: timestamp, lastCheckOutcome: 'blocked', stopReason: input.summary, }; } persist(nextState, ctx); if (nextState.phase === 'achieved') { ctx.ui.notify(`Mosaic goal verified.\n${formatStatus(nextState)}`, 'info'); } else if (nextState.phase === 'verifying') { ctx.ui.notify( 'Goal achievement is provisional; one verification pass is required.', 'info', ); } else if (nextState.phase === 'blocked' || nextState.phase === 'exhausted') { ctx.ui.notify(`Mosaic goal stopped in phase ${nextState.phase}.`, 'warning'); } return { content: [ { type: 'text', text: nextState.phase === 'achieved' ? 'Goal verification complete.' : `Goal report recorded; phase is ${nextState.phase}.`, }, ], details: { state: copyState(nextState), report: copyReport(report) }, terminate: true, }; }, }); pi.on('context', async (event) => { const messages = event.messages.filter( (message) => message.role !== 'custom' || (message.customType !== CONTEXT_MESSAGE_TYPE && message.customType !== CONTINUATION_MESSAGE_TYPE), ); if (state === undefined || !isContinuingPhase(state.phase)) { return messages.length === event.messages.length ? undefined : { messages }; } messages.push({ role: 'custom', customType: CONTEXT_MESSAGE_TYPE, content: buildGoalContract(state), display: false, timestamp: Date.now(), }); return { messages }; }); pi.on('turn_end', async (event, ctx) => { if (state === undefined || state.phase === 'paused' || state.phase === 'cancelled') return; const hasGoalReport = toolResultIncludesGoalReport(event.toolResults); if (!isContinuingPhase(state.phase) && !hasGoalReport) return; const timestamp = nowIso(); let nextState = { ...state, updatedAt: timestamp, turnCount: state.turnCount + 1, lastCheckSource: 'turn' as const, lastCheckAt: timestamp, lastCheckOutcome: hasGoalReport ? 'reported' : 'checked-unreported', }; if ( hasGoalReport && toolResultCount(event.toolResults) !== 1 && reportRollbackState !== undefined ) { nextState = { ...reportRollbackState, phase: 'active', updatedAt: timestamp, turnCount: reportRollbackState.turnCount + 1, verificationPasses: 0, lastCheckSource: 'turn', lastCheckAt: timestamp, lastCheckOutcome: 'mixed-goal-report-rejected', stopReason: undefined, }; ctx.ui.notify( `${GOAL_REPORT_TOOL} must be the only tool call in its final response; the mixed report was ignored.`, 'warning', ); } reportRollbackState = undefined; if (isContinuingPhase(nextState.phase) && nextState.turnCount >= nextState.maxTurns) { nextState = { ...nextState, phase: 'exhausted', lastCheckOutcome: 'max-turn-limit', stopReason: `Maximum autonomous turn limit reached (${nextState.maxTurns}).`, }; persist(nextState, ctx); ctx.ui.notify('Mosaic goal exhausted its autonomous turn limit.', 'warning'); ctx.abort(); return; } persist(nextState, ctx); }); pi.on('agent_start', async () => { continuationQueued = false; clearDeferredTimer(); }); pi.on('agent_settled', async (_event, ctx) => { if (state === undefined || !isContinuingPhase(state.phase)) return; queueContinuation(ctx, state.phase === 'verifying' ? 'the provisional claim' : 'agent settle'); }); pi.on('session_compact', async (event, ctx) => { if (state === undefined) return; const timestamp = nowIso(); const wasContinuing = isContinuingPhase(state.phase); persist( { ...state, phase: wasContinuing ? 'active' : state.phase, updatedAt: timestamp, verificationPasses: wasContinuing ? 0 : state.verificationPasses, compactionCount: state.compactionCount + 1, lastCheckSource: 'compact', lastCheckAt: timestamp, lastCheckOutcome: `checked-${event.reason}`, ...(wasContinuing ? { stopReason: undefined } : {}), }, ctx, ); if (wasContinuing) scheduleIdleContinuation(ctx, `${event.reason} compaction`); }); pi.on('session_start', async (_event, ctx) => { lifecycleGeneration += 1; clearDeferredTimer(); restoreState(ctx); if (state !== undefined && isContinuingPhase(state.phase)) { const timestamp = nowIso(); persist( { ...state, updatedAt: timestamp, lastCheckSource: 'restore', lastCheckAt: timestamp, lastCheckOutcome: 'session-start', }, ctx, ); scheduleIdleContinuation(ctx, 'session restore'); } }); pi.on('session_tree', async (_event, ctx) => { lifecycleGeneration += 1; clearDeferredTimer(); restoreState(ctx); if (state !== undefined && isContinuingPhase(state.phase)) { const timestamp = nowIso(); persist( { ...state, updatedAt: timestamp, lastCheckSource: 'restore', lastCheckAt: timestamp, lastCheckOutcome: 'tree-navigation', }, ctx, ); scheduleIdleContinuation(ctx, 'tree navigation'); } }); pi.on('session_shutdown', async (_event, ctx) => { lifecycleGeneration += 1; clearDeferredTimer(); continuationQueued = false; ctx.ui.setStatus(STATUS_KEY, undefined); }); }