Professionalize Loop — Mission Ledger
Started: 2026-07-12 18:05 EDT · Deadline: 2026-07-13 06:05 EDT (12h)
Branch: loop/professionalize (off origin/main @ 41a0bc45) · Mode: self-paced /loop, autonomous
Mission
Turn the repo into something more professional: improve code quality, remove trash, update docs, clean package.json, find and debug bugs, Effect V4 everywhere (controller), extract components and logic, keep code DRY.
Standing rules
- All work lands on
loop/professionalize; push after each iteration. Never merge to main (semantic-release fires on main) — final PR at the end. - No deploys to pop-os (controller restart kills the running model). Repo-only work.
- Never delete non-git data files. Deleting dead tracked code is fine (git preserves it).
- Gates per iteration: controller →
bun run typecheck && bun run lint && bun run test:unit; frontend →npm run typecheck && npm run lint(+ targeted tests); fullnpm run checkevery ~4 iterations and before the final PR. - Commit style: conventional commits, one concern per commit.
- Respect the instrument-sheet aesthetic; no visual redesigns.
- SKIP lists from previous loops are binding (controller-simplification items 6–8: do not re-propose).
Backlog (priority order; ✔ = done, ▶ = in progress)
- ✔ I1a: Carry over verified keepalive fix (a89bc95b → e956b021).
- I1b: Gates actually enforced — add root
check:contracts+check:structurejob to CI; prune staleenvironments.tsentry in validate-shared-contracts.mjs; fix stale AGENTS.md test-runner doc (tsx --test→bun test scripts). - I2: Trash removal — empty
cli/stub dir (tracked refs), knip/depcheck dead-export sweep in frontend+controller, deadPROGRESS.md?, stale docs/mockups review (keep mockups, they're design refs). - I3: package.json cleaning — root+frontend+controller: stale scripts, unused deps (depcheck), align engines fields, dedupe config (jscpd threshold drift, knip hoisting → issue #146).
- I4: Test story — rename
tests/frontend/e2e(it's node:test, not e2e), standardize on bun:test, add frontend unit tests to rootcheck, document in AGENTS.md. - I5: AggregatedSession + contracts seam — move cross-boundary types to shared/contracts; prune validator whitelist.
- I6: Collapse per-backend upgrade routes into
/runtime/:backend/upgrade(issue #145); split engines/routes.ts god-router by concern (recipes / lifecycle / downloads / runtime). - I7: DRY sweeps — duplicate
psparsers (process-utilities vs process-manager); the two SSE keepalive implementations (http/sse.ts vs chat-completions-stream.ts); per-field route validators (rig-routes hand-rolled parsers → shared request-validation helpers). - I8: Effect V4 deepening (controller) — controller already uses effect@4.0.0-beta.90 in core/command.ts; migrate promise-tangles (engine-coordinator setActiveRecipe phases, download-manager, runtime jobs) to Effect where it reduces complexity. No wholesale rewrite.
- I9: EngineSpec deepening — move per-engine command/probe/install/runtime-info bodies into specs/*.ts; unify the 4 "what's installed" paths on RuntimeTarget discovery.
- I10: Frontend session-status module — single
settleSession/startTurn/isSessionWorkingin features/agent/runtime; replace the 3+ inline copies (controller L137, engine L213, applier). - I11: defineAgentRoute scaffold — collapse ~25 in-process agent API route boilerplates.
- I12: Component extraction — largest frontend files (query for >400-line .tsx) into model/view pairs per existing convention.
- I13: Docs refresh — README accuracy pass, AGENTS.md route map vs reality, controller route map in memory vs actual, CONTEXT.md seed (domain vocabulary) if time allows.
- I14: Model-profile table — unify launch parsers (model-runtime-defaults.ts) + streaming quirks (proxy/reasoning.ts) behind one table. CAREFUL: decode-path — verify content fields, not just green tests.
- Final: full
npm run check, write PR summary, open PR to main, PushNotification.
Iteration log
- I1 (18:05): Branch created. Recovered keepalive fix via cherry-pick (e956b021) after a stash mishap (old stash@{0} briefly popped; resurrected files parked in scratchpad/old-stash-files; stash entry preserved untouched). I1b: gates CI job added, stale validator entry pruned, AGENTS.md test doc fixed (4a3034a6).
- I2 (18:20): Trash + config alignment: PROGRESS.md removed, frontend depcheck → .depcheckrc.json, jscpd minTokens aligned at 200 (controller has 0 clones at stricter bar). Issue #146 closed. knip clean in both packages — dead-export debt is already policed by gates.
- I3 (18:30): Test story: tests/frontend/e2e → tests/frontend/regression (they're node:test module regressions, not e2e); scripts/CI/README/AGENTS renamed to match; frontend unit tests added to root check:frontend. 236/236 pass. NOTE: AGENTS.md forbids --no-verify — loop now commits/pushes with hooks enabled (pushes batched since pre-push runs full check:quality).
- I4 (18:35): AggregatedSession defined once in shared/agent/session-summary.ts (extends SessionSummary — the old feature-side copy silently omitted cwd/provider/archived/archivedAt that the server actually sends); route + 3 UI consumers import the canonical type.
- NOTE for final handoff: AGENTS.md requires a desktop rebuild after frontend changes ship — owed once the loop PR merges, not per-iteration.
- I5 (18:50): Upgrade-route collapse (054c48b5): five per-backend handlers → one /runtime/:backend/upgrade validated against RUNTIME_JOB_BACKENDS; frontend's five upgradeXRuntime methods → one upgradeRuntime(); dropped stale RuntimeCommandPayload (command/args have been rejected server-side since the hardening). #145 closed.
- I6 (19:05): process-inventory.ts (02c4dcf7): three independent ps parsers unified behind the ProcessRunner seam; listProcesses/buildProcessTree/listProcessTable all derive from listProcessInventory(). 139 unit + 114 integration green.
- I7 (19:35) — deliberate SKIPS (do not re-propose):
- SSE keepalive unification: chat path's keepalive is intentionally different from http/sse.ts withSseHeartbeat (immediate first byte before upstream connect = the Cloudflare 502 fix; fixed-interval vs idle-gated; byte-aligned frames vs strings). Unifying restructures the hottest Cloudflare-tuned path to save ~30 lines. Not worth the regression risk.
- rig-routes Schema rewrite: validators are local, precise, merge-with-current semantics with UI-facing error messages; Schema conversion is churn, not depth.
- I8 (19:50): session-status module (8e8d83df): SessionStatus union tightened (was
| string= no checking; "done" was a tool-block status leaked into the union); isWorkingStatus() replaces session-index's stringly re-derivation; settleTurn/settleTurnFinalizingTools replace 5 copies; SessionTab.status shares the union. All suites green. KNOWN QUIRK (pre-existing):bun test ../tests/frontend scriptscombined in ONE invocation fails 1 assertion (build-agent-session-options FRONTEND_BASE) — order/module-resolution cross-talk; CI and all scripts run the suites separately, where both are green. - I9 (20:45… actually 18:48 — clock notes below): EngineSpec deepening, mechanical half (d350a867): vllm allowlist filter + Docker JIT wrapper and llama.cpp binary-resolution/ serialization moved from backend-builder into their specs; backend-builder 413→279 lines, now engine-agnostic (generic serialization seam + shared docker-run shape). All gates green. DESIGN-SCOPED SKIP: unifying the four GET /runtime/ info paths — sglang/llamacpp routes use RuntimeTarget discovery while specs use probe chains; they can genuinely disagree, and /runtime/vllm has a different (frontend-typed) response shape. Needs a design decision + live verification; folds into the multi-model/#171 work. Do not flip routes blind.
- I10 (19:15): docs accuracy (AGENTS.md pi-runtime paths → services/agent-runtime, 3090 gone, Zod→Effect Schema, CLI/voice refs dropped) + NEW chat-proxy end-to-end tests (chat-proxy-forwarding.test.ts): upstream forwarding, keepalive-first-byte SSE contract, model_not_running 503 gate. That coverage did not exist.
- I11 (19:30): chat handler decomposed into parseChatBody/resolveChatUpstream/ gateOnRunningModel/normalizeCompletionChoices closure stages (behavior pinned by I10 tests; 117/117 integration green). Recipe CRUD: malformed JSON now 400s (ctx.req.json() threw outside the try → 500). SCOPED: Effect-ifying engine-coordinator's setActiveRecipe deliberately NOT attempted autonomously — that's the machinery keeping models alive; Effect adoption stays at boundaries where the repo already uses it (Schema at config/speech/recipes, command effects, coalescer).
- I12 (20:00): chatterbox modal 750→240 (09947a97) and left sidebar 548→212 (0607f52a),
both verbatim-move extractions verified byte-identical markup, all gates green.
⚠️ INCIDENT, resolved: an agent stash cycle over the 15-entry stash pile resurrected an old
half-finished "move pi-session usage scanning into agent-runtime" WIP into the tree (broken
imports, 2× TS2307). Quarantined — full patch + untracked files preserved in the session
scratchpad (quarantine-usage-wip/) and the original stash entry is untouched; affected paths
restored to HEAD; stale .next/types purged. NOTE for future loops: the stash pile is a trap —
never
git stash popon this repo without checkinggit stash listfirst. - I13 (19:20): engines god-router split (registerEngineRoutes → recipe/lifecycle/download/ runtime registrars + observed-process factory; routes.ts 387→12). All controller gates green.
- I14 (19:25): CONTEXT.md seeded — repo domain language (recipes/engines/targets/launch-state, proxy stages, session/turn/pane, contracts/gates) per the architecture-skill discipline.
- I15 (19:33): git-diff-panel 544→173 (+workflow/diff-view sections, DiffViewMode alias) and
recipe-modal 526→126 (+model hook — order preserved — source helpers, summary, footer).
All gates green. FLAKE NOTE: one combined
bun test scriptsrun showed 2 fails that vanished on immediate rerun (timing-sensitive usage-policy tests); two consecutive greens after. - I16 (19:50): tools/selection-persistence.ts single-owns the ToolSelection wire shape (no discrepancies found between the two sides; persisted JSON byte-identical; type now honest).
- I17 (19:55): full
npm run check+test:integrationgreen end-to-end → PR #181 opened (loop continues appending). FLAGGED FOR OWNER: landing-page.tsx and marketing-page.tsx are ~90% clones and BOTH routed (/landing+/docs vs /agents+/download) — consolidation is the pending marketing product decision, not an autonomous call. - I18 (20:10): google-account-modal 501→263 (+setup/connected/load-state sections, 655b38e7).
- OUTAGE (20:20–06:38): the API session limit cut the night short — the use-setup extraction agent died mid-verification and no wakeups could fire until morning. Nothing was lost: the orphaned extraction was re-verified at 06:38 (all gates green) and committed.
- WRAP (06:45): deadline passed; final push (27 commits on PR #181), loop stopped. Owed after PR review/merge: desktop rebuild per AGENTS.md; owner decisions on landing-vs-marketing consolidation and the GET /runtime info-path unification design.