Filesystem¶
Role¶
HarnessAgent abstracts the agent’s view of the workspace away from “must be local disk” into a uniform interface. All file tools (read_file / write_file / edit_file / grep_files / glob_files / list_files) and the optional execute (shell) go through this abstraction.
The payoff: you can switch between three deployment modes without changing agent code:
Local + shell — single process, local, trusted env;
Shared store — multiple replicas / pods share the same long-term memory;
Sandbox — files and commands run in an isolated container; the same workspace state is restored across calls.
Three declarative modes¶
Pick one with filesystem(...) on HarnessAgent.Builder (no call = mode 3 by default):
Mode |
Config |
Shell? |
When to use |
|---|---|---|---|
1 · Shared store |
|
❌ |
Multiple replicas share |
2 · Sandbox |
|
✅ (inside sandbox) |
Isolated execution, cross-call workspace recovery, optional snapshots + distributed |
3 · Local + shell (default) |
|
✅ (host |
Single process / local / trusted env / scripts and tests |
filesystem(...)is mutually exclusive withabstractFilesystem(...); the latter is an escape hatch for fully self-managed filesystems and rarely needed.
Mode 2: sandbox¶
For “code may run untrusted operations” or “isolate from the production host”. Every file op and shell command goes to the sandbox; the host is untouched. The sandbox can snapshot, so the next call() brings back node_modules, pip install results, etc.:
HarnessAgent agent = HarnessAgent.builder()
.name("sandbox")
.model(model)
.workspace(workspace)
.filesystem(new DockerFilesystemSpec()
.image("ubuntu:24.04")
.isolationScope(IsolationScope.SESSION))
.build();
Details in Sandbox. Backends: Docker / Kubernetes / Daytona / E2B / AgentRun (Aliyun).
Mode 3: local + shell (default)¶
What you get with no filesystem(...) call: workspace lives at ${cwd}/.agentscope/workspace/, shell runs on the host:
HarnessAgent agent = HarnessAgent.builder()
.name("local")
.model(model)
.workspace(workspace)
// .filesystem(...) omitted = local + shell
.build();
Adjust timeouts, env vars, etc.:
.filesystem(new LocalFilesystemSpec()
.executeTimeoutSeconds(120)
.env("MY_VAR", "value")
.inheritEnv(false))
IsolationScope — bucketing across users and replicas¶
Both mode 1 (shared store) and mode 2 (sandbox) use the same IsolationScope concept to decide who shares state with whom:
Scope |
Meaning |
Typical use |
|---|---|---|
|
Each sessionId is independent |
Multi-user SaaS, each conversation runs on its own |
|
Same |
Same user’s multiple sessions share long-term memory (distributed deployments) |
|
All users/sessions of this agent share |
Public-knowledge-base type agent |
|
One shared slot for everything |
Use with care |
Example: to let Alice’s conversations across devices share the same long-term memory — choose USER and put userId="alice" in RuntimeContext.
How multi-user isolation works¶
RuntimeContext.userId is the key to multi-user splitting:
Local mode: user-level files land in
workspace/<userId>/..., e.g.workspace/alice/skills/code-reviewer/SKILL.mdis visible only to Alice;Shared store mode: used as the KV namespace prefix, distributed replicas share naturally;
Sandbox mode: used as the sandbox state slot key (paired with
IsolationScope.USER).
Without userId, single-tenant default applies and everyone shares one root.
Two-layer reading in the workspace¶
Key files like AGENTS.md, MEMORY.md, KNOWLEDGE.md have a “two-layer fallback” on reads: look in your configured filesystem backend first, fall back to local disk if not found. This is useful for “template files” in mode 1 (shared store): the first replica’s local has the template AGENTS.md so it works immediately; later replicas read the up-to-date version from the shared store.
Writes always go through the configured filesystem backend.
Fully self-managed: abstractFilesystem(...)¶
If none of the three modes fits, pass a fully self-implemented filesystem:
HarnessAgent.builder()
...
.abstractFilesystem(myCustomFilesystem) // mutually exclusive with filesystem(...)
.build();
Usually not needed — the three modes cover ~95% of use cases.