IMPORTANT: Developer documentation for the current development branch. This content is unreleased, may change without notice, and must not be treated as Buildish release documentation.
CI Abstraction Layer
Overview
The action is built around a strict boundary between CI-platform-specific adapters and a shared core.
All platform knowledge lives in src/ci/. The shared core in src/phases/ never imports from
src/ci/ — it only depends on abstract interfaces.
graph TD
subgraph "CI adapters (src/ci/github/)"
GH_MAIN["main.ts\nrunPrepareExecution()"]
GH_POST["post.ts\nrunFinalizeExecution()"]
GH_HOST["host.ts\nHostReporter + HostStateStore"]
GH_CACHE["cache.ts\nBaseCacheBackend"]
GH_ARTS["artifacts.ts\nWorkflowArtifactBackend"]
GH_RPT["report-sink.ts\nReportSink"]
GH_PROV["provider.ts\nCiPlatformAdapter"]
end
subgraph "Shared interfaces"
I_HOST["src/host/types.ts\nHostReporter, HostStateStore\nHostInputSource, HostOutputSink\nReportSink"]
I_CACHE["src/cache/backend.ts\nBaseCacheBackend"]
I_ARTS["src/delta/backend.ts\nWorkflowArtifactBackend"]
I_CI["src/ci/types.ts\nCiPlatformAdapter\nCiJobContext"]
end
subgraph "Shared core (src/phases/)"
BOOT["bootstrap.ts"]
PREP["prepare/flow.ts"]
FIN["finalize/flow.ts"]
end
GH_MAIN --> I_HOST
GH_MAIN --> I_CACHE
GH_MAIN --> I_ARTS
GH_MAIN --> I_CI
GH_POST --> I_HOST
GH_POST --> I_CACHE
GH_POST --> I_ARTS
GH_POST --> I_CI
I_HOST --> BOOT
I_CACHE --> BOOT
I_ARTS --> BOOT
I_CI --> BOOT
BOOT --> PREP
BOOT --> FIN
The shared seam
A CI adapter must supply implementations of five interfaces before calling into the shared core:
| Interface | Defined in | Purpose |
|---|---|---|
HostReporter |
src/host/types.ts |
Write log lines and group markers to the CI log |
HostStateStore |
src/host/types.ts |
Persist and retrieve cross-phase state |
HostInputSource |
src/host/types.ts |
Read action inputs from the CI environment |
HostOutputSink |
src/host/types.ts |
Write action outputs back to the CI environment |
ReportSink |
src/host/types.ts |
Write job summaries / reports |
BaseCacheBackend |
src/cache/backend.ts |
Save and restore the base cache |
WorkflowArtifactBackend |
src/delta/backend.ts |
Upload, list, and download delta artifact packages |
CiPlatformAdapter |
src/ci/types.ts |
Expose CiJobContext (job/run identity and source revision when available) |
The shared core receives these as plain dependency-injection arguments. No global state; no environment variable reads after the adapter layer.
Provider boundary rules
These rules keep CI-specific logic out of the shared core and make it possible to add new provider adapters without touching phase logic.
What belongs in src/ci/<provider>/
- Reading CI-specific environment variables.
- Constructing
CiJobContextfrom CI metadata (runner info, run IDs, job names). - Implementing
BaseCacheBackendusing the provider’s cache API. - Implementing
WorkflowArtifactBackendusing the provider’s artifact API. - Implementing
HostReporter,HostStateStore,HostInputSource,HostOutputSinkusing provider-specific mechanisms (e.g.@actions/corefor GitHub Actions). - Implementing
ReportSinkfor provider-specific summary output.
What must NOT be in src/ci/<provider>/
- Cache key computation, partition fingerprint calculation, manifest capture, or delta computation.
- Wrapper discovery or verification.
- Any decision about whether to save or skip the base cache.
- Any decision about whether to upload or skip a delta artifact.
Those decisions belong in src/phases/ and draw only on the abstract interface contracts.
What must NOT be in src/phases/
- Any import from
src/ci/. - Any reference to a specific CI provider’s API, SDK, or environment variable names.
- Any fallback behavior that assumes a specific provider.
This boundary is enforced by TypeScript’s module system: the shared core only knows the interface shapes, never the concrete implementations.
Adding a new provider
- Create
src/ci/<provider>/with implementations for each interface in the seam table above. - Create phase entrypoints (equivalent to
src/ci/github/main.tsandsrc/ci/github/post.ts) that construct the concrete implementations and pass them torunPrepareExecution()/runFinalizeExecution(). - Create an action directory under
actions/<provider>/<build-tool>/with anaction.yml(equivalent toactions/github/gradle/) for the CI platform’s action descriptor files. - No changes to
src/phases/,src/cache/,src/delta/, orsrc/config/should be needed unless the new provider reveals a missing abstraction.
See Provider portability for the current status of planned provider support.