Documentation
Concepts
The detachable desktop host: attaching, detaching and what restores.
On this page
A session is a process, not a window
A session is a detachable host process that owns a running TDE desktop. The host allocates a PTY, launches the desktop inside it, and publishes a Unix socket. Your terminal is only a viewer: attach to look at the desktop, press Ctrl-] to walk away, reattach tomorrow from a different SSH connection and find the same windows in the same places.
That separation is what makes TDE usable on a VPS. The desktop's lifetime is tied to the host process, not to your shell, your terminal emulator or your network link.
tde session start
tde session attachThis page covers what a session is. For the full verb list, flags and on-disk
state, see the tde session reference.
Anatomy
Everything a session owns lives in one directory, ~/.tde/sessions/<name>/,
created 0700 with every file inside it 0600.
| Piece | What it is |
|---|---|
| Host process | The supervisor. Owns the PTY, the socket and the session's identity. |
| Desktop child | tde desktop --desktop-child, running inside the PTY. |
session.sock | The Unix socket attach clients connect to. Owner-only, never TCP. |
metadata.json | Identity, generation counter, controller lease, heartbeat. |
manifest.json | The window layout that gets restored. |
desktop.log | What tde session logs prints. |
The host writes a heartbeat every 250 ms. tde session status reports Running
only when that heartbeat is fresh and the recorded process identity — pid,
start time and an executable fingerprint — still matches a live process. A pid
number alone is never treated as proof, which is why kill refuses to delete
state it cannot attribute.
If the desktop child dies unexpectedly, the host restarts it — up to three times — and each restart increments the session's generation counter. Attached clients notice the change, request a resync and are handed a fresh full snapshot rather than a stream that no longer makes sense.
Attaching, detaching, spectating
Several clients can attach to one session at the same time; they all see the same frames. Exactly one of them holds the controller lease and can send input. The rest are told, on attach:
TDE session attached as spectator; input disabledThe lease is released when the controller detaches, disconnects or the generation rotates, and the next client that asks for it gets it. Every mutating frame also carries a sequence fence, so a client that fell behind cannot replay stale input into a session that has moved on.
Ctrl-] is the only key the attach client intercepts. Everything else — including Esc, Ctrl-C and Ctrl-Q — belongs to the desktop.
What restores
The desktop writes manifest.json every five seconds and once more at shutdown.
On the next start it reads that manifest back and rebuilds the layout.
| Restored | Detail |
|---|---|
| Window layout | Position, size, workspace, stack order, taskbar order, minimized and always-on-top flags, and which window had focus. |
| First-party windows | Which TDE apps were open — Files, My Loop, Code, Sheets, Browser and the rest — reopened fresh. |
| PTY relaunch intent | Program, argv, working directory and the names of the environment variables the command was launched with. |
| Shell scrollback | The captured output of TDE Shell windows (see below). |
Two limits are worth internalising:
- Environment values are never persisted. Only key names are recorded, and they are resolved against the current environment at restore time. A session restore cannot leak a token that was exported into a shell.
- App-internal state is not restored. A first-party window comes back open, not where you left it. Selected task, active tab, filters and draft fields belong to each app and are not part of the manifest.
The manifest is bounded on both write and read: at most 128 windows, 1 MiB total, 4 KiB per string, 128 argv entries and 64 environment key names. A program path is re-validated before relaunch — it must still be absolute, canonical, non-symlink and executable. If the recorded working directory no longer exists, the window is relaunched in your home directory and TDE tells you so:
Session restore degraded — <title> cwd missing; using homeA manifest that fails validation is skipped entirely with a "Session restore skipped" toast, rather than half-applied.
Persistent scrollback
TDE Shell windows keep their output across restarts. Raw primary-screen bytes are
written to ~/.tde/scrollback/, namespaced by session id and generation, with an
index file listing each retained shell's id, title and working directory. Both the
directories (0700) and the files (0600) are owner-only, and every write is
atomic.
| Bound | Value |
|---|---|
| Retained bytes per shell | 512 KiB (configurable) |
| Shells restored on start | 8, newest first |
| Generation namespaces kept | 3 |
| Flush cadence | Every 3 seconds, plus once at shutdown |
A new generation seeds itself from the previous one, so a desktop restart does not cost you your history. Older namespaces beyond the newest three are pruned.
persist_scrollback = true
restore_on_start = true
max_scrollback_kb = 512Two behaviours are deliberate and easy to misread as bugs:
- Closing a shell window discards its history. Closing is treated as an explicit "I am done with this", and the record is removed immediately.
- Task-scoped shells with a Project Environment are never recorded at all, so secrets injected into a run cannot end up in a file on disk.
Only TDE Shell windows are recorded. A generic PTY pane restores its command through the manifest, but not its output.
Searching and exporting scrollback
Search and export run against the live terminal of an open window — which includes history that was replayed into it at restore. They are exposed through the agent surface, not through a keybinding:
tde agent scrollback-search WINDOW_ID "connection refused" 200
tde agent scrollback-export WINDOW_ID /tmp/shell.json jsonSearch is case-insensitive and returns at most 100 matches by default, 1000 at the
most. Export writes text or json, capped at 1 MiB — when the buffer is larger,
the oldest rows are dropped first and the result is flagged as truncated. Both are
classified read-only, so neither needs the controller lease. See the
Agent API for the transport.
There is no cross-session full-text index: the history of a shell you closed, or of a session you never restored, is not searchable.
What a session is not
- Not a snapshot of process memory. Nothing about a running program's state, open file descriptors or sockets survives. A relaunched command starts over.
- Not multi-view. Every attached client sees the same layout and the same focus. Per-client window arrangements are not implemented.
- Not a remote broker. Attaching from another machine means reaching it over SSH
first and running
tde session attachthere — see Resume anywhere. Managed Machines run that attach for you on an interactive login, but the model is the same: the session lives on its own host. - Not the Runtime. A session keeps a desktop alive for a human. The Runtime keeps work running with no desktop at all. They are independent; you can run either without the other.