This document defines the native local-domains path for Flow.
Goal:
- keep stable
*.localhostnames, - remove docker/nginx runtime dependency,
- provide low-overhead local routing suitable for agent-heavy workflows.
This is an incremental migration path.
Phase 1 (implemented now):
- opt-in engine:
f domains --engine native ... - experimental C++ daemon (
domainsd-cpp) built by Flow withclang++ - host-based HTTP/1.1 routing from
~/.config/flow/local-domains/routes.json - WebSocket upgrade passthrough
- request-side chunked transfer-encoding decode
- upstream keepalive connection pooling for safe HTTP/1.1 reuse
- bounded active handler slots with overload shedding (
503) - upstream connect/read/write timeouts (
504for upstream connect timeout) - health endpoint:
/_flow/domains/health - macOS launchd socket-activation installer for native privileged
:80bind without Docker
Phase 2:
- better connection pooling and backpressure controls
- optional HTTP/2/TLS frontend mode
Phase 3:
- optional HTTPS + HTTP/2
- structured trace export for agent context
- system DNS changes
- packet filter / firewall manipulation
- replacing
.localhostconventions
Flow CLI remains the control plane:
f domains list
f domains add app.localhost 127.0.0.1:3000
f domains rm app.localhost
f domains --engine native up
f domains --engine native down
f domains --engine native doctorEngine selection:
- CLI flag:
--engine docker|native - env fallback:
FLOW_DOMAINS_ENGINE=native - default:
docker
Current state remains:
- routes:
~/.config/flow/local-domains/routes.json
Native runtime artifacts:
- pid:
~/.config/flow/local-domains/domainsd.pid - log:
~/.config/flow/local-domains/domainsd.log - built daemon binary:
~/.config/flow/local-domains/domainsd-cpp - macOS launchd plist (optional):
/Library/LaunchDaemons/dev.flow.domainsd.plist
Native tuning env vars (read by f domains --engine native up and passed to daemon):
FLOW_DOMAINS_NATIVE_MAX_ACTIVE_CLIENTS(default128)FLOW_DOMAINS_NATIVE_UPSTREAM_CONNECT_TIMEOUT_MS(default10000)FLOW_DOMAINS_NATIVE_UPSTREAM_IO_TIMEOUT_MS(default15000)FLOW_DOMAINS_NATIVE_CLIENT_IO_TIMEOUT_MS(default30000)FLOW_DOMAINS_NATIVE_POOL_MAX_IDLE_PER_KEY(default8)FLOW_DOMAINS_NATIVE_POOL_MAX_IDLE_TOTAL(default256)FLOW_DOMAINS_NATIVE_POOL_IDLE_TIMEOUT_MS(default15000)FLOW_DOMAINS_NATIVE_POOL_MAX_AGE_MS(default120000)
Listen address:
127.0.0.1:80
macOS launchd mode:
- daemon can be started with
--launchd-socket domainsd(socket inherited from launchd) - launchd owns privileged bind; daemon runs as local user
Routing:
- Read
Hostheader (strip:port) - Lookup
host -> targetfromroutes.json - Forward request to target (
host:port)
Special endpoint:
GET /_flow/domains/health- returns header
X-Flow-Domainsd: 1
Errors:
404when host route is not configured502on upstream connection/forward failures503when proxy is saturated and sheds overload504on upstream connect timeout400for malformed HTTP requests
- Keep Docker engine as default during hardening.
- Native engine is explicit opt-in.
f domains doctorshould always show effective owner on port 80.- Any startup failure must surface log path directly.
- added local proxy latency p99 < 1ms for tiny responses
- idle CPU near zero
- route update visibility < 100ms (mtime-based reload)
f domains add myflow.localhost 127.0.0.1:3000
sudo ./tools/domainsd-cpp/install-macos-launchd.sh # macOS when direct bind is denied
f domains --engine native up
f domains --engine native doctor
curl -H 'Host: myflow.localhost' http://127.0.0.1/
sudo ./tools/domainsd-cpp/uninstall-macos-launchd.sh # optional teardown- Add per-upstream timeouts (connect, first-byte, total) with explicit 502/504 mapping.
- Add end-to-end trace summary output for agents (route misses, upstream failures, latency buckets).
- Add launchd install/uninstall tasks for persistent local startup.
- Add optional HTTPS + HTTP/2 frontend mode.