<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jon Mandraki</title>
    <description>The latest articles on DEV Community by Jon Mandraki (@anonjon).</description>
    <link>https://dev.to/anonjon</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3870323%2Fb9ef47ed-b077-4b13-ab06-294555b312c7.jpg</url>
      <title>DEV Community: Jon Mandraki</title>
      <link>https://dev.to/anonjon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anonjon"/>
    <language>en</language>
    <item>
      <title>We tried every multi-agent framework — then built our own runtime</title>
      <dc:creator>Jon Mandraki</dc:creator>
      <pubDate>Thu, 09 Apr 2026 18:27:56 +0000</pubDate>
      <link>https://dev.to/anonjon/we-tried-every-multi-agent-framework-then-built-our-own-runtime-4f06</link>
      <guid>https://dev.to/anonjon/we-tried-every-multi-agent-framework-then-built-our-own-runtime-4f06</guid>
      <description>&lt;p&gt;Why we gave up on framework-as-library and built Orloj, an open-source orchestration runtime for multi-agent AI systems, with governance enforced at runtime and declarative YAML manifests inspired by Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wall every framework hit
&lt;/h2&gt;

&lt;p&gt;Last year my co-founder Kristiane and I tried to build a production multi-agent system. The use case was boring: a few agents that research, write, review, and publish. The part that wasn't boring was trying to actually run it.&lt;/p&gt;

&lt;p&gt;We tried most of the popular frameworks. Every single one broke down in the same places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Governance was "trust the prompt". Tool permissions lived inside system prompts. One clever jailbreak and the whole thing was wide open.&lt;/li&gt;
&lt;li&gt;State was somebody else's problem. Worker crashes left orphan tasks. Restarts double-ran jobs. There was no durable task queue, no concept of ownership.&lt;/li&gt;
&lt;li&gt;Everything was glued together in Python. Want a non-Python team to edit a workflow? Tough. Want to swap a tool implementation without touching the agent graph? Tough.&lt;/li&gt;
&lt;li&gt;MCP and CLI tools were an afterthought. We use a lot of MCP servers. Managing, and bolting them into every framework felt like a part-time job.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is a knock on those frameworks. They're great for prototyping and small projects. But we wanted something we could hand to a platform team and say "run this in prod." It didn't exist, so we built it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet Orloj
&lt;/h2&gt;

&lt;p&gt;Orloj is an open-source orchestration runtime for multi-agent AI systems. You declare your agents, tools, policies, and workflows in YAML manifests, and Orloj handles scheduling, execution, governance, and reliability. We call it &lt;code&gt;Agent-Infrastructure-as-Code&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you've used Kubernetes or Terraform, the pattern is going to feel familiar, because that's exactly what inspired us. I've been writing Kubernetes manifests and Terraform modules for years, and the declarative, resource-based model just works for distributed systems. Turns out agent systems are distributed systems with extra steps.&lt;/p&gt;

&lt;p&gt;Here's a minimal agent manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orloj.dev/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Agent&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-writer-agent&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;model_ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anthropic-default&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;You are the writer and delivery stage of a Telegram content bot&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;telegram-send-message&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;max_steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's what ties a system together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orloj.dev/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AgentSystem&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-system&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;orloj.dev/pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pipeline&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;agents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-parser-agent&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-planner-agent&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-research-agent&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-writer-agent&lt;/span&gt;
  &lt;span class="na"&gt;graph&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;telegram-bot-parser-agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;edges&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-planner-agent&lt;/span&gt;
    &lt;span class="na"&gt;telegram-bot-planner-agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;edges&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-research-agent&lt;/span&gt;
    &lt;span class="na"&gt;telegram-bot-research-agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;edges&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;telegram-bot-writer-agent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. &lt;code&gt;orlojctl apply -f ./my-system&lt;/code&gt; and the scheduler picks it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things we think we got right
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Governance is a runtime gate, not a prompt instruction&lt;/strong&gt;&lt;br&gt;
This was the biggest unlock for us. Instead of trusting the model to follow instructions like "don't call the delete API", we treat policies as first-class resources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orloj.dev/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AgentPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cost-policy&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;apply_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scoped&lt;/span&gt;
  &lt;span class="na"&gt;target_systems&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;report-system&lt;/span&gt;
  &lt;span class="na"&gt;max_tokens_per_run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50000&lt;/span&gt;
  &lt;span class="na"&gt;allowed_models&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gpt-4o&lt;/span&gt;
  &lt;span class="na"&gt;blocked_tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;filesystem_delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every agent turn and every tool call hits the policy engine before it runs. Unauthorized actions fail closed with a structured error and a full audit trail. If the model tries to call a blocked tool, it doesn't get a polite refusal, it gets a hard stop and a trace entry.&lt;/p&gt;

&lt;p&gt;For anyone who's ever tried to explain to a security team "we ask the AI nicely not to exfiltrate data" knows the feeling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Lease-based task ownership, borrowed from distributed systems&lt;/strong&gt;&lt;br&gt;
Workers claim tasks with a lease. If a worker crashes mid-task, the lease expires and another worker picks it up. No orphans, double-runs. Same pattern Kubernetes uses for controller leader election.&lt;/p&gt;

&lt;p&gt;The practical effect: you can run &lt;code&gt;orlojworker&lt;/code&gt; on whatever compute you want, including heterogeneous fleets. We run some workers on CPU boxes for cheap tool calls and some on GPU boxes for local model inference. The scheduler doesn't care.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Complete audit trails&lt;/strong&gt;&lt;br&gt;
Orloj keeps a complete audit trail via traces to understand and debug how your system is running every step of the way. See how many tokens (input/output) were used per agent. Track which tools were called when and even check the latency throughout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. MCP servers &amp;amp; CLI's are first-class resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Register an MCP server (container, stdio or HTTP) and Orloj auto-discovers its tools. They become resources you can reference in manifests, attach policies to, and audit like anything else. No adapter layer, no wrapper code. Containerized tools just make sense. Why run a MCP server with 24/7 uptime when I may just need it a few times a day? Your MCP server spins up when needed and down when idol.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orloj.dev/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;McpServer&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gmail&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stdio&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp/gmail&lt;/span&gt;
  &lt;span class="na"&gt;idle_timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5m"&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GMAIL_OAUTH_PATH&lt;/span&gt;
      &lt;span class="na"&gt;secretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gmail-creds/oauth_keys&lt;/span&gt;
      &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/secrets/gcp-oauth.keys.json&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GMAIL_CREDENTIALS_PATH&lt;/span&gt;
      &lt;span class="na"&gt;secretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gmail-creds/credentials&lt;/span&gt;
      &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/secrets/credentials.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, every tool the MCP server exposes is usable by agents — and governable by policies.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we're still figuring out
&lt;/h2&gt;

&lt;p&gt;Orloj is still in Beta so here are honest tradeoffs today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The ecosystem is tiny compared to LangGraph or CrewAI. We have examples, templates, and Python/JS SDK's but no massive community contributing yet.&lt;/li&gt;
&lt;li&gt;We don't have a hosted platform. You run &lt;code&gt;orlojd&lt;/code&gt; and &lt;code&gt;orlojworker&lt;/code&gt; yourself. Some teams love this, some want a managed option which is coming in the future.&lt;/li&gt;
&lt;li&gt;The declarative model is great for stable workflows and less great for highly dynamic agent graphs that rewrite themselves at runtime. We're working on it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'd rather ship these honestly than pretend they're not tradeoffs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Everything is Apache 2.0 and on GitHub. The quickstart is a few commands:&lt;br&gt;
Install the cli:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew tap OrlojHQ/orloj
brew &lt;span class="nb"&gt;install &lt;/span&gt;orlojctl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install server/workers&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSfL&lt;/span&gt; https://raw.githubusercontent.com/OrlojHQ/orloj/main/scripts/install.sh | &lt;span class="nv"&gt;ORLOJ_BINARIES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"orlojd"&lt;/span&gt; sh

curl &lt;span class="nt"&gt;-sSfL&lt;/span&gt; https://raw.githubusercontent.com/OrlojHQ/orloj/main/scripts/install.sh | &lt;span class="nv"&gt;ORLOJ_BINARIES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"orlojworker"&lt;/span&gt; sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And once running you can go to &lt;code&gt;localhost:8080&lt;/code&gt; to see the webui and even manage your systems from there.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/OrlojHQ/orloj" rel="noopener noreferrer"&gt;https://github.com/OrlojHQ/orloj&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://docs.orloj.dev" rel="noopener noreferrer"&gt;https://docs.orloj.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Website: &lt;a href="https://orloj.dev" rel="noopener noreferrer"&gt;https://orloj.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've hit the same walls we did, I'd love to hear what you're building. What would you use this for? What's missing? Drop a comment or open an issue.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
