Context
Surfaced during a real-time dogfood of #12146 on a cloud Agent OS deployment. The deployment's images build neo from a co-located local checkout (NEO_SOURCE_DIR, default ../../../../github/neomjs/neo). Two failure modes fell out immediately:
- A second operator cannot deploy. Anyone without that exact co-located checkout has no build context — the relative path resolves to nothing, and
docker compose build fails. The deployment is only buildable on the original author's machine.
- The deployed neo version is "whatever the local checkout happens to be." During the dogfood the co-located checkout was on an unrelated feature branch with uncommitted WIP — so a rebuild would have baked another lane's untested working tree into the deployment image, and still lacked the merged fix being dogfooded.
The Problem
The canonical ai/deploy build sources neo via Docker COPY . . of a local build context — there is no git clone, no pinned ref. Consequences:
- Non-portable — requires a co-located neo checkout at a hardcoded relative path on the build host. The Day-0 docs list "clone + co-locate a neo checkout" as a manual prerequisite, which is the smell.
- Non-reproducible — the image contents equal the local working tree at build time, including uncommitted changes and whatever branch is checked out. Two builders produce different images.
- Version-coupled to local branch state — the deployment's neo version is implicit and mutable, not declared.
neo is MIT-licensed, so cloning + baking the source into the deploy image has no license barrier.
The Architectural Reality
ai/deploy/Dockerfile:15 — COPY . . from the build context (no source acquisition step).
ai/deploy/docker-compose.yml — context: ../.. (canonical); deployment overlays set context: ${NEO_SOURCE_DIR:-<local path>}.
git is available in alpine via apk, so a build-time clone is feasible without changing the base image family.
The Fix
For cloud / portable deployments, acquire neo from a pinned GitHub ref at build time instead of COPY . . from a local folder:
- Add a source-acquisition step (build
ARG NEO_REF + optional ARG NEO_REPO_URL=https://github.com/neomjs/neo) that git clones neo at the pinned ref into the build stage. A shallow clone (--depth 1 --branch <ref>) also sidesteps the #12017 local-context-bloat problem by construction.
- Prefer a tag or commit SHA for reproducibility; a branch ref (e.g.
dev) is acceptable only as an explicit interim for branch-tracking deployments, with the mutability tradeoff documented.
- Keep a local-source mode for fast dev iteration (explicit
NEO_SOURCE=git-ref|local), so the convenience of the co-located checkout is preserved without being the only path.
- Update the Day-0 / deployment docs: the co-located checkout becomes a dev convenience, not a deployment prerequisite.
Acceptance Criteria
Out of Scope
- Sourcing neo from a published npm package or a prebuilt neo base image — a heavier, longer-term evolution; this ticket is the immediate portability fix (pinned clone).
- Choosing the specific release tag for any given deployment — operator config, not a code change.
Avoided Traps
- ❌ Pinning to a mutable branch as the default — undermines reproducibility; default to tag/SHA, branch only as a documented interim.
- ❌ Removing the local-
COPY path entirely — it's the right tool for dev iteration; make source-mode explicit instead of replacing one coupling with another.
Decision Record impact
aligned-with ADR 0014 (cloud deployment topology) — refines the neo-sourcing model the deployment topology depends on. If ADR 0014 codified the co-located-checkout model explicitly, this amends that detail.
Related
- #12017 (missing root
.dockerignore → 90 GB build context) — same local-COPY . root mechanism, different facet (size); a shallow pinned clone addresses both.
- ADR 0014 (cloud deployment topology + scheduler task taxonomy).
- Surfaced during the #12146 (pull-mode
tenantRepos tiered resolver) real-time dogfood.
Handoff Retrieval Hints
- Retrieval Hint: "cloud deploy neo source local folder COPY vs pinned github clone reproducible portable"
Context
Surfaced during a real-time dogfood of #12146 on a cloud Agent OS deployment. The deployment's images build neo from a co-located local checkout (
NEO_SOURCE_DIR, default../../../../github/neomjs/neo). Two failure modes fell out immediately:docker compose buildfails. The deployment is only buildable on the original author's machine.The Problem
The canonical
ai/deploybuild sources neo via DockerCOPY . .of a local build context — there is nogit clone, no pinned ref. Consequences:neo is MIT-licensed, so cloning + baking the source into the deploy image has no license barrier.
The Architectural Reality
ai/deploy/Dockerfile:15—COPY . .from the build context (no source acquisition step).ai/deploy/docker-compose.yml—context: ../..(canonical); deployment overlays setcontext: ${NEO_SOURCE_DIR:-<local path>}.gitis available in alpine viaapk, so a build-time clone is feasible without changing the base image family.The Fix
For cloud / portable deployments, acquire neo from a pinned GitHub ref at build time instead of
COPY . .from a local folder:ARG NEO_REF+ optionalARG NEO_REPO_URL=https://github.com/neomjs/neo) thatgit clones neo at the pinned ref into the build stage. A shallow clone (--depth 1 --branch <ref>) also sidesteps the #12017 local-context-bloat problem by construction.dev) is acceptable only as an explicit interim for branch-tracking deployments, with the mutability tradeoff documented.NEO_SOURCE=git-ref|local), so the convenience of the co-located checkout is preserved without being the only path.Acceptance Criteria
Out of Scope
Avoided Traps
COPYpath entirely — it's the right tool for dev iteration; make source-mode explicit instead of replacing one coupling with another.Decision Record impact
aligned-with ADR 0014(cloud deployment topology) — refines the neo-sourcing model the deployment topology depends on. If ADR 0014 codified the co-located-checkout model explicitly, this amends that detail.Related
.dockerignore→ 90 GB build context) — same local-COPY .root mechanism, different facet (size); a shallow pinned clone addresses both.tenantRepostiered resolver) real-time dogfood.Handoff Retrieval Hints