1 Syntax Quick Reference
Tactus .tac files are Lua with a small, assignment-based DSL for declaring models, tools, agents, procedures, and tests.
1.1 File Skeleton
-- Standard library tools
local done = require("tactus.tools.done")
-- Custom tools (optional)
search = Tool {
description = "Search the web",
input = { query = field.string{required = true} },
function(args) return "..." end
}
-- Agents (assignment-based; tools are variables, not strings)
researcher = Agent {
model = "openai/gpt-4o-mini",
system_prompt = "Research {input.topic}. Call done when finished.",
tools = {search, done}
}
-- Models (stateless prediction; registry-backed or other backends)
Model "sentiment" {
type = "registry",
name = "sentiment",
version = "latest",
input = { text = "string" },
output = { label = "string", confidence = "float" },
-- Optional: training config (used by `tactus train` and `tactus models evaluate`)
training = {
data = {
source = "hf",
name = "imdb",
train = "train",
test = "test",
text_field = "text",
label_field = "label"
},
candidates = {
{ name = "nb-tfidf", trainer = "naive_bayes" }
}
}
}
-- Optional: declare the allowed stage names
Stages({"researching", "writing", "complete"})
-- The procedure (unnamed; defaults to "main")
Procedure {
input = { topic = field.string{required = true} },
output = { findings = field.string{required = true} },
function(input)
Stage.set("researching")
repeat researcher() until done.called()
return {findings = done.last_result()}
end
}
-- Optional: tests (BDD, in-file)
Specifications([[
Feature: Research
Scenario: Completes
When the researcher agent takes turns
Then the done tool should be called
]])1.2 Declarations
1.2.1 Tools
Define a Lua function tool:
slugify = Tool {
description = "Convert text to a slug",
input = { text = field.string{required = true} },
function(args)
return string.lower(args.text):gsub("%s+", "-")
end
}Import a standard library tool:
local done = require("tactus.tools.done")1.2.2 Agents
worker = Agent {
model = {
name = "openai/gpt-4o",
temperature = 0.3,
max_tokens = 1200
},
prepare = function()
return {now = os.date()}
end,
system_prompt = [[
Time: {prepared.now}
Task: {input.task}
]],
tools = {done}
}Callable agent syntax:
worker()
worker({message = "Focus on edge cases"})
worker({tools = {}}) -- no tools this turn
worker({tools = {search, done}}) -- restrict tools this turn1.2.3 Procedures
Procedures are declared with Procedure { ... } (unnamed, defaults to "main"). Sub-procedures can be assigned to variables:
summarize = Procedure {
name = "summarize",
input = { text = field.string{required = true} },
output = { summary = field.string{required = true} },
return_prompt = "Return a short summary.",
function(input)
worker({message = input.text})
return {summary = done.last_result()}
end
}
Procedure {
function(input)
local result = summarize.run({text = "..."})
return {summary = result.summary}
end
}1.2.4 Toolsets
Use a Toolset when you want a bundle of tools.
math_tools = Toolset {
type = "lua",
tools = {
{
name = "add",
description = "Add numbers",
parameters = {
a = {type = "number", required = true},
b = {type = "number", required = true}
},
handler = function(args) return tostring(args.a + args.b) end
}
}
}
calculator = Agent { model = "openai/gpt-4o-mini", tools = {math_tools, done} }1.3 Schemas (Input/Output/State)
1.3.1 Field Types
| Type | Builder |
|---|---|
| String | field.string{...} |
| Number | field.number{...} |
| Integer | field.integer{...} |
| Boolean | field.boolean{...} |
| Array | field.array{...} |
| Object | field.object{...} |
1.3.2 Common Field Options
| Option | Meaning |
|---|---|
required = true |
Must be provided / returned |
default = ... |
Optional field with a default |
description = "..." |
Shows in CLI/IDE forms and docs |
enum = {...} |
Restrict values (strings) |
1.4 Templates
Templates are {...} substitutions (re-evaluated before each agent turn).
| Namespace | Example |
|---|---|
input |
{input.topic} |
state |
{state.count} |
prepared |
{prepared.file_contents} |
context |
{context.parent_id} |
env |
{env.API_KEY} |
1.5 Control Flow (Lua)
-- repeat/until is the common “agent loop”
repeat
worker()
until done.called() or Iterations.exceeded(10)
-- standard Lua conditionals and loops also apply
if Stop.requested() then
Log.warn("Stopping early", {reason = Stop.reason()})
end