Build a governed image in CI
Wrap your agent's unchanged image with the initializ governance layer in CI — the wrapper Dockerfile, the build-wrap-push-deploy pipeline, and what the governed loader records and enforces at runtime.
A CI-deployed claude-agent
brings its own image — so governance has to reach that image in your
pipeline. This guide adds it as a wrapper build step: your
application's Dockerfile, source, and package.json stay completely
unchanged, and a second docker build layers the governance package on
top. A vanilla Claude Agent SDK service that imports nothing from
initializ gets full outbound governance — audit, policy checks, managed
model access — from this step alone.
Before you start
- A CI pipeline that builds and deploys the agent with the
initializCLI — see Deploy a CI-built agent for tokens, registry setup, and the deploy job. - The governance package image reference for your platform environment
(
claude-agent-pkg) — ask your platform operator; it's a normal image your CI can pull.
Step 1 — add the wrapper Dockerfile
Commit this alongside your own Dockerfile (by convention at
deploy/initializ-governance.Dockerfile); it never changes per agent:
ARG AGENT_IMAGE
ARG PKG_IMAGE=ghcr.io/initializ/claude-agent-pkg:v0
FROM ${PKG_IMAGE} AS gov
FROM ${AGENT_IMAGE}
COPY --from=gov /opt/initializ /opt/initializ
ENV NODE_OPTIONS="--import /opt/initializ/dist/register.js"Three lines do all the work:
AGENT_IMAGEis your image, unchanged — whatever your own Dockerfile produced.COPY --from=gov /opt/initializ /opt/initializadds the governance package: a self-contained directory with the loader and its bundled dependencies. It resolves nothing from yournode_modules, so your dependency tree is untouched — no@initializpackage to install.ENV NODE_OPTIONS="--import /opt/initializ/dist/register.js"activates the loader in whatevernode(ortsx) process yourCMD/ENTRYPOINTruns — you don't need to know or change the start command. The loader intercepts the@anthropic-ai/claude-agent-sdkyour app installed, so the SDK must stay a regular dependency (not bundled into your build output).
The final stage is a normal Dockerfile stage, so agent-specific
adjustments can ride along when the base image needs them — real
pipelines use it to restate a named USER numerically (so Kubernetes can
verify non-root) or to set the CMD when the base image leaves it
unset.
No platform configuration is baked here: identity, the model gateway endpoint and credential, policy, and audit wiring are all injected at deploy time — the image carries no LLM credentials and no environment-specific values, so one governed image promotes across environments.
Step 2 — wire it into the pipeline
The pipeline becomes build → wrap → push → deploy:
# 1) the agent's own image — its Dockerfile is untouched
docker build -t "agent-base:${BUILD_ID}" .
# 2) wrap it with the governance layer
docker build \
--build-arg AGENT_IMAGE="agent-base:${BUILD_ID}" \
--build-arg PKG_IMAGE="${PKG_IMAGE}" \
-f deploy/initializ-governance.Dockerfile \
-t "${IMAGE_REPO}:${TAG}" .
# 3) push the governed image
docker push "${IMAGE_REPO}:${TAG}"
# 4) deploy it
initializ agent deploy -f initializ-deploy.yaml --image "${IMAGE_REPO}:${TAG}"Only the wrapped image is pushed and deployed — the intermediate
agent-base tag stays local to the build. The deploy spec's
agent.type: claude-agent tells the platform how to run it; see
the claude-agent runtime reference
and the
complete pipeline examples
for the surrounding job.
What the governed loader adds
Once deployed, the loader in the image governs the agent's outbound behavior with zero app awareness:
- Audit of every model and tool call. Each run appears as its own invocation timeline, with token usage recorded cache-inclusively and attributed to model and provider, and the execution list and per-run transcript populated in the console — see what the platform records for every run.
- Policy enforcement on tool calls. Every tool call is checked
against the agent's policy baseline, and calls on governed connections
are additionally checked online against the platform's policy decision
point — see
governing a tool with compliance policies.
The
INITIALIZ_ENFORCEMENTenv in the deploy spec picks the mode:audit_only(the scaffold default) decides and records but never blocks;enforceblocks denials and turns deferrals into approvals. - Managed model access. Model traffic is pinned to the
platform-managed gateway named by the spec's
model.provider— the app cannot pick its own endpoint or key, and the credential never exists in the repo or image. - Platform identity. The agent carries a platform workload identity, so its calls are attributed to the right organization, workspace, and agent.
A2A composes with this — it doesn't replace it
@initializ/a2a-kit is not required for this path, and this path is
not made redundant by it: the kit only shapes inbound skills, while the
wrap is what puts governance in the image at all. An agent that does use
a2a-kit ships through this exact same wrapper build — see
Enable A2A on a claude-agent.