Практичні поради: не дозволяйте вашим AI-агентам працювати в нескінченному циклі: інженерний посібник
Покрокове керівництво з практичних порад: Як не дозволити вашим AI-агентам працювати в нескінченному циклі: інженерний посібник щодо контрактів, перевірок та готових фрагментів коду для команд, які використовують цю модель.
Використовуйте цей документ як оновлену версію ідей з книги «Не дозволяйте вашим AI-агентам працювати в нескінченному циклі: інженерний посібник з критеріями завершення роботи» для фахівців-операторів: чіткі етапи, впорядковані блоки коду та примітки щодо відновлення, які залишаються при передачі обов’язків. Етап огляду найкраще функціонує, якщо його розглядати як вимірювану поверхню. Запишіть один ідеальний запис роботи, один випадок збою та примітки щодо скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і невдалий сценарії роботи разом. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.
Похмура ситуація у п’ятницю після обіду
Для етапу «Кошмар п’ятничного полудня» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану систему обробки даних. Необхідно включати людське схвалення для операцій, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення елементів під час компіляції не є гарантією повноти бізнес-функціоналу.
Анатомія агентського циклу
Для аналізу етапу з використанням агентів необхідно перед зміною коду визначити вхідні дані, власника кроку та критерії завершення. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового завершення. Вимагайте людського схвалення для операцій, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення елементів під час компіляції не є гарантією повності виконання бізнес-завдань.
┌──────────────────────────────────────┐
│ Agent Perception Loop │
│ (Perceive → Plan → Act) │
└──────────────────┬───────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
▼ ▼ ▼
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ 1. Success Guard │ │ 2. Resource Caps │ │ 3. Progress Guard │
│ (Programmatic Test)│ │ (Tokens/Turns/Time)│ │ (Loop/Hash Detect) │
└────────────────────┘ └────────────────────┘ └────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 4. Human Handoff / Safe Rollback │
└──────────────────────────────────────┘
1. Критерії успіху: детерміністична перевірка цілей
Для етапу „1 Критерій успіху: детерміністичний“ необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не здогадуючись про прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Відображення витрат на ранньому етапі запобігає несподіваним рахункам під час переходу з демо-середовища у спільні середовища. Встановлюйте людське схвалення для кроків, які вимагають фінансових витрат чи змінюють дані у продакшені. Підключення під час компіляції не є гарантією повності бізнес-функцій.
Підступ: самооцінка
На етапі самооцінки підводних каменів необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Необхідно передбачити людське схвалення для операцій, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення на етапі компіляції не є гарантією повноти бізнес-функціоналу.
Рішення: зовнішні програмні верифікатори
На етапі зовнішньої програмної реалізації рішення необхідно визначити вхідні дані, відповідальну особу за кожен крок та критерії завершення ще до зміни коду. Оператори мають мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Необхідно документувати як шлях успішного виконання, так і шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Необхідно встановити людське схвалення для операцій, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення на етапі компіляції не є гарантією повності функціоналу продукту.
import { execSync } from 'node:child_process';
export interface VerificationResult {
success: boolean;
message: string;
stepFailed?: string;
}
/** execSync throws on non-zero exit; diagnostics may land on either stream. */
function runOrCapture(command: string, cwd: string): string | null {
try {
execSync(command, { cwd, stdio: 'pipe' });
return null;
} catch (err: unknown) {
const e = err as { stdout?: Buffer; stderr?: Buffer };
const out = e.stdout?.toString() ?? '';
const errOut = e.stderr?.toString() ?? '';
return [out, errOut].filter(Boolean).join('\n') || String(err);
}
}
export class GoalVerifier {
public static verify(workspacePath: string): VerificationResult {
const steps: Array<[string, string]> = [
['tsc', 'npx tsc --noEmit'],
['npm_test', 'npm test'],
];
for (const [stepId, command] of steps) {
const failure = runOrCapture(command, workspacePath);
if (failure !== null) {
return {
success: false,
message: `\`${command}\` failed:\n${failure}`,
stepFailed: stepId,
};
}
}
return { success: true, message: 'All typechecks and tests passed cleanly.' };
}
}
2. Ліміти ресурсів та бюджету: жорсткі обмеження двигуна
На етапі 2 «Ресурси та бюджет» необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру процесу. Необхідно встановити людське схвалення для кроків, які передбачають витрати грошей чи зміну даних у продакшені. Підключення елементів під час компіляції не є гарантією повноти бізнес-функціоналу.
Підступ: необмежені спроби
На етапі неконтрольованих спроб уникнення проблем необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте елементи проекту, визначте критерії успіху та не допускайте беззвучного часткового завершення. Вимагайте людського схвалення для операцій, які призводять до витрат грошей чи змінюють дані у продакшені. Підключення під час компіляції не є гарантією повноти виконання завдань у бізнес-сенсі.
Рішення: багатовимірні обмеження
На етапі багатовимірних обмежень рішення необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні. Встановлюйте людське схвалення для кроків, які спричиняють витрати чи змінюють дані у продакшені. Підключення під час компіляції не є гарантією повноти бізнес-функціоналу. На етапі багатовимірних обмежень рішення необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Документуйте як успішний, так і відновлювальний сценарії роботи. Повторні спроби, людське схвалення та обробка некоректних повідомлень є частиною функціоналу у продакшені.
ct, не пізніше ніж після опрацювання полішу.export interface ResourceLimits {
maxTurns: number; // e.g. 10 iterations
maxTotalTokens: number; // e.g. 100_000 input + output
timeoutMs: number; // e.g. 120_000 (2 minutes)
}
export class ResourceGuard {
private readonly startTime = Date.now();
private totalTokensUsed = 0;
private currentTurn = 0;
constructor(private readonly limits: ResourceLimits) {}
/** Call once per loop iteration, before the model call. */
public beginTurn(): void {
this.currentTurn += 1;
}
/** Call for every model call, including retries inside a turn. */
public recordUsage(tokens: number): void {
this.totalTokensUsed += tokens;
}
public getTurnCount(): number {
return this.currentTurn;
}
public checkShouldTerminate(): { terminate: boolean; reason?: string } {
if (this.currentTurn >= this.limits.maxTurns) {
return {
terminate: true,
reason: `Exceeded turn cap (${this.limits.maxTurns})`,
};
}
if (this.totalTokensUsed >= this.limits.maxTotalTokens) {
return {
terminate: true,
reason: `Exceeded token budget (${this.totalTokensUsed}/${this.limits.maxTotalTokens})`,
};
}
const elapsed = Date.now() - this.startTime;
if (elapsed >= this.limits.timeoutMs) {
return {
terminate: true,
reason: `Wall-clock timeout reached (${elapsed}ms/${this.limits.timeoutMs}ms)`,
};
}
return { terminate: false };
}
}
3. Захисники прогресу: виявлення застрягання та зсувів
Під час роботи над етапом 3 Progress Guards Stuck спочатку запишіть контракт: необхідні вхідні дані, сигнал успіху та те, що відбувається при частковій невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Віддавайте перевагу малим, тестованим одиницям перед об’ємними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій. Робіть контрольні пункти після дорогих кроків. Функція відновлення не повинна знову оплачувати один і той самий виклик LLM, коли оператор перепробовує пізніший етап.
Типові моди невдач
Під час роботи над етапом «Загальні моделі збоїв» спочатку запишіть угоду: необхідні вхідні дані, сигнал про успіх та те, що відбувається при частковому збої. Цей перелік допомагає зберігати чесність пізніших змін у коді. Розглядайте цей етап як угоду між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безпроблемного часткового виконання завдань. Робіть перевірки після дорогих кроків. Система відновлення не повинна знову оплачувати однаковий виклик LLM, коли оператор намагається виконати наступний етап.
Рішення: підписи інструментів та хешиування стану робочого простору
Під час роботи над етапом підготовки підписів інструменту рішення спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Запишіть час виконання та витрати на токени або запити поруч із функціональними результатами. Відображення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-середовища до спільних. Записуйте назву інструменту, хеш аргументів, час відгуку та результат кожного виклику. Без цих записів дебагування може займати години. Під час роботи над етапом підготовки підписів інструменту рішення спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність подальших змін у коді. Одночасно задокументуйте оптимальний та резервний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.
import { createHash } from 'node:crypto';
export interface ToolCall {
name: string;
args: Record<string, unknown>;
}
export class ProgressGuard {
private readonly recentActionHashes: string[] = [];
constructor(
private readonly windowSize = 5,
private readonly repeatThreshold = 3,
) {}
/** Stable stringify: key order must not change the hash. */
private hashToolCall(call: ToolCall): string {
const args = JSON.stringify(call.args, Object.keys(call.args).sort());
return createHash('sha256').update(`${call.name}:${args}`).digest('hex');
}
/** Returns true when the same call has appeared `repeatThreshold` times in the window. */
public trackAndCheckStuck(call: ToolCall): boolean {
const actionHash = this.hashToolCall(call);
const priorOccurrences = this.recentActionHashes.filter((h) => h === actionHash).length;
this.recentActionHashes.push(actionHash);
if (this.recentActionHashes.length > this.windowSize) {
this.recentActionHashes.shift();
}
return priorOccurrences + 1 >= this.repeatThreshold;
}
}
4. Участь людини та безпечне скасування дій
Етапи «Участь людини» та «Безпечне скасування» функціонують найкраще, якщо їх розглядати як вимірювану структуру. Зберіть один ідеальний запис дій, один випадок збою та примітку щодо скасування перед розширенням обсягу роботи. Віддавайте перевагу невеликим, тестованим одиницям коду перед складними сценаріями. Якщо якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій. Зберігайте стан графа у простій та типованій формі. Вкладені структури приховують інформацію про те, який вузол заповнив певне поле, що ускладнює продовження роботи після перерв.
import { execSync } from 'node:child_process';
import { writeFileSync } from 'node:fs';
import { join } from 'node:path';
export class AgentEscalationRequiredError extends Error {
constructor(message: string, public readonly reportPath?: string) {
super(message);
this.name = 'AgentEscalationRequiredError';
}
}
export class AgentCircuitBreaker {
constructor(
private readonly workspaceDir: string,
private readonly reportDir: string, // keep reports OUTSIDE the workspace
) {}
public handleAbort(reason: string, history: unknown[] = []): never {
console.error(`[CIRCUIT BREAKER] Terminating agent loop: ${reason}`);
// 1. Park workspace changes recoverably.
try {
execSync('git stash push --include-untracked -m "agent-abort"', {
cwd: this.workspaceDir,
stdio: 'pipe',
});
} catch (err) {
console.error('git stash failed during abort; workspace left as-is:', err);
}
// 2. Write a diagnostic trace for human review.
const reportPath = this.writeFailureReport(reason, history);
// 3. Signal the orchestrator.
throw new AgentEscalationRequiredError(`Agent failed safely. Reason: ${reason}`, reportPath);
}
private writeFailureReport(reason: string, history: unknown[]): string {
const reportPath = join(this.reportDir, `agent_failure_${Date.now()}.json`);
writeFileSync(
reportPath,
JSON.stringify(
{
timestamp: new Date().toISOString(),
workspace: this.workspaceDir,
reason,
historyLength: history.length,
history: history.slice(-10),
},
null,
2,
),
'utf-8',
);
return reportPath;
}
}
Дослідження випадку: усі чотири механізми захисту в генераторі додатків з відкритою структурою
У рамках дослідження конкретного випадку всі чотири етапи найкраще розглядати як вимірювану поверхню. Зафіксуйте один ідеальний результат, один випадок невдачі та примітку про скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового виконання завдань. Зберігайте стан графа у простому та типованому вигляді. Вкладені структури приховують інформацію про те, який вузол заповнив певне поле, що ускладнює продовження роботи після перерв.
┌──────────────────────────────────────────────────────────┐
│ Vague prompt ("build a modern web app locally") │
└────────────────────────────┬─────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ Phase 1: Dynamic spec synthesis (`ac-matrix.json`) │
└────────────────────────────┬─────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ Phase 2: Multi-agent execution loop │
│ (Coder agent + design critic + headless E2E verifier) │
└────────────────────────────┬─────────────────────────────┘
│
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Gate 1: Goal │ │ Gate 2: Resource │ │ Gate 3: Progress │
│ verification │ │ caps (turns/ │ │ guard (deadlock/ │
│ (build/E2E/ACs) │ │ token budget) │ │ repetition) │
└─────────┬────────┘ └─────────┬────────┘ └─────────┬────────┘
└───────────────────────┼───────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ Gate 4: Safe exit OR circuit-breaker rollback │
└──────────────────────────────────────────────────────────┘
Динамічна синтеза специфікацій
Етап синтезу динамічних специфікацій працює найкраще, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат на ранньому етапі запобігає несподіваним рахункам під час переходу від демо-середовища до спільних середовищ. Зберігайте стан графа у випрямленому та типованому форматі. Вкладені блоки приховують інформацію про те, який вузол заповнив яке поле, і ускладнюють відновлення після перерв. Етап синтезу динамічних специфікацій працює найкраще, коли його розглядають як вимірювану поверхню. Збережіть один ідеальний запис, один випадок збою та примітку про скасування змін перед розширенням обсягу роботи. Документуйте як успішний, так і відновлювальний шляхи роботи разом. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.
Розподіл обов’язків між кількома агентами
На етапі розподілу роботи між кількома агентами необхідно визначити вхідні дані, відповідального за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись визначити прихований стан. Краще використовувати невеликі, перевірювані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру процесу. Необхідно встановити людське схвалення для операцій, які призводять до витрат грошей чи змінюють дані виробництва. Підключення елементів під час компіляції не є гарантією повноти бізнес-логіки.
Головна система керування
На етапі головного керування необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Призначте назви елементів, визначте критерії успіху та не допускайте беззвучного часткового завершення. Аутентифікуйтеся біля шлюзу та повторно авторизуйтесь на рівні обробки даних. Один лише токен-носій не є межею території користувача.
import { execSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { ResourceGuard, ProgressGuard, AgentCircuitBreaker } from './guards';
interface AcceptanceCriterion {
id: string;
description: string;
status: 'PENDING' | 'IN_PROGRESS' | 'DONE';
}
interface AcMatrix {
items: AcceptanceCriterion[];
}
export interface RunResult {
success: true;
turns: number;
summary: string;
}
export async function runOpenEndedWebAppGenerator(
userPrompt: string,
workspacePath: string,
reportDir: string,
devServerUrl = 'http://localhost:5173',
options = { maxTurns: 15, maxTotalTokens: 200_000, timeoutMs: 300_000 },
): Promise<RunResult> {
const resources = new ResourceGuard(options);
const progress = new ProgressGuard();
const circuitBreaker = new AgentCircuitBreaker(workspacePath, reportDir);
const acMatrixPath = join(workspacePath, 'ac-matrix.json');
let currentPrompt = userPrompt;
let designRetries = 0;
const maxDesignRetries = 3;
while (true) {
// GUARD 1: resource ceilings
const resourceCheck = resources.checkShouldTerminate();
if (resourceCheck.terminate) {
circuitBreaker.handleAbort(resourceCheck.reason!);
}
resources.beginTurn();
const turnResult = await llmAgent.step(currentPrompt);
resources.recordUsage(turnResult.tokensUsed);
// GUARD 2: deadlock detection (only meaningful when a tool was called)
let toolOutput = '(no tool call this turn)';
if (turnResult.toolCall) {
if (progress.trackAndCheckStuck(turnResult.toolCall)) {
circuitBreaker.handleAbort('Repeating tool call detected (stuck agent)');
}
toolOutput = await executeTool(turnResult.toolCall);
}
// GUARD 3: deterministic convergence check
const verification = await evaluateConvergence(workspacePath, acMatrixPath, devServerUrl);
if (verification.gateFailed === 'design') {
designRetries += 1;
if (designRetries > maxDesignRetries) {
circuitBreaker.handleAbort(
`Design gate never converged after ${maxDesignRetries} refinement passes`,
);
}
}
if (verification.isConverged) {
return {
success: true,
turns: resources.getTurnCount(),
summary: 'Web app built, tested, and design-reviewed cleanly.',
};
}
currentPrompt = `Tool output:\n${toolOutput}\n\nConvergence status:\n${verification.statusMessage}`;
}
}
interface ConvergenceResult {
isConverged: boolean;
statusMessage: string;
gateFailed?: 'build' | 'runtime' | 'acs' | 'design';
}
async function evaluateConvergence(
workspacePath: string,
acMatrixPath: string,
devServerUrl: string,
): Promise<ConvergenceResult> {
// Gate 1: build and typecheck
try {
execSync('npx tsc --noEmit && npm run build', { cwd: workspacePath, stdio: 'pipe' });
} catch (err: unknown) {
const e = err as { stdout?: Buffer; stderr?: Buffer };
const output = [e.stdout?.toString(), e.stderr?.toString()].filter(Boolean).join('\n');
return {
isConverged: false,
gateFailed: 'build',
statusMessage: `Gate 1 failed (build/typecheck):\n${output || String(err)}`,
};
}
// Gate 2: dev server and runtime health
const e2eResult = await runHeadlessBrowserCheck(devServerUrl);
if (!e2eResult.noConsoleErrors) {
return {
isConverged: false,
gateFailed: 'runtime',
statusMessage: `Gate 2 failed (console errors): ${e2eResult.errors.join(', ')}`,
};
}
// Gate 3: acceptance criteria fully complete
let acMatrix: AcMatrix;
try {
acMatrix = JSON.parse(readFileSync(acMatrixPath, 'utf-8')) as AcMatrix;
} catch {
return {
isConverged: false,
gateFailed: 'acs',
statusMessage: 'Gate 3 incomplete: `ac-matrix.json` missing or unparseable.',
};
}
const pending = acMatrix.items.filter((ac) => ac.status !== 'DONE');
if (pending.length > 0) {
return {
isConverged: false,
gateFailed: 'acs',
statusMessage: `Gate 3 incomplete: ${pending.length} ACs remaining (${pending
.map((a) => a.id)
.join(', ')})`,
};
}
// Gate 4: design audit (soft gate — see retry cap in the caller)
const criticVerdict = await runDesignCriticAgent(e2eResult.screenshots);
if (criticVerdict.score < 8.5) {
return {
isConverged: false,
gateFailed: 'design',
statusMessage: `Gate 4 incomplete (design ${criticVerdict.score}/10): ${criticVerdict.feedback}`,
};
}
return { isConverged: true, statusMessage: 'All four convergence gates passed.' };
}
Готовий до використання головний запит
На етапі готового до використання майстер-промпту необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні. У разі, коли наступним кроком є код чи виклик інструменту, віддавайте перевагу структурованим результатам із верифікацією схеми перед вільним текстом. На етапі готового до використання майстер-промпту необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Документуйте як оптимальний, так і альтернативний шлях виконання. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.
You are an autonomous lead software engineer, UX designer, and QA verifier. Your goal
is to build a production-quality web application locally, from scratch.
You must operate in a self-terminating agentic loop, running iteratively until the
application is complete, polished, functional, and verified.
================================================================================
1. TARGET APPLICATION SPECIFICATION
================================================================================
[DESCRIBE YOUR APP IDEA HERE — e.g. "A task management web app with local SQLite
persistence, a kanban board with drag-and-drop, priority tags, search/filter
controls, and a dark mode theme."]
================================================================================
2. EXECUTION PROTOCOL
================================================================================
PHASE 1 — DYNAMIC SPEC SYNTHESIS (TURN 1)
Before writing application code or installing dependencies:
1. Initialize the local project structure (e.g. Vite + React, Next.js, or Node).
2. Create `ac-matrix.json` in the workspace root defining explicit acceptance
criteria:
- Feature ACs: persistence, full CRUD, interactive components, error
handling, edge cases.
- Engineering ACs: strict TypeScript (`npx tsc --noEmit`), zero build
errors, zero linter warnings, dev server boots cleanly.
- Design ACs: visual hierarchy, responsive layout, dark/light toggle,
empty states, micro-interactions.
Format:
{
"project": "<app-name>",
"items": [
{ "id": "FEAT-1", "category": "feature", "description": "Local database persistence for tasks", "status": "PENDING" },
{ "id": "FEAT-2", "category": "feature", "description": "Drag-and-drop kanban re-ordering", "status": "PENDING" },
{ "id": "ENG-1", "category": "engineering", "description": "Clean TypeScript build, zero errors", "status": "PENDING" },
{ "id": "ENG-2", "category": "engineering", "description": "Dev server starts with 0 console errors","status": "PENDING" },
{ "id": "DSGN-1", "category": "design", "description": "Responsive UI with dark/light mode", "status": "PENDING" }
]
}
Once written, treat `ac-matrix.json` as frozen scope. Do not delete or weaken an
AC to make a gate pass. If an AC turns out to be genuinely infeasible, mark it
BLOCKED with a reason and surface it in the final summary.
PHASE 2 — AUTONOMOUS DEVELOPMENT LOOP
In each turn:
- Implement features, components, schemas, and routes incrementally.
- Run local validation after code changes (`npx tsc --noEmit`, `npm run build`).
- Update AC statuses (PENDING → IN_PROGRESS → DONE) as work is verified.
- Self-correction rule: if a command fails, read the exact error, fix the root
cause, and re-verify. Do not repeat the same failing command or edit more
than twice — change approach instead.
PHASE 3 — THE 4-GATE CONVERGENCE CHECK (MANDATORY)
Do not end execution or declare the project finished until all four gates pass
in the same turn:
Gate 1 — Compiler and build
`npx tsc --noEmit` and `npm run build` both exit 0 with zero errors.
Gate 2 — Dev server and runtime health
`npm run dev` boots cleanly with zero unhandled console or network errors.
Gate 3 — Acceptance criteria complete
Every item in `ac-matrix.json` has "status": "DONE".
Gate 4 — Design audit score >= 8.5/10
Audit visual hierarchy, color consistency, typography scale, spacing,
transitions, responsive behavior, and empty states. Score out of 10. If
below 8.5, refine and re-audit — but no more than 3 design passes total.
After 3 passes, stop and report the final score as-is.
================================================================================
3. FINAL COMPLETION OUTPUT
================================================================================
Only when all four gates pass, output:
- Final status: PROJECT COMPLETE & VERIFIED
- App summary and architecture overview
- Build and test commands executed, with exit codes
- Completed acceptance-criteria summary (including any BLOCKED items)
- Final design score (X/10) and UX highlights
- Instructions for running the app locally
Then stop.
Чек-лист підсумку
Під час роботи над етапом чек-листу підсумку спочатку запишіть умови контракту: необхідні вхідні дані, сигнал успіху та наслідки часткової невдачі. Цей чек-лист допомагає зберігати чесність у подальших змінах коду. Віддавайте перевагу невеликим, тестованим одиницям коду перед об’ємними скриптами. Якщо якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на складну послідовність операцій. Робіть перевірки після дорогих кроків. Система не повинна знову стягувати плату за один і той самий виклик LLM, коли оператор намагається виконати наступний етап.
Висновок
Під час роботи над етапом Висновків спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте безпроблемного часткового виконання завдань.
Перелік операційних кроків
Під час роботи над етапом переліку операційних кроків спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді.
Зберігайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь кодовий граф.
Пункт перевірки після дорогих кроків. Функція відновлення не повинна знову брати плату за той самий виклик LLM, коли оператор намагається знову виконати пізніший етап.
Забезпечте фіксацію версій залежностей та зафіксуйте дайджест зображення, яке використовувалося під час демонстрації. Відтворюваність краща за індивідуальні знання.
Описайте одночасно оптимальний та резервний сценарії роботи. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.
Пункт перевірки після дорогих кроків. Функція відновлення не повинна знову брати плату за той самий виклик LLM, коли оператор намагається знову виконати пізніший етап.
Перед підвищенням рівня стеку заморозьте версії, зафіксуйте ідеальний запис для критичного сценарію та підтвердьте кроки відкату. У спільних середовищах необхідні обмеження швидкості, перевірки прав на використання та чіткий власник для зміни секретів. Краща нудна надійність, ніж кмітливі одноразові демонстрації.
Примітка до пакету c09d8d68f871: не включайте ключі постачальників у репозиторій, встановіть ліміт токенів на сеанс та зберігайте транскрипції поруч із фіксами для оцінки, щоб подальша заміна моделей залишалася порівнянною.