pub struct KernelConfig {Show 17 fields
pub name: String,
pub vfs_mode: VfsMountMode,
pub cwd: PathBuf,
pub skip_validation: bool,
pub interactive: bool,
pub ignore_config: IgnoreConfig,
pub output_limit: OutputLimitConfig,
pub allow_external_commands: bool,
pub trash_enabled: bool,
pub errexit_enabled: bool,
pub initial_vars: HashMap<String, Value>,
pub request_timeout: Option<Duration>,
pub kill_grace: Duration,
pub vfs_budget_bytes: Option<u64>,
pub overlay: bool,
pub job_manager: Option<Arc<JobManager>>,
pub kill_children_on_parent_death: bool,
}Expand description
Configuration for kernel initialization.
Fields§
§name: StringName of this kernel (for identification).
vfs_mode: VfsMountModeVFS mount mode — controls how local filesystem is exposed.
cwd: PathBufInitial working directory (VFS path).
skip_validation: boolWhether to skip pre-execution validation.
When false (default), scripts are validated before execution to catch errors early. Set to true to skip validation for performance or to allow dynamic/external commands.
interactive: boolWhen true, standalone external commands inherit stdio for real-time output.
Set by script runner and REPL for human-visible output. Not set by MCP server (output must be captured for structured responses).
ignore_config: IgnoreConfigIgnore file configuration for file-walking tools.
output_limit: OutputLimitConfigOutput size limit configuration for agent safety.
allow_external_commands: boolWhether external command execution (PATH lookup, exec, spawn) is allowed.
When true (default), commands not found as builtins are resolved via PATH
and executed as child processes. When false, only kaish builtins and
backend-registered tools are available.
Security: External commands bypass the VFS sandbox entirely — they see
the real filesystem, network, and environment. Set to false when running
untrusted input.
trash_enabled: boolEnable trash-on-delete for rm (set -o trash).
When enabled, small files are moved to freedesktop.org Trash instead of
being permanently deleted. Can also be enabled at runtime with set -o trash
or via KAISH_TRASH=1.
errexit_enabled: boolEnable errexit (set -e) at kernel construction (set -o errexit default).
When enabled, a script aborts at the first statement that exits
nonzero instead of continuing to the next one. Off by default —
standard shell behavior, so an embedder upgrading kaish sees no
change. There is one piece of state behind this
(Scope::error_exit_enabled), seeded from this field and mutated at
runtime by set -e/set +e: this only picks the starting value,
a script’s own set -e/set +e still applies afterward regardless
of what this was, and set -o always reports the true, single
answer no matter which one set it. ExecuteOptions::errexit
overrides this for one call.
initial_vars: HashMap<String, Value>Variables to populate the root scope with at construction, all marked for export to child processes.
The kernel itself is hermetic — it never reads std::env::vars() —
so frontends that want OS-env passthrough (REPL, MCP) populate this
from std::env::vars(). Embedders that want isolation pass nothing
(or only the keys they curate).
request_timeout: Option<Duration>Default per-request timeout. When Some, every execute_with_options
call without an explicit ExecuteOptions::timeout uses this duration.
When elapsed, the kernel cancels the request, kills any external
children with the configured grace, and returns exit code 124.
None means no default timeout — only explicit per-call timeouts apply.
kill_grace: DurationGrace period between SIGTERM and SIGKILL when killing an external child on cancellation or timeout.
Defaults to 2 seconds. Set to Duration::ZERO to escalate immediately
to SIGKILL. Long-shutdown processes (databases, etc.) may need more.
vfs_budget_bytes: Option<u64>Cap on memory-resident bytes across all kernel-owned MemoryFs mounts.
One shared ByteBudget (labeled "vfs-memory") is created at kernel
construction and handed to every MemoryFs the kernel builds in
setup_vfs (Passthrough /v; Sandboxed / and /v; NoLocal /,
/tmp, /v). Writes that would exceed the cap fail loudly with
StorageFull — an in-band error a model reads and adapts to; fail
loud over quietly eating RAM.
Why the agent preset is bounded by default: an agent embedder
typically creates a fresh kernel per execute() call, so the 64 MiB cap
is per-call, not per-session. Embedders that know their workload needs
more opt out with without_vfs_budget() or raise the cap with
with_vfs_budget(bytes) — protection on by default, opt out knowingly.
All other profiles default to None (unbounded).
Follows the same pattern as OutputLimitConfig: agent preset bounded, rest unbounded.
overlay: boolEnable copy-on-write overlay mode (opt-in).
When true, the primary local filesystem mount is wrapped in an
OverlayFs so writes are virtual — the lower layer is never touched.
Use kaish-vfs status/diff/commit/reset to inspect and manage the
overlay transaction.
Passthrough: / becomes OverlayFs over LocalFs::read_only("/").
Sandboxed{root}: the {root} mount becomes
OverlayFs over LocalFs::read_only(root); the /tmp and XDG runtime
mounts stay as real LocalFs (real writes escape the transaction —
see docs/kaish-overlayfs.md for the escape-hatch inventory).
NoLocal: incompatible — construction fails loudly (everything is
already virtual; an overlay adds no value and no lower layer to wrap).
with_backend: incompatible — the embedder controls the VFS; the
kernel cannot wrap it without bypassing the embedder’s semantics.
Not default-on for the agent preset: each execute() call gets a fresh kernel,
making the overlay a per-call transaction — kaish-vfs commit must run
in the same call as the writes, or the transaction is discarded on drop.
Frontends (REPL, MCP) expose --overlay as an explicit opt-in flag.
job_manager: Option<Arc<JobManager>>The JobManager this kernel adopts. None — the default — builds a
fresh one, so every kernel owns its own job table.
Supply one to share a single job table across kernels. An embedder that
builds a kernel per request (kaijutsu builds one per tool call) has no
other way to keep a cmd & job reachable: ids, status, and output
streams all live on the manager, so a per-kernel manager takes them
down with the kernel that made it. One manager held by the embedder and
handed to every kernel keeps & usable across calls, and keeps job ids
unique because they are minted from the manager’s own counter.
A shared manager carries shared settings. kill_grace and
persist_output_files are stamped onto the manager at kernel
construction, so the last kernel built wins for both: a hermetic kernel
(NoLocal, or any with_backend kernel) turns persist_output_files
off for every kernel on that manager, and each kernel’s
Self::kill_grace overwrites the previous one’s. Share a manager
between kernels configured alike, or accept the last writer.
Set through Self::with_job_manager.
kill_children_on_parent_death: boolArm PR_SET_PDEATHSIG(SIGKILL) on every external command this kernel
spawns, so the OS kills the child the instant this process dies —
for any reason, including kill -9, a segfault, or an OOM kill.
Off by default; on for Self::agent and Self::agent_with_root,
the same “protection on by default for the agent preset, opt in
elsewhere” split Self::vfs_budget_bytes uses.
Why not unconditional. kaish already puts every child in its own
process group and kills through a pidfd on cancel, and drops it with
kill_on_drop. All three need this process to still be running code,
so none of them survive a hard kill — that is the gap this closes. But
closing it costs something a human at a REPL may not want: an armed
child cannot outlive its shell, at all, and the child has no way to
opt out from inside (unlike SIGHUP, which nohup/disown exist to
escape). A REPL user who backgrounds a long download and exits expects
it to keep going. An agent embedder expects the opposite — an
invisible orphaned cargo build is the failure — so the presets
differ rather than one behavior being forced on both.
Linux only. macOS has no PR_SET_PDEATHSIG and no equivalent that
works without a live parent (kqueue’s NOTE_EXIT needs a watcher
process). This flag is accepted and has no effect there, rather than
being faked with something weaker.
Set through Self::with_kill_children_on_parent_death.
Implementations§
Source§impl KernelConfig
impl KernelConfig
Sourcepub fn named(name: &str) -> Self
pub fn named(name: &str) -> Self
Create a kernel config with the given name (sandboxed by default).
Sourcepub fn repl() -> Self
pub fn repl() -> Self
Create a REPL config with passthrough filesystem access.
Native paths like /home/user/project work directly.
The cwd is set to the actual current working directory.
Sourcepub fn agent() -> Self
pub fn agent() -> Self
Create a sandboxed-agent config with sandboxed filesystem access.
The preset for embedding kaish as an untrusted agent’s shell (e.g. an MCP
server like kaibo/kaijutsu): sandboxed VFS, non-interactive, bounded
memory and output. Local filesystem is accessible at its real path (e.g.,
/home/user), but sandboxed to $HOME. Paths outside the sandbox are not
accessible through builtins. External commands still access the real
filesystem — use .with_allow_external_commands(false) to block them.
VFS memory is bounded at 64 MiB per execute() call by default (an agent
embedder typically creates a fresh kernel per call). Raise or remove with
with_vfs_budget / without_vfs_budget.
Sourcepub fn agent_with_root(root: PathBuf) -> Self
pub fn agent_with_root(root: PathBuf) -> Self
Create a sandboxed-agent config with a custom sandbox root.
Use this to restrict access to a subdirectory like ~/src.
VFS memory is bounded at 64 MiB per execute() call by default.
Raise or remove with with_vfs_budget / without_vfs_budget.
Sourcepub fn isolated() -> Self
pub fn isolated() -> Self
Create a config with no local filesystem (memory only).
Complete isolation: no local filesystem and external commands are disabled. Useful for tests or pure sandboxed execution.
Sourcepub fn with_vfs_mode(self, mode: VfsMountMode) -> Self
pub fn with_vfs_mode(self, mode: VfsMountMode) -> Self
Set the VFS mount mode.
Sourcepub fn with_skip_validation(self, skip: bool) -> Self
pub fn with_skip_validation(self, skip: bool) -> Self
Skip pre-execution validation.
Sourcepub fn with_interactive(self, interactive: bool) -> Self
pub fn with_interactive(self, interactive: bool) -> Self
Enable interactive mode (external commands inherit stdio).
Sourcepub fn with_ignore_config(self, config: IgnoreConfig) -> Self
pub fn with_ignore_config(self, config: IgnoreConfig) -> Self
Set the ignore file configuration.
Sourcepub fn with_output_limit(self, config: OutputLimitConfig) -> Self
pub fn with_output_limit(self, config: OutputLimitConfig) -> Self
Set the output limit configuration.
Sourcepub fn with_allow_external_commands(self, allow: bool) -> Self
pub fn with_allow_external_commands(self, allow: bool) -> Self
Set whether external command execution is allowed.
When false, commands not found as builtins report that external
commands are disabled on this shell — distinct from “command not
found”, which stays reserved for a name that genuinely isn’t
resolvable — instead of searching PATH. Backend-registered tools
(MCP, an embedder’s own registry) are unaffected and still resolve.
The exec and spawn builtins also refuse, with the same wording.
Use this to prevent VFS sandbox bypass via external binaries.
Sourcepub fn with_trash(self, enabled: bool) -> Self
pub fn with_trash(self, enabled: bool) -> Self
Enable or disable trash-on-delete at startup.
Sourcepub fn with_errexit(self, enabled: bool) -> Self
pub fn with_errexit(self, enabled: bool) -> Self
Enable or disable errexit (set -e) at startup. See errexit_enabled
for precedence against ExecuteOptions::errexit and runtime set -e.
Sourcepub fn with_var(self, name: impl Into<String>, value: Value) -> Self
pub fn with_var(self, name: impl Into<String>, value: Value) -> Self
Add a single initial variable; marked exported when the kernel boots.
Repeated calls add (last write wins on key collision).
Sourcepub fn with_initial_vars(self, vars: HashMap<String, Value>) -> Self
pub fn with_initial_vars(self, vars: HashMap<String, Value>) -> Self
Replace the entire initial-vars map. All entries are marked exported.
Sourcepub fn with_vars(self, vars: HashMap<String, Value>) -> Self
pub fn with_vars(self, vars: HashMap<String, Value>) -> Self
Extend the initial-vars map with the given entries (last write wins).
Sourcepub fn with_request_timeout(self, timeout: Duration) -> Self
pub fn with_request_timeout(self, timeout: Duration) -> Self
Set the default per-request timeout (kernel-wide).
Each execute_with_options call without an explicit timeout uses
this. On elapsed, the kernel cancels and returns exit code 124.
Sourcepub fn with_kill_grace(self, grace: Duration) -> Self
pub fn with_kill_grace(self, grace: Duration) -> Self
Set the SIGTERM-to-SIGKILL grace period for child kills.
Sourcepub fn with_kill_children_on_parent_death(self, on: bool) -> Self
pub fn with_kill_children_on_parent_death(self, on: bool) -> Self
Arm PR_SET_PDEATHSIG(SIGKILL) on external commands so a hard-killed
kaish process cannot orphan them (Linux only — read
Self::kill_children_on_parent_death for the tradeoff and the macOS
gap).
Sourcepub fn with_job_manager(self, jobs: Arc<JobManager>) -> Self
pub fn with_job_manager(self, jobs: Arc<JobManager>) -> Self
Adopt an embedder-owned JobManager instead of building a fresh one,
so background jobs outlive the kernel that started them. Read
Self::job_manager before sharing one manager between kernels that
are configured differently.
Sourcepub fn with_vfs_budget(self, bytes: u64) -> Self
pub fn with_vfs_budget(self, bytes: u64) -> Self
Cap VFS memory-resident bytes at bytes across all kernel-owned
MemoryFs mounts. A shared ByteBudget labeled "vfs-memory" is
created at kernel construction and passed to every MemoryFs the
kernel builds (see setup_vfs and with_backend).
Writes that would exceed the cap fail loudly with StorageFull — an
in-band error a model reads and adapts to; fail loud over quietly eating
RAM. Use without_vfs_budget to remove the cap entirely.
Sourcepub fn without_vfs_budget(self) -> Self
pub fn without_vfs_budget(self) -> Self
Remove the VFS memory budget — all MemoryFs mounts are unbounded.
Use when the caller knows the workload and the default 64 MiB cap
(set by KernelConfig::agent) is too conservative.
Sourcepub fn with_overlay(self, overlay: bool) -> Self
pub fn with_overlay(self, overlay: bool) -> Self
Enable or disable copy-on-write overlay mode.
When true, the primary local filesystem mount is wrapped in an
OverlayFs so writes are virtual — the lower layer is never touched.
Incompatible with VfsMountMode::NoLocal (fails loudly at construction)
and with_backend kernels (same — the embedder controls the VFS).
Trait Implementations§
Source§impl Clone for KernelConfig
impl Clone for KernelConfig
Source§fn clone(&self) -> KernelConfig
fn clone(&self) -> KernelConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for KernelConfig
impl !UnwindSafe for KernelConfig
impl Freeze for KernelConfig
impl Send for KernelConfig
impl Sync for KernelConfig
impl Unpin for KernelConfig
impl UnsafeUnpin for KernelConfig
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
impl<T> OrderedSeq<'_, T> for Twhere
T: Clone,
Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<'p, T> Seq<'p, T> for Twhere
T: Clone,
impl<'p, T> Seq<'p, T> for Twhere
T: Clone,
Source§impl<T, S> SpanWrap<S> for Twhere
S: WrappingSpan<T>,
impl<T, S> SpanWrap<S> for Twhere
S: WrappingSpan<T>,
Source§fn with_span(self, span: S) -> <S as WrappingSpan<Self>>::Spanned
fn with_span(self, span: S) -> <S as WrappingSpan<Self>>::Spanned
WrappingSpan::make_wrapped to wrap an AST node in a span.