Workspaces
Give agents durable scratch space and generated output files without writing custom file tools.
Most agents need somewhere to work. Without a workspace, intermediate notes, drafts, generated files, uploaded material, and final deliverables usually end up in one of two bad places: stuffed back into the prompt, or hidden behind custom file tools that every app has to design from scratch.
workspace() gives the model a durable, path-addressed file tree with a compact
manifest and safe file tools. The model sees what files exist, reads only the
files it needs, writes drafts and outputs to known folders, and leaves your app
with inspectable files instead of a long hidden transcript.
Use workspaces for notes, intermediate drafts, generated reports, CSVs, PDFs,
images, and uploaded or mounted task files. Do not use them for learned user
memory, shared coordination state, or searchable knowledge. Those are
memory(), blackboards,
and retrieval.
Basic Usage
import { prompt } from "@use-crux/core";
import { inMemoryStorage } from "@use-crux/core/storage";
import { workspace } from "@use-crux/core/workspace";
const ws = workspace({
id: "research",
namespace: `thread:${threadId}`,
storage: inMemoryStorage(),
});
const analyst = prompt({
id: "analyst",
use: [ws],
system: "Research the request and write final deliverables to /outputs.",
});use: [ws] injects a compact workspace manifest and file tools:
listWorkspace
readWorkspaceFile
writeWorkspaceFile
editWorkspaceFile
renameWorkspaceFile
grepWorkspaceThe manifest shows paths and metadata, not full file contents. The model calls read tools when it needs content, which keeps large work products out of the prompt until they are relevant.
Default Folders
Zero-config workspaces create two writable mounts:
/workspace scratch notes, intermediate files, working state
/outputs final generated deliverablesawait ws.write("/workspace/notes.md", "# Research notes");
await ws.write("/outputs/report.md", "# Final report");This convention is intentionally simple:
| Path | Use it for |
|---|---|
/workspace | Notes, plans, intermediate files, extracted data, draft fragments |
/outputs | User-facing deliverables, generated downloads, published artifacts |
/sources | Optional mounted reference files from uploads, retrievers, MCP, or app data |
Outputs are regular files under /outputs. Mark generated deliverables with
status and kind when the app needs an artifact view:
await ws.write("/outputs/report.md", "# Final report", {
status: "draft",
kind: "report",
});
const artifact = await ws.finalize("/outputs/report.md");What Your App Can Do
Apps can use the same workspace directly:
await ws.list("/workspace/**/*.md");
await ws.read("/workspace/notes.md");
await ws.write("/outputs/report.md", "# Report");
await ws.edit("/outputs/report.md", { find: "draft", replace: "final" });
await ws.exists("/workspace/notes.md");
await ws.stat("/workspace/notes.md");
await ws.append("/outputs/report.md", "\nAppendix");
await ws.copy("/workspace/notes.md", "/outputs/notes.md");
await ws.grep("launch", { path: "/workspace/**/*.md", ignoreCase: true });
await ws.finalize("/outputs/report.md");Every method accepts a { namespace } override for direct calls outside prompt
resolution:
await ws.write("/workspace/notes.md", "# Notes", { namespace: "thread:123" });Production Shape
For production, pass durable storage. records holds metadata and small inline
text or JSON. assets holds binary and large payloads:
import { storage } from "@use-crux/core/storage";
workspace({
id: "research",
namespace,
storage: storage({
records,
assets,
}),
content: {
inlineTextBelowBytes: 64_000,
},
});Namespaces
Namespaces isolate files for tenants, users, threads, or runs. Static namespaces work directly. Dynamic namespaces resolve during prompt injection, and direct calls can pass an override:
const ws = workspace({
id: "research",
namespace: ({ input }) => `thread:${input.threadId}`,
storage: storage({ records, assets }),
});
await ws.write("/workspace/notes.md", "# Notes", { namespace: "thread:123" });
const tools = ws.asTools({ namespace: "thread:123" });The override is also useful when running workspace operations outside a prompt resolution.
Execution evidence
Successful native workspace.operation mutations author capture-safe change
evidence against the exact operation subject. Delivery retries of the same
prepared artifact and relationship do not duplicate the claim; a separate
workspace occurrence remains a separate claim.
Automatic Workspace recovery evidence is not shipped yet. Crux does not infer recovery from undo support, versions, names, nesting, or timestamps. Add advanced custom evidence only when your application has an exact recovery claim and subject. See Execution evidence.
Where To Go Next
Files and artifacts
Read, write, list, copy, finalize, and publish generated files.
Tools and safety
Tool injection, prefixes, delete and undo opt-ins, approvals, and guardrails.
Sources and mounts
Expose retrievers, MCP resources, app documents, uploads, and provider-owned files as workspace paths.
Versions, snapshots, and transactions
Use history, explicit subtree checkpoints, pinned artifact versions, and staged multi-file writes.
Watching changes
Subscribe to workspace changes with durable cursors and update app views outside the model loop.
Storage and limits
Choose records and assets, configure TTL, quotas, inline thresholds, and namespace isolation.
For exact method signatures and option names, use the Workspace API reference.