Rules for people and coding agents changing this repo. The README covers what Frametop is and how to install it; docs/reference.md covers each component, and docs/design.md records how SteamVR on the Frame behaves and why things are built the way they are. Read its notes on SteamVR before changing how the screens, the pointer, or the input relay talk to SteamVR.
Every script works in both modes, and must keep working in both:
~/dev/frametop on the Frame (scripts/sync.sh), and commands run there. scripts/_env.sh works out which mode applies (FRAME_LOCAL, FRAME_HOST, FRAME_REPO).scripts/sync.sh # PC -> ~/dev/frametop on the Frame
scripts/frame.sh -C <dir> '<build cmd>' # runs in the "dev" Fedora distrobox
scripts/frame.sh --host '<cmd>' # runs on the SteamOS host
sync.sh overwrites.dev container. The SteamOS host has a read-only root and no compilers. Container builds link against the container’s libraries, so they run in the container (distrobox enter dev -- ...); the SteamVR driver is built to run on the host.setup/dev-container.sh, so the container can be rebuilt.build/ next to the sources. It’s gitignored and never synced.A Steam Frame is someone’s personal headset, and they may be wearing it while you work.
gamescope, steam, vrserver, vrcompositor, the gamescope session, or the Frametop desktop without asking. Each one ends or disrupts whatever is happening in VR.sudo, steamos-readonly disable, steamos-devmode changes, pacman installs, or reboots without explicit approval. Three installers need host sudo, and they ask for it: the Bluetooth fixes (setup/bluetooth/install.sh), hand tracking (hands/run.sh install and caps, which set ft-camd’s file capabilities with setcap, and uninstall and uncaps, which take them back), and our own eye tracker’s frame grabber (gaze/tracker/install.sh)./tmp, and the container unless told otherwise. The installers are the exception: they write the user services, launchers, and the SteamVR driver into the home folder. The Bluetooth fixes and the eye tracker’s frame grabber also install root-owned files and system services under /etc (/etc/steamframe, /etc/frametop, /etc/systemd/system). When an installer starts writing something new outside the repo, or sets file capabilities, add it to uninstall.sh too: users uninstall with that script, not with each installer’s uninstall..netrc, SSH keys, or Steam config off the Frame or into this repo.A SteamOS update replaces SteamVR, KWin, and gamescope with the rest of the OS image. When a change starts depending on something from the image (a host file, an OpenVR interface outside the bundled header, an undocumented layout or output format, a SteamVR or KWin quirk), add a check for it to scripts/update-check.py, or a retest hint for its package there. docs/design.md has the background.
pack/)pack/Containerfile builds Frametop as an OCI image, the groundwork for installing without building on the headset; no installer uses it yet. pack/design.md explains why and what is open, and pack/README.md documents the specifics. Rules:
uv.lock (commit the lock, never a bare uv pip install), downloads by tag or commit and sha256, CI actions by commit SHA.build.sh scripts (FRAME_IN_BOX=1), and the OpenVR SDK they build against is pinned in scripts/openvr.sh. Change a build there, not in the Containerfile, and keep the Containerfile buildable on arm64, the only architecture the Frame has../ft dev test runs just test inside it, and CI runs the same recipes. A new offline test that needs no headset goes in the justfile too.User-facing names are “Frametop”, “Frametop Display Settings”, and “Frametop Input Settings”. Programs and files use the ft- / ft_ prefix (ft-screens, ft-pointer, ft-layout, the ft_pointer driver); config, units, and overlay keys use frametop. Program names must stay within 15 characters: Linux truncates process names there, and the scripts find programs with pgrep -x / pkill -x.