<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Lunch Pail Labs — Writing</title>
    <link>https://lunchpaillabs.com/writing/</link>
    <atom:link href="https://lunchpaillabs.com/writing/rss.xml" rel="self" type="application/rss+xml"/>
    <description>Notes from the workbench on software, product, and agents.</description>
    <language>en</language>
    <lastBuildDate>Wed, 29 Jul 2026 00:00:00 GMT</lastBuildDate>
    <item>
      <title>How to use acceptance tests to get features working on first review</title>
      <link>https://lunchpaillabs.com/writing/how-to-use-acceptance-tests-to-get-features-working-on-first-review/</link>
      <guid isPermaLink="true">https://lunchpaillabs.com/writing/how-to-use-acceptance-tests-to-get-features-working-on-first-review/</guid>
      <description>A practical workflow for turning product intent into an acceptance test your coding agent can run before it calls a feature done.</description>
      <pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Maybe this sounds familiar: you spend a long time creating a detailed plan with a coding agent. You explain what needs to be built. The agent implements the feature, writes tests, runs a code review loop, and declares the work complete.</p>
<p>Then you try the feature, and it does not behave the way you expected.</p>
<p>This happened to me enough times that I started requiring the agent to run an acceptance test before it calls a feature done.</p>
<p>The acceptance test forces me to clarify what I expect from the product. It then turns that expectation into a real user flow the agent can run and verify before I review the pull request.</p>
<h3 id="what-is-an-acceptance-test">What is an acceptance test?</h3>
<p>An acceptance test verifies that a feature delivers the outcome it was built to provide.</p>
<p>It starts from the user’s perspective. What should the user be able to do? What should happen as a result? What evidence would prove that the feature works?</p>
<p>For a new file upload feature in a Slack agent, the acceptance test might be:</p>
<ol>
<li>Post a message in Slack that attaches the file.</li>
<li>Mention the agent.</li>
<li>Ask the agent to summarize the file.</li>
<li>Confirm that the response uses information from the file.</li>
</ol>
<p>Contrast this with a unit or integration test. Those tests might confirm that the upload handler accepts a file or that the file moves successfully through the system. Both can pass even though the user never receives a useful response.</p>
<p>The acceptance test adds the product perspective. It defines what the feature should accomplish and what a successful experience should look like for the user.</p>
<h3 id="step-1-define-the-behavior">Step 1: Define the behavior</h3>
<p>Write down how the user should interact with the feature and what visible result would prove that it works.</p>
<p>A simple version</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>Behavior: [what the user can do]</span></span>
<span class="line"><span>Success: [what the user sees when it works]</span></span></code></pre>
<p>For the file upload example:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>Behavior: A user attaches a file and asks the Slack agent to summarize it.</span></span>
<span class="line"><span>Success: The agent responds with an accurate summary based on the file contents.</span></span></code></pre>
<p>The success state should be specific enough to verify. “The agent replies” is not enough. The reply must demonstrate that the agent received, processed, and used the file.</p>
<h3 id="step-2-choose-the-runner">Step 2: Choose the runner</h3>
<p>Once the behavior is clear, determine what the agent needs access to in order to run the flow.</p>
<p>Some features can be tested in a browser. Others require an API call, Slack, email, payments, a database, file uploads, or a scheduler.</p>
<p>I use different tools depending on where the feature lives. I use an agent inbox to confirm email delivery, sequencing, and triggers. I keep a separate Slack profile for sending test requests and evaluating the responses. I use an agent-controlled browser to open pages, trigger actions, take screenshots, and verify visible results.</p>
<p>The runner should be the smallest setup that can drive the real user flow.</p>
<p>Anything that touches a real product surface also needs a safe test lane. I do not want an agent posting test messages in a customer channel, sending emails to real users, charging real cards, or leaving behind records that I have to clean up later.</p>
<p>The acceptance test should define that safe lane:</p>
<ol>
<li>Test accounts.</li>
<li>Test Slack channels.</li>
<li>Test inboxes.</li>
<li>Payment sandbox credentials or test cards.</li>
<li>Unique values in messages and records.</li>
<li>Required environment variables.</li>
<li>Cleanup instructions.</li>
</ol>
<h3 id="step-3-create-the-test-before-the-feature">Step 3: Create the test before the feature</h3>
<p>I create the acceptance test before I ask the agent to build the feature.</p>
<p>It defines the expected user flow, the environment required to run it, and the evidence that will count as success.</p>
<p>Creating it first prevents the test from becoming a description of whatever the agent happened to build. Instead, it becomes an executable definition of what the product is supposed to do.</p>
<p>For the file upload example, the test might:</p>
<ol>
<li>Open the test Slack channel.</li>
<li>Post a message containing a unique test value.</li>
<li>Attach a known file.</li>
<li>Ask Pipa to summarize it.</li>
<li>Wait for the response.</li>
<li>Confirm that the response includes facts found only in the attached file.</li>
<li>Save a link to the Slack thread as evidence.</li>
</ol>
<h3 id="step-4-run-and-verify">Step 4: Run and verify</h3>
<p>Once the feature is built, the agent runs the acceptance test and keeps iterating until it passes.</p>
<p>I use the <a href="https://github.com/EveryInc/compound-engineering-plugin/tree/main/skills/lfg">LFG loop by Compound Engineering</a> for the broader implementation, review, and testing process. The acceptance test gives that loop a concrete product outcome to work toward.</p>
<p>The test should drive the real user flow and collect evidence that the flow worked.</p>
<p>For a Slack feature, that means posting the message, uploading the file, mentioning Pipa, waiting for the reply, and verifying that the response uses the file contents.</p>
<h3 id="what-an-acceptance-test-does-not-prove">What an acceptance test does not prove</h3>
<p>A passing acceptance test does not mean the feature is correct in every possible situation.</p>
<p>It does not prove that invalid inputs are handled well, permissions are enforced, failures recover cleanly, retries are safe, or the feature performs well under load.</p>
<p>Those concerns still need unit tests, integration tests, negative-path tests, security checks, and human judgment.</p>
<p>The acceptance test prevents the agent from declaring success when the underlying components work but the user-facing outcome does not.</p>
<h3 id="conclusion">Conclusion</h3>
<p>Coding agents can write tests, inspect logs, edit files, and try again. What they cannot reliably infer is the exact product outcome you had in your head.</p>
<p>An acceptance test turns that outcome into an executable standard. It gives the agent a concrete definition of done and gives you evidence that the feature works before you begin reviewing it.</p>
<p>If you are building with coding agents, define the acceptance test before the implementation gets too far. Start with one important feature, one real user flow, and one observable success state.</p>
<p>If you are building with agents and want a set of operational skills to get more out of the ones you already use, so you can stay focused on the work itself, you can find them at <a href="https://www.usepipa.com">usepipa.com</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>How I built an autonomous OpenCode agent in Slack</title>
      <link>https://lunchpaillabs.com/writing/how-i-built-an-autonomous-opencode-agent-in-slack/</link>
      <guid isPermaLink="true">https://lunchpaillabs.com/writing/how-i-built-an-autonomous-opencode-agent-in-slack/</guid>
      <description>How I built Pipa, an autonomous OpenCode agent in Slack, plus the open-source setup for running OpenCode from Slack on your own computer.</description>
      <pubDate>Tue, 16 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://www.usepipa.com/">Pipa</a>, my operations agent running on OpenCode and living in Slack, came from a boring problem.</p>
<p>The more I trusted coding agents with non-coding work, the more annoying it became that they still needed my laptop, my terminal, and my attention.</p>
<p>I was handing local work to OpenCode: plans, writing, research, reviews, repo cleanup, content workflows, and studio operations. Some of that work became cron jobs and recurring agent loops.</p>
<p>So Pipa moved into Slack.</p>
<p>Slack gives me channels for topics, threads for tasks, and a shared place to see what happened. Pipa can work autonomously, but I can still talk to her like a teammate.</p>
<p>Other teams are making the same move. <a href="https://aaif.io/blog/how-duolingo-built-an-ai-slackbot-with-180-mcp-tools/">Duolingo built an AI Slackbot with 180+ MCP tools</a> and got to 250 weekly active users. <a href="https://www.youtube.com/watch?v=5sb9iA2v78g">Shopify shared River</a>, its Slack-native agent that coauthored one in eight merged pull requests. <a href="https://www.mintlify.com/blog/knowledge-management-agent-era">Mintlify wrote</a> that its docs agent runs on OpenCode and Daytona in sandboxes.</p>
<p>If you want to build your own version, you can probably point your agent at this article and have it spin one up.</p>
<blockquote>
<p><strong>Update, August 29, 2026:</strong> This article documents the hosted architecture behind Pipa when I wrote it. Pipa Local now gives you a direct way to connect OpenCode on your computer to Slack. The architecture below still matters if you want to build a hosted agent that can run without your laptop.</p>
</blockquote>
<h3 id="install-pipa">Install Pipa</h3>
<p>If you already use OpenCode, install Pipa Local from your terminal:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="sh"><code><span class="line"><span style="color:#B392F0">npm</span><span style="color:#9ECBFF"> install</span><span style="color:#79B8FF"> --global</span><span style="color:#9ECBFF"> @usepipa/pipa</span></span>
<span class="line"><span style="color:#B392F0">pipa</span><span style="color:#9ECBFF"> init</span></span>
<span class="line"><span style="color:#B392F0">pipa</span><span style="color:#9ECBFF"> start</span></span></code></pre>
<p>During setup, you choose the Slack users and channels that can use Pipa. Pipa uses the folder where you run <code>pipa init</code> as OpenCode’s working context, and it inherits the configuration and permissions from your OpenCode setup.</p>
<p>The <a href="https://www.usepipa.com/opencode-slack">OpenCode Slack install page</a> has the shortest setup path. The <a href="https://www.usepipa.com/blog/how-to-run-opencode-from-slack">full tutorial</a> walks through creating the Slack app and testing your first request.</p>
<h3 id="how-it-works">How it works</h3>
<p>The architecture behind Pipa looks like this:</p>
<p><img src="https://res.cloudinary.com/dpfmaccxx/image/upload/v1781623309/ChatGPT_Image_Jun_16_2026_11_10_12_AM_vrh0qs.png" alt="Pipa architecture diagram"></p>
<p>Each tool has a job.</p>
<ul>
<li>
<p><a href="https://slack.com/">Slack</a> is where most work starts and answers land. It gives Pipa the message, requester, workspace, thread, and delivery target.</p>
</li>
<li>
<p>The gateway is the web service that receives requests. I host it on <a href="https://fly.io/">Fly</a>. It accepts Slack events, automation API calls, trigger requests, Composio webhooks, Inngest calls, and runtime calls.</p>
</li>
<li>
<p><a href="https://www.inngest.com/">Inngest</a> wakes work up. It handles scheduling, retries, cancellation, concurrency, and execution handoff.</p>
</li>
<li>
<p><a href="https://e2b.dev/">E2B</a> is the sandbox. It gives the agent its own computer to do work.</p>
</li>
<li>
<p><a href="https://opencode.ai/">OpenCode</a> is the agent harness. It is the brain that edits files, runs commands, calls tools, works in repos, and returns structured output.</p>
</li>
<li>
<p><a href="https://composio.dev/">Composio</a> handles external triggers and tool integrations. It can wake the gateway when something happens in another app, and it makes it easy to add tool connections in Slack.</p>
</li>
</ul>
<p>If you do not need the autonomy pieces, Slack, a sandbox, and an agent harness can get you pretty far.</p>
<h3 id="creating-autonomy">Creating “autonomy”</h3>
<p>You can stop at a setup where a Slack message starts OpenCode in a sandbox and get leverage. If you already live in Slack, that reduces friction for you and your team. Threads become workspaces. You can keep several tasks moving at once without living inside a terminal or another agent UI.</p>
<p>With a little more shaping, the agent can start doing more on its own.</p>
<p>The pieces I add after the base sandbox loop are:</p>
<ul>
<li>
<p>Character and instruction files. OpenClaw popularized files like <code>soul.md</code>, <code>heartbeat.md</code>, and <code>character.md</code>. You can put the same kind of files into the OpenCode config. They shape behavior, set standards, and give the agent more personality.</p>
</li>
<li>
<p>Automations, workflows, and triggers. This is where I get the most benefit. Inngest wakes the agent and sandbox at a set time. Sometimes the prompt is specific: run this skill on this thing every morning. Sometimes it is more like a heartbeat: look at the current state, use judgment, and decide what needs attention. Not every run starts from time. Many SaaS tools send events. If you want the agent to wake up and execute a skill when something happens, create a trigger.</p>
</li>
<li>
<p>Tool access. I use Composio because it makes broad tool access easy. If I need to give the agent something, I click a link. If the agent is blocked, it can post in Slack, say what it needs, and I can connect it. A lot happens when the agent has access to the same everyday tools I use.</p>
</li>
<li>
<p>Skills. Agent skills teach the agent how to write things and do things. This matters more with automations, because many of my scheduled prompts look like “run this skill on this target.” The skill holds the logic. The public Pipa skills live in the <a href="https://github.com/lunchpaillola/pipa-skills">Pipa skills repo</a>.</p>
</li>
<li>
<p>Memory. I use <a href="https://supermemory.ai/">Supermemory</a> for this. Before, Pipa loaded context files and knew to update them. A memory tool adds teammate-like recall: goals, preferences, latest business state, and small details that should carry across runs. Good memory tools also know how to supersede and delete memories, which matters once the agent has more autonomy.</p>
</li>
</ul>
<p>My favorite pattern right now uses Linear. I keep a task list there, then Pipa can wake up, pick work, do it, ship it, and leave me something to review.</p>
<h3 id="why-opencode">Why OpenCode</h3>
<p>You could use the Claude SDK, the OpenAI SDK, LangChain, OpenClaw, Hermes, Codex, or another agent system and still use the pattern in this article.</p>
<p>I like OpenCode for a few reasons.</p>
<p><strong>1. It is easy to reason about.</strong></p>
<p>I have run experiments with OpenClaw and Hermes, and they are fun. They are also built around stronger autonomy patterns. But I have had more trouble making them execute as deterministically as a coding agent. Call it a skill issue, but OpenCode is easier for me to understand when it works and when it breaks.</p>
<p><strong>2. It works for local synchronous work and “autonomous” Slack work.</strong></p>
<p>My work now falls into two buckets: tasks I go deep on locally, and tasks that can run in Slack with less supervision. OpenCode gives me one harness for both. I am not learning the edges of two different systems.</p>
<p><strong>3. It is open source and swappable.</strong></p>
<p>I can change the model without rebuilding the runtime around another provider. I can swap models, plugins, memory tools, and sandboxes without tying the whole system to one agent ecosystem.</p>
<h3 id="build-your-own-opencode-slack-agent">Build your own OpenCode Slack agent</h3>
<iframe src="https://www.youtube-nocookie.com/embed/rlTMdkPWPcA?rel=0" title="How to turn OpenCode into a Slack agent with Pipa" loading="lazy" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen style="display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: 1rem;"></iframe>
<p>The architecture in this article is the hosted path: Slack for the interface, a gateway for requests, Inngest for workflows, E2B for sandboxes, and OpenCode for agent work.</p>
<p>If you want to run OpenCode from Slack without assembling that stack, <a href="https://github.com/lunchpaillola/pipa">Pipa Local is open source</a>. If you want Lunch Pail Labs to configure, host, and keep the broader setup working for your company, read about <a href="https://www.usepipa.com/managed">Pipa Managed</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>A skill to turn agent work into a two-minute audio brief</title>
      <link>https://lunchpaillabs.com/writing/install-audio-briefs-for-any-agent/</link>
      <guid isPermaLink="true">https://lunchpaillabs.com/writing/install-audio-briefs-for-any-agent/</guid>
      <description>Install pipa-audio-brief, a free Pipa skill that turns PRs, plans, sessions, and docs into short listening links.</description>
      <pubDate>Tue, 02 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>One thing I keep pushing myself toward is running less of my work from my laptop.</p>
<p>Some of that is practical. Trying to work away from my laptop is a good constraint on the business. Every bit of friction shows me something that still needs to be operationalized or agentified. It exposes the parts of the business that still depend too much on me being at a computer.</p>
<p>Some of it is aspirational. I like being able to keep work moving while I am going for a walk, eating ice cream, or generally away from my desk. (P.S. I made <a href="https://www.youtube.com/shorts/SLY7IeLumL0">a short on how I set up OpenCode</a> so I could do more of that.)</p>
<p>The version of work I keep wanting is one that can move with me. I can still jump into deep sessions when I need to, but I can also live outside of work and have the business keep moving around me: long walks where I can brainstorm, quick check-ins between errands, meaningful progress that does not require me to stare at a screen.</p>
<p>One piece that keeps getting in the way is review.</p>
<p>Agents generate a lot of things for me to read: plans, PRs, specs, summaries, and so on and so on. The pile is not exactly friendly when I am on the go.</p>
<p>That is what <em><a href="https://github.com/lunchpaillola/pipa-skills/tree/main/skills/pipa-audio-brief">pipa-audio-brief</a></em> is for.</p>
<h3 id="the-audio-brief-skill">The audio brief skill</h3>
<p>Think of it like the summary you want from a sharp coworker before you decide where to dig in. It orients you. It tells you what happened, what changed, and where your attention is needed. You can ask for a brief on anything your agent can access: an agent session, PR, plan, spec, doc, URL, repo changes, metrics, or pasted markdown. The skill turns that into a short audio brief and publishes it as a <a href="https://here.now/">here.now</a> link, so you can listen yourself or share it with someone else.</p>
<p><img src="https://res.cloudinary.com/dpfmaccxx/image/upload/v1780414760/CleanShot_2026-06-02_at_11.35.33_2x_qbrzb6.png" alt="A here.now listening page generated by the Pipa audio brief skill."></p>
<p><a href="https://www.usepipa.com/">Pipa</a>, our studio operations agent, uses the skill when I need to:</p>
<ul>
<li>check what happened across my PRs</li>
<li>check the shape of a plan before reading the full doc</li>
<li>get the gist of a PR before opening the diff</li>
<li>listen while walking, commuting, between calls, or generally doing other things</li>
</ul>
<p>It’s free and open source. You can use it with any agent including Claude, Codex, OpenCode, OpenClaw, Hermes, or whatever else you use. If the agent can install skills, it can create a brief.</p>
<p>Just run:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">npx</span><span style="color:#9ECBFF"> skills</span><span style="color:#9ECBFF"> add</span><span style="color:#9ECBFF"> lunchpaillola/pipa-skills</span><span style="color:#79B8FF"> --skill</span><span style="color:#9ECBFF"> pipa-audio-brief</span></span></code></pre>
<p>After that, your agent can turn whatever you hand it into a listening link.</p>
<p>Every brief follows the same rough path:</p>
<ol>
<li>Context and overview</li>
<li>The story</li>
<li>Attention areas</li>
<li>Takeaway</li>
</ol>
<h3 id="what-is-behind-the-skill">What is behind the skill</h3>
<p>Under the hood, the skill gathers the context you point it at. Then it writes a 300 to 350 word spoken brief, generates audio with <a href="https://github.com/hexgrad/kokoro">Kokoro</a>, builds a single page listening UI, publishes it with here.now, and hands back the listening URL.</p>
<p>The architecture notes:</p>
<ul>
<li>
<p>No external text to speech API. It runs <a href="https://github.com/hexgrad/kokoro">Kokoro</a> locally, with extra handling for containers and lower memory sandboxes. It needs at least 1 GB of memory. That means I can generate as many briefs as I want without thinking about API costs.</p>
</li>
<li>
<p>The brief opens as a here.now listening page. Authenticated here.now links can persist. Unauthenticated ones expire after 24 hours.</p>
</li>
<li>
<p>The default brief stays around two minutes, even if the source is huge.</p>
</li>
</ul>
<h3 id="pipa-skills-are-free-to-install">Pipa skills are free to install</h3>
<p><em><a href="https://github.com/lunchpaillola/pipa-skills/tree/main/skills/pipa-audio-brief">Pipa audio brief</a></em> is part of our <em><a href="https://github.com/lunchpaillola/pipa-skills">Pipa skills</a></em> repository, the set of skills behind our studio operations agent <a href="https://www.usepipa.com/">Pipa</a>.</p>
<p>You can use the skill on its own. Install it and give it to your agent.</p>
<p><a href="https://www.usepipa.com/">Pipa</a> is our managed agent for studio operations. This audio brief skill is one thing she can do, alongside the other skills, automations, triggers, and workflows we use to run our work.</p>
<p>If you want to wire and tune that yourself, start with the <em><a href="https://github.com/lunchpaillola/pipa-skills">Pipa skills</a></em>. If you do not, <a href="https://www.usepipa.com/">hire Pipa</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Turning the Lunch Pail Labs website into a workbench</title>
      <link>https://lunchpaillabs.com/writing/turning-lunch-pail-labs-website-into-a-workbench/</link>
      <guid isPermaLink="true">https://lunchpaillabs.com/writing/turning-lunch-pail-labs-website-into-a-workbench/</guid>
      <description>A weekend redesign of the Lunch Pail Labs website to include tools, music, books, and a CRT.</description>
      <pubDate>Tue, 26 May 2026 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>The old Lunch Pail Labs website was doing the minimum acceptable job.</p>
<p>That sounds harsher than I mean it. I have never treated <em>lunchpaillabs.com</em> as an important surface in the business. It is not directly a revenue driver. People usually meet Lunch Pail through one of its arms: a YouTube video, an article, a marketplace integration, a tool, or a project already in motion.</p>
<p>Lunch Pail Labs is the container for all of those activities. Because of that, I have usually kept the site simple. It needed to explain roughly what Lunch Pail was, not carry the whole business.</p>
<p>Over the weekend, I gave it more attention than I had in months.</p>
<p>Partly because building with AI has made these experiments feel trivial enough to attempt. But mostly because I have been having too much fun pushing Codex and OpenCode to build things with more taste. I wrote more about that in <a href="https://lunchpaillabs.com/writing/how-to-give-agents-design-taste/">how to give agents design taste</a>.</p>
<p>So the weekend project became a small experiment: could I make Lunch Pail Labs express more of the world it lives in?</p>
<p>Here’s how that went.</p>
<h2 id="software-for-the-workbench">Software for the workbench</h2>
<p>Lunch Pail Labs has taken a few shapes.</p>
<p>Last year, the site was saying something like, <em>Focus on your business, we’ll handle integrations.</em> That was true enough for the services and integrations season of the studio, but it started to feel too narrow. It made Lunch Pail sound like an implementation shop, when the work was drifting toward something else.</p>
<p>The studio was becoming more of a portfolio of tools.</p>
<p>That is where <em>software for the workbench</em> came from.</p>
<p>The phrase felt closer to the instinct behind Lunch Pail. I like making things that make my own work easier. I like software that feels like something you reach for while you are already in the middle of making.</p>
<p>A couple months ago, I shifted the tagline. That became the first real iteration of the site in this direction. To drive the metaphor home in a simple way, we added drafting paper.</p>
<p>That was step one.</p>
<h2 id="from-drafting-paper-to-an-actual-bench">From drafting paper to an actual bench</h2>
<p>The old site was already reaching for the workbench idea, just in a flatter way. It used a grid that felt a little like drafting paper. I liked parts of it. It suggested architecture, making, and planning.</p>
<p><img src="https://res.cloudinary.com/dpfmaccxx/image/upload/v1779815703/Screenshot_2026-05-23_at_4.13.41_AM_qohaq3.png" alt="The previous Lunch Pail Labs website with a drafting paper-inspired grid."></p>
<p>But the metaphor stayed on the surface.</p>
<p>This weekend, I wanted to push it one step further. What if the homepage felt less like a page about the studio and more like entering the bench itself?</p>
<p>So now the site is a workbench with items I actually reach for in my life and in the studio.</p>
<ul>
<li>A plant, because I like plants.</li>
<li>A radio, because I have been getting more into music and experimenting with live coding for beats (hellooo <a href="https://strudel.cc/">strudel</a>).</li>
<li>A reading list, because there are a few works that feel fundamental to how I think about running Lunch Pail Labs and the business.</li>
<li>A lunch pail, because I had to do it. It gives me a place to explain why we are called Lunch Pail and what that name means.</li>
<li>A CRT, partly as an homage to the internet and software, because we are still a software studio.</li>
</ul>
<p>There are other elements too: scraps, objects, handles you can click around, and small pieces of the studio’s world sitting on the bench.</p>
<p><img src="https://res.cloudinary.com/dpfmaccxx/image/upload/v1779817029/CleanShot_2026-05-26_at_13.29.10_2x_rlm1cf.png" alt="The redesigned Lunch Pail Labs homepage as an interactive workbench scene."></p>
<h2 id="ai-made-the-nonconventional-version-worth-attempting">AI made the nonconventional version worth attempting</h2>
<p>A more interactive, layered website was not impossible before. It was just easier to talk myself out of it.</p>
<p>Before AI, that kind of expression still had a cost. Cutting up images, composing the scene, wiring the interactions, and polishing mobile behavior would have been enough friction to make the practical version win.</p>
<p>Especially for the Lunch Pail Labs website, where I can trade a little legibility for more fun. This is not the main funnel. It is the home you find when you trace a project, tool, article, or integration back to the studio behind it.</p>
<p>That gives the site room to be more expressive. It can carry more of the taste of its maker because it does not have to carry the whole commercial burden.</p>
<p>AI makes basic competence cheaper, which means I can push a little harder and take a few more risks. That has been the fun part of building lately. The cost of trying the stranger version is lower, so the stranger version can survive long enough to be judged.</p>
<h2 id="conclusion">Conclusion</h2>
<p>That is the redesign.</p>
<p>The cool thing about the workbench is that it does not have to stay fixed. Each object is its own scene. Over time, I can swap images, add new tools, change what is sitting on the bench, and let the site evolve as the studio’s taste and focus evolve.</p>
<p>It is a home the studio can keep growing into.</p>]]></content:encoded>
    </item>
    <item>
      <title>How to add Honeycomb traces to your AI Slack bot</title>
      <link>https://lunchpaillabs.com/writing/how-to-add-honeycomb-traces-to-your-ai-slack-bot/</link>
      <guid isPermaLink="true">https://lunchpaillabs.com/writing/how-to-add-honeycomb-traces-to-your-ai-slack-bot/</guid>
      <description>How I wired Honeycomb traces into Pipa so a Slack message, sandbox run, OpenCode session, agent timeline, and Slack reply show up together.</description>
      <pubDate>Wed, 20 May 2026 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://www.usepipa.com/">Pipa</a> is our agent for studio operations at <a href="https://lunchpaillabs.com/">Lunch Pail Labs</a>. She lives in Slack, is powered by <a href="https://www.e2b.dev/">E2B</a> sandboxes, and uses <a href="http://opencode.ai/">OpenCode</a> for the harness.</p>
<p>When it works, it’s awesome. You ask for help. Pipa goes off, runs the tools, does the work, and comes back with the answer.</p>
<p>When it goes wrong, it’s a complete black box. In the terminal, I can see the mess: tool calls, permission prompts, stalls, and weird little “I can’t do that” moments. In Slack, most of that disappears behind a typing indicator and one final message.</p>
<p>If you’re building an AI agent that lives in Slack or runs in the background, this pain may feel familiar. You need traces. This is the setup I used to send mine to <a href="https://www.honeycomb.io/">Honeycomb</a>.</p>
<h3 id="start-with-the-trace-shape">Start with the trace shape</h3>
<p>A trace shows one request moving through your system. For a Slack agent, that usually means one Slack message, one agent run, and one Slack reply.</p>
<p>The shape depends on your architecture. In Pipa, a chat gateway pings an E2B sandbox, loads the right skills and templates, and runs OpenCode.</p>
<p>For <a href="https://www.usepipa.com/">Pipa</a>, I put the telemetry in the chat gateway because that layer sees the whole run: the Slack prompt, the sandbox lifecycle, the OpenCode event stream, stdout and stderr, retries, run status, and Slack delivery status.</p>
<p>The gateway creates one trace per run. That trace is made of spans. A span is one timed step inside the run, like preparing the sandbox, starting OpenCode, watching a tool call, or sending the final Slack reply.</p>
<p>For my bot, the trace includes spans like:</p>
<ul>
<li><code>pipa.run.execute</code></li>
<li><code>pipa.e2b.sandbox.prepare</code></li>
<li><code>pipa.opencode.command</code></li>
<li><code>invoke_agent pipa.standard_opencode</code></li>
</ul>
<p>The first few spans explain the backend path. The <code>invoke_agent</code> span explains the agent session. Inside that span, Pipa attaches events for the user message, assistant responses, tool calls, retries, and run summary.</p>
<p>Now the boring infrastructure stuff and the agent’s actual behavior live in the same trace.</p>
<h3 id="add-the-traces">Add the traces</h3>
<h4 id="1-send-opentelemetry-traces-to-honeycomb">1. Send OpenTelemetry traces to Honeycomb</h4>
<p>OpenTelemetry creates and sends the trace data. Honeycomb is where I inspect it. In Pipa, the gateway sends traces to Honeycomb when <code>HONEYCOMB_API_KEY</code> is present.</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="text"><code><span class="line"><span>Slack event -> gateway run -> sandbox prepare -> OpenCode command -> Slack reply</span></span></code></pre>
<h4 id="2-create-one-top-level-span-for-the-agent-run">2. Create one top-level span for the agent run</h4>
<p>For Pipa, the top-level run span is <code>pipa.run.execute</code>. This is the span I search for when someone says, “the bot got stuck” or “Slack never got a good answer.”</p>
<h4 id="3-add-spans-for-the-big-infrastructure-steps">3. Add spans for the big infrastructure steps</h4>
<p>These spans tell me whether the basic plumbing worked:</p>
<ul>
<li><code>pipa.e2b.sandbox.prepare</code></li>
<li><code>pipa.opencode.command</code></li>
</ul>
<p>They answer the early questions. Did the sandbox start? Did OpenCode run? How long did each step take? Did the failure happen before the agent really got going?</p>
<h4 id="4-add-an-agent-invocation-span-for-honeycomb-agent-timeline">4. Add an agent invocation span for Honeycomb Agent Timeline</h4>
<p>One thing I missed at first: traces alone do not give you an agent timeline.</p>
<p>You can emit a bunch of spans and Honeycomb will show you a normal backend trace. Useful, yes, but it still reads like infrastructure: Slack event received, sandbox started, command ran, response sent. You can see which services ran and how long they took. You still cannot see what the agent did.</p>
<p>For that, you need Honeycomb’s Agent Timeline.</p>
<p>The way I understand it, Agent Timeline works when Honeycomb can recognize an agent invocation span and read the agent’s activity as events inside that span. Instead of showing only backend work, the trace can show the session itself: the user prompt, assistant messages, tool calls, tool results, retries, and final output.</p>
<p>A normal trace might look like:</p>
<p><code>slack.event.received -> sandbox.prepare -> opencode.command -> slack.reply.sent</code></p>
<p>An agent timeline is more like:</p>
<p><code>invoke_agent -> user_message -> assistant_response -> tool_call -> tool_result -> assistant_response -> run_summary</code></p>
<p>That distinction matters. Honeycomb can show normal service spans automatically, but it will not magically know what happened inside your agent. You have to emit those events yourself.</p>
<p>As far as I understand it, “Agent Timeline” is Honeycomb’s product view for this. Other observability tools may support GenAI tracing, span events, or custom trace views. Honeycomb’s Agent Timeline is the feature I was targeting here.</p>
<p>Pipa emits a Honeycomb Agent Timeline-compatible span:</p>
<p><code>invoke_agent pipa.standard_opencode</code></p>
<p>That span gets the attributes Honeycomb needs to group and display the run:</p>
<ul>
<li><code>gen_ai.conversation.id</code></li>
<li><code>gen_ai.agent.name</code></li>
<li><code>gen_ai.operation.name</code></li>
<li><code>gen_ai.request.model</code></li>
<li><code>app.run_id</code></li>
</ul>
<p>This is what lets Honeycomb show the agent session as a timeline instead of a pile of unrelated events.</p>
<h4 id="5-attach-the-agents-activity-as-events">5. Attach the agent’s activity as events</h4>
<p>Honeycomb can show service calls, but it cannot know what your agent did unless you tell it. The gateway sends the moments I actually care about: the user message, the tool call, the agent response, and the run summary.</p>
<p>For Pipa, the gateway parses structured <code>opencode run --format json</code> output and emits events such as:</p>
<ul>
<li><code>opencode.user_message</code></li>
<li><code>opencode.tool_call</code></li>
<li><code>opencode.agent_response</code></li>
<li><code>opencode.run_summary</code></li>
<li><code>opencode.parser_skipped</code></li>
</ul>
<p>That makes the hidden middle visible: the prompt, assistant-visible text, tool names, tool status, token and cost data, retry markers, and failure summaries.</p>
<h4 id="6-verify-with-a-real-failed-run">6. Verify with a real failed run</h4>
<p>After adding traces, run the bot from Slack and inspect the trace in Honeycomb. The trace should answer these questions:</p>
<ul>
<li>Did Slack reach the gateway?</li>
<li>Was the run created?</li>
<li>Did E2B prepare a sandbox?</li>
<li>Did OpenCode start?</li>
<li>What prompt did the agent receive?</li>
<li>Which tools did it call?</li>
<li>What assistant-visible text did it produce?</li>
<li>Did it retry?</li>
<li>Did the run fail or complete?</li>
<li>Did the Slack reply send?</li>
<li>Is anything sensitive leaking?</li>
</ul>
<p>If the trace cannot answer them, add another span or event at the layer that can see the missing context.</p>
<h3 id="conclusion">Conclusion</h3>
<p>If your AI bot runs inside Slack, traces are how you see what happened between the prompt and the final reply.</p>
<p>Start with the questions you ask when the bot responds badly. Then emit spans and events around those moments. One Slack request should become one run you can actually inspect in Honeycomb.</p>]]></content:encoded>
    </item>
    <item>
      <title>How to give agents design taste</title>
      <link>https://lunchpaillabs.com/writing/how-to-give-agents-design-taste/</link>
      <guid isPermaLink="true">https://lunchpaillabs.com/writing/how-to-give-agents-design-taste/</guid>
      <description>A practical reflection on using references and critique loops to push AI-generated software pages away from the median.</description>
      <pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>I have been building waitlist pages for <a href="https://pailflow.com/">Pailflow</a> to test interest in a few specific jobs that Pailflow can run end-to-end so we can see what actually gets pull. AI makes this kind of work absurdly fast. I can ask for a page, get a structure, tweak the copy, and spin up another direction in minutes.</p>
<p>But it is no secret that AI-generated work usually has the <em>smell</em>. It sits in a sort of uncanny valley: clearly a website, but not quite something that feels made by a person. The page has the right functional pieces: hero, CTA, cards, proof. But it still feels like the average version of every software page you have ever seen.</p>
<p><img src="https://www.notion.so/image/attachment:832fc9d7-5c94-48d0-9e77-19d1d0f29266:CleanShot_2026-05-11_at_09.31.222x.png?table=block&#x26;id=35d4768c-ac2d-8033-8225-f4f82d87d6f2&#x26;cache=v2" alt="Example of generic AI website design"></p>
<p>Agents are trained on much of the public internet. So when you ask an agent for a design, you often get the median.</p>
<p>And it lacks taste.</p>
<h3 id="what-is-taste">What is taste?</h3>
<p>Taste is a fuzzy word, but I define it as knowing what direction to push in, what to reject, and what feels like you. It is the small decisions that make a page feel specific instead of generic.</p>
<p>When agents make creation cheaper, taste matters more. Everyone can get to “fine” faster. The advantage moves to the person who can look at “fine” and say: no, not that.</p>
<p>More of this. Less of that. This reference, not that one.</p>
<h3 id="how-do-you-cultivate-taste">How do you cultivate taste?</h3>
<p>I think taste starts with consumption. You look at good work on purpose. You ask what makes it work, what makes it shine, and what you would steal from it.</p>
<p>Austin Kleon’s <a href="https://www.amazon.com/s?k=steal%20like%20an%20artist&#x26;adgrpid=133"><em>Steal Like an Artist</em></a> is useful here because it gives language to something creative people already do. Nothing is fully original. Good work builds on what came before it. The point is to notice what you are drawn to, borrow the parts that resonate, and remix them into something that reflects your own point of view.</p>
<p>That is where taste starts to become a muscle. The more good inputs you study, the easier it becomes to tell the difference between what is worth stealing and what is just noise.</p>
<h3 id="tools-to-give-agents-better-taste">Tools to give agents better taste</h3>
<p>Taste is context. A sharper set of references gives it something to push toward.</p>
<p><a href="https://styles.refero.design/">Refero</a> is great for this. It is a collection of high-quality product flows, landing pages, and design references from real products. I used it to find examples that felt closer to the world I wanted Pailflow to live in.</p>
<p><img src="https://www.notion.so/image/https:%2F%2Ffile.notion.so%2Ff%2Ff%2F480f0932-72ea-496f-a70d-3632da8d6e99%2Ff57510d2-1c69-44bd-8af6-6910053a7f87%2FCleanShot_2026-05-11_at_09.33.45.gif%3Ftable=block&#x26;id=35d4768c-ac2d-8024-a362-f52acaf99d31&#x26;spaceId=480f0932-72ea-496f-a70d-3632da8d6e99&#x26;expirationTimestamp=1779789600000&#x26;signature=fPgL4xaAla0omvclYsrrZUwSdgT5lC3E189cvKxwz-k?table=block&#x26;id=35d4768c-ac2d-8024-a362-f52acaf99d31&#x26;cache=v2" alt="Refero design references"></p>
<p>Then I used <a href="https://impeccable.style/">Impeccable</a> as the critique layer. After the agent produced a draft, Impeccable helped me push on the parts that make a page feel intentional: hierarchy, spacing, copy, motion, restraint, and overall vibe. The useful thing is that it gives you levers. You can ask for quieter, bolder, more animated, more simple, etc.</p>
<p>The later versions are not perfect, but they have less generic software energy.</p>
<p>Initial design, with no Impeccable or Refero:</p>
<p><img src="https://www.notion.so/image/attachment:c3dda895-0ab1-4b27-ad59-97052a5faa4f:CleanShot_2026-05-11_at_09.37.012x.png?table=block&#x26;id=35d4768c-ac2d-80f5-9d15-eba0189ff5c2&#x26;cache=v2" alt="Initial AI-generated design"></p>
<p>Variations with Refero and Impeccable:</p>
<p><img src="https://www.notion.so/image/https:%2F%2Ffile.notion.so%2Ff%2Ff%2F480f0932-72ea-496f-a70d-3632da8d6e99%2F796fca31-e0ff-4cef-8015-7abde297aef4%2FCleanShot_2026-05-11_at_09.47.35.gif%3Ftable=block&#x26;id=35d4768c-ac2d-8001-aab3-e33374a9077e&#x26;spaceId=480f0932-72ea-496f-a70d-3632da8d6e99&#x26;expirationTimestamp=1779789600000&#x26;signature=HInD7iEhHOE8aLGXHm1djEFhNcK-5B4qapIFclzXLBU?table=block&#x26;id=35d4768c-ac2d-8001-aab3-e33374a9077e&#x26;cache=v2" alt="Design variations with references and critique"></p>
<h3 id="conclusion">Conclusion</h3>
<p>When the cost of generating a page drops to almost nothing, the hard part is knowing whether the thing on the screen should exist in that form. Does it feel generic? Does it feel like you? Does it communicate the right world? Does it have a point of view?</p>
<p>If I let the agent drive from the median, I get median work. If I give it better references, sharper constraints, and more honest critique, I can push the work toward something that feels more like me.</p>]]></content:encoded>
    </item>
    <item>
      <title>The head chef model of AI collaboration</title>
      <link>https://lunchpaillabs.com/writing/head-chef-ai-collaboration/</link>
      <guid isPermaLink="true">https://lunchpaillabs.com/writing/head-chef-ai-collaboration/</guid>
      <description>The Head Chef Model reframes how to work with AI: not as a manager, intern, or copilot, but as a hands-on creative lead guiding taste, timing, and vision.</description>
      <pubDate>Sat, 08 Nov 2025 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Working with AI is still strange territory. We reach for metaphors: manager, intern, editor, surgeon. Each gets close, but none explain the back-and-forth dance of giving inputs, interpreting outputs, and adjusting course as you work alongside a machine. We want scale, but we also want the output to reflect our judgment, our standards, and our voice. It is not just about producing more; it is about making sure what is produced still feels like us.</p>
<h3 id="the-old-metaphors">The Old Metaphors</h3>
<p><strong>Manager:</strong> Too detached. You end up supervising outputs instead of shaping them.</p>
<p><strong>Intern:</strong> Too one-way. You spend more time teaching and correcting than creating.</p>
<p><strong>Editor:</strong> Too reactive. You polish what already exists instead of driving direction.</p>
<p><strong>Surgeon:</strong> Too specialized. Great for precision work, but not for broad creative problem-solving.</p>
<h3 id="the-head-chef-frame">The Head Chef Frame</h3>
<p>The head chef is not a distant strategist. They are in the kitchen, hands-on, guiding the team, tasting, and keeping everything aligned with their creative vision. They delegate, but they also step in when something needs attention.</p>
<p>A head chef also has a certain level of competency with the craft. They understand ingredients, technique, timing, and flavor. They can jump on the line if needed. They know what good looks and feels like.</p>
<h3 id="putting-it-into-practice">Putting It Into Practice</h3>
<p>Here is how I apply the Head Chef model in my own stack, using AI agents embedded in my dev environment to handle execution while I guide direction.</p>
<ol>
<li><strong>Set up your stations.</strong> I work in two Ghostty terminals. The left side is for planning and viewing, the right for synchronous agents running through <a href="https://opencode.ai/">OpenCode</a>.</li>
<li><strong>Prep your ingredients.</strong> I pick the next task from my list and break it into clear, sequential phases using a custom <strong>/create-plan</strong> command.</li>
<li><strong>Open a shared recipe.</strong> Once the direction feels right, I open a <strong>GitHub issue</strong> so every agent can read from the same context.</li>
<li><strong>Cook in phases.</strong> I offload each phase to the execution agents with a <strong>/create-instruction</strong> command and let them work through it.</li>
<li><strong>Taste and adjust.</strong> As outputs come back, I use a <strong>/review</strong> command to inspect and refine them before committing changes.</li>
<li><strong>Serve and reset.</strong> When all phases are complete, I close the issue and pull the next most important task.</li>
</ol>
<p>This loop keeps me in the kitchen. I am orchestrating, tasting, and directing while AI handles execution without pulling me out of the work.</p>
<h3 id="conclusion">Conclusion</h3>
<p>The metaphors we use for AI are not just storytelling. They shape how we work. When we frame AI as an intern, a coworker, or a copilot, we interact with it in fundamentally different ways. These mental models influence trust, delegation, and how hands-on we stay (<a href="https://sloanreview.mit.edu/projects/achieving-individual-and-organizational-value-with-ai/#:~:text=match%20at%20L575%20percent%20of,subordinate,%20or%20a%20mere%20tool">source</a>).</p>
<p>The Head Chef model reflects what great product work really requires. You need to understand the tools, the timing, and the ingredients. You need competency with the material.</p>
<p>And for builders, when AI enters the kitchen, that competency matters even more. The more fluent you are across design, code, marketing, and storytelling, the better you can shape what AI produces.</p>]]></content:encoded>
    </item>
    <item>
      <title>Speed is a commodity</title>
      <link>https://lunchpaillabs.com/writing/speed-is-a-commodity/</link>
      <guid isPermaLink="true">https://lunchpaillabs.com/writing/speed-is-a-commodity/</guid>
      <description>AI turns speed into a commodity. The real advantage is not moving faster, but building systems that let AI sprint while you sustain quality work.</description>
      <pubDate>Sat, 11 Oct 2025 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>When Facebook shouted “move fast and break things,” it felt like a secret weapon. Being fast required rare ingredients: a talented team, deep pockets, and the capital to survive the inevitable failures. Speed was a scarce, high-value asset that only a few could wield.</p>
<p>Today AI turns speed into a commodity.</p>
<ul>
<li>An AI assistant can spin up a blog post in the time it used to take to draft an outline.</li>
<li>AI agents can post thousands of LinkedIn comments to farm engagement with a single workflow.</li>
<li>Vibe-coding tools let you clone and publish the core functionality of any app idea in the time it takes to discuss it.</li>
</ul>
<p>This is not meant to be anti-AI; I use AI heavily in every part of my business. Yet articles warning that <a href="https://time.com/7295195/ai-chatgpt-google-learning-school/">ChatGPT rots your brain</a> and headlines about <a href="https://fortune.com/2025/10/07/deloitte-ai-australia-government-report-hallucinations-technology-290000-refund/">Deloitte’s error-laden AI report</a> are clear red flags. I want to use AI thoughtfully so that it increases output without sacrificing quality.</p>
<p>And it is a tension. As the owner of a solo enterprise, I perpetually have more work than time. Sending a half-baked prompt to an AI seems like a productivity gain, yet it still forces me to sit beside the tool, edit its output, and often results in not very thoughtful outputs.</p>
<p>True leverage is not just “a little faster”. It is a non-linear system that produces more results than the effort I invest. The real payoff comes from spending the effort upfront to thoughtfully construct a workflow.</p>
<p>With the marginal cost of executing a task approaching zero, AI gives us a paradoxical gift: the space to <strong>slow down</strong> and be more intentional.</p>
<p>Across processes, this means taking the time to:</p>
<ul>
<li>Define standards</li>
<li>Identify the good inputs required for quality work</li>
<li>Articulate the step-by-step process for producing the work</li>
<li>Encode that process in a system that can run autonomously</li>
<li>Create benchmarks and frameworks to continuously evaluate quality</li>
</ul>
<p>All of that meta-work is slower at first. It can feel like it gets in the way of actually completing the task. But it makes you a better architect. The advantage lies not in how many tasks you can personally finish per hour, but in the leverage you embed in the systems that run for you. If speed was once the secret weapon, today the secret weapon is systemic speed: the ability to let AI sprint while we focus on the deeper processes and guidelines that sustain it.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
