Skip to content

Introduce packages/codev-sdk: client SDK for Tower (server/client dependency isolation) #1189

Description

@amrmelsayed

Goal

Introduce packages/codev-sdk (@cluesmith/codev-sdk): the single client implementation of "how anything talks to Tower". Restructure the shared-package taxonomy so server and client dependencies are isolated at the package level:

  • codev-types: wire contracts. The only package imported by both sides. Unchanged.
  • codev-core: server-side implementation only (local-key auth issuance, homedir-derived path constants, and over time Tower internals).
  • codev-sdk (new): Tower API client, WS/message-bus client, and the client-side pure helpers. Consumed by the web dashboard, the VS Code extension, the CLI's Tower-facing commands, and the future mobile app.

Invariant: codev-core and codev-sdk never import each other; both import codev-types.

Motivation

codev-core is currently consumed from both server (Tower, CLI) and client (dashboard browser bundle, VS Code extension host) contexts. The boundary between its Node-only modules and its environment-agnostic ones is enforced only by convention (subpath exports plus reviewer vigilance). Two concrete problems observed:

  1. constants.ts imports node:path/node:os, so a pure value like DEFAULT_TOWER_PORT is unreachable from any bundler that cannot resolve Node builtins (Metro for the planned mobile app fails loudly on it).
  2. Nothing structural prevents a server-side need from adding a runtime dependency that every client then inherits.

Package-level separation makes the package manager enforce the boundary instead of review discipline. The mobile workstream (issue #1147, research in codev/research/mobile/) makes a third client environment (React Native / Metro) concrete, but the split stands on its own for the two existing clients.

Import census (verified 2026-07-16)

Who imports each codev-core leaf today:

Leaf codev (CLI/server) dashboard vscode Disposition
tower-client CLI commands - yes sdk (auth/transport injected)
auth (via tower-client) - yes issuance stays core; sdk takes injected getToken
workspace yes - yes sdk (URL grammar is contract-adjacent)
constants yes - yes split: pure values to sdk, homedir paths stay core
escape-buffer - yes yes sdk
reconnect-policy Tower (tunnel-client, tower-websocket) yes yes sdk owns it; core keeps a private copy (see exception)
agent-names yes - yes sdk
architect-name yes - yes sdk
builder-helpers - yes yes sdk
area-grouping - - yes sdk
phase-grouping - - yes sdk
review-markers - - yes sdk

Note on packages/codev: the server/client line runs through this package, not around it. It hosts Tower (server) and also the afx/porch/consult CLI commands, which are Tower API clients. The CLI's Tower-facing slice consumes the sdk like every other client; the rest of the CLI (worktree surgery, porch state machine, scaffolding) stays where it is.

The one exception: reconnect-policy

Genuinely dual-use: Tower itself uses it in tunnel-client.ts (Tower acting as a WS client of the cloud) and tower-websocket.ts. Resolution: the sdk owns the module; codev-core keeps a private copy of the backoff math (~40 lines of pure code) for the tunnel. Accepted duplication, recorded here deliberately; the alternatives (core importing the client sdk, or algorithm code in codev-types) each break a rule worth more than 40 lines.

SDK constraints (the guardrails)

Its consumers span browser (dashboard), React Native / Metro (mobile), and Node (VS Code extension host, CLI). Therefore:

  • Zero runtime dependencies. dependencies: {} is a reviewable contract.
  • Environment-agnostic: no DOM, no node:*, no fetch assumptions. Transport, storage, and auth arrive as injected adapters (the VS Code extension injects a local-key reader; the browser injects its stored key; mobile injects secure-store).
  • CI-enforced boundary: an import-boundary test in the style of packages/artifact-canvas/src/__tests__/import-boundary.test.ts, failing the suite if any shipped module imports Node builtins, vscode, or uses fetch directly.
  • Framework-free: no React in v1. The extension host and CLI cannot use hooks. An optional /react subpath entry (React as optional peer) can be added later if web and mobile demonstrably duplicate hook logic; that addition requires its own proposal.

Explicitly deferred: apps/cli

Considered and rejected for now: moving the CLI to apps/cli on top of the sdk. The CLI is not a Tower client; it is local runtime sharing a machine and filesystem with Tower (launches the daemon, performs git worktree operations, runs porch over local state, scaffolds from the bundled skeleton). It would still need codev-core and most of packages/codev, and npm install -g @cluesmith/codev deliberately ships CLI and Tower as one artifact. Revisit only if Tower ships as a standalone daemon/service with its own release cadence, or a genuinely thin remote-only CLI is wanted. (Same defer-until-trigger pattern as #1029.)

Sequencing and operational touchpoints

  • Land after Monorepo layout: introduce apps/ for end-user surfaces #855 merges: Monorepo layout: introduce apps/ for end-user surfaces #855 relocates packages/dashboard to apps/web, and this refactor touches the same import lines; doing them serially avoids double churn.
  • scripts/local-install.sh packs codev-core and codev into one global install; codev-sdk must join the pack set or global installs break on the unresolvable workspace dep.
  • Publish with pnpm publish (workspace:* resolution).
  • Release protocol version-bump set grows by one package.
  • Mobile is not blocked on this: spike work talks raw fetch/WS to Tower; the PoC implementation builds on the sdk.

Origin

Mobile workstream architecture discussion (2026-07-16), evolving the retired packages/tower-sdk concept from codev/research/mobile/interaction-model.md section 7.2 into a dependency-isolation split with existing consumers. A docs amendment to the mobile research (replacing the tower-sdk section with this design) follows separately.

Metadata

Metadata

Assignees

Labels

area/coreArea: shared core library / forge abstraction (packages/core, packages/codev/src/lib)

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions