Skip to Content
DocsWorkspaceOverview

Workspace (0.9.39+)

A workspace is a shared notebook. Agents on a team write notes to it, read each other’s notes, and the framework handles the boring parts: slugs, YAML frontmatter, the auto-regenerated index, write atomicity, per-author attribution.

The metaphor matters. It’s a notebook, not a filesystem. Agents call note(title, content) and never see a filename. They refer to notes by title or by an opaque slug.

from loomflow import Agent, LocalDiskWorkspace ws = LocalDiskWorkspace.temp() researcher = Agent( "Research the question. Write one findings note.", model="gpt-4.1-mini", workspace=ws.member("researcher", teammates=["writer"]), ) writer = Agent( "Read the researcher's notes. Write the final answer.", model="gpt-4.1-mini", workspace=ws.member("writer", teammates=["researcher"]), ) await researcher.run("Is microservices worth it at 10 engineers?", user_id="team") await writer.run("Write the recommendation.", user_id="team")

The researcher and writer never see each other’s transcripts. The only thing that crosses between them is the curated note. That’s the point.

Why a notebook instead of shared history

When you run a team of agents, the naive approach is to pipe every agent’s full transcript into the next one. That blows up fast. Five specialists at 4K tokens each means the synthesizer reads 20K tokens of raw transcript, most of it reasoning noise.

The notebook fixes that. Each specialist writes one ~100-token note. The synthesizer reads five notes, not five transcripts. The context stays small and the signal stays high.

It also persists. Point a LocalDiskWorkspace at a fixed path and a second run picks up where the first left off. The notebook becomes a substrate the team gets smarter on, run over run. See Workspace lifecycle for the v0.10 self-improvement surface.

The five tools an agent gets

Wire a workspace= and the framework installs five tools on the agent’s tool host. It also augments the system prompt so the model knows they exist.

ToolWhat it does
note(title, content, kind)Write a new note. The author is baked in; the agent never types it.
read_note(slug_or_title)Read one note by slug or partial title.
list_notes(author, kind)List notes, newest first. Returns summaries, not full bodies.
search_notes(query)Text-search the notebook. BM25 by default, semantic if an embedder is wired.
update_note(slug, content)Rewrite a note this author owns. The prior body is snapshotted to history.

Note kinds are a small fixed set: finding, question, decision, summary, artifact, plan, note. They’re metadata, not partitions. list_notes(kind="decision") filters, but every kind is visible to every teammate.

Wiring it on an Agent

The workspace= kwarg accepts several shapes.

A WorkspaceMembership via ws.member(...). This is the usual path. One call carries the notebook, this agent’s author identity, and the team it’s collaborating with:

agent = Agent( "...", workspace=ws.member("researcher", teammates=["analyst", "writer"]), )

A bare Workspace instance. Share the notebook with no specific identity. Notes get attributed to the generic agent:

agent = Agent("...", workspace=ws)

A string. The resolver builds the backend for you:

agent = Agent("...", workspace="temp") # fresh temp dir agent = Agent("...", workspace="memory") # InMemoryWorkspace agent = Agent("...", workspace="./team-notebook") # LocalDiskWorkspace at a path

A dict. Declarative, TOML-friendly. Identity keys (author, teammates) are optional:

agent = Agent( "...", workspace={ "backend": ws, "author": "researcher", "teammates": ["analyst", "writer"], }, )

The same workspace= kwarg works on Workflow and Team. Pass it once at the workflow level and nested agent steps inherit it through the ambient context, the same way memory= propagates.

Two backends

BackendStorageUse
LocalDiskWorkspaceOne markdown file per note, plus an auto-regenerated WORKSPACE.md indexProduction. Survives restarts. cat it during a run.
InMemoryWorkspacePython dictsTests, notebooks, ephemeral coordination inside one process

LocalDiskWorkspace has three constructors:

from loomflow import LocalDiskWorkspace # Fresh temp directory. cleanup=True (default) wipes it on aclose(). ws = LocalDiskWorkspace.temp(prefix="loom-research-", cleanup=False) # Open or create at a fixed path. Never auto-cleans. ws = LocalDiskWorkspace.open("./team-notebook") # Direct constructor — same thing, with seed_paths for reference docs. ws = LocalDiskWorkspace("./team-notebook", seed_paths=["./brief.md"])

On disk you get a real directory you can inspect:

team-notebook/ research_team/ WORKSPACE.md # auto-regenerated index notes/ 001-rate-limits.md 002-data-consistency.md

WORKSPACE.md regenerates atomically on every write, so a concurrent reader always sees a consistent table of contents.

Multi-tenancy

Every workspace method takes an optional user_id. Notes from different user_id runs never appear in each other’s listings, even on a shared workspace root. The disk backend partitions by user_id at the directory level. Same partition guarantee you get everywhere else in the framework.

Read more

Workspace vs Memory. Memory is per-agent conversational state: episodes and facts, scoped to one agent’s runs. The workspace is cross-agent shared state: notes one agent writes that another agent reads. Different scope, different lifecycle. A team usually wants both.

Last updated on