Workflows are Starlark files that declare reusable Condukt agents, inputs,
tools, sandboxes, and triggers. They let you keep agentic automation as project
data that can be checked, locked, shared through git, and run by the standalone
condukt engine or by Mix tasks in an Elixir project.
Use Condukt.Session directly when the agent belongs in application code and
is supervised by your own OTP tree. Use workflows when the declaration should
travel with a project, be runnable from a terminal, or be shared with other
teams.
Create a workflow project
A workflow project can be as small as one .star file:
my-workflows/
condukt.lock
workflows/
triage.starcondukt.lock is committed. It can start empty:
version = 1Create workflows/triage.star:
condukt.workflow(
name = "triage",
agent = condukt.agent(
model = "openai:gpt-4.1-mini",
system_prompt = "Triage incoming issues.",
tools = [condukt.tool("read"), condukt.tool("grep")],
sandbox = condukt.sandbox.local(cwd = "."),
),
inputs = {"type": "object"},
)The workflow name is the command name you run later. The inputs value is a
JSON Schema map. It is validated before the workflow starts.
Check and run locally
When Condukt is installed as a library, use the Mix tasks:
mix condukt.workflows.check --root .
mix condukt.workflows.run triage --root . --input '{"issue":"broken"}'
When Condukt is installed as the standalone engine, use the matching commands:
condukt workflows check --root .
condukt workflows run triage --root . --input '{"issue":"broken"}'
Both paths load the project, evaluate the Starlark files, validate tool references, validate sandbox declarations, and check model identifiers. Errors are reported with source file context:
workflows/triage.star:1:1: invalid_model: badServe workflows
Workflows can be served by a caller-owned runtime. The Condukt application supervisor does not start workflow runtimes automatically.
mix condukt.workflows.serve --root . --port 4000
condukt workflows serve --root . --port 4000
Manual runs use Condukt.Workflows.run/3, mix condukt.workflows.run, or
condukt workflows run.
Cron triggers use condukt.schedule.cron(expr):
condukt.workflow(
name = "daily_summary",
agent = condukt.agent(model = "openai:gpt-4.1-mini"),
triggers = [condukt.schedule.cron("0 9 * * *")],
)Webhook triggers use condukt.trigger.webhook(path). When a served project has
webhook triggers and Bandit is available, the runtime starts an HTTP listener
and routes POST requests to the matching workflow worker.
condukt.workflow(
name = "triage",
agent = condukt.agent(model = "openai:gpt-4.1-mini"),
triggers = [condukt.trigger.webhook(path = "/triage")],
)Organize reusable Starlark
Keep entrypoints under workflows/. Put shared helpers under lib/ and load
them with relative paths:
my-workflows/
workflows/
triage.star
lib/
support.starload("../lib/support.star", "support_agent")
condukt.workflow(
name = "triage",
agent = support_agent,
inputs = {"type": "object"},
)Loaded modules are best used for reusable agents, helper functions, constants,
or tool lists. Workflow declarations in loaded modules are evaluated, but only
workflows declared by files under workflows/ are materialized as project
entrypoints.
Share workflows
Workflow packages are plain git repositories with a condukt.toml at the root
and one or more exported .star files.
support-workflows/
condukt.toml
lib/
triage.starcondukt.toml is required for shared packages:
name = "support-workflows"
version = "1.0.0"
exports = ["lib/triage.star"]
requires_native = ["starlark", "pubgrub"]
[signatures]Package names are lowercase and hyphenated. Versions are semantic versions.
Exports are relative .star paths. Tag the git repository with the same
version:
git tag v1.0.0
git push origin v1.0.0
An exported file should define values that consumers can load:
triage_agent = condukt.agent(
model = "openai:gpt-4.1-mini",
system_prompt = "Triage support issues.",
tools = [condukt.tool("read"), condukt.tool("grep")],
)Use shared workflows
Consumers use versioned load strings:
load("github.com/you/support-workflows/lib/triage.star@v1.0.0", "triage_agent")
condukt.workflow(
name = "triage",
agent = triage_agent,
inputs = {"type": "object"},
)Non-relative loads must include @<version>. Relative loads such as
./helpers.star and ../lib/tools.star stay inside the workspace.
For the common hosted git form, the package identity is
<host>/<owner>/<repo> and the rest of the path is the .star file inside
that repository. For nested git paths, insert .git before the file path:
load("gitlab.com/group/subgroup/support-workflows.git/lib/triage.star@v1.0.0", "triage_agent")Resolve dependencies and write the lockfile:
mix condukt.workflows.lock --root .
condukt workflows lock --root .
Use --offline to require the existing lockfile to satisfy every requirement.
Use --upgrade when you want resolution to consider newer matching versions.
The store
Fetched workflow packages are copied into a content-addressed store:
~/.condukt/store/<sha256>/The store key is the deterministic SHA-256 tree hash returned by the workflows NIF. If fetched contents do not match the expected hash, the store write is rejected.
The lockfile records the selected package versions and content hashes:
version = 1
[packages."github.com/tuist/condukt-tools"]
version = "1.2.0"
url = "https://github.com/tuist/condukt-tools"
sha256 = "abcdef..."
integrity = "sha256-base64..."
dependencies = ["github.com/foo/bar"]Starlark API
See the Workflow Starlark API reference for every available builtin, load target, tool reference, sandbox declaration, and trigger shape.
Future hooks
The current subsystem keeps these features out of scope:
- Sigstore verification
- Hosted package discovery
- Dependency mirrors
- Rich secret provider integrations
Those can be added without changing the core file layout, lockfile format, or runtime ownership model.