- All of
vp fmt,vp lint, andvp run typecheckmust pass before considering tasks completed.vp(vite-plus) is the repo toolchain — use it for all repo tasks. - Run the tests covering the code you changed:
vp run '@threadlines/server#test' <filename substring>(same pattern for the other packages; the filter matches file names, not repo-relative paths). Reservevp run test(full Vitest suite) for broad or cross-package changes. - Web UI changes also need the browser suite:
vp run '@threadlines/web#test:browser'. It is not part ofvp run test, and CI runs it — green unit tests alone do not mean a green branch. - NEVER run
bun test. The Bun toolchain is not used for repo tasks.
Tests must earn their maintenance cost. When adding or changing tests:
- Extend the existing test file for a module instead of creating a new one.
- Test observable behavior at module boundaries (commands in → events/projections out, RPC in → response out), not implementation details.
- Don't write tests that restate the implementation or assert mock wiring — they pass when the code is wrong and break when the code is refactored.
- One focused test that would catch a real regression beats five that mirror the code.
Threadlines is a minimal web GUI for using coding agents. Codex and Claude are the supported providers.
The core architecture — event-sourced orchestration, provider drivers, schema-only contracts — is established. Incremental maintainability improvements are welcome; propose sweeping or cross-cutting changes and get agreement before implementing them.
- Reliability and correctness first.
- Performance is a close second.
- Keep behavior predictable under load and during failures (session restarts, reconnects, partial streams).
If a tradeoff is required, choose correctness and robustness over short-term convenience.
Long term maintainability is a core priority. If you add new functionality, first check if there is shared logic that can be extracted to a separate module. Duplicate logic across multiple files is a code smell and should be avoided. Don't be afraid to change existing code. Don't take shortcuts by just adding local logic to solve a problem.
Threadlines is dense and flat. When building or changing any user-facing surface:
- Structure comes from typography, spacing, and hairline dividers (
--border), not boxes. Never wrap content in a bordered/rounded/filled card unless it's a clickable tile or an input surface. A list of items is dividers between rows, not a stack of cards. - Compact type scale: one display-size element per page (~40px max), section headings 18–20px, body 15–16px. If a heading feels impressive, it's too big.
- Tight vertical rhythm: list rows 16–20px padding, section gaps under 40px. If the page scrolls mostly through whitespace, shrink the gaps, not the content.
- Copy is scannable: lead with the feature name, keep descriptions to one sentence (about two rendered lines). Users skim changelogs and UIs; they don't read them.
- Hover feedback is a color shift only — no translateY lifts, scale, or shadows.
- Reuse the existing tokens (
--border,--surface,--fg-*, mono--font-monofor meta labels like versions and dates). No new colors, radii, or shadows without agreement.
apps/server: Node.js WebSocket server. Manages provider sessions (Codex, Claude, Cursor, OpenCode), serves the React web app, and owns the event-sourced orchestration core.apps/web: React/Vite UI. Owns session UX, conversation/event rendering, and client-side state. Connects to the server via WebSocket.packages/contracts: Shared effect/Schema schemas and TypeScript contracts for provider events, WebSocket protocol, and model/session types. Keep this package schema-only — no runtime logic.packages/shared: Shared runtime utilities consumed by both server and web. Uses explicit subpath exports (e.g.@threadlines/shared/git) — no barrel index.
Threadlines is multi-provider. Each provider is wrapped by a driver in apps/server/src/provider/Drivers/. Codex (via codex app-server, JSON-RPC over stdio) and Claude are the supported providers; the Cursor and OpenCode drivers exist in the codebase but are not actively supported — keep them compiling, but don't extend them with new features unless explicitly asked. Provider runtime activity is ingested into the event-sourced orchestration core and projected into read models that the browser consumes.
How the pieces fit:
- Codex session startup/resume and turn lifecycle live in
apps/server/src/provider/Layers/CodexSessionRuntime.ts(withDrivers/CodexDriver.tsandLayers/CodexAdapter.ts). - Orchestration commands are validated in
apps/server/src/orchestration/decider.tsand dispatched to providers byapps/server/src/orchestration/Layers/ProviderCommandReactor.ts; provider events flow back throughLayers/ProviderRuntimeIngestion.tsand are projected byorchestration/projector.tsinto SQLite projections (apps/server/src/persistence/Migrations/). - Orchestration commands from the web arrive over HTTP routes in
apps/server/src/orchestration/http.ts; the WebSocket server inapps/server/src/ws.tsroutes theWS_METHODSRPC table (packages/contracts/src/rpc.ts) and streaming subscriptions. - Web app consumes orchestration state via the shell/thread-detail subscription streams (
orchestration.subscribeShell, wired inapps/web/src/environments/runtime/connection.ts).
Docs:
- Codex App Server docs: https://developers.openai.com/codex/sdk/#app-server
- Open-source Codex repo: https://github.com/openai/codex
- Codex-Monitor (Tauri, feature-complete, strong reference implementation): https://github.com/Dimillian/CodexMonitor
Use these as implementation references when designing protocol handling, UX flows, and operational safeguards.