Skip to main content

Your First Workspace

Let's create a workspace manifest from scratch and understand its structure.

What Is a Workspace Manifest?

A workspace manifest is a JSON file that declares:

  • Which AI packages apply to a repository
  • Which providers (Claude, Codex, etc.) are in use
  • What projection policies enforce trust requirements
  • Telemetry and CI settings

It's similar to package.json in npm, but for AI agent configuration.

A Minimal Workspace

Here's the simplest valid workspace:

{
"workspaceId": "wksp_my_first_01",
"orgId": "org_mycompany",
"name": "My First Workspace",
"binding": {
"type": "git-repository",
"gitRemote": "git@github.com:mycompany/my-repo.git"
},
"targets": [
{
"id": "root",
"path": ".",
"providers": ["claude"]
}
],
"revision": 1
}

Breaking it down:

  • workspaceId — Unique identifier for this workspace (recommend wksp_<name>_<number>)
  • orgId — Your organization identifier (recommend org_<name>)
  • name — Human-readable name
  • binding — How this workspace is located (git repo, folder, or API key)
  • targets — One or more deployment targets (see below)
  • revision — Increments on every change (starts at 1)

Let's validate it:

cat > /tmp/my-workspace.json << 'EOF'
{
"workspaceId": "wksp_my_first_01",
"orgId": "org_mycompany",
"name": "My First Workspace",
"binding": {
"type": "git-repository",
"gitRemote": "git@github.com:mycompany/my-repo.git"
},
"targets": [
{
"id": "root",
"path": ".",
"providers": ["claude"]
}
],
"revision": 1
}
EOF

pnpm wl validate /tmp/my-workspace.json

Expected output:

Valid workspace manifest: /tmp/my-workspace.json
Workspace: My First Workspace (wksp_my_first_01)
Targets: root
Revision: 1

Adding Packages

Now let's reference a package:

{
"workspaceId": "wksp_my_first_01",
"orgId": "org_mycompany",
"name": "My First Workspace",
"binding": {
"type": "git-repository",
"gitRemote": "git@github.com:mycompany/my-repo.git"
},
"targets": [
{
"id": "root",
"path": ".",
"providers": ["claude"],
"packages": [
{
"packageId": "@mycompany/baseline@1.0.0",
"versionConstraint": "^1.0.0",
"channel": "stable"
}
]
}
],
"revision": 1
}

What we added:

  • packageId — Scope + name + version (like npm)
  • versionConstraint — Semver range (optional; defaults to exact version)
  • channel — Which release channel to use (optional; defaults to stable)

Adding Providers

Let's expand to support multiple providers:

{
"workspaceId": "wksp_my_first_01",
"orgId": "org_mycompany",
"name": "My First Workspace",
"binding": {
"type": "git-repository",
"gitRemote": "git@github.com:mycompany/my-repo.git"
},
"targets": [
{
"id": "root",
"path": ".",
"providers": ["claude", "codex", "cursor"],
"packages": [
{
"packageId": "@mycompany/baseline@1.0.0"
}
]
}
],
"revision": 1
}

Now the same package will be rendered for Claude, Codex, and Cursor. Workloom handles the provider-specific rendering automatically.

Understanding Projection Policies

Projection policies control how files are written to disk. Add them at the workspace level:

{
"workspaceId": "wksp_my_first_01",
"orgId": "org_mycompany",
"name": "My First Workspace",
"binding": {
"type": "git-repository",
"gitRemote": "git@github.com:mycompany/my-repo.git"
},
"targets": [
{
"id": "root",
"path": ".",
"providers": ["claude", "codex"],
"packages": [
{
"packageId": "@mycompany/baseline@1.0.0"
}
]
}
],
"revision": 1,
"projectionPolicy": {
"claude": "generated_local",
"codex": "approval_required"
}
}

This means:

  • Claude files are generated locally without approval
  • Codex files require explicit approval before they're written

Monorepo: Multiple Targets

For monorepos, add multiple targets:

{
"workspaceId": "wksp_mono_01",
"orgId": "org_mycompany",
"name": "My Monorepo",
"binding": {
"type": "git-repository",
"gitRemote": "git@github.com:mycompany/monorepo.git"
},
"targets": [
{
"id": "root",
"path": ".",
"providers": ["codex"],
"packages": [
{ "packageId": "@mycompany/baseline@1.0.0" }
]
},
{
"id": "frontend",
"path": "apps/web",
"providers": ["claude", "cursor"],
"packages": [
{ "packageId": "@mycompany/baseline@1.0.0" },
{ "packageId": "@mycompany/react-agent@2.1.0" }
]
},
{
"id": "backend",
"path": "services/api",
"providers": ["claude"],
"packages": [
{ "packageId": "@mycompany/baseline@1.0.0" },
{ "packageId": "@mycompany/security-review@1.4.2" }
]
}
],
"revision": 1
}

Each target gets:

  • A unique id (root, frontend, backend)
  • A path (relative to repo root)
  • Its own providers list
  • Its own packages list

Workloom renders each target independently. The root gets baseline instructions. The frontend gets baseline + React-specific guidance. The backend gets baseline + security review guidance.

Connecting to Disk

When you run wl bind in Phase 1, Workloom creates a .loom/binding.toml file in your repository that connects the local directory to this workspace manifest:

workspace_id = "wksp_my_first_01"
registry_url = "https://registry.workloom.dev"
mode = "generated-local"
conflict_policy = "fail"

This file lets Workloom:

  • Find the workspace manifest for this directory
  • Know where to pull packages from
  • Track local files and detect drift

Validate Your Workspace

Before committing, always validate:

pnpm wl validate /path/to/workspace.json

If validation passes, you're ready for Phase 1 — when wl pull will render your provider files.

What's Next

Now you understand workspace structure. Let's dive into core concepts — what packages are, how assets work, and how trust classification keeps you safe.

Phase 1 Coming

When Phase 1 launches, wl init will guide you through creating a workspace interactively. For now, edit JSON directly and validate with wl validate.