Documentación
Runtime daemon
The per-user service that keeps work running with no desktop open.
En esta página
Work that does not need you watching
The TDE Runtime is a per-user background service that owns durable execution. It runs pipeline stages, Bot polls and bounded shell commands with no desktop open, no terminal attached and nobody logged into a UI. Close every TDE window on a VPS and your tasks keep moving.
It is not the same thing as a session. A session keeps a desktop alive so a person can come back to it. The Runtime keeps work alive so it finishes whether or not anybody comes back.
tde runtime status
tde runtime jobsThis page explains the model. The verbs, flags and JSON shapes are in the
tde runtime reference.
It installs itself
You do not normally start the Runtime. The first semantic command you run —
tde task, tde project, tde pipeline, tde share, tde ask, tde chat —
installs and starts the per-user service before it does anything else.
Later commands re-render the service definition from the current executable path,
the resolved PATH, the profile name and the log path, then compare it
byte-for-byte with the installed file. Missing or drifted means the service is
replaced and reloaded before the command proceeds. Upgrade TDE and the very next
CLI invocation quietly repoints the unit at the new binary.
| Platform | What gets installed |
|---|---|
| Linux | A systemd user unit, ~/.config/systemd/user/tde-runtime-<profile>.service |
| macOS | A LaunchAgent, ~/Library/LaunchAgents/dev.tde.runtime.<profile>.plist, in the gui/<uid> domain |
Installation is transactional. TDE keeps the previous definition, writes the new one atomically, activates it, and then requires a real readiness proof — a heartbeat whose version matches the running binary, a live pid, an existing socket, and a successful ping/pong over the semantic socket — within 15 seconds. If any of that fails it restores the previous definition and its previous enabled state. On Linux it also refuses to manage a unit that systemd resolves to a file path TDE did not write.
When there is no service manager
Some hosts have no usable user service manager, or a broken residual unit. Rather
than block every CLI command, TDE announces the reason on stderr and falls back to
a detached Unix session: it spawns tde runtime detached-run, whose first act
is to call setsid(). Closing the terminal that started it does not deliver a
hangup to the daemon.
The fallback lasts for the current login or boot, not across reboots. It is entered when the service manager preflight fails, when a managed start does not become ready in 15 seconds, or when an activation rolled back.
What it executes
Jobs are typed. Three kinds have production executors:
| Job kind | What it does |
|---|---|
process_exec | Runs one bounded command with a cleared environment and a fixed safe PATH. Enqueued by tde runtime exec. |
pipeline_stage | Runs a complete My Loop pipeline from a frozen execution snapshot. |
connector_poll | Runs an Bot cron or webhook trigger. |
Concurrency is modest and worth knowing: one process job and one business job per profile at a time. The Runtime is a reliability mechanism, not a build farm.
How a job survives everything
The job store is a SQLite database under ~/.tde/runtime/<profile>/jobs/. Five
mechanisms stack on top of it.
Leases. A worker claims a job by writing an owner and a lease deadline (30 seconds by default), then heartbeats it every 10 seconds. Nothing else may touch a claimed job while its lease is live.
Fencing. Each lease carries a monotonic generation. Every completion, failure, cancellation and journal append re-checks owner and generation, so a worker that was presumed dead and came back cannot commit a result over its successor.
Idempotency. A job may carry an idempotency key, unique per kind. Re-enqueuing returns the existing record instead of duplicating work — a pipeline run is keyed on the task and the run intent, an Bot on its id and trigger, so a retried CLI call or a replayed webhook is a no-op.
Recovery, not backoff. A job whose lease expired is examined, never blindly
retried: if a cancel was requested it becomes cancelled; if it has already used
its attempts (three by default) it becomes failed; otherwise it goes back to
queued. A process_exec job that still has a recorded live child is left alone
until that child is reaped. There is no exponential backoff — requeues are
immediate, paced only by the 50 ms poll.
Cancellation. Cancels are cooperative and are recorded even without a lease. Executors observe the request at checkpoints. Shutdown-induced interruption is distinguished from a user cancel so external leases stay recoverable.
Frozen snapshots
A pipeline job does not read live configuration when it eventually runs. At dispatch time TDE freezes an immutable execution snapshot into the job payload: the pipeline definition, the agent chosen for each stage, and the run config — model routing, budgets, cycle limits, verification commands and timeouts.
Editing a pipeline afterwards does not mutate a run that is already queued. It also means a queued run cannot be surprised by a stage whose agent was deleted: the snapshot is validated on the way in and on the way out.
Durable, resumable events
Two journals back the "watch a task from anywhere" experience.
Each pipeline run appends a JSON-lines journal, one line per event, flushed and
fsync-ed before the call returns; a torn tail from a crash is repaired on open
and the sequence resumes. A crash can lose at most the in-flight line.
Separately, a SQLite event store holds control events keyed by a monotonic
event_id. Readers pass the last id they saw and get everything after it, up to
1000 at a time. That cursor is the whole trick behind tde task watch and
tde task logs surviving both client and daemon restarts — the reader is stateless
and the store is authoritative. A durable intent outbox does the same job in the
write direction, reconciling any pending task create, retry, cancel or gate
decision at daemon boot.
Where it keeps things
| Path | Contents |
|---|---|
~/.tde/runtime/<profile>/semantic.sock | The control socket every CLI client connects to. |
~/.tde/runtime/<profile>/jobs/ | The job store and the per-run event journals. |
~/.tde/runtime/<profile>/runtime.log | What tde runtime logs prints. |
~/.tde/runtime/<profile>/status.json | The heartbeat the status commands read. |
Directories are created 0700 and the log 0600 before anything starts. The
socket is a 0600 Unix domain socket and is never bound to a TCP port on any
interface — anything that can talk to it is already running as you.
The desktop and Web Share are peers, not clients-of-a-proxy: they read the same durable board, project, pipeline and job stores the Runtime writes. There is no separate "CLI board", and no rendered frames travel over the semantic socket.