<?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: Halil Agin</title>
    <description>The latest articles on DEV Community by Halil Agin (@halilagin).</description>
    <link>https://dev.to/halilagin</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4026145%2Fd6c5d1a6-8586-41bb-9486-2f1ce40dcf50.jpg</url>
      <title>DEV Community: Halil Agin</title>
      <link>https://dev.to/halilagin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/halilagin"/>
    <language>en</language>
    <item>
      <title>Meet rysh.ai: one agent engine for your terminal, browser, Slack, and website</title>
      <dc:creator>Halil Agin</dc:creator>
      <pubDate>Mon, 20 Jul 2026 11:15:05 +0000</pubDate>
      <link>https://dev.to/halilagin/meet-ryshai-one-agent-engine-for-your-terminal-browser-slack-and-website-12hm</link>
      <guid>https://dev.to/halilagin/meet-ryshai-one-agent-engine-for-your-terminal-browser-slack-and-website-12hm</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://rysh.ai/blog/meet-rysh" rel="noopener noreferrer"&gt;rysh.ai/blog/meet-rysh&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Your company probably runs five AIs that don't know each other exist. rysh is one agent engine for every surface — observable and owned.&lt;/p&gt;

&lt;p&gt;Your company probably runs five AIs that don't know each other exist.&lt;/p&gt;

&lt;p&gt;A coding assistant in the editor. A chatbot bolted onto the website. Someone's LangChain script in a cron job. A Slack bot nobody trusts. And a ChatGPT tab where the actual work happens. Five vendors, five bills, five silos — and not one of them can see what the others did.&lt;/p&gt;

&lt;p&gt;I've been building rysh because I think that's the wrong shape entirely. Not five AIs. One agent engine, every surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  What rysh is
&lt;/h2&gt;

&lt;p&gt;rysh starts life as an agentic terminal multiplexer — think tmux or Zellij, but every pane is a conversation, not just glass in front of a shell. A pane can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a plain shell (it's a real terminal — vim and htop work),&lt;/li&gt;
&lt;li&gt;an AI conversation wired to that shell, your files, and 46+ built-in tools,&lt;/li&gt;
&lt;li&gt;an autonomous agent you spawned from a markdown file,&lt;/li&gt;
&lt;li&gt;or a live external channel — an agent answering your email or your website chat.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You flip a single pane between shell and AI with a double-tap of Escape. Same pane, same working directory, same context. The AI isn't in another tab; it's in the terminal with you.&lt;/p&gt;

&lt;p&gt;Getting started is one binary — the message broker is embedded, so there's no daemon zoo to stand up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;rysh-ai/rysh/rysh
rysh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the terminal is the starting surface, not the whole product. That's the part I want to be precise about, because "AI terminal" undersells what we're actually attempting.&lt;/p&gt;

&lt;h2&gt;
  
  
  One engine, every surface
&lt;/h2&gt;

&lt;p&gt;Here's the core move. In rysh, an agent is a markdown file — persona in the body, configuration in the frontmatter, secrets as &lt;code&gt;${ENV_VAR}&lt;/code&gt; tokens:&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="nn"&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;support-bot&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Support&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;engineer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;our&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CLI&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;product"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="s"&gt;You are support-bot. Answer briefly, only from the product&lt;/span&gt;
&lt;span class="s"&gt;facts below. If you don't know, say so and open a ticket.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spawn it and it becomes a named coworker in your workspace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;##agent spawn support-bot.md
@support-bot triage the failing CI run in pane 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That same file — the same engine underneath — can be wired to external channels as a humanoid: today that's Slack, email (IMAP/SMTP), and website chat, with WhatsApp and phone on the roadmap. The same logic that answers you in a pane answers a customer on your site. One definition, versioned in git, deployed everywhere.&lt;/p&gt;

&lt;p&gt;And the engine's reach keeps going:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browser&lt;/strong&gt; — an agent can drive a real Chrome: navigate, click, extract, fill forms, with recipes written (again) in one markdown file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your APIs&lt;/strong&gt; — Rysh Forge points at an OpenAPI spec and generates agent tools and an MCP server from it (GraphQL/gRPC are roadmap).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The MCP ecosystem&lt;/strong&gt; — rysh is an MCP client, so external MCP servers' tools plug straight into the engine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your team&lt;/strong&gt; — any pane can be shared live to a teammate, view-only or full control, through the collaboration server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The unifying idea: every one of these is the same engine with the same governance. Competitors do one surface. The bet behind rysh is that the surface count is the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents you can trust because you can see them
&lt;/h2&gt;

&lt;p&gt;The reason most companies keep AI at arm's length isn't capability — it's that agents run in black boxes. rysh's answer is architectural, not a dashboard bolted on later.&lt;/p&gt;

&lt;p&gt;Every tool call an agent makes is visible in a pane, as it happens. Dangerous operations don't just execute: file edits show you a coloured diff before anything touches disk, mutating shell commands stop for explicit approval, git commit waits for a yes. Safe, read-only commands flow without friction — the allowlist is safe-by-default, not naggy-by-default.&lt;/p&gt;

&lt;p&gt;For external channels, governance is per-channel: run a humanoid autonomous, or in draft-and-confirm mode where every outbound reply waits for a human in the terminal before it posts (live for email and website chat today). Start careful. Earn trust. Flip the switch when you're ready.&lt;/p&gt;

&lt;p&gt;And when your agent needs to reason about credentials, SecretNAT (&lt;code&gt;##snat&lt;/code&gt;) translates real secret values into stable tokens before anything reaches the model provider — we've verified on the wire that the provider receives the token, not the value. Your keys stay yours in the most literal sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  You own it
&lt;/h2&gt;

&lt;p&gt;The third pillar, and the one I'd argue matters most in five years: ownership.&lt;/p&gt;

&lt;p&gt;Your agent logic lives in markdown files in your repo — reviewable in PRs, diffable, revertable. rysh is self-hostable: run it on your own machines with your own Anthropic key (rysh runs on Claude — more on why we build on the best available model rather than pretending we trained one in a separate post). Your data path is your machine → Anthropic, not your machine → our servers → who knows.&lt;/p&gt;

&lt;p&gt;That's the difference between adopting AI and renting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is going
&lt;/h2&gt;

&lt;p&gt;I call the destination an AI-native company: agents doing real work across dev, ops, and customer support — writing code, running incident response, answering customers — with humans able to see every action, approve the risky ones, and own the logic and the data.&lt;/p&gt;

&lt;p&gt;Most companies today are AI-painted: a chatbot on the website, a copilot in the editor, and a strategy deck. The gap between those two states is exactly the gap rysh is built to close.&lt;/p&gt;

&lt;p&gt;We're early, and I'd rather say that plainly than hide it. Some things are shipped and filmed (we've timed brew install → agent answering on company Slack at 1 minute 47 seconds, real clock on screen). Some things are roadmap, and we label them as roadmap every time.&lt;/p&gt;

&lt;p&gt;If the shape of this resonates — one engine, every surface, observable, owned — the best way in right now is below.&lt;/p&gt;

&lt;p&gt;We're recruiting design partners. Hands-on early access, a direct line to the founder, and your workflow shaping the roadmap. Early is a feature: &lt;a href="https://rysh.ai/design-partner" rel="noopener noreferrer"&gt;rysh.ai/design-partner&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I budget my AI agents like a library — pages, books, and shelves</title>
      <dc:creator>Halil Agin</dc:creator>
      <pubDate>Thu, 16 Jul 2026 10:39:40 +0000</pubDate>
      <link>https://dev.to/halilagin/i-budget-my-ai-agents-like-a-library-pages-books-and-shelves-35kc</link>
      <guid>https://dev.to/halilagin/i-budget-my-ai-agents-like-a-library-pages-books-and-shelves-35kc</guid>
      <description>&lt;p&gt;My biggest fear with autonomous agents was never "will it work."&lt;/p&gt;

&lt;p&gt;It was walking away. You give an agent a goal, it starts looping — browse, extract, save, judge, repeat — and the moment you close the laptop, a question starts nagging: &lt;em&gt;what is this costing right now?&lt;/em&gt; I've checked an API dashboard at 7am the way you check your phone after a night out. Nervously.&lt;/p&gt;

&lt;p&gt;The fix sounds boring: give the loop a budget. But when I actually tried to do that, I ran into a problem I didn't expect — and it wasn't technical.&lt;/p&gt;

&lt;h2&gt;
  
  
  "This run gets 600,000 tokens" means nothing
&lt;/h2&gt;

&lt;p&gt;Tokens are the natural unit for LLM spend, and they are a &lt;em&gt;terrible&lt;/em&gt; unit for humans. Quick: is 600,000 tokens a lot for a research task? Is 50,000 stingy? If a teammate says "I capped the nightly job at 2 million tokens," do you nod because you understand, or because nodding is easier?&lt;/p&gt;

&lt;p&gt;Nobody has intuition for raw token counts. Which means token budgets don't get set — or get set once, wrong, and never touched again.&lt;/p&gt;

&lt;p&gt;While building &lt;a href="https://rysh.ai" rel="noopener noreferrer"&gt;rysh&lt;/a&gt; (an agentic terminal multiplexer — every pane can be a shell, an agent, or a chat), I ended up giving agent budgets a vocabulary borrowed from reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1 page = 1,000 tokens&lt;/strong&gt; — about a page of dense text, honestly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 book = 200 pages&lt;/strong&gt; (200k tokens)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 shelf = 20 books&lt;/strong&gt; (4M tokens)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So a run gets &lt;code&gt;--budget-size 20p&lt;/code&gt; — twenty pages. My Instagram-scouting automation gets &lt;code&gt;3b&lt;/code&gt; — three books per session. A serious overnight job might get a shelf.&lt;/p&gt;

&lt;p&gt;The units changed the conversation more than the enforcement did. "This run gets three books" is a sentence you can say out loud in a planning meeting, and everyone in the room has the same rough picture. "This run gets 600,000 tokens" is a number you paste into a config file and forget. Legible budgets get set, argued about, and tuned. Illegible ones rot.&lt;/p&gt;

&lt;p&gt;(And yes — the ceiling is enforced, not advisory. The loop cannot outspend it.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The anatomy of a budgeted loop
&lt;/h2&gt;

&lt;p&gt;In rysh, an automation is a markdown file with YAML frontmatter, stored under &lt;code&gt;.rysh/automations/&lt;/code&gt; — so the whole loop lives in git, next to the code it serves. Here's the (trimmed) recipe for a real one I run: it scouts podcast-guest candidates on Instagram for a show, discovery-only, and saves a shortlist file.&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;loop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;do&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                       &lt;span class="c1"&gt;# inner loop — one working session&lt;/span&gt;
    &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
    &lt;span class="na"&gt;max_duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;7m&lt;/span&gt;
    &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3b&lt;/span&gt;              &lt;span class="c1"&gt;# 3 books = 600k tokens, hard ceiling&lt;/span&gt;
      &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;takeover_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;   &lt;span class="c1"&gt;# at 90% spent, switch to the wrap-up leg&lt;/span&gt;
        &lt;span class="na"&gt;takeover_prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;The discovery budget is used up — stop browsing now.&lt;/span&gt;
          &lt;span class="s"&gt;Save the shortlist as-is, add a note that it is PARTIAL,&lt;/span&gt;
          &lt;span class="s"&gt;then print the file path and what to cover next time.&lt;/span&gt;

  &lt;span class="na"&gt;while&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                    &lt;span class="c1"&gt;# outer loop — repeat until the goal holds&lt;/span&gt;
    &lt;span class="na"&gt;max_iterations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
    &lt;span class="na"&gt;max_duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;40m&lt;/span&gt;
    &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15b&lt;/span&gt;             &lt;span class="c1"&gt;# whole job: 15 books&lt;/span&gt;
    &lt;span class="na"&gt;prompts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;until&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;The saved shortlist has at least 12 strong candidates, each&lt;/span&gt;
        &lt;span class="s"&gt;with a handle, a why-they-fit line, and a contact — no dupes.&lt;/span&gt;
      &lt;span class="na"&gt;iterate_with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;Continue scouting for {{args}}. The current shortlist is&lt;/span&gt;
        &lt;span class="s"&gt;seeded above: find what's missing, merge, save back.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two loops, two budgets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;do&lt;/code&gt; is one working session.&lt;/strong&gt; It gets its own token ceiling (3 books) &lt;em&gt;and&lt;/em&gt; its own wall-clock cap (7 minutes). Whichever ceiling is hit first wins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;while&lt;/code&gt; wraps the whole job.&lt;/strong&gt; Its budget (15 books) bounds everything the job can ever spend, across all sessions. Even if the goal is never met, the total cost has a known worst case &lt;em&gt;before the job starts&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last sentence is the whole point. You can answer "what will this cost tonight?" at review time, from the diff.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeover leg — because dying at 100% is also a failure
&lt;/h2&gt;

&lt;p&gt;Budgeted loops usually fail in one of two default ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No budget&lt;/strong&gt; → the bill surprises you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A hard cutoff&lt;/strong&gt; → the run dies mid-thought at 100%, and the work in flight is lost.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both are bad, and the second one quietly teaches teams to remove budgets — which gets you back to the first one.&lt;/p&gt;

&lt;p&gt;So the budget has a &lt;code&gt;watch&lt;/code&gt;. &lt;code&gt;takeover_when: 90&lt;/code&gt; means: when 90% of the ceiling is spent, the task's own prompt is taken off the wheel and the &lt;code&gt;takeover_prompt&lt;/code&gt; takes over — with the reserved 10% as &lt;em&gt;its&lt;/em&gt; budget. Its job is not to make progress. Its job is to land the plane: save what exists, label it &lt;code&gt;PARTIAL&lt;/code&gt;, note what's missing, exit clean.&lt;/p&gt;

&lt;p&gt;The run always ends with saved, labeled output. Never a wall.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reset and resume — the loop is interruptible by design
&lt;/h2&gt;

&lt;p&gt;When a &lt;code&gt;do&lt;/code&gt; session ends (goal-ish reached, budget spent, or clock expired), an LLM judge reads the &lt;em&gt;saved output&lt;/em&gt; against the &lt;code&gt;until:&lt;/code&gt; text — a stop condition that's written down in the file, reviewable in code review like everything else.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Goal met&lt;/strong&gt; → the loop ends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not yet&lt;/strong&gt; → the inner budget &lt;strong&gt;resets&lt;/strong&gt; to a fresh 3 books, and the next session starts — seeded with the shortlist the last one saved (that's the &lt;code&gt;iterate_with&lt;/code&gt; prompt). It resumes the work, not the transcript. Each pass starts with a clean context and the &lt;em&gt;artifact&lt;/em&gt;, which is both cheaper and less noisy than dragging a 200k-token history along.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And because sessions checkpoint their state, you can interrupt the whole thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;##auto web stop scout        # park it&lt;/span&gt;
&lt;span class="c"&gt;##auto web continue scout    # resume from the last checkpoint, budget re-armed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;stop&lt;/code&gt; isn't a kill. &lt;code&gt;continue&lt;/code&gt; isn't a restart. The loop picks up where it left off, with a fresh session budget. Then you schedule it and go to sleep:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;##cron add nightly-scout "0 7 * * *" ##auto web run --headless scout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Design decisions I'd defend (and what I'm less sure about)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Human units over raw tokens.&lt;/strong&gt; Covered above, but it's the hill I'll die on: a budget nobody can reason about is a budget nobody maintains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Percentage-based takeover over "detect when stuck."&lt;/strong&gt; &lt;code&gt;takeover_when&lt;/code&gt; is a number (10–99), not a natural-language predicate. Detecting "the agent is stuck" reliably is a research problem; "90% of budget is gone" is a fact. Plain-language guardrails ("stop on any login wall") live in the recipe prompt itself, where the agent applies them per-step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Artifact-seeded resume over transcript replay.&lt;/strong&gt; Restarting from the saved file keeps each pass cheap and forces the automation to define what "its output" actually is — which turns out to be great discipline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'm less sure about:&lt;/strong&gt; the judge. An LLM evaluating &lt;code&gt;until:&lt;/code&gt; is far better than iteration counting, but it's still an LLM reading your criteria — vague goals get vague verdicts. Writing a crisp &lt;code&gt;until:&lt;/code&gt; is the skill; mine took three edits before "12 strong candidates, no dupes, each with a contact" stopped being gameable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest footer
&lt;/h2&gt;

&lt;p&gt;rysh is my product. It's in private beta, built on Claude (bring your own Anthropic key), self-hostable — your automations are files in your repo, not rows in my database. The longer write-up, with the takeover and tunneling mechanics side by side, is here: &lt;a href="https://rysh.ai/blog/agents-on-a-leash" rel="noopener noreferrer"&gt;agents on a leash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you run agents in loops and want to kick the tires while it's early, we're onboarding design partners: &lt;a href="https://rysh.ai/design-partner" rel="noopener noreferrer"&gt;rysh.ai/design-partner&lt;/a&gt; — or tell me why pages/books/shelves is the wrong abstraction. I've been wrong before; that's what the takeover leg is for.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The two scariest parts of autonomous agents — runaway loops and exposed APIs</title>
      <dc:creator>Halil Agin</dc:creator>
      <pubDate>Sun, 12 Jul 2026 17:21:54 +0000</pubDate>
      <link>https://dev.to/halilagin/the-two-scariest-parts-of-autonomous-agents-runaway-loops-and-exposed-apis-1ob7</link>
      <guid>https://dev.to/halilagin/the-two-scariest-parts-of-autonomous-agents-runaway-loops-and-exposed-apis-1ob7</guid>
      <description>&lt;p&gt;Everyone I talk to about autonomous agents has the same two fears, and they're both justified:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The loop runs away.&lt;/strong&gt; You give an agent a goal, it starts iterating, and it either burns
your API budget at 3am or cheerfully does the wrong thing forty times in a row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The access problem.&lt;/strong&gt; For an agent to do real work it needs your &lt;em&gt;internal&lt;/em&gt; APIs — billing,
inventory, the admin service that has no auth story because it was never supposed to leave
localhost. Every "just expose an endpoint" answer makes your security team (rightly) say no.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've been building &lt;a href="https://rysh.ai" rel="noopener noreferrer"&gt;rysh&lt;/a&gt; — an agentic terminal multiplexer where every pane&lt;br&gt;
can be a shell, an agent, or a chat — and these two fears shaped two features I want to walk&lt;br&gt;
through properly, because I think the &lt;em&gt;mechanics&lt;/em&gt; matter more than the pitch. As always on&lt;br&gt;
dev.to: real commands, and an honest list of what's not done at the end.&lt;/p&gt;
&lt;h2&gt;
  
  
  Part 1 — Loop engineering: autonomy with a leash you define
&lt;/h2&gt;

&lt;p&gt;rysh has saved, reusable automations. You write the goal once, then run it with hard limits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# save a recipe (stored under .rysh/automations/)&lt;/span&gt;
&lt;span class="c"&gt;##auto web save scout "find the pricing page, extract the plan names and prices"&lt;/span&gt;

&lt;span class="c"&gt;# run it — with a leash&lt;/span&gt;
&lt;span class="c"&gt;##auto web run --budget-size 50p --max-duration 10m --takeover-when 80 scout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things are going on there, and each one exists because of a real failure mode:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hard budgets, not vibes.&lt;/strong&gt; &lt;code&gt;--budget-size&lt;/code&gt;, &lt;code&gt;--max-iterations&lt;/code&gt;, and &lt;code&gt;--max-duration&lt;/code&gt; are&lt;br&gt;
ceilings, not suggestions — when a ceiling is hit, the loop stops. Budgets are measured in&lt;br&gt;
context tokens with units I'm unreasonably fond of: &lt;strong&gt;pages, books, and shelves&lt;/strong&gt;. A page is&lt;br&gt;
1,000 tokens, a book is 200 pages, a shelf is 20 books — so &lt;code&gt;--budget-size 50p&lt;/code&gt; is a 50k-token&lt;br&gt;
run and &lt;code&gt;3b&lt;/code&gt; (the default) is 600k. "How much should this cost?" becomes a number you set,&lt;br&gt;
not a surprise you discover. There's also &lt;code&gt;--passes N&lt;/code&gt; for fixed-round runs, &lt;code&gt;--while-duration&lt;/code&gt;&lt;br&gt;
/ &lt;code&gt;--while-budget&lt;/code&gt; for open-ended-but-bounded work, and &lt;code&gt;--dry-run&lt;/code&gt; to see what a recipe&lt;br&gt;
&lt;em&gt;would&lt;/em&gt; do before it does it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LLM-judged loop conditions.&lt;/strong&gt; The loop doesn't just count iterations — after each pass, a&lt;br&gt;
judge step evaluates whether the goal is actually met. "Run until the tests pass" means&lt;br&gt;
something; "run 10 times and hope" doesn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Graceful takeover, not a wall.&lt;/strong&gt; &lt;code&gt;--takeover-when 80&lt;/code&gt; means: when 80% of any ceiling is&lt;br&gt;
consumed, the run switches to a &lt;strong&gt;takeover leg&lt;/strong&gt; — a wrap-up prompt you wrote (in the recipe's&lt;br&gt;
&lt;code&gt;takeover_prompt&lt;/code&gt;) takes over the &lt;em&gt;remaining&lt;/em&gt; budget to finish cleanly: save partial results,&lt;br&gt;
report what's missing, print where it stopped. The agent lands the plane instead of hitting a&lt;br&gt;
wall mid-task. (Plain-language guardrails — "stop on any login wall or rate limit" — live in&lt;br&gt;
the recipe prompt itself, where the agent obeys them per-step.)&lt;/p&gt;

&lt;p&gt;The same engine fans out and schedules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# run one recipe across a list&lt;/span&gt;
&lt;span class="c"&gt;##auto web run --each "site-a.com,site-b.com,site-c.com" scout&lt;/span&gt;

&lt;span class="c"&gt;# put it on a schedule — cron can fire ANY rysh input: prompts, @agent calls, shell, automations&lt;/span&gt;
&lt;span class="c"&gt;##cron add nightly-scout "0 2 * * *" --pane scout-pane --mode rysh "##auto web run scout"&lt;/span&gt;
&lt;span class="c"&gt;##cron next     # when does it fire?&lt;/span&gt;
&lt;span class="c"&gt;##cron logs     # what happened last night?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And because interruptions happen, automations (and agents generally) checkpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;@@researcher stop        &lt;span class="c"&gt;# interrupt mid-run — state is preserved&lt;/span&gt;
@@researcher &lt;span class="k"&gt;continue&lt;/span&gt;    &lt;span class="c"&gt;# resume from the checkpoint, not from zero&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Recipes are files (this is where loop engineering gets real)
&lt;/h2&gt;

&lt;p&gt;The one-liner &lt;code&gt;save&lt;/code&gt; is just the front door. A recipe is a &lt;strong&gt;markdown file with YAML&lt;br&gt;
frontmatter&lt;/strong&gt; under &lt;code&gt;.rysh/automations/&lt;/code&gt; — versionable, reviewable, PR-able like everything&lt;br&gt;
else in your repo. Here's a real one from my own setup (lightly trimmed): a scout that&lt;br&gt;
browses Instagram for podcast-guest candidates on a topic, discovery-only, and saves a&lt;br&gt;
shortlist to a results folder.&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="c1"&gt;# .rysh/automations/webs/guest-scout.md&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Discover potential podcast guests on Instagram, scoped to a topic.&lt;/span&gt;
  &lt;span class="s"&gt;Discovery-only (never messages/follows/likes); saves a reviewed shortlist.&lt;/span&gt;
&lt;span class="na"&gt;web_profile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ig-podcast&lt;/span&gt;        &lt;span class="c1"&gt;# persistent, pre-authenticated browser profile&lt;/span&gt;
&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://www.instagram.com/&lt;/span&gt;
&lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;topic&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;                  &lt;span class="c1"&gt;# run as: ##auto web run guest-scout tango&lt;/span&gt;
&lt;span class="na"&gt;output_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;guest-scout/results&lt;/span&gt;
&lt;span class="na"&gt;loop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;do&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                          &lt;span class="c1"&gt;# the INNER loop — one working session&lt;/span&gt;
    &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
    &lt;span class="na"&gt;max_iterations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
    &lt;span class="na"&gt;max_duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;7m&lt;/span&gt;
    &lt;span class="na"&gt;auto_continue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3b&lt;/span&gt;                 &lt;span class="c1"&gt;# 3 "books" = 600k tokens, hard ceiling&lt;/span&gt;
      &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;takeover_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;      &lt;span class="c1"&gt;# at 90% consumed, switch to the wrap-up leg&lt;/span&gt;
        &lt;span class="na"&gt;takeover_prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;The discovery budget is used up — stop browsing now. Save the&lt;/span&gt;
          &lt;span class="s"&gt;shortlist as-is, mark it PARTIAL at the top, print the file path&lt;/span&gt;
          &lt;span class="s"&gt;and what to cover next time.&lt;/span&gt;
  &lt;span class="na"&gt;while&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                       &lt;span class="c1"&gt;# the OUTER loop — repeat sessions until the GOAL holds&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;max_iterations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
    &lt;span class="na"&gt;max_duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;40m&lt;/span&gt;
    &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15b&lt;/span&gt;
    &lt;span class="na"&gt;prompts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;until&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;The saved shortlist contains at least 12 strong candidates, each with&lt;/span&gt;
        &lt;span class="s"&gt;a handle, a why-they-fit line, and a public contact or an explicit&lt;/span&gt;
        &lt;span class="s"&gt;"on-platform only" note — with no duplicate handles.&lt;/span&gt;
      &lt;span class="na"&gt;iterate_with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;Continue scouting for podcast guests about {{args}}, same rules as&lt;/span&gt;
        &lt;span class="s"&gt;before (discovery only; stop on any login wall or rate limit). The&lt;/span&gt;
        &lt;span class="s"&gt;current shortlist is seeded above: find NEW candidates it is missing,&lt;/span&gt;
        &lt;span class="s"&gt;merge, and save back to the same file.&lt;/span&gt;
&lt;span class="s"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;You are browsing Instagram looking for potential podcast GUESTS about&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="err"&gt;**&lt;/span&gt;&lt;span class="pi"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;**&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;

&lt;span class="s"&gt;If **{{args}}** is empty, ask me which topic to scout and stop — do not guess.&lt;/span&gt;

&lt;span class="s"&gt;This is **discovery only** — do NOT message, follow, like, or DM. Just read&lt;/span&gt;
&lt;span class="s"&gt;public pages. If you hit a login wall, captcha, or rate-limit notice&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;STOP&lt;/span&gt;
&lt;span class="s"&gt;immediately and report it.&lt;/span&gt;

&lt;span class="na"&gt;For each candidate collect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;handle, why-they-fit, follower count, public&lt;/span&gt;
&lt;span class="s"&gt;contact (or "none"), and one post that makes them relevant. Aim for 8–12.&lt;/span&gt;

&lt;span class="s"&gt;When done, write the list as Markdown to {{output_dir}}/&amp;lt;topic&amp;gt;-&amp;lt;date&amp;gt;.md&lt;/span&gt;
&lt;span class="s"&gt;and print the saved file path here.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the &lt;code&gt;loop&lt;/code&gt; block again, because the two-level structure is the whole idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;do&lt;/code&gt; loop&lt;/strong&gt; is one bounded working session: step interval, iteration cap, wall-clock
cap, token budget — and at &lt;code&gt;takeover_when: 90&lt;/code&gt; the &lt;code&gt;takeover_prompt&lt;/code&gt; takes the last 10% to
finish gracefully (save partial results, say what's missing).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;while&lt;/code&gt; loop&lt;/strong&gt; wraps it: after each session, the &lt;code&gt;until&lt;/code&gt; condition is judged by the
LLM against actual output — &lt;em&gt;"at least 12 candidates, each with a contact, no duplicate
handles"&lt;/em&gt; — and if it doesn't hold, &lt;code&gt;iterate_with&lt;/code&gt; re-enters with the current shortlist
seeded, under its own outer budget (&lt;code&gt;15b&lt;/code&gt;) and iteration cap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the recipe encodes: &lt;em&gt;what to do, when to act, when to stop, how to stop gracefully, what&lt;br&gt;
"done" actually means, and how to continue if it isn't.&lt;/em&gt; That's what I mean by loop&lt;br&gt;
engineering — the loop is data, not code, and every safety property is declared next to the&lt;br&gt;
goal it protects. &lt;code&gt;{{args}}&lt;/code&gt; templating makes one file a family of automations&lt;br&gt;
(&lt;code&gt;##auto web run guest-scout tango&lt;/code&gt; today, &lt;code&gt;guest-scout "science communicators"&lt;/code&gt; tomorrow),&lt;br&gt;
and results land in &lt;code&gt;output_dir&lt;/code&gt; as dated markdown files you can diff.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;##auto&lt;/code&gt; isn't just for browsers — the same save/run/schedule/budget machinery drives &lt;code&gt;task&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;agent&lt;/code&gt;, and &lt;code&gt;code&lt;/code&gt; automations (&lt;code&gt;##auto code&lt;/code&gt; anchors prompts to a project working directory).&lt;br&gt;
Browser automations can run headless (&lt;code&gt;##web headless on&lt;/code&gt;), so this works on a server without&lt;br&gt;
a desktop session.&lt;/p&gt;

&lt;p&gt;The design position: &lt;strong&gt;the interesting engineering in agent loops isn't the loop — it's the&lt;br&gt;
brakes.&lt;/strong&gt; Budgets, judges, takeover predicates, checkpoints. That's what makes "let it run&lt;br&gt;
overnight" a reasonable sentence instead of a horror-story opener.&lt;/p&gt;
&lt;h2&gt;
  
  
  Part 2 — Forge: your private API, callable by agents, never exposed
&lt;/h2&gt;

&lt;p&gt;Now the access problem. Say your team has an internal REST service on &lt;code&gt;localhost:8080&lt;/code&gt; —&lt;br&gt;
or behind your VPN — and you want &lt;em&gt;agents&lt;/em&gt; (yours, or a teammate's in another rysh session)&lt;br&gt;
to call it. The standard options are all bad: expose it publicly behind auth you now have to&lt;br&gt;
harden, hand out credentials to every agent runtime, or don't do it at all.&lt;/p&gt;

&lt;p&gt;Here's the rysh flow. First, turn the spec into tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;##forge add billing ./billing-openapi.yaml&lt;/span&gt;
&lt;span class="c"&gt;##integration enable billing&lt;/span&gt;
&lt;span class="c"&gt;# your agents can now call the billing API as ordinary tools — locally&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Forge ingests the OpenAPI spec and generates governed agent tools, plus a standalone MCP&lt;br&gt;
server, SDKs (Go/Python/TypeScript/Java), and docs. That alone is useful. But here's the part&lt;br&gt;
I haven't seen elsewhere — &lt;strong&gt;share the API to another session's agents without exposing it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# you (the API owner):&lt;/span&gt;
&lt;span class="c"&gt;##forge share api billing&lt;/span&gt;

&lt;span class="c"&gt;# your teammate, in their own rysh session:&lt;/span&gt;
&lt;span class="c"&gt;##forge subscribe billing --scope pane&lt;/span&gt;
&lt;span class="c"&gt;# their agent now sees the billing operations as normal tools&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What actually happens when their agent calls one of those tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The subscriber side sends only the &lt;strong&gt;operation name + arguments&lt;/strong&gt; over the rysh upstream
(NATS over WebSocket — the same channel used for live pane sharing).&lt;/li&gt;
&lt;li&gt;Your session receives the request, checks it against &lt;strong&gt;your&lt;/strong&gt; allowlist, and — this is the
key part — &lt;strong&gt;executes the real HTTP call locally, from your machine&lt;/strong&gt;, where
&lt;code&gt;localhost:8080&lt;/code&gt; actually resolves.&lt;/li&gt;
&lt;li&gt;The response is &lt;strong&gt;redacted&lt;/strong&gt; (secrets stripped) and sent back as the tool result.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The remote agent never learns the API's address. The API is never bound to a public interface.&lt;br&gt;
No credentials leave your machine. The endpoint stays exactly where it was — behind your&lt;br&gt;
firewall — and requests tunnel through rysh to be executed by the only party that was already&lt;br&gt;
trusted to call it: you.&lt;/p&gt;

&lt;p&gt;The safety posture, because this feature is only as good as its defaults:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Off by default.&lt;/strong&gt; API sharing requires explicit opt-in configuration &lt;em&gt;and&lt;/em&gt; a control-mode
share — you can't leak an API by accident.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default-deny mutations.&lt;/strong&gt; Shared operations are read-only unless you explicitly allowlist
mutating ones. A remote agent can &lt;code&gt;GET /invoices&lt;/code&gt;; it cannot &lt;code&gt;DELETE&lt;/code&gt; anything you didn't
name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forge-origin only.&lt;/strong&gt; Only Forge-generated API tools can enter the shareable set — built-in
tools (bash, file access) provably cannot be shared through this path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redaction + rate limits.&lt;/strong&gt; Responses pass through secret redaction before leaving your
session, and the server enforces per-day quotas and rate limits on invocations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This path is end-to-end tested and went through an adversarial security audit before I'd let&lt;br&gt;
anyone use it — I'll happily go deeper on the invariants in the comments.&lt;/p&gt;

&lt;p&gt;Honest scope note: &lt;strong&gt;Forge is OpenAPI-only today.&lt;/strong&gt; gRPC ingest is a stub and there's no&lt;br&gt;
GraphQL runtime. If your API has a spec, this works now; if not, not yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why these two features are the same feature
&lt;/h2&gt;

&lt;p&gt;Both are answers to the same question: &lt;em&gt;how much power can you give an agent while keeping a&lt;br&gt;
human meaningfully in control?&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loops: as much autonomy as you want, &lt;strong&gt;bounded by budgets and takeover legs you wrote&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;APIs: as much access as you grant, &lt;strong&gt;executed only on your machine, read-only by default&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the design thesis behind rysh generally — every tool call visible in the pane, dangerous&lt;br&gt;
actions gated behind approval, secrets redacted before anything leaves your session. Agents you&lt;br&gt;
can trust because you can &lt;em&gt;see&lt;/em&gt; them and &lt;em&gt;bound&lt;/em&gt; them, not because a vendor promised.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack, briefly
&lt;/h2&gt;

&lt;p&gt;Go; an actor runtime over NATS for all messaging (the tunneling above is "just" the same&lt;br&gt;
actor/subject machinery that powers live pane sharing); Bubble Tea TUI. It runs &lt;strong&gt;on Anthropic&lt;br&gt;
Claude&lt;/strong&gt; — I'm not claiming a better model; the value is the governance and the surfaces around&lt;br&gt;
it. Self-hostable on your own key; the provider layer is pluggable, Claude is the live backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's not done (don't believe me if I imply otherwise)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Forge: &lt;strong&gt;OpenAPI only&lt;/strong&gt; — gRPC ingest is a stub, no GraphQL runtime&lt;/li&gt;
&lt;li&gt;WhatsApp / phone humanoid channels (not live)&lt;/li&gt;
&lt;li&gt;Token-by-token streaming in the CLI (responses land on completion)&lt;/li&gt;
&lt;li&gt;Hosted billing is gated on dev, not live&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Rysh is in &lt;strong&gt;private beta&lt;/strong&gt; — the code isn't public yet. It's self-hostable (you run it on&lt;br&gt;
your own infra with your own Anthropic key), and access right now is through the&lt;br&gt;
&lt;strong&gt;design-partner program&lt;/strong&gt;: free access, a direct line to me, and your feedback sets the&lt;br&gt;
roadmap. If you have one internal API you'd love agents to use safely, or one workflow you&lt;br&gt;
want to run overnight on a leash, that's exactly the conversation I want:&lt;br&gt;
&lt;a href="https://rysh.ai/design-partner" rel="noopener noreferrer"&gt;apply to the design-partner program&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feedback on the tunneling trust model is especially welcome — poke holes in it in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>security</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
