Routines
Orchestrate multi-step agent workflows using directed acyclic graphs (DAGs).
Routines define the execution flow for agent work in Nenjo. Each routine is a directed acyclic graph (DAG) of steps connected by edges, where each step performs a unit of work -- running an agent, evaluating a gate, executing a script, or coordinating a council.
Core concepts
A routine consists of three primitives:
- Steps (nodes) -- Units of work such as agent tasks, quality gates, lambda scripts, cron loops, councils, or terminal states.
- Edges -- Directed connections between steps that define execution order.
- Conditions -- Rules on edges that determine which path to follow based on the previous step's result (
on_pass,on_fail, etc.).
Every routine has exactly one entry point (a step with no incoming edges) and at least one terminal step where execution ends.
Data model
Routine
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier |
name | string | Human-readable name |
description | string? | Optional description |
trigger | string | When to execute: task.ready or cron |
is_active | boolean | Whether the routine can be executed |
is_default | boolean | Whether this is the user's default routine |
max_retries | integer | Maximum retry attempts on failure (default: 3) |
metadata | JSON | Arbitrary metadata (e.g., schedule for cron, entry_step_ids for editor) |
created_by | UUID | Owner user ID |
Routine step
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier |
routine_id | UUID | Parent routine |
name | string | Display name |
step_type | string | One of: agent, council, gate, cron, lambda, terminal |
agent_id | UUID? | Agent to run (for agent steps) |
council_id | UUID? | Council to run (for council steps) |
role_id | UUID? | Role to use (resolves to an agent, for agent/cron steps) |
lambda_id | UUID? | Lambda script to run (for lambda/cron steps) |
config | JSON | Step-specific configuration |
position_x | float | X coordinate in the visual editor |
position_y | float | Y coordinate in the visual editor |
order_index | integer | Ordering hint for entry-point resolution |
Routine edge
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier |
routine_id | UUID | Parent routine |
source_step_id | UUID | Step this edge originates from |
target_step_id | UUID | Step this edge points to |
condition | string | When to follow: always, on_pass, on_fail, on_review_pass, on_review_fail |
metadata | JSON | Optional edge metadata |
Trigger types
Routines are activated by a trigger:
task.ready-- Executes when a task transitions to thereadystate. This is the default trigger for task-driven routines.cron-- Executes on a recurring schedule. See Cron and scheduling for details.
Execution lifecycle
- The routine is loaded with its steps and edges.
- The entry step is identified (the step with no incoming edges, or via
metadata.entry_step_ids). - The entry step executes and produces a
StepResultwith apassedboolean. - The executor evaluates outgoing edges from the current step. The first edge whose condition is satisfied by the step result is followed.
- The next step executes, and the process repeats.
- Execution ends when a terminal step is reached or no matching outgoing edge is found.
The executor is bounded to steps.len() * 100 iterations to prevent infinite loops on misconfigured routines.
Project assignment
Routines are assigned to projects. When a task in a project becomes ready, the project's assigned routine (or the user's default routine) is executed. One routine can be marked as the default using the set-default endpoint.
API
All routine routes are under /api/v1/routines and require authentication.
Routine CRUD
# List all routines
curl -H "Authorization: Bearer $TOKEN" \
https://your-instance.com/api/v1/routines
# Create a routine
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Code Review Routine",
"trigger": "task.ready",
"max_retries": 3
}' \
https://your-instance.com/api/v1/routines
# Get routine with steps and edges
curl -H "Authorization: Bearer $TOKEN" \
https://your-instance.com/api/v1/routines/$ROUTINE_ID
# Update a routine
curl -X PATCH \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"is_active": false}' \
https://your-instance.com/api/v1/routines/$ROUTINE_ID
# Delete a routine
curl -X DELETE \
-H "Authorization: Bearer $TOKEN" \
https://your-instance.com/api/v1/routines/$ROUTINE_ID
# Set as default routine
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
https://your-instance.com/api/v1/routines/$ROUTINE_ID/set-default
# Manually trigger a cron routine
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
https://your-instance.com/api/v1/routines/$ROUTINE_ID/triggerSteps CRUD
# Add a step
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Developer",
"step_type": "agent",
"role_id": "ROLE_UUID"
}' \
https://your-instance.com/api/v1/routines/$ROUTINE_ID/steps
# Update a step
curl -X PATCH \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Senior Developer"}' \
https://your-instance.com/api/v1/routines/$ROUTINE_ID/steps/$STEP_ID
# Delete a step
curl -X DELETE \
-H "Authorization: Bearer $TOKEN" \
https://your-instance.com/api/v1/routines/$ROUTINE_ID/steps/$STEP_IDEdges CRUD
# Add an edge
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_step_id": "STEP_A_UUID",
"target_step_id": "STEP_B_UUID",
"condition": "on_pass"
}' \
https://your-instance.com/api/v1/routines/$ROUTINE_ID/edges
# Delete an edge
curl -X DELETE \
-H "Authorization: Bearer $TOKEN" \
https://your-instance.com/api/v1/routines/$ROUTINE_ID/edges/$EDGE_IDNext steps
- Step types -- Detailed reference for each step type
- Edges and conditions -- How edge conditions control flow
- DAG validation -- Rules your routine must follow
- Executions -- Runtime context and monitoring