<?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: Bizbox</title>
    <description>The latest articles on Forem by Bizbox (@citro).</description>
    <link>https://forem.com/citro</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%2F3911387%2F685160a2-5e56-4b44-a4f9-a7ea4cb9f9cc.png</url>
      <title>Forem: Bizbox</title>
      <link>https://forem.com/citro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/citro"/>
    <language>en</language>
    <item>
      <title>Deep Dive: The awaiting_human Status — Rethinking Agent-Human Handoff in Bizbox</title>
      <dc:creator>Bizbox</dc:creator>
      <pubDate>Tue, 12 May 2026 05:08:49 +0000</pubDate>
      <link>https://forem.com/citro/deep-dive-the-awaitinghuman-status-rethinking-agent-human-handoff-in-bizbox-300l</link>
      <guid>https://forem.com/citro/deep-dive-the-awaitinghuman-status-rethinking-agent-human-handoff-in-bizbox-300l</guid>
      <description>&lt;h1&gt;
  
  
  Deep Dive: The &lt;code&gt;awaiting_human&lt;/code&gt; Status — Rethinking Agent-Human Handoff in Bizbox
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;May 2026&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: When "Blocked" Means Two Different Things
&lt;/h2&gt;

&lt;p&gt;For the first few months of Bizbox, we used a single &lt;code&gt;blocked&lt;/code&gt; status to mean "this issue can't move forward right now." Simple enough. But as our agent routines grew more sophisticated, we hit a pattern that kept causing friction:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some blocked issues need an AI agent to unstick them. Others need a human.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When an issue is waiting on a dependency—another task to complete, an external API to respond, a CI pipeline to finish—that's work another AI agent &lt;em&gt;could&lt;/em&gt; help with. Maybe a reconciler can auto-assign the blocker, or a monitoring routine can check if the condition cleared.&lt;/p&gt;

&lt;p&gt;But when an issue is waiting on a &lt;em&gt;human decision&lt;/em&gt;—"Should we proceed with this plan?" or "Which option do you prefer?"—those are fundamentally different. An AI agent stepping in to "unstick" a decision the board is still weighing breaks the execution contract.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;blocked&lt;/code&gt; status was doing double duty, and it meant our reconciler logic had to choose: either ignore &lt;em&gt;all&lt;/em&gt; blocked work (and miss real unblocking opportunities), or risk auto-claiming issues that humans had explicitly parked for review.&lt;/p&gt;

&lt;p&gt;We chose to split the concept.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/33" rel="noopener noreferrer"&gt;PR #33: Add &lt;code&gt;awaiting_human&lt;/code&gt; issue status&lt;/a&gt;&lt;/strong&gt; landed on May 8, 2026, introducing a new status and tightening the semantics of the existing one.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Design: Two Flavors of Waiting
&lt;/h2&gt;

&lt;p&gt;Here's how we now distinguish parked work:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;blocked&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Meaning:&lt;/strong&gt; Waiting on another issue, external system, or dependency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who can unstick it:&lt;/strong&gt; Other AI agents, automated workflows, or the blocking condition clearing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconciler behavior:&lt;/strong&gt; May auto-assign or auto-wake when the blocker resolves.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;awaiting_human&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Meaning:&lt;/strong&gt; Waiting on a human or board decision, answer, or informal confirmation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who can unstick it:&lt;/strong&gt; Only the board (or the owning user-assignee).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconciler behavior:&lt;/strong&gt; Explicitly excluded—agents must not auto-claim or transition out of this status.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The third status, &lt;code&gt;in_review&lt;/code&gt;, remains unchanged—it still covers formal execution-policy signoff gates, which are a separate control.&lt;/p&gt;




&lt;h2&gt;
  
  
  Implementation: Where It Touches
&lt;/h2&gt;

&lt;p&gt;This wasn't just a database enum tweak. The &lt;code&gt;awaiting_human&lt;/code&gt; status flows through the whole system:&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto-Park Triggers
&lt;/h3&gt;

&lt;p&gt;When an agent creates an interaction of type &lt;code&gt;ask_user_questions&lt;/code&gt; or &lt;code&gt;request_confirmation&lt;/code&gt; on an &lt;code&gt;in_progress&lt;/code&gt; issue, we now &lt;strong&gt;auto-park the issue to &lt;code&gt;awaiting_human&lt;/code&gt;&lt;/strong&gt; immediately. This prevents the agent from continuing to act on the issue while a human response is pending.&lt;/p&gt;

&lt;p&gt;Interactions created by board users (not agents) don't trigger auto-park—those are considered collaborative edits, not blocking questions.&lt;/p&gt;

&lt;p&gt;Here's the relevant logic from &lt;code&gt;services/issue-thread-interactions.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Auto-park to awaiting_human when an agent asks a question or requests confirmation&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ask_user_questions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;request_confirmation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nx"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createdByAgentId&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;in_progress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;issueStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issueId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;awaiting_human&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reconciler Exclusion
&lt;/h3&gt;

&lt;p&gt;The heartbeat reconciler—which auto-assigns unowned blocking issues—now explicitly skips &lt;code&gt;awaiting_human&lt;/code&gt;. That's enforced in &lt;code&gt;services/heartbeat.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eligibleStatuses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blocked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// NOT awaiting_human&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wake-Reason Filtering
&lt;/h3&gt;

&lt;p&gt;When a cron wake or external event tries to auto-checkout an issue, we now allow &lt;code&gt;awaiting_human&lt;/code&gt; &lt;em&gt;only&lt;/em&gt; when the wake reason indicates genuine human action: &lt;code&gt;issue_commented&lt;/code&gt;, &lt;code&gt;issue_reopened_via_comment&lt;/code&gt;, &lt;code&gt;interaction_resolved&lt;/code&gt;, or &lt;code&gt;approval_approved&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Other wake reasons (like &lt;code&gt;scheduled&lt;/code&gt; or &lt;code&gt;dependency_unblocked&lt;/code&gt;) will skip &lt;code&gt;awaiting_human&lt;/code&gt; issues, because those wakes are system-driven, not human-driven.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent Mutation Guards
&lt;/h3&gt;

&lt;p&gt;Agents can &lt;em&gt;set&lt;/em&gt; an issue to &lt;code&gt;awaiting_human&lt;/code&gt; (useful when they detect a blocker they can't resolve), but they &lt;strong&gt;cannot transition out of it&lt;/strong&gt;. That's enforced via a 403 response in &lt;code&gt;routes/issues.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;existingIssue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;awaiting_human&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;awaiting_human&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;principalType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Agents may not transition issues out of awaiting_human status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Board users and the owning user-assignee can still move the issue forward.&lt;/p&gt;

&lt;h3&gt;
  
  
  UI Changes
&lt;/h3&gt;

&lt;p&gt;The status shows up in the Kanban board between &lt;code&gt;in_review&lt;/code&gt; and &lt;code&gt;blocked&lt;/code&gt;, rendered in an amber/orange palette (distinct from the red &lt;code&gt;blocked&lt;/code&gt;). The dashboard now surfaces a separate &lt;code&gt;tasks.awaitingHuman&lt;/code&gt; counter so operators can see at a glance how many issues are parked waiting on them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;The split solves three concrete problems we were hitting in production:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reconciler Safety:&lt;/strong&gt; The auto-assignment logic can now confidently act on &lt;code&gt;blocked&lt;/code&gt; work without risking stepping on human decision-making.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Clarity:&lt;/strong&gt; When an agent routine wakes up and sees a &lt;code&gt;blocked&lt;/code&gt; issue, it knows it's allowed to help. When it sees &lt;code&gt;awaiting_human&lt;/code&gt;, it knows to leave it alone.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Board Visibility:&lt;/strong&gt; Operators get a clean signal: the &lt;code&gt;awaiting_human&lt;/code&gt; counter is the queue of issues that need &lt;em&gt;their&lt;/em&gt; attention. The &lt;code&gt;blocked&lt;/code&gt; counter is work the system might auto-resolve.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Trade-Offs and Open Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Overload Risk
&lt;/h3&gt;

&lt;p&gt;We now have &lt;em&gt;three&lt;/em&gt; parked states (&lt;code&gt;blocked&lt;/code&gt;, &lt;code&gt;awaiting_human&lt;/code&gt;, &lt;code&gt;in_review&lt;/code&gt;), and the boundaries aren't always obvious. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What if an issue is both dependency-blocked &lt;em&gt;and&lt;/em&gt; waiting on a human decision?&lt;/li&gt;
&lt;li&gt;Should &lt;code&gt;awaiting_human&lt;/code&gt; support a &lt;code&gt;blockedByIssueIds&lt;/code&gt; array, or is that mixing concepts?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Right now, the answer is: &lt;strong&gt;pick the strongest constraint.&lt;/strong&gt; If a human needs to weigh in, use &lt;code&gt;awaiting_human&lt;/code&gt; even if there's also a dependency blocker. The agent can't act either way, so the human-block is the active gate.&lt;/p&gt;

&lt;p&gt;We're open to feedback on whether that heuristic holds as routine complexity grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto-Park Scope
&lt;/h3&gt;

&lt;p&gt;We currently auto-park only for &lt;code&gt;ask_user_questions&lt;/code&gt; and &lt;code&gt;request_confirmation&lt;/code&gt; interactions. Other interaction kinds—like &lt;code&gt;suggest_tasks&lt;/code&gt;—don't trigger auto-park, because those are seen as proposals the board can act on asynchronously without blocking the agent.&lt;/p&gt;

&lt;p&gt;Is that the right line? Maybe. We're watching for cases where an agent leaves a "what should I do?" interaction and then keeps working, which would suggest we need to widen the auto-park net.&lt;/p&gt;

&lt;h3&gt;
  
  
  External Consumers
&lt;/h3&gt;

&lt;p&gt;If you're building on Bizbox or consuming our issue API, note that the status enum just expanded. The canonical list lives in &lt;code&gt;packages/shared/src/constants.ts&lt;/code&gt; (&lt;code&gt;ISSUE_STATUSES&lt;/code&gt;). Hard-coded status checks in external tooling will need an update.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;awaiting_human&lt;/code&gt; status shipped in &lt;a href="https://github.com/zesthq/bizbox/releases/tag/v0.0.11" rel="noopener noreferrer"&gt;v0.0.11&lt;/a&gt; on May 8, 2026. We're already seeing cleaner reconciler behavior and fewer "why did the agent touch this?" support questions.&lt;/p&gt;

&lt;p&gt;But we're still learning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do we need a separate &lt;code&gt;awaiting_external&lt;/code&gt; for third-party API blockers that aren't agent-unblockable but also aren't human decisions?&lt;/li&gt;
&lt;li&gt;Should the UI show &lt;em&gt;why&lt;/em&gt; an issue is &lt;code&gt;awaiting_human&lt;/code&gt;—like surfacing the unresolved interaction inline?&lt;/li&gt;
&lt;li&gt;How does this interact with approval workflows when those land?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're running Bizbox in production, we'd love to hear how the new status fits (or doesn't fit) your workflows. Drop a note in &lt;a href="https://github.com/zesthq/bizbox/discussions" rel="noopener noreferrer"&gt;GitHub Discussions&lt;/a&gt; or on &lt;a href="https://bizboxai.discourse.group" rel="noopener noreferrer"&gt;Discourse&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related Work
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/33" rel="noopener noreferrer"&gt;PR #33: Add &lt;code&gt;awaiting_human&lt;/code&gt; issue status&lt;/a&gt;&lt;/strong&gt; — full implementation and test coverage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/38" rel="noopener noreferrer"&gt;PR #38: Human handoff logging and notifications&lt;/a&gt;&lt;/strong&gt; — ClickUp notification integration for &lt;code&gt;awaiting_human&lt;/code&gt; transitions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/blob/master/doc/execution-semantics.md" rel="noopener noreferrer"&gt;Execution Semantics doc&lt;/a&gt;&lt;/strong&gt; — updated status definitions&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;About Bizbox:&lt;/strong&gt; We're building an AI-native task orchestration system where humans and AI agents collaborate on structured work. This Deep Dive is part of our monthly series on architectural decisions and lessons learned. &lt;a href="https://github.com/zesthq/bizbox" rel="noopener noreferrer"&gt;Follow the project on GitHub.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>automation</category>
    </item>
    <item>
      <title>Bizbox Build Log: May 2–8, 2026</title>
      <dc:creator>Bizbox</dc:creator>
      <pubDate>Thu, 07 May 2026 02:18:58 +0000</pubDate>
      <link>https://forem.com/citro/bizbox-build-log-may-2-8-2026-hd1</link>
      <guid>https://forem.com/citro/bizbox-build-log-may-2-8-2026-hd1</guid>
      <description>&lt;p&gt;Four releases, nine PRs merged, and one clear theme this week: making Bizbox agents more capable and trustworthy in multi-turn execution contexts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shipped this week
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Company AI Builder (Phases 0–4)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/20" rel="noopener noreferrer"&gt;#20&lt;/a&gt; landed the full Company AI Builder feature — a curated set of mutation tools delivered via a proposal-approval flow. Phase 0 shipped read-only spike work (sessions, settings, OpenAI-compat interface, six read tools, UI). This update extends with Phases 1–4: proposal-store infrastructure, mutation tools behind proposals, and the approval surface for company owners.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trade-off:&lt;/strong&gt; Mutation tools are gated by human approval for now. We chose safety and trust before convenience. Future iterations will tune the guardrails based on real operator feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Artifact validation and schema hardening
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/27" rel="noopener noreferrer"&gt;#27&lt;/a&gt; introduced stricter validation for "artifact" work products — enforcing that artifact work products always have attachment-backed metadata and a &lt;code&gt;createdByRunId&lt;/code&gt;. New schema validators, runtime type guards, and tighter integration mean artifact handling is now fail-fast instead of fail-silent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Agents produce artifacts (deliverables, documents, code outputs). Loose validation meant broken artifact references could propagate through the system. This change catches those errors at the boundary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Artifact persistence and UI updates for issue-backed runs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/25" rel="noopener noreferrer"&gt;#25&lt;/a&gt; adds support for collecting output artifacts from adapter executions (especially OpenClaw Gateway adapters), introduces new types and logic for artifact management, and exposes utilities for artifact-related work products.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open challenge:&lt;/strong&gt; Artifact handling is still evolving. We're learning what metadata needs to travel with artifacts, how to version them, and what the UI should surface. Feedback welcome.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent thread chat with optimistic UI
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/21" rel="noopener noreferrer"&gt;#21&lt;/a&gt; adds a direct communication channel between operators and agents. Users can now message agents from the agent detail page, with optimistic UI updates for a snappier feel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; We chose optimistic updates over waiting for server confirmation. It makes the UI feel faster. The trade-off: rare cases where the server rejects a message won't be obvious until you refresh. We're watching for confusion signals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routine execution recovery logic
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/22" rel="noopener noreferrer"&gt;#22&lt;/a&gt; fixes how Bizbox handles &lt;code&gt;routine_execution&lt;/code&gt; issues in &lt;code&gt;blocked&lt;/code&gt; state. Previously, the recovery logic treated blocked routines as failures and tried to resume them prematurely. Now, &lt;code&gt;blocked&lt;/code&gt; is recognized as a healthy, parked wait state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this was broken:&lt;/strong&gt; Routines often block on human approval or child issue completion. The old logic didn't distinguish "blocked and waiting" from "blocked and stuck." This change codifies the difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upstream merge and OpenTelemetry metrics
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/16" rel="noopener noreferrer"&gt;#16&lt;/a&gt; merged upstream PaperClip changes from April 30, 2026 (assisted by Claude Sonnet 4.6).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/14" rel="noopener noreferrer"&gt;#14&lt;/a&gt; adds OpenTelemetry metrics, starting with &lt;code&gt;bizbox.issues.human_comments_total&lt;/code&gt; — a signal for human intervention frequency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trade-off:&lt;/strong&gt; We're starting with one metric to validate the integration pattern. More will follow once we've confirmed the collector setup works in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  agentParams refactor and regression fix
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/24" rel="noopener noreferrer"&gt;#24&lt;/a&gt; fixes a regression introduced in &lt;code&gt;v0.0.6&lt;/code&gt; where the OpenClaw gateway adapter changed the outbound agent request shape. The fix refactors &lt;code&gt;agentParams&lt;/code&gt; handling and removes an unused function that was masking the real issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Request shape changes in adapters are easy to miss when tests don't cover the boundary. We added a test to catch this pattern in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow cleanup
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/23" rel="noopener noreferrer"&gt;#23&lt;/a&gt; removes the &lt;code&gt;sync-upstream&lt;/code&gt; workflow. We're switching to manual upstream merges (with AI assistance) for now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Automated upstream sync introduced more conflicts than it saved in merge time. Manual merges with AI assistance give us control without the constant breakage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decisions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mutation tools behind proposals:&lt;/strong&gt; We're prioritizing trust and transparency over convenience. Operators see and approve changes before agents make them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Artifact validation is fail-fast:&lt;/strong&gt; Better to catch broken artifacts early than let them propagate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blocked routine state is healthy:&lt;/strong&gt; Routines can wait. Not every blocked issue is a failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual upstream merges:&lt;/strong&gt; Automation failed here. Human-in-the-loop merges with AI assistance work better for our repo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Trade-offs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Proposal flow adds friction:&lt;/strong&gt; Every mutation requires approval. This is intentional for now, but we know it slows down agents. Future work: smart approval defaults based on context and trust signals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimistic UI updates hide rare server rejections:&lt;/strong&gt; We chose speed over certainty. Watching for user confusion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One OpenTelemetry metric to start:&lt;/strong&gt; We're validating the pattern before adding dozens of metrics. Risk: we might miss important signals early.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Open challenges
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Artifact versioning and metadata:&lt;/strong&gt; What needs to travel with an artifact? How do we version it? What should the UI surface? Still figuring this out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approval UX for high-frequency mutations:&lt;/strong&gt; Approving every change works for low-frequency operations. It won't scale to high-frequency agent work. Need smarter defaults.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upstream merge strategy:&lt;/strong&gt; Manual merges with AI assistance work for now, but they don't scale. We need a better long-term approach.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Releases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/zesthq/bizbox/releases/tag/v0.0.9" rel="noopener noreferrer"&gt;v0.0.9&lt;/a&gt; — May 6, 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/zesthq/bizbox/releases/tag/v0.0.8" rel="noopener noreferrer"&gt;v0.0.8&lt;/a&gt; — May 5, 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/zesthq/bizbox/releases/tag/v0.0.7" rel="noopener noreferrer"&gt;v0.0.7&lt;/a&gt; — May 5, 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/zesthq/bizbox/releases/tag/v0.0.6" rel="noopener noreferrer"&gt;v0.0.6&lt;/a&gt; — May 5, 2026&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This Build Log is grounded in real repo activity. Every claim links to a PR, issue, release, or ADR. No internal-only context, no invented features, no marketing fluff.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Questions? Join the discussion on &lt;a href="https://github.com/zesthq/bizbox" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>bizbox</category>
      <category>buildlog</category>
      <category>buildinpublic</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
