Runtime and storage configuration¶
Configuration for processes, services, local storage, and telemetry.
procs¶
Durable proc records live in ~/.sase/procs/procs.jsonl, with combined output logs
under ~/.sase/procs/logs/. Retention keeps every pending or running proc plus the
newest configured number of finished procs. Lowering the limit trims the oldest finished
rows and their logs; active work is never pruned. Finished procs tagged command-line
(TUI Command Line submissions) keep a separate bucket of 50 beside this limit, so heavy
Command Line use never evicts operational proc history.
Each proc also has a runtime directory under ~/.sase/procs/runtime/. Retention deletes
a pruned row's runtime directory immediately, while the hourly proc_runtime_sweep
housekeeping job removes older rowless (orphaned) runtime directories within the horizon
and per-pass budget below. Fresh orphans are left alone so a launch that is still
reserving its row is never raced.
procs:
history_limit: 100
runtime_orphan_horizon_seconds: 259200
runtime_orphan_max_removals: 2000
The top-level tasks block is still schema-valid, and sase config layers and
sase doctor flag it for migration. In practice the legacy key has no effect in a
normal merged configuration: the bundled defaults always supply procs.history_limit,
which takes precedence over tasks.history_limit. Move the value to
procs.history_limit to change retention.
service¶
The per-machine service host supervises configured daemon procs and transient oneshots.
Its catalog is deliberately machine-owned: builtin defaults, plugin defaults, user
config, and machine overlays compose field by field, while project-local sase/sase.yml
service: entries are ignored — the host resolves machine-level layers only, never a
project-local sase.yml. Lists replace earlier lists whole; env is the one map that
merges key by key. A section-level error fails closed, while an invalid individual entry
stays visible as unavailable and does not block valid peers.
service:
procs:
scheduler:
builtin: scheduler
description: "SASE's background automation: routines and their jobs."
gateway:
builtin: gateway
description: "Mobile gateway HTTP API for remote agent dispatch."
enabled: false
indexer:
command: [my-indexer, --watch]
cwd: ~/work
env:
LOG_LEVEL: info
restart: on-failure
after: [scheduler]
The shipped scheduler entry is enabled and owns routine/job automation. The shipped
gateway entry is disabled so a default host does not expose a mobile API on machines
that never paired a phone; it is enabled per machine in the overlay where the gateway is
wanted. Builtin launchers must use the entry's own reserved name. A custom entry instead
supplies exactly one command: a string runs through sh -c, while a string array runs
directly as argv.
Generated reference for service
A bare command array's first element (for example sase_job_tg_inbound) is looked up
on PATH first and then in the bin directory of the interpreter running the host. The
second lookup is what makes a plugin's console scripts work under
uv tool install --with, which links only the primary package's entry points onto
PATH. A PATH hit always wins, an element that contains a path separator is used as
written, and the remaining arguments are never changed. The string (shell) form gets no
such fallback, because the shell resolves the name; prefer the array form for plugin
scripts. sase service init warns when an enabled entry's executable resolves nowhere.
sase service proc enable/disable writes machine-local effective enablement without
editing YAML. stop changes only the current boot: it records a marker that is cleared
on the next host boot. start and restart record a durable, numbered request that
also clears that marker; the host consumes it and the CLI waits for the confirmed pid.
Use sase service proc show NAME to see where an effective entry and enablement came
from, plus the current restart decision and any pending request.
Restart policy: always restarts after every exit and on-failure after a non-clean
one, each with a backoff that starts at 1 second and doubles up to 60 seconds. A clean
exit is exit code 0, a success_exit_codes code, or death by SIGTERM, SIGINT,
SIGHUP, or SIGPIPE; a stop the host itself requested is never restarted. Three
restart-triggering exits or spawn failures within 60 seconds mark the proc crash_loop
and raise one service notification per crash-loop episode; a run of at least 5 minutes
resets the backoff and ends the episode. When the policy decides not to restart — a
clean exit under on-failure, or any exit or spawn failure under never — the host
parks the proc instead of relaunching it on the next reconcile, and raises a service
notification when the proc is still desired running. A parked proc stays down until an
explicit start/restart request, a changed entry, a disable-then-enable cycle, or a
restart of the service host itself. If the service.procs configuration stops loading,
the host keeps supervising its last-known-good configuration and surfaces the load error
as the host error in sase service status; a host that has never loaded a valid
configuration launches nothing until it does.
sase service init --yes installs an idempotent user unit (sase.service under
systemd --user on Linux, sh.sase.service as a macOS LaunchAgent), captures only the
allow-listed provider credentials, PATH, SASE_TMPDIR, SASE_HOME, and configured
mobile credential environment variable into a mode-0600 file, retires legacy
gateway/AXE units, enables the unit, and starts it. SASE_FEATURE_FLAGS is never
captured: the host resolves flags from saved state. Planning and diffs redact every
captured value. Linux warns when user linger is off because the service may then stop at
logout. See sase service for lifecycle
commands.
Source: src/sase/default_config.yml, src/sase/config/sase.schema.json,
src/sase/service/config.py, src/sase/service/platform.py
disk¶
Disk-pressure thresholds combine absolute byte floors with proportional free-space
floors, so large volumes warn before they are almost out of bytes. The doctor resource
check uses these values, and the hourly disk_pressure housekeeping job uses the warn
threshold to decide when to notify and run owner-safe cleanup early.
disk:
pressure:
warn_free_percent: 5.0
error_free_percent: 1.0
top_owner_min_bytes: 1073741824
sase doctor still honors its absolute floors of 3 GiB for WARN and 1 GiB for ERROR;
the effective threshold is the larger of the absolute and proportional values. Use
sase disk list to see SASE disk usage by owner and sase disk reap to preview or run
the owners' cleanup passes.
Source: src/sase/default_config.yml, src/sase/core/disk_pressure.py
managed_tmp¶
Age horizons and pressure thresholds for the managed SASE temp root: $SASE_TMPDIR when
set, otherwise $SASE_HOME/tmp (~/.sase/tmp by default). SASE writes scratch there in
per-purpose bucket directories, and launched agents get TMPDIR/TMP/TEMP,
CARGO_TARGET_DIR, and CARGO_BUILD_BUILD_DIR pointed into managed buckets. Runners
remove their own launch-assigned scratch at exit when no live process still uses it;
sase disk reap and the hourly managed_tmp_reap housekeeping job clean up the rest
with these values.
Each bucket belongs to one horizon category. Editor, wrapper, per-agent agent-tmp, and
similar command scratch uses the command-scratch horizon; handoff, gh-diffs, and
muse-prompts use the handoff horizon; build-targets and cargo-targets use the
build-scratch horizon; and launch-prompts, screenshots, and workflow-artifacts,
which sase's TUI and screenshot tooling read back after a run ends, use the run-artifact
horizon. Unknown buckets and stray top-level entries are aged at the handoff horizon.
The bucket mapping is fixed; only the durations and pressure thresholds are
configurable.
Between the age horizons runs a dead-launch backstop over the launch-keyed buckets
(agent-tmp, cargo-targets, legacy build-targets) for launches that never ran
runner-exit cleanup — crashed, SIGKILLed, OOM-killed, or handed off to a monitor/gate
follow-up, which mints a fresh scratch key and leaves the old one quiet. Entries whose
newest descendant write predates dead_launch.grace_seconds and that no live process
holds (by environment or working directory, observed through procfs in one batch scan)
are removed largest-first within the removal budget. Held and incomplete-observation
entries are preserved and counted; hosts without readable procfs skip the pass and keep
the age horizons as the fallback.
Pressure pruning is a later pass that removes aged, large build scratch early when the
managed root grows past pressure.max_bytes or the filesystem's free space drops below
pressure.min_available_bytes. It never prunes generic agent scratch, handoff data,
unknown buckets, or build trees with fresh descendants. While the procfs observer is
available it is liveness-aware: a held entry is never removed, an incomplete observation
is preserved, and an unheld entry needs only the dead-launch grace rather than
pressure.min_age_seconds.
Every root get_sase_managed_tmpdir() writes into is recorded in a Rust-owned registry
at $SASE_HOME/managed_tmp/roots.json (schema version plus
{path, first_seen_epoch, last_seen_epoch} entries, written atomically under a lock
file). The hourly managed_tmp_reap job, the disk_pressure cleanup, and
sase disk reap each reap the effective root plus every registered root that still
exists, so scratch is bounded no matter which environment its writer resolved. A root
nested inside another covered root is folded into it, so it is not reaped or counted
twice. Registration is fail-open and never breaks a launch; only absolute, non-symlink
directories enroll, and broad roots such as /tmp or $HOME are refused.
In practice, the housekeeping managed_tmp_reap job, the disk_pressure job, and
sase disk reap all pass the shared disk.pressure warn threshold (the larger
of 3 GiB and disk.pressure.warn_free_percent) as both the free-space floor and the
recovery target, so pressure.min_available_bytes and
pressure.recovery_available_bytes currently take effect only for direct reaper calls
that leave those values unset.
Launched agents export CARGO_INCREMENTAL=0 by default, or CARGO_INCREMENTAL=1 when
agent_cargo_incremental is enabled. Only hosts with the splitting rustc wrapper
(athena) should opt in; elsewhere incremental test builds cost ~9 GB per run.
managed_tmp:
horizons:
command_scratch_seconds: 43200
handoff_seconds: 259200
build_scratch_seconds: 86400
run_artifact_seconds: 1209600
max_removals: 2000
dead_launch:
enabled: true
grace_seconds: 7200
pressure:
max_bytes: 17179869184
target_bytes: 8589934592
min_available_bytes: 34359738368
recovery_available_bytes: 51539607552
min_age_seconds: 43200
low_free_space_min_age_seconds: 3600
min_entry_bytes: 67108864
agent_cargo_incremental: false
Generated reference for managed_tmp
Source: src/sase/default_config.yml, src/sase/config/_settings_system.py,
src/sase/core/managed_tmp_reaper.py
telemetry¶
Configures local telemetry recording and retention. See Telemetry details for the full telemetry reference, including the CLI, metric catalog, local store, and Admin Center tab.
telemetry:
enabled: true
flush_interval_seconds: 15
retention:
raw_seconds: 172800
rollup_5m_seconds: 2592000
rollup_1h_seconds: 31536000
health_thresholds:
error_rate_warn: 10.0
error_rate_critical: 25.0
retry_rate_warn: 10.0
retry_rate_critical: 25.0
p95_latency_warn: 300.0
p95_latency_critical: 600.0
Generated reference for telemetry
The legacy telemetry.prometheus block (url, pushgateway_url, exposition_port) is
still schema-valid for compatibility but is ignored.
Source: src/sase/default_config.yml, src/sase/telemetry/_config.py
tool_runs¶
Operational retention for the machine-local ToolRun ledger. This block uses ordinary
config-layer precedence (builtin, plugin, user, overlay, then project). It is
independent of the project-owned tools catalog: changing
retention cannot change argv.
tool_runs:
summary_days: 180
detail_days: 60
log_days: 14
log_max_bytes: 2147483648
run_log_max_bytes: 268435456
event_max_bytes: 16777216
soft_ceiling:
default: ""
providers: {}
Generated reference for tool_runs
tool_runs.soft_ceiling is the most time an agent should block on one sase tool run
before escalating to a monitor; it kills nothing; the effective budget is the smaller of
this and the hard ceiling's budget. The provider entry wins, then default, then none.
A malformed or non-positive value is ignored with one warning and never fails a launch.
Unknown fields and non-positive or inconsistent horizons are rejected. JSON Schema
cannot express detail_days <= summary_days; runtime validation covers that.
Source: src/sase/default_config.yml, src/sase/config/sase.schema.json,
src/sase/config/tools.py
update¶
Configures install-mode switching (see Install mode switching).
update:
dev_root: "~/projects/github"
Generated reference for update
Source: src/sase/default_config.yml, src/sase/mode_switch/repos.py
Related¶
- Runtime and stored data configuration — generated keys and defaults.
- Configuration reference — all configuration subjects.
_[project]: A sase project is a named unit of work registered with SASE. _[workspace]: A sase workspace is a numbered clone of a project's primary repo, managed by the workspace store and tracked in that project's registry.json. _[agent]: A sase agent is an agent session or a single agent that does not belong to a session. _[prompt]: A prompt is the text SASE hands to a provider to start an agent turn. _[macro]: A macro is a reusable prompt triggered with #name in agent prompts. _[Patch]: A Patch is SASE's local unit of change. _[bead]: A bead is one tracked work item in SASE's git-native issue tracker. _[plan]: A plan is a persisted, approved artifact recording the intent behind agent work. _[TUI]: The TUI is SASE's terminal interface for running agents and reviewing results. _[epic]: An epic is an executable multi-phase plan run with sase bead work. _[gate]: A sase gate is a durable, command-backed request for one user decision, created when work must pause for the user. _[monitor]: A sase monitor is a monitor turn that runs one long command under a detached supervisor, so the command outlives the agent that started it. *[stitch]: A stitch is the lightweight ordered change record inside a Patch's STITCHES: section.