Skip to content

Embed a coding agent

Chimera’s assembled coding agent is embeddable through one documented, stable surface: chimera.AgentSession (a session your app owns) and chimera.run_agent (the blocking one-liner). You do not need the TUI, the CLI, or any knowledge of the 8-layer internals — the same seam Chimera’s own frontends run on is importable from the package root.

Stability: this surface is semver-stable within the 0.9.x line — additions only, no renames, no signature breaks.

Terminal window
pip install "chimera-run[anthropic]"

The PyPI package is chimera-run; the import name is chimera. The anthropic extra carries the wire client used by Anthropic-protocol endpoints — that includes GLM served via api.z.ai, which is what the examples below use.

Point the environment at your model endpoint. For GLM-5 via z.ai (the setup Chimera itself is tested against):

Terminal window
export ANTHROPIC_BASE_URL="https://api.z.ai/api/anthropic"
export ANTHROPIC_API_KEY="your-z.ai-key"

Any model id the provider factory recognizes works the same way — claude-sonnet-4-... (hosted Anthropic), gpt-... (OpenAI), gemini-... (Google), qwen3/llama/… (local Ollama, no key needed), or a modal-endpoint/... model you serve yourself. The model string is the only thing you change; see the Third-Party Providers guide on the docs site for every backend’s environment variables.

Save as embed_demo.py and run it. It gives the agent a scratch directory, streams every event of one real coding turn, then prints what it cost:

import asyncio
import pathlib
import chimera
WORKDIR = pathlib.Path("chimera-scratch")
WORKDIR.mkdir(exist_ok=True)
TASK = "Create fib.py containing a fibonacci(n) function with a docstring."
async def main() -> None:
with chimera.AgentSession(model="glm-5.2", project_dir=WORKDIR) as session:
async for ev in session.send(TASK):
line = chimera.render_event(ev)
if line:
end = "" if ev.type == chimera.LoopEventType.assistant_chunk else "\n"
print(line, end=end, flush=True)
print(f"\ncost: ${session.total_cost:.4f} across {session.turn_count} turn(s)")
asyncio.run(main())

You will watch the model think, call write_file, and finish — then find chimera-scratch/fib.py on disk and the session’s real dollar cost on your terminal. render_event is the no-frills renderer; the typed events are yours to render differently (below).

No event loop, no streaming — task in, result out:

import chimera
result = chimera.run_agent(
"Create fib.py containing a fibonacci(n) function.",
model="glm-5.2",
project_dir="chimera-scratch",
)
print(result.text) # the final assistant message
print(f"${result.cost_usd:.4f} in {result.steps} step(s), {result.reason}")

run_agent returns a TurnResulttext, cost_usd, steps, reason ("completed", "max_turns", …), duration_ms, usage. Inside an async app, use await session.run_async(task) instead.

send() is an async generator, so your app stays responsive while a turn runs — and can inject course corrections between tool calls:

async def steered() -> None:
with chimera.AgentSession(model="glm-5.2", project_dir=WORKDIR) as session:
async def consume() -> None:
async for ev in session.send("Refactor utils.py into a package."):
... # render events
turn = asyncio.create_task(consume())
await asyncio.sleep(5)
session.steer("Keep the public API identical — re-export everything.")
await turn

session.queue_follow_up(text) instead waits until the agent would stop, then hands it the next instruction. session.cancel() aborts cooperatively.

Swap the model — including one you serve yourself

Section titled “Swap the model — including one you serve yourself”

The session is model-agnostic; the string picks the backend:

chimera.AgentSession(model="glm-5.2[1m]", ...) # GLM, 1M-token window
chimera.AgentSession(model="claude-sonnet-4-20250514", ...) # hosted Anthropic
chimera.AgentSession(model="qwen3", ...) # local Ollama
chimera.AgentSession(model="modal-endpoint/zai-org/GLM-5.2-FP8", ...)

The last line talks to an inference endpoint you deployed on Modal — scale-to-zero GPU serving with the same session code; setup in docs/guides/use-modal-endpoints.md.

Render events yourself — a custom frontend

Section titled “Render events yourself — a custom frontend”

Every event is a chimera.LoopEvent with a chimera.LoopEventType: assistant_chunk (streamed text deltas), tool_use / tool_result, thinking_chunk, compact_boundary, error, and a terminal result carrying cost and duration. Switch on ev.type and render however your UI wants:

async for ev in session.send(task):
if ev.type == chimera.LoopEventType.tool_use:
show_spinner(ev.data.name, ev.data.arguments)
elif ev.type == chimera.LoopEventType.assistant_chunk:
append_to_chat(ev.data)

The full event vocabulary, the double-print rule, and the path from “REPL” to “multi-lane TUI” are in docs/building-a-tui.md — everything there applies, because AgentSession is the same driver the Chimera TUIs use.

TierYou writeYou get
One-linerchimera.run_agent(task, model=..., project_dir=...)a finished turn: TurnResult
Configuredchimera.AgentSession(model=..., preset=..., max_turns=..., provider=..., permission_callback=...)streaming send(), blocking run()/run_async(), steer / queue_follow_up / cancel / clear / close, and model / tools / total_cost / turn_count / history / context_window
Subclassableclass Mine(chimera.AgentSession) — or inject provider= / tools_override= / extra_tools=your behavior on the same stable contract

Notes for embedders:

  • Working directory. The agent’s file and shell tools are rooted at project_dir. Point it at a scratch directory first; point it at a real repo when you mean it.
  • Approvals. With no permission_callback, the embedded agent auto-approves its own tool calls (bypass mode). Pass a callback to gate risky actions through your own UI.
  • Presets. coding_agent (default, full stack), codex, minimal (four basic tools), explore (read-only) — the read-only preset is the safe choice for untrusted tasks.
  • Cost. session.total_cost accrues across turns from per-model pricing; unpriced models report 0.0.