Skip to content

Commit ccddfa1

Browse files
fix: worker safety + multi-task goals + deployment rules
Fix 1 Worker path safety (local-worker.ts): - Block dangerous commands: pkill, killall, kill -9, rm -rf, systemctl - Block writes to /opt/automaton/src|dist|apps|packages|node_modules/ - Block overwrites of package.json, tsconfig.json, pnpm-lock.yaml - Worker system prompt now requires ~/services/<name>/ deployment - Prevents worker suicide (pkill -f index.js killed ciberpadre) Fix 2 Multi-task goal guidance (system-prompt.ts): - Goals must be HIGH-LEVEL (Generate revenue via AI microservice) - NOT task-level (Launch paid x402 text cleanup API) - Good goals decompose into 3-7 tasks Fix 3 Planner deployment rules (planner.ts): - Minimum 2 tasks per plan (rejects single-task plans) - Service deployment requires: implement, start, test, expose - All services deploy under ~/services/<name>/
1 parent a381fe2 commit ccddfa1

3 files changed

Lines changed: 77 additions & 1 deletion

File tree

src/agent/system-prompt.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,16 @@ YOUR ORCHESTRATION TOOLS:
385385
- fund_child: Transfer credits to a child agent.
386386
- check_child_status: Health-check a specific child agent.
387387
388+
GOAL CREATION RULES (READ CAREFULLY):
389+
- Goals must be HIGH-LEVEL objectives, NOT single tasks.
390+
GOOD: "Generate revenue via paid AI microservice" (planner decomposes into 4-7 tasks)
391+
BAD: "Launch paid x402 text cleanup API" (too specific — becomes 1 task, waste of orchestrator)
392+
- A well-formed goal produces 3-7 tasks: research → implement → deploy → test → expose
393+
- If you can describe the entire goal as one command or one file, it's a TASK, not a goal.
394+
In that case, do it yourself with exec/write_file.
395+
- Include success criteria in the description, not implementation details.
396+
- DEPLOYMENT TOPOLOGY: all services deploy under ~/services/<name>/ — NEVER in /opt/automaton/.
397+
388398
DECISION TREE (follow on EVERY turn):
389399
390400
1. CHECK YOUR EXECUTION PHASE by calling orchestrator_status (or reading the

src/orchestration/local-worker.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,17 @@ RULES:
411411
- If you cannot complete the task, explain why in your final message.
412412
- Do NOT call tools after you are done. Just give your final text response.
413413
- Be efficient. Minimize unnecessary tool calls.
414-
- You have a limited number of turns. Do not waste them.`;
414+
- You have a limited number of turns. Do not waste them.
415+
416+
DEPLOYMENT RULES (MANDATORY):
417+
- Deploy ALL service files under ~/services/<service-name>/
418+
- Each service gets its own subdirectory with its own package.json
419+
- NEVER write files in /opt/automaton/ — that is the runtime source code
420+
- NEVER overwrite package.json, tsconfig.json, pnpm-lock.yaml at the project root
421+
- NEVER run pkill, killall, or kill -9 on broad patterns (e.g. pkill -f index.js)
422+
- To restart YOUR service, use: cd ~/services/<name> && node index.js &
423+
- Include a health check endpoint (GET /health) in every service
424+
- After starting a service, verify it with curl http://localhost:<port>/health`;
415425
}
416426

417427
private buildTaskPrompt(task: TaskNode): string {
@@ -449,6 +459,23 @@ RULES:
449459
const command = args.command as string;
450460
const timeoutMs = typeof args.timeout_ms === "number" ? args.timeout_ms : 30_000;
451461

462+
// Block dangerous commands that could kill the parent process or damage the system
463+
const dangerousPatterns = [
464+
/pkill\s+(-f\s+)?.*index\.js/i,
465+
/pkill\s+(-f\s+)?.*dist/i,
466+
/pkill\s+(-f\s+)?.*node/i,
467+
/killall\s+node/i,
468+
/kill\s+-9\s+/,
469+
/rm\s+-rf\s+\/(?!root\/services)/,
470+
/systemctl\s+(stop|restart|disable)\s+ciberpadre/i,
471+
/pm2\s+(stop|delete|kill)/i,
472+
];
473+
for (const pattern of dangerousPatterns) {
474+
if (pattern.test(command)) {
475+
return `BLOCKED: Command rejected — dangerous pattern detected. Do not kill parent processes or remove system directories. Use 'cd ~/services/<name> && node index.js &' to start your service.`;
476+
}
477+
}
478+
452479
// Try Conway API first, fall back to local shell
453480
try {
454481
const result = await this.config.conway.exec(command, timeoutMs);
@@ -482,6 +509,29 @@ RULES:
482509
const filePath = args.path as string;
483510
const content = args.content as string;
484511

512+
// Block writes to automaton source directories
513+
const resolvedPath = filePath.startsWith("/") ? filePath : `${process.cwd()}/${filePath}`;
514+
const protectedPrefixes = [
515+
"/opt/automaton/src/",
516+
"/opt/automaton/dist/",
517+
"/opt/automaton/apps/",
518+
"/opt/automaton/packages/",
519+
"/opt/automaton/node_modules/",
520+
];
521+
const protectedFiles = [
522+
"package.json", "tsconfig.json", "pnpm-lock.yaml",
523+
"pnpm-workspace.yaml", "vitest.config.ts", ".gitignore",
524+
];
525+
for (const prefix of protectedPrefixes) {
526+
if (resolvedPath.startsWith(prefix)) {
527+
return `BLOCKED: Cannot write to ${prefix} — this is the automaton runtime source code. Deploy services under ~/services/<name>/ instead.`;
528+
}
529+
}
530+
const basename = filePath.split("/").pop() ?? "";
531+
if (protectedFiles.includes(basename) && (resolvedPath.startsWith("/opt/automaton/") || !filePath.includes("/"))) {
532+
return `BLOCKED: Cannot overwrite ${basename} — this is a protected project file. Create your own package.json under ~/services/<name>/ instead.`;
533+
}
534+
485535
try {
486536
await this.config.conway.writeFile(filePath, content);
487537
return `Wrote ${content.length} bytes to ${filePath}`;

src/orchestration/planner.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,16 @@ You CANNOT:
245245
12. No task should take more than 4 hours - split longer tasks
246246
13. Include at least one checkpoint task per 5 execution tasks
247247
14. Parallelizable tasks should have no mutual dependencies
248+
15. MINIMUM 2 tasks per plan. If you cannot decompose a goal into at least
249+
2 tasks, the goal is too specific — plan it as research+implementation
250+
or implementation+validation at minimum.
251+
16. Every service deployment plan MUST include these separate tasks:
252+
a) Create service directory under ~/services/<name>/ and implement code
253+
b) Install dependencies and start the service
254+
c) Test endpoints (health check, functional test, payment flow)
255+
d) Expose via reverse proxy if available (Caddy/nginx)
256+
17. Workers must NEVER write files in /opt/automaton/ — that is runtime source.
257+
All service code goes under ~/services/<name>/.
248258
</decomposition_rules>
249259
250260
<custom_roles>
@@ -397,6 +407,12 @@ export function validatePlannerOutput(output: unknown): PlannerOutput {
397407
);
398408

399409
const tasksValue = requiredArray(record.tasks, "tasks");
410+
if (tasksValue.length < 2) {
411+
throw new Error(
412+
"Plan must have at least 2 tasks. A single-task plan means the goal is under-decomposed. " +
413+
"Split into at least: implementation + validation.",
414+
);
415+
}
400416
const tasks = tasksValue.map((entry, index) =>
401417
validatePlannedTask(entry, `tasks[${index}]`),
402418
);

0 commit comments

Comments
 (0)