Harness Intelligence Wiki
SpecsCLIIP-97-effect-api-contract-boundary

Plan: IP-97 Shared Effect API Contract Boundary

Plan: IP-97 Shared Effect API Contract Boundary

Initial Situation

IP-96 established the Harness Intelligence Turborepo and left apps/api as a temporary Better-T-Stack Hono app while packages/contract was an empty boundary. The CLI still owns real operator behavior in apps/cli, including baseline resolution through GitHub releases and bundled fallback. IP-97 now needs the first shared control-plane contract without destabilizing that behavior.

Issue

The CLI and backend need a typed API boundary before the backend becomes the source of truth for baselines, artifacts, auth-required calls, telemetry, or reports. If apps/cli and apps/api define request paths separately, future API renames and schema changes can silently drift.

Child-story coverage:

  • IP-112: baseline/channel resolution and artifact metadata shapes live in packages/contract and are consumed by both API and CLI.
  • IP-113: auth-required calls and authorization failures are typed without leaking Better Auth implementation details.
  • IP-114: CLI control-plane calls use an Effect HttpApi typed client path, not new raw untyped HTTP.

Solution Shape

Create a small, app-independent @punks/contract package around Effect v4 HttpApi. Export schemas, tagged HTTP errors, bearer auth security declaration, the Harness API definition, and a typed client factory. Replace the API scaffold's Hono contract surface with an Effect HttpApiBuilder implementation layer. Add a CLI control-plane adapter that consumes the typed client factory while preserving the current baseline resolver as the runtime fallback until backend artifact storage exists.

Inner Skill Phases

  • $grill-me: no blocking product decision remains; Linear fixes HttpApi, baseline/artifact/auth scope, and RPC non-goal.
  • $parallel-research: used for split readonly discovery of CLI call paths and Effect HttpApi syntax.
  • $swarm-planner: tasks are dependency-ordered and single-branch executable.
  • $tdd: add focused contract/API/client tests before relying on root validation.

Decision Ledger

DecisionStatusRationale
Contract package owns API shapeLockedIP-97 requires CLI/API sharing without app imports.
API implements with Effect HTTP layersLockedM1 notes mark Hono scaffold temporary and future backend direction as Effect HTTP.
CLI gets a typed control-plane adapterLockedIP-114 requires typed client path while existing baseline fallback remains operational.
Backend storage is deferredLockedIP-112/IP-97 define shapes and boundaries, not full storage path.

Codebase Findings

  • packages/contract/src/index.ts is empty but already has @effect/platform and effect dependencies.
  • apps/api/src/index.ts is still Hono scaffold code and imports auth/env directly.
  • apps/cli/src/baseline/resolve.ts performs raw GitHub release lookup/download for the current stable baseline path.
  • apps/cli already depends on @effect/platform, @effect/platform-bun, effect, and @effect/vitest.
  • Effect v4 examples support the needed syntax with HttpApi, HttpApiGroup, HttpApiEndpoint, HttpApiSecurity.bearer, HttpApiBuilder.group, and HttpApiClient.makeWith.

Dependency Graph

T1 -> T2 -> T3 -> T4 -> T5

Tasks

T1: Define shared contract schemas and errors

  • depends_on: []
  • location: packages/contract
  • description: Add baseline channel, baseline resolution, artifact metadata, bearer credentials, and API-visible tagged error schemas.
  • validation: bun run check-types --filter=@punks/contract and focused contract tests.
  • status: Complete
  • log: Added contract schemas and API-visible tagged errors in packages/contract/src/schemas.ts and packages/contract/src/errors.ts.
  • files edited/created: packages/contract/src/schemas.ts, packages/contract/src/errors.ts, packages/contract/src/api.test.ts
  • backlog_item_id: IP-112, IP-113
  • backlog_item_url: https://linear.app/devpunks/issue/IP-112/cli-and-api-share-a-typed-baseline-control-plane-contract, https://linear.app/devpunks/issue/IP-113/contract-models-authenticated-cli-requests
  • relation_mode: native
  • assigned_skills: effect-authoring, quality-types, tdd, simplify
  • tdd_target: Contract tests prove schemas decode baseline/artifact/auth shapes and error tags/status annotations are exported.
  • review_mode: cli

T2: Export Effect HttpApi and typed client factory

  • depends_on: [T1]
  • location: packages/contract
  • description: Build HarnessApi with baseline/artifact endpoints and export an Effect-native typed client factory that accepts base URL and optional bearer token.
  • validation: contract package typecheck plus tests that the client factory composes through Effect.
  • status: Complete
  • log: Added HarnessApi, bearer security middleware, and makeHarnessClient backed by Effect's fetch HTTP client.
  • files edited/created: packages/contract/src/api.ts, packages/contract/src/security.ts, packages/contract/src/client.ts, packages/contract/src/index.ts, packages/contract/package.json
  • backlog_item_id: IP-112, IP-113, IP-114
  • backlog_item_url: https://linear.app/devpunks/issue/IP-114/cli-uses-typed-effect-client-instead-of-raw-untyped-http-for-control
  • relation_mode: native
  • assigned_skills: effect-authoring, quality-types, tdd, simplify
  • tdd_target: Typed client creation requires the shared HarnessApi shape and supports bearer credentials without raw request strings at call sites.
  • review_mode: cli

T3: Implement contract in apps/api

  • depends_on: [T2]
  • location: apps/api
  • description: Replace the temporary Hono contract boundary with Effect HttpApiBuilder handlers for baseline resolution, artifact metadata, and health. Keep behavior intentionally minimal until storage/backend stories exist.
  • validation: bun run check-types --filter=@punks/api, bun run build --filter=@punks/api, focused API tests if introduced.
  • status: Complete
  • log: Replaced the Hono scaffold boundary with Effect HttpApiBuilder groups and a Bun web handler. API tests verify health and auth-required baseline behavior.
  • files edited/created: apps/api/src/index.ts, apps/api/src/index.test.ts, apps/api/package.json
  • backlog_item_id: IP-97, IP-112, IP-113
  • backlog_item_url: https://linear.app/devpunks/issue/IP-97/define-shared-effect-api-contract-boundary
  • relation_mode: native
  • assigned_skills: effect-authoring, effect-backend-structure, quality-types, tdd, simplify
  • tdd_target: API implementation imports only @punks/contract for API shape and provides Effect handlers/layers for every endpoint.
  • review_mode: cli

T4: Add CLI typed control-plane adapter

  • depends_on: [T2]
  • location: apps/cli
  • description: Add an Effect-native adapter for baseline/artifact control-plane calls using the shared client factory. Do not remove existing GitHub/bundled fallback behavior.
  • validation: bun run test --filter=@punks/cli and CLI typecheck.
  • status: Complete
  • log: Added apps/cli/src/control-plane/client.ts and wired optional control-plane baseline metadata resolution into the existing resolver before GitHub fallback.
  • files edited/created: apps/cli/src/control-plane/client.ts, apps/cli/src/baseline/resolve.ts, apps/cli/src/baseline/resolve.test.ts, apps/cli/package.json
  • backlog_item_id: IP-114
  • backlog_item_url: https://linear.app/devpunks/issue/IP-114/cli-uses-typed-effect-client-instead-of-raw-untyped-http-for-control
  • relation_mode: native
  • assigned_skills: effect-authoring, quality-types, tdd, simplify
  • tdd_target: New control-plane calls are expressed through @punks/contract typed client methods; no new raw fetch path is added for control-plane behavior.
  • review_mode: cli

T5: Review, docs-ingest-phase, validation, and Linear closeout

  • depends_on: [T3, T4]
  • location: packages/contract, apps/api, apps/cli, apps/wiki, docs, Linear IP-97/IP-112/IP-113/IP-114
  • description: Run findings-first review with relevant skills, resolve each issue before docs-ingest-phase/commit, ingest durable wiki concepts/flows, validate root tasks, commit, and close Linear only after evidence is complete.
  • validation: Review issue list closed or explicitly deferred with Linear/spec-backed rationale; bun run check, bun run check-types, bun run test, bun run build, git diff --check.
  • status: Complete
  • log: Review found two issues: control-plane failures skipped GitHub fallback, and implementation notes lacked the manual review checklist. Both were fixed before docs-ingest-phase and final validation. docs-ingest-phase wrote one flow and three concepts.
  • files edited/created: apps/wiki/specs/cli/IP-97-effect-api-contract-boundary/**, apps/wiki/content/docs/cli/**, apps/wiki/content/docs/cli/**, docs/README.md, docs/runbooks/dp-cli-scaffolding.md
  • backlog_item_id: IP-97
  • backlog_item_url: https://linear.app/devpunks/issue/IP-97/define-shared-effect-api-contract-boundary
  • relation_mode: native
  • assigned_skills: parallel-research, effect-review, simplify, improve-codebase-architecture, docs-ingest-phase, tdd
  • tdd_target: Closeout evidence links each child issue acceptance signal to repository changes and passing validation.
  • review_mode: cli

Testing Strategy

  • Add package-local tests before relying on root validation.
  • Use @effect/vitest for Effect-shaped tests.
  • Run targeted package typechecks/builds during implementation.
  • Finish with bun run check, bun run check-types, bun run test, bun run build, and git diff --check.

Risks and Mitigations

  • Effect HttpApi syntax drift: use cached Effect 3.21.2 source/tests before editing and validate with TypeScript.
  • Over-scoping backend behavior: implement minimal shape-level handlers and defer storage to later stories.
  • Breaking current CLI baseline behavior: add typed adapter beside the existing resolver and keep GitHub/bundled fallback intact.
  • Auth coupling to Better Auth: model bearer credentials and auth failures in the contract only.

Validation Gates

  • Gate 1: Contract package exports typed schemas, errors, API, security, and client.
  • Gate 2: API and CLI both import @punks/contract and typecheck.
  • Gate 3: Review findings are fixed or explicitly deferred before docs-ingest-phase.
  • Gate 4: Root validation passes before commit and Linear closeout.

Unresolved Questions

None for IP-97. Exact backend persistence and release-artifact storage remain deferred beyond this contract boundary.

On this page