Base URL
http://localhost:3333/api/· Authentication · Conventions
Experiment Routes
Base path: /api/experiments
Manages A/B testing experiments, evaluation datasets, and benchmarks for the evolution system.
Create Eval Dataset
POST /datasets
- Authentication: Required
- Description: Create an evaluation dataset (manual or synthetic)
- Body:
{
"name": "Dataset Name",
"skillId": "skill-id",
"category": "general",
"source": "manual|synthetic|history|golden",
"items": [
{
"input": "Test input",
"expectedOutput": "Expected output",
"metadata": {}
}
],
"splitConfig": {
"train": 0.7,
"test": 0.2,
"validation": 0.1
}
}- Response:
{
"success": true,
"datasetId": "dataset-uuid"
}List Datasets
GET /datasets
- Authentication: Required
- Parameters:
skillId(query, optional): Filter by skillcategory(query, optional): Filter by category
- Response:
{
"success": true,
"datasets": [
{
"id": "dataset-id",
"name": "Dataset Name",
"skillId": "skill-id",
"category": "general",
"source": "manual",
"itemCount": 100,
"createdAt": "2024-01-01T00:00:00Z"
}
]
}Generate Dataset
POST /datasets/generate
- Authentication: Required
- Description: Auto-generate a dataset from goal history, golden standards, or synthetically
- Body:
{
"skillId": "skill-id",
"source": "history|golden|synthetic",
"category": "general",
"provider": "openai",
"model": "gpt-4"
}- Response:
{
"success": true,
"datasetId": "dataset-uuid"
}Get Dataset with Splits
GET /datasets/:id
- Authentication: Required
- Parameters:
id(path): Dataset ID
- Response:
{
"success": true,
"dataset": {
"id": "dataset-id",
"name": "Dataset Name",
"items": []
},
"splits": {
"train": [],
"test": [],
"validation": []
}
}Delete Dataset
DELETE /datasets/:id
- Authentication: Required
- Parameters:
id(path): Dataset ID
- Response:
{
"success": true
}Get Benchmarks
GET /benchmarks
- Authentication: Required
- Description: List golden standard benchmarks available for experiments
- Response:
{
"success": true,
"benchmarks": [
{
"id": "benchmark-id",
"name": "Benchmark Name",
"sourceGoalId": "goal-id",
"createdAt": "2024-01-01T00:00:00Z"
}
]
}Create Experiment
POST /
- Authentication: Required
- Body:
{
"name": "Experiment Name",
"hypothesis": "Skill v2 will outperform v1 on accuracy",
"type": "ab_test|benchmark|regression",
"sourceGoalId": "goal-id",
"benchmarkId": "benchmark-id",
"skillId": "skill-id",
"evalDatasetId": "dataset-id",
"config": {}
}- Response:
{
"success": true,
"experiment": {
"id": "experiment-id",
"name": "Experiment Name",
"status": "created",
"createdAt": "2024-01-01T00:00:00Z"
}
}List Experiments
GET /
- Authentication: Required
- Parameters:
status(query, optional): Filter by statuslimit(query, optional): Max results (default: 50)
- Response:
{
"success": true,
"experiments": [
{
"id": "experiment-id",
"name": "Experiment Name",
"status": "created|running|completed|failed",
"type": "ab_test",
"createdAt": "2024-01-01T00:00:00Z"
}
]
}Get Experiment with Results
GET /:id
- Authentication: Required
- Parameters:
id(path): Experiment ID
- Response:
{
"success": true,
"experiment": {
"id": "experiment-id",
"name": "Experiment Name",
"status": "completed",
"results": {},
"createdAt": "2024-01-01T00:00:00Z"
}
}Run Experiment
POST /:id/run
- Authentication: Required
- Parameters:
id(path): Experiment ID
- Body (optional):
{
"provider": "openai",
"model": "gpt-4"
}- Description: Fire-and-forget experiment execution. Returns immediately while the experiment runs in the background.
- Response:
{
"success": true,
"message": "Experiment run started"
}Delete Experiment
DELETE /:id
- Authentication: Required
- Parameters:
id(path): Experiment ID
- Response:
{
"success": true
}Get Experiment Runs
GET /:id/runs
- Authentication: Required
- Parameters:
id(path): Experiment ID
- Description: Get all run results for an experiment
- Response:
{
"success": true,
"runs": [
{
"id": "run-id",
"experimentId": "experiment-id",
"status": "completed",
"results": {},
"startedAt": "2024-01-01T00:00:00Z",
"completedAt": "2024-01-01T00:05:00Z"
}
]
}Contract Routes
Base path: /api/contracts
Contracts are refinement-type runtime invariants (PRD-091 Layer 5). They are either authored by the user/agent or mined by InsightEngine from successful executions ("output must be JSON", "step count ≤ 5", "response includes citation block"). At runtime, ContractsService.check evaluates whether evidence satisfies the contract; violations are counted on the contract row and feed into FitnessScoreService (contract cleanliness component).
Contract shape
{
"id": "uuid",
"user_id": "user-uuid",
"target_type": "tool|workflow|skill|agent",
"target_id": "target-uuid",
"name": "Output must be valid JSON",
"predicate": { "type": "json_valid", "field": "output" },
"source": "authored|mined",
"status": "active|disabled|deprecated",
"confidence": 0.92,
"evidence_count": 47,
"violation_count": 2,
"created_at": "...",
"updated_at": "..."
}List Contracts
GET /
- Authentication: Required
- Parameters:
status(query, optional):active,disabled,deprecatedtargetType(query, optional):tool,workflow,skill,agent
- Response:
{ "success": true, "contracts": [ { ... } ] }Create Contract
POST /
- Authentication: Required
- Body:
{
"targetType": "tool",
"targetId": "web-search",
"name": "Output must include source URLs",
"predicate": { "type": "regex", "field": "output", "pattern": "https?://" },
"confidence": 0.9
}- Description: Authors a new contract.
targetTypeandtargetIdscope the contract to a specific asset;predicateis a JSON shape interpreted byContractsService.check. Errors return400if required fields are missing. - Response (
201):
{ "success": true, "contract": { ... } }Get Single Contract
GET /:id
- Authentication: Required
- Response:
{ "success": true, "contract": { ... } }- Errors:
404not found,403forbidden
Get Contract Violations
GET /:id/violations
- Authentication: Required
- Description: Returns the violation history for a contract — useful when surfacing why a
canary-checkflagged regression. - Response:
{
"success": true,
"violations": [
{
"id": "v-uuid",
"contract_id": "c-uuid",
"source_execution_id": "exec-uuid",
"details": { "expected": "...", "actual": "..." },
"created_at": "..."
}
]
}Update Contract Status
PATCH /:id
- Authentication: Required
- Body:
{ "status": "disabled" }- Description: Currently only
statusis mutable. Use this to disable a noisy contract without deleting it. - Response:
{ "success": true, "contract": { ... } }Check Evidence Against Active Contracts
POST /check
- Authentication: Required
- Body:
{
"targetType": "tool",
"targetId": "web-search",
"runtimeState": { "output": "..." },
"sourceExecutionId": "exec-uuid"
}- Description: Evaluates
runtimeStateagainst every active contract for(targetType, targetId). Records evidence on each contract; persists a violation row if a predicate fails. Returns per-contract verdicts. - Response:
{
"success": true,
"checked": 3,
"passed": 2,
"failed": 1,
"verdicts": [
{ "contractId": "...", "name": "...", "passed": true },
{ "contractId": "...", "name": "...", "passed": false, "violationId": "..." }
]
}Delete Contract
DELETE /:id
- Authentication: Required
- Response:
{ "success": true, "deleted": true }Mutation History Routes
Base path: /api/mutations
Every router-applied change is recorded here (PRD-091 Layer 7). Each row captures the before-state snapshot and the fitness_before baseline so a regression can trigger non-lossy revert. This is the audit trail the agent should consult when the user asks "what did AGNT change?" or "undo that change."
Mutation shape
{
"id": "uuid",
"user_id": "user-uuid",
"insight_id": "insight-uuid|null",
"target_type": "agent|skill|workflow|tool|memory",
"target_id": "target-uuid",
"operation": "apply|revert",
"status": "applied|reverted|failed",
"before_snapshot": { "...": "...": "the asset as it was before the change" },
"after_snapshot": { "...": "...": "the asset as written" },
"fitness_before": 0.82,
"fitness_after": 0.78,
"fitness_delta": -0.04,
"reverted_reason": "manual|canary_regression|null",
"created_at": "...",
"reverted_at": "..."
}List Mutations
GET /
- Authentication: Required
- Parameters:
status(query, optional):applied,reverted,failedtargetType(query, optional):agent,skill,workflow,tool,memorylimit(query, optional): default200
- Description: Returns the mutation history for the authenticated user, newest first.
- Response:
{ "success": true, "history": [ { ... } ] }Get Single Mutation
GET /:id
- Authentication: Required
- Description: Full row including
before_snapshotandafter_snapshot. Use this to render a diff or to surface what changed. - Response:
{ "success": true, "mutation": { ... } }- Errors:
404not found,403forbidden
Canary Check (Detect Regression)
POST /:id/canary-check
- Authentication: Required
- Description: Re-scores fitness for the mutated asset right now (using
FitnessScoreService.forTool/forWorkflow) and compares against the storedfitness_beforebaseline. Persistsfitness_afterandfitness_deltaon the row. The agent should call this before suggesting revert. - Response:
{
"success": true,
"verdict": {
"regression": true,
"delta": -0.12,
"fitnessAfter": 0.70
}
}- Verdict shape:
regression: truewhendelta < -0.05(defaultminDelta)regression: false, reason: 'not_applicable'when mutation isn't inappliedstatusregression: false, reason: 'no_baseline'whenfitness_beforewas never capturedregression: false, reason: 'no_after_score'when there's no recent execution data to score against
Revert Mutation
POST /:id/revert
- Authentication: Required
- Body (optional):
{ "reason": "manual" }- Description: Marks the mutation row as
revertedwithreverted_reason. The actual rollback uses thebefore_snapshotto restore the asset (handled by the model). Safe to call only when canary-check confirms regression OR the user explicitly requests it. - Response:
{ "success": true }- Default
reason:"manual"when the user triggers revert; the periodic canary sweep uses"canary_regression".