NixOS and Home Manager configuration for Jet's Framework laptop and devbox.
This flake defines two hosts:
devbox: headless T3 Code hostframework: Framework laptop
flake.nix: flake inputs, host wiring, formatter, and dev shellflake.lock: pinned flake input revisionsoverlays/: nixpkgs overlays and package overridesmodules/nixos/common/: shared NixOS system modulesmodules/home/common/: shared Home Manager modulesmodules/home/optional/: optional Home Manager modules not imported by defaulthosts/framework/: NixOS and Home Manager configuration for the Framework laptophosts/devbox/: NixOS and Home Manager configuration for the T3 Code hostpkgs/: local package definitionsgnome-extensions/: local GNOME Shell extensionssecrets/: agenix-encrypted secrets
Run these before switching a machine:
nix flake check --print-build-logs path:.
nix build --no-link --print-build-logs path:.#nixosConfigurations.devbox.config.system.build.toplevel
nix build --no-link --print-build-logs path:.#nixosConfigurations.framework.config.system.build.toplevelThe repository uses direnv via .envrc with use flake.
Enter the dev shell automatically with direnv, or explicitly with:
nix developSwitch the current host:
nhsWithout an already-loaded dev shell:
nix develop -c nhsBuild and make the new generation the next boot without switching now:
nhbUpdate inputs:
nix flake updateThe interactive Bash alias nfu also runs nix flake update.
After updates, validate and switch:
nix flake check --print-build-logs path:.
nix build --no-link --print-build-logs path:.#nixosConfigurations.framework.config.system.build.toplevel
nhsThe system starts one background OpenCode server for user jet:
opencode serveThe server host and port are declared in ~/.config/opencode/opencode.json:
127.0.0.1:4096
In interactive Bash, both opencode and o attach to that background server from the current directory:
opencode
oTo bypass the shell function and run the underlying binary directly:
command opencode --helpOpenCode is configured with permissive permissions and only the Chrome DevTools MCP globally enabled.
The Framework also exposes OpenCode to the tailnet with Tailscale Serve:
opencode-tailnet-url
opencode-tailnet-url --qrTailnet policy also restricts access to framework: broad tailnet and exit-node access remains enabled, but framework is removed from the broad tailnet grant and added back only for pixel-10. The live policy uses pixel-10's Tailscale IPs plus built-in Android posture (node:os == 'android', stable release track, encrypted Tailscale state) because custom device posture attributes are not available on the current Tailscale plan. The local firewall additionally limits the Serve HTTPS endpoint to pixel-10 (100.106.98.89 / fd7a:115c:a1e0::1433:6259).
OpenCode remains available independently on HTTPS port 443. T3 Code runs alongside it with:
- The desktop client on Framework.
- A Framework server owned by
jet, using/home/jet/Documents/nix-configand local port3774. - A devbox server owned by
jet, using/home/jet/devand local port3773. - Tailscale Serve HTTPS endpoints on port
8443.
Create a fresh mobile pairing link on either host:
t3code-pair --label pixel-10 --ttl 1hThe mobile endpoints are:
https://framework.taile9e84e.ts.net:8443
https://devbox.taile9e84e.ts.net:8443
The official Android client is built from the pinned matching upstream revision in the dedicated shell:
nix develop .#t3code-android
build-t3code-mobileIts private signing key is retained under ~/.local/share/t3code-mobile-signing so later self-built preview APKs can upgrade the existing installation.
The unofficial ChatGPT Desktop for Linux runs on Framework with experimental Linux Remote support. Framework and devbox are separate Codex hosts:
- Framework threads use
/home/jet/.codexand are remotely available while ChatGPT Desktop is running and the laptop is awake. - Devbox threads use
/home/jet/.codexand are served continuously by T3 Code from/home/jet/dev. - ChatGPT mobile can pair with both hosts.
- Framework Desktop works locally on Framework and uses Control other devices for devbox.
Codex Remote uses OpenAI's outbound relay. The app-server Unix socket is not exposed through Tailscale.
Devbox uses agenix-managed Anthropic and OpenAI API credentials rather than subscription logins. See hosts/devbox/README.md for provisioning and rotation instructions.
Generate a separate short-lived pairing code for ChatGPT mobile and Framework Desktop:
codex-remote-pairOn Framework, enable mobile access for the local host from ChatGPT Desktop's Connections settings. Pair devbox under Control other devices. On the phone, use Remote to switch between the Framework and devbox thread catalogs.
Both hosts reserve tailnet TCP ports 5100-5199 for development previews. The local firewalls restrict Framework previews to pixel-10 and devbox previews to Framework plus pixel-10.
Bind a preview server to 0.0.0.0 on an available port in that range, then open the matching MagicDNS URL:
http://framework:5173
http://devbox:5173
Direct HTTP preview traffic is encrypted by Tailscale, but browsers do not treat it as a secure context. Use a dedicated Tailscale Serve HTTPS endpoint when testing service workers, secure cookies, WebAuthn, or other HTTPS-only browser features. Keep databases, debuggers, Chrome DevTools, MCP servers, and app-server transports bound to localhost.
Ghostty uses its GTK single-instance/systemd integration and runs one persistent Zellij session named main.
Launching Ghostty attaches to that session through:
zellij attach --create mainThe helper ghostty-zellij opens Ghostty with single-instance behavior. Zellij tab names sync from the current working directory on prompt updates.