Tool
A Tool is the fundamental building block for backend operations in Fascia. Each Tool represents a single executable unit of server logic -- equivalent to an API endpoint, webhook handler, or cron job. Tools are defined entirely through structured specs, and their execution follows the immutable Execution Contract.
Tool Spec Structure
A Tool spec includes the following components:
| Field | Description |
|---|---|
name | Unique identifier in camelCase (e.g., createReservation, processPayment) |
version | Immutable version number, incremented on each change |
description | Human-readable description of what the Tool does |
trigger | How the Tool is invoked (HTTP, webhook, cron, queue) |
input | JSON Schema defining the expected input payload |
output | JSON Schema defining the response format |
flow | The Flow graph (nodes and edges) that defines execution logic |
policies | References to Policy specs that govern this Tool |
auth | Authentication and authorization configuration |
riskLevel | Assigned by the Risk Engine: green, yellow, or red |
concurrencyStrategy | How concurrent invocations are handled |
idempotencyKey | Expression for deduplicating repeated calls |
Trigger Types
The trigger determines how a Tool is invoked:
| Trigger | Description | Use Case |
|---|---|---|
http | Called via tool.call(name, payload) over HTTP | API endpoints, form submissions |
webhook | Invoked by an external service callback | Payment confirmations, third-party notifications |
cron | Invoked on a schedule | Daily reports, periodic cleanup, recurring billing |
queue | Invoked by a message queue event (future) | Async processing, event-driven workflows |
Auth Configuration
Every Tool specifies its authentication requirements:
required-- Whether authentication is needed to invoke the Tool. Public Tools (like a status page) can set this tofalse.allowedRoles-- Which roles can invoke the Tool. Roles follow RBAC (Role-Based Access Control), such asadmin,staff, orcustomer.
The auth check occurs at step 2 of the Execution Contract. Unauthorized requests are rejected before any business logic runs.
Risk Levels
Every Tool is assigned a risk level by the Risk Engine based on its flow patterns:
| Level | Meaning | Deployable? |
|---|---|---|
| Green | Safe patterns only -- Entity actions within transactions, no unbounded queries | Yes |
| Yellow | Warning patterns detected -- external calls in transitions, missing retry config | Yes, with acknowledgment |
| Red | Unsafe patterns -- raw writes, missing transactions, payment without rollback | Blocked |
Red-level Tools cannot be deployed under any circumstances. The issues must be resolved first. See the risk rules reference for the full classification criteria and auto-fix suggestions.
Example: processPayment Tool
{
"name": "processPayment",
"version": 1,
"description": "Process a payment for a confirmed reservation",
"trigger": { "type": "http", "method": "POST", "path": "/payments/process" },
"input": {
"type": "object",
"properties": {
"reservationId": { "type": "string", "format": "uuid" },
"amount": { "type": "number", "minimum": 0 },
"paymentMethod": { "type": "string", "enum": ["card", "bank_transfer"] }
},
"required": ["reservationId", "amount", "paymentMethod"]
},
"output": {
"type": "object",
"properties": {
"paymentId": { "type": "string" },
"status": { "type": "string" },
"processedAt": { "type": "string", "format": "date-time" }
}
},
"auth": {
"required": true,
"allowedRoles": ["admin", "staff", "customer"]
},
"flow": {
"startNode": "validate-reservation",
"nodes": [
{
"id": "validate-reservation",
"type": "Read",
"config": { "entity": "Reservation", "filter": { "id": "input.reservationId" } }
},
{
"id": "check-status",
"type": "Assert",
"config": { "expression": "reservation.status == 'confirmed'", "message": "Reservation must be confirmed" }
},
{
"id": "tx-start",
"type": "Transaction",
"config": { "action": "begin" }
},
{
"id": "create-payment",
"type": "Write",
"config": { "entity": "Payment", "action": "create" }
},
{
"id": "tx-end",
"type": "Transaction",
"config": { "action": "commit" }
},
{
"id": "charge",
"type": "Payment",
"config": { "provider": "stripe", "action": "charge" }
}
],
"edges": [
{ "from": "validate-reservation", "to": "check-status" },
{ "from": "check-status", "to": "tx-start" },
{ "from": "tx-start", "to": "create-payment" },
{ "from": "create-payment", "to": "tx-end" },
{ "from": "tx-end", "to": "charge" }
]
},
"policies": ["requireTransaction", "paymentRollback"],
"riskLevel": "yellow",
"idempotencyKey": "concat(input.reservationId, '-', input.amount)"
}
This Tool reads a reservation, asserts it is in the confirmed status, creates a payment record within a transaction, and then calls the payment provider outside the transaction boundary. The external payment call is placed after the transaction commit -- this is intentional, because if the transaction rolled back, an already-charged payment could not be undone automatically. The idempotencyKey prevents duplicate charges for the same reservation and amount.