Skip to content

Roadmap: one-day multimodal chat app — assembled vertical + gates #188

Description

@drewstone

Definition of done: create-agent-app → fill agent.config.ts + profile → wrangler deploy = a working multimodal chat product, in one day, with CI that makes the known incident classes unshippable. Everything below is derived from a measured audit (2026-07-15) of agent-app, agent-dev-container, legal-agent, and tax-agent — each item cites the gap it closes. Nothing speculative.

Ground truth today: every primitive exists and is production-proven (client streamChatTurn w/ resume, D1 turn-buffer, PromptInputPart[] dispatch as of #187, interactions contract as of #176, teams/access/seat-billing, harness-native images on all 3 product harnesses). What's missing is the assembly: legal wrote 2,190 lines of chat orchestration, tax wrote 1,058 — differently (legal skips the turn-buffer, tax skips onInteraction, both fork the question-card stack ~1,000 lines each, neither delivers an image part). The scaffold emits a JSON tool-loop worker, not a chat app.

Phase 1 — the assembled chat vertical (kills ~3,500–4,500 lines of per-app glue)

  • createChatTurnRoutes() (M): one exported factory assembling body-parse → sandbox producer → turn-buffer tap → SSE Response, plus replay + interaction-answer endpoints. Consumers: replace legal api.chat.ts (895 lines) and tax chat-turn.ts (1,058 lines) with it — the migration is the acceptance test.
  • /chat-store (S–M): threads+messages drizzle table factory (same injection pattern as createTeamTables) + thread/message CRUD incl. batched + bulk delete. Legal/tax each hand-roll incompatible schemas today; tax re-declares the framework's own turn_events DDL.
  • Multimodal middle (M): upload helper (inline ≤~750 KB, else fs.uploadData + path-ref part — the 1 MiB gateway cap makes this a required two-step), file→PromptInputPart assembly, and ChatComposer emitting parts from onSend (today it emits onSend(string) and a disjoint FileList; both products drop attachments on the floor).
  • Interaction UI + answer forwarding (M): shared question-card component + sidecar-answer server helper. Legal (1,059 lines) and tax (844 lines) each maintain a forked copy of the contract agent-app already ships.
  • createAppAuth() (S): better-auth config factory (drizzle adapter, providers, cookie prefix, SSO wiring). Both apps hand-roll; tax re-implements cookie signing.

Phase 2 — provable (works, tests, ships)

  • Five S-cost gates in agent-app (each an assertion at an existing choke point): provision-payload size (<240 KiB, per-section breakdown) in ensureWorkspaceSandbox; composed-prompt byte budget (default 40 KB) in profile composition; onErrorEvent fail-loud when unhandled (silent-empty-answer class); generalize the /catalog import-graph walker over a declared browser-safe manifest (all ~12 browser subpaths); env-var size check (E2BIG class) piggybacked on the payload gate.
  • Nightly live-e2e workflow in agent-dev-container (S): one workflow flipping the existing RUN_*_LIVE_E2E flags — the test content exists; the flags appear in zero of 30 workflows. This is the class behind every "green CI, dead in prod" event this month.
  • Chat-app scaffold variant (M once Phase 1 lands): create-agent-app --chat assembles Phase 1; the existing scaffold test (which already typechecks generated apps against real dist) extends to run one fake-backend turn + the prompt/theme budget checks.
  • /preflight secret-liveness bin (M): declared probes (router chat ping, sandbox auth ping, platform HEAD) run as a deploy step — the one class that can't be a CI gate (4 dead secrets in one day last incident).

Phase 3 — platform closers (agent-dev-container)

  • #3539 E2BIG (S–M): OPENCODE_CONFIG_CONTENT is still an unbounded env var (sdk-provider-opencode/src/server.ts:357); write config to the on-disk opencode.jsonc it already points at. #3621 covered file mounts only.
  • Attachment workflow docs + opencode live image test (S): the upload-then-path two-step is mechanically solid and documented nowhere; opencode's native image path has no live proof that the model sees the image.
  • Codex images × interactions — blocked upstream (#3586); until then apps must check runtime getCapabilities().multimodal (registry imageInput: true is not the whole truth on app-server configs). Document the check in the SDK README.

Deliberately excluded (not "necessary to ship")

User-facing AgentProfile customization UI (the only true L — seams exist via userSkills/ProfileOverlay, zero producers; build when a product needs it), additional harness attachment support beyond the 3 product harnesses, balance-manager adoption (S, cleanup not blocker).

Sequencing / effort

Phase 1 items are independent → parallelizable; ~1 focused engineer-week total, or 2–3 orchestrated days. Phase 2 gates are hours each. Phase 3 is Lin's lane and mostly S. After Phase 1 + scaffold variant, the one-day claim is real and the scaffold test enforces it forever.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions