agent build

This commit is contained in:
2026-08-28 12:21:44 +05:30
parent b6f8655909
commit f7df96c973
138 changed files with 24164 additions and 207 deletions

View File

@@ -7,13 +7,22 @@
#
# docker build -f infrastructure/Dockerfile.api -t krow-api:latest .
#
# Three binaries ship in the image, because all three are things an operator
# needs against a running deployment and none of them justify a second image:
# EVERY command in go-api/cmd/ ships in the image, built by a loop rather than
# named one at a time. Naming them individually is how the image came to be
# missing `importagents`, and a deployment with no agents published answers every
# Owliver question with "no agent" while looking perfectly healthy — the API is
# up, the database is migrated, and there is simply nothing to run.
#
# /usr/local/bin/api the HTTP service (the default command)
# /usr/local/bin/seed loads the demo fixture
# /usr/local/bin/setpassword sets a user's password — without it a fresh
# database has no one who can sign in
# /usr/local/bin/api the HTTP service (the default command)
# /usr/local/bin/seed loads the demo fixture
# /usr/local/bin/setpassword sets a user's password — without it a fresh
# database has no one who can sign in
# /usr/local/bin/importagents publishes agents/ and skills/ into a tenant
# /usr/local/bin/ingest ingests knowledge/ into a tenant
# /usr/local/bin/reembed re-embeds a tenant's corpus
#
# A new command under cmd/ is shipped automatically. That is the point: what
# exists locally is what exists on the server.
#
# Migrations are deliberately NOT run by this image. They are a discrete deploy
# step against the target database BEFORE the new binary rolls out, which is
@@ -53,16 +62,22 @@ COPY go-api/ ./
# a near-empty image with no libc to keep patched.
# -trimpath keeps build-machine paths out of panics and binaries
# -s -w drops the symbol table and DWARF; roughly a third off the size
# -X main.version stamps the build in, so a running process can say which one
# it is. The arg was declared and plumbed through compose but
# reached no linker flag, so every deployment reported nothing
# and "did my deploy land?" had no answer. A binary with no
# main.version symbol just ignores this.
ARG VERSION=dev
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \
-trimpath -ldflags="-s -w" \
-o /out/api ./cmd/api && \
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \
-trimpath -ldflags="-s -w" -o /out/seed ./cmd/seed && \
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \
-trimpath -ldflags="-s -w" -o /out/setpassword ./cmd/setpassword
set -eux; \
for cmd in ./cmd/*/; do \
name="$(basename "$cmd")"; \
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \
-trimpath -ldflags="-s -w -X main.version=${VERSION}" \
-o "/out/$name" "$cmd"; \
done; \
test -x /out/api
# The golang-migrate CLI, built here rather than pulled as a second image.
#
@@ -102,15 +117,28 @@ FROM alpine:3.20 AS runtime
RUN apk add --no-cache ca-certificates tzdata wget && \
adduser -D -H -u 10001 -s /sbin/nologin krow
COPY --from=build /out/api /usr/local/bin/api
COPY --from=build /out/seed /usr/local/bin/seed
COPY --from=build /out/setpassword /usr/local/bin/setpassword
COPY --from=build /out/migrate /usr/local/bin/migrate
# Everything built above, plus the migrate CLI. One COPY, so adding a command
# needs no change here either.
COPY --from=build /out/ /usr/local/bin/
# The seed fixture, so `seed` works without a bind mount.
COPY seed/fixtures/seed.json /app/seed/fixtures/seed.json
ENV SEED_FIXTURE_PATH=/app/seed/fixtures/seed.json
# The agent specs, skill definitions and knowledge corpus.
#
# importagents and ingest default to ./agents, ./skills and ./knowledge relative
# to the working directory, which is /app below — so the defaults resolve without
# flags. Without these the binaries would ship and have nothing to publish, which
# is the same failure one step later.
#
# They are Markdown, and .dockerignore's `*.md` does NOT exclude them: a
# .dockerignore `*` does not cross a `/`, so that rule only matches Markdown at
# the context root. Verified against the daemon, not assumed.
COPY agents/ /app/agents/
COPY skills/ /app/skills/
COPY knowledge/ /app/knowledge/
# The migration files, so an initContainer can apply them from this image.
# They are read-only at runtime and the process is non-root, so nothing here
# can be rewritten by the service.