nandi/oripublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/nandi/ori.git
git clone ssh://git@rickub.com/nandi/ori.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

forked from bots-garden/ori

🛟 Updated. b6cd929Unverified · on main · k33g · 11h ago
history.md · 190 lines · 38.0 KBmarkdown
Blame HistoryOpen raw

History

2026-09-17 — Ticket 0004: ACP web client (initial implementation)

  • Goal: implement .tickets/issues/0004-specifications.yaml — a webapp (Go backend + SPA) acting as an ACP client for a code agent (Claude Code first), UI following the principles of Zed's agent panel, designed to evolve. Driven with the methodical-dev skill, all checkpoints user-approved.
  • Changes: whole codebase created — cmd/ori, cmd/ori-mock-agent, internal/{config,httpserver,agent,bridge,mockagent}, ui/ (Vite + React 19 + TS SPA with reducer/store/ws-client and panel components), Makefile, biome.json, .qlty/qlty.toml, bilingual docs/ (en+fr, Diátaxis, 7 pages each), docs/diagrams/packages.drawio, root README.md.
  • Decisions: coder/acp-go-sdk for ACP (no official Go lib exists; the claude CLI has no native ACP mode — the user initially chose "native CLI", reversed after verification, and approved the claude-code-acp adapter); ACP payloads relayed verbatim to the browser; server as single source of truth with history replay + user_message echo; one shared session in v1. Mid-session the user corrected the Go module path from github.com/bots-garden/ori to rickub.com/bots-garden/ori (repo not on GitHub) — renamed everywhere, tests green.
  • Tests: 7 config + 6 httpserver + 10 agent (in-memory mock ACP agent) + 15 bridge (incl. 4 real-WebSocket integration) + 2 mockagent + 1 full e2e (compiled mock binary, real subprocess, real WS, permission round-trip, late-joiner replay) — all green incl. -race; 28 frontend tests (reducer, ws client with fake WebSocket, components) — green. One command: make test.
  • Quality: gate PASS (0 errors / 0 warnings / 0 smells, total complexity 145; started at 13/4/5/158). Config adjustments user-approved (see summary). Two environment fights: the 488MB ~/.qlty volume (cache symlinked to main disk) and a partial JDK extraction.
  • Docs: docs/en/ + docs/fr/ complete four-quadrant sets; package diagram in draw.io; root README quick start.

2026-09-17 — Live thinking block + working spinner (same session, follow-up)

  • Goal: after testing against real Claude Code, the user asked for (1) the agent's thinking content visible live while it streams, (2) a spinner with rotating phrases while the agent works, Claude-style.
  • Changes: new ui/src/components/WorkingIndicator.tsx (spinner + workingPhrases rotating every 2.5s), ChatThread refactored with a ThoughtEntry component (live open block 💭 Thinking… while streaming, collapsible 💭 Thought for a moment once the turn ends), CSS spinner/thought-live, tutorials updated in both languages.
  • Decisions: live-vs-collapsed decided by the existing closed flag on thought items (no reducer change needed); phrases exported for deterministic tests.
  • Tests: +3 WorkingIndicator (fake timers: first phrase, rotation, wrap-around) and +2 App (thought open→collapsed across turn end; spinner present during a turn, gone after) — 33 frontend tests green, Go suite untouched.
  • Quality: gate PASS again (a first re-run flagged ThreadEntry at 6 returns; fixed by extracting ThoughtEntry).
  • Also verified this session: real Claude Code works end to end via env -u CLAUDECODE ./bin/ori (nested-session guard); adapter package renamed upstream to @agentclientprotocol/claude-agent-acp (default not changed yet).

2026-09-17 — Workspace panel: preview, editor, terminal, monospace command output (same session, follow-up 2)

  • Goal: user-requested evolutions — a preview panel (syntax-highlighted code + rendered Markdown/AsciiDoc), a terminal panel, a file editor panel (Monaco), and monospace rendering for system-command output in the chat.
  • Changes: backend internal/files (list/read/write file API, unrestricted access per user's explicit choice) and internal/terminal (PTY shell per WebSocket, creack/pty); frontend workspace layout (chat left + collapsible right panel: file tree with lazy directories, Preview/Editor/Terminal tabs kept mounted when inactive), MonacoViewer shared by read-only preview and editor (bundled workers, lazy chunk), AsciiDoc rendering via lazy @asciidoctor/core, xterm.js terminal, tool-output monospace block for execute tool calls. New deps: creack/pty, monaco-editor + @monaco-editor/react, @asciidoctor/core, @xterm/xterm + addon-fit.
  • Decisions: layout chat+workspace (user), interactive user terminal only in v1 (ACP terminals later, user), free filesystem/terminal access (user — sandbox assumed isolated), Monaco over CodeMirror (user); panes hidden not unmounted so the shell survives tab switches; monaco 0.56 import specifiers go through its exports map (no esm/vs/ prefix).
  • Tests: +9 files API, +5 terminal PTY integration (real shell over real WS: command output, cwd, resize via stty, malformed frames, exit closes socket) → 46 Go tests incl. e2e; front +5 workspace store, +4 FileTree, +8 lang detection, +6 PreviewPane, +6 EditorPane, +4 TerminalPane (xterm/WS mocked), +2 ToolCallCard mono/markdown → 66 front tests. All green, -race clean.
  • Quality: gate PASS (0/0/0, total complexity 281). Iterations: biome 1.9 rejects the noStaticElementInteractions suppression (rule doesn't exist there — removed), the dangerouslySetInnerHTML suppression must sit between JSX attributes, EditorPane/ToolContent refactored (extracted EditorHeader/editorPlaceholder/TextToolContent) to clear return/complexity smells.
  • Docs: new how-to use-the-workspace + reference workspace-api in both languages; architecture pages and indexes updated; drawio diagram extended (files, terminal, pty, SPA runtime edges); root README.

2026-09-17 — Source code analysis document (new session)

  • Goal: analyse the source code and produce a summary as an AsciiDoc document.
  • Changes: new docs/source-code-analysis.adoc — overview, backend package table, frontend module/component inventory, HTTP/WS endpoints, bridge protocol summary, test counts (55 Go tests + 1 e2e, ~215 vitest cases), Makefile targets, design decisions, known limitations. No code changed.
  • Method: read .memory/ first, then an Explore agent verified the memory picture against the sources (LOC: ~3,064 Go / ~3,252 TS-TSX).
  • Tests / quality: not run — documentation-only session, no code touched.

2026-09-17 — Workspace polish: AsciiDoc fix, VS Code-style tree with Material icons, dark terminal (same session, follow-up 3)

  • Goal: user feedback after trying the workspace — AsciiDoc preview broken in production ("m is not a function"), file tree should look like VS Code's with Material icons, terminal should always be dark.
  • Changes: AsciiDocView now uses @asciidoctor/core v4's real API — convert is a named export and asynchronous (the v3 asciidoctor() factory no longer exists; my CJS-default cast called undefined()); added a non-mocked AsciiDocView test rendering with the real converter — the mocked-only tests were exactly why the breakage reached production. FileTree restyled VS Code-like: vscode-material-icons (910 SVGs copied to ui/public/material-icons/ by ui/scripts/copy-icons.mjs, npm pre-hooks on dev/build, gitignored), chevrons, indent guides, open-folder icons, active-file highlight. Terminal always dark (#1e1e1e) whatever the app theme.
  • Tests: +2 real AsciiDoc render, +2 FileTree (icons present, active highlight) → 70 front tests, all green; Go untouched (46).
  • Quality: gate PASS.

2026-09-17 — Inline monospace for backticked commands (same session, follow-up 4)

  • Goal: user feedback — tool titles like Run `ls .memory/` showed literal backticks in a proportional font.
  • Changes: new InlineText component (backtick spans → <code class="inline-code">, no markdown pipeline), applied to tool call titles, permission titles and plan entries; .inline-code CSS.
  • Tests: +4 InlineText (spans, multiples, plain, unpaired backtick) and +1 ToolCallCard title assertion → 75 front tests green.

2026-09-17 — sbx template + kit for ori (same session, follow-up 5)

  • Goal: package ori as a Docker Sandboxes template (image k33g/ori, the user builds it under their handle) and add a kit to launch it easily from sbx.
  • Changes: template/Dockerfile (multi-stage: node builds the SPA, go builds the binaries, final layer = docker/sandbox-templates:claude-code + globally installed @zed-industries/claude-code-acp + /usr/local/bin/{ori,ori-mock-agent}, EXPOSE 8888, standalone CMD), .dockerignore (excludes the 635MB sandboxes/ checkout, node_modules, .git…), kits/ori/spec.yaml (schemaVersion 2 mixin: idempotent setup.startup launching ori as the agent user on :8888, agentInstructions), kits/ori/README.md, make template, how-to run-in-a-sandbox in docs en+fr.
  • Decisions: no sbx template build exists — a template IS a container image passed via sbx create claude --template k33g/ori, and --kit accepts a mixin directory (verified in sandboxes/docs/yml/sbx_create_claude.yaml); the ori kit adds no network permissions (Anthropic hosts come from the claude agent kit, the adapter is baked into the image); kit startup guarded by pgrep -x ori because startup commands re-run on every container start.
  • Tests/validation: image built locally (2.81GB) and smoke-tested standalone with the mock agent (healthz + session OK); the kit's exact startup command exec'd in a sleeping container of the image → adapter session created, healthz OK; idempotency check OK; kit YAML parse-validated.

2026-09-17 — Kit refinements from the sbx source deep-dive (same session, follow-up 5b)

  • A thorough exploration of the sbx source confirmed the template/kit design and yielded three refinements applied to kits/ori/spec.yaml: requires: {agent: claude} (mixin-only field, enforces composition with the claude agent kit), a ports: block (container 8888 — kits auto-publish an ephemeral localhost port at create; Dockerfile EXPOSE is read by nothing), and dropping user: "agent" from the startup step (StartupCommand.user defaults to "1000", the agent uid; "agent" is non-standard).
  • Also learned and documented: sandboxd has its own image store — a never-pushed local image reaches it via docker save + sbx template load; kit references resolve fresh each create (no local kit registry); sbx kit validate/pack/push exist for distribution; an alternative shape (kind:sandbox + extends: claude + sandbox.image: k33g/ori) would allow sbx create ./kits/ori . in one argument — not adopted, the mixin matches the dev-toolkit pattern already in use.

2026-09-17 — build.sh, Hub publication at 0.0.0, parameterized kit port, quickstart (same session, follow-up 5c)

  • Goal: user wants to push k33g/ori to Docker Hub — a template/build.sh they run themselves, image tagged 0.0.0; the kit's listen port made configurable; a quickstart.md with the sandbox-creation commands.
  • Changes: template/build.sh (multi-arch buildx --push, tags 0.0.0 + latest, VERSION as $1, PLATFORMS overridable); kits/ori/spec.yaml gained args.port (default "8888", pattern-validated) substituted into ports.container (unquoted ${{ kit.args.port }} — the source's expand.go explicitly re-infers it as an integer), the startup --addr, and the agentInstructions; quickstart.md at the repo root; kit README and both run-in-a-sandbox pages now reference k33g/ori:0.0.0 and --kit-arg ori.port=.
  • Validation: spec YAML parses with the arg refs; build.sh is the push path, make template stays the local-only path. The actual Hub push is the user's action (their Docker login).

2026-09-17 — Multi-arch build fix: no qemu in the template build (same session, follow-up 5d)

  • Problem: the user's ./template/build.sh failed on the linux/amd64 half — on an arm64 host that stage runs under qemu, where Vite bundling Monaco exhausts Node's 2GB heap ("FATAL ERROR: Ineffective mark-compacts near heap limit", "qemu: uncaught target signal 6").
  • Fix: every build stage now runs on --platform=$BUILDPLATFORM: the SPA build is platform-independent (built once, natively), Go cross-compiles with GOOS=$TARGETOS GOARCH=$TARGETARCH, and the ACP adapter is npm-installed in a native stage then COPY'd into the template's npm prefix (/usr/local/share/npm-global, agent-owned, on PATH). The final stage contains no RUN at all, so a multi-arch build never invokes qemu.
  • Validation: native rebuild green; smoke tests pass (healthz with mock agent; claude-code-acp resolves from the copied prefix and initializes a real ACP session).

2026-09-17 — Kit startup fix: su resets PATH (same session, follow-up 5e)

  • Problem: the user's real sbx create … --kit ./kits/ori -p 5555:8888 came up with nothing listening. Root cause read from the sbx source (sandboxlib/kit/durable_startup.go): startup commands are rendered as exec su -s /bin/sh -c '<script>' agent, and util-linux su always resets PATH to the login.defs default — which lacks /usr/local/share/npm-global/bin, so ori died instantly with "claude-code-acp: executable file not found". Reproduced in the image (su -c 'command -v claude-code-acp' agent → missing); my earlier validation had used docker exec, which preserves image ENV — that's why it passed.
  • Fix: the kit's startup script now exports PATH="/usr/local/share/npm-global/bin:/home/agent/.local/bin:$PATH" first (comment marks it load-bearing). Re-validated through the exact su path: healthz OK, ACP session created.
  • No image rebuild needed — kit-side only; the user must sbx rm and recreate the sandbox for the new kit to apply. Debug window for kit startup: /var/log/sbx-kit-startup.log (dispatcher log) + /home/agent/.ori.log.

2026-09-17 — Session end inside the sandbox: WS-offline investigation in flight (follow-up 5f)

  • After the su-PATH fix, the user's sandbox serves the SPA on localhost:5555 but the UI shows "offline" (the WebSocket to /ws does not stay up). Established before stopping: ori's WS handshake is correct against browser-like Origin headers (101 for localhost:* origins, 403 for foreign — tested with curl against the image); sbx port publishing goes through gvisor's port mapper (raw L4, so the upgrade should pass). Three discriminating diagnostics were handed to the user (server log; WS handshake from inside the sandbox; WS handshake through the forward) — answers not yet received. The session ends here: the user is relaunching the assistant outside sbx.
  • Everything since commit 2434cc7 is still uncommitted (user's call, repeatedly deferred).

2026-09-17 — Why the ori sandbox stops on its own: sbx auto-stop investigation (follow-up 6, read-only)

  • Asked: the sandbox created with sbx create claude . --template k33g/ori:0.0.0 --kit ./kits/ori --name ori -p 8888:8888 serves the webapp then goes stopped by itself; find the auto-stop mode in the sbx source and a way to disable it.
  • Found (in sandboxes/, the vendored sbx checkout, v0.43.0 daemon on this Mac): sandboxd counts "sentinel" long-poll sessions per sandbox (GET /sandbox/{name}/session, holdSession in sandboxd/pkg/server/backend_dockernext.go); when the count hits zero it stops the container after a hard-coded 30 s grace (WithAutoStopDelay(30*time.Second) in setupDockerNextBackend). sbx create holds a sentinel only for its own lifetime (executeCreateAndReleaseSession in cli-plugin/commands/create.go), so the stop fires 30 s after the command returns — confirmed by the daemon log (session disconnected, deferring auto-stopauto-stopped runtime 30 s later for ori and ori2). Port publishing and browser traffic hold no session.
  • Escape hatch: the create-time spec field detached: true (openapi SandboxCreateRequest.detached) makes holdSession never auto-stop. Only sbx run -d/--detached sets it (create_daemon.go: Detached: opts.detached); sbx create has no such flag; there is no update API, no sbx settings key and no env var for the delay.
  • Recommendation given: sbx rm ori then sbx run -d claude . --template k33g/ori:0.0.0 --kit ./kits/ori --name ori -p 8888:8888.
  • Docs switched (same session, at the user's request while they tested): quickstart.md, kits/ori/README.md, docs/en|fr/how-to/run-in-a-sandbox.md now use sbx run -d, explain the 30 s auto-stop and why detached is the fix, and add a restart line (sbx run -d --name <name>) plus a daemon-log diagnostic hint. No sbx create invocation remains in project docs. No code change.
  • Also observed: the WS-"offline" symptom from follow-up 5f is very plausibly this same stop (the page was already loaded when the container died), still to be confirmed by the user.

2026-09-17 — Three parallel agents: ori-desktop (Wails), @/skill selectors + draw.io/image previews, ACP command inventory

  • Asked: (bob) create ori-desktop/, a Wails app connecting to the ori webapp; (riker) add an @ file selector, a skill selector, draw.io and image previews; (milo, read-only) list the ACP commands exposed. Then the user built ori-desktop on their Mac: Check OK, Connect "did nothing".
  • bob: new module ori-desktop/ (Wails v2.16.0, plain template, iframe embed of the ori SPA, settings JSON, bound methods, internal/settings + internal/health with 12 tests, EN+FR READMEs, make desktop/desktop-test, .gitignore, ticket 0005 filled). Verified: tests, vet, gofmt, Windows cross-build, root make build/make test unaffected. Not verifiable in the sandbox: running the window (no gcc/webkit2gtk).
  • riker: GET /api/files/search, GET /api/raw, new internal/skills + GET /api/skills; prompt.attachments → ACP resource_link blocks (Prompter.Prompt(blocks) replaces PromptText, Bridge.SetWorkspaceRoot); reducer stores available_commands_update commands; mentions.ts, useCompletion.ts, CompletionPopup, rewritten PromptInput, ImageView, DrawioView (embed.diagrams.net + Source fallback), lang.ts kinds image/drawio; mock agent emits commands and echoes attachments; Vite dev proxy gained /api; biome format --write reformatted 11 files. Docs EN+FR: workspace-api, websocket-protocol, use-the-workspace, new how-to mention-files-and-skills, architecture sections, READMEs. Tickets 0008/0009/0011/0012 filled.
  • milo: ori calls initialize, session/new, session/prompt, session/cancel; serves session/update, session/request_permission, fs/read_text_file, fs/write_text_file; refuses terminal/*; unused stable methods: authenticate, logout, session/load|resume|list|close|set_mode|set_config_option. "Agent commands" are not ACP methods: available_commands_update/name text in the prompt. Relayed to riker, who implemented it (ticket 0008).
  • Bug fixed after the user's test: ori-desktop/frontend/src/main.css#connect-screen {display:grid} outranked .screen[hidden], so Connect (and the startup auto-connect) rendered the viewer below the fold; now class .connect + .screen[hidden] {display:none !important}. Rebuild needed (wails build); iframe content in WKWebView still unconfirmed.
  • Tests: make test → 9 Go packages ok, vitest 16 files / 102 tests (was 66); go test -race ./... ok (riker installed gcc + libc6-dev via apt in the sandbox for it).
  • Quality gate: NOT run — qlty absent from this sandbox (~/.qlty missing). gofmt / go vet / biome check clean.
  • Nothing committed (still everything since 2434cc7).

2026-09-17 — Launch ori for manual testing of the new features (evening session)

  • Asked: "lance ori que je puisse tester les nouveautés". No code change: make build (SPA + binaries), then env -u CLAUDECODE nohup ./bin/ori --addr 0.0.0.0:8888 > /tmp/ori.log 2>&1 & inside the claude-ori sandbox. Adapter @zed-industries/claude-code-acp@0.16.2 resolved via npx (npm now flags it deprecated → renamed @agentclientprotocol/claude-agent-acp; still works). ACP session ready, /healthz ok, /api/skills lists the skills. Port 8888 must be published on the host with sbx ports claude-ori --publish 8888:8888/tcp (not doable from inside the sandbox).
  • Trap hit: a curl WebSocket handshake against /ws never returns on success (101 keeps the socket open) — use -m or check the log instead.
  • Follow-up (same session): first real prompt failed with -32603 There's an issue with the selected model (fable[1m]). Root cause: @zed-industries/claude-code-acp@0.16.2 bundles @anthropic-ai/claude-agent-sdk@0.2.44, whose embedded Claude Code CLI is 2.1.44 (zero mentions of Fable), while ~/.claude/settings.json sets "model": "fable[1m]" and the adapter forwards it verbatim. The system CLI (2.1.275) accepts fable[1m] fine. Fix without touching the user's settings: the adapter honours CLAUDE_CODE_EXECUTABLEpathToClaudeCodeExecutable; ori relaunched with CLAUDE_CODE_EXECUTABLE=/home/agent/.local/share/claude/versions/2.1.275; a WS prompt round-trip returned pong (turn_ended end_turn). No code change.

2026-09-17 — Resizable file explorer column (ticket 0015), via methodical-dev

  • Goal: make the workspace file tree column resizable with the mouse; user chose localStorage persistence and the file-tree divider only (not the chat/workspace split).
  • Changes: ui/src/workspace.ts (fileTreeWidth, setFileTreeWidth, resetFileTreeWidth, clampFileTreeWidth, constants, guarded localStorage), new ui/src/components/ResizeHandle.tsx (+ test), Workspace.tsx (handle between tree and tabs, --filetree-width on the aside; new Workspace.test.tsx), app.css (.filetree width from the variable, .resize-handle styles). Ticket 0015 closed.
  • Decisions: width in px (drag produces px; comparable with bounds); FileTree untouched — width reaches CSS via a custom property; handle owns no width, the store clamps. jsdom 26 has no PointerEvent → test-local MouseEvent polyfill.
  • Quality gate (first run of qlty on the tree since the parallel-agents session): 12 errors / 1 warning / 2 smells, all pre-existing — fixed without weakening anything: ori-desktop/frontend/src/main.js became an ES module (type="module", IIFE and "use strict" dropped, optional chains, template literals, reloadFrame() instead of src = src), internal/files/raw.go explicit _ = file.Close() with rationale, internal/files/search.go walk callback → searchWalker.visit/visitDir/collect, PreviewPane.tsx loading effect → usePreviewFile hook; qlty fmt on main.css / main.js / wails.json. Run #15 PASS (0/0/0, complex 507).
  • Tests: 118 vitest (18 files), 9 Go packages, ori-desktop 2 packages — green. make test.
  • Docs: how-to use-the-workspace (step 5 + keyboard/persistence variant) and architecture explanation, EN + FR; root README; ori-desktop READMEs (ES module).
  • Not verifiable here: the ori-desktop frontend change (ES module) needs a wails build + launch on the user's Mac.

2026-09-17 — Light / dark theme selector, light by default (ticket 0013)

  • Goal: user request received mid-session; choices made via AskUserQuestion: two themes only (no "system" option), single review at the end.
  • Changes: new ui/src/theme.ts (+ theme.test.ts), app.css (dark palette on :root[data-theme="dark"], color-scheme per theme, .topbar-theme), App.tsx (☾/☀ button, aria-label "Switch to dark/light theme"), MonacoViewer.tsx (store instead of matchMedia), main.tsx (side-effect import so the theme is stamped before the first render), App.test.tsx (+1). Ticket 0013 closed.
  • Decisions: dropping prefers-color-scheme is a behaviour change (dark-OS users now get light until they toggle) — accepted by the user ("light par défaut"); documented in the architecture explanation. Terminal keeps its dark background (pre-existing decision).
  • Tests: 124 vitest / 19 files green; Go untouched. Quality: run #16 PASS (0/0/0, complex 514).
  • Docs: new how-to switch-the-theme.md EN + FR, both indexes, architecture explanation paragraph EN + FR, root README.
  • ori rebuilt and restarted on :8888 for the user's review.

2026-09-17 — Commit and merge into main

  • User asked to merge feat/acp-webapp into main. Everything since 2434cc7 committed as 76d62ac (203 files, +21 595 lines), excluding hello.md (test artefact) and .claude/settings.local.json (local permissions). main fast-forwarded (merge base was 4edda86, no divergence). Not pushed to origin (git.rickub.com) — not asked. This memory update itself is a follow-up commit on main.

2026-09-18 — Diagnose git push --set-upstream origin main hanging

  • Asked: why the first push to origin never finishes. Diagnostic only; no code or config changed.
  • Finding: origin is https://git.rickub.com/bots-garden/ori.git; the server answers 401 on git-receive-pack, the macOS keychain has no entry for that host, and the session (launched from VSCodium's terminal) exports GIT_ASKPASS → VSCodium's askpass.sh. Git therefore hands the password prompt to VSCodium's input box, which is easy to miss, so the push waits forever. Confirmed with ps: git-remote-httpsaskpass.sh "Password for 'https://git.rickub.com'" blocked.
  • Also verified: network fine (DNS, 443, 22 all open); anonymous read over HTTPS works; SSH key ~/.ssh/id_ed25519 is accepted by git@git.rickub.com (server replies "serves git only"); git ls-remote over SSH succeeds and shows the remote repo is empty (no branches yet). Local main = 34e69b5.
  • Recommendation left to the user: switch origin to git@git.rickub.com:bots-garden/ori.git (no password, key already trusted), or run the push in a plain terminal with GIT_ASKPASS unset so osxkeychain stores the credentials. Not applied — awaiting the user's choice.

2026-09-18 — AppleScript launcher for the ori sandbox + desktop app

  • Asked: an AppleScript that runs sbx run -d claude . --template k33g/ori:0.0.1 --kit ./kits/ori --name ori -p 5555:8888 then launches ori-desktop/build/bin/ori-desktop.app.
  • Changes: new scripts/launch-ori.applescript; one row in quickstart.md (everyday commands); pointer in summary.md.
  • Decisions: (1) if sbx ls -q already lists ori, restart it with sbx run -d --name ori instead of re-running the create command (which would collide on the name); errors on that path only notify, the health check decides. (2) Poll /healthz on :5555 (2 s × 45) before opening the app, because the kit starts the server asynchronously and the desktop app auto-connects to the saved URL (~/Library/Application Support/ori-desktop/settings.json already holds http://localhost:5555). (3) PATH exported explicitly (Finder launches lack /opt/homebrew/bin). (4) Repo root derived from path to me so the compiled .app works from scripts/ too. Rejected: sbx rm + recreate on every launch (destroys the sandbox's Claude session/state).
  • Tests: osacompile OK; handlers exercised via load script: sandboxExists → false with no sandbox, waitForServer → false on a closed port, true against a throw-away Python /healthz on :5555. Not run end to end (would create a real sandbox and start Claude in it). Quality gate not re-run (no Go/TS touched).

2026-09-18 — Ticket 0005 back to the IssueSpec task schema; launcher compiled as an app

  • Asked: "le ticket 0005 n'est plus au bon format"; then how to make the AppleScript launcher double-clickable.
  • Cause: the 0005 checklist had been hand-written as - text: … / done: true|false, which is not IssueSpec's task shape (id, title, state, priority, author, createdAt, optional updatedAt/closedAt). IssueSpec's parser rejects the file: "tasks[0].id must be a positive integer".
  • Changes: .tickets/issues/0005-….yaml — 8 tasks rewritten (7 closed with updatedAt/closedAt = 2026-09-17T22:23:39Z, 1 open; all priority: none, author k33g); issue updatedAt bumped. scripts/Launch Ori.app built with osacompile, ignored via .gitignore (scripts/*.app/). summary.md gains a .tickets paragraph.
  • Verification: bundled IssueSpec's parseIssueDocument (from the local clone ~/CodeBerg/issuespec, esbuild --format=cjs) and ran it over all 15 tickets: all OK; the committed 0005 fails as expected.
  • Follow-up: scripts/README.md + scripts/README.fr.md written (what the launcher does, run vs. double-click, design choices, handler test recipe); quickstart row now points to it.

2026-09-18 — sbx kit package does not exist

  • User hit ERROR: sbx: unknown command: sbx kit package (sbx v0.43.0). The verbs are sbx kit pack DIRECTORY [-o file.zip] (local ZIP) and sbx kit push DIRECTORY registry/repo:tag (package + push to OCI, adds SLSA provenance, --sign optional). Both take the kit directory, not spec.yaml. sbx kit validate kits/ori → VALID. Not pushed: publishing to Docker Hub left to the user.

2026-09-18 — sbx kit push rejected the kit: arg placeholder in an integer field

  • Asked: sbx kit push kits/ori docker.io/k33g/ori-kit:latest failed with invalid spec.yaml: line 38: cannot unmarshal !!str ${{ kit... into int.
  • Cause (verified in sandboxes/ source, v0.44.0-rc1+26, and by trial): Pack/Push call LoadFromDirectory → strict typed decode of the raw spec (ports[].container is int), with no ${{ kit.args.* }} expansion; validate/inspect/run expand first (expand.go, argScan), hence VALID vs INVALID for the same directory. v3 kits (schemaVersion: "3", com.docker.runtime/port@1 capabilities) keep placeholders at push and expand at pull, but the installed sbx v0.43.0 has no v3 support (0 hits for the capability type in the binary).
  • Changes: kits/ori/spec.yaml ports[0].container → literal 8888 with a comment explaining why; ${{ kit.args.port }} kept in the startup command and agentInstructions (string fields decode fine). Kit README, docs EN/FR how-to run-in-a-sandbox: with a custom port, publish it with -p since the declared port stays 8888. Rejected: dropping the port arg (loses a documented feature); moving to v3 (needs sbx ≥ 0.44 on every consumer).
  • Verification: sbx kit validate kits/ori (default and --kit-arg ori.port=9000) VALID; sbx kit pack kits/ori OK; inspect --kit-arg ori.port=9000 shows --addr ":9000" substituted with "container": 8888. Push not run — the user publishes.
  • Follow-up: kit published by the user; sbx kit inspect docker.io/k33g/ori-kit:latest resolves (mixin, schema v2, 1 port, 1 startup command). Sandboxes running at that time: ori (5555→8888) and hello-ori (3000→8888), both on this repo.

2026-09-18 — "Claude Code 2.1.44 does not support this model; 2.1.251 or newer required"

  • Asked: reminder of what to do to avoid this prompt failure in the sandbox (kit docker.io/k33g/ori-kit:latest, template k33g/ori:0.0.1).
  • Diagnosis (read-only, verified): ori in sandbox ori runs with no CLAUDE_CODE_EXECUTABLE, so the Zed adapter 0.16.2 uses its bundled CLI 2.1.44 (SDK 0.2.44). The model comes from the host ~/.claude/settings.json (claude-fable-5-1[1m]), which the API only serves to CLI ≥ 2.1.251. Yesterday's workaround (point the adapter at the template's system CLI) no longer suffices: the base image docker/sandbox-templates:claude-code (built 2026-08-26) ships CLI 2.1.246. Sandbox egress reaches the Claude Code release bucket (latest = 2.1.276) and npm, so claude update inside is feasible. @agentclientprotocol/claude-agent-acp@0.79.0 (bin claude-agent-acp) depends on @anthropic-ai/claude-agent-sdk@0.3.274, whose manifest.json says CLI 2.1.274, delivered through per-platform optional deps (…-sdk-linux-arm64, …-linux-x64, …) — no cli.js any more.
  • Nothing changed: options given to the user (immediate: claude update in the sandbox + restart ori with CLAUDE_CODE_EXECUTABLE; permanent: switch the template to the new adapter, or bake a recent CLI + the env var into template/kit). Their call.

2026-09-18 — Switch the ACP adapter to @agentclientprotocol/claude-agent-acp (template 0.0.2), Node 25 test fix, MIME pin

  • Goal: option 1 of the "Claude Code 2.1.44 too old" diagnosis, approved by the user: stop depending on the Zed adapter's embedded CLI; rebuild template 0.0.2; republish the kit. Worked on feature/copy-paste-functionality (user's choice), commit 5d476ff, fast-forwarded into main; this memory update is a follow-up commit on main.
  • Changes: internal/config/config.go DefaultAgentCommandnpx -y @agentclientprotocol/claude-agent-acp (+ TestDefaultAgentCommandIsClaudeAgentACP); doc comments in internal/agent/agent.go, cmd/ori/main.go. template/Dockerfile: adapter stage installs the new adapter with npm install --os=linux --cpu=$npm_cpu, Docker's amd64 mapped to npm's x64 (with --cpu=amd64 npm silently installs no native SDK), and asserts claude-agent-sdk-linux-<cpu> exists; CMD --agent-cmd claude-agent-acp. kits/ori/spec.yaml: startup + agentInstructions → claude-agent-acp, template 0.0.2. internal/files/raw.go: textTypes pins .md/.markdowntext/markdown; charset=utf-8 (Go's mime table comes from the host; macOS leaves text/markdown commented out, so TestRawAcceptsAbsolutePathsLikeTheOtherEndpoints failed on the Mac) + 2 table cases. ui/package.json test script gains NODE_OPTIONS=--no-experimental-webstorage. ui/src/components/Markdown.tsx: React.ReactElement<{ children?: unknown }> cast — the copy-paste commit did not compile (TS2339 ×3) and blocked docker build. ui/src/components/ToolCallCard.tsx: copy text extracted into pure contentText / toolContentText (+5 tests), clearing two function-complexity smells. .qlty/qlty.toml: golangci-lint pinned 2.13.2. Docs EN+FR (architecture explanation, how-to run-with-claude-code / run-in-a-sandbox / run-the-tests, reference cli), docs/diagrams/packages.drawio, docs/source-code-analysis.adoc, kit README, root README, quickstart, scripts/launch-ori.applescript (0.0.2, /tcp, converted back from UTF-16) + its READMEs.
  • Decisions: (1) new adapter over "bake claude update + CLAUDE_CODE_EXECUTABLE": the SDK ships a current CLI per platform, no version chasing. (2) adapter stage stays --platform=$BUILDPLATFORM (native npm) and targets the CPU explicitly, instead of npm under qemu. (3) Backend default changed too (user: "backend + template") so make run gets the same fix. (4) Pre-existing failures fixed along the way with the user's explicit OK: MIME test, Node 25, Markdown.tsx types, ToolCallCard complexity. (5) Left untracked as the user's artefacts/memos: kits/.backup/, demo/ (the three prompt-generated stories the user moved there — their root copies are deleted in 5d476ff), kits/ori/publish.kit.md, template/publish.template.md.
  • Verification: go vet ./... && go test ./... green; ui tsc -b + 134 vitest green; docker build --check clean; arm64 image built locally — claude-agent-acp resolves for root and via su … agent, native SDK linux-arm64 with the 230 MB CLI, manifest 2.1.274, ACP initialize answered by adapter 0.79.0, Zed adapter gone; amd64 install verified in a node:24 container (-linux-x64 present). Test sandbox ori-acp (image via sbx template load) served ori with CLI 2.1.274; the user pushed k33g/ori:0.0.2 (multi-arch) and confirmed a real prompt in sandbox hello-world after the kit re-push. Quality: run #18 PASS (0/0/0, complex 532) after repairing qlty on the Mac (dangling .qlty/* symlinks from the sandbox; golangci-lint too old for Go 1.26).
  • Docs: as listed, EN + FR in sync. diataxis-doc skill not invoked: edits to existing pages, done directly.

2026-09-18 — Linux build of ori-desktop (webkit2gtk-4.1) + MIT LICENSE

  • Asked: cd ori-desktop && wails build; then, mid-session, "ajoute un fichier de licence MIT".
  • Build: installed the Wails CLI (go install …/cmd/wails@v2.16.0) and the GUI toolchain (sudo apt-get install libgtk-3-dev libwebkit2gtk-4.1-dev) in the sandbox — they were absent, which is why the window had never been launched here. Plain wails build fails: Wails' cgo pkg-config asks for webkit2gtk-4.0, Ubuntu 26.04 only ships 4.1. wails build -tags webkit2_41build/bin/ori-desktop, ELF aarch64, 9.4 MB, 4.8 s. wails doctor still says libwebkit: Not Found (it only probes 4.0) — a false negative. No source change was needed.
  • Not done: no macOS build — Wails cannot cross-compile to macOS from Linux, and the .app the user actually launches (build/bin/ori-desktop.app, and the AppleScript launcher) must still be built on the Mac. The Linux binary was added next to the existing .app and .exe, overwriting neither. The window itself was not run (no display in the sandbox).
  • Changes: LICENSE (MIT, Copyright (c) 2026 k33g) at the repository root — the only file added to the tree; build/bin/ and frontend/wailsjs/ are gitignored. .memory/summary.md: the -tags webkit2_41 requirement and the three build outputs on the ori-desktop/ bullet, the apt/CLI install recipe under "Environment facts", the licence line.
  • Decisions: holder k33g (the name used by every ticket author block and the git identity), not a guessed legal name. Root-only LICENSE, no copy under ori-desktop/ despite it being a separate Go module. make desktop left untouched even though it fails on Linux for want of the tag — a Makefile change was outside what was asked; flagged to the user instead.
  • Verification: go test ./internal/... in ori-desktop green (health, settings). Quality gate not re-run: no Go/TS source was modified.
  • Follow-up (same session): ori-desktop/how-to-build.md written on request — prerequisites, the from-where/to-what cross-build matrix (macOS only from macOS; Windows from anywhere; Linux from Linux), one section per platform, the wails build flags that matter, wails dev, the tests, and a troubleshooting list (webkit 4.0 vs 4.1, the wails doctor false negative, make desktop on Linux, the lost execute bit under cloud sync, Gatekeeper/xattr -cr, empty window = no server). English only, house Diátaxis how-to style; how-to-build.fr.md NOT written and README.md NOT linked to it — the user's own edits to ori-desktop/README*.md are uncommitted in the tree and were left alone. All four relative links in the doc were checked to resolve.
  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
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# History

## 2026-09-17 — Ticket 0004: ACP web client (initial implementation)

- **Goal**: implement `.tickets/issues/0004-specifications.yaml` — a webapp (Go backend + SPA) acting as an ACP client for a code agent (Claude Code first), UI following the principles of Zed's agent panel, designed to evolve. Driven with the `methodical-dev` skill, all checkpoints user-approved.
- **Changes**: whole codebase created — `cmd/ori`, `cmd/ori-mock-agent`, `internal/{config,httpserver,agent,bridge,mockagent}`, `ui/` (Vite + React 19 + TS SPA with reducer/store/ws-client and panel components), `Makefile`, `biome.json`, `.qlty/qlty.toml`, bilingual `docs/` (en+fr, Diátaxis, 7 pages each), `docs/diagrams/packages.drawio`, root `README.md`.
- **Decisions**: `coder/acp-go-sdk` for ACP (no official Go lib exists; the claude CLI has no native ACP mode — the user initially chose "native CLI", reversed after verification, and approved the `claude-code-acp` adapter); ACP payloads relayed verbatim to the browser; server as single source of truth with history replay + `user_message` echo; one shared session in v1. Mid-session the user corrected the Go module path from `github.com/bots-garden/ori` to `rickub.com/bots-garden/ori` (repo not on GitHub) — renamed everywhere, tests green.
- **Tests**: 7 config + 6 httpserver + 10 agent (in-memory mock ACP agent) + 15 bridge (incl. 4 real-WebSocket integration) + 2 mockagent + 1 full e2e (compiled mock binary, real subprocess, real WS, permission round-trip, late-joiner replay) — all green incl. `-race`; 28 frontend tests (reducer, ws client with fake WebSocket, components) — green. One command: `make test`.
- **Quality**: gate **PASS** (0 errors / 0 warnings / 0 smells, total complexity 145; started at 13/4/5/158). Config adjustments user-approved (see summary). Two environment fights: the 488MB `~/.qlty` volume (cache symlinked to main disk) and a partial JDK extraction.
- **Docs**: `docs/en/` + `docs/fr/` complete four-quadrant sets; package diagram in draw.io; root README quick start.

## 2026-09-17 — Live thinking block + working spinner (same session, follow-up)

- **Goal**: after testing against real Claude Code, the user asked for (1) the agent's thinking content visible live while it streams, (2) a spinner with rotating phrases while the agent works, Claude-style.
- **Changes**: new `ui/src/components/WorkingIndicator.tsx` (spinner + `workingPhrases` rotating every 2.5s), `ChatThread` refactored with a `ThoughtEntry` component (live open block `💭 Thinking…` while streaming, collapsible `💭 Thought for a moment` once the turn ends), CSS spinner/thought-live, tutorials updated in both languages.
- **Decisions**: live-vs-collapsed decided by the existing `closed` flag on thought items (no reducer change needed); phrases exported for deterministic tests.
- **Tests**: +3 WorkingIndicator (fake timers: first phrase, rotation, wrap-around) and +2 App (thought open→collapsed across turn end; spinner present during a turn, gone after) — 33 frontend tests green, Go suite untouched.
- **Quality**: gate PASS again (a first re-run flagged `ThreadEntry` at 6 returns; fixed by extracting `ThoughtEntry`).
- **Also verified this session**: real Claude Code works end to end via `env -u CLAUDECODE ./bin/ori` (nested-session guard); adapter package renamed upstream to `@agentclientprotocol/claude-agent-acp` (default not changed yet).

## 2026-09-17 — Workspace panel: preview, editor, terminal, monospace command output (same session, follow-up 2)

- **Goal**: user-requested evolutions — a preview panel (syntax-highlighted code + rendered Markdown/AsciiDoc), a terminal panel, a file editor panel (Monaco), and monospace rendering for system-command output in the chat.
- **Changes**: backend `internal/files` (list/read/write file API, unrestricted access per user's explicit choice) and `internal/terminal` (PTY shell per WebSocket, creack/pty); frontend workspace layout (chat left + collapsible right panel: file tree with lazy directories, Preview/Editor/Terminal tabs kept mounted when inactive), `MonacoViewer` shared by read-only preview and editor (bundled workers, lazy chunk), AsciiDoc rendering via lazy `@asciidoctor/core`, xterm.js terminal, `tool-output` monospace block for `execute` tool calls. New deps: creack/pty, monaco-editor + @monaco-editor/react, @asciidoctor/core, @xterm/xterm + addon-fit.
- **Decisions**: layout chat+workspace (user), interactive user terminal only in v1 (ACP terminals later, user), free filesystem/terminal access (user — sandbox assumed isolated), Monaco over CodeMirror (user); panes hidden not unmounted so the shell survives tab switches; monaco 0.56 import specifiers go through its exports map (no `esm/vs/` prefix).
- **Tests**: +9 files API, +5 terminal PTY integration (real shell over real WS: command output, cwd, resize via stty, malformed frames, exit closes socket) → 46 Go tests incl. e2e; front +5 workspace store, +4 FileTree, +8 lang detection, +6 PreviewPane, +6 EditorPane, +4 TerminalPane (xterm/WS mocked), +2 ToolCallCard mono/markdown → 66 front tests. All green, `-race` clean.
- **Quality**: gate PASS (0/0/0, total complexity 281). Iterations: biome 1.9 rejects the `noStaticElementInteractions` suppression (rule doesn't exist there — removed), the dangerouslySetInnerHTML suppression must sit between JSX attributes, EditorPane/ToolContent refactored (extracted EditorHeader/editorPlaceholder/TextToolContent) to clear return/complexity smells.
- **Docs**: new how-to `use-the-workspace` + reference `workspace-api` in both languages; architecture pages and indexes updated; drawio diagram extended (files, terminal, pty, SPA runtime edges); root README.

## 2026-09-17 — Source code analysis document (new session)

- **Goal**: analyse the source code and produce a summary as an AsciiDoc document.
- **Changes**: new `docs/source-code-analysis.adoc` — overview, backend package table, frontend module/component inventory, HTTP/WS endpoints, bridge protocol summary, test counts (55 Go tests + 1 e2e, ~215 vitest cases), Makefile targets, design decisions, known limitations. No code changed.
- **Method**: read `.memory/` first, then an Explore agent verified the memory picture against the sources (LOC: ~3,064 Go / ~3,252 TS-TSX).
- **Tests / quality**: not run — documentation-only session, no code touched.

## 2026-09-17 — Workspace polish: AsciiDoc fix, VS Code-style tree with Material icons, dark terminal (same session, follow-up 3)

- **Goal**: user feedback after trying the workspace — AsciiDoc preview broken in production ("m is not a function"), file tree should look like VS Code's with Material icons, terminal should always be dark.
- **Changes**: AsciiDocView now uses @asciidoctor/core v4's real API — `convert` is a **named export and asynchronous** (the v3 `asciidoctor()` factory no longer exists; my CJS-default cast called `undefined()`); added a **non-mocked** AsciiDocView test rendering with the real converter — the mocked-only tests were exactly why the breakage reached production. FileTree restyled VS Code-like: `vscode-material-icons` (910 SVGs copied to `ui/public/material-icons/` by `ui/scripts/copy-icons.mjs`, npm pre-hooks on dev/build, gitignored), chevrons, indent guides, open-folder icons, active-file highlight. Terminal always dark (`#1e1e1e`) whatever the app theme.
- **Tests**: +2 real AsciiDoc render, +2 FileTree (icons present, active highlight) → 70 front tests, all green; Go untouched (46).
- **Quality**: gate PASS.

## 2026-09-17 — Inline monospace for backticked commands (same session, follow-up 4)

- **Goal**: user feedback — tool titles like ``Run `ls .memory/` `` showed literal backticks in a proportional font.
- **Changes**: new `InlineText` component (backtick spans → `<code class="inline-code">`, no markdown pipeline), applied to tool call titles, permission titles and plan entries; `.inline-code` CSS.
- **Tests**: +4 InlineText (spans, multiples, plain, unpaired backtick) and +1 ToolCallCard title assertion → 75 front tests green.

## 2026-09-17 — sbx template + kit for ori (same session, follow-up 5)

- **Goal**: package ori as a Docker Sandboxes template (image `k33g/ori`, the user builds it under their handle) and add a kit to launch it easily from sbx.
- **Changes**: `template/Dockerfile` (multi-stage: node builds the SPA, go builds the binaries, final layer = `docker/sandbox-templates:claude-code` + globally installed `@zed-industries/claude-code-acp` + `/usr/local/bin/{ori,ori-mock-agent}`, EXPOSE 8888, standalone CMD), `.dockerignore` (excludes the 635MB `sandboxes/` checkout, node_modules, .git…), `kits/ori/spec.yaml` (schemaVersion 2 mixin: idempotent `setup.startup` launching ori as the agent user on :8888, agentInstructions), `kits/ori/README.md`, `make template`, how-to `run-in-a-sandbox` in docs en+fr.
- **Decisions**: no `sbx template build` exists — a template IS a container image passed via `sbx create claude --template k33g/ori`, and `--kit` accepts a mixin directory (verified in `sandboxes/docs/yml/sbx_create_claude.yaml`); the ori kit adds no network permissions (Anthropic hosts come from the claude agent kit, the adapter is baked into the image); kit startup guarded by `pgrep -x ori` because startup commands re-run on every container start.
- **Tests/validation**: image built locally (2.81GB) and smoke-tested standalone with the mock agent (healthz + session OK); the kit's exact startup command exec'd in a sleeping container of the image → adapter session created, healthz OK; idempotency check OK; kit YAML parse-validated.

## 2026-09-17 — Kit refinements from the sbx source deep-dive (same session, follow-up 5b)

- A thorough exploration of the sbx source confirmed the template/kit design and yielded three refinements applied to `kits/ori/spec.yaml`: `requires: {agent: claude}` (mixin-only field, enforces composition with the claude agent kit), a `ports:` block (container 8888 — kits auto-publish an ephemeral localhost port at create; Dockerfile EXPOSE is read by nothing), and dropping `user: "agent"` from the startup step (StartupCommand.user defaults to "1000", the agent uid; "agent" is non-standard).
- Also learned and documented: sandboxd has its own image store — a never-pushed local image reaches it via `docker save` + `sbx template load`; kit references resolve fresh each create (no local kit registry); `sbx kit validate/pack/push` exist for distribution; an alternative shape (kind:sandbox + `extends: claude` + `sandbox.image: k33g/ori`) would allow `sbx create ./kits/ori .` in one argument — not adopted, the mixin matches the dev-toolkit pattern already in use.

## 2026-09-17 — build.sh, Hub publication at 0.0.0, parameterized kit port, quickstart (same session, follow-up 5c)

- **Goal**: user wants to push `k33g/ori` to Docker Hub — a `template/build.sh` they run themselves, image tagged `0.0.0`; the kit's listen port made configurable; a `quickstart.md` with the sandbox-creation commands.
- **Changes**: `template/build.sh` (multi-arch buildx --push, tags 0.0.0 + latest, VERSION as $1, PLATFORMS overridable); `kits/ori/spec.yaml` gained `args.port` (default "8888", pattern-validated) substituted into `ports.container` (unquoted `${{ kit.args.port }}` — the source's expand.go explicitly re-infers it as an integer), the startup `--addr`, and the agentInstructions; `quickstart.md` at the repo root; kit README and both run-in-a-sandbox pages now reference `k33g/ori:0.0.0` and `--kit-arg ori.port=`.
- **Validation**: spec YAML parses with the arg refs; build.sh is the push path, `make template` stays the local-only path. The actual Hub push is the user's action (their Docker login).

## 2026-09-17 — Multi-arch build fix: no qemu in the template build (same session, follow-up 5d)

- **Problem**: the user's `./template/build.sh` failed on the linux/amd64 half — on an arm64 host that stage runs under qemu, where Vite bundling Monaco exhausts Node's 2GB heap ("FATAL ERROR: Ineffective mark-compacts near heap limit", "qemu: uncaught target signal 6").
- **Fix**: every build stage now runs on `--platform=$BUILDPLATFORM`: the SPA build is platform-independent (built once, natively), Go cross-compiles with `GOOS=$TARGETOS GOARCH=$TARGETARCH`, and the ACP adapter is npm-installed in a native stage then COPY'd into the template's npm prefix (`/usr/local/share/npm-global`, agent-owned, on PATH). The final stage contains no RUN at all, so a multi-arch build never invokes qemu.
- **Validation**: native rebuild green; smoke tests pass (healthz with mock agent; `claude-code-acp` resolves from the copied prefix and initializes a real ACP session).

## 2026-09-17 — Kit startup fix: su resets PATH (same session, follow-up 5e)

- **Problem**: the user's real `sbx create … --kit ./kits/ori -p 5555:8888` came up with nothing listening. Root cause read from the sbx source (`sandboxlib/kit/durable_startup.go`): startup commands are rendered as `exec su -s /bin/sh -c '<script>' agent`, and util-linux `su` always resets PATH to the login.defs default — which lacks `/usr/local/share/npm-global/bin`, so ori died instantly with "claude-code-acp: executable file not found". Reproduced in the image (`su -c 'command -v claude-code-acp' agent` → missing); my earlier validation had used `docker exec`, which preserves image ENV — that's why it passed.
- **Fix**: the kit's startup script now exports `PATH="/usr/local/share/npm-global/bin:/home/agent/.local/bin:$PATH"` first (comment marks it load-bearing). Re-validated through the exact `su` path: healthz OK, ACP session created.
- **No image rebuild needed** — kit-side only; the user must `sbx rm` and recreate the sandbox for the new kit to apply. Debug window for kit startup: `/var/log/sbx-kit-startup.log` (dispatcher log) + `/home/agent/.ori.log`.

## 2026-09-17 — Session end inside the sandbox: WS-offline investigation in flight (follow-up 5f)

- After the su-PATH fix, the user's sandbox serves the SPA on localhost:5555 but the UI shows "offline" (the WebSocket to /ws does not stay up). Established before stopping: ori's WS handshake is correct against browser-like Origin headers (101 for localhost:* origins, 403 for foreign — tested with curl against the image); sbx port publishing goes through gvisor's port mapper (raw L4, so the upgrade should pass). Three discriminating diagnostics were handed to the user (server log; WS handshake from inside the sandbox; WS handshake through the forward) — answers not yet received. The session ends here: the user is relaunching the assistant outside sbx.
- Everything since commit 2434cc7 is still uncommitted (user's call, repeatedly deferred).

## 2026-09-17 — Why the ori sandbox stops on its own: sbx auto-stop investigation (follow-up 6, read-only)

- **Asked**: the sandbox created with `sbx create claude . --template k33g/ori:0.0.0 --kit ./kits/ori --name ori -p 8888:8888` serves the webapp then goes `stopped` by itself; find the auto-stop mode in the sbx source and a way to disable it.
- **Found** (in `sandboxes/`, the vendored sbx checkout, v0.43.0 daemon on this Mac): sandboxd counts "sentinel" long-poll sessions per sandbox (`GET /sandbox/{name}/session`, `holdSession` in `sandboxd/pkg/server/backend_dockernext.go`); when the count hits zero it stops the container after a hard-coded 30 s grace (`WithAutoStopDelay(30*time.Second)` in `setupDockerNextBackend`). `sbx create` holds a sentinel only for its own lifetime (`executeCreateAndReleaseSession` in `cli-plugin/commands/create.go`), so the stop fires 30 s after the command returns — confirmed by the daemon log (`session disconnected, deferring auto-stop``auto-stopped runtime` 30 s later for `ori` and `ori2`). Port publishing and browser traffic hold no session.
- **Escape hatch**: the create-time spec field `detached: true` (openapi `SandboxCreateRequest.detached`) makes `holdSession` never auto-stop. Only `sbx run -d/--detached` sets it (`create_daemon.go: Detached: opts.detached`); `sbx create` has no such flag; there is no update API, no `sbx settings` key and no env var for the delay.
- **Recommendation given**: `sbx rm ori` then `sbx run -d claude . --template k33g/ori:0.0.0 --kit ./kits/ori --name ori -p 8888:8888`.
- **Docs switched (same session, at the user's request while they tested)**: `quickstart.md`, `kits/ori/README.md`, `docs/en|fr/how-to/run-in-a-sandbox.md` now use `sbx run -d`, explain the 30 s auto-stop and why detached is the fix, and add a restart line (`sbx run -d --name <name>`) plus a daemon-log diagnostic hint. No `sbx create` invocation remains in project docs. No code change.
- **Also observed**: the WS-"offline" symptom from follow-up 5f is very plausibly this same stop (the page was already loaded when the container died), still to be confirmed by the user.

## 2026-09-17 — Three parallel agents: ori-desktop (Wails), @/skill selectors + draw.io/image previews, ACP command inventory

- **Asked**: (bob) create `ori-desktop/`, a Wails app connecting to the ori webapp; (riker) add an `@` file selector, a skill selector, draw.io and image previews; (milo, read-only) list the ACP commands exposed. Then the user built ori-desktop on their Mac: Check OK, Connect "did nothing".
- **bob**: new module `ori-desktop/` (Wails v2.16.0, plain template, iframe embed of the ori SPA, settings JSON, bound methods, `internal/settings` + `internal/health` with 12 tests, EN+FR READMEs, `make desktop`/`desktop-test`, .gitignore, ticket 0005 filled). Verified: tests, vet, gofmt, Windows cross-build, root `make build`/`make test` unaffected. Not verifiable in the sandbox: running the window (no gcc/webkit2gtk).
- **riker**: `GET /api/files/search`, `GET /api/raw`, new `internal/skills` + `GET /api/skills`; `prompt.attachments` → ACP `resource_link` blocks (`Prompter.Prompt(blocks)` replaces `PromptText`, `Bridge.SetWorkspaceRoot`); reducer stores `available_commands_update` commands; `mentions.ts`, `useCompletion.ts`, `CompletionPopup`, rewritten `PromptInput`, `ImageView`, `DrawioView` (embed.diagrams.net + Source fallback), `lang.ts` kinds `image`/`drawio`; mock agent emits commands and echoes attachments; Vite dev proxy gained `/api`; `biome format --write` reformatted 11 files. Docs EN+FR: workspace-api, websocket-protocol, use-the-workspace, new how-to `mention-files-and-skills`, architecture sections, READMEs. Tickets 0008/0009/0011/0012 filled.
- **milo**: ori calls `initialize`, `session/new`, `session/prompt`, `session/cancel`; serves `session/update`, `session/request_permission`, `fs/read_text_file`, `fs/write_text_file`; refuses `terminal/*`; unused stable methods: `authenticate`, `logout`, `session/load|resume|list|close|set_mode|set_config_option`. "Agent commands" are not ACP methods: `available_commands_update``/name` text in the prompt. Relayed to riker, who implemented it (ticket 0008).
- **Bug fixed after the user's test**: `ori-desktop/frontend/src/main.css``#connect-screen {display:grid}` outranked `.screen[hidden]`, so Connect (and the startup auto-connect) rendered the viewer below the fold; now class `.connect` + `.screen[hidden] {display:none !important}`. Rebuild needed (`wails build`); iframe content in WKWebView still unconfirmed.
- **Tests**: `make test` → 9 Go packages ok, vitest 16 files / 102 tests (was 66); `go test -race ./...` ok (riker installed gcc + libc6-dev via apt in the sandbox for it).
- **Quality gate**: NOT run — qlty absent from this sandbox (`~/.qlty` missing). gofmt / go vet / biome check clean.
- Nothing committed (still everything since 2434cc7).

## 2026-09-17 — Launch ori for manual testing of the new features (evening session)

- **Asked**: "lance ori que je puisse tester les nouveautés". No code change: `make build` (SPA + binaries), then `env -u CLAUDECODE nohup ./bin/ori --addr 0.0.0.0:8888 > /tmp/ori.log 2>&1 &` inside the `claude-ori` sandbox. Adapter `@zed-industries/claude-code-acp@0.16.2` resolved via npx (npm now flags it deprecated → renamed `@agentclientprotocol/claude-agent-acp`; still works). ACP session ready, `/healthz` ok, `/api/skills` lists the skills. Port 8888 must be published on the host with `sbx ports claude-ori --publish 8888:8888/tcp` (not doable from inside the sandbox).
- Trap hit: a `curl` WebSocket handshake against `/ws` never returns on success (101 keeps the socket open) — use `-m` or check the log instead.
- **Follow-up (same session)**: first real prompt failed with `-32603 There's an issue with the selected model (fable[1m])`. Root cause: `@zed-industries/claude-code-acp@0.16.2` bundles `@anthropic-ai/claude-agent-sdk@0.2.44`, whose embedded Claude Code CLI is **2.1.44** (zero mentions of Fable), while `~/.claude/settings.json` sets `"model": "fable[1m]"` and the adapter forwards it verbatim. The system CLI (2.1.275) accepts `fable[1m]` fine. Fix without touching the user's settings: the adapter honours `CLAUDE_CODE_EXECUTABLE``pathToClaudeCodeExecutable`; ori relaunched with `CLAUDE_CODE_EXECUTABLE=/home/agent/.local/share/claude/versions/2.1.275`; a WS prompt round-trip returned `pong` (`turn_ended end_turn`). No code change.

## 2026-09-17 — Resizable file explorer column (ticket 0015), via methodical-dev

- **Goal**: make the workspace file tree column resizable with the mouse; user chose localStorage persistence and the file-tree divider only (not the chat/workspace split).
- **Changes**: `ui/src/workspace.ts` (`fileTreeWidth`, `setFileTreeWidth`, `resetFileTreeWidth`, `clampFileTreeWidth`, constants, guarded localStorage), new `ui/src/components/ResizeHandle.tsx` (+ test), `Workspace.tsx` (handle between tree and tabs, `--filetree-width` on the aside; new `Workspace.test.tsx`), `app.css` (`.filetree` width from the variable, `.resize-handle` styles). Ticket 0015 closed.
- **Decisions**: width in px (drag produces px; comparable with bounds); FileTree untouched — width reaches CSS via a custom property; handle owns no width, the store clamps. jsdom 26 has no PointerEvent → test-local MouseEvent polyfill.
- **Quality gate** (first run of qlty on the tree since the parallel-agents session): 12 errors / 1 warning / 2 smells, all pre-existing — fixed without weakening anything: `ori-desktop/frontend/src/main.js` became an ES module (`type="module"`, IIFE and `"use strict"` dropped, optional chains, template literals, `reloadFrame()` instead of `src = src`), `internal/files/raw.go` explicit `_ = file.Close()` with rationale, `internal/files/search.go` walk callback → `searchWalker.visit/visitDir/collect`, `PreviewPane.tsx` loading effect → `usePreviewFile` hook; `qlty fmt` on main.css / main.js / wails.json. Run #15 PASS (0/0/0, complex 507).
- **Tests**: 118 vitest (18 files), 9 Go packages, ori-desktop 2 packages — green. `make test`.
- **Docs**: how-to `use-the-workspace` (step 5 + keyboard/persistence variant) and architecture explanation, EN + FR; root README; ori-desktop READMEs (ES module).
- **Not verifiable here**: the ori-desktop frontend change (ES module) needs a `wails build` + launch on the user's Mac.

## 2026-09-17 — Light / dark theme selector, light by default (ticket 0013)

- **Goal**: user request received mid-session; choices made via AskUserQuestion: two themes only (no "system" option), single review at the end.
- **Changes**: new `ui/src/theme.ts` (+ `theme.test.ts`), `app.css` (dark palette on `:root[data-theme="dark"]`, `color-scheme` per theme, `.topbar-theme`), `App.tsx` (☾/☀ button, aria-label "Switch to dark/light theme"), `MonacoViewer.tsx` (store instead of `matchMedia`), `main.tsx` (side-effect import so the theme is stamped before the first render), `App.test.tsx` (+1). Ticket 0013 closed.
- **Decisions**: dropping `prefers-color-scheme` is a behaviour change (dark-OS users now get light until they toggle) — accepted by the user ("light par défaut"); documented in the architecture explanation. Terminal keeps its dark background (pre-existing decision).
- **Tests**: 124 vitest / 19 files green; Go untouched. **Quality**: run #16 PASS (0/0/0, complex 514).
- **Docs**: new how-to `switch-the-theme.md` EN + FR, both indexes, architecture explanation paragraph EN + FR, root README.
- ori rebuilt and restarted on :8888 for the user's review.

## 2026-09-17 — Commit and merge into main

- User asked to merge `feat/acp-webapp` into `main`. Everything since 2434cc7 committed as `76d62ac` (203 files, +21 595 lines), excluding `hello.md` (test artefact) and `.claude/settings.local.json` (local permissions). `main` fast-forwarded (merge base was 4edda86, no divergence). Not pushed to `origin` (git.rickub.com) — not asked. This memory update itself is a follow-up commit on main.

## 2026-09-18 — Diagnose `git push --set-upstream origin main` hanging

- **Asked**: why the first push to `origin` never finishes. Diagnostic only; no code or config changed.
- **Finding**: `origin` is `https://git.rickub.com/bots-garden/ori.git`; the server answers 401 on `git-receive-pack`, the macOS keychain has no entry for that host, and the session (launched from VSCodium's terminal) exports `GIT_ASKPASS` → VSCodium's `askpass.sh`. Git therefore hands the password prompt to VSCodium's input box, which is easy to miss, so the push waits forever. Confirmed with `ps`: `git-remote-https``askpass.sh "Password for 'https://git.rickub.com'"` blocked.
- **Also verified**: network fine (DNS, 443, 22 all open); anonymous read over HTTPS works; SSH key `~/.ssh/id_ed25519` is accepted by `git@git.rickub.com` (server replies "serves git only"); `git ls-remote` over SSH succeeds and shows the remote repo is **empty** (no branches yet). Local `main` = 34e69b5.
- **Recommendation left to the user**: switch `origin` to `git@git.rickub.com:bots-garden/ori.git` (no password, key already trusted), or run the push in a plain terminal with `GIT_ASKPASS` unset so osxkeychain stores the credentials. Not applied — awaiting the user's choice.

## 2026-09-18 — AppleScript launcher for the ori sandbox + desktop app

- **Asked**: an AppleScript that runs `sbx run -d claude . --template k33g/ori:0.0.1 --kit ./kits/ori --name ori -p 5555:8888` then launches `ori-desktop/build/bin/ori-desktop.app`.
- **Changes**: new `scripts/launch-ori.applescript`; one row in `quickstart.md` (everyday commands); pointer in `summary.md`.
- **Decisions**: (1) if `sbx ls -q` already lists `ori`, restart it with `sbx run -d --name ori` instead of re-running the create command (which would collide on the name); errors on that path only notify, the health check decides. (2) Poll `/healthz` on :5555 (2 s × 45) before opening the app, because the kit starts the server asynchronously and the desktop app auto-connects to the saved URL (`~/Library/Application Support/ori-desktop/settings.json` already holds `http://localhost:5555`). (3) `PATH` exported explicitly (Finder launches lack `/opt/homebrew/bin`). (4) Repo root derived from `path to me` so the compiled `.app` works from `scripts/` too. Rejected: `sbx rm` + recreate on every launch (destroys the sandbox's Claude session/state).
- **Tests**: `osacompile` OK; handlers exercised via `load script`: `sandboxExists` → false with no sandbox, `waitForServer` → false on a closed port, true against a throw-away Python `/healthz` on :5555. Not run end to end (would create a real sandbox and start Claude in it). Quality gate not re-run (no Go/TS touched).

## 2026-09-18 — Ticket 0005 back to the IssueSpec task schema; launcher compiled as an app

- **Asked**: "le ticket 0005 n'est plus au bon format"; then how to make the AppleScript launcher double-clickable.
- **Cause**: the 0005 checklist had been hand-written as `- text: … / done: true|false`, which is not IssueSpec's task shape (`id`, `title`, `state`, `priority`, `author`, `createdAt`, optional `updatedAt`/`closedAt`). IssueSpec's parser rejects the file: "tasks[0].id must be a positive integer".
- **Changes**: `.tickets/issues/0005-….yaml` — 8 tasks rewritten (7 `closed` with `updatedAt`/`closedAt` = 2026-09-17T22:23:39Z, 1 `open`; all `priority: none`, author k33g); issue `updatedAt` bumped. `scripts/Launch Ori.app` built with `osacompile`, ignored via `.gitignore` (`scripts/*.app/`). `summary.md` gains a `.tickets` paragraph.
- **Verification**: bundled IssueSpec's `parseIssueDocument` (from the local clone `~/CodeBerg/issuespec`, esbuild `--format=cjs`) and ran it over all 15 tickets: all OK; the committed 0005 fails as expected.
- **Follow-up**: `scripts/README.md` + `scripts/README.fr.md` written (what the launcher does, run vs. double-click, design choices, handler test recipe); quickstart row now points to it.

## 2026-09-18 — `sbx kit package` does not exist

- User hit `ERROR: sbx: unknown command: sbx kit package` (sbx v0.43.0). The verbs are `sbx kit pack DIRECTORY [-o file.zip]` (local ZIP) and `sbx kit push DIRECTORY registry/repo:tag` (package + push to OCI, adds SLSA provenance, `--sign` optional). Both take the kit **directory**, not `spec.yaml`. `sbx kit validate kits/ori` → VALID. Not pushed: publishing to Docker Hub left to the user.

## 2026-09-18 — `sbx kit push` rejected the kit: arg placeholder in an integer field

- **Asked**: `sbx kit push kits/ori docker.io/k33g/ori-kit:latest` failed with `invalid spec.yaml: line 38: cannot unmarshal !!str `${{ kit...` into int`.
- **Cause (verified in `sandboxes/` source, v0.44.0-rc1+26, and by trial)**: `Pack`/`Push` call `LoadFromDirectory` → strict typed decode of the raw spec (`ports[].container` is `int`), with **no** `${{ kit.args.* }}` expansion; `validate`/`inspect`/`run` expand first (`expand.go`, `argScan`), hence VALID vs INVALID for the same directory. v3 kits (`schemaVersion: "3"`, `com.docker.runtime/port@1` capabilities) keep placeholders at push and expand at pull, but the installed sbx v0.43.0 has no v3 support (0 hits for the capability type in the binary).
- **Changes**: `kits/ori/spec.yaml` `ports[0].container` → literal `8888` with a comment explaining why; `${{ kit.args.port }}` kept in the startup command and agentInstructions (string fields decode fine). Kit README, docs EN/FR how-to `run-in-a-sandbox`: with a custom port, publish it with `-p` since the declared port stays 8888. Rejected: dropping the `port` arg (loses a documented feature); moving to v3 (needs sbx ≥ 0.44 on every consumer).
- **Verification**: `sbx kit validate kits/ori` (default and `--kit-arg ori.port=9000`) VALID; `sbx kit pack kits/ori` OK; `inspect --kit-arg ori.port=9000` shows `--addr ":9000"` substituted with `"container": 8888`. **Push not run** — the user publishes.
- **Follow-up**: kit published by the user; `sbx kit inspect docker.io/k33g/ori-kit:latest` resolves (mixin, schema v2, 1 port, 1 startup command). Sandboxes running at that time: `ori` (5555→8888) and `hello-ori` (3000→8888), both on this repo.

## 2026-09-18 — "Claude Code 2.1.44 does not support this model; 2.1.251 or newer required"

- **Asked**: reminder of what to do to avoid this prompt failure in the sandbox (kit `docker.io/k33g/ori-kit:latest`, template `k33g/ori:0.0.1`).
- **Diagnosis (read-only, verified)**: ori in sandbox `ori` runs with no `CLAUDE_CODE_EXECUTABLE`, so the Zed adapter 0.16.2 uses its bundled CLI 2.1.44 (SDK 0.2.44). The model comes from the host `~/.claude/settings.json` (`claude-fable-5-1[1m]`), which the API only serves to CLI ≥ 2.1.251. Yesterday's workaround (point the adapter at the template's system CLI) **no longer suffices**: the base image `docker/sandbox-templates:claude-code` (built 2026-08-26) ships CLI 2.1.246. Sandbox egress reaches the Claude Code release bucket (latest = 2.1.276) and npm, so `claude update` inside is feasible. `@agentclientprotocol/claude-agent-acp@0.79.0` (bin `claude-agent-acp`) depends on `@anthropic-ai/claude-agent-sdk@0.3.274`, whose `manifest.json` says CLI **2.1.274**, delivered through per-platform optional deps (`…-sdk-linux-arm64`, `…-linux-x64`, …) — no `cli.js` any more.
- **Nothing changed**: options given to the user (immediate: `claude update` in the sandbox + restart ori with `CLAUDE_CODE_EXECUTABLE`; permanent: switch the template to the new adapter, or bake a recent CLI + the env var into template/kit). Their call.

## 2026-09-18 — Switch the ACP adapter to @agentclientprotocol/claude-agent-acp (template 0.0.2), Node 25 test fix, MIME pin

- **Goal**: option 1 of the "Claude Code 2.1.44 too old" diagnosis, approved by the user: stop depending on the Zed adapter's embedded CLI; rebuild template 0.0.2; republish the kit. Worked on `feature/copy-paste-functionality` (user's choice), commit `5d476ff`, fast-forwarded into `main`; this memory update is a follow-up commit on `main`.
- **Changes**: `internal/config/config.go` `DefaultAgentCommand``npx -y @agentclientprotocol/claude-agent-acp` (+ `TestDefaultAgentCommandIsClaudeAgentACP`); doc comments in `internal/agent/agent.go`, `cmd/ori/main.go`. `template/Dockerfile`: `adapter` stage installs the new adapter with `npm install --os=linux --cpu=$npm_cpu`, Docker's `amd64` mapped to npm's `x64` (with `--cpu=amd64` npm silently installs **no** native SDK), and asserts `claude-agent-sdk-linux-<cpu>` exists; CMD `--agent-cmd claude-agent-acp`. `kits/ori/spec.yaml`: startup + agentInstructions → `claude-agent-acp`, template 0.0.2. `internal/files/raw.go`: `textTypes` pins `.md`/`.markdown``text/markdown; charset=utf-8` (Go's mime table comes from the host; macOS leaves `text/markdown` commented out, so `TestRawAcceptsAbsolutePathsLikeTheOtherEndpoints` failed on the Mac) + 2 table cases. `ui/package.json` test script gains `NODE_OPTIONS=--no-experimental-webstorage`. `ui/src/components/Markdown.tsx`: `React.ReactElement<{ children?: unknown }>` cast — the copy-paste commit did not compile (TS2339 ×3) and blocked `docker build`. `ui/src/components/ToolCallCard.tsx`: copy text extracted into pure `contentText` / `toolContentText` (+5 tests), clearing two function-complexity smells. `.qlty/qlty.toml`: golangci-lint pinned 2.13.2. Docs EN+FR (architecture explanation, how-to run-with-claude-code / run-in-a-sandbox / run-the-tests, reference cli), `docs/diagrams/packages.drawio`, `docs/source-code-analysis.adoc`, kit README, root README, quickstart, `scripts/launch-ori.applescript` (0.0.2, `/tcp`, converted back from UTF-16) + its READMEs.
- **Decisions**: (1) new adapter over "bake `claude update` + `CLAUDE_CODE_EXECUTABLE`": the SDK ships a current CLI per platform, no version chasing. (2) `adapter` stage stays `--platform=$BUILDPLATFORM` (native npm) and targets the CPU explicitly, instead of npm under qemu. (3) Backend default changed too (user: "backend + template") so `make run` gets the same fix. (4) Pre-existing failures fixed along the way with the user's explicit OK: MIME test, Node 25, Markdown.tsx types, ToolCallCard complexity. (5) Left untracked as the user's artefacts/memos: `kits/.backup/`, `demo/` (the three prompt-generated stories the user moved there — their root copies are deleted in `5d476ff`), `kits/ori/publish.kit.md`, `template/publish.template.md`.
- **Verification**: `go vet ./... && go test ./...` green; ui `tsc -b` + 134 vitest green; `docker build --check` clean; arm64 image built locally — `claude-agent-acp` resolves for root and via `su … agent`, native SDK `linux-arm64` with the 230 MB CLI, manifest 2.1.274, ACP `initialize` answered by adapter 0.79.0, Zed adapter gone; amd64 install verified in a `node:24` container (`-linux-x64` present). Test sandbox `ori-acp` (image via `sbx template load`) served ori with CLI 2.1.274; the user pushed `k33g/ori:0.0.2` (multi-arch) and confirmed a real prompt in sandbox `hello-world` after the kit re-push. **Quality**: run #18 PASS (0/0/0, complex 532) after repairing qlty on the Mac (dangling `.qlty/*` symlinks from the sandbox; golangci-lint too old for Go 1.26).
- **Docs**: as listed, EN + FR in sync. `diataxis-doc` skill not invoked: edits to existing pages, done directly.

## 2026-09-18 — Linux build of ori-desktop (webkit2gtk-4.1) + MIT LICENSE

- **Asked**: `cd ori-desktop && wails build`; then, mid-session, "ajoute un fichier de licence MIT".
- **Build**: installed the Wails CLI (`go install …/cmd/wails@v2.16.0`) and the GUI toolchain (`sudo apt-get install libgtk-3-dev libwebkit2gtk-4.1-dev`) in the sandbox — they were absent, which is why the window had never been launched here. Plain `wails build` fails: Wails' cgo pkg-config asks for `webkit2gtk-4.0`, Ubuntu 26.04 only ships 4.1. `wails build -tags webkit2_41``build/bin/ori-desktop`, ELF aarch64, 9.4 MB, 4.8 s. `wails doctor` still says `libwebkit: Not Found` (it only probes 4.0) — a false negative. No source change was needed.
- **Not done**: no macOS build — Wails cannot cross-compile to macOS from Linux, and the `.app` the user actually launches (`build/bin/ori-desktop.app`, and the AppleScript launcher) must still be built on the Mac. The Linux binary was added next to the existing `.app` and `.exe`, overwriting neither. The window itself was not run (no display in the sandbox).
- **Changes**: `LICENSE` (MIT, `Copyright (c) 2026 k33g`) at the repository root — the only file added to the tree; `build/bin/` and `frontend/wailsjs/` are gitignored. `.memory/summary.md`: the `-tags webkit2_41` requirement and the three build outputs on the `ori-desktop/` bullet, the apt/CLI install recipe under "Environment facts", the licence line.
- **Decisions**: holder `k33g` (the name used by every ticket author block and the git identity), not a guessed legal name. Root-only LICENSE, no copy under `ori-desktop/` despite it being a separate Go module. `make desktop` left untouched even though it fails on Linux for want of the tag — a Makefile change was outside what was asked; flagged to the user instead.
- **Verification**: `go test ./internal/...` in `ori-desktop` green (health, settings). Quality gate not re-run: no Go/TS source was modified.
- **Follow-up (same session)**: `ori-desktop/how-to-build.md` written on request — prerequisites, the from-where/to-what cross-build matrix (macOS only from macOS; Windows from anywhere; Linux from Linux), one section per platform, the `wails build` flags that matter, `wails dev`, the tests, and a troubleshooting list (webkit 4.0 vs 4.1, the `wails doctor` false negative, `make desktop` on Linux, the lost execute bit under cloud sync, Gatekeeper/`xattr -cr`, empty window = no server). English only, house Diátaxis how-to style; `how-to-build.fr.md` NOT written and `README.md` NOT linked to it — the user's own edits to `ori-desktop/README*.md` are uncommitted in the tree and were left alone. All four relative links in the doc were checked to resolve.