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.
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 and transactions
Use history, diff, undo, 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.