forked from molecule-ai/molecule-core
Closes core#116. Brings local-dev iteration parity with the canvas's
Turbopack HMR — edit a Go file, see the platform restart in <5s
instead of running 'docker compose up --build' (~30s) per change.
USAGE
make dev # docker compose with air-driven live reload
make up # production-shape stack (no air, normal Dockerfile)
WHAT THIS ADDS
workspace-server/.air.toml — air watch config
workspace-server/Dockerfile.dev — air-on-golang:1.25-alpine, dev-only
docker-compose.dev.yml — overlay swapping platform service
to Dockerfile.dev + bind-mounting
workspace-server/ source
Makefile — make {dev,up,down,logs,build,test}
WHAT THIS DOES NOT TOUCH
workspace-server/Dockerfile (production multi-stage build)
docker-compose.yml (prod-shape stack)
CI workflows (build prod image directly)
Tenant deployment / SaaS (image swap stays the model)
Pure additive. Existing 'docker compose up' path unchanged; production
stays on the static binary. Air install pinned via go install at image
build time so the dev image is reproducible-enough for local use (we
don't pin air to a SHA — the dev image is rebuilt locally and updates
opportunistically).
PHASE 4 SELF-REVIEW (FIVE-AXIS)
Correctness: No finding — additive change, no existing path modified.
.air.toml watches .go + .yaml under workspace-server/, excludes
_test.go and tests dir so test edits don't trigger rebuild.
Dockerfile.dev mirrors prod's 'go mod download' so first rebuild
is fast.
Readability: No finding — three small files plus a Makefile, each
with header comments explaining the WHY, not just the WHAT. The
Makefile uses the standard ## help-target pattern.
Architecture: No finding — overlay pattern (docker-compose.dev.yml
on top of docker-compose.yml) is the standard compose convention
for env-specific overrides. Doesn't fork the prod path.
Security: No finding because no production code path; dev-only image
isn't built in CI and isn't published to ECR.
Performance: No finding — air debounce=500ms, exclude_unchanged=true
so a save that doesn't change content is a no-op rebuild.
REFS
core#116 — this issue
Companion: core#117 (workspace-side config-watcher for hot-reload of
config.yaml) — different scope; this issue is platform-only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
50 lines
1.5 KiB
TOML
50 lines
1.5 KiB
TOML
# air.toml — live-reload config for local docker-compose dev mode.
|
|
#
|
|
# Active when the platform service runs from workspace-server/Dockerfile.dev
|
|
# (selected via docker-compose.dev.yml overlay). In production, the regular
|
|
# Dockerfile builds a static binary; air is dev-only.
|
|
#
|
|
# Reference: https://github.com/air-verse/air
|
|
|
|
root = "."
|
|
testdata_dir = "testdata"
|
|
tmp_dir = "tmp"
|
|
|
|
[build]
|
|
# Same build invocation as Dockerfile's builder stage minus the
|
|
# CGO_ENABLED=0 toggle (CGO ok in dev for richer race detector output).
|
|
cmd = "go build -o ./tmp/server ./cmd/server"
|
|
bin = "tmp/server"
|
|
full_bin = ""
|
|
args_bin = []
|
|
# Watch every .go and .yaml file under workspace-server/.
|
|
include_ext = ["go", "yaml", "tmpl"]
|
|
# Don't watch tests, build artifacts, vendored deps, or migration .sql
|
|
# (migrations need a clean DB anyway — handled by docker-compose down/up).
|
|
exclude_dir = ["assets", "tmp", "vendor", "testdata", "node_modules"]
|
|
exclude_file = []
|
|
# _test.go and *_mock.go shouldn't trigger a rebuild — saves cycles.
|
|
exclude_regex = ["_test\\.go$", "_mock\\.go$"]
|
|
exclude_unchanged = true
|
|
follow_symlink = false
|
|
log = "build-errors.log"
|
|
# Kill running binary 1s before starting new one.
|
|
kill_delay = "1s"
|
|
send_interrupt = true
|
|
stop_on_error = true
|
|
# Debounce: wait this long after last change before triggering rebuild.
|
|
delay = 500
|
|
|
|
[log]
|
|
time = false
|
|
|
|
[color]
|
|
main = "magenta"
|
|
watcher = "cyan"
|
|
build = "yellow"
|
|
runner = "green"
|
|
|
|
[misc]
|
|
# Don't keep the tmp/ dir around between runs.
|
|
clean_on_exit = true
|