Skip to content

Runtime

The Sloppy runtime is the orchestration layer that receives messages, decides what to do with them, and coordinates all the work that follows — model calls, background tasks, memory updates, supervision, and event emission. It runs as a set of isolated concurrent actors that each own one responsibility.

Core components

ComponentWhat it does
ChannelsHolds message history, estimates context usage, decides how to respond
WorkersExecutes background tasks: coding, research, file operations, compaction
BranchesFocused sub-task forks that load relevant memory before working
CompactorMonitors context usage and triggers summarization when needed
VisorSupervises everything: timeouts, health signals, memory maintenance, bulletins
Event BusInternal pub-sub that connects all components and exposes activity to subscribers
MemoryStores and recalls knowledge across sessions

All of these are coordinated through a single entry point. The HTTP service layer talks to this entry point; everything downstream is handled internally.

How a message is processed

When a message arrives in a channel, the runtime:

  1. Appends it to the channel's message history.
  2. Estimates how full the context window is.
  3. Decides how to respond (inline reply, spawn a branch, or spawn a worker).
  4. Executes the response path.
  5. Checks whether context compaction should run.

After the response is sent, the compactor evaluates the updated context usage and schedules a summarization job if a threshold has been crossed.

Channels

A channel is the container for a conversation. The runtime keeps the full message history in memory, along with the set of active workers attached to that channel and the current context utilization estimate.

When responding inline, the runtime assembles a prompt from the last 80 messages in the channel and injects the latest memory bulletin (a Visor-generated digest of the agent's current context) as additional background. This means the model has both the recent conversation and relevant long-term memory available on every response.

Workers

Workers are the runtime's unit of asynchronous work. When a task is too complex to answer inline — a coding task, a research job, a file operation — the runtime creates a worker and hands it a task specification: what to do, which tools to use, and how to behave when done.

Worker modes

Fire-and-forget — the worker runs to completion without waiting for external input. Used for autonomous tasks, compaction jobs, and background operations. The result is saved as an artifact when the worker finishes.

Interactive — the worker pauses after its initial execution and waits for a route message from the conversation. Used for user-facing tasks where the agent needs clarification, approval, or step-by-step guidance. The conversation can send structured commands to continue, complete, or fail the worker.

Worker lifecycle

A worker starts in a queued state, transitions to running when its executor picks it up, and ends in either completed or failed. Interactive workers have an additional waiting state between cycles. The runtime maintains a snapshot of each worker's status, start time, tools, and latest report — these are visible in the Dashboard and used by Visor for health monitoring.

Artifacts

When a worker completes, it writes an artifact: a titled, typed piece of output with a preview and full content. Artifacts are persisted to SQLite and remain accessible after a restart.

Branches

A branch is a short-lived, memory-aware sub-task. When a message benefit from deep analysis — for example, a complex question that needs to pull in past decisions and goals — the runtime can spawn a branch instead of responding inline.

Before starting work, the branch recalls up to eight memories that are relevant to the task. This gives the executor focused context without loading the entire conversation history. When the branch concludes, its summary is saved as a new memory (linked back to the memories that informed it) and appended to the channel as a system message.

Branches are supervised by Visor. Any branch that doesn't conclude within the configured timeout (default: 60 seconds) is force-concluded.

Visor

Visor is the runtime's supervision and self-awareness layer. It runs a periodic tick loop and watches for problems.

Worker timeouts — workers that have been running or waiting for longer than the configured limit are flagged with a timeout event. The service layer is responsible for cancelling them.

Branch timeouts — branches that haven't concluded within the branch timeout are force-concluded by Visor directly.

Channel health signals — if a channel accumulates too many worker failures in a short window (default: 3 failures within 10 minutes), Visor emits a "channel degraded" signal. This can trigger alerts or automatic recovery logic.

Idle detection — if the system receives no messages for a long period (default: 30 minutes), Visor emits an idle signal. Useful for heartbeat scheduling or auto-shutdown.

Memory maintenance — on a separate schedule (default: every hour), Visor runs the importance decay, pruning, and optional merge passes on the memory store. See the Memory article for details.

Bulletin generation — Visor periodically generates a compact digest of the agent's current state: recent activity, active workers, top memories by category. This bulletin is injected into every LLM prompt, giving the model ambient awareness of what's happening without requiring explicit memory queries. If the state hasn't changed since the last bulletin, the cached version is reused.

Event Bus

Every significant action in the runtime is published to an internal event bus as a timestamped envelope. Subscribers receive a live stream of events as they happen.

EventEmitted byMeaning
channelMessageReceivedChannelsA message was appended
channelRouteDecidedChannelsA route decision was made
workerSpawnedWorkersA new worker was created
workerProgressWorkersA worker reported a status update
workerCompletedWorkersA worker finished successfully
workerFailedWorkersA worker failed or was cancelled
branchSpawnedBranchesA branch was created
branchConclusionBranchesA branch concluded with a summary
compactorThresholdHitCompactorA context utilization threshold was crossed
compactorSummaryAppliedCompactorA compaction job completed
visorBulletinGeneratedVisorA new state bulletin was generated
visorWorkerTimeoutVisorA worker has been running too long
visorBranchTimeoutVisorA branch was force-concluded
visorSignalChannelDegradedVisorToo many failures in a channel
visorSignalIdleVisorSystem has been idle
visorMemoryMaintainedVisorDecay/prune maintenance completed
visorMemoryMergedVisorMemory merge pass completed

Events are buffered for late subscribers (up to 256 events). The WebSocket gateway and any registered webhook URLs receive all events in real time.

Agent configuration

Runtime type

Each agent runs in one of two modes, set in its config.json:

Native — the agent runs inside Sloppy's own runtime using a configured model provider. This is the standard mode for agents managed by Sloppy. You select which model the agent uses by setting selectedModel in the agent's config.

ACP — the agent delegates its execution to an external process running the ACP protocol. Sloppy acts as a proxy: it forwards messages to the external process and relays the responses back. Useful for integrating agents built outside of Sloppy.

Heartbeat

The heartbeat triggers a background session for the agent on a recurring schedule. During each heartbeat, the agent reads a prompt template from its HEARTBEAT.md file and executes it autonomously — for example, checking for new tasks, sending status summaries, or doing proactive maintenance.

The heartbeat is disabled by default. You can enable it and set the interval in the agent's config.

SettingDefaultWhat it controls
heartbeat.enabledfalseWhether the heartbeat is active
heartbeat.intervalMinutes5How often the heartbeat fires

Channel session auto-close

By default, channel sessions stay open indefinitely. You can configure them to close automatically after a period of inactivity.

SettingDefaultWhat it controls
channelSessions.autoCloseEnabledfalseWhether idle sessions close automatically
channelSessions.autoCloseAfterMinutes30How long a session must be idle before closing

Visor settings

SettingDefaultWhat it controls
visor.tickIntervalSeconds30How often the supervision loop runs
visor.workerTimeoutSeconds600Maximum runtime for a worker before a timeout event is fired
visor.branchTimeoutSeconds60Maximum runtime for a branch before force-conclusion
visor.maintenanceIntervalSeconds3600How often memory maintenance runs
visor.channelDegradedFailureCount3Worker failures needed to trigger a degraded signal
visor.channelDegradedWindowSeconds600Time window for counting failure events
visor.idleThresholdSeconds1800Inactivity period before an idle signal is emitted
visor.bootstrapBulletintrueWhether a bulletin is generated on startup
visor.bulletinMaxWords300Maximum length of a generated bulletin
visor.mergeEnabledfalseWhether similar memories are automatically merged
visor.mergeSimilarityThreshold0.80Minimum recall score to consider two memories for merging
visor.mergeMaxPerRun10Maximum merges per maintenance pass

Recovery after restart

When the Sloppy process restarts, the runtime replays all persisted state from SQLite in a deterministic order: channels are recreated, artifacts are restored, and events are replayed. Workers that have no matching event in the log are restored directly from the task table. This means a crash or a controlled restart does not lose in-progress context.

Built from docs/ and styled to match the live Dashboard shell.