forked from bots-garden/ori
Handoff — 2026-09-17 — ACP web client (ticket 0004)
State
The full v1 works and is verified: make run-mock serves the panel on :8888 with the bundled demo agent (smoke-tested live over a real WebSocket: hello → prompt → thought/plan/tool calls → permission → turn_ended). All test suites green (make test, plus go test -race), quality gate PASS, bilingual docs written, .memory/ created. Two commits on branch feat/acp-webapp (main holds only the initial repo state); a final commit with docs/memory/module-rename is proposed but not yet made — the user decides.
In flight — READ THIS FIRST (updated at session end)
Open bug: the UI shows "offline" in the user's real sbx sandbox (sbx create claude . --template k33g/ori:0.0.0 --kit ./kits/ori -p 5555:8888; page loads, so ori runs and HTTP forwards — the /ws WebSocket is what fails or drops). Already established:
- ori's WS origin handling is CORRECT: curl handshakes against the image give 101 for
Origin: http://localhost:5555(and any localhost:*), 403 for foreign origins. Node-based smoke tests send no Origin header, so they never exercised this. - sbx port publishing is raw L4 (gvisor MapPorts in
sandboxes/sandboxd/pkg/server/backend_dockernext.go), so the upgrade should traverse. - Three discriminating diagnostics were given to the user, ANSWERS PENDING: (1)
sbx exec ori tail -20 /home/agent/.ori.log(an origin rejection logs "websocket accept failed"); (2) curl WS handshake from INSIDE the sandbox to :8888/ws; (3) same from the host through :5555. 101/101 → look at the browser console; inside-101/forward-not-101 → the forward blocks upgrades; inside-403 → origin, ask the exact browser URL. If (1) shows nothing at all, check/var/log/sbx-kit-startup.log. - Possible follow-up angle if 101/101: default publish protocol is tcp4 (IPv4-only host listener) while browsers try ::1 first for localhost — page fallback works, some WS stacks may not; retry publishing with explicit
/tcp(dual-stack) or have the browser use http://127.0.0.1:5555.
In flight (rest)
Nothing half-written. The final commit of docs + .memory/ + the module rename is the only pending mechanical action.
Workspace panel (added later in the session)
The user requested and approved a workspace evolution, delivered complete: internal/files + internal/terminal on the backend; file tree, Monaco preview/editor, Markdown/AsciiDoc rendering, xterm.js terminal on the front; execute tool output in monospace. Gate PASS again, 46 Go + 66 front tests. Server redeployed live with it. New traps recorded in "Watch out for".
Next steps
- Let the user try the UI in a real browser (in the sandbox this needs
sbx ports <sandbox> --publish 8888:8888/tcpon the host; the server already binds0.0.0.0). - Try against real Claude Code (
make run) — needs claude auth in the environment; never exercised here. - Tickets 0002 (architecture diagram — largely satisfied by
docs/diagrams/packages.drawio, consider closing) and 0003 (how to run outside the sandbox — the docs' how-to pages are most of the answer). - Natural evolutions, in design order: render non-text content blocks (images/resources), session modes (
current_mode_updateis currently ignored), multi-session/tabs via thebridge.Prompterseam, file preview / file list panes (the ticket names them as future needs).
Open questions / blockers
- No git remote is configured; where this repo is hosted (rickub.com?) is unknown here.
- Whether
make runworks with the user's Claude auth has not been verified in this sandbox.
Verified against real Claude Code (later in the session)
make run failed at first inside this sandbox: Claude Code refuses to launch inside another Claude Code session (the CLAUDECODE env var is inherited from the sandbox's own session). Workaround that works: env -u CLAUDECODE ./bin/ori. With that, the full chain was verified live: real session created (UUID id), prompt over WebSocket, streamed answer, turn_ended end_turn. Decision pending: whether to strip CLAUDECODE in spawnProcess, in the Makefile, or only document it. Also noted: the adapter package was renamed @zed-industries/claude-code-acp → @agentclientprotocol/claude-agent-acp (old name still works, deprecated) — consider updating config.DefaultAgentCommand.
Watch out for
-
The adapter inherits the user's
~/.claude/settings.jsondefault model. A/modeltoggle in another session saved"claude-fable-5[1m]"(the 1M-context variant), which the adapter's session cannot access → every prompt failed with -32603 "issue with the selected model (fable[1m])". Fix in force: launch ori withANTHROPIC_MODEL=claude-fable-5(plain id) so the adapter is decoupled from the UI's saved default. -
~/.npmis a full 488MB dedicated volume — npm installs of big packages fail with ENOSPC; the cache now lives at~/.npm-bigviaNPM_CONFIG_CACHEin/etc/sandbox-persistent.sh. -
monaco-editor 0.56 exports map: import workers as
monaco-editor/editor/editor.worker.js?worker(noesm/vs/prefix — the map adds it);?workerimports need"vite/client"in tsconfig types. -
biome 1.9 suppressions:
lint/a11y/noStaticElementInteractionsdoes not exist in 1.9 (suppression = parse error); a suppression for a JSX attribute must sit on the line directly above that attribute, inside the opening tag. -
@asciidoctor/core v4 API:
convertis a NAMED export and returns a Promise — there is no default export and noasciidoctor()factory (that was v3). Never mock this module in the only test covering it: the real-render test inAsciiDocView.test.tsxexists precisely because a mocked test let a production breakage through. -
Material icons: served from
/material-icons(copied fromvscode-material-iconsintoui/public/byui/scripts/copy-icons.mjs, hooked on npmpredev/prebuild, gitignored). A fresh checkout gets them on the firstmake build/make dev. -
Module path is
rickub.com/bots-garden/ori— do not "fix" it back to github; the user explicitly corrected this mid-session. -
~/.qltyis a dedicated 488MB volume; the qlty tool cache lives at~/.qlty-cacheon the main disk behind a symlink. If that symlink disappears (sandbox recreation), qlty installs will fail with ENOSPC again; recreate it before running the quality skill. -
The coder acp-go-sdk does NOT auto-inject the connection into an agent implementation: call
SetAgentConnectionmanually (bit us once; the mock ininternal/agent/agent_test.goandmockagent.Runboth do it). -
qlty's
return-statementssmell counts returns inside nested closures as part of the enclosing function — extract named functions, don't fight it with inline funcs. -
qlty fmt(biome) reformats TS/CSS/JSON to tabs; run it rather than hand-formatting. -
Frontend tests: jsdom lacks
scrollIntoView(call it optionally) and store dispatches outside React needact(). -
Vitest is pinned to major 3 in
ui/package.json(^3.0.0) — fine today, but remember it's a floor choice made for install determinism, not a hard requirement.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
|