Skip to content

fix(tools): allow autonomous sessions to write the workspace directory (#1493)#1498

Merged
Aaronontheweb merged 3 commits into
netclaw-dev:devfrom
Aaronontheweb:fix/1493-autonomous-workspace-write
Jun 25, 2026
Merged

fix(tools): allow autonomous sessions to write the workspace directory (#1493)#1498
Aaronontheweb merged 3 commits into
netclaw-dev:devfrom
Aaronontheweb:fix/1493-autonomous-workspace-write

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Collaborator

What

Fixes #1493. Autonomous (non-interactive) reminder/webhook sessions could not write files under {workspaces_dir} — the operator's designated writable working area — even though the workspace exists to be written to. An autonomous reminder that tried to persist a dedup/state file there hit:

Error: autonomous session may only access files inside its session directory, project directory, or configured autonomous roots.

…then degraded and stalled (a root trigger for the #1492 duplicate-guard hang).

Root cause (two compounding issues)

  1. By design (over-restriction). ScopedFileAccessPolicy.ResolveAutonomousZone included the global read roots for reads but excluded them for writes/attach (introduced in fix(tools): unblock non-interactive shell + webhook provenance + autonomous filesystem zone (#1244) #1250). So autonomous writes were confined to session + project only.
  2. Plumbing gap. FileWriteTool / FileEditTool / AttachFileTool / SetWorkingDirectoryTool constructed ScopedFileAccessPolicy without NetclawPaths, leaving the global-roots cache empty — so even read-eligible operations on those tools couldn't resolve {workspaces_dir}.

Fix

  • The autonomous write/attach zone now additionally includes the configured workspaces directory only — not the system-managed skills/identity trees, which stay read-only (an autonomous session must never rewrite its own identity or skills).
  • NetclawPaths is threaded into the four write-side tools (mirroring FileReadTool/FileListTool), so {workspaces_dir} resolves.

The workspaces root is sourced from NetclawPaths.WorkspacesDirectory, which the daemon builds from the Workspaces:Directory config (Program.cs:351) — verified, so writes land where the operator pointed them.

Tests

  • AutonomousZoneClampTests: replaced the old "can read but not write workspace" assertion with Autonomous_personal_can_write_workspaces_but_not_identity_or_skills (workspace writable; identity/skills denied) and added Autonomous_personal_can_write_under_configured_custom_workspaces_dir (cross-boundary contract — honors the configured override).
  • Full Netclaw.Actors.Tests suite green (2479 passed).
  • dotnet slopwatch analyze: clean (the 3 warnings are pre-existing, in files this PR doesn't touch); copyright headers verified.

Skill

Updated netclaw-operations (scheduling reference) to describe the autonomous zone accurately, including the now-writable workspace; bumped metadata.version 2.18.0 → 2.19.0.

Gates not run locally

The behavioral eval suite (./evals/run-evals.sh) requires a live model endpoint not configured in this environment — should be run in CI / before merge given the skill-content edit.

netclaw-dev#1493)

Autonomous (non-interactive) reminder/webhook sessions were confined to a
filesystem write zone of session + project only (introduced in netclaw-dev#1250), which
blocked them from persisting state files under the workspaces directory — the
operator's designated writable working area. An autonomous reminder that tried
to write a dedup/state file there hit "autonomous session may only access files
inside its session directory, project directory, or configured autonomous
roots", degraded, and stalled.

Two compounding causes, both fixed:

- ScopedFileAccessPolicy.ResolveAutonomousZone included the global read roots for
  reads but excluded them for writes/attach. It now additionally includes the
  configured workspaces directory for write/attach access — but NOT the
  system-managed skills/identity trees, which stay read-only (an autonomous
  session must never rewrite its own identity or skills).
- FileWriteTool/FileEditTool/AttachFileTool/SetWorkingDirectoryTool constructed
  ScopedFileAccessPolicy without NetclawPaths, leaving the global-roots cache
  empty. NetclawPaths is now threaded through these tools (mirroring
  FileReadTool/FileListTool) so the {workspaces_dir} token resolves.

Cross-boundary contract: the workspaces root is sourced from
NetclawPaths.WorkspacesDirectory, which the daemon builds from the
Workspaces:Directory config (Program.cs), so writes land where the operator
pointed them. Added a test asserting the policy honors a custom configured
workspaces directory.

Updates the netclaw-operations skill (scheduling reference) to describe the
autonomous zone accurately, including the now-writable workspace.
@Aaronontheweb Aaronontheweb added tools Issues related to agent tools: file_read, web_search, shell_execute, image processing, etc. security Security-related changes labels Jun 25, 2026
…(no silent-skip fallbacks)

Review follow-up to netclaw-dev#1493. The same silent-fallback pattern that hid the
workspace-write bug existed across the file/shell tool surface: NetclawPaths,
ToolPathPolicy, and ShellCommandPolicy were all optional/nullable and consumed
with `?.` / `is not null`, so a null silently disabled the check — path roots
dropped, deny-lists skipped, hard-deny command evaluation bypassed. All three
are constructed unconditionally in production, so nullability bought nothing but
a security-skip hazard.

- ScopedFileAccessPolicy, FileReadTool, FileListTool, FileWriteTool,
  FileEditTool, AttachFileTool, SetWorkingDirectoryTool, ShellTool,
  ShellTrustZonePolicy and WithFirstPartyTools now require these dependencies
  (non-nullable). Consumption sites drop the `?.`/null-guards.
- SkillToolRegistration uses GetRequiredService<ToolPathPolicy>() instead of the
  nullable GetService (ToolPathPolicy is a registered singleton).
- Feature-toggle params that genuinely mean "feature off" (searchBackend,
  webhookRouteStore) stay optional.
- Call sites (production + ~40 test sites) updated to pass explicit
  dependencies; the compiler enforced completeness.

Adds an AGENTS.md (constitution) rule: optional/nullable parameters are rare by
default — never added for compatibility, and especially not for security-
relevant dependencies where a null silently disables the check.

Note: ToolAccessPolicy (tool-exposure filtering in SearchToolsTool/LoadToolTool)
is the same pattern and a good follow-up; left out here to keep this change
scoped to the file/shell access surface.

Full Netclaw.Actors.Tests suite green (2479); solution builds clean.

@Aaronontheweb Aaronontheweb left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the rest of this PR is essentially just making the file resolution policy non-optional inside tool calls.

if (accessKind == AccessKind.Read)
roots.AddRange(_cachedGlobalReadRoots.Value);
else if (_cachedWorkspacesRoot.Value is { } workspacesRoot)
roots.Add(workspacesRoot);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - solves the issue inside the policy class.

@Aaronontheweb
Aaronontheweb merged commit 5e00383 into netclaw-dev:dev Jun 25, 2026
15 checks passed
@Aaronontheweb
Aaronontheweb deleted the fix/1493-autonomous-workspace-write branch June 25, 2026 23:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

security Security-related changes tools Issues related to agent tools: file_read, web_search, shell_execute, image processing, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: autonomous sessions cannot access {workspaces_dir} despite GlobalReadRoots config

1 participant