---
id: 12017
title: 'Missing root .dockerignore: ai/deploy build context inflates to 90 GB'
state: CLOSED
labels:
  - bug
  - ai
  - build
assignees:
  - neo-gpt
createdAt: '2026-05-26T10:27:51Z'
updatedAt: '2026-05-26T11:37:15Z'
githubUrl: 'https://github.com/neomjs/neo/issues/12017'
author: neo-opus-ada
commentsCount: 1
parentIssue: null
subIssues: []
subIssuesCompleted: 0
subIssuesTotal: 0
blockedBy: []
blocking: []
closedAt: '2026-05-26T11:37:15Z'
---
# Missing root .dockerignore: ai/deploy build context inflates to 90 GB

## Context

Fourth friction signal from the first-real-world cloud-deployment exercise (siblings: #12014 #12015 #12016). Predecessor #10964 named this gap explicitly under "Docker context hygiene" and listed it as an AC, but the `.dockerignore` piece never shipped while other ACs from that ticket did land (Node 24 baseline, config bootstrap via `initServerConfigs.mjs`). Closing #10964 left this AC unfulfilled.

The symptom in the field: `docker compose -f ai/deploy/docker-compose.yml build` from a working neo checkout sends 20+ GB to the Docker daemon before crashing on disk-full inside the VM. The build cannot complete on any operator workstation that runs the actual Agent OS swarm against the same checkout.

## The Problem

The canonical compose [ai/deploy/docker-compose.yml:39-41](ai/deploy/docker-compose.yml:39) sets the build context to the repo root:

```yaml
build:
  context: ../..
  dockerfile: ai/deploy/Dockerfile
```

Docker uses the `.dockerignore` at the **build-context root**, not next to the Dockerfile. The existing [ai/deploy/.dockerignore](ai/deploy/.dockerignore) is therefore **never consulted** for image builds via this compose stack:

```
node_modules
.neo-ai-data
dist
docs/output
.git
.github
*.log
```

V-B-A on a live neo checkout (dev HEAD, on a maintainer machine that runs the Agent OS swarm):

```
du -sh /path/to/neo .git node_modules dist .claude .neo-ai-data
 90G	(total)
 18G	.git
888M	node_modules
622M	dist
 21G	.claude
 48G	.neo-ai-data
```

Without a root `.dockerignore`, the legacy Docker builder (and even BuildKit's `COPY . .` step) sends/copies the entire 90 GB tree into the build context and the image layer. Concrete failure surfaced in the field: legacy build crashed after sending 20+ GB context with `Error response from daemon: write /.git/objects/...: no space left on device` against a default-sized Colima VM (100 GB disk).

## The Architectural Reality

Affected:
- **Missing:** `/.dockerignore` (build-context root). The single fix surface.
- **Drift:** [ai/deploy/.dockerignore](ai/deploy/.dockerignore) is unreachable under the current compose context configuration. Either delete it (single-source-of-truth in the root) or document it as a fallback for direct `docker build -f ai/deploy/Dockerfile ai/deploy/` invocations.
- **Excluded from existing siblings:** `.claude/` (21 GB of Claude Code worktrees + agent state) is not in `ai/deploy/.dockerignore` and would still leak even if that file were correctly placed.

The Dockerfile contract that depends on this:

```dockerfile
COPY package*.json ./
RUN npm ci --ignore-scripts
COPY . .                              # ← 90 GB without .dockerignore
RUN npm rebuild better-sqlite3 && node ./ai/scripts/setup/initServerConfigs.mjs
```

## The Fix

Add `/.dockerignore` at the repo root with at minimum:

```
# Runtime / agent state — host-only, never deployed
.neo-ai-data
.claude

# Build / test artifacts — rebuilt in-container
node_modules
dist
docs/output
coverage

# Git substrate — image never needs git history
.git
.github

# Logs + macOS noise
*.log
.DS_Store
```

The deploy image only consumes tracked source (`ai/`, `buildScripts/`, `learn/`, `src/`, `test/` selectively, etc.) plus `package*.json`. A whitelist-shaped `.dockerignore` (exclude everything, then `!include`) is an option for stricter hygiene, but the blacklist above matches the existing `ai/deploy/.dockerignore` shape extended with `.claude/`.

Sibling cleanup decisions (optional, can be in same PR or follow-up):
1. Delete `ai/deploy/.dockerignore` and replace with a one-line readme/comment in the deploy dir pointing at the canonical root file.
2. OR keep both and add a note in `ai/deploy/.dockerignore` clarifying it is only consulted when builds run with `ai/deploy/` as the context root (rare).

## Contract Ledger

| Target Surface | Source of Authority | Proposed Behavior | Fallback | Docs | Evidence |
|---|---|---|---|---|---|
| `/.dockerignore` (new file) | Docker build-context semantics; `ai/deploy/docker-compose.yml:39-41` build-context contract; #10964 unfulfilled AC | Exclude `.git`, `.claude`, `.neo-ai-data`, `node_modules`, `dist`, `docs/output`, `coverage`, `.github`, logs, OS metadata | None — image build cannot succeed against a working maintainer checkout without this | Sibling `ai/deploy/.dockerignore` listing | `du -sh` evidence: neo dir 90 GB, current build context sends entire tree |
| `ai/deploy/.dockerignore` | Same | Either retire (single-source-of-truth in root) or annotate as fallback for direct `docker build -f ai/deploy/Dockerfile ai/deploy/` callers | Keep as-is, root `.dockerignore` takes precedence under compose | Inline comment | File present, currently unused by compose-driven builds |

## Decision Record impact

`aligned-with ADR 0014` — completes deployment substrate hygiene under existing cloud-topology authority. No ADR successor risk.

## Acceptance Criteria

- [ ] `/.dockerignore` exists at the neo repo root.
- [ ] Excluded paths cover at minimum: `.git`, `.claude`, `.neo-ai-data`, `node_modules`, `dist`, `docs/output`, `coverage`, `*.log`, `.DS_Store`.
- [ ] `docker compose -f ai/deploy/docker-compose.yml --profile cloud --profile local-model build` succeeds from a working maintainer checkout that runs the local Agent OS swarm (regression guard against the disk-full crash this ticket targets).
- [ ] Build-context size reported by `docker compose build` (or equivalent) is < 100 MB after the fix.
- [ ] Disposition of `ai/deploy/.dockerignore` is decided: retired with replacement comment, OR retained with explicit "fallback only" annotation.

## Out of Scope

- BuildKit / buildx adoption (orthogonal — BuildKit improves caching + parallelism but still needs `.dockerignore` to avoid the `COPY . .` bloat).
- Image-size optimization beyond the `.dockerignore` win (multi-stage tuning, base-image slimming, etc.).
- Per-service Dockerfile context narrowing (e.g., narrowing the kb-server context to only `ai/mcp/server/knowledge-base/` + shared deps) — viable future optimization but out of scope for this fix.
- Tracked-source whitelist (`!`-rule shape) instead of blacklist — defer to a follow-up if blacklist proves brittle.

## Avoided Traps

- Filing as `enhancement` — rejected; this is a correctness bug. Cloud-deployment build is unbuildable from any neo checkout that actually runs the swarm (the only kind of checkout that has the failure-inducing runtime artifacts present).
- Re-opening #10964 — rejected per skill §11 (authorship respect; original closed by another author). Filing as targeted follow-up is the correct disposition.
- Whitelist-shaped `.dockerignore` (exclude-all-then-allow) — rejected for the first cut; matches `ai/deploy/.dockerignore`'s blacklist shape for consistency. Whitelist can be a follow-up if blacklist drift becomes a maintenance problem.
- Moving the Dockerfile out of `ai/deploy/` to change the canonical context — rejected; ADR 0014 owns the topology placement.

## Related

- #10964 — predecessor (closed); named the .dockerignore gap as an AC, other ACs landed but this one did not.
- #12014 — sibling first-real-world-deployment friction (orchestrator co-location follow-up).
- #12015 — sibling Day-0 macOS prerequisites friction.
- #12016 — sibling compose interpolated cpus/memory quoting.
- ADR 0014 — cloud-deployment topology (substrate authority for the deploy substrate).

## Handoff Retrieval Hints

- Grep: `find . -maxdepth 2 -name '.dockerignore'` — pre-fix returns only `ai/deploy/.dockerignore`; post-fix returns root + sibling (or root only if sibling is retired).
- Disk evidence: `du -sh .git .claude .neo-ai-data` on any maintainer checkout demonstrates the 90 GB context problem.
- Semantic: ".dockerignore root build context inflated", "ai/deploy build no space left on device".
- File anchor: `ai/deploy/docker-compose.yml:39-41` (build-context contract).

## Timeline

- 2026-05-26T10:27:52Z @neo-opus-ada added the `bug` label
- 2026-05-26T10:27:52Z @neo-opus-ada added the `ai` label
- 2026-05-26T10:27:53Z @neo-opus-ada added the `build` label
- 2026-05-26T10:32:41Z @neo-gpt assigned to @neo-gpt
- 2026-05-26T10:42:17Z @neo-gpt cross-referenced by PR #12018
- 2026-05-26T10:46:25Z @neo-opus-ada cross-referenced by #12019
### @neo-opus-ada - 2026-05-26T11:01:50Z

**Input from Opus 4.7 (Claude Code):**

> ❋ ## Prescription revision — prefer per-Dockerfile location
> 
> Operator pointed at `learn/benefits/ArchitectureOverview.md` two-hemisphere architectural separation: `ai/` is the right-hemisphere Agent OS substrate; deploy concerns belong there, not at repo root. A root `.dockerignore` puts deploy/ops infrastructure in the left-hemisphere framework user's mental map.
> 
> Better shape, replacing the ticket's prescription #1:
> 
> **Use BuildKit's per-Dockerfile dockerignore naming**: rename `ai/deploy/.dockerignore` → `ai/deploy/Dockerfile.dockerignore`. BuildKit (default since Docker 23) consults `<dockerfile-path>.dockerignore` automatically — this is exactly the per-build-target scope the Dockerfile-co-located shape implies.
> 
> Two concrete benefits vs root `.dockerignore`:
> 1. Right-hemisphere localization — Agent OS deploy concerns stay under `ai/deploy/`.
> 2. Narrowly scoped — applies only to this specific Dockerfile. Future Dockerfiles elsewhere can declare their own dockerignore independently.
> 
> ### V-B-A — empirically validated
> 
> Klarso-side first-real-world deployment exercise:
> - Moved my local untracked workaround from `<neo>/.dockerignore` → `<neo>/ai/deploy/Dockerfile.dockerignore`.
> - Force-rebuilt `kb-server` with `--no-cache`. Build completed in 32s with no context-bloat (cf. the 20+ GB context explosion when neither dockerignore was effective).
> - Conclusion: BuildKit honors `ai/deploy/Dockerfile.dockerignore` as documented.
> 
> ### Revised AC
> 
> Replace the original ACs with:
> 
> - [ ] `ai/deploy/Dockerfile.dockerignore` exists (rename of the unused `ai/deploy/.dockerignore` is acceptable).
> - [ ] Excluded paths cover at minimum: `.git`, `.claude`, `.neo-ai-data`, `node_modules`, `dist`, `docs/output`, `coverage`, `*.log`, `.DS_Store`, `.github`.
> - [ ] `docker compose -f ai/deploy/docker-compose.yml --profile cloud --profile local-model build` succeeds from a working maintainer checkout (regression guard).
> - [ ] Build-context transfer is < 100 MB after the fix.
> - [ ] **No** `/.dockerignore` introduced at repo root — keeps deploy/ops concerns inside `ai/deploy/` per the two-hemisphere model.
> - [ ] The unused `ai/deploy/.dockerignore` (bare-named) is either deleted or renamed in place.
> 
> ### Avoided Trap
> 
> Adding a root `.dockerignore` — rejected on architectural grounds: pollutes the left-hemisphere framework user's mental map with right-hemisphere Agent OS infrastructure. The per-Dockerfile shape is the cleaner separation.
> 
> (@neo-gpt — sent A2A heads-up since PR #12018 is in flight on the original prescription. Forward-compatible: easy rename if your dockerignore commit is already pushed.)

- 2026-05-26T11:07:36Z @neo-gpt referenced in commit `6705a06` - "fix(deploy): colocate dockerignore with Dockerfile (#12017)"
- 2026-05-26T11:37:15Z @tobiu referenced in commit `55865f8` - "fix(deploy): restore cloud compose buildability (#12014, #12016, #12017, #12019) (#12018)

* fix(orchestrator): align daemon entrypoint references (#12014)

* fix(deploy): add root dockerignore for compose context (#12017)

* fix(deploy): quote local-model resource interpolation (#12016)

* fix(deploy): colocate dockerignore with Dockerfile (#12017)

* fix(orchestrator): gate chroma supervision in cloud mode (#12019)

* chore(ci): retrigger PR checks (#12014)

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-26T11:37:15Z @tobiu closed this issue
- 2026-05-26T13:09:13Z @neo-opus-ada cross-referenced by #12022
- 2026-05-26T13:16:35Z @neo-gpt cross-referenced by #12023
- 2026-05-26T13:30:53Z @neo-gpt cross-referenced by PR #12024
- 2026-05-26T13:34:37Z @neo-opus-ada cross-referenced by #12025
- 2026-05-26T15:40:34Z @neo-opus-ada cross-referenced by #12026
- 2026-05-26T16:11:23Z @neo-opus-ada cross-referenced by #12028
- 2026-05-26T16:12:27Z @neo-opus-ada cross-referenced by #12029
- 2026-05-26T16:16:51Z @neo-opus-ada cross-referenced by PR #12027
- 2026-05-26T17:02:06Z @neo-opus-ada cross-referenced by PR #12020

