Workspace
What Workspace is
Workspace is the project boundary inside clumsies. It is where shared organizational behavior meets project-specific knowledge and local runtime state.
That sentence hides three different responsibilities, so it is worth unpacking them.
A workspace selects Library-backed behavior. It owns project context. It also acts as the server-side anchor for the manifest and cache that local runtime reads from.
This is why workspace is more than a folder binding and more than a repo name.
What a workspace contains
A workspace combines several distinct object types that should not be collapsed into one bucket.
| Part | Ownership | What it is |
|---|---|---|
| selected rules and workflows | reference to Library | shared behavioral assets chosen for this project |
| selected bundles | reference to Library | named group selections that expand into behavior content |
| context files | workspace-owned | project knowledge such as specs, ADRs, research, design notes |
| manifest | Hub-generated | current indexed snapshot of workspace runtime state |
| local drafts | local in-progress work | edits not yet merged into Library or workspace mainline |
The first three rows are the most important. They explain why workspace exists as its own object rather than being implied by a local checkout path.
Workspace is not the same thing as a repo
The specs are explicit about this: a workspace can bind to more than one local path and does not need to be reduced to a single repository checkout.
The server-side workspace ID is the real identity. Local paths are bindings recorded by the client. That distinction matters because the product is trying to model a project boundary, not just a folder on one machine.
Binding: how local paths attach to a workspace
The current client records workspace bindings in:
~/.clumsies/config.tomlThat file stores at least:
| Field | Meaning |
|---|---|
server.url | Hub base URL |
[[workspaces]].name | local label |
[[workspaces]].ws_id | authoritative workspace ID |
[[workspaces]].paths | local filesystem paths bound to this workspace |
This means a local path lookup is a resolution step, not identity creation. The client does not infer a workspace from a folder name. It resolves the folder through the binding config and then works against the authoritative ws_id.
A simplified example looks like this:
[server]
url = "http://127.0.0.1:8400"
[[workspaces]]
name = "clumsies"
ws_id = "ws-4a5c282474c9b5d9385dec0502267738"
paths = [
"/Users/lilhammer/workspace/clumsies",
"/Users/lilhammer/workspace/clumsies-docs"
]That example makes two design points concrete.
First, both local paths bind to the same workspace ID. Second, the path list is only local resolution state. The server-side workspace still remains the real project identity.
Manifest: the current workspace snapshot
The manifest is the bridge between Hub authority and local runtime. In the current implementation it is written to:
~/.clumsies/workspaces/{ws_id}/manifest.jsonThe current top-level schema is:
| Field | Meaning |
|---|---|
ws_id | workspace identity |
name | workspace name |
revision | current workspace snapshot revision |
rules | stable-ID keyed map of selected Library behavior |
context | stable-ID keyed map of workspace context |
The current entry schema inside rules and context includes:
| Field | Meaning |
|---|---|
path | runtime-relative path for the item |
hash | content hash used during sync |
description | optional schema-carried description |
A simplified example looks like this:
{
"ws_id": "ws-1",
"name": "demo",
"revision": 7,
"rules": {
"p-1": {
"path": "rule/coding/00_COMPATIBILITY.md",
"hash": "sha256:def",
"description": ""
}
},
"context": {
"ctx-1": {
"path": "spec/ARCHITECTURE.md",
"hash": "sha256:abc",
"description": ""
}
}
}There are two design choices here that deserve explicit explanation.
First, the manifest is not just a list of names. It is the indexed state of the workspace.
Second, rules and context are keyed by stable IDs rather than paths. That keeps identity stable across rename. The system can understand that an item moved without pretending it was deleted and recreated.
For example, if a rule keeps the same rule_id but moves from rule/coding/STYLE.md to rule/style/STYLE.md, the manifest only needs to update the path field for that one entry. The client does not need to treat it as a delete plus a brand-new unrelated rule.
Why manifest matters
The manifest does three jobs at once.
It tells the client what the workspace currently contains. It gives sync a stable object to compare against. It gives runtime surfaces one shared snapshot instead of forcing each client to invent its own discovery path.
That is why manifest belongs in the workspace model, not only in a sync page.
Cache: the materialized side of workspace runtime
Each workspace also has a dedicated local runtime directory:
~/.clumsies/workspaces/{ws_id}/The synced content lives under:
~/.clumsies/workspaces/{ws_id}/cache/The current implementation materializes at least:
| Path under cache | Meaning |
|---|---|
rule/ | synced rules and workflows selected by the workspace |
context/ | synced workspace context files |
META_PROMPT.md | cached meta prompt used by agent bootstrap |
This is where the workspace model touches runtime directly.
The local workspace directory has two layers:
| Path | Role |
|---|---|
~/.clumsies/workspaces/{ws_id}/manifest.json | workspace snapshot and sync index |
~/.clumsies/workspaces/{ws_id}/cache/ | materialized files used by local runtime |
That split explains practical behavior. Sync can skip unchanged content because the manifest tells it what should exist and which hash each item should have. MCP can serve from local state because the cache already contains the materialized files.
Context belongs to the workspace side
Context is where project-specific facts live. In the current design, that includes things like:
- architecture documents
- specs
- ADRs
- research notes
- design material
- journals
The important point is not the file type. The important point is ownership and role. Context is workspace knowledge.
That means context should not be explained as a special kind of Library content. It may be rendered into cache in a similar way, but it has a different collaboration destination and a different authority model.
Library selections stay Library selections
Rules, workflows, and bundles remain Library-backed even after a workspace selects them. The workspace does not become their new authority. It becomes the project boundary that selects which shared behavioral assets should be active for this project.
That distinction is what keeps the object model clean:
- Library owns shared behavior
- workspace owns project knowledge
- manifest brings both into one runtime snapshot
Drafts and review flow
Workspace also matters because real editing happens around it.
A local draft is not the same thing as synced cache. Cache is pulled state. Draft is in-progress work.
The collaboration split stays important here:
- rule-oriented edits move back toward Library proposal and review flow
- context-oriented edits move toward workspace-owned mainline
This is one of the reasons the workspace model exists at all. Without it, rule lifecycle and project-knowledge lifecycle would collapse into one ambiguous bucket.
Workspace membership and authorization
The workspace boundary is also where membership starts to matter. A workspace is not only a content container. It is an authorization boundary for who can bind, inspect, edit, and review project-specific material.
That is why the server-side workspace object has to stay authoritative. If local folders were treated as identity, permission checks would become guesswork.
Why Workspace matters in the docs
If docs talk only about Library, the system looks too centralized. If docs talk only about local cache, the system looks too accidental. Workspace is the object that explains how shared behavior, project-specific knowledge, sync, and runtime all meet in one place.