Dev runner
How the root dev command starts the local web, API, and docs surfaces.
Dev runner
The preferred local workflow is the root bun dev command. It starts the storefront, API, and docs together and gives them stable HTTPS names through Portless.
Default mode
Portless is the sensible default because it removes port memorization from day-to-day review:
storefront: https://web.kof
api: https://api.kof
docs: https://docs.kofThe root command runs a small wrapper before Portless:
bun devThe wrapper checks that Node.js 24+ is available on PATH, then launches the checked-in Portless dependency with Node. It keeps HTTPS on, derives the default TLD from the git repo name (kof-repo becomes kof), and treats port 443 as part of the contract for bun dev, so the repo keeps clean HTTPS URLs as the default.
Before app startup, the wrapper pins PORTLESS_STATE_DIR to ~/.portless and reads ~/.portless/proxy.port. If Portless is persisted on a non-443 proxy port, such as the fallback 1355, it prompts to clear that stale Portless proxy state and retries 443. It then starts portless proxy start --port 443 --https explicitly before handing off to the normal app runner. If an older privileged proxy is answering on 443 without writing to the shared state directory, the wrapper prompts to stop that proxy and restart it. That prevents Portless from silently reusing a stale fallback proxy or splitting proxy state from app route state.
Clean Portless URLs require the proxy on port 443. If Portless asks for sudo and that prompt is denied, bun dev exits instead of using the unprivileged fallback that would add a proxy port to every URL.
If Portless reports that port 443 is already in use, check the actual local listener:
sudo lsof -nP -iTCP:443 -sTCP:LISTENTailscale can bind 443 through the macOS io.tailscale system extension. If the listener is io.tailscale, quitting the Tailscale macOS app frees the port. Clean https://web.kof Portless URLs require freeing port 443, or use bun run dev:plain.
The same class of failure can happen in WSL when tailscaled owns 443 on the WSL tailscale0 addresses. If bun dev prints https://web.kof:1355, use the detailed Portless debugging runbook before disabling the whole network stack.
Direct-port fallback
The traditional local ports should remain available for debugging, CI-style checks, or machines that are not ready to trust the Portless certificate:
bun run dev:plainThat fallback starts the same three surfaces directly:
storefront: http://localhost:5173
api: http://localhost:8787
docs: http://localhost:3000Individual package commands are still useful when only one surface is needed:
bun run web:dev
bun run api:dev
bun run docs:devFirst-run setup
Portless runs an HTTPS proxy on the local machine. On first run it may ask for permission to bind the proxy and trust a local certificate authority.
If Firefox-family browsers show SEC_ERROR_UNKNOWN_ISSUER, restart the browser after Portless trust setup. If the warning remains, enable security.enterprise_roots.enabled in about:config or import ~/.portless/ca.pem into the browser certificate authorities.
The page can still load on web.kof while inventory fetches fail against api.kof. That usually means the browser has a host-specific exception for web.kof, but does not trust the Portless CA for every local host. Open https://api.kof/health directly; if the browser warns there, import the CA or add the exception for that host too.
If Portless state gets stuck after a sudo attempt, run portless clean or remove stale proxy files under ~/.portless, then retry.
The root dev wrappers also restore terminal modes on exit. If a child dev server leaves the shell showing raw control sequences after Ctrl-C, the wrapper sends the usual terminal reset controls and runs stty sane on Unix-like systems before exiting.
Naming direction
The current names are intentionally short and repo-scoped through the TLD. You can override the default with PORTLESS_TLD=localhost bun dev or by passing Portless --tld arguments through the root command.