222 lines
8.7 KiB
JSON
222 lines
8.7 KiB
JSON
{
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"$id": "https://casan.local/schemas/agentic-lifecycle.schema.json",
|
|
"title": "CASAN Agentic Lifecycle Contract",
|
|
"description": "Plan-20 client-agnostic lifecycle contract for the CASAN agentic bridge. Each request is a single JSON object read on stdin; each response is a single JSON object written on stdout. Client adapters (Claude Code, Codex, VS Code) translate their native hook payloads into these shapes and render bridge responses back into client-native JSON. The bridge NEVER calls a model — it only admits, gates, records evidence, and finalizes traces (single-model invariant, Plan-20 §3.1).",
|
|
"type": "object",
|
|
"required": ["op"],
|
|
"properties": {
|
|
"op": {
|
|
"type": "string",
|
|
"enum": ["begin", "pre-tool", "post-tool", "telemetry", "finalize", "abort"],
|
|
"description": "Lifecycle operation to perform."
|
|
}
|
|
},
|
|
"allOf": [
|
|
{
|
|
"if": { "properties": { "op": { "const": "begin" } } },
|
|
"then": { "$ref": "#/definitions/beginRequest" }
|
|
},
|
|
{
|
|
"if": { "properties": { "op": { "const": "pre-tool" } } },
|
|
"then": { "$ref": "#/definitions/preToolRequest" }
|
|
},
|
|
{
|
|
"if": { "properties": { "op": { "const": "post-tool" } } },
|
|
"then": { "$ref": "#/definitions/postToolRequest" }
|
|
},
|
|
{
|
|
"if": { "properties": { "op": { "const": "telemetry" } } },
|
|
"then": { "$ref": "#/definitions/telemetryRequest" }
|
|
},
|
|
{
|
|
"if": { "properties": { "op": { "const": "finalize" } } },
|
|
"then": { "$ref": "#/definitions/finalizeRequest" }
|
|
},
|
|
{
|
|
"if": { "properties": { "op": { "const": "abort" } } },
|
|
"then": { "$ref": "#/definitions/abortRequest" }
|
|
}
|
|
],
|
|
"definitions": {
|
|
"clientContext": {
|
|
"type": "object",
|
|
"required": ["client"],
|
|
"properties": {
|
|
"client": {
|
|
"type": "string",
|
|
"enum": ["claude-code", "codex", "vscode", "unknown"],
|
|
"description": "Agentic client family."
|
|
},
|
|
"client_version": { "type": ["string", "null"] },
|
|
"adapter_version": { "type": ["string", "null"] },
|
|
"project": {
|
|
"type": ["string", "null"],
|
|
"description": "Project root as the client sees it; canonicalized by the bridge."
|
|
},
|
|
"session": {
|
|
"type": ["string", "null"],
|
|
"description": "Client-native session id. Hashed by the bridge, never stored raw."
|
|
},
|
|
"actor": {
|
|
"type": ["string", "null"],
|
|
"description": "Stable actor identity asserted by the authenticated runtime boundary."
|
|
},
|
|
"integration_mode": {
|
|
"type": ["string", "null"],
|
|
"enum": ["casan_owned", "managed_hook", "project_hook", "observed_only", null],
|
|
"description": "Declared integration mode; the bridge may DOWNGRADE (never upgrade) it based on enforcement mode and coverage."
|
|
}
|
|
}
|
|
},
|
|
"beginRequest": {
|
|
"allOf": [{ "$ref": "#/definitions/clientContext" }],
|
|
"required": ["op", "client", "prompt"],
|
|
"properties": {
|
|
"op": { "const": "begin" },
|
|
"prompt": {
|
|
"type": "string",
|
|
"description": "Raw user prompt. Scanned by H4 then discarded — only a salted hash is persisted."
|
|
},
|
|
"turn": {
|
|
"type": ["string", "null"],
|
|
"description": "Optional client-native turn correlation id; hashed, not stored raw."
|
|
}
|
|
}
|
|
},
|
|
"preToolRequest": {
|
|
"required": ["op", "admission_id", "tool"],
|
|
"properties": {
|
|
"op": { "const": "pre-tool" },
|
|
"admission_id": { "type": "string" },
|
|
"tool": {
|
|
"type": "string",
|
|
"description": "Client-native tool name, e.g. Bash, Edit, Write, WebFetch."
|
|
},
|
|
"tool_input": {
|
|
"description": "Tool input payload. Scanned/redacted; only a hash + redacted summary are persisted."
|
|
},
|
|
"project": { "type": ["string", "null"] }
|
|
}
|
|
},
|
|
"postToolRequest": {
|
|
"required": ["op", "admission_id", "tool"],
|
|
"properties": {
|
|
"op": { "const": "post-tool" },
|
|
"admission_id": { "type": "string" },
|
|
"tool": { "type": "string" },
|
|
"status": {
|
|
"type": ["string", "null"],
|
|
"enum": ["success", "error", "denied", "timeout", null]
|
|
},
|
|
"duration_ms": { "type": ["integer", "null"], "minimum": 0 },
|
|
"result": { "description": "Tool result. Never stored raw — hashed + redacted." }
|
|
}
|
|
},
|
|
"telemetryRequest": {
|
|
"required": ["op", "admission_id"],
|
|
"properties": {
|
|
"op": { "const": "telemetry" },
|
|
"admission_id": { "type": "string" },
|
|
"model": { "type": ["string", "null"] },
|
|
"runtime_ms": { "type": ["integer", "null"], "minimum": 0 },
|
|
"input_tokens": { "type": ["integer", "null"], "minimum": 0 },
|
|
"output_tokens": { "type": ["integer", "null"], "minimum": 0 },
|
|
"cache_tokens": { "type": ["integer", "null"], "minimum": 0 },
|
|
"cost_amount": { "type": ["number", "null"], "minimum": 0 },
|
|
"cost_currency": { "type": ["string", "null"] },
|
|
"cost_source": {
|
|
"type": ["string", "null"],
|
|
"description": "Provenance of cost/token numbers, e.g. provider_reported, statusline_estimate, session_delta, unavailable. Numbers WITHOUT an accurate source MUST be null with a warning (Plan-20 §5).",
|
|
"enum": [
|
|
"provider_reported",
|
|
"sdk_result_message",
|
|
"statusline_estimate",
|
|
"session_delta",
|
|
"unavailable",
|
|
null
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"finalizeRequest": {
|
|
"required": ["op", "admission_id"],
|
|
"properties": {
|
|
"op": { "const": "finalize" },
|
|
"admission_id": { "type": "string" },
|
|
"stop_reason": {
|
|
"type": ["string", "null"],
|
|
"enum": ["completed", "user_interrupt", "error", "max_turns", "timeout", null]
|
|
},
|
|
"assistant_summary": { "type": ["string", "null"] },
|
|
"changed_files": {
|
|
"type": ["array", "null"],
|
|
"items": { "type": "string" }
|
|
}
|
|
}
|
|
},
|
|
"abortRequest": {
|
|
"required": ["op"],
|
|
"properties": {
|
|
"op": { "const": "abort" },
|
|
"admission_id": { "type": ["string", "null"] },
|
|
"reason": { "type": ["string", "null"] }
|
|
}
|
|
},
|
|
"bridgeResponse": {
|
|
"type": "object",
|
|
"required": ["op", "decision", "schema_version"],
|
|
"properties": {
|
|
"op": { "type": "string" },
|
|
"schema_version": { "type": "string" },
|
|
"decision": {
|
|
"type": "string",
|
|
"enum": ["allow", "block", "deny", "require_approval", "halt", "quarantine", "recorded", "certified", "non_certified", "error"]
|
|
},
|
|
"admission_id": { "type": ["string", "null"] },
|
|
"trace_id": { "type": ["string", "null"] },
|
|
"integration_mode": { "type": ["string", "null"] },
|
|
"certification_strength": {
|
|
"type": ["string", "null"],
|
|
"enum": ["casan_owned", "managed_hook", "project_hook", "observed_only", null]
|
|
},
|
|
"telemetry_quality": {
|
|
"type": ["string", "null"],
|
|
"enum": ["complete", "partial", "insufficient", null]
|
|
},
|
|
"reason": { "type": ["string", "null"] },
|
|
"warnings": { "type": "array", "items": { "type": "string" } },
|
|
"report_url": { "type": ["string", "null"], "format": "uri" },
|
|
"receipt": {
|
|
"type": "object",
|
|
"description": "Non-sensitive materialized pointer for CLI and dashboard discovery.",
|
|
"properties": {
|
|
"schema_version": { "const": 1 },
|
|
"trace_id": { "type": ["string", "null"] },
|
|
"project_id": { "type": ["string", "null"] },
|
|
"decision": { "type": "string" },
|
|
"certified": { "type": "boolean" },
|
|
"certification_strength": { "type": ["string", "null"] },
|
|
"telemetry_quality": { "type": ["string", "null"] },
|
|
"telemetry_warnings": { "type": "array", "items": { "type": "string" } },
|
|
"duration_ms": { "type": ["number", "null"] },
|
|
"tool_calls": { "type": "integer" },
|
|
"failures": { "type": "integer" },
|
|
"finalized_at": { "type": ["string", "null"] },
|
|
"report_url": { "type": ["string", "null"] },
|
|
"trace_path": { "type": "string" },
|
|
"delivery": {
|
|
"type": "string",
|
|
"enum": ["local_spool", "async_delivery_started"]
|
|
}
|
|
}
|
|
},
|
|
"context": {
|
|
"type": ["string", "null"],
|
|
"description": "Optional additional context the adapter may inject into the turn (e.g. certification banner)."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|