Tool Spec Schema
This page defines the complete JSON Schema for Tool specifications in Fascia. A Tool is the fundamental building block for backend operations -- equivalent to an API endpoint, webhook handler, or cron job. Each Tool is defined by a spec that includes its trigger, flow graph, input/output schemas, and policies.
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["name", "version", "description", "trigger", "input", "output", "flow"],
"properties": {
"name": {
"type": "string",
"pattern": "^[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$",
"description": "camelCase tool name (e.g., createReservation, auth.login)"
},
"version": {
"type": "integer",
"minimum": 1
},
"description": { "type": "string" },
"trigger": { "$ref": "#/$defs/Trigger" },
"input": {
"type": "object",
"description": "JSON Schema for input validation"
},
"output": {
"type": "object",
"description": "JSON Schema for output format"
},
"flow": { "$ref": "#/$defs/FlowGraph" },
"policies": {
"type": "array",
"items": { "type": "string" },
"description": "References to Policy spec names"
},
"auth": { "$ref": "#/$defs/AuthConfig" },
"riskLevel": {
"enum": ["green", "yellow", "red"],
"description": "Assigned by Risk Engine (not user-defined)"
},
"concurrencyStrategy": {
"enum": ["none", "optimistic", "pessimistic"],
"description": "Auto-selected based on flow analysis"
},
"idempotencyKey": {
"type": "string",
"description": "Value DSL expression to derive idempotency key from input"
}
}
}
Top-Level Properties
| Property | Type | Required | Description |
|---|---|---|---|
name | string | Yes | camelCase tool name. Dot notation allowed for namespacing (e.g., auth.login). Must match ^[a-z][a-zA-Z0-9]*(\.[a-z][a-zA-Z0-9]*)*$. |
version | integer | Yes | Immutable version number, starting at 1. |
description | string | Yes | Human-readable description of what the tool does. |
trigger | Trigger | Yes | How the tool is invoked. See Trigger. |
input | object | Yes | JSON Schema defining the expected input payload. Validated at step 1 of the Execution Contract. |
output | object | Yes | JSON Schema defining the response format. |
flow | FlowGraph | Yes | Directed acyclic graph defining the execution logic. See FlowGraph. |
policies | string[] | No | Array of Policy spec names to enforce before execution. |
auth | AuthConfig | No | Authentication and authorization configuration. See AuthConfig. |
riskLevel | enum | No | Assigned by the Risk Engine after analysis. One of green, yellow, red. Not user-defined. See Risk Rules. |
concurrencyStrategy | enum | No | Auto-selected based on flow analysis. One of none, optimistic, pessimistic. |
idempotencyKey | string | No | A Value DSL expression used to derive a unique key from the input, preventing duplicate execution. |
Definitions
Trigger
Defines how the tool is invoked.
{
"type": "object",
"required": ["type"],
"properties": {
"type": { "enum": ["http", "webhook", "cron", "queue"] },
"method": {
"enum": ["GET", "POST", "PUT", "DELETE"],
"description": "For HTTP triggers"
},
"path": {
"type": "string",
"description": "Custom path for HTTP triggers"
},
"schedule": {
"type": "string",
"description": "Cron expression for cron triggers"
},
"webhookSecret": {
"type": "string",
"description": "Secret name in Secret Manager"
}
}
}
| Property | Type | Required | Description |
|---|---|---|---|
type | enum | Yes | Trigger type: http, webhook, cron, or queue. |
method | enum | No | HTTP method. Applicable only when type is "http". |
path | string | No | Custom URL path. Applicable only when type is "http". |
schedule | string | No | Cron expression (e.g., 0 */6 * * *). Required when type is "cron". |
webhookSecret | string | No | Name of the secret in GCP Secret Manager used to verify webhook signatures. Applicable when type is "webhook". |
Trigger Types
| Type | Invocation | Use Case |
|---|---|---|
http | tool.call(name, payload) via HTTP | External clients calling the Tool API |
webhook | External service callback | Payment provider notifications, third-party integrations |
cron | Scheduled execution | Daily reports, cleanup jobs, recurring tasks |
queue | Message queue event (future) | Asynchronous processing, event-driven workflows |
FlowGraph
The directed acyclic graph (DAG) that defines the tool's execution logic.
{
"type": "object",
"required": ["nodes", "edges", "startNode"],
"properties": {
"nodes": {
"type": "object",
"additionalProperties": { "$ref": "#/$defs/FlowNode" }
},
"edges": {
"type": "array",
"items": { "$ref": "#/$defs/FlowEdge" }
},
"startNode": { "type": "string" }
}
}
| Property | Type | Required | Description |
|---|---|---|---|
nodes | object | Yes | Map of node ID to FlowNode definition. Keys are unique string identifiers. |
edges | FlowEdge[] | Yes | List of connections between nodes. See FlowEdge. |
startNode | string | Yes | The node ID where execution begins. Must reference a key in nodes. |
FlowNode
A single operation within the flow graph.
{
"type": "object",
"required": ["type"],
"properties": {
"type": {
"enum": [
"read", "write", "transform", "if", "switch",
"retry", "timeout", "payment", "email", "sms",
"httpRequest", "transaction", "policyCheck", "assert"
]
},
"config": {
"type": "object",
"description": "Node-type-specific configuration"
},
"position": {
"type": "object",
"properties": {
"x": { "type": "number" },
"y": { "type": "number" }
},
"description": "Visual position in Flow Studio canvas"
}
}
}
| Property | Type | Required | Description |
|---|---|---|---|
type | enum | Yes | The node type. Determines the operation performed. See Node Types. |
config | object | No | Configuration specific to the node type (e.g., entity name for read, expression for transform). |
position | object | No | Visual coordinates (x, y) for rendering in Flow Studio. Does not affect execution. |
Node Types
| Category | Node | Description |
|---|---|---|
| Data | read | Fetch data from an Entity or Composite |
| Data | write | Create, update, transition status, or soft-delete an Entity |
| Logic | transform | Transform data using a Value DSL expression |
| Logic | if | Conditional branching (two outputs: true/false) |
| Logic | switch | Multi-way branching based on a value |
| Logic | retry | Retry a downstream node on failure (configurable count and backoff) |
| Logic | timeout | Enforce an execution time limit on downstream nodes |
| External | payment | Call a payment service (e.g., Stripe, Toss) |
| External | email | Send an email |
| External | sms | Send an SMS |
| External | httpRequest | Call an external HTTP API |
| Safety | transaction | Define an explicit transaction boundary around child nodes |
| Safety | policyCheck | Evaluate a Policy at runtime |
| Safety | assert | Enforce an invariant; abort execution if the assertion fails |
FlowEdge
A directed connection between two nodes, defining data flow and execution order.
{
"type": "object",
"required": ["from", "to"],
"properties": {
"from": { "type": "string", "description": "Source node ID" },
"to": { "type": "string", "description": "Target node ID" },
"label": {
"type": "string",
"description": "Branch label (for if/switch nodes)"
},
"dataMapping": {
"type": "object",
"description": "Maps output fields from source to input fields of target"
}
}
}
| Property | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Source node ID. Must reference a key in nodes. |
to | string | Yes | Target node ID. Must reference a key in nodes. |
label | string | No | Branch label for conditional nodes. For if nodes, use "true" or "false". For switch nodes, use the matching case value. |
dataMapping | object | No | Defines how output fields from the source node are mapped to input fields of the target node. |
AuthConfig
Authentication and authorization settings for the tool.
{
"type": "object",
"properties": {
"required": {
"type": "boolean",
"default": true
},
"allowedRoles": {
"type": "array",
"items": { "type": "string" },
"description": "Roles that can execute this tool. Empty = all roles."
}
}
}
| Property | Type | Required | Description |
|---|---|---|---|
required | boolean | No | Whether authentication is required to invoke this tool. Defaults to true. |
allowedRoles | string[] | No | List of roles permitted to execute this tool (e.g., ["admin", "staff"]). An empty array or omission means all authenticated roles are allowed. |
Flow Graph Validation Rules
The Risk Engine validates every flow graph against these rules before deployment:
- DAG requirement -- The graph must be a directed acyclic graph. Cycles are not permitted (triggers a Red risk level).
- Single start node -- There must be exactly one
startNode, and it must reference a valid node in thenodesmap. - Terminal reachability -- All execution paths must reach at least one terminal node (a node with no outgoing edges).
- Write nodes in transactions -- All
writenodes must be enclosed within atransactionboundary. Missing transaction boundaries trigger a Red risk level. - External node retry -- External nodes (
payment,email,sms,httpRequest) should have aretrynode configured. Missing retry triggers a Yellow risk level. - No orphan nodes -- Every node must be reachable from the
startNode. Unreachable nodes indicate a malformed flow.
Execution Contract
Every Tool execution follows this exact 9-step sequence. No exceptions.
| Step | Operation |
|---|---|
| 1 | Validate input against the input JSON Schema |
| 2 | Authorize (JWT verification + RBAC + row-level policy) |
| 3 | Policy check (evaluate all referenced policies) |
| 4 | Start database transaction |
| 5 | Execute flow graph (node by node, following edges) |
| 6 | Enforce invariants on all modified entities |
| 7 | Commit transaction (or rollback on failure) |
| 8 | Write audit log entry |
| 9 | Return normalized output |
No LLM is involved at any step. All behavior is deterministic.
Example
A createReservation tool spec:
{
"name": "createReservation",
"version": 1,
"description": "Create a new vehicle reservation",
"trigger": {
"type": "http",
"method": "POST",
"path": "/reservations"
},
"input": {
"type": "object",
"required": ["customerId", "vehicleId", "startDate", "endDate"],
"properties": {
"customerId": { "type": "string", "format": "uuid" },
"vehicleId": { "type": "string", "format": "uuid" },
"startDate": { "type": "string", "format": "date-time" },
"endDate": { "type": "string", "format": "date-time" },
"notes": { "type": "string" }
}
},
"output": {
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" },
"status": { "type": "string" },
"totalPrice": { "type": "number" }
}
},
"flow": {
"startNode": "calcPrice",
"nodes": {
"calcPrice": {
"type": "transform",
"config": {
"expression": "diffDays(input.startDate, input.endDate) * vehicle.dailyRate"
}
},
"txn": {
"type": "transaction"
},
"createRecord": {
"type": "write",
"config": {
"entity": "Reservation",
"operation": "create",
"fields": {
"customerId": "input.customerId",
"vehicleId": "input.vehicleId",
"startDate": "input.startDate",
"endDate": "input.endDate",
"totalPrice": "calcPrice.result",
"notes": "input.notes"
}
}
},
"checkInvariants": {
"type": "assert",
"config": {
"expression": "createRecord.result.totalPrice > 0",
"message": "Total price must be positive"
}
}
},
"edges": [
{ "from": "calcPrice", "to": "txn" },
{ "from": "txn", "to": "createRecord" },
{ "from": "createRecord", "to": "checkInvariants" }
]
},
"policies": ["maxRowLimit"],
"auth": {
"required": true,
"allowedRoles": ["admin", "staff", "customer"]
},
"idempotencyKey": "concat(input.customerId, '-', input.vehicleId, '-', input.startDate)"
}
See Also
- Entity Spec Schema -- Defines the business objects that Tools operate on
- Policy Spec Schema -- Rules enforced at design time
- Risk Classification Rules -- How flow graphs are evaluated for deployment safety
- System Architecture -- Overall system design and Execution Contract