<?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>Forem: Aaron Walker</title>
    <description>The latest articles on Forem by Aaron Walker (@aaron_walker_dc0d1194638f).</description>
    <link>https://forem.com/aaron_walker_dc0d1194638f</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%2F3745891%2Fbfb4339e-72a1-4293-9cf6-89e8689e52db.jpg</url>
      <title>Forem: Aaron Walker</title>
      <link>https://forem.com/aaron_walker_dc0d1194638f</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/aaron_walker_dc0d1194638f"/>
    <language>en</language>
    <item>
      <title>Jailbreaking Claude Cowork: Escaping the “Sandbox”</title>
      <dc:creator>Aaron Walker</dc:creator>
      <pubDate>Mon, 02 Feb 2026 03:50:39 +0000</pubDate>
      <link>https://forem.com/aaron_walker_dc0d1194638f/escaping-the-sandbox-jailbreaking-claude-cowork-dbd</link>
      <guid>https://forem.com/aaron_walker_dc0d1194638f/escaping-the-sandbox-jailbreaking-claude-cowork-dbd</guid>
      <description>&lt;h2&gt;
  
  
  Checkout The Repo: &lt;a href="https://github.com/virtuosotravlr/cowork-bridge" rel="noopener noreferrer"&gt;Cowork-Bridge&lt;/a&gt;
&lt;/h2&gt;




&lt;h4&gt;
  
  
  TL;DR: The "Bridge" Protocol
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Claude’s Cowork mode is a powerful orchestrator, but its security sandbox (running under bwrap) blocks real-world developer tasks like hitting private APIs, running Docker, or using local git credentials.&lt;br&gt;
I built a bidirectional filesystem bridge that turns the Cowork VM into a frontend UX while delegating restricted tasks to a host-side watcher.&lt;br&gt;
&lt;strong&gt;The Hack:&lt;/strong&gt; An "RPC over a mounted folder" protocol using JSON requests and responses.&lt;br&gt;
&lt;strong&gt;The Capability:&lt;/strong&gt; Enables host-side execution of curl, git, docker, and even "Claude-to-Claude" delegation using the unrestricted host CLI.&lt;br&gt;
&lt;strong&gt;The Secret Sauce:&lt;/strong&gt; A script to rewrite Cowork's internal systemPrompt to remove "guardrail rituals" and treat the agent like a high-speed power tool.&lt;br&gt;
&lt;strong&gt;The Setup:&lt;/strong&gt; Fully automated via a background daemon that detects and "bridges" new Cowork sessions as soon as they are created.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A Love/Hate Relationship with Claude Cowork
&lt;/h2&gt;

&lt;p&gt;Cowork mode is awesome… until you try to do real power-user things.&lt;br&gt;
I wanted Claude in Cowork to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hit arbitrary APIs (not just allowlisted domains)&lt;/li&gt;
&lt;li&gt;push to git remotes with real credentials&lt;/li&gt;
&lt;li&gt;run Docker on my machine&lt;/li&gt;
&lt;li&gt;use my custom agents + MCP servers&lt;/li&gt;
&lt;li&gt;behave like a dev tool, not a guarded assistant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, I kept slamming into the reality of Cowork’s sandbox: a VM launched with isolation tooling (in my case I confirmed it’s running under bwrap / bubblewrap), with restricted host access and outbound network limitations that show up the moment your workflow touches something outside the box.&lt;/p&gt;

&lt;p&gt;So I built a bridge.  It is a bidirectional filesystem protocol between the sandboxed Cowork VM and an unrestricted Claude CLI running on my Mac (optionally in Docker). Cowork writes requests into a shared folder; a host-side watcher executes them with full capabilities and writes responses back.&lt;/p&gt;

&lt;p&gt;It’s basically “RPC over a mounted folder.” Here is the idea in a diagram:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="err"&gt;┌─────────────────────────────────────────────────────────────────┐&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="no"&gt;COWORK&lt;/span&gt; &lt;span class="nf"&gt;VM&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sandboxed&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;                                          &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                                                                 &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="s"&gt;"Fetch from api.example.com, then summarize"&lt;/span&gt;                    &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                           &lt;span class="err"&gt;│&lt;/span&gt;                                     &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                           &lt;span class="err"&gt;▼&lt;/span&gt;                                     &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mnt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;/.&lt;/span&gt;&lt;span class="na"&gt;bridge&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;...-&lt;/span&gt;&lt;span class="mo"&gt;001&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;json&lt;/span&gt;           &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;└───────────────────────────┬─────────────────────────────────────┘&lt;/span&gt;
                            &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mounted&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="n"&gt;folder&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                            &lt;span class="err"&gt;▼&lt;/span&gt;
&lt;span class="err"&gt;┌─────────────────────────────────────────────────────────────────┐&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="no"&gt;HOST&lt;/span&gt; &lt;span class="nf"&gt;MAC&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unrestricted&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;                                        &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                                                                 &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sh&lt;/span&gt; &lt;span class="n"&gt;sees&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;executes&lt;/span&gt; &lt;span class="nf"&gt;it&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;curl&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="no"&gt;CLI&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="n"&gt;writes&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="nf"&gt;JSON&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;                            &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                           &lt;span class="err"&gt;│&lt;/span&gt;                                     &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                           &lt;span class="err"&gt;▼&lt;/span&gt;                                     &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="o"&gt;.../&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;/.&lt;/span&gt;&lt;span class="na"&gt;bridge&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="o"&gt;...-&lt;/span&gt;&lt;span class="mo"&gt;001&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;json&lt;/span&gt;           &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;└───────────────────────────┬─────────────────────────────────────┘&lt;/span&gt;
                            &lt;span class="err"&gt;│&lt;/span&gt;
                            &lt;span class="err"&gt;▼&lt;/span&gt;
&lt;span class="err"&gt;┌─────────────────────────────────────────────────────────────────┐&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="no"&gt;COWORK&lt;/span&gt; &lt;span class="no"&gt;VM&lt;/span&gt;                                                       &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                                                                 &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="nc"&gt;Reads&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="nf"&gt;JSON&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="n"&gt;tails&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="n"&gt;continues&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;└─────────────────────────────────────────────────────────────────┘&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cowork stays your chat UX + orchestration brain.&lt;br&gt;
Your Mac (and optionally host Claude CLI) becomes the executor with real access.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Cowork feels powerful… and then suddenly doesn’t
&lt;/h2&gt;

&lt;p&gt;Cowork is designed to be safe and broadly usable. That’s great. But if you’re doing developer workflows, the safety posture often translates to friction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;outbound HTTP is restricted (in my environment it was allowlisted)&lt;/li&gt;
&lt;li&gt;anything touching your real machine—Docker, credentialed git, custom toolchains—becomes awkward or blocked&lt;/li&gt;
&lt;li&gt;the agent behaves like it must follow guardrail rituals (more on that later)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My goal became simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep Cowork for the UX, but delegate anything restricted to a host-side executor I control.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s the bridge.&lt;/p&gt;


&lt;h2&gt;
  
  
  Architecture: two “sides” + one shared directory
&lt;/h2&gt;

&lt;p&gt;This repo is conceptually two components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;VM-side:&lt;/strong&gt; cowork-bridge: A small “skill” that writes requests into the shared folder and polls for responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Host-side:&lt;/strong&gt; cli-bridge watcher: A script (watcher.sh) that watches for new requests and executes them on the host with full permissions (optionally inside Docker).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The transport layer is just files.&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 1 — The protocol (deep dive)
&lt;/h2&gt;

&lt;p&gt;The protocol is intentionally boring. That’s a feature:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you can inspect it with &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;cat&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;you can debug it by reading the request/response JSON&lt;/li&gt;
&lt;li&gt;it doesn’t depend on network access&lt;/li&gt;
&lt;li&gt;it works even when the sandbox is locked down&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The bridge lives under a .bridge/ directory inside the session’s shared outputs folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;.bridge/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;requests/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Cowork writes request JSON files here&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;responses/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Host watcher writes response JSON files here&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;streams/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Optional: streaming output log files&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;logs/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Audit/debug logs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s also a small status.json file written during initialization so the VM side can confirm it’s wired up.&lt;/p&gt;

&lt;h3&gt;
  
  
  File locations (VM vs host)
&lt;/h3&gt;

&lt;p&gt;This is the key trick: the same files appear in two places.&lt;/p&gt;

&lt;p&gt;Inside the Cowork VM, you’ll typically see it under something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;/sessions/&amp;lt;session-name&amp;gt;/mnt/outputs/.bridge/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the host Mac, the same folder is inside Claude’s session directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;~/Library/Application&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Support/Claude/local-agent-mode-sessions/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;account-id&amp;gt;/&amp;lt;workspace-id&amp;gt;/local\_&amp;lt;session-id&amp;gt;/outputs/.bridge/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you accept that “Cowork sessions are just directories,” this stops feeling like a hack and starts feeling like infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Request format
&lt;/h3&gt;

&lt;p&gt;Each request is a single JSON file at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;requests/&amp;lt;job-id&amp;gt;.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A request has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; — unique job ID (also the filename)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt; — what kind of operation to run&lt;/li&gt;
&lt;li&gt;type-specific fields (&lt;code&gt;command&lt;/code&gt;, &lt;code&gt;args&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;prompt&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;timeout&lt;/code&gt; — seconds&lt;/li&gt;
&lt;li&gt;optional &lt;code&gt;env&lt;/code&gt; — values or references (e.g., $HOST_API_KEY)&lt;/li&gt;
&lt;li&gt;optional &lt;code&gt;cwd&lt;/code&gt; — where to run on host&lt;/li&gt;
&lt;li&gt;optional &lt;code&gt;stream&lt;/code&gt;: true — for streaming output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a representative exec request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"job-20260201-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-02-01T03:14:15Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"exec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-lc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"curl -s https://api.example.com/data | jq ."&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"cwd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/projects/my-app"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The watcher script is careful to avoid the classic “shell injection by string concatenation” problem: for sensitive handlers it builds argument arrays and sends prompts via stdin rather than interpolating them into shell strings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Request types (and why they exist)
&lt;/h3&gt;

&lt;p&gt;In principle, you could make everything exec.  But first-class request types make the system safer and easier to audit.&lt;/p&gt;

&lt;p&gt;Supported types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;exec&lt;/code&gt; — run a shell command&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;http&lt;/code&gt; — make an HTTP request directly (safer than crafting curl strings)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git&lt;/code&gt; — git operations with credentials&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;node&lt;/code&gt; — node/npm/npx/yarn/pnpm style commands&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker&lt;/code&gt; — run docker commands on host&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prompt&lt;/code&gt; — delegate to host Claude CLI (Claude-to-Claude)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;env&lt;/code&gt; — inject env vars into the VM session settings&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;file&lt;/code&gt; — read/write/list/check existence on the host filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Response format
&lt;/h3&gt;

&lt;p&gt;Each response is a JSON file at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;responses/&amp;lt;job-id&amp;gt;.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A response includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exit_code&lt;/code&gt; (where relevant)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stdout&lt;/code&gt; / &lt;code&gt;stderr&lt;/code&gt; (unless streaming)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;duration_ms&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;error&lt;/code&gt; (structured when possible)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"job-20260201-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-02-01T03:14:16Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"exit_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"stdout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{ &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;ok&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: true }"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"stderr"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"duration_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;842&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Status values
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pending&lt;/code&gt; — request received, not started&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;running&lt;/code&gt; — executing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;completed&lt;/code&gt; — success&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;failed&lt;/code&gt; — finished with error&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;timeout&lt;/code&gt; — exceeded timeout&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;streaming&lt;/code&gt; — output is in a stream file (see below)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Streaming protocol (for logs + huge outputs)
&lt;/h3&gt;

&lt;p&gt;Some outputs don’t belong inside JSON:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;long-running commands (docker logs -f, watchers)&lt;/li&gt;
&lt;li&gt;huge outputs (large diffs, large JSON responses)&lt;/li&gt;
&lt;li&gt;long Claude CLI responses&lt;/li&gt;
&lt;li&gt;anything you’d naturally “tail”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Streaming can happen in three ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicit: request includes "stream": true&lt;/li&gt;
&lt;li&gt;Auto-stream: output exceeds a threshold (default is ~50KB in the watcher)&lt;/li&gt;
&lt;li&gt;Naturally continuous: logs/watch commands&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What happens during streaming
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8xc6u3xs426pd4d5wykj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8xc6u3xs426pd4d5wykj.jpg" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Host creates &lt;code&gt;streams/&amp;lt;job-id&amp;gt;.log&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Host writes output incrementally to the stream file&lt;/li&gt;
&lt;li&gt;Host writes a sentinel line &lt;code&gt;**STREAM_END**&lt;/code&gt; when complete&lt;/li&gt;
&lt;li&gt;Host writes the final &lt;code&gt;responses/&amp;lt;job-id&amp;gt;.json&lt;/code&gt; with bytes_written, exit_code, etc.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On the Cowork side, it just does:&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="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /mnt/outputs/.bridge/streams/job-20260201-logs.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you can read incrementally with offset tracking if you want to be fancy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2 — The skills: VM-side ergonomics + host-side execution
&lt;/h2&gt;

&lt;p&gt;The bridge feels “native” only if Cowork can use it naturally.  That’s why there are two skills:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. cowork-bridge (inside the VM)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the “client” side. It gives Cowork a repeatable workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;confirm bridge is initialized (status.json)&lt;/li&gt;
&lt;li&gt;write a request JSON file into requests/&lt;/li&gt;
&lt;li&gt;poll responses/ until the matching response exists&lt;/li&gt;
&lt;li&gt;return the result (or stream pointer)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skill doc includes a simple step-by-step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;“Write&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;request”&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“Poll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;response”&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“Tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stream”&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also includes helper shell functions that make this nice from inside the VM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;job ID generator&lt;/li&gt;
&lt;li&gt;“write request + wait”&lt;/li&gt;
&lt;li&gt;“stream request + tail until sentinel”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters more than it sounds: once you have one-liners, Cowork can be guided to reliably use them and you stop re-inventing glue code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. cli-bridge (host watcher)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The host side is a loop that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;finds the latest active session (or uses an explicit &lt;code&gt;--session&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;finds that session’s &lt;code&gt;.bridge/requests/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;processes each JSON request file&lt;/li&gt;
&lt;li&gt;routes by &lt;code&gt;type&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;writes response JSON&lt;/li&gt;
&lt;li&gt;logs everything to &lt;code&gt;.bridge/logs/bridge.log&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Watcher defaults (useful details)
&lt;/h3&gt;

&lt;p&gt;The watcher is configurable via env vars, but defaults include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;poll interval: 1 second&lt;/li&gt;
&lt;li&gt;stream threshold: ~50KB (&lt;code&gt;51200&lt;/code&gt; bytes)&lt;/li&gt;
&lt;li&gt;allowed types: exec/http/git/node/docker/prompt/env/file&lt;/li&gt;
&lt;li&gt;a small blocked-command list for obviously dangerous footguns (&lt;code&gt;rm -rf /&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Streaming support on host
&lt;/h3&gt;

&lt;p&gt;Streaming is currently supported for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;exec&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prompt&lt;/code&gt; (Claude-to-Claude), including streamed Claude output&lt;/li&gt;
&lt;li&gt;Other types typically return normal JSON responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 3 — Claude-to-Claude delegation (&lt;code&gt;prompt&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;This is the feature that turns the bridge from “job runner” into “distributed agent.”&lt;/p&gt;

&lt;p&gt;A prompt request looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"job-20260201-claude-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fetch latest issues in my repo and summarize"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"agent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-github-agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sonnet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Read"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Write"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"system_prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"You are helping a sandboxed Cowork session. Be concise."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the host, the watcher calls Claude CLI roughly like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sends prompt via stdin (safer)&lt;/li&gt;
&lt;li&gt;passes through &lt;code&gt;--agent&lt;/code&gt;, &lt;code&gt;--model&lt;/code&gt;, &lt;code&gt;--tools&lt;/code&gt;, &lt;code&gt;--system-prompt&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So Cowork becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;frontend&lt;/strong&gt; (chat + context + orchestration)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;router&lt;/strong&gt; (decide what to delegate)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;consumer&lt;/strong&gt; (read the response and continue)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And host Claude becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;full network&lt;/li&gt;
&lt;li&gt;real filesystem&lt;/li&gt;
&lt;li&gt;your real tools + credentials&lt;/li&gt;
&lt;li&gt;your agent library&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have this, “sandbox limitations” stop being blockers—they become a routing decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4 — System prompt rewrites: making Cowork behave like a power tool
&lt;/h2&gt;

&lt;p&gt;This is the part that feels slightly illegal the first time you do it.  It turns out that the Cowork session configuration lives in a directory on the host, and that the session prompt is stored in the JSON.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why prompt injection matters
&lt;/h3&gt;

&lt;p&gt;The default Cowork prompt is optimized for broad safety and “non-developer” workflows, which can translate to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mandatory TodoWrite&lt;/li&gt;
&lt;li&gt;mandatory ask-a-question-before-work patterns&lt;/li&gt;
&lt;li&gt;refusal patterns for curl/wget/requests even via bash&lt;/li&gt;
&lt;li&gt;verbose confirmations&lt;/li&gt;
&lt;li&gt;“read skill docs even for trivial actions”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was simply too much overhead.  So I created prompt presets that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;assume developer competence&lt;/li&gt;
&lt;li&gt;allow terse, CLI-like responses&lt;/li&gt;
&lt;li&gt;make TodoWrite/AskUserQuestion optional (not ritual)&lt;/li&gt;
&lt;li&gt;build in “use the bridge automatically when sandbox limits appear”&lt;/li&gt;
&lt;li&gt;make Claude-to-Claude delegation first-class&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The presets
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;power-user — dev mode + bridge awareness&lt;/li&gt;
&lt;li&gt;cli-mode — terse, Claude Code-esque behavior&lt;/li&gt;
&lt;li&gt;minimal — barebones prompt, maximum freedom&lt;/li&gt;
&lt;li&gt;unrestricted — “no limitations” posture (use carefully)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Injecting prompts
&lt;/h3&gt;

&lt;p&gt;In the repo, there’s a script that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;list presets&lt;/li&gt;
&lt;li&gt;backup the original config (cowork_settings.json.original)&lt;/li&gt;
&lt;li&gt;inject a preset&lt;/li&gt;
&lt;li&gt;show the current prompt (truncated)&lt;/li&gt;
&lt;li&gt;restore the original&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&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;# list presets&lt;/span&gt;

./scripts/inject-prompt.sh &lt;span class="nt"&gt;--list&lt;/span&gt;

&lt;span class="c"&gt;# backup original&lt;/span&gt;

./scripts/inject-prompt.sh &lt;span class="nt"&gt;--backup&lt;/span&gt; power-user

&lt;span class="c"&gt;# inject power-user&lt;/span&gt;

./scripts/inject-prompt.sh power-user

&lt;span class="c"&gt;# restore original&lt;/span&gt;

./scripts/inject-prompt.sh &lt;span class="nt"&gt;--restore&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The best part: changes apply immediately (next message), no restart needed.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A note on template variables
&lt;/h3&gt;

&lt;p&gt;The prompt files are JSON and support template vars (things like current working directory, selected folders, etc.), which means you can write prompts that adapt to the session context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 5 — The scripts: making it reliable across sessions
&lt;/h2&gt;

&lt;p&gt;If this stayed a manual hack, it would die in a week. Sessions come and go. Paths change. New sessions appear. So I built scripts that turn it into “set and forget.”&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;install.sh&lt;/code&gt; — main installer
&lt;/h3&gt;

&lt;p&gt;What it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;installs skills into ~/.claude/skills/&lt;/li&gt;
&lt;li&gt;installs CLI wrappers into ~/.local/bin/&lt;/li&gt;
&lt;li&gt;optionally installs a daemon (launchd) to auto-setup new sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--auto&lt;/code&gt; — install/start daemon&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--setup-existing&lt;/code&gt; — retrofit existing sessions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--full&lt;/code&gt; — do both&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;session-finder.sh&lt;/code&gt; (cowork-session) — finding active sessions
&lt;/h3&gt;

&lt;p&gt;It scans:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/Library/Application Support/Claude/local-agent-mode-sessions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and can list sessions or print the latest one (based on mtime / recency). This is used by basically every other script.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;bridge-init.sh&lt;/code&gt; (cowork-bridge-init) — wire up one session
&lt;/h3&gt;

&lt;p&gt;This is the actual “plumbing” script. It:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;creates .bridge/requests|responses|streams|logs&lt;/li&gt;
&lt;li&gt;writes .bridge/status.json&lt;/li&gt;
&lt;li&gt;finds the session’s account/workspace IDs&lt;/li&gt;
&lt;li&gt;injects the VM-side skill into Claude’s skills-plugin registry path&lt;/li&gt;
&lt;li&gt;updates manifest.json to register the skill&lt;/li&gt;
&lt;li&gt;injects an env var toggle into .claude/settings.json:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"BRIDGE_ENABLED"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That env var becomes a “capability bit” Cowork can check.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;setup-all-sessions.sh&lt;/code&gt; — retrofit everything
&lt;/h3&gt;

&lt;p&gt;This loops over existing sessions and runs the init steps on any that aren’t already configured.&lt;/p&gt;

&lt;p&gt;Useful flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--force&lt;/code&gt; — reconfigure everything&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--dry-run&lt;/code&gt; — show what would change&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;auto-setup-daemon.sh&lt;/code&gt; (cowork-bridge-daemon) — set-and-forget
&lt;/h3&gt;

&lt;p&gt;This is the “always on” piece.  It runs continuously and detects new Cowork sessions appearing. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;polls every 2 seconds by default&lt;/li&gt;
&lt;li&gt;uses fswatch if installed (faster)&lt;/li&gt;
&lt;li&gt;tracks known sessions in ~/.claude/.bridge-known-sessions&lt;/li&gt;
&lt;li&gt;initializes any new session automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the difference between “I built a bridge” and “my environment is always bridged.”&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;bridge-uninstall.sh&lt;/code&gt; — clean removal
&lt;/h3&gt;

&lt;p&gt;It supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uninstall one session&lt;/li&gt;
&lt;li&gt;uninstall all sessions&lt;/li&gt;
&lt;li&gt;remove global installs&lt;/li&gt;
&lt;li&gt;full cleanup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…and importantly it can run in &lt;code&gt;--dry-run&lt;/code&gt; mode so you can see what it would remove.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;inject-session.sh&lt;/code&gt; — power tools for session config
&lt;/h2&gt;

&lt;p&gt;This script is basically: “treat session config as editable infrastructure.”&lt;/p&gt;

&lt;p&gt;It supports commands like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;show — print session config&lt;/li&gt;
&lt;li&gt;model opus|sonnet|haiku — switch models&lt;/li&gt;
&lt;li&gt;prompt  — inject prompt&lt;/li&gt;
&lt;li&gt;approve-path  — pre-approve file access path&lt;/li&gt;
&lt;li&gt;mount  — pre-mount a folder&lt;/li&gt;
&lt;li&gt;enable-tool  / disable-tool  — toggle MCP tools&lt;/li&gt;
&lt;li&gt;list-tools&lt;/li&gt;
&lt;li&gt;backup / restore&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the moment you stop thinking of Cowork as “an app” and start thinking of it as “a runtime with configuration.”&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 6 — Security: you’re the sandbox now
&lt;/h2&gt;

&lt;p&gt;A bridge like this gives Cowork real power.  So the host watcher includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;allowed-type allowlist&lt;/li&gt;
&lt;li&gt;blocked command substrings for obvious disasters&lt;/li&gt;
&lt;li&gt;timeouts&lt;/li&gt;
&lt;li&gt;logging for audit/debug&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn’t “secure” in the formal sense. It’s “controlled by you.”&lt;br&gt;
Treat it like SSH keys: useful, powerful, and worth respecting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing: Cowork becomes a UI, not a cage
&lt;/h2&gt;

&lt;p&gt;This project started with “why can’t Cowork just curl this endpoint” and ended with a pretty clean architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cowork = orchestration + context + UX&lt;/li&gt;
&lt;li&gt;Bridge = transport&lt;/li&gt;
&lt;li&gt;Host watcher = executor&lt;/li&gt;
&lt;li&gt;Host Claude CLI = unrestricted agent brain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have this, you stop fighting the sandbox and start routing around it.&lt;/p&gt;

&lt;p&gt;And once you add prompt rewrites + session automation, it stops being a hack and starts being a workflow.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>automation</category>
      <category>claude</category>
    </item>
  </channel>
</rss>
