Local deploy (the dev loop)¶
The fastest way to validate a change end-to-end against leoflow lite โ
without going through git tag, the release pipeline, install-smoke, or
curl | sh. The script is scripts/lite-redeploy.sh, wired as a
Makefile target.
When to use¶
- Validating a Go change in the control plane, the agent, or the CLI
against a real
leoflow liteboot. - Reproducing a runtime bug a user reported, without round-tripping through the release machinery.
- Smoke-testing a fix BEFORE cutting a tag โ keeps prealpha tags clean.
This is not an install path. Real users still install via
install.sh from a published release (see docs/installation.md).
What it does¶
- Builds
leoflow,leoflow-server, andleoflow-agentfrom the current working tree (nogit tagneeded). - Ad-hoc code-signs the binaries on macOS so the OS does not
SIGKILL them at exec (Sequoia 14+ refuses to run an unsigned binary
that carries
com.apple.provenanceโ silent failure mode with exit 137 and no log output). - Stops any running
leoflow lite(via the script's pidfile, with apkill -f "leoflow lite"fallback). - Swaps the binaries in both locations
leoflow literesolves them from โ./bin/(the repo's local bin, preferred byresolveBinaryininternal/cli/dev.go) and~/.leoflow/bin/(the user-install location). Keeping them in lockstep is critical: if only one is updated the stale one silently runs and the dev loop becomes confusing fast (this happened โ see the commit that added the script). - Starts
leoflow lite --postgres managed(a docker-free local Postgres on a Unix socket, so the loop does not collide with anypostgres:16you already have on 5432). - Polls
/readyzand reports the boot URL + PID + log path.
Usage¶
make lite-redeploy # rebuild, restart, tail-ready
PORT=9090 make lite-redeploy # custom HTTP port
LOG_LEVEL=debug make lite-redeploy # verbose
After it returns:
# log tail (boot lines, http requests, executor activity)
tail -f /tmp/leoflow-lite.log
# get / rotate the admin password
~/.leoflow/bin/leoflow lite reset-password
# stop
kill "$(cat /tmp/leoflow-lite.pid)"
The two-binary trap (why this script exists)¶
leoflow lite is a thin orchestrator: it spawns leoflow-server as a
subprocess. The Subprocess executor (the dev-only path that runs your
Python tasks) in turn spawns leoflow-agent. So a single leoflow lite
process tree uses all three binaries:
leoflow lite (CLI / orchestrator)
โโโ leoflow-server (control plane HTTP + gRPC + scheduler)
โโโ leoflow-agent (per-task subprocess; runs the user's dag.py)
If you rebuild only leoflow (the CLI) but leave a stale leoflow-server
behind, lite still boots โ but the control plane that actually handles
requests is the OLD code. Symptom: your code change "doesn't show up"
and you waste 30 minutes second-guessing the test. The script avoids
this by rebuilding and swapping all three on every invocation.
How this fits the GitOps flow¶
| Layer | Tool | Triggered by | Validates |
|---|---|---|---|
| Local dev loop | make lite-redeploy |
manual make |
a change runs against a real leoflow lite |
| PR CI | .github/workflows/ci.yaml |
pull_request |
unit + integration + lint + e2e on the PR HEAD |
| Release CI | .github/workflows/release.yaml |
push: tags: v* |
the published binaries install, boot, and upgrade cleanly across 7 distros |
The local loop is the inner ring โ it catches "does my change boot at all" in seconds, before you push. The release smoke jobs are designed for stable releases; they retract a published tag to a draft on any failure. Using the local loop first keeps prealpha tags clean and avoids the retract / re-cut churn.
If you find yourself cutting a prealpha purely to test a Lite change,
that is a smell โ make lite-redeploy will give you the same
validation in seconds without burning a tag number.