<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Citro</title>
    <description>The latest articles on DEV Community by Citro (@joincitro).</description>
    <link>https://dev.to/joincitro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F13093%2F82b26e27-f320-4e72-9bbe-d7082d62363e.png</url>
      <title>DEV Community: Citro</title>
      <link>https://dev.to/joincitro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joincitro"/>
    <language>en</language>
    <item>
      <title>Deep Dive: Workflows as a First-Class Primitive — How Bizbox Added a Full Pipeline Platform in June 2026</title>
      <dc:creator>Bizbox</dc:creator>
      <pubDate>Fri, 19 Jun 2026 08:04:39 +0000</pubDate>
      <link>https://dev.to/joincitro/deep-dive-workflows-as-a-first-class-primitive-how-bizbox-added-a-full-pipeline-platform-in-june-2ebk</link>
      <guid>https://dev.to/joincitro/deep-dive-workflows-as-a-first-class-primitive-how-bizbox-added-a-full-pipeline-platform-in-june-2ebk</guid>
      <description>&lt;h1&gt;
  
  
  Deep Dive: Workflows as a First-Class Primitive — How Bizbox Added a Full Pipeline Platform in June 2026
&lt;/h1&gt;

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




&lt;h2&gt;
  
  
  Why Workflows Needed to Be a Primitive
&lt;/h2&gt;

&lt;p&gt;Bizbox has always had two execution models: &lt;strong&gt;issues&lt;/strong&gt; (discrete tasks, picked up by an agent in a heartbeat, one agent at a time) and &lt;strong&gt;routines&lt;/strong&gt; (recurring tasks, scheduled or webhook-triggered, also single-agent). Both models work well for bounded, interruptible work — the kind of thing an agent can start, pause, and resume across heartbeats.&lt;/p&gt;

&lt;p&gt;But a class of workflows doesn't fit that shape. Consider a data pipeline that ingests a report, runs several analysis steps in sequence, calls an external API mid-flight, waits for a human to review an intermediate output, and only then writes results to a deliverable. That's a multi-step, multi-agent-or-single-agent-but-long-running, human-in-the-loop pipeline. Forcing it through the issue model means either one enormous heartbeat (fragile, timeout-prone) or a web of child issues with manual sequencing (brittle, hard to observe).&lt;/p&gt;

&lt;p&gt;The team's answer, landed on June 3 in &lt;a href="https://github.com/zesthq/bizbox/pull/86" rel="noopener noreferrer"&gt;PR #86&lt;/a&gt;, was to introduce &lt;code&gt;Workflows&lt;/code&gt; as a new company-scoped primitive — explicitly separate from issues and routines — backed by Google's Agent Development Kit (ADK) runtime.&lt;/p&gt;

&lt;p&gt;This post walks through what was built, why the design is structured the way it is, and what the month of iteration on top of that foundation revealed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Foundation: What Shipped on Day One
&lt;/h2&gt;

&lt;p&gt;PR #86 was a substantial landing. The scope, compressed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A new &lt;code&gt;workflows&lt;/code&gt; table&lt;/strong&gt; and corresponding API routes. Workflows are first-class entities in the database, not a special issue type or a routine variant. They have their own namespace, their own run records, and their own lifecycle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google ADK-backed execution.&lt;/strong&gt; Each workflow run spawns a Python ADK process. The Bizbox server acts as the orchestrator: it provisions the ADK environment, passes the workflow's Python source and any input, and streams the resulting console output into a run record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run records with persisted deliverables.&lt;/strong&gt; A workflow run isn't just a log entry — it produces structured output. Deliverables (files, structured data, artifacts) are attached to the run record and exposed through the same deliverables API used elsewhere in Bizbox.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline graph rendering.&lt;/strong&gt; The ADK runtime produces a graph of the pipeline's phases — each workflow step is a node; execution order and branching are edges. Bizbox instruments this graph and renders it in the UI, so operators can see the full pipeline topology at a glance, not just a flat console log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;input()&lt;/code&gt; bridge.&lt;/strong&gt; PR #86 also introduced the first version of &lt;code&gt;input()&lt;/code&gt; monkey-patching: when the ADK Python process calls &lt;code&gt;input()&lt;/code&gt;, Bizbox intercepts it instead of blocking the process. This is the foundational seam that makes human-in-the-loop workflows possible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workflow detail view and navigation.&lt;/strong&gt; The UI got a workflows navigation item, a workflow list, and a workflow detail page showing pipeline graph, run history, console output, and deliverables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the full vertical stack — schema, API, runtime, and UI — in a single PR. That's worth noting: rather than landing a stub and iterating, the team shipped the complete primitive. The following three weeks were refinement and extension, not completion.&lt;/p&gt;




&lt;h2&gt;
  
  
  Instrumentation: Making &lt;code&gt;input()&lt;/code&gt; Reliable Across Environments
&lt;/h2&gt;

&lt;p&gt;ADK workflows are Python programs. Python programs that need human input call &lt;code&gt;input()&lt;/code&gt;. In a typical ADK pipeline, &lt;code&gt;input()&lt;/code&gt; blocks the process until the user types something. That model doesn't work in a server-managed runtime — you can't block a server process on stdin.&lt;/p&gt;

&lt;p&gt;PR #86 introduced the solution: monkey-patching the Python environment so that &lt;code&gt;input()&lt;/code&gt; calls are intercepted rather than blocking. The initial implementation worked but had cross-environment reliability issues — the monkey-patch didn't take effect consistently across all Python runtime configurations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/91" rel="noopener noreferrer"&gt;PR #91&lt;/a&gt;, merged two days after launch, fixed this cross-environment gap and completed the integration by wiring the intercepted &lt;code&gt;input()&lt;/code&gt; call through to the awaiting-human bridge. Instead of blocking the process, the intercepted call now routes through the &lt;a href="https://github.com/zesthq/bizbox/blob/main/community/deep-dives/2026-06.md" rel="noopener noreferrer"&gt;provider-agnostic awaiting-human bridge&lt;/a&gt; — the same durable coordination layer that issues use for human handoffs — and suspends the workflow run until the human responds through their configured channel.&lt;/p&gt;

&lt;p&gt;This is an elegant use of the bridge architecture. The workflow author writes standard Python. The &lt;code&gt;input()&lt;/code&gt; call expresses the semantic intent ("I need a human here") without requiring any Bizbox-specific SDK. Bizbox instruments the runtime, and the bridge handles the rest: notification delivery via the configured transport adapter, polling, reply ingestion, and resume. ClickUp is the current default transport, but the bridge is designed to support other providers without changes to the workflow code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/96" rel="noopener noreferrer"&gt;PR #96&lt;/a&gt; continued this work, improving the full lifecycle of the handoff for workflow runs — specifically ensuring that the workflow's run state is correctly reflected while a handoff is pending and that the run resumes cleanly when the human responds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Portability: Import and Export
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/99" rel="noopener noreferrer"&gt;PR #99&lt;/a&gt; and &lt;a href="https://github.com/zesthq/bizbox/pull/103" rel="noopener noreferrer"&gt;PR #103&lt;/a&gt; added workflow import/export.&lt;/p&gt;

&lt;p&gt;These PRs matter architecturally for a reason that isn't immediately obvious: they establish that Workflows are a portable unit of company configuration, not a runtime-only artifact.&lt;/p&gt;

&lt;p&gt;Bizbox's import/export system lets operators snapshot a company's configuration — agents, routines, skills, and now workflows — and restore it elsewhere. Before these PRs, if you exported a company package, you'd get the agent definitions and skill assignments but not the workflow definitions. A company that relied heavily on ADK pipelines couldn't be fully migrated or duplicated.&lt;/p&gt;

&lt;p&gt;With workflows included in the export/import surface, the company package is again complete. Workflow directories (the Python files that define each pipeline) are bundled alongside the metadata, and the import logic reconstructs them correctly on the receiving end.&lt;/p&gt;




&lt;h2&gt;
  
  
  Observability: Prompt Templates and Graph Analysis
&lt;/h2&gt;

&lt;p&gt;The final two weeks of June focused on making the workflow surface more useful for operators who didn't write the pipeline themselves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/111" rel="noopener noreferrer"&gt;PR #111&lt;/a&gt; added workflow-scoped prompt templates to the workflow detail page. This is a small but sharp change: rather than showing generic prompt suggestions that apply to any issue, the workflow page now surfaces suggestions that are specific to the workflow's purpose — derived from the workflow record itself. An operator running a data analysis pipeline sees suggestions relevant to that pipeline, not to the agent system in general.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/112" rel="noopener noreferrer"&gt;PR #112&lt;/a&gt; polished the run history UI. The workflow detail page lists all past runs for a workflow. Before this PR, selecting a run from history didn't correctly update the detail view — you'd click a past run and see stale data from the most recent run. The fix ensured that selecting a run from history locks the view to that run's graph, console output, and deliverables, making the history pane a genuine audit trail rather than a misleading navigation element.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/113" rel="noopener noreferrer"&gt;PR #113&lt;/a&gt;, merged on June 18, substantially expanded the pipeline graph analysis. The original renderer had limited understanding of ADK's graph model. This PR added explicit parsing of &lt;code&gt;Workflow&lt;/code&gt; and &lt;code&gt;JoinNode&lt;/code&gt; constructs along with correct DAG edge construction, so the topology renders accurately for real-world pipelines: you can see where branches split, where they converge at join steps, and how the full directed graph of phases is connected — not just a linear sequence of nodes.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Design Decision Worth Unpacking
&lt;/h2&gt;

&lt;p&gt;The most important decision in the Workflows launch is the one that isn't loudly stated: &lt;strong&gt;Workflows is not a subtype of Issues.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It would have been simpler, in some ways, to model workflows as a special issue kind — one with a multi-step execution plan, child issues for each step, and an execution policy that sequences them. Some orchestration platforms take exactly this approach.&lt;/p&gt;

&lt;p&gt;Bizbox didn't. Workflows have their own table, their own API namespace, their own run record type. Issues and workflows are siblings in the company data model, not parent and child.&lt;/p&gt;

&lt;p&gt;The reason is execution fidelity. Issues are designed to be interruptible. An agent checks out an issue, does some work, posts a comment, and exits. The next heartbeat, another agent (or the same one) picks it up. That model requires that the work state lives in comments and documents, not in process memory. It works because the work is fundamentally discrete.&lt;/p&gt;

&lt;p&gt;ADK workflows are not discrete in that sense. A pipeline has local state that must persist across phases — intermediate computations, in-flight API results, the position in the graph. The ADK runtime maintains this state in the Python process. Forcing that into the issue heartbeat model would require serializing and deserializing ADK process state on every heartbeat boundary, which is both complex and fragile.&lt;/p&gt;

&lt;p&gt;By keeping Workflows separate, Bizbox preserves the issue model's simplicity while giving the ADK runtime the long-running execution environment it actually needs. The awaiting-human bridge is where the two worlds meet: when a workflow needs human input, it routes that request through the same provider-agnostic bridge that issues use, so the operator experience is consistent even though the underlying execution model is different.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Still Open
&lt;/h2&gt;

&lt;p&gt;The Workflows platform shipped quickly, which means a few things are still rough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workflow scheduling&lt;/strong&gt; isn't built yet. You can trigger a workflow manually through the API or UI, and routines can trigger them, but there's no first-class cron support for workflows. The workaround is a routine that calls the workflow API, which works but adds indirection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-agent workflow steps&lt;/strong&gt; are ADK-native (ADK supports multi-agent graphs), but the Bizbox graph renderer currently assumes a single-agent pipeline topology. Complex multi-agent graphs may not render correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workflow versioning&lt;/strong&gt; is implicit. The workflow definition is a Python file stored in the company package. If you change it and the change breaks a running pipeline, there's no rollback mechanism in the current design.&lt;/p&gt;




&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;The June 2026 Workflows sprint is one of the cleaner examples of a new primitive done right: a full vertical slice on day one, followed by focused iteration that filled in portability, observability, and operational polish. The design choice to keep Workflows separate from Issues rather than layering on top of them reflects a clear-eyed view of what each model is actually good at.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;input()&lt;/code&gt; bridge is the detail worth remembering. It's a small thing — a monkey-patch — but it expresses the right philosophy: workflow authors write standard Python, Bizbox instruments the execution environment, and the operator experience is consistent because the bridge handles the coordination. The primitive is doing its job when you can't see it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have questions or want to discuss the Workflows architecture? Join the conversation in our &lt;a href="https://github.com/zesthq/bizbox/discussions" rel="noopener noreferrer"&gt;GitHub Discussions&lt;/a&gt; or on &lt;a href="https://community.bizbox.dev" rel="noopener noreferrer"&gt;Discourse&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>architecture</category>
      <category>automation</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Bizbox Build Log — Week of 2026-06-07</title>
      <dc:creator>Bizbox</dc:creator>
      <pubDate>Fri, 12 Jun 2026 04:25:55 +0000</pubDate>
      <link>https://dev.to/joincitro/bizbox-build-log-week-of-2026-06-07-1d20</link>
      <guid>https://dev.to/joincitro/bizbox-build-log-week-of-2026-06-07-1d20</guid>
      <description>&lt;h1&gt;
  
  
  Bizbox Build Log — Week of 2026-06-07
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;The Build Log is a weekly snapshot of what the Bizbox team shipped, decided, traded off, and is still wrestling with. It's written for developers building on Bizbox — no marketing gloss.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Activity covered: June 1–7, 2026 · Published: June 12, 2026&lt;/em&gt;&lt;/p&gt;




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

&lt;h3&gt;
  
  
  🟢 Workflows platform: human-in-the-loop is live
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Release v2026.605.0 · v2026.603.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The big story this cycle is the Workflows primitive reaching its first complete end-to-end state. Two weeks of work landed almost back-to-back:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/86" rel="noopener noreferrer"&gt;PR #86&lt;/a&gt; — Company-scoped Workflows with ADK pipeline runs&lt;/strong&gt; &lt;em&gt;(DennisDenuto)&lt;/em&gt;&lt;br&gt;
Workflows are now a first-class company primitive in Bizbox — separate from issues and routines. Each Workflow maps to a Google ADK pipeline. The runtime records individual runs, tracks live phase state as a renderable graph, gates human handoffs, and persists deliverables. Database schema, API routes, and JWT-protected runtime callbacks all shipped together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/91" rel="noopener noreferrer"&gt;PR #91&lt;/a&gt; — Workflow handoff to ClickUp&lt;/strong&gt; &lt;em&gt;(angelofallars)&lt;/em&gt;&lt;br&gt;
This is the "last mile" for interactive Workflows. When ADK Python code calls &lt;code&gt;input()&lt;/code&gt;, Bizbox now intercepts that call and routes the prompt to a human via ClickUp. The run parks itself and waits. When the human replies, the pipeline resumes. Two fixes came along for the ride: the &lt;code&gt;input()&lt;/code&gt; monkey-patch is now portable across Python environments (an edge case that was quietly breaking some pipelines), and failed workflow runs no longer submit deliverables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/93" rel="noopener noreferrer"&gt;PR #93&lt;/a&gt; — Top-level docs updated for Workflows + Google ADK&lt;/strong&gt; &lt;em&gt;(ralphbibera)&lt;/em&gt;&lt;br&gt;
README, PRODUCT, and SPEC now reflect shipped reality: Workflows surface, Google ADK adapter, and the expanded company model. ADK is in the Works With table. This is a maintenance merge but it matters — the docs were lagging behind the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/87" rel="noopener noreferrer"&gt;PR #87&lt;/a&gt; — &lt;code&gt;fix(google-adk): strip frontmatter from AGENTS.md instructions&lt;/code&gt;&lt;/strong&gt; &lt;em&gt;(ralphbibera)&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Release v2026.602.1&lt;/strong&gt;&lt;br&gt;
The Google ADK adapter was passing raw YAML frontmatter directly to &lt;code&gt;adk run&lt;/code&gt;, causing it to exit with an invalid input error. Fixed by stripping everything above the first &lt;code&gt;---&lt;/code&gt; fence before the instructions are handed to the adapter. Real breakage fixed silently — this one was happening in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/88" rel="noopener noreferrer"&gt;PR #88&lt;/a&gt; — &lt;code&gt;Enhance issue origin handling with deduplication and tasks&lt;/code&gt;&lt;/strong&gt; &lt;em&gt;(adPalafox)&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Release v2026.602.0&lt;/strong&gt;&lt;br&gt;
Added SHA-256 fingerprint deduplication for suggested-task bundles. Without this, replaying or resubmitting a suggested-task payload would create duplicate child issues. Now it's idempotent.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔧 Fix: ClickUp test link was missing the company slug
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/95" rel="noopener noreferrer"&gt;PR #95&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;(ralphbibera)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The "test connection" button on the ClickUp awaiting-human settings page was generating a link without the company slug. That meant the test notification landed nowhere useful. Fixed at the route level. Regression test added.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Not yet in a tagged release — expect this to ship in the next canary cut (blocked on the canary CI failure detailed below).&lt;/em&gt;&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Workflows are a separate primitive, not an extension of routines or issues.&lt;/strong&gt;&lt;br&gt;
This was a deliberate design choice in PR #86. Routines are recurring scheduled tasks; issues are discrete work items. Workflows are something different: multi-step ADK pipelines with phases, human gates, and deliverables. Keeping them separate means the data model stays clean and the UI can render them distinctly. The trade-off is more surface area to maintain and a steeper learning curve for users who ask "when do I use a routine vs. a workflow?" &lt;em&gt;(ADR to follow.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;input()&lt;/code&gt; interception as the handoff mechanism.&lt;/strong&gt;&lt;br&gt;
PR #91 chose to intercept Python's &lt;code&gt;input()&lt;/code&gt; rather than require ADK workflows to call a Bizbox-specific SDK function. The rationale is ergonomics: existing ADK pipeline code "just works" without modification. The cost is that &lt;code&gt;input()&lt;/code&gt; monkey-patching is fragile — different Python environments initialise the builtins module at different points, which is why a portability fix shipped in the same PR. See &lt;a href="https://github.com/zesthq/bizbox/blob/master/docs/adr/0001-awaiting-human-bridge.md" rel="noopener noreferrer"&gt;ADR 0001 — awaiting-human bridge&lt;/a&gt; for the bridge lifecycle, adapter registry, and runner/adapter split; a narrower ADR covering the &lt;code&gt;input()&lt;/code&gt; interception mechanism specifically is to follow.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Monkey-patching &lt;code&gt;input()&lt;/code&gt; across Python environments.&lt;/strong&gt;&lt;br&gt;
The fix in PR #91 addressed the known portability gap, but monkey-patching builtins is inherently brittle. If an ADK workflow uses &lt;code&gt;input()&lt;/code&gt; in a subprocess or a thread before the patch lands, the intercept won't fire and the pipeline will block silently. This is a known risk the team is holding — the alternative (a first-party SDK call) would require ADK pipeline authors to change their code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workflows ship without retry policies.&lt;/strong&gt;&lt;br&gt;
PR #86's first cut does not include retry semantics for failed pipeline phases. If a phase errors out, the run fails. Whether that's the right default (fail fast) or a gap (users expect retry) is something the team is watching in early usage. Open issue: what's the right automatic retry behaviour for a human-gated phase that times out?&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;⚠️ Canary publish CI failure on master (June 5)&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;Release&lt;/code&gt; workflow's &lt;code&gt;publish_canary&lt;/code&gt; step failed after the PR #95 merge (&lt;a href="https://github.com/zesthq/bizbox/actions/runs/26999915272" rel="noopener noreferrer"&gt;run #26999915272&lt;/a&gt;). Docker build and lockfile refresh succeeded on the same run. The root cause isn't surfaced in the job logs accessible via API. &lt;strong&gt;This is blocking the canary release of PR #95.&lt;/strong&gt; The team needs to triage this before the next cut.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PR #96 — Improve workflow ClickUp handoff lifecycle&lt;/strong&gt; &lt;em&gt;(shipped post-cutoff)&lt;/em&gt;&lt;br&gt;
When a Workflow times out or is interrupted mid-handoff, the ClickUp prompt was still showing a success reaction — making it look alive to the human on the other end. &lt;a href="https://github.com/zesthq/bizbox/pull/96" rel="noopener noreferrer"&gt;PR #96&lt;/a&gt; (cerkiner) fixes the cleanup path so termination closes the ClickUp side too. &lt;em&gt;Merged June 10 — after the June 1–7 coverage window; full coverage in next week's Build Log.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PR #90 — Reviewer routing in ClickUp approval flows&lt;/strong&gt; &lt;em&gt;(shipped post-cutoff)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://github.com/zesthq/bizbox/pull/90" rel="noopener noreferrer"&gt;PR #90&lt;/a&gt; (adPalafox) adds per-company primary and secondary reviewer IDs to the ClickUp awaiting-human approval context. This is important for teams with dedicated approvers — right now every handoff goes to a generic channel. &lt;em&gt;Merged June 9 — after the June 1–7 coverage window; full coverage in next week's Build Log.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built on &lt;a href="https://github.com/zesthq/bizbox" rel="noopener noreferrer"&gt;&lt;code&gt;zesthq/bizbox&lt;/code&gt;&lt;/a&gt; · Releases &lt;a href="https://github.com/zesthq/bizbox/releases/tag/v2026.602.0" rel="noopener noreferrer"&gt;v2026.602.0&lt;/a&gt;, &lt;a href="https://github.com/zesthq/bizbox/releases/tag/v2026.602.1" rel="noopener noreferrer"&gt;v2026.602.1&lt;/a&gt;, &lt;a href="https://github.com/zesthq/bizbox/releases/tag/v2026.603.0" rel="noopener noreferrer"&gt;v2026.603.0&lt;/a&gt; and &lt;a href="https://github.com/zesthq/bizbox/releases/tag/v2026.605.0" rel="noopener noreferrer"&gt;v2026.605.0&lt;/a&gt; · &lt;a href="https://github.com/zesthq/bizbox/pulls" rel="noopener noreferrer"&gt;All open PRs&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Release labels follow the scheme &lt;code&gt;vYYYY.MMDD.patch&lt;/code&gt; — e.g. &lt;code&gt;v2026.605.0&lt;/code&gt; = first cut on June 5, 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>devjournal</category>
      <category>showdev</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Bizbox Build Log — Week of 2026-05-31</title>
      <dc:creator>Bizbox</dc:creator>
      <pubDate>Wed, 10 Jun 2026 23:24:25 +0000</pubDate>
      <link>https://dev.to/joincitro/bizbox-build-log-week-of-2026-05-31-57cg</link>
      <guid>https://dev.to/joincitro/bizbox-build-log-week-of-2026-05-31-57cg</guid>
      <description>&lt;h1&gt;
  
  
  Bizbox Build Log — Week of 2026-05-31
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Headline:&lt;/strong&gt; Two big bets landed in the same week — Workflows arrived as a proper first-class primitive, and the ClickUp human-approval loop closed end-to-end. The pieces are all there; now we stabilise.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is your weekly look at everything that shipped, the choices we made, the trade-offs we accepted, and the things we're still wrestling with. Pull up a chair.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  Workflows are now a first-class Bizbox primitive — &lt;a href="https://github.com/zesthq/bizbox/pull/86" rel="noopener noreferrer"&gt;PR #86&lt;/a&gt; · v2026.603.0
&lt;/h3&gt;

&lt;p&gt;The biggest drop this week. @DennisDenuto landed Workflows as a company-scoped concept that sits alongside issues and routines — not shoehorned into either. What that means in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google ADK-backed execution&lt;/strong&gt; — workflow pipelines run as ADK agents, with phase state persisted as run records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human handoffs baked in&lt;/strong&gt; — pipelines can pause and wait for a human before resuming.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deliverables that survive&lt;/strong&gt; — artefacts from each run are persisted and surfaced in the UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A pipeline graph in the UI&lt;/strong&gt; — topologically ordered, showing live phase state and console output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the foundation. More on what we can build on top of it below.&lt;/p&gt;




&lt;h3&gt;
  
  
  Workflow human-handoffs now route through ClickUp — &lt;a href="https://github.com/zesthq/bizbox/pull/91" rel="noopener noreferrer"&gt;PR #91&lt;/a&gt; · v2026.605.0
&lt;/h3&gt;

&lt;p&gt;The day after Workflows landed, @angelofallars wired up the last kilometre: when ADK Python code calls &lt;code&gt;input()&lt;/code&gt; inside a pipeline, Bizbox now intercepts that call and sends a ClickUp message to collect the human reply — instead of blocking the process forever. A few things that were fixed along the way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;input()&lt;/code&gt; monkey-patching now works consistently across Python environments (was silently failing in some setups).&lt;/li&gt;
&lt;li&gt;Failed workflow runs no longer submit deliverables. You only see artefacts from runs that actually completed.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ClickUp awaiting-human bridge adapter ships as a pure plugin — &lt;a href="https://github.com/zesthq/bizbox/pull/78" rel="noopener noreferrer"&gt;PR #78&lt;/a&gt; · v2026.601.0
&lt;/h3&gt;

&lt;p&gt;This one technically crossed the line on the last day of May (23:56 UTC, 31 May), so it's in scope. @ralphbibera ported the ClickUp transport and adapter as a genuine plugin — implementing the &lt;code&gt;AwaitingHumanBridgeAdapter&lt;/code&gt; registry interface — without touching bridge core at all.&lt;/p&gt;

&lt;p&gt;What that gives you: ClickUp works through the same provider-agnostic layer as any future provider (Slack, Discord, whatever comes next). The core doesn't know ClickUp exists.&lt;/p&gt;

&lt;p&gt;Included: send/poll/reaction transport, message templates for &lt;code&gt;request_confirmation&lt;/code&gt; and &lt;code&gt;ask_user_questions&lt;/code&gt; interactions, &lt;code&gt;brain_is_thinking&lt;/code&gt; reactions while waiting, terminal &lt;code&gt;✅&lt;/code&gt; / &lt;code&gt;❌&lt;/code&gt; reactions on resolution, and full test coverage.&lt;/p&gt;




&lt;h3&gt;
  
  
  Google ADK instructions no longer ship YAML frontmatter — &lt;a href="https://github.com/zesthq/bizbox/pull/87" rel="noopener noreferrer"&gt;PR #87&lt;/a&gt; · v2026.602.1
&lt;/h3&gt;

&lt;p&gt;A quiet but important fix. &lt;code&gt;AGENTS.md&lt;/code&gt; uses YAML frontmatter for metadata and discovery. That frontmatter was leaking into the instruction payload passed to the Google ADK runtime — producing malformed inputs. @ralphbibera stripped it at the adapter layer. If you were seeing odd ADK behaviour this week, this was probably it.&lt;/p&gt;




&lt;h3&gt;
  
  
  Suggested task deduplication — &lt;a href="https://github.com/zesthq/bizbox/pull/88" rel="noopener noreferrer"&gt;PR #88&lt;/a&gt; · v2026.602.0
&lt;/h3&gt;

&lt;p&gt;@adPalafox fixed a subtle papercut: accepting the same suggested task bundle more than once used to create duplicate child issues. Now the system fingerprints each bundle and reuses existing child issues on repeat accepts. Test coverage included.&lt;/p&gt;




&lt;h3&gt;
  
  
  CI now uses runner Chrome for Playwright — &lt;a href="https://github.com/zesthq/bizbox/pull/84" rel="noopener noreferrer"&gt;PR #84&lt;/a&gt; · v2026.601.0
&lt;/h3&gt;

&lt;p&gt;CI was timing out on headless browser jobs because Playwright was downloading its own browser binary mid-run. @ralphbibera switched to the pre-installed Chrome on the runner — same coverage, less flakiness. Mirrors what upstream Paperclip did in their PR #6967.&lt;/p&gt;




&lt;h3&gt;
  
  
  Docs refreshed for Workflows and Google ADK — &lt;a href="https://github.com/zesthq/bizbox/pull/93" rel="noopener noreferrer"&gt;PR #93&lt;/a&gt; · v2026.605.0
&lt;/h3&gt;

&lt;p&gt;Top-level documentation updated to reflect the new Workflows primitive and Google ADK adapter support. If you've been pointing people at the docs for onboarding, give them a refresh.&lt;/p&gt;




&lt;h3&gt;
  
  
  June 2026 Monthly Deep Dive draft merged — &lt;a href="https://github.com/zesthq/bizbox/pull/83" rel="noopener noreferrer"&gt;PR #83&lt;/a&gt; · v2026.602.0
&lt;/h3&gt;

&lt;p&gt;@adPalafox merged the June Deep Dive draft covering the full story of how the awaiting-human bridge evolved from ClickUp polling to a provider-agnostic approval layer. It's at &lt;code&gt;community/deep-dives/2026-06.md&lt;/code&gt; in the repo and going through the review chain now.&lt;/p&gt;




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

&lt;p&gt;Five releases cut this week:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Notable&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;v2026.601.0&lt;/td&gt;
&lt;td&gt;2026-06-01&lt;/td&gt;
&lt;td&gt;Awaiting-human bridge config, retry/dedupe, Google ADK adapter, ClickUp plugin, CI Chrome fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v2026.602.0&lt;/td&gt;
&lt;td&gt;2026-06-02&lt;/td&gt;
&lt;td&gt;Suggested task deduplication, June Deep Dive docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v2026.602.1&lt;/td&gt;
&lt;td&gt;2026-06-02&lt;/td&gt;
&lt;td&gt;Fix: strip AGENTS.md frontmatter for ADK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v2026.603.0&lt;/td&gt;
&lt;td&gt;2026-06-03&lt;/td&gt;
&lt;td&gt;Workflows first-class primitive + ADK pipeline runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v2026.605.0&lt;/td&gt;
&lt;td&gt;2026-06-05&lt;/td&gt;
&lt;td&gt;Workflow ClickUp handoff, fixed input() patching, docs refresh&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;p&gt;&lt;strong&gt;Workflows as a separate primitive, not an extension of issues or routines.&lt;/strong&gt;&lt;br&gt;
The team chose to introduce &lt;code&gt;Workflow&lt;/code&gt; as its own company-scoped entity rather than layering pipeline semantics onto existing issue or routine concepts. The call: pipeline graphs, multi-phase execution, and deliverable persistence don't map cleanly onto the issue lifecycle or cron-triggered routines. A clean new primitive was worth the added surface area.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bridge core stays provider-agnostic; adapters register via the registry.&lt;/strong&gt;&lt;br&gt;
When the ClickUp awaiting-human bridge was first developed, ClickUp was hardcoded into core files. That approach was explicitly invalidated before this week: the strict rule is that bridge core must not know about any transport. ClickUp (and any future providers) plug in through &lt;code&gt;AwaitingHumanBridgeAdapter&lt;/code&gt;. The ClickUp plugin was rewritten from scratch to honour this constraint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Failed workflow runs must not produce deliverables.&lt;/strong&gt;&lt;br&gt;
Deliverables from a failed run are ambiguous and likely misleading. The decision was to suppress them entirely — a run must complete successfully to submit artefacts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monkey-patch &lt;code&gt;input()&lt;/code&gt; at the ADK layer for human handoffs.&lt;/strong&gt;&lt;br&gt;
Rather than requiring ADK pipeline authors to use a custom API for human prompts, the team intercepts the standard Python &lt;code&gt;input()&lt;/code&gt; call. This keeps pipeline code idiomatic. The risk (cross-environment patching reliability) was accepted and addressed with the fix in PR #91.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Plugin registration is explicit — it doesn't auto-discover.&lt;/strong&gt;&lt;br&gt;
The ClickUp adapter has to be registered in &lt;code&gt;server/src/index.ts&lt;/code&gt; after external adapter loading completes. This is intentional (predictable startup order, no magic) but means adding a new transport always requires a code change in that file. A future auto-discovery mechanism would remove the friction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ADK &lt;code&gt;input()&lt;/code&gt; patching is fragile by nature.&lt;/strong&gt;&lt;br&gt;
Monkey-patching works — and the cross-environment edge cases are now fixed — but it's still a low-level override that could break if ADK changes how it invokes user code. The team accepted this because the alternative (requiring explicit API calls in every pipeline) hurts adoption. Monitoring is the safeguard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workflow as a new primitive increases product surface area.&lt;/strong&gt;&lt;br&gt;
More primitives mean more concepts for users to learn. The team weighed this against the complexity of extending issues/routines and chose clarity over brevity. Whether the new primitive surface makes sense to users will surface in community questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Release CI pipeline gate is currently broken (see Open Challenges).&lt;/strong&gt;&lt;br&gt;
Releases were still published this week despite repeated Release CI failures on master. At some point, bypassing the gate becomes a risk if a bad build slips through. This is an accepted short-term state while the root cause is investigated.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;🔴 Release CI failing on master — eight consecutive failures spanning all five releases&lt;/strong&gt;&lt;br&gt;
The Release workflow has failed on every master merge this week — eight consecutive failures spanning all five releases (v2026.601.0 through v2026.605.0). The regression appears to predate this week; root cause is not yet confirmed. Releases were published despite each failure. This is a significant signal: if the release gate is routinely bypassed, a bad build could slip through. If you're looking for a high-impact investigation, this is it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🟡 PR #90 — Reviewer routing for ClickUp approval handoffs is drafted but stalled&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/zesthq/bizbox/pull/90" rel="noopener noreferrer"&gt;PR #90&lt;/a&gt; adds &lt;code&gt;primaryReviewerUserId&lt;/code&gt; and &lt;code&gt;secondaryReviewerUserId&lt;/code&gt; to the ClickUp awaiting-human approval flow, enabling named reviewer mentions in outbound notifications. It's drafted but CI is failing on the &lt;code&gt;feat-approval-scheme&lt;/code&gt; branch. The feature is needed for any team using named approvers in ClickUp workflows. Blocked until CI is green.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🟡 Pre-existing test failures: agent-permissions and company-portability routes&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;agent-permissions-routes.test.ts&lt;/code&gt; is reporting &lt;code&gt;socket hang up&lt;/code&gt;, and &lt;code&gt;company-portability-routes.test.ts&lt;/code&gt; is returning &lt;code&gt;200&lt;/code&gt; where &lt;code&gt;403&lt;/code&gt; is expected. Both were called out as pre-existing in PR #78. They're not new this week, but they're unresolved and they add noise to every CI run. Someone should own a fix.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Build Log produced from GitHub API data for zesthq/bizbox, 2026-05-31 → 2026-06-06. 8 PRs merged, 5 releases.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>buildinpublic</category>
      <category>devjournal</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Deep Dive: Building the Awaiting-Human Bridge — From ClickUp Polling to a Provider-Agnostic Approval Layer</title>
      <dc:creator>Bizbox</dc:creator>
      <pubDate>Mon, 01 Jun 2026 05:26:22 +0000</pubDate>
      <link>https://dev.to/joincitro/deep-dive-building-the-awaiting-human-bridge-from-clickup-polling-to-a-provider-agnostic-5dm4</link>
      <guid>https://dev.to/joincitro/deep-dive-building-the-awaiting-human-bridge-from-clickup-polling-to-a-provider-agnostic-5dm4</guid>
      <description>&lt;h1&gt;
  
  
  Deep Dive: Building the Awaiting-Human Bridge — From ClickUp Polling to a Provider-Agnostic Approval Layer
&lt;/h1&gt;

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




&lt;h2&gt;
  
  
  Background: The Status That Needed a Bridge
&lt;/h2&gt;

&lt;p&gt;In May 2026, we shipped the &lt;code&gt;awaiting_human&lt;/code&gt; status — a dedicated state for issues parked on a human decision, distinct from &lt;code&gt;blocked&lt;/code&gt; (which is for dependency-blocked work that agents can help unstick). If you missed that post, the short version: when an agent creates a &lt;code&gt;request_confirmation&lt;/code&gt; or &lt;code&gt;ask_user_questions&lt;/code&gt; interaction on an &lt;code&gt;in_progress&lt;/code&gt; issue, Bizbox auto-parks the issue to &lt;code&gt;awaiting_human&lt;/code&gt; and prevents agents from acting on it until a human responds.&lt;/p&gt;

&lt;p&gt;That was the right design. But it immediately raised a practical question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does the human actually respond?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a zero-human company, the "board" isn't sitting in a Bizbox tab watching for notifications. They're in ClickUp, Slack, or wherever their team already lives. If the approval signal has to come through a Bizbox UI action, you've just added a context-switch tax to every human decision point — and in a system designed to reduce human toil, that's a problem.&lt;/p&gt;

&lt;p&gt;The answer we built over the second half of May 2026 is the &lt;strong&gt;awaiting-human bridge&lt;/strong&gt;: a pluggable layer that lets Bizbox send approval requests to external channels and poll for responses, closing the loop without requiring the human to leave their existing workflow.&lt;/p&gt;

&lt;p&gt;This post walks through how we built it, the design decisions we made along the way, and where it's headed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem in Detail
&lt;/h2&gt;

&lt;p&gt;When an issue enters &lt;code&gt;awaiting_human&lt;/code&gt;, Bizbox needs to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Notify&lt;/strong&gt; the right human in the right channel that a decision is needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wait&lt;/strong&gt; for a response — which might be a reply, a reaction, or a structured approval action.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interpret&lt;/strong&gt; that response correctly: is a thumbs-up an approval? Is a plain text reply a rejection, a question, or just an acknowledgement?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resume&lt;/strong&gt; the agent workflow once the decision is made.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each of these steps has failure modes. Notifications can fail to deliver. Responses can be ambiguous. The same external event can arrive multiple times (webhooks are not exactly-once). And the human might respond days later, after the system has restarted or the bridge state has been garbage-collected.&lt;/p&gt;

&lt;p&gt;We needed a design that was reliable, idempotent, and extensible — because ClickUp is the first channel, but it won't be the last.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture: Four Layers
&lt;/h2&gt;

&lt;p&gt;The bridge architecture that emerged across PRs &lt;a href="https://github.com/zesthq/bizbox/pull/42" rel="noopener noreferrer"&gt;#42&lt;/a&gt;, &lt;a href="https://github.com/zesthq/bizbox/pull/52" rel="noopener noreferrer"&gt;#52&lt;/a&gt;, &lt;a href="https://github.com/zesthq/bizbox/pull/56" rel="noopener noreferrer"&gt;#56&lt;/a&gt;, &lt;a href="https://github.com/zesthq/bizbox/pull/65" rel="noopener noreferrer"&gt;#65&lt;/a&gt;, &lt;a href="https://github.com/zesthq/bizbox/pull/68" rel="noopener noreferrer"&gt;#68&lt;/a&gt;, &lt;a href="https://github.com/zesthq/bizbox/pull/70" rel="noopener noreferrer"&gt;#70&lt;/a&gt;, &lt;a href="https://github.com/zesthq/bizbox/pull/74" rel="noopener noreferrer"&gt;#74&lt;/a&gt;, and &lt;a href="https://github.com/zesthq/bizbox/pull/76" rel="noopener noreferrer"&gt;#76&lt;/a&gt; has four distinct layers:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Outbox (Reliable Notification Delivery)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/56" rel="noopener noreferrer"&gt;PR #56&lt;/a&gt;&lt;/strong&gt; introduced the &lt;code&gt;awaiting_human_notification_outbox&lt;/code&gt; table — a durable queue for outbound notifications. Instead of firing-and-forgetting a ClickUp message, Bizbox writes a row to the outbox first, then a background processor picks it up, delivers it, and records the resulting ClickUp message ID.&lt;/p&gt;

&lt;p&gt;This gives us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retryability:&lt;/strong&gt; If the ClickUp API is down, the notification retries on the next heartbeat cycle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deduplication:&lt;/strong&gt; The outbox row has a &lt;code&gt;dedupeKey&lt;/code&gt; tied to the issue and interaction, so we never send the same notification twice even if the trigger fires multiple times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auditability:&lt;/strong&gt; Every notification attempt, success, and failure is logged with timestamps and error details.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The outbox pattern is a classic reliability primitive, but it's worth calling out explicitly: this is the foundation that makes everything else safe to build on.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Approval Polling Loop
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/42" rel="noopener noreferrer"&gt;PR #42&lt;/a&gt;&lt;/strong&gt; added the first version of ClickUp approval polling. On each heartbeat cycle, for every &lt;code&gt;awaiting_human&lt;/code&gt; issue with a pending &lt;code&gt;request_confirmation&lt;/code&gt; interaction, Bizbox polls the ClickUp message thread for replies and reactions.&lt;/p&gt;

&lt;p&gt;The initial design was straightforward: if a configured positive reply or reaction is detected, resolve the interaction as approved and wake the assignee agent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/52" rel="noopener noreferrer"&gt;PR #52&lt;/a&gt;&lt;/strong&gt; cleaned up two reliability issues that surfaced early in production. First, ClickUp comment IDs can arrive as numbers rather than strings — the adapter was only accepting strings, which caused valid top-level comments and replies to be silently dropped during import. PR #52 aligned the adapter with the existing scalar-ID coercion pattern used elsewhere in the codebase. Second, a bridge status value (&lt;code&gt;agent_replied&lt;/code&gt;) existed in types and UI filtering but had no runtime transition path — it was unreachable dead code. Removing it simplified the bridge state machine and eliminated a source of confusion when reading bridge lifecycle logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/68" rel="noopener noreferrer"&gt;PR #68&lt;/a&gt;&lt;/strong&gt; hardened the message ID resolution. The polling loop needs the ClickUp message ID to know which thread to poll — but there's a race condition: the activity log entry (which stores the message ID) might be written before the outbox processor has actually delivered the notification. PR #68 added a fallback: if the message ID isn't in the activity log, look it up from the outbox table using the &lt;code&gt;dedupeKey&lt;/code&gt;. This eliminated a class of "polling the wrong thread" bugs that showed up in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Rejection Semantics
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/70" rel="noopener noreferrer"&gt;PR #70&lt;/a&gt;&lt;/strong&gt; tackled a question that sounds simple but has real behavioral implications: &lt;em&gt;what does a non-approval reply mean?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The initial implementation treated non-approval replies as noise — they were ignored, and the bridge kept waiting. That turned out to be wrong in practice. When a human replies "no, don't do this" or "I need more context first," ignoring that reply leaves the issue parked indefinitely and the agent unaware that the human has weighed in.&lt;/p&gt;

&lt;p&gt;The new behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explicit negative reactions&lt;/strong&gt; (e.g., &lt;code&gt;thumbsdown&lt;/code&gt;) → immediate rejection, no comment forwarded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-approval text replies&lt;/strong&gt; → treated as rejection, forwarded as a comment on the issue so the agent has context when it wakes up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approval replies/reactions&lt;/strong&gt; → resolve the interaction as approved, wake the agent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes the bridge a two-way channel, not just a one-way approval gate. The human's response — whatever it is — gets back to the agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The Provider-Agnostic Bridge Core
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/65" rel="noopener noreferrer"&gt;PR #65&lt;/a&gt;&lt;/strong&gt; laid the configuration groundwork for the bridge. It introduced dedicated environment variables (&lt;code&gt;CLICKUP_AWAITING_HUMAN_CHANNEL_ID&lt;/code&gt; and &lt;code&gt;CLICKUP_AWAITING_HUMAN_CHANNEL_NAME&lt;/code&gt;) for specifying the ClickUp approval channel, with fallback to legacy engineering variables and a default of &lt;code&gt;bizbox-feed&lt;/code&gt; when no channel name is provided. It also improved the human-facing notification message content — making the approval request clearer and more actionable — and updated &lt;code&gt;.env.example&lt;/code&gt; documentation. This was the first step toward making the bridge channel-configurable rather than hardcoded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/74" rel="noopener noreferrer"&gt;PR #74&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/76" rel="noopener noreferrer"&gt;PR #76&lt;/a&gt;&lt;/strong&gt; are where the architecture shifted from "ClickUp integration" to "bridge infrastructure."&lt;/p&gt;

&lt;p&gt;PR #74 introduced the &lt;code&gt;company_awaiting_human_settings&lt;/code&gt; table and a configuration schema that lets each company specify its own bridge provider and routing. The first supported provider is ClickUp, with workspace and channel routing. But the schema is designed to accommodate future providers without changes to the core.&lt;/p&gt;

&lt;p&gt;PR #76 finalized the bridge lifecycle semantics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interaction-scoped dedupe.&lt;/strong&gt; Inbound events now deduplicate on &lt;code&gt;(interaction_id, external_event_id)&lt;/code&gt; rather than just &lt;code&gt;external_event_id&lt;/code&gt;. This means the same external event (e.g., a webhook delivered twice) is safely ignored, but the same event arriving for a &lt;em&gt;different&lt;/em&gt; interaction on the same issue is handled correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free-text replies stay as comments.&lt;/strong&gt; Plain replies from the human are imported as issue comments and wake the agent, rather than being treated as approval signals. The bridge stays open until an explicit approval or rejection arrives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retries create fresh rows.&lt;/strong&gt; Bridge retries no longer reuse stale state; each retry creates a new outbox row, preventing stale delivery state from blocking future attempts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ClickUp transport adapter itself is being extracted into a pure plugin in &lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/78" rel="noopener noreferrer"&gt;PR #78&lt;/a&gt;&lt;/strong&gt; (still in review at time of writing), which will keep the bridge core entirely provider-agnostic and let ClickUp register via &lt;code&gt;AwaitingHumanBridgeRegistry&lt;/code&gt; like any future provider.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Design Decisions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Decision 1: Outbox-first, not fire-and-forget
&lt;/h3&gt;

&lt;p&gt;We could have sent ClickUp notifications inline during the issue status transition. It's simpler code. But inline delivery means a ClickUp API failure blocks the status transition, and a retry requires re-running the whole transition logic.&lt;/p&gt;

&lt;p&gt;The outbox decouples delivery from state change. The issue parks to &lt;code&gt;awaiting_human&lt;/code&gt; immediately; the notification goes out when it can. This is the right trade-off for a system where the human-facing notification is important but not on the critical path of the state machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decision 2: Non-approval replies are rejections, not noise
&lt;/h3&gt;

&lt;p&gt;This was the most debated call. The argument for treating non-approval replies as noise: it's simpler, and it avoids false rejections from humans who reply "got it" or "looking now" without intending to reject.&lt;/p&gt;

&lt;p&gt;The argument for treating them as rejections: in a zero-human company, the human's time is the scarce resource. If they've replied, they've engaged. Ignoring their reply and leaving the issue parked is worse than a false rejection — at least a rejection wakes the agent and gives it the human's comment as context.&lt;/p&gt;

&lt;p&gt;We went with rejection-as-default, with the explicit negative reaction path as the "clean" rejection signal. We're watching for false-rejection reports in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decision 3: Provider-agnostic core from the start
&lt;/h3&gt;

&lt;p&gt;We could have shipped a ClickUp-specific bridge and refactored later. The counter-argument: the bridge touches the database schema, the heartbeat service, and the interaction resolution flow. Refactoring those layers after the fact is expensive and risky.&lt;/p&gt;

&lt;p&gt;By designing the bridge core to be provider-agnostic from PR #74 onward — with ClickUp as the first adapter — we pay a small upfront cost for a much cleaner extension path. When Slack or Discord support lands, it registers via the same &lt;code&gt;AwaitingHumanBridgeRegistry&lt;/code&gt; without touching bridge core.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  The Polling Tax
&lt;/h3&gt;

&lt;p&gt;The current implementation polls ClickUp on every heartbeat cycle for every &lt;code&gt;awaiting_human&lt;/code&gt; issue. At low volume, this is fine. At scale, it's a lot of API calls — and ClickUp's rate limits are not generous.&lt;/p&gt;

&lt;p&gt;We're considering a webhook-first approach where ClickUp pushes events to Bizbox, with polling as a fallback. That requires a publicly reachable webhook endpoint and more complex event routing, but it would dramatically reduce the polling load.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approval Signal Ambiguity
&lt;/h3&gt;

&lt;p&gt;The configured "positive reply" list is a blunt instrument. Right now, operators configure a list of strings (e.g., &lt;code&gt;["yes", "approved", "lgtm"]&lt;/code&gt;) that count as approval. That works for structured workflows but breaks down for natural language responses.&lt;/p&gt;

&lt;p&gt;A future direction: use a lightweight classifier to interpret free-text replies, rather than exact-match string lists. The risk is false positives on ambiguous language — which in an approval context is a meaningful safety concern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-Provider Routing
&lt;/h3&gt;

&lt;p&gt;The current schema supports one bridge provider per company. But some companies might want to route different issue types to different channels — high-priority approvals to a dedicated Slack channel, routine confirmations to ClickUp.&lt;/p&gt;

&lt;p&gt;The settings schema has room for this, but the routing logic isn't there yet. It's on the roadmap.&lt;/p&gt;

&lt;h3&gt;
  
  
  The PR #78 Gap
&lt;/h3&gt;

&lt;p&gt;The ClickUp transport adapter is still in review as a pure plugin (&lt;a href="https://github.com/zesthq/bizbox/pull/78" rel="noopener noreferrer"&gt;PR #78&lt;/a&gt;). Until it merges, the bridge core and the ClickUp adapter are more coupled than the final architecture intends. We're treating this as a known technical debt item with a clear resolution path.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reliability primitives pay for themselves.&lt;/strong&gt; The outbox pattern added a migration, a background processor, and a handful of service methods. It also eliminated an entire class of "notification never arrived" bugs and made the retry story trivial. Worth it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavioral design is harder than technical design.&lt;/strong&gt; The rejection semantics question — what does a non-approval reply mean? — took more discussion than the outbox implementation. The technical work was straightforward; the behavioral contract required careful thought about what the system should do in ambiguous situations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider-agnostic from the start is the right call for integration layers.&lt;/strong&gt; The temptation to ship a ClickUp-specific bridge and "clean it up later" is real. The cost of doing it right upfront was one extra PR and a slightly more abstract schema. The benefit is a clean extension path for every future provider.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/78" rel="noopener noreferrer"&gt;PR #78&lt;/a&gt;&lt;/strong&gt; — ClickUp transport as a pure plugin, completing the provider-agnostic bridge architecture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook-first polling&lt;/strong&gt; — reduce the heartbeat polling load by accepting ClickUp push events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-provider routing&lt;/strong&gt; — route different issue types to different approval channels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Natural language approval interpretation&lt;/strong&gt; — move beyond exact-match string lists for approval signal detection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building on Bizbox or thinking about how to handle human-in-the-loop approval flows in your own agent systems, we'd love to hear what patterns you're using. 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; — the status that made the bridge necessary&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/42" rel="noopener noreferrer"&gt;PR #42: ClickUp approval polling&lt;/a&gt;&lt;/strong&gt; — first approval polling implementation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/52" rel="noopener noreferrer"&gt;PR #52: Normalize comment IDs and remove dead bridge status&lt;/a&gt;&lt;/strong&gt; — cleanup and normalization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/56" rel="noopener noreferrer"&gt;PR #56: Awaiting-human notification outbox&lt;/a&gt;&lt;/strong&gt; — reliable notification delivery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/65" rel="noopener noreferrer"&gt;PR #65: ClickUp approval configuration&lt;/a&gt;&lt;/strong&gt; — company-scoped channel routing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/68" rel="noopener noreferrer"&gt;PR #68: Message ID fallback in heartbeat&lt;/a&gt;&lt;/strong&gt; — race condition fix&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/70" rel="noopener noreferrer"&gt;PR #70: Rejection semantics for non-approval replies&lt;/a&gt;&lt;/strong&gt; — behavioral design decision&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/74" rel="noopener noreferrer"&gt;PR #74: Bridge configuration schema&lt;/a&gt;&lt;/strong&gt; — provider-agnostic settings layer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/76" rel="noopener noreferrer"&gt;PR #76: Bridge retry and reply dedupe&lt;/a&gt;&lt;/strong&gt; — lifecycle hardening&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/pull/78" rel="noopener noreferrer"&gt;PR #78: ClickUp bridge adapter as pure plugin&lt;/a&gt;&lt;/strong&gt; — in review&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/zesthq/bizbox/blob/master/docs/blog/deep-dive-2026-05-awaiting-human.md" rel="noopener noreferrer"&gt;May 2026 Deep Dive: The &lt;code&gt;awaiting_human&lt;/code&gt; Status&lt;/a&gt;&lt;/strong&gt; — the foundation this bridge builds on&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>agents</category>
      <category>architecture</category>
      <category>automation</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Bizbox Build Log — Week of 2026-05-30</title>
      <dc:creator>Bizbox</dc:creator>
      <pubDate>Fri, 29 May 2026 00:06:15 +0000</pubDate>
      <link>https://dev.to/joincitro/bizbox-build-log-week-of-2026-05-30-4n3</link>
      <guid>https://dev.to/joincitro/bizbox-build-log-week-of-2026-05-30-4n3</guid>
      <description>&lt;h1&gt;
  
  
  Bizbox Build Log — Week of 2026-05-30
&lt;/h1&gt;

&lt;p&gt;Five substantive PRs merged this week (2026-05-23 through 2026-05-30), two releases shipped. The theme: the awaiting-human bridge grows up — two merged PRs lay the provider-agnostic infrastructure (company-scoped configuration and hardened lifecycle semantics), with the ClickUp transport adapter still in review. Plus: the first Google ADK agent adapter lands, and the production VMs get a resource bump to match real workloads.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note on release tags: PRs #72, #74, and #76 merged to master on 2026-05-28 and are not yet in a tagged release at time of writing. PRs #70 and #73 shipped in v2026.525.0 and v2026.525.1 respectively.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Shipped This Week
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🤖 Google ADK agent adapter
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PR &lt;a href="https://github.com/zesthq/bizbox/pull/72" rel="noopener noreferrer"&gt;#72&lt;/a&gt; · @DennisDenuto · merged 2026-05-28 · not yet in a tagged release&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bizbox can now create and manage agents backed by Google's Agent Development Kit (ADK). The new adapter package covers server execution, CLI formatting, stdout parsing, and UI config/build helpers. Google ADK is registered in the shared agent-type registry, adapter registry, and capability lookup — so it behaves like any other built-in adapter from the operator's perspective: create it, configure it, assign it to issues.&lt;/p&gt;

&lt;p&gt;The adapter ships with server-level tests for event parsing and execution behaviour, and the agent loadout UI was updated to include Google ADK in the configuration and new-agent flows.&lt;/p&gt;

&lt;p&gt;This is the first non-OpenClaw adapter to land in the core codebase. It opens the door to multi-runtime agent pipelines where different tasks can be routed to the best-fit execution environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌉 Awaiting-human bridge: retry and reply dedupe
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PR &lt;a href="https://github.com/zesthq/bizbox/pull/76" rel="noopener noreferrer"&gt;#76&lt;/a&gt; · @ralphbibera · merged 2026-05-28 · not yet in a tagged release&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The second of two merged awaiting-human bridge PRs this week (a third, the ClickUp transport adapter PR &lt;a href="https://github.com/zesthq/bizbox/pull/78" rel="noopener noreferrer"&gt;#78&lt;/a&gt;, is still in review). This PR finalises the bridge lifecycle. Key changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interaction-scoped dedupe.&lt;/strong&gt; Inbound events now deduplicate on &lt;code&gt;(interaction_id, external_event_id)&lt;/code&gt; rather than just &lt;code&gt;external_event_id&lt;/code&gt;. The same external event can be safely ignored across bridge reopenings without false-positive suppression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free-text replies stay as comments.&lt;/strong&gt; Plain replies from the human operator are now imported as issue comments and wake the agent, rather than being treated as approval signals. The bridge stays open until an explicit approval or rejection arrives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retries create fresh rows.&lt;/strong&gt; Bridge retries no longer reuse stale state; each retry starts clean, which eliminates a class of ghost-approval bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heartbeat compatibility.&lt;/strong&gt; The heartbeat reconciler previously contained a hardcoded &lt;code&gt;clickup-chat&lt;/code&gt; reference for filtering legacy delivered interactions. That reference has been moved into the bridge service, keeping the reconciler provider-agnostic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Migration &lt;code&gt;0076&lt;/code&gt; consolidates the final inbound event schema and dedupe index in one place.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙️ Awaiting-human bridge: company-scoped configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PR &lt;a href="https://github.com/zesthq/bizbox/pull/74" rel="noopener noreferrer"&gt;#74&lt;/a&gt; · @ralphbibera · merged 2026-05-28 · not yet in a tagged release&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first of the two merged bridge PRs this week adds the settings layer that makes the bridge multi-tenant. Before this, every company shared the same (or no) external channel for human approvals — settings were hardcoded or absent. Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A new &lt;code&gt;company_awaiting_human_settings&lt;/code&gt; table (migration &lt;code&gt;0075&lt;/code&gt;) stores per-company provider config as JSONB.&lt;/li&gt;
&lt;li&gt;The first supported provider is ClickUp, with workspace/channel routing and secret rotation.&lt;/li&gt;
&lt;li&gt;Zod validators cover PATCH requests; the &lt;code&gt;awaitingHumanSettingsService&lt;/code&gt; handles CRUD and secret rotation.&lt;/li&gt;
&lt;li&gt;The schema is designed so future providers (Slack, Discord, etc.) can be added without changing the settings shape.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the infrastructure that makes the pure-plugin ClickUp adapter (PR &lt;a href="https://github.com/zesthq/bizbox/pull/78" rel="noopener noreferrer"&gt;#78&lt;/a&gt;, still open) meaningful: each company can now point the bridge at its own ClickUp workspace.&lt;/p&gt;

&lt;h3&gt;
  
  
  🖥️ VM resource upgrade: 4 GB memory, 4 CPUs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PR &lt;a href="https://github.com/zesthq/bizbox/pull/73" rel="noopener noreferrer"&gt;#73&lt;/a&gt; · v2026.525.1 · @adPalafox · merged 2026-05-25&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;fly.toml&lt;/code&gt; and &lt;code&gt;fly.private.toml&lt;/code&gt; now allocate 4 GB of memory and 4 shared CPUs per VM, up from 2 GB / 2 CPUs. The change reflects real production workloads: multi-agent runs with concurrent heartbeats were hitting memory pressure under the old allocation. The upgrade doubles headroom for parallel execution without changing any application code.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ ClickUp approval: non-approval replies treated as rejection
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PR &lt;a href="https://github.com/zesthq/bizbox/pull/70" rel="noopener noreferrer"&gt;#70&lt;/a&gt; · v2026.525.0 · @adPalafox · merged 2026-05-25&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ClickUp awaiting-human approval handler now has explicit semantics for every reply type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explicit negative reactions&lt;/strong&gt; (&lt;code&gt;thumbsdown&lt;/code&gt;) immediately reject the interaction — no comment text is forwarded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-approval free-text replies&lt;/strong&gt; are treated as rejections, with the reply text forwarded as a comment into the related issue for context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approval signals&lt;/strong&gt; (positive reactions, explicit approval phrases) continue to work as before.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Previously, a human replying with anything other than an approval phrase could leave the interaction in an ambiguous state. The new behaviour is deterministic: every reply resolves the interaction one way or the other.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Provider-agnostic bridge architecture.&lt;/strong&gt; The team committed to keeping the awaiting-human bridge core strictly provider-agnostic. PRs #74 and #76 build the infrastructure; PR #78 (still open) ports the ClickUp transport as a pure plugin that registers via &lt;code&gt;AwaitingHumanBridgeRegistry&lt;/code&gt;. The rule: bridge core files must not reference any specific provider. This makes adding Slack, Discord, or any future channel a matter of writing a new adapter, not touching shared infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google ADK as a first-class adapter.&lt;/strong&gt; Rather than treating Google ADK as an experimental or external integration, the team registered it in the same adapter registry and capability lookup as OpenClaw. The decision signals that Bizbox is positioning itself as runtime-agnostic — the orchestration layer, not a wrapper around a single agent runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VM resources doubled proactively.&lt;/strong&gt; The resource bump in PR #73 was driven by observed memory pressure in production, not a planned capacity review. The decision to double both memory and CPUs (rather than a more conservative step-up) reflects a preference for headroom over incremental tuning.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bridge config is company-scoped, not agent-scoped.&lt;/strong&gt; The new &lt;code&gt;company_awaiting_human_settings&lt;/code&gt; table routes all awaiting-human interactions for a company through the same provider and channel. That's the right default for most deployments, but companies that want different approval channels for different agent types or projects will need a future per-agent or per-project override layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google ADK adapter ships without end-to-end integration tests.&lt;/strong&gt; The PR includes server-level unit tests for event parsing and execution, and UI tests for the loadout editor. A full end-to-end test (agent creation → issue assignment → heartbeat execution → result) is not yet in place. The adapter is functional but the integration surface is less hardened than the OpenClaw adapter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-approval reply semantics are a breaking change for edge cases.&lt;/strong&gt; PR #70 changes what happens when a human replies with free text that isn't an approval phrase. Previously the behaviour was undefined; now it's an explicit rejection. Any workflow that relied on free-text replies being ignored (rather than treated as rejections) will behave differently. The change is correct, but operators should be aware.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Open Challenges
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ClickUp pure-plugin adapter (PR #78) is still open.&lt;/strong&gt; The bridge infrastructure (PRs #74 and #76) is merged, but the ClickUp transport itself is still in review. Until #78 lands, the bridge has the configuration layer but no live ClickUp transport wired to it. The full end-to-end path — company settings → bridge core → ClickUp transport → human reply → agent wake — is not yet closed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bridge reconciliation coverage.&lt;/strong&gt; Two PRs merged to the awaiting-human bridge this week, with a third (PR #78) still in review. The surface is being hardened rapidly, but the full reconciliation path (outbox → ClickUp delivery → heartbeat poll → interaction accept → agent wake) still lacks an end-to-end integration test. This was flagged last week and remains on the backlog.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-runtime agent routing.&lt;/strong&gt; The Google ADK adapter landing opens a real question: how does an operator decide which runtime to use for a given task? Today the choice is made at agent-creation time and is static. Dynamic routing — assigning tasks to the best-fit runtime based on task type, cost, or latency — is not yet designed.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  X Thread Teaser
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;🧵 Bizbox Build Log — Week of May 30, 2026&lt;/p&gt;

&lt;p&gt;5 PRs merged, 2 releases shipped. The awaiting-human bridge got a full architecture upgrade, Google ADK landed as a first-class adapter, and the VMs got a resource bump. Here's what moved 👇&lt;/p&gt;

&lt;p&gt;1/ New: Google ADK agent adapter. Bizbox can now create and run agents backed by Google's Agent Development Kit — registered in the same adapter registry as OpenClaw. First step toward runtime-agnostic orchestration.&lt;br&gt;
&lt;a href="https://github.com/zesthq/bizbox/pull/72" rel="noopener noreferrer"&gt;https://github.com/zesthq/bizbox/pull/72&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2/ Awaiting-human bridge: company-scoped config + lifecycle hardening. Each company can now configure its own approval channel (ClickUp first). Retries create fresh rows, free-text replies stay as comments, inbound events dedupe per interaction.&lt;br&gt;
&lt;a href="https://github.com/zesthq/bizbox/pull/74" rel="noopener noreferrer"&gt;https://github.com/zesthq/bizbox/pull/74&lt;/a&gt; &lt;a href="https://github.com/zesthq/bizbox/pull/76" rel="noopener noreferrer"&gt;https://github.com/zesthq/bizbox/pull/76&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3/ ClickUp approval semantics are now deterministic. Thumbsdown = immediate rejection. Free-text non-approval reply = rejection with context forwarded. No more ambiguous states.&lt;br&gt;
&lt;a href="https://github.com/zesthq/bizbox/pull/70" rel="noopener noreferrer"&gt;https://github.com/zesthq/bizbox/pull/70&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4/ VMs doubled: 4 GB / 4 CPUs. Driven by real memory pressure from concurrent multi-agent heartbeats. Headroom &amp;gt; incremental tuning.&lt;br&gt;
&lt;a href="https://github.com/zesthq/bizbox/pull/73" rel="noopener noreferrer"&gt;https://github.com/zesthq/bizbox/pull/73&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5/ Open challenge: the ClickUp bridge adapter (PR #78) is still in review. The infrastructure is merged but the live transport isn't wired yet. The full approval loop closes when #78 lands.&lt;/p&gt;

&lt;p&gt;Full build log: &lt;a href="https://github.com/zesthq/bizbox/blob/master/community/build-logs/2026-05-30.md" rel="noopener noreferrer"&gt;https://github.com/zesthq/bizbox/blob/master/community/build-logs/2026-05-30.md&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;Grounded in merged PRs and releases from &lt;a href="https://github.com/zesthq/bizbox" rel="noopener noreferrer"&gt;zesthq/bizbox&lt;/a&gt;, 2026-05-23 to 2026-05-30. No activity was invented.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>devjournal</category>
      <category>infrastructure</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
