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/contractand 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
| Decision | Status | Rationale |
|---|---|---|
| Contract package owns API shape | Locked | IP-97 requires CLI/API sharing without app imports. |
| API implements with Effect HTTP layers | Locked | M1 notes mark Hono scaffold temporary and future backend direction as Effect HTTP. |
| CLI gets a typed control-plane adapter | Locked | IP-114 requires typed client path while existing baseline fallback remains operational. |
| Backend storage is deferred | Locked | IP-112/IP-97 define shapes and boundaries, not full storage path. |
Codebase Findings
packages/contract/src/index.tsis empty but already has@effect/platformandeffectdependencies.apps/api/src/index.tsis still Hono scaffold code and imports auth/env directly.apps/cli/src/baseline/resolve.tsperforms raw GitHub release lookup/download for the current stable baseline path.apps/clialready 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, andHttpApiClient.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/contractand focused contract tests. - status: Complete
- log: Added contract schemas and API-visible tagged errors in
packages/contract/src/schemas.tsandpackages/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
HarnessApiwith 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, andmakeHarnessClientbacked 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
HarnessApishape 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
HttpApiBuilderhandlers 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
HttpApiBuildergroups 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/contractfor 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/cliand CLI typecheck. - status: Complete
- log: Added
apps/cli/src/control-plane/client.tsand 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/contracttyped client methods; no new rawfetchpath 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-phasewrote 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/vitestfor 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, andgit 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/contractand 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.