loopctl runs the part of an agent that is not intelligence: send the conversation, read the stream, call the tools, shrink the history, catch the loops, survive the failures, stop on command. You bring the model connection and your tools — it brings the rest, without a panic in sight.
A complete, working agent from examples/hello-cli.rs — it runs with a mock connection, no API key. Swap the mock for an OpenAI, Anthropic, Gemini, Bedrock, or Ollama client and nothing else changes.
BareLoop is the default engine. Its run() does the entire round-trip: send the conversation, read the stream, execute tool calls, feed results back, repeat until the model gives a final answer.
The result is a typed Run — the final text, turn count, tool calls, token usage. When things go wrong you get a typed error, never a panic; even a tool that panics is caught and reported as a message the model can read.
The engine splits in two at a strict border. The brain — LoopMachine — is pure data: it never touches the network. The hands — BareLoop — do whatever the brain asked, then report back, with middleware, hooks, observers and managers standing guard over everything they touch. Hover any band to see it light up.
Pure data in, pure data out. To check “after three identical tool results, does it detect a loop?” you feed a machine results and read what it says — no fake network, no flaky tests.
The brain serializes. Take a running agent, turn it into JSON, store it anywhere, and put it into a fresh body later — on another machine if you like.
The brain never learns who the model is. The hands speak to it through one small trait, so OpenAI becomes a local Ollama and nothing upstream notices.
Every system below is opt-in, composable, and documented to the threshold — each one has a page in the knowledge base explaining exactly when it fires and what it costs.
OpenAI ·Anthropic ·Google Gemini ·AWS Bedrock ·Azure OpenAI ·Ollama ·DeepSeek ·Moonshot ·xAI Grok ·Z.ai ·or implement one trait — ApiClient — and bring your own.