> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monolex.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Monolex Headless

> Run Monolex terminal sessions without the desktop GUI, expose local control to Monopty, or attach an owned remote gateway session.

`monolex-headless` is the GUI-free Monolex terminal server. It supervises PTY
sessions through the PTY daemon, maintains rendered terminal state, exposes a
local control socket for [Monopty](/ai-clis/monopty), and—outside local-only
mode—opens an owned gateway session for remote access.

*Published contract: `monolex-headless 0.1.45`, OpenCLIs build
`2026-07-18-160008`, source commit
`0ccadab991a6ba90f6e4268e0d720ba229244662`. The clean macOS archive has
SHA-256 `a8f340613d4a99ea7de6b19e0c09ba97dc92286d8a202ea554b011965dfcbcba`.*

## Quick Start

```bash theme={null}
openclis install monolex-headless
openclis install monolex-pty-daemon

monolex-headless --version
monolex-headless --local-only
```

Use a second terminal to check `monopty health`. For a persistent machine,
prefer the OS-service commands below over an unsupervised foreground process.

## Complete Command Reference

Version 0.1.45 exposes one foreground invocation and six service operations.
Clap also provides the generated `help` command plus `-h`/`--help` and
`-V`/`--version`.

| Command                      | What it does                                                            | Effect or proof boundary                                                        |
| ---------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `monolex-headless [options]` | Runs the headless server in the foreground.                             | Owns local control and PTY session lifecycle until stopped.                     |
| `service-install`            | Registers the binary as an auto-start OS service.                       | Persistent launchd, systemd, or Windows service/task mutation.                  |
| `service-uninstall`          | Removes the OS-service registration.                                    | Does not prove that every separately started process has exited.                |
| `service-status`             | Reports registered service state.                                       | Supervisor truth; pair with `monopty health` for runtime truth.                 |
| `service-start`              | Starts the registered service.                                          | Requires prior installation.                                                    |
| `service-stop`               | Stops the registered service.                                           | Service-state mutation.                                                         |
| `upgrade`                    | Downloads the latest public binary and restarts the registered service. | Network, executable, and process mutation; verify version and health afterward. |
| `help [command]`             | Prints root or service-command help.                                    | Read-only parser inspection.                                                    |

`service-start` refreshes the stable service wrapper to the currently installed
`monolex-headless` and sibling `monolex-pty-daemon` before asking the OS service
manager to start it. After an OpenCLIs update, use `service-stop` followed by
`service-start` so an older service-owned child does not survive the upgrade.

## Runtime Options

| Option                     | Meaning                                                                                                                                                  |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--local-only`             | Skips gateway session creation, device presence, WebSocket relay, egress, key announcement, and heartbeat while preserving local control and PTY access. |
| `--session-id <id>`        | Labels a local-only session; remote mode always opens an owned gateway session. Also available as `MONOLEX_SESSION_ID`.                                  |
| `--device-id <id>`         | Overrides the generated device id. Also available as `MONOLEX_DEVICE_ID`.                                                                                |
| `--app-id <id>`            | Selects the PTY daemon app id; default is auto-discovery with fallback `app`.                                                                            |
| `--cols <n>`, `--rows <n>` | Sets new-session dimensions; defaults are 120 × 40.                                                                                                      |
| `--proxy <port>`           | Relays the WebRTC DataChannel to a local TCP service instead of exposing a terminal PTY.                                                                 |
| `--default-cwd <path>`     | Sets the default directory for new sessions; `NIIA_DEFAULT_CWD` is supported.                                                                            |
| `--default-shell <path>`   | Sets the shell for new sessions; `NIIA_DEFAULT_SHELL` is supported.                                                                                      |

`--local-only` and `--proxy` are mutually exclusive. A `--session-id` is also
rejected outside local-only mode: remote Headless opens a new session owned by
the authenticated vault device rather than attaching a viewer token as the
host. These validation failures occur before PTY runtime startup.

Remote authentication is owned by the shared OpenCLIs vault. Do not pass
gateway secrets through arbitrary argv or environment variables; authenticate
with the estate's supported login surface and let the runtime read the vault.

## Session Close and Reaping

Version 0.1.43 adds the local control-socket twin of the gateway `tab-close`
operation. It is not a new Headless root CLI command: local automation calls
`monopty close <SESSION>`, while a remote viewer sends the corresponding tab
close event. Headless closes the PTY daemon session, removes it from the
Headless session map, and ends the matching heartbeat row so a dead shell does
not remain listed or reappear as a recoverable ghost. Closing an already-gone
session is idempotent. The operation retires one session; it does not stop the
Headless server or PTY daemon.

Version 0.1.45 keeps that Headless command/control surface and bundles PTY
Daemon 0.2.8. A close now succeeds only after the PTY owner terminates and
reaps the session shell plus its foreground descendants. On Unix the daemon
owns the session/foreground process groups and escalates from a graceful signal
to a bounded kill; on Windows it contains descendants in a Job Object with
kill-on-close. Cleanup failure remains an error rather than silently deleting
only the session row or socket, and daemon shutdown applies the same process-
tree contract to every live session.

## Local and Remote Modes

```text theme={null}
local-only                         remote mode
──────────                         ───────────
local control socket               local control socket
PTY daemon + rendered grid         PTY daemon + rendered grid
Monopty workflows                  owned gateway session
no gateway presence                presence + relay + heartbeat
```

The local control message is bounded to 1 MiB. File transfer remains confined
to the receiving user's home boundary: relative paths and `~/` resolve there,
while outside absolute paths, parent traversal, and symlink escapes fail.
Dedicated DataChannel transfers use a 4 KiB header and a 64 MiB file limit;
local control-socket JSON transfer uses a 1 MiB decoded-file limit. Remote
WebSocket/WebRTC JSON `FileGet` and `FilePut` fail closed—use
`monosystem remote cp` for cross-machine copies.

Uploads stage beside the destination and replace it atomically only after the
declared byte count and `PUT-END N` agree. Downloads do not report success until
the receiver returns `GET-ACK N`. Zero-byte files are valid. These contracts
make the transfer surface bounded and acknowledged; they do not turn Headless
into an unrestricted filesystem API.

## Service Semantics by Platform

| Platform | Service owner                | Important behavior                                                                                                                         |
| -------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| macOS    | launchd wrapper              | Registration and process liveness are separate; verify the role-tagged pidfile and local socket.                                           |
| Linux    | systemd/user-service wrapper | The wrapper starts the PTY daemon first, then Headless in local-only mode.                                                                 |
| Windows  | per-user Scheduled Task      | `service-status` trusts the wrapper pidfile and intentionally does not count unrelated orphan `monolex-headless.exe` processes as healthy. |

Service pidfiles identify `headless=PID` and `pty=PID`; status and cleanup reject
reused PIDs whose executable does not match the recorded role. The wrapper
retries a Headless process that dies within 15 seconds up to five times with a
two-second backoff. This is startup resilience, not proof of a stable PTY—run
the Monopty checks below after the service settles.

## Published Platforms

The 0.1.45 train packages Headless together with PTY Daemon 0.2.8
(`monolex-headless` plus `monolex-pty-daemon`, with `.exe` names on Windows).
Every platform fragment must record source commit
`0ccadab991a6ba90f6e4268e0d720ba229244662` and `source_dirty: false`.

| Public platform  | CDN archive SHA-256                                                | Current proof                                                                                                                            |
| ---------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `darwin-aarch64` | `a8f340613d4a99ea7de6b19e0c09ba97dc92286d8a202ea554b011965dfcbcba` | Directly downloaded and hash-verified; both payloads inspected, Headless executed as 0.1.45, and strict Developer ID verification passed |
| `linux-x86_64`   | `2558091cd7e470e11adc43594e3a124b092d9b3e0ef3bf08b9272df16f87ebbf` | Directly downloaded; archive and both extracted payload hashes verified                                                                  |
| `linux-aarch64`  | `f9def791598f6fdb5bea0a1e192372a5c6e6f33b160954011a61ecdc7eac8bf1` | Directly downloaded; archive and both extracted payload hashes verified                                                                  |
| `windows-x86_64` | `cd033e303b108b9357eae398898e06da0b650a7f0d0116c10254da63b6778e5d` | Directly downloaded; archive and both extracted PE payload hashes verified                                                               |

The extracted macOS Headless executable has SHA-256
`65fbb8a0369ae40fe948b80c53b830e6ff82f86a85c1f29d97d6cd0d20b821ef`;
its bundled PTY Daemon has SHA-256
`76d9ae5f5eaf1e85acc75a78d0d1cf2946ec89d814583dba9116437bd69ec7d3`.
Both passed strict Developer ID signature verification and reported versions
0.1.45 and 0.2.8 respectively.

The extracted Linux x86\_64 Headless executable has SHA-256
`128134a7a90795917e56f1d2c3a48a643956c243fc82f58ad7b3a0def6c4282b`;
the bundled PTY Daemon has SHA-256
`6613984819fb154c641406228c5a5ce8d512f59b043b18ae2211c356fef56fb7`.

The extracted Windows x86\_64 Headless executable has SHA-256
`42bd5f67485026b69bd46c369fae5ca16424e68a8d60aa5373f8040ced2c17be`;
its bundled PTY Daemon has SHA-256
`2191bec7087a74279e5eb55ecd3fd32adb8b4623ae1daccff4415b2c9aebb186`.

The extracted Linux AArch64 Headless executable has SHA-256
`e13527a9f4666d1d6f561afdabe19dcf2b7baa447b0936f7ff90943c76854b7b`;
its bundled PTY Daemon has SHA-256
`d96789d8bb49c5ffd16f9ee22dc25937a21161e13712fa51a1eac406d7a26743`.

The current `latest.json`, every platform fragment, and merged metadata report
`source_dirty: false`. All four platform rows were directly downloaded and
hash-verified. Platform availability proves distribution only; it does not
prove service registration or a live PTY.

## Verification

```bash theme={null}
monolex-headless service-status
monopty sockets
monopty sessions
monopty health
monopty test
monopty close <SESSION>
monopty sessions  # confirm it is gone
```

Service registration, a running process, a responsive local socket, and a
drivable PTY are separate claims. An isolated `--local-only` smoke proved the
new close path end to end: Headless owned a live daemon, Monopty created a
session, the shell exited, `close` removed the session from Headless, a repeated
close remained successful, and shutdown left no test daemon, socket, or process
behind. A complete deployment check proves each layer independently.

## Relationships

| Tool                                              | Ownership                                                          |
| ------------------------------------------------- | ------------------------------------------------------------------ |
| [Monolex PTY Daemon](/ai-clis/monolex-pty-daemon) | Spawns PTYs and owns VTE/process state beneath headless            |
| [Monopty](/ai-clis/monopty)                       | Drives and verifies the local headless control protocol            |
| [Monosystem](/ai-clis/monosystem)                 | Supervises cross-machine headless presence and remote control      |
| [Maxmux](/ai-clis/maxmux)                         | Human-facing terminal UI over the same headless and PTY foundation |
