docs/guides/extract-tenant.md

Extracting a tenant workspace repo

Vocion is designed so every tenant's authored content — Sources, Objects, Skills, Workflows, Agents — lives in a separate git repo (a "tenant workspace repo" or <client>-vocion). Core runs the platform; the workspace repo holds the work.

During early dev, a tenant's content typically lives alongside core in workspace/<org>/ for convenience. When you're ready to split it out (phase C — OSS launch, or earlier for client separation), this doc walks through the extraction.

What moves

A tenant workspace repo owns:

workspace/<org>/
├── workspace.yaml                # manifest — orgId, tenant name, retrieval overrides
├── sources/<slug>/source.yaml  # connector config (OAuth scope, filters, retrieval overrides)
├── objects/<slug>/type.yaml    # business object schemas
├── skills/<slug>/              # skill.yaml + prompt.md
├── workflows/<slug>/           # workflow.yaml (+ optional step prompts)
└── agents/<slug>.yaml          # + <slug>.system-prompt.md

Plus any tenant-specific docs (case studies, onboarding notes) if you want.

What stays in core

Everything under packages/core/ — the runtime, UI, plugin SDK, Postgres schema, MCP server. These are generic; they read whatever context you point them at.

Portability contract

Core is tenant-agnostic by design. Points of contact:

SignalDefaultOverride
WORKSPACE_PATH env varworkspace/metactoAny path (absolute or relative)
VOCION_ORG_NAME env varmetactoYour tenant slug
VOCION_ORG_ID env var(from session)org id for MCP or scripts

No core code references metacto except as a default; change the env vars and everything re-points.

Extraction recipe

Assumes tenant content today lives at workspace/metacto/ in this repo.

1. Split the history

# From vocion-core repo root
git subtree split --prefix=workspace/metacto -b metacto-split

This creates a local branch metacto-split containing only the commits that touched workspace/metacto/, with that path reparented to the branch root.

2. Push to a new repo

# Create the new GitHub repo (private or public)
gh repo create vocion/metacto-vocion --private --description "MetaCTO tenant context for Vocion"

# Push the split branch as main
git push git@github.com:vocion/metacto-vocion.git metacto-split:main

3. Clone + layout the new repo

git clone git@github.com:vocion/metacto-vocion.git
cd metacto-vocion

# The split landed everything at root — no workspace/metacto/ prefix anymore.
# Optional: add a README + .gitignore + CI + a Vocion version pin.

Typical tenant repo layout after the split:

metacto-vocion/
├── README.md
├── workspace.yaml
├── sources/
├── objects/
├── skills/
├── workflows/
└── agents/

4. Point core at the new path

In the core install (local dev or production), update .env.local:

WORKSPACE_PATH=/absolute/path/to/metacto-vocion
VOCION_ORG_NAME=metacto

Then:

npm run workspace:apply

Same behavior, content now version-controlled separately.

5. Clean up the core repo

# From vocion-core
git rm -r workspace/metacto
git commit -m "chore: extract metacto tenant to its own repo"
git push

The history of workspace/metacto/ is preserved in both repos (core sees the delete, the tenant repo has the full prior history via git subtree split).

Writing back from core to the tenant repo

The MCP workspace_write_* tools + the in-app Resource Editor both honor WORKSPACE_PATH. They write to whatever directory you've pointed at, auto-commit with chore(context): <summary> in that repo, and call workspace:apply to sync the DB.

The tenant repo becomes the source of truth. Core is the runtime.

Versioning + drift

  • Tenant repo pins a compatible @vocion/core range in its workspace.yaml:
    coreVersion: '>=0.1 <1.0'
    
  • workspace:apply warns if the installed core is outside that range.
  • Every skill_run stamps the active workspace_sha, so every output traces back to the tenant repo commit that produced it.

Multiple tenants, one core install

Core is multi-tenant out of the box. To onboard a second tenant:

  1. Create <other>-vocion repo (same layout).
  2. Set WORKSPACE_PATH=/path/to/<other>-vocion + VOCION_ORG_NAME=<other> + VOCION_ORG_ID=<org-id>.
  3. npm run workspace:apply — each tenant's rows are scoped by org_id automatically.

Running two tenants from one process today means setting those env vars in the invoking shell (MCP session, cron, script). Per-request tenant switching (cloud-style) lands in Phase 3 v0.3.