pub struct ToolContext {Show 26 fields
pub cwd: PathBuf,
pub extra_roots: Vec<PathBuf>,
pub sandbox: SandboxPolicy,
pub multimodal_read: bool,
pub read_line_numbers: bool,
pub require_read_before_edit: bool,
pub read_paths: Arc<Mutex<HashMap<PathBuf, u64>>>,
pub notebook_aware: bool,
pub shell_env: Option<Arc<HashMap<String, String>>>,
pub nested_instructions: bool,
pub injected_instruction_dirs: Arc<Mutex<HashSet<PathBuf>>>,
pub path_rules: Arc<Vec<RuleFile>>,
pub injected_rule_files: Arc<Mutex<HashSet<PathBuf>>>,
pub network_policy: Option<NetworkPolicy>,
pub permission_rules: Option<Arc<RuleSet>>,
pub bash_timeout_secs: Option<u64>,
pub write_observer: Option<Arc<dyn WriteObserver>>,
pub sandbox_os_enabled: Option<bool>,
pub sandbox_escalation: SandboxEscalation,
pub sandbox_env_policy: SandboxEnvPolicy,
pub sandbox_approval_handler: Option<SandboxApprovalHandler>,
pub question_handler: Option<UserQuestionHandler>,
pub approval_handler: Option<ToolApprovalHandler>,
pub plan_mode: Arc<PlanModeState>,
pub context_budget: Arc<ContextBudget>,
pub plan: Arc<Mutex<Vec<PlanEntry>>>,
}Expand description
Ambient context passed to every tool invocation.
Fields§
§cwd: PathBufThe working directory tools resolve relative paths against.
extra_roots: Vec<PathBuf>BP-10 (catalog row “Additional working directories”, cc/cx
--add-dir): extra roots granted BEYOND Self::cwd, from
core.additional_dirs/--add-dir. These are real grants, not
discovery hints: Self::check_write treats a path under one of
them as inside the workspace, the OS backstop adds each to the
subprocess’s writable set (crate::sandbox::apply_linux_confinement
on Linux, the seatbelt profile on macOS), and the permissions
engine’s path rules are evaluated relative to each root as well as
to cwd (so a write(.git/**) floor still covers an extra root’s
own .git). Empty (the default) is byte-identical to confining
everything to cwd alone.
sandbox: SandboxPolicyFilesystem confinement for write-capable tools.
multimodal_read: boolP4c (S1.2 core.tools.read_file.multimodal): whether read_file
(and view_image, unconditionally) returns a recognized image file
as a model-visible image content block. false (the default) is
byte-identical to today’s UTF-8-lossy-decode behavior.
read_line_numbers: boolBP-2 (S1.2 core.tools.read_file.line_numbers, catalog:26): whether
read_file prefixes every returned line with its 1-based file line
number and a tab (cat -n), numbered from the requested offset.
false (the default) returns the raw slice, as today.
require_read_before_edit: boolP4c (S1.2 core.tools.edit_file.require_read_before_edit, UNIQUE CC
row): whether edit_file refuses a path not yet read this
conversation. false (the default) is byte-identical to today’s
behavior — Self::read_paths is simply never consulted.
read_paths: Arc<Mutex<HashMap<PathBuf, u64>>>P4c: canonicalized paths read_file has successfully read so far
this conversation — shared (via Arc<Mutex<_>>) across every clone
of this context, since Agent constructs one ToolContext at
startup and reuses it for every tool call. Consulted by EditFileTool
only when Self::require_read_before_edit is true.
BP-2 (catalog:32 “Edit refuses unless file was read and
unchanged this conversation”): the value is the content hash AT
READ TIME, so a file modified behind the model’s back after its read
is detected as STALE instead of editing cleanly against a view that
no longer exists — see Self::read_state.
notebook_aware: boolP4c (S1.2 core.tools.edit_file.notebook_aware, UNIQUE CC row
“NotebookEdit”): whether edit_file accepts Jupyter cell
replace/insert/delete operations against a .ipynb target. false
(the default) is byte-identical to today’s exact-string-replace-only
behavior.
shell_env: Option<Arc<HashMap<String, String>>>P4c (S1.2 core.shell_env_snapshot): the user’s captured
interactive-shell environment, if crate::Config::shell_env_snapshot
is on — BashTool/PersistentShellTool merge this into the spawned
process’s environment. None (the default) is byte-identical to
today’s behavior: no extra environment is injected.
nested_instructions: boolP4c (S1.4 core.nested_instructions, deferred from P4b): whether a
file-touching tool injects an as-yet-unseen subdirectory’s own
CLAUDE.md/AGENTS.md into its result the first time a path under
it is touched. false (the default) is byte-identical to today’s
behavior.
injected_instruction_dirs: Arc<Mutex<HashSet<PathBuf>>>P4c: subdirectories (relative to Self::cwd) whose nested
instructions have already been injected this conversation — shared
across clones, same rationale as Self::read_paths. Consulted only
when Self::nested_instructions is true.
path_rules: Arc<Vec<RuleFile>>BP-5 (catalog D2 “Path-scoped rules”, cc§2 .claude/rules paths:):
the rule files this config loaded whose paths: selector holds them
back until a matching file is touched. Empty (and inert) unless
[core.path_rules] is on.
injected_rule_files: Arc<Mutex<HashSet<PathBuf>>>BP-5: which of Self::path_rules have already been injected this
conversation — one injection per rule, the same de-duplication
Self::injected_instruction_dirs gives nested instructions.
network_policy: Option<NetworkPolicy>P4c (S2 module 5 tools.web, S17): the network-domain policy
web_fetch/web_search must respect, if one is configured. None
(the default) means no policy is enforced — see NetworkPolicy’s
doc comment for the honest-gap rationale.
permission_rules: Option<Arc<RuleSet>>BP-10 (catalog row “Allow/ask/deny rule language”): the
CONFIG-DECLARED rule set (capabilities.permissions.rules.*, the
same arrays crate::agent::Agent’s dispatch gate evaluates), so a
domain(...) rule written there is enforced by the ONE engine at
the network surface too — see Self::check_network. None (the
default, and whenever capabilities.permissions is off) leaves the
network check reading network_policy’s own two lists alone,
byte-identical to before.
bash_timeout_secs: Option<u64>P4e (S3.1 core.tools.bash.timeout_secs, S14): the DEFAULT
execution timeout (seconds) BashTool::execute falls back to when a
model-issued call carries no timeout_ms argument of its own – see
crate::config::ToolOverride::timeout_secs. None (the default) is
byte-identical to today’s behavior: BashTool’s built-in
DEFAULT_BASH_TIMEOUT_MS (120s) stands.
write_observer: Option<Arc<dyn WriteObserver>>P5-9 (§2 module 20, D-5 shared write-path interception seam) — see
WriteObserver’s doc comment. None (the default) is a true
no-op: every write-tool call site’s if let Some(obs) = ... branch
is simply never taken.
sandbox_os_enabled: Option<bool>P5-10 (§2 module 12 permissions.sandbox): whether the OS-level
backstop (Landlock/seatbelt) is engaged for the bash/shell
subprocess — see crate::sandbox::os_sandbox_active. None (the
default) preserves the pre-P5-10 trigger (confine whenever
Self::sandbox isn’t SandboxPolicy::DangerFullAccess).
sandbox_escalation: SandboxEscalationP5-10 (§2 module 12, escalation): what to do when a confining fs
tier can’t actually be enforced on this platform/kernel — see
crate::sandbox::SandboxEscalation. Defaults to Deny
(fail-closed).
sandbox_env_policy: SandboxEnvPolicyP5-10 (§2 module 12, env_policy): child-process environment
sanitization for the spawned subprocess — see
crate::sandbox::SandboxEnvPolicy. Defaults to Inherit
(byte-identical to pre-P5-10 behavior).
sandbox_approval_handler: Option<SandboxApprovalHandler>P5-10 (§2 module 12, escalation = "ask" → permissions.approvals,
P5-1): the ambient handler crate::sandbox::decide_fs consults for
an ask-tier sandbox-unenforceable decision. None (the default —
no handler installed) is fail-closed, same posture as the P5-1 rule
engine’s own Ask tier with no handler.
question_handler: Option<UserQuestionHandler>BP-3 (§2 module 6 tools.question): the door ask_user asks the
human through — the SAME elicitation/create handler the design
names as “the tools.question surface’s PROTOCOL side”
(crate::mcp::McpElicitationHandler), installed by
crate::agent::Agent::set_user_question_handler. None (the
default) means no interactive frontend is attached, and the tool
says so rather than blocking on an answer nobody can give.
approval_handler: Option<ToolApprovalHandler>BP-3 (§2 module 8 plan_mode): the approval door exit_plan_mode
presents the plan on — the same
crate::permissions::PermissionsApprovalHandler
Agent::set_permissions_approval_handler installs (under an
SDK-owned runtime, that is the frontend request broker). None is
fail-closed: the plan cannot be approved, so plan mode stays on.
plan_mode: Arc<PlanModeState>BP-3 (§2 module 8): the shared plan-mode state — read by the agent’s
permission gate (plan_mode::deny_rules), written by
enter_plan_mode/exit_plan_mode and the REPL’s /plan. Inactive
by default, and an inactive state contributes no rules at all.
context_budget: Arc<ContextBudget>BP-3 (catalog row “Context-budget tools”): the shared token
accounting get_context_remaining reads and new_context parks its
request on. The agent publishes onto it; nothing is published until
a turn has actually run.
plan: Arc<Mutex<Vec<PlanEntry>>>BP-8 (§2 module todos persist, catalog:156 “Todos/plan persisted
per session”): the session’s update_plan checklist. It lives HERE,
on the context the agent owns and shares with every clone, rather
than inside UpdatePlanTool — a plan the agent cannot read is a
plan it cannot persist, which is exactly the residue the ledger row
named. Empty by default, at zero cost.
Implementations§
Source§impl ToolContext
impl ToolContext
Sourcepub fn plan_snapshot(&self) -> Vec<PlanEntry>
pub fn plan_snapshot(&self) -> Vec<PlanEntry>
BP-8: the current plan, as (step, status) pairs.
Sourcepub fn set_plan(&self, steps: Vec<PlanEntry>)
pub fn set_plan(&self, steps: Vec<PlanEntry>)
BP-8: replace the plan wholesale (update_plan replaces; a resume
restores).
Sourcepub fn permissions_engine_active(&self) -> bool
pub fn permissions_engine_active(&self) -> bool
BP-10: whether the permissions ENGINE adjudicated this call —
i.e. capabilities.permissions.enabled was on when this context
was built, so crate::agent::Agent’s dispatch gate ran the rule
algebra (and any Ask tier) before the tool was invoked.
The one consumer is the sandbox-escalation path
(builtins::escalation_requested): a model-issued
with_escalated_permissions is only honored where a gate exists to
have approved it.
Sourcepub fn os_sandbox_active(&self) -> bool
pub fn os_sandbox_active(&self) -> bool
P5-10: whether the OS-level backstop is active for this context —
thin wrapper over crate::sandbox::os_sandbox_active.
Sourcepub fn mark_read(&self, path: &Path)
pub fn mark_read(&self, path: &Path)
P4c: record path (canonicalized if possible, else the resolved
path as-is) as having been read this conversation — called by
ReadFileTool on every successful read, unconditionally (cheap; the
map is only ever CONSULTED when Self::require_read_before_edit is
on, but recording it unconditionally means turning the knob on
mid-conversation sees every read that already happened).
BP-2: reads the file’s CURRENT bytes to stamp the content hash. Use
Self::mark_read_bytes from a caller that already holds them.
Sourcepub fn mark_read_bytes(&self, path: &Path, bytes: &[u8])
pub fn mark_read_bytes(&self, path: &Path, bytes: &[u8])
BP-2: the same record, stamped from bytes the caller just read.
Sourcepub fn was_read(&self, path: &Path) -> bool
pub fn was_read(&self, path: &Path) -> bool
P4c: whether path was previously recorded via Self::mark_read,
ignoring whether it has changed since.
Sourcepub fn read_state(&self, path: &Path) -> ReadState
pub fn read_state(&self, path: &Path) -> ReadState
BP-2 (catalog:32): what edit_file needs to know before accepting
an edit — never read, read but changed on disk since, or read and
still identical.
Sourcepub fn check_network(&self, url: &str) -> Result<()>
pub fn check_network(&self, url: &str) -> Result<()>
P4c (S2.1 S17): does url pass Self::network_policy, if one is
configured? Ok(()) when no policy is set (the honest-gap default)
or the policy is present-but-disabled; Err names the reason
otherwise. A URL with no parseable host is denied whenever a policy
is actively enforced (fail closed — an unparseable host can’t be
matched against an allowlist).
Sourcepub fn resolve(&self, path: &str) -> PathBuf
pub fn resolve(&self, path: &str) -> PathBuf
Resolve a possibly-relative path against the working directory.
Sourcepub fn write_roots(&self) -> Vec<PathBuf>
pub fn write_roots(&self) -> Vec<PathBuf>
BP-10: every root a WorkspaceWrite call may write under — cwd
first, then each Self::extra_roots entry. The ONE list
Self::check_write, the seatbelt profile, and the Landlock
writable set all read, so a grant can never be honored by one and
missed by another.
Sourcepub fn check_write(&self, path: &Path) -> Result<()>
pub fn check_write(&self, path: &Path) -> Result<()>
Enforce the sandbox policy for a write to path. Err if denied.
Trait Implementations§
Source§impl Clone for ToolContext
impl Clone for ToolContext
Source§fn clone(&self) -> ToolContext
fn clone(&self) -> ToolContext
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more