Core Concepts
Task Chains
A chain is a JSON file that defines how the AI agent behaves — which model to use, what it can do, and how it moves between steps.
Chains are the central building block. The contenox CLI, contenox beam, and headless runs all use the same chain engine.
Chains aren't limited to AI loops. A single chain can mix LLM steps, direct tool/hook calls, and manual transitions — in any order. Swapping chains is easy:
# run subcommand — use any chain for this invocation:
contenox run --chain ./my-chain.json "input"
# (falls back to <resolved .contenox>/default-run-chain.json if --chain is omitted)
# chat — set the default session chain:
contenox config set default-chain ./my-chain.json
# (falls back to .contenox/default-chain.json if not set)
{
"id": "my-chain",
"tasks": [ ... ],
"token_limit": 8192
}
Tasks
Each item in tasks[] is a task — a single step with a handler, optional LLM config, and a transition rule.
{
"id": "ask_model",
"handler": "chat_completion",
"system_instruction": "You are a helpful assistant.",
"execute_config": {
"model": "qwen2.5:7b",
"provider": "ollama"
},
"transition": {
"branches": [
{ "operator": "default", "when": "", "goto": "end" }
]
}
}
The handler determines what the task does. See Handlers for all types.
Hooks
A hook is a capability the model can call — a local shell command, the local filesystem, or a remote HTTP service.
local_shell— run shell commands (requires--shellflag)local_fs— read/write local files- Remote hooks — any service exposing an OpenAPI v3 spec at
/openapi.json - MCP servers — any Model Context Protocol server (added via
contenox mcp add)
Hooks are listed by name in execute_config.hooks. Use ["*"] to expose all registered hooks, or list them explicitly for least-privilege access:
"execute_config": {
"hooks": ["nws", "local_shell"]
}
Important
"hooks": ["*"] grants the model access to every registered tool in this run.
For production or sensitive environments, list only the hooks the task actually needs.
This is how Contenox enforces per-invocation tool policy — the model can only call what you explicitly grant.
See Hooks reference for access control patterns.
Transitions
After a task runs, the chain evaluates transition branches to decide the next task.
"transition": {
"branches": [
{ "operator": "equals", "when": "tool-call", "goto": "run_tools" },
{ "operator": "default", "when": "", "goto": "end" }
]
}
Branches are evaluated top to bottom. "goto": "end" terminates the chain.
Data flow
Output from each task is passed as input to the next. Use input_var to read from a specific previous task instead of the immediately preceding one:
{
"id": "run_tools",
"handler": "execute_tool_calls",
"input_var": "ask_model"
}
Macros
Chain JSON supports runtime macros inside string fields:
| Macro | Expands to |
|---|---|
{{var:model}} | The active model name from config |
{{var:provider}} | The active provider from config |
{{now:2006-01-02}} | Current date (Go time format) |
{{hookservice:list}} | Comma-separated list of registered hook names |
See Transitions & Branching and Handlers for the full reference.