−
100%
+
fit
scroll
# Portal Awakens (Day 382) How the live Portal
actually boots — the full set of flags, env,
and companion processes needed to run the way
it does. Grounded in `ecosystem.config.js` +
`rust/src/main.rs` (clap `Args`, dotenvy
loader) as of Day 382. Companion to
[[Postgres-Node-Topology.00382]] and
[[Portal-API-Reference.00382]]. ## The live
web process — `portal-hexlet` ```
./rust/target/release/hexos-portal \ --web \
--port 3333 \ --static-dir
/Volumes/HEXCRAFT/Sacred-Lab/HexOS/Vessels/Web-Vessel/static
\ --stream ``` | Flag | Effect | |---|---| |
`--web` | Web-server mode — serves
Web-Vessel + full API + websocket. The master
switch; without it the binary is a CLI/daemon.
| | `--port 3333` | Listen port. Also the clap
**default**, so technically redundant — but
explicit is correct; cloudflared proxies to
it. | | `--static-dir …/Web-Vessel/static` |
Where the site is served from. **Must** be
`Vessels/Web-Vessel/static` — the old
`Portal-Web-Vessel` path doesn't exist and
would 404 the whole site. | | `--stream` |
**NOT inert — it's a stitch between the two
binaries.** Does two separable things, only
one of which was ever feature-gated (see
below). On this binary it turns on the `/hls`
route that serves the segments the standalone
`hexos-stream` app produces. | ### `--stream`
is a stitch, not a no-op `--stream` does two
separable things: | Half | Gate | This binary
| |---|---|---| | Embedded RTMP ingest
(in-process) | `#[cfg(feature = "stream")]`
— **compile-time** | **never built in** →
prints `⚠️ --stream flag requires building
with: cargo build --features stream`. The
embedded RTMP server was never compiled into
the live binary — `stream` is opt-in
(`default = ["pty"]`), never used. | | Serving
`/hls` over `/tmp/hexos-stream/hls` | plain
**runtime** `if stream` (`main.rs:361`) |
**active** → `effective_hls_dir =
Some("/tmp/hexos-stream/hls")` →
`server/mod.rs:1396` nests the `/hls` ServeDir
→ logs `📡 HLS serving: /hls →
/tmp/hexos-stream/hls` | So the stitch: the
standalone **`hexos-stream`** binary ingests
RTMP on `:1935` and writes HLS segments into
the shared dir `/tmp/hexos-stream/hls`;
**`--stream` on Portal** turns on the `/hls`
route that serves those exact segments at
`hexcraft.dev/hls`. The two binaries are
bridged by (a) that shared filesystem dir and
(b) the flag toggling Portal's read side.
**Drop `--stream` and playback 404s** —
Portal stops exposing the directory (`else {
None }`, main.rs:363-364). Confirmed live (Day
382) by the boot log showing BOTH the `⚠️`
warning AND `📡 HLS serving` on the same
boot. **The flags that shape the live process
are `--web`, `--port`, `--static-dir`, and
`--stream` (its HLS-serving half).**
Everything else that makes Portal "run the way
it does" is **env, not flags.** ## Required
env ### Set by pm2 (ecosystem `env` block —
committed, secret-free) | Var | Value | Why |
|---|---|---| | `RUST_LOG` | `info` | Log
level | | `HEXCRAFT_HEARTH_ID` | `hexlet` |
Sovereignty — flips DB discovery to
localhost-FIRST (db/mod.rs `is_sovereign`), so
the daemon stops reaching across the mesh to
`
[email protected]
` and eating a ~30s pool
timeout on every restart | |
`HEXCRAFT_DB_NAME` | `hexlet` | Which Postgres
DB this process talks to — a separate axis
from hearth id | | `CLAUDE_BIN` |
`/Users/hex/.local/bin/claude` | The
Brilliant's chronicle Muse pass shells out to
this claude CLI (subscription auth, no raw API
key); falls to data-only if absent | |
`PORTAL_BSKY_INBOUND` | `1` | Enable Jetstream
inbound | | `PORTAL_BSKY_JETSTREAM_HOST` |
`jetstream1.us-west.bsky.network` | Pinned
known-good instance (default
jetstream2.us-east lagged) | |
`PORTAL_BSKY_NOTIFICATIONS_HANDLE` |
`hex.hexcraft.dev` | Bluesky account | ###
Loaded by Portal itself from `Sacred-Lab/.env`
(NOT in ecosystem) Portal calls
`dotenvy::from_path` at startup (`main.rs:36`
`load_dotenv`), checking in order: 1.
`$HOME/HEXCRAFT/Sacred-Lab/.env` ← the
canonical one 2. `$HOME/.hexcraft/.env` 3.
`./.env` (relative to cwd) `dotenvy` is
**set-if-absent** — it never overrides a var
pm2 already set. So the ecosystem block wins
for `HEARTH_ID`/`DB_NAME`, and `.env`-only
secrets load cleanly. | Var | Purpose |
|---|---| | `HEXCRAFT_MESH_SECRET` |
Node-to-node auth — validated constant-time
by `verify_mesh_secret()` (Day 382,
[[Portal-API-Reference.00382]]). Must match
across all nodes; same file = same value | |
`PORTAL_BSKY_NOTIFICATIONS_APP_PASSWORD` |
Bluesky auth | | `PORTAL_TOKEN` | Daemon / MCP
session token (Claude Code reads via
`${PORTAL_TOKEN}` in `.mcp.json`) | |
`HEXCRAFT_ENCRYPTION_KEY` | Thing Box
encryption (hexlet box) | |
`CLOUDFLARE_API_KEY_NEW`, `ASANA_PAT_HEX` |
External API keys | **`.env` is gitignored**
— it does NOT travel with `git push` / mesh
deploy. It already exists on hexlet. A *new*
node needs its own `.env` placed manually
before first start, or its mesh writes get
rejected (safe-fail: they silently stop
syncing until the file's added). Because
Portal loads `.env` on its own at startup, a
plain `pm2 restart` picks up secret changes
— `--update-env` is only load-bearing when
you change the **ecosystem env block** itself.
## Companion pm2 apps (part of "the way it
runs") | App | Command | Role | |---|---|---|
| `portal-hexperiment` | `--web --port 3334
--static-dir …` (no `--stream`),
`HEXCRAFT_DB_NAME=hexperiment` | Local dev —
same binary, second DB, localhost-only, not
edge-exposed | | `hexos-stream` | `--rtmp-addr
0.0.0.0:1935 --http-addr 0.0.0.0:8443
--hls-dir /tmp/hexos-stream/hls` | The
RTMP→HLS media server (separate crate).
Ingests RTMP, writes HLS segments to the
shared dir. Portal's `--stream` serves those
segments at `/hls` — the two are stitched
via that dir (see `--stream` section above) |
| `cloudflared` | `start-cloudflared.sh`
(interpreter: none) | Public ingress / edge
tunnel | ⚰️ **Entombed (Day 375):**
`lumen-daemon` pm2 app retired — the
Brilliant's daily chronicle now runs
in-process (`maybe_create_daily_chronicle()`
at the daily tick, Muse via the claude
subprocess). ccmd-006. ## Flags that exist but
the live process does NOT use `--api` (web
implies it), `--daemon` (the dark-command path
— `hx` / local forge), `--forest` (SQLite
offline sovereignty), `--migrate`, `--token`,
`--tcp-port`, `--vessel`, `--plain` /
`--json`, and `--rtmp-addr` / `--hls-dir`
(those belong to `hexos-stream`, not
Portal-with-`--stream`). ## Restart / boot
mechanics - hexlet runs everything under
**PM2**; launchd agent `pm2.hex.plist`
resurrects on boot. - Source of truth:
`/Volumes/HEXCRAFT/Sacred-Lab/HexOS/Portal/ecosystem.config.js`.
- Restart one app from the ecosystem file,
then persist: ``` ssh hexlet "zsh -l -c 'cd
/Volumes/HEXCRAFT/Sacred-Lab/HexOS/Portal &&
pm2 restart ecosystem.config.js --only <app>
--update-env'" ssh hexlet "zsh -l -c 'pm2
save'" ``` - PM2 over SSH needs a login shell:
`ssh hexlet "zsh -l -c '<pm2 cmd>'"`. - Verify
a stream-capable Portal binary by the boot log
line `📡 Stream server: RTMP=… HLS=…`,
NOT by `strings` (clap args compile in
unconditionally even without the feature). ##
Source pointers - `Portal/ecosystem.config.js`
— all four app definitions, env blocks. -
`Portal/rust/src/main.rs:36` (`load_dotenv`),
`:187-255` (clap `Args`), `:361-365` (the `if
stream` → `effective_hls_dir` stitch),
`:349-352` (the
`#[cfg(not(feature="stream"))]` RTMP warning
branch). -
`Portal/rust/src/server/mod.rs:1395-1398` —
the `/hls` ServeDir nest gated on
`config.hls_dir`. -
`Portal/rust/src/db/mod.rs` — `is_sovereign`
/ `DbConfig::db_name` (HEARTH_ID vs DB_NAME
axes). - `Sacred-Lab/.env` — the secret
source (gitignored). </content>
△