Base URL
http://localhost:3333/api/· Authentication · Conventions
Closed Loop System (PRD-091)
AGNT runs a self-improvement loop across four primitives that together let goals fire on a cadence, mutations prove themselves before promoting, safe insights auto-apply, contracts enforce runtime invariants, and regressions auto-revert. This section is required reading for any agent that touches scheduling, auto-apply, budgets, or revert.
The four primitives
| Primitive | Base path | What it stores | Layer |
|---|---|---|---|
| Schedules | /api/schedules |
Durable cron entries (target + cron + next_run). Survives backend restart. | 1 (Clock) |
| Wallets | /api/wallets |
Linear capability budgets (root + sub-wallets). Sub-wallets can never exceed parent balance. | 3 (Budgets) |
| Contracts | /api/contracts |
Runtime invariants mined from successful executions ("output must be JSON", "step count ≤ 5"). | 5 (Invariants) |
| Mutation History | /api/mutations |
Every router-applied change, with before-snapshot + fitness baseline. | 7 (Provenance) |
Plus the Autonomy Router at POST /api/insights/route which decides per pending insight whether to direct-apply, gate via sandbox, escalate to the user, or skip. Driven by EvolutionSettingsModel.autonomy (off by default).
When to use which endpoint (intent → call)
| User says... | Call |
|---|---|
| "Run this goal every morning at 9 ET" | POST /api/schedules with targetType:'goal', cron:'0 9 * * *', timezone:'America/New_York' |
| "When will my schedule fire next?" | POST /api/schedules/preview (no persist) — or GET /api/schedules/:id and read next_run |
| "Show me what AGNT auto-changed lately" | GET /api/mutations |
| "Did that auto-change regress quality?" | POST /api/mutations/:id/canary-check |
| "Undo that auto-applied change" | POST /api/mutations/:id/revert |
| "Turn on autonomy" | POST /api/insights/settings with { autonomy: { enabled: true } } |
| "Apply all my safe pending insights" | POST /api/insights/route (sweeps every pending insight through the router) |
| "Route just this one insight" | POST /api/insights/:id/route |
| "What's my budget?" | GET /api/wallets/root |
| "Add credit to my budget" | POST /api/wallets/root/topup |
| "Spin up a sub-budget for this agent" | (server-side) WalletService.allocate(...) — no public route yet |
| "Show this agent's spend ledger" | GET /api/wallets/:id/ledger |
| "Does this output satisfy our quality contracts?" | POST /api/contracts/check |
| "Show me what rules have been mined" | GET /api/contracts |
Safety contract (the agent MUST respect this)
- Never flip
autonomy.enabledon the user's behalf without explicit, in-conversation confirmation. It is off by default for a reason. - Never call
POST /api/insights/:id/applyon insights withpriority: 'critical'orcategory: 'parameter_tune' | 'bottleneck'without explicit confirmation. - Always call
POST /api/mutations/:id/canary-checkbefore suggestingrevert. Show the user the verdict (regression: true|false,delta,fitnessAfter). - Always call
GET /api/wallets/rootbefore scheduling a recurring goal that will incur LLM cost — confirm there is budget. - Default to escalation, not direct-apply. When in doubt, use
POST /api/insights/route(which respects the router) rather thanPOST /api/insights/:id/apply(which bypasses it).
Layered guarantees the safety contract relies on
- The router itself returns
{ decision: 'escalate', reason: 'autonomy_disabled' }for every insight whenautonomy.enabled === false. Flippingenabledis the only way auto-apply turns on. - Every router-applied mutation captures
fitness_beforeat apply time. Revert is non-lossy because the before-snapshot lives inmutation_history. VerifierGateenforcesdelta > MIN_DELTA (0.05)AND structural-constraint gates before promote. A regression cannot pass the gate.- Wallets cap blast radius — even if autonomy is on AND all gates pass, a tool with a depleted wallet cannot keep spending.
Default policy values (live in AutonomyPolicy.DEFAULTS)
{
"enabled": false,
"minConfidence": 0.7,
"minDelta": 0.05,
"maxBlastRadius": 0.5,
"dailyBudget": 20,
"allowedCategories": [
"memory", "prompt_refinement", "tool_preference",
"contract_proposal", "skill_recommendation", "pattern", "antipattern"
],
"requireGateAbove": 0.45
}Insight with blast_radius >= requireGateAbove is routed gated (sandbox-tested) instead of direct. Insight with blast_radius > maxBlastRadius is escalated (human required).
Realtime events the frontend listens for
| Event | When it fires |
|---|---|
autonomy.router.decision |
Router emits a decision per insight |
autonomy.mutation.applied |
A mutation lands in mutation_history |
autonomy.canary.regression |
Periodic canary sweep detects a regression |
scheduler.tick |
Scheduler tick fires a schedule |
scheduler.run.complete |
A scheduled run finishes |
(Implemented in frontend/src/composables/useRealtimeSync.js.)
Goal Routes
Base path: /api/goals
Health Check
GET /health
- Authentication: None
- Description: Check if the goal service is running
- Response:
{
"status": "OK"
}Get All Goals
GET /
- Authentication: Required
- Description: Retrieve all goals for the authenticated user. Includes aggregated token usage from goal evaluations.
- Response:
[
{
"id": "goal-id",
"title": "Goal Title",
"description": "Goal description",
"status": "active|paused|completed|validated|needs_review|failed",
"priority": "low|medium|high",
"task_count": 5,
"completed_tasks": 3,
"input_tokens": 15000,
"output_tokens": 3200,
"total_tokens": 18200,
"estimated_cost": 0.045,
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}
]Create Goal
POST /create
- Authentication: Required
- Body:
{
"title": "Goal Title",
"description": "Goal description",
"priority": "low|medium|high",
"config": {}
}- Response:
{
"success": true,
"goal": {
"id": "goal-id",
"title": "Goal Title",
"description": "Goal description",
"status": "active",
"priority": "medium",
"config": {},
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}
}Execute Goal
POST /:goalId/execute
- Authentication: Required
- Parameters:
goalId(path): Goal ID
- Body (optional):
{
"provider": "anthropic",
"model": "claude-sonnet-4-20250514"
}- Description: Start goal execution. Any failed or stuck tasks are reset to pending. The provider/model override the user's default settings for this execution and all downstream operations (task execution, evaluation, insight extraction, skill evolution).
- Response:
{
"message": "Goal execution started",
"goalId": "goal-id",
"status": "executing"
}Get Goal by ID
GET /:id
- Authentication: Required
- Parameters:
id(path): Goal ID
- Description: Retrieve a specific goal with tasks and aggregated token usage from evaluations and task executions
- Response:
{
"goal": {
"id": "goal-id",
"title": "Goal Title",
"description": "Goal description",
"status": "active|paused|completed|validated|needs_review|failed",
"priority": "low|medium|high",
"config": {},
"tasks": [],
"total_duration": 120,
"credits_used": 120,
"input_tokens": 15000,
"output_tokens": 3200,
"total_tokens": 18200,
"estimated_cost": 0.045,
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}
}Get Goal Status
GET /:id/status
- Authentication: Required
- Parameters:
id(path): Goal ID
- Description: Get the current status of a goal
- Response:
{
"goalId": "goal-id",
"status": "active|paused|completed|failed",
"progress": 75,
"lastExecution": "2024-01-01T00:00:00Z",
"nextExecution": "2024-01-01T01:00:00Z"
}Pause Goal
POST /:id/pause
- Authentication: Required
- Parameters:
id(path): Goal ID
- Description: Pause an active goal
- Response:
{
"success": true,
"message": "Goal paused successfully"
}Resume Goal
POST /:id/resume
- Authentication: Required
- Parameters:
id(path): Goal ID
- Body (optional):
{
"provider": "anthropic",
"model": "claude-sonnet-4-20250514"
}- Description: Resume a paused or failed goal. Failed/stuck tasks are reset to pending. Provider/model are forwarded to all downstream operations.
- Response:
{
"message": "Goal resumed"
}Delete Goal
DELETE /:id
- Authentication: Required
- Parameters:
id(path): Goal ID
- Description: Delete a goal by ID
- Response:
{
"success": true,
"message": "Goal deleted successfully"
}Execute Goal Autonomously (AGI Loop)
POST /:goalId/execute-autonomous
- Authentication: Required
- Parameters:
goalId(path): Goal ID
- Body (optional):
{
"maxIterations": 50,
"provider": "anthropic",
"model": "claude-sonnet-4-20250514"
}- Description: Trigger autonomous goal execution. The system iterates through execute → evaluate → re-plan cycles until the goal passes evaluation or reaches
maxIterations. Provider/model are forwarded to task execution, evaluation, re-planning, insight extraction, and skill evolution. Broadcasts real-timegoal:iteration_*events via WebSocket. - Response:
{
"message": "Autonomous goal execution started",
"goalId": "goal-id",
"maxIterations": 50
}Get Iteration History
GET /:goalId/iterations
- Authentication: Required
- Parameters:
goalId(path): Goal ID
- Description: Get the full iteration history for an autonomous goal execution. Each iteration includes evaluation scores and re-planned task data.
- Response:
{
"success": true,
"iterations": [
{
"iteration": 1,
"action": "Description of action taken",
"result": {},
"evaluation": {},
"evaluation_score": 65.5,
"evaluation_passed": 0,
"world_state_snapshot": {},
"replanned_tasks": [],
"duration_ms": 45000,
"timestamp": "2024-01-01T00:00:00Z"
}
]
}Get World State
GET /:goalId/world-state
- Authentication: Required
- Parameters:
goalId(path): Goal ID
- Description: Get the current world state snapshot for a goal's autonomous execution
- Response:
{
"success": true,
"worldState": {
"goalId": "goal-id",
"currentIteration": 5,
"state": {},
"updatedAt": "2024-01-01T00:00:00Z"
}
}Revert to Iteration
POST /:goalId/revert/:iteration
- Authentication: Required
- Parameters:
goalId(path): Goal IDiteration(path): Iteration number to revert to
- Description: Revert the goal's execution state to a specific iteration
- Response:
{
"success": true,
"revertedToIteration": 3,
"worldState": {}
}Review Goal
POST /:id/review
- Authentication: Required
- Parameters:
id(path): Goal ID
- Description: Approve or reject a goal that is in
needs_reviewstatus - Body:
{
"status": "approved|rejected",
"feedback": "Optional feedback message"
}- Response:
{
"success": true,
"goal": {
"id": "goal-id",
"status": "approved",
"reviewedAt": "2024-01-01T00:00:00Z"
}
}Evaluate Goal
POST /:id/evaluate
- Authentication: Required
- Parameters:
id(path): Goal ID
- Body:
{
"evaluation_type": "automatic",
"provider": "anthropic",
"model": "claude-sonnet-4-20250514"
}- Description: Evaluate a completed goal using LLM-as-judge. Each task output is scored against its success criteria, then an overall evaluation is produced. Token usage is tracked and stored per evaluation. The goal status is set to
validated(score ≥ 70%) orneeds_review. - Response:
{
"passed": true,
"status": "validated",
"scores": {
"overall": 85,
"taskScores": {}
},
"feedback": "Detailed evaluation feedback...",
"input_tokens": 8000,
"output_tokens": 1500,
"total_tokens": 9500,
"estimated_cost": 0.025
}Get Evaluation Report
GET /:id/evaluation
- Authentication: Required
- Parameters:
id(path): Goal ID
- Description: Get evaluation report for a goal
- Response:
{
"goalId": "goal-id",
"evaluations": [
{
"timestamp": "2024-01-01T00:00:00Z",
"score": 85,
"metrics": {},
"recommendations": []
}
]
}Save as Golden Standard
POST /:id/golden-standard
- Authentication: Required
- Parameters:
id(path): Goal ID
- Body:
{
"name": "Golden Standard Name",
"description": "Description of the golden standard"
}- Response:
{
"success": true,
"goldenStandard": {
"id": "golden-standard-id",
"name": "Golden Standard Name",
"description": "Description",
"sourceGoalId": "goal-id",
"createdAt": "2024-01-01T00:00:00Z"
}
}Get Golden Standards
GET /golden-standards/list
- Authentication: Required
- Description: Retrieve all golden standards
- Response:
{
"goldenStandards": [
{
"id": "golden-standard-id",
"name": "Golden Standard Name",
"description": "Description",
"sourceGoalId": "goal-id",
"createdAt": "2024-01-01T00:00:00Z"
}
]
}Get All Goals (Summary)
GET /summary
- Authentication: Required
- Description: Lightweight goal list — summary rows for rendering lists without loading full task payloads
- Parameters:
includeDeleted(query, optional):trueto include soft-deleted goals
- Response:
{
"goals": []
}