Starflow-server state — 2026-05-13 21:30 UTC
2026-05-25 amendment (task M1): the public URL renamed from
starflow-prod.celestialintelligence.co→starflow.celestialintelligence.co(dropping the-prodinternal-env suffix that leaked into customer-visible surfaces). At the same time the server moved behind Caddy on entmoot for HTTPS — previously raw HTTP on port 7702. The old hostname now 301s to the new one + the GitHub webhook (hook id 605920001) was repointed tohttps://starflow.celestialintelligence.co/webhooks/github. References below preserve the historical URL for accuracy.
Discovered while migrating scribe-newswatch off GitHub Actions. Two issues found; one fixed, one captured for next session.
Fixed in this session
Section titled “Fixed in this session”-
GitHub webhook URL was stale. The repo’s webhook (
hooks/605920001) pointed atcelestial-starflow-prod.fly.dev(dead since the Railway migration). Every delivery for ~a month returned 502. Updated tohttps://starflow-server-production.up.railway.app/webhooks/githuband synced theSTARFLOW_WEBHOOK_SECRETbetween Railway env and GitHub config. Ping now returns 200; push events now create pipeline runs. -
Railway watchPatterns on starflow-server were too broad. Included
package-lock.json/package.json/tsconfig.json/packages/storage/**/packages/supabase/migrations/**— almost every commit matched, redeploying starflow-server (and wiping its in-memory run state) on every push. Tightened topackages/starflow-*+ workspace deps + the two yaml configs starflow loads at startup (starflow.yaml,starsystem.prod.yaml).
Update — 2026-05-23
Section titled “Update — 2026-05-23”The two outstanding items below are both resolved:
- Crash-loop on
packages/starflow-*pushes — Dockerfile still hadCOPY starsystem.prod.yamlafter ADR-017 retired the file. Every matched push failed withfailed to compute cache key. Fixed in556346f; Railway watchPatterns also pruned to drop the orphan entry. Deploy5686c87confirmed green. - Runs stuck in ‘running’ forever —
server.ts:259.catch()logged the error but never calledstateAdapter.onRunError(), so any throw beforeengine.ts:220’s graceful-error path left the workflow_runs row atstatus='running'indefinitely. Fixed in5686c87. Failed runs now correctly transition tostatus='error'with the error message persisted.
What this does not fix:
- Whether the Alpine image actually has
bash/git/nodeto run pipelinerun:steps. We’ll find out the next time a real pipeline fires — the error (if any) will now be visible in/api/runs. - Mid-execution hangs (node handler that never throws or returns) — still need a separate timeout mechanism.
Final update — 2026-05-23 (round 3): RESOLVED via Hetzner migration
Section titled “Final update — 2026-05-23 (round 3): RESOLVED via Hetzner migration”Status: fully resolved. starflow-server is off Railway and running on
the existing Hetzner box (entmoot-db-node, 5.161.83.131) alongside
scribe.newswatch. Smoke pipeline completes status=success in ~108ms
with all events persisted. The original “runs hang in ‘running’ forever”
bug is gone — was 100% the stubbed Promise issue from
packages/starflow-server/stubs/.
What the migration shipped:
-
esbuild bundle (commit
e29cdb3).npm run buildnow producesdist/entrypoint.bundle.mjs(6.8 MB, one self-contained file with every@celestial/*workspace dep inlined). Production node never resolves@celestial/storageetc. at runtime. Seepackages/starflow-server/esbuild.config.mjsfor the config + the pinned external native modules. -
Hetzner deploy via ss (overlay in
packages/starflow/starflow.ssmod.yaml).type: external, host: 5.161.83.131._artifact.workspace_packagescollapsed to just@celestial/starflow-server(bundle does the rest)._artifact.cmdpoints at the bundle. Saves ~80% artifact size and eliminates toposort fragility. -
DNS via Cloudflare (NOT Porkbun —
celestialintelligence.conameservers are at CF). A recordstarflow-prod.celestialintelligence.co→ 5.161.83.131, TTL 300, proxied=false (port 7702 needs direct). -
GitHub webhook URL swap (hook id 605920001) from the Railway subdomain to
http://starflow-prod.celestialintelligence.co:7702/webhooks/github. Redelivery test returned 200 immediately. Shared secret was already in the vault; no re-sync needed. -
Railway service deleted (service id
0b5da70a-...). The crash-loop emails are over.
Outstanding follow-ups (small, not blocking):
-
Post-extract
npm rebuildfor native deps. Today this is a manual SSH after eachss artifact deploy— the build machine is darwin-arm64 and ships itsbetter-sqlite3binary, which won’t run on linux-x64. Either add a post-extract hook toss artifact deploy, or setnpm_config_target_platform=linux npm_config_target_arch=x64during the artifact’snpm installstep. Tracked as task #99. -
TLS / HTTPS in front of port 7702. Currently plain HTTP. Webhook HMAC verification means payload integrity is fine, but hygiene says put Cloudflare in front (would require dropping to a CF-proxiable port or running the app on 443/8443 with cert via Caddy). Not urgent — GitHub is fine with plain HTTP and the secret never travels in cleartext.
-
starsystem.prod.yamltemp file.ss artifact deploydoesn’t yet accept--workspace-file; we work around bycping the legacy-shim-generated yaml into place. Tracked as part of audit task §73 (CLI wart) — fix by adding--workspace-fileto artifact-deploy.
Update — 2026-05-23 (round 2): a deeper bug surfaced
Section titled “Update — 2026-05-23 (round 2): a deeper bug surfaced”Tested the fix with a real push to packages/lens/README.md (commit
3e5e74b). 5 pipelines fired correctly (ci, lens-dev, docs-dev,
marketing-dev, sync-subtrees) — webhook → run-row creation works
cleanly. But all five stayed at status='running' events=[] for 10+
minutes with no error.
Added a smoke pipeline (one echo step, commit c2f2db5) and
triggered it manually. echo "starflow smoke ok" also hangs at
running/events: [] for 90+ seconds with no error.
Conclusions:
- Not a slim-image issue (
echois busybox builtin). - Not “real pipelines are slow” — even instant work hangs.
- The engine queue / handler execution path is hanging without
throwing.
onRunErrordoesn’t fire because nothing throws.
Most likely cause: one of the stubbed packages in
packages/starflow-server/stubs/ (@celestial/scribe,
@celestial/storage, @celestial/agent-host-ports) has a method
that returns a never-settling Promise instead of throwing or
returning. The engine’s first await on a step handler hangs forever.
The drift-detection test added in commit 0929f0d was a code smell
flagging this risk — the stub architecture is fighting us.
Recommended path forward: stop stubbing. Either rebuild the Dockerfile to use the real workspace packages (likely requires dropping Alpine for a Debian-based image so the submodule deps build), or migrate starflow-server back to Fly.io (where it was before Railway) where real workspace support is first-class. The runbook author has been on Railway for a month chasing stub bugs; this is the second silent failure mode found in that time.
Status: diagnosed; fix deferred pending provider/architecture decision.
Original (resolved) — Still outstanding
Section titled “Original (resolved) — Still outstanding”Pipeline runs are created but never appear to execute past “running” state with zero events.
Confirmed:
POST /api/pipelines/<name>/triggerreturns{ ok: true, runId }- The run row is inserted into
workflow_runsas status=‘running’ engine.execute()is firedactiveRuns.set(runId, ...)happens- BUT: status never moves to
completed/failed;events: []forever;durationMs: null;completedAt: null
Suspicion (not confirmed): the bash run: steps in my pipelines
require tools (git clone, npm ci, npm run build, node) that
the slim starflow-server Docker image may not fully support, OR
something earlier in engine.execute() throws and the .catch() on
line ~259 of server.ts logs to console (not captured in /api/runs).
What to dig into next session:
- Tail Railway deployment logs while triggering a manual run; look
for the
console.error("[starflow] run ${runId} fatal error: …")branch from server.ts ~262. - Check whether the engine’s
run:node handler can actually shell out in the container — might needapk add bashor similar at the Dockerfile level. - Verify
workflow_runstable updates actually fire from the state adapter (the table insert is at server.ts:244-247; the updates happen elsewhere — maybeMirroringWorkflowStateAdapteror the innerScribeStateAdapteris failing silently).
What still works regardless
Section titled “What still works regardless”- Webhook receives + matches pipelines + creates run rows ✓
- Manual trigger via
POST /api/pipelines/<name>/triggercreates run rows ✓ - Schedule-based runs registered at startup (nightly, spacecraft- scheduled-agent) per server logs ✓
- The artifact build (
ss artifact build scribe-newswatch --env=prod) works perfectly when run locally — we just can’t trigger it via starflow yet.
Acceptable short-term workflow: keep building artifacts on the laptop; once execution is unblocked, the same pipeline runs hands-off on starflow.