Host-side setup utility for NovaScale Codex integration. It configures a user-level codex app-server service, creates a capability token, and prints a pairing URI for NovaScale iOS.
The wrapper uses the official codex command already installed on the host and the user's existing Tailscale networking mesh. When remote notifications are enabled, setup also installs NovaScale's open-source notification agent from a signed, pinned release.
curl -fsSL https://raw.githubusercontent.com/GalaxNet-Ltd/nova-codex-bootstrap/refs/heads/main/setup.sh | shIf a 100.64.0.0/10 interface address is detected, setup assumes it is a Tailscale address and offers a small terminal menu. The recommended choice binds codex app-server only to that Tailscale-range address.
If no Tailscale-range address is detected, pass an explicit address:
./setup.sh --listen 100.88.77.66 --host 100.88.77.66To force literal URI output even when qrencode is installed:
./setup.sh --no-qrIf setup has already been run, setup.sh shows the current config and asks before reconfiguring it. For scripted or non-interactive SSH reconfiguration:
./setup.sh --yesRedeploying preserves the existing capability token, so already-paired apps
continue to work. Token replacement happens only when --rotate-token is
explicitly supplied or no usable token exists.
Host notification support is enabled by default for every user. The updated
app supplies the notification endpoint and a short-lived setup-token file, so
bootstrap downloads and enrolls the pinned signed agent release automatically.
This prepares the host but does not activate paid remote delivery. Remote Push
is enabled separately in Codex Settings and requires a Pro subscription.
Turning host notification support off passes --no-notifications and keeps the
host on the lean wrapper-only path.
Older apps and manual invocations do not have enrollment credentials. In that case setup reports that notification enrollment is unavailable and continues with the wrapper-only installation instead of failing. To choose that path explicitly, use:
./setup.sh --no-notificationsThis compatibility fallback lets existing NovaScale versions continue to use Codex hosts, while hosts created before notification-aware bootstrap can be redeployed later without deleting, repairing, or re-adding them.
Use 0.0.0.0 only when the host is behind Tailscale subnet routing or a trusted private network:
./setup.sh --listen 0.0.0.0 --host 192.168.50.20 --port 14500Network listen mode exposes Codex app-server to any machine that can reach the configured host and port. A capability token is required, but reachable network exposure still increases risk.
You can skip the service helper and run codex app-server manually in a terminal. The terminal must stay open. If you want it to run in the background or at login, wire the command into your preferred service manager.
Create a token:
mkdir -p "$HOME/.codex"
umask 077
openssl rand -base64 32 > "$HOME/.codex/novascale-app-server-token"
chmod 600 "$HOME/.codex/novascale-app-server-token"Start the app server on your Tailscale IP:
codex app-server \
--listen ws://100.88.77.66:14500 \
--ws-auth capability-token \
--ws-token-file "$HOME/.codex/novascale-app-server-token"For subnet-router mode, use 0.0.0.0 as the listen address and use the reachable subnet IP or hostname when creating the NovaScale host entry.
Setup creates:
~/.local/bin/novascale-codex
Commands:
novascale-codex status
novascale-codex restart
novascale-codex stop
novascale-codex notification-status
novascale-codex notification-restart
novascale-codex notification-stop
novascale-codex print-pairing
novascale-codex print-pairing --no-qr
novascale-codex rotate-token
novascale-codex uninstallThe notification-* commands are available in the unified helper but report
an error until the notification agent has been installed.
The wrapper installation creates:
~/.codex/novascale-codex-host.env
~/.codex/novascale-app-server-token
~/Library/LaunchAgents/dev.galaxnet.novascale.codex.plist
~/.config/systemd/user/novascale-codex.service
A notification-enabled installation additionally creates or updates:
~/.codex/hooks.json
~/.local/bin/novascale-agent
~/.config/novascale-agent/config.json
~/.config/novascale-agent/host-key
~/.local/state/novascale-agent/
~/Library/LaunchAgents/dev.galaxnet.novascale.agent.plist
~/.config/systemd/user/novascale-agent.service
If you clone this repository instead of running the setup via curl:
bin/novascale-codex: The service helper script. When running./setup.shfrom a local clone, the setup script copies this file directly to the helper path. When installing via thecurlpiping method, the helper is generated from a copy embedded insidesetup.sh.templates/: Contains static examples of the systemd service (linux-systemd-user.service) and macOS LaunchAgent (macos-launchagent.plist) configs. These are for manual setup reference only and are not read or executed bysetup.sh(which generates service configs dynamically).
NovaScale Codex pairing is generated on your Codex host. It is not sent to GalaxNet or any website. NovaScale imports it locally and stores the token in iOS Keychain.
The host agent and notification backend never receive a thread title, prompt, assistant response, tool input, command, patc, working directory, or transcript path. The agent emits only the lifecycle event type, timestamp, and non-content identifiers needed to correlate the host, thread, turn, and approval request. Each event is signed by the host key before upload.
The APNs payload contains a generic notification plus opaque event, host, thread, and turn identifiers. NovaScale keeps a small, time-limited mapping from host and thread identifiers to titles in the device's protected App Group container. Its notification service extension uses that local mapping to add a title after delivery. If no local title is available, the generic notification is shown. Thread titles therefore do not pass through the notification backend or APNs. APNs device tokens are encrypted at rest by the notification backend.
The repository contains the open-source host agent for NovaScale's independent
notification side channel. novascale-agent observes PermissionRequest and
Stop, discards all non-whitelisted content, queues the minimized event
locally, and uploads a signed event to the configured service. The hook always
returns {} and never supplies a Codex verdict.
The agent also provides an explicit app-server restart command for the host
user. It never restarts the wrapper automatically or exposes restart control
over the notification channel.
For notification-enabled setup, bootstrap downloads the pinned agent release for the host platform. An already-enrolled agent keeps its existing identity:
./setup.sh --yes --enable-notificationsDuring an agent redeploy, setup asks the running daemon for its version and compares the installed and incoming binaries. It restarts only the notification daemon when the live version or binary is stale, after the binary, hooks, and service definition are ready. The durable queue survives this restart, and the Codex App Server wrapper is not restarted by the notification upgrade check.
For first enrollment, the app obtains a short-lived, single-use setup token and
writes it to a temporary 0600 file. Pass that protected file and the backend
URL. Bootstrap creates the host identity and stages enrollment locally; it does
not wait on a registration network request:
./setup.sh --yes --enable-notifications \
--notification-endpoint https://<NOTIFICATION_ENDPOINT> \
--notification-setup-token-file /path/to/protected/setup-tokenThe bootstrap currently pins stable agent 0.1.1. Use
--agent-version <version> to select another published immutable release.
Bootstrap downloads the exact platform archive and SHA256SUMS from the
corresponding agent-v<version> GitHub Release, rejects unexpected archive
paths or links, verifies the SHA-256 digest and embedded version, and never
falls back to an unsigned build. macOS additionally requires a valid Developer
ID signature, notarization ticket, and the expected universal architectures
before the binary is executed. A matching installed version is reused without
a network download.
The daemon keeps a protected 0600 copy outside its config, key file, queue,
and service definition while registration is pending. It proves possession of
the host private key, sends the token only as registration authorization,
retries transient failures across restarts, and removes the copy after success
or permanent rejection. The caller-owned temporary file can be deleted as
soon as bootstrap has staged it. Redeploying an active host preserves its
identity; redeploying a pending host continues the existing attempt.
Notification endpoints must use HTTPS. Plain HTTP is accepted only for
loopback development through localhost, 127.0.0.0/8, or ::1.
Setup adds only the exact novascale-agent hook handlers to the user's
existing ~/.codex/hooks.json. Notifications remain inactive until those exact
definitions have been reviewed and trusted, and Codex has loaded them. After
setup, open Codex CLI on the host, run /hooks, and review and trust the
NovaScale PermissionRequest and Stop hooks. If the Codex App Server is
already running, wait for active turns and approvals to finish, then restart it
after trusting the hooks before testing a new or existing thread:
novascale-codex restartThe hook reports events only and always returns {}; Codex and the user retain
the approval decision.
--dev-agent and --agent-binary remain explicit development overrides and
cannot be combined with --agent-version.
See docs/release-preparation.md for the clean
Linux host matrix, backward-compatibility gate, and staged release checklist.
See notifications/README.md for the agent's data
minimization, local state, commands, and build instructions.
APNs-based push notifications use Codex lifecycle hooks and a dedicated outbound-only companion agent. The agent is not a proxy and does not enter the authoritative App Server/Tailscale connection path.