Skip to main content

Agentic functional programming: a multi-agent harness over orchestral with recursive spawn, addressable mailboxes, and FP-style combinators.

Project description

conjure — a wizard conjuring a tree of smaller wizards

conjure

Agentic functional programming. A multi-agent harness built on orchestral, organized around three primitives — recursive agent spawning, addressable mailboxes, and capability passing — with a library of FP-style combinators (agent_map, agent_fold, agent_filter, agent_race, agent_ensemble, agent_critic) built on top.

Most multi-agent frameworks bake in a topology — group chat, supervisor/worker, DAG — and you fight the framework when your problem has a different shape. Conjure inverts that: the primitives are the substrate, and topology is ordinary code. The composition vocabulary is borrowed from functional programming, where these problems have decades of prior art.

See DESIGN.md for the design philosophy and architecture.

The three primitives

  1. Recursive spawning. One root agent; every other agent is created by another agent via spawn(spec) → address. The spawn tree is the system's structure: callers own callees, lifecycle is parental, termination cascades.
  2. Addressable mailboxes. Every live agent has a persistent, threaded, journaled inbox. Messages are async; parents are never blocked while children work. The user is just another address in the graph.
  3. Capability passing. An agent can only message addresses it was given at spawn time or explicitly handed later. Possession of an address is permission — addresses compose like function references.

The load-bearing deviation from subagent-style frameworks: a spawned agent does not vanish when it returns a value. It stays addressable — it can be re-prompted, queried, and introduced to siblings — until its parent (or the user) terminates it.

Install

pip install conjure-agents                 # core library + headless CLI (repl)
pip install "conjure-agents[ui]"           # + the tmux/textual cockpit (conjure run)
pip install "conjure-agents[claude_agent]" # + claude-agent-sdk engine

The distribution is named conjure-agents; the import package and CLI are plain conjure.

Requires Python ≥ 3.10 on POSIX (the daemon forks; Windows is unsupported).

Quickstart — CLI

Point conjure at a YAML config describing the root agent:

# agent.yaml
llms:
  default:
    provider: anthropic           # or openai / google / groq / ollama
    model: claude-haiku-4-5

root:
  role_prompt: |
    You are the root orchestrator. Spawn children when a specialist is
    warranted; otherwise just do the work.
  engine: orchestral
  llm: default
  tools: [primitive, combinator]
conjure config set ANTHROPIC_API_KEY sk-...   # stored in ~/.config/conjure/.env
conjure check agent.yaml                      # validate config + keys, no LLM calls
conjure repl agent.yaml                       # single-pane REPL, no tmux needed
conjure run agent.yaml                        # tmux cockpit (requires the [ui] extra)

In tmux mode the session is daemonized: window 0 is your prompt to the root agent, every spawned agent gets its own live window, and Ctrl+B M opens a meta-view popup (spawn tree + inboxes + cost). Detach with Ctrl+B d, reattach with conjure run --attach, stop with conjure quit.

Quickstart — library

The runtime is a plain Python object; engines are pluggable. This example uses the deterministic ScriptedEngine (no API key needed) to show the mechanics — swap in the orchestral or claude_agent engine factories for LLM-backed agents (see examples/):

from conjure import AgentSpec, BehaviorRegistry, Runtime, agent_map
from conjure.tools.primitives import send_impl

def squarer(engine, prompt, envelopes):
    for env in envelopes:
        body = env.body
        if isinstance(body, dict) and "item" in body:
            send_impl(token=engine.token, to=body["reply_to"], body=body["item"] ** 2)
    return "ok"

reg = BehaviorRegistry()
reg.register("idle", lambda *a, **kw: "idle")
reg.register("squarer", squarer)

rt = Runtime(engine_factory=reg.factory())
root = rt.root(AgentSpec(role_prompt="idle"))

squares = agent_map(
    rt, root,
    lambda _item: AgentSpec(role_prompt="squarer"),
    [1, 2, 3, 4, 5],
    timeout_s=5.0,
)
assert squares == [1, 4, 9, 16, 25]   # workers spawned, gathered, terminated
rt.shutdown()

Combinators

All of these are ordinary code over the three primitives — and LLM-callable tools, so agents can invoke them on their own subtrees:

Combinator Shape
agent_map Fan out one worker per item in parallel; gather in order
agent_fold Thread an accumulator sequentially through workers
agent_filter Classification swarm; keep items that pass
agent_fixed_point Iterate an agent on its own output until it stabilizes
agent_race Speculative execution: first reply wins, losers terminated
agent_ensemble Best-of-N: gather all replies, synthesize via an aggregator
agent_critic Generator/critic refinement loop with principled termination

Engines

  • orchestral — wraps orchestral.Agent; multi-provider out of the box (Anthropic, OpenAI, Google, Groq, Ollama).
  • claude_agent (pip install "conjure[claude_agent]") — agents run as claude-agent-sdk sessions with Claude Code's full tool surface (Bash, Edit, Grep, …), per-agent sandbox directories, and permission routing.
  • ScriptedEngine — deterministic behaviors for tests and offline development.

Persistence & replay

Every spawn, send, and terminate is journaled to an append-only JSONL log per session. Runtime.replay(session_dir) reconstructs the spawn tree and all inbox contents for post-hoc inspection — every interaction in a session is auditable.

Limitations (v0.1)

Honest boundaries, documented rather than discovered:

  • Single-process runtime; one OS thread per live agent.
  • Termination does not interrupt an in-flight LLM call; it takes effect after the current step.
  • Per-inbox FIFO ordering only — no global message order.
  • Cost is tracked but not yet enforced as a ceiling.
  • agent_fixed_point uses strict output equality, which stochastic LLMs rarely satisfy — prefer agent_critic for refinement loops.

See DESIGN.md §6 and §10 for where the FP framing breaks down and which workloads the substrate fits poorly.

Development

git clone <repo-url> && cd conjure
pip install -e ".[test,ui]"
pytest -q

License

AGPL-3.0-only. You can use, modify, and redistribute conjure freely — but any distributed or network-served derivative must publish its source under the same terms. For commercial licensing outside the AGPL, contact the author.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

conjure_agents-0.1.1.tar.gz (164.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

conjure_agents-0.1.1-py3-none-any.whl (180.6 kB view details)

Uploaded Python 3

File details

Details for the file conjure_agents-0.1.1.tar.gz.

File metadata

  • Download URL: conjure_agents-0.1.1.tar.gz
  • Upload date:
  • Size: 164.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for conjure_agents-0.1.1.tar.gz
Algorithm Hash digest
SHA256 cb534136fbad5bf304ed5ea608d4e85915cf6276eaa80a40af166c61e77c7e2f
MD5 baeed61882cf2c7629873090807a1e65
BLAKE2b-256 9c6c45eba777f0e6196b4d9d4a7dfa3e6dac511dd9a1f78983518220e5b6bf96

See more details on using hashes here.

File details

Details for the file conjure_agents-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: conjure_agents-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 180.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for conjure_agents-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 109a0a3e7c84b69a32e5101941b9a74df47f4309fc9d29bc8e8451b504c3119a
MD5 94e64d08df71ebabf507fd7cf7e3da6f
BLAKE2b-256 b5a6449102197c149f497b74e99d302368a61d57aafb370918606cf2b9d730a7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page