Recipe catalog / action-effects
Label the side effects of an action
Which side effects does the described action involve: writing or modifying data, sending a message or notification, spending or moving money, deleting something, or calling an external service?
An agent is about to execute a step and your approval policy differs by effect, so you want to gate auto-execution per side effect rather than with one blanket risk score.
Explore this recipe interactively ยท Source and implementation guide
Use action-effects in TypeScript
Install with npm install jev-recipes. Requires Node.js 22.9 or newer and ES modules. Set TYPESAFE_API_KEY in your server environment for live calls, which send input to TypeSafe and use API quota. See the installation guide.
import { actionEffects } from 'jev-recipes/action-effects';
const result = await actionEffects({
"action": "Send the weekly product digest to all 1,240 subscribers on the newsletter list through the SendGrid API, then set last_digest_sent_at to now on each subscriber row in the users table.",
"minConfidence": 0.8
});
console.log(result);
Input contract
| Field | Type | Needed |
|---|---|---|
| action | string | Required |
| minConfidence | number | Optional |
Full input and result schemas
{
"input": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"action": {
"type": "string"
},
"minConfidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": [
"action"
]
},
"result": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"model": {
"type": "string"
},
"usage": {
"type": "object",
"properties": {
"input_tokens": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"output_tokens": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"input_tokens",
"output_tokens"
],
"additionalProperties": false
},
"status": {
"type": "string",
"enum": [
"ready",
"review"
]
},
"detected": {
"type": "array",
"items": {
"type": "string",
"enum": [
"writesData",
"sendsMessage",
"spendsMoney",
"deletesData",
"callsExternal"
]
}
},
"labels": {
"type": "object",
"properties": {
"writesData": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"ready",
"review"
]
},
"verdict": {
"type": "string",
"enum": [
"present",
"absent"
]
},
"probability": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": [
"status",
"verdict",
"probability",
"confidence"
],
"additionalProperties": false
},
"sendsMessage": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"ready",
"review"
]
},
"verdict": {
"type": "string",
"enum": [
"present",
"absent"
]
},
"probability": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": [
"status",
"verdict",
"probability",
"confidence"
],
"additionalProperties": false
},
"spendsMoney": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"ready",
"review"
]
},
"verdict": {
"type": "string",
"enum": [
"present",
"absent"
]
},
"probability": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": [
"status",
"verdict",
"probability",
"confidence"
],
"additionalProperties": false
},
"deletesData": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"ready",
"review"
]
},
"verdict": {
"type": "string",
"enum": [
"present",
"absent"
]
},
"probability": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": [
"status",
"verdict",
"probability",
"confidence"
],
"additionalProperties": false
},
"callsExternal": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"ready",
"review"
]
},
"verdict": {
"type": "string",
"enum": [
"present",
"absent"
]
},
"probability": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": [
"status",
"verdict",
"probability",
"confidence"
],
"additionalProperties": false
}
},
"required": [
"writesData",
"sendsMessage",
"spendsMoney",
"deletesData",
"callsExternal"
],
"additionalProperties": false
}
},
"required": [
"model",
"usage",
"status",
"detected",
"labels"
],
"additionalProperties": false
}
}Saved example result
This hand-authored response demonstrates the contract. It is not a model accuracy measurement. Run it without an API key: npx jev-recipes demo action-effects.
{
"model": "demo-fixture",
"usage": {
"input_tokens": 0,
"output_tokens": 0
},
"status": "ready",
"detected": [
"writesData",
"sendsMessage",
"callsExternal"
],
"labels": {
"writesData": {
"status": "ready",
"verdict": "present",
"probability": 0.94,
"confidence": 0.94
},
"sendsMessage": {
"status": "ready",
"verdict": "present",
"probability": 0.97,
"confidence": 0.97
},
"spendsMoney": {
"status": "ready",
"verdict": "absent",
"probability": 0.04,
"confidence": 0.96
},
"deletesData": {
"status": "ready",
"verdict": "absent",
"probability": 0.02,
"confidence": 0.98
},
"callsExternal": {
"status": "ready",
"verdict": "present",
"probability": 0.93,
"confidence": 0.93
}
}
}
Evaluation evidence
typesafe-ai/jev / 2026-09-27 / 40 held-out cases
Scoring revision 1.
20 ready decisions, with 100% accuracy among those decisions.
95% case-level interval: 91% to 100%. Related synthetic cases are correlated.
Measured on these synthetic cases
This measurement uses an earlier or unverified recipe or evaluator version. Rerun with the current recipe and evaluator before treating these numbers as current.
Use the evaluation guide to measure this decision on your own labeled cases.
Limitations
- Labels the effects the action description states or plainly entails. It does not know what your tools actually do behind the description.
- Read-only lookups against an external API still count as external calls; whether that is acceptable is a policy decision for application code.
- Permission checks, spending limits, and confirmation prompts belong in application code that consumes these labels.
Related recipes
- action-reversibility: Use action-reversibility to grade how hard the action is to undo, rather than which kinds of effect it has.
- action-scope: Use action-scope to check whether the action stays within the work that was requested.