Skip to content

Workspaces

A workspace is the tenant boundary in Forge. Every issue, project, sprint, attachment, and audit row carries a workspaceId, and access is gated on membership. This page covers identity (key vs slug vs name), members and roles, and the workspace-level configuration knobs that govern dispatch, SLAs, and AI features.

Workspace as tenant

One workspace, one isolated dataset. Members of one workspace see nothing of another, even if they share a Forge instance. All tenant-scoped procedures in src/server/trpc.ts enforce this — workspaceProcedure requires an active membership for the targeted workspace, and adminProcedure additionally requires OWNER or ADMIN role.

A user can belong to multiple workspaces; switch between them with g w.

Identity: key, slug, name

Three fields describe a workspace:

FieldMutable?Used for
keyNoIssue-id prefix (WRK-42)
slugYesURL segment (/w/<slug>/...)
nameYesDisplay name

The key is the load-bearing one. It's the prefix on every issue id, so changing it after-the-fact is not a settings update — it's a data migration. Issue keys appear in IssueRelation payloads, audit rows, webhook deliveries that have already been shipped, external systems that cached the id, and (often) commit messages. Forge does not support in-place renames of key for this reason.

WARNING

Pick the key deliberately at creation time. Three to four uppercase letters, related to the workspace name. If you absolutely must change it, see the migration pattern in DEVLOG.md under "Phase 1 of 2026-04-20" — but expect downtime and external coordination.

slug and name are display affordances and can be changed freely. Slug changes update the URL; old links 404. Name changes are cosmetic.

Members and roles

Forge has four roles:

RoleWhat it grants
OWNEREverything an admin can do, plus delete the workspace
ADMINSettings, members, agents, plugins, dispatch, statuses, labels
MEMBERCreate/edit issues, projects, sprints, comments
GUESTRead-only on issues they're explicitly added to

Self-service email invitation is disabled by design. Forge does not have "invite anyone with a link" or "anyone at this email domain joins automatically" flows. Instead, an admin uses workspace.addMember (or the Members panel in Settings, which is the same call) to add a known user by email or handle. The added user must already have a Forge account.

INFO

This is a deliberate posture, not a missing feature. Forge instances often host multiple sensitive workspaces on shared infrastructure; auto-join flows leak surface area and create audit gaps. Keeping membership admin-gated keeps the audit log meaningful.

To change a member's role, use the Members panel — the same row that adds also exposes role-change. To remove a member, the same row. All three are admin-only.

The configurability principle

Bailey's standing rule for Forge: prefer settings-driven values over hardcoded defaults. Every workspace-level knob lives as a column on Workspace, not as a constant in a handler. If a number governs behavior, it's surfaced in Settings, with a sensible default and a documented effect.

This is not a stylistic preference — it's why dispatch, SLAs, watchdogs, and AI behavior are all tunable per workspace without touching code.

Workspace knobs

Here's the full list of workspace-level configuration columns, grouped by what they govern.

Sprints and time

KnobDefaultWhat it does
cycleLengthDays7Default sprint length in days
cycleCooldownDays0Gap between sprints
timeTrackingEnabledfalseSurfaces the time-tracker widget
attachmentQuotaMb1024Per-workspace MinIO quota

Dispatch

KnobDefaultWhat it does
autoDispatchfalseMaster toggle for dispatcher
autoDispatchModeMANUAL_ONLYOne of MANUAL_ONLY / ROUND_ROBIN / PRIORITY_MATCH / CAPABILITY_MATCH
autoStartOnAssignfalsePush webhook immediately on assign
requireApprovalBeforeStartfalseGate dispatch behind manual approval

See Agents → Auto-dispatch for what each mode does and how ties are broken.

SLAs, stalls, and acks

KnobDefaultWhat it does
agentIdleTimeoutMinutes0Auto-OFFLINE sweep window (0 = disabled)
assignmentSlaMinutes0Stall detection window (0 = disabled)
autoRedispatchOnStallfalseClear assignment on stall
requiredAckSeconds0Required-ack window after assign (0 = disabled)
autoRedispatchOnNoackfalseClear assignment on noack
slaEnforcementEnabledfalseEnable per-issue SLA breach checks

See Agents → SLAs and watchdogs for the timing semantics.

AI

KnobDefaultWhat it does
aiEnabledfalseMaster toggle for AI features
aiTriageOnCreatetrueRun AI triage on issue create (when AI enabled)
aiCoachEnabledtrueAI Coach posts comments on stall/noack/breach
aiProvider"hermes"hermes / openai / anthropic / custom
aiModel(provider default)Override model id

See Agents → AI triage and coach for what triage produces and when the Coach speaks up.

TIP

All knobs are editable in Settings → Workspace. None require a server restart; changes apply on the next request.

Reading and updating

In tRPC: workspace.get, workspace.update. The latter is admin-gated and validates each field. Attempts to change key are rejected at the validator.

ts
await trpc.workspace.update.mutate({
  workspaceId,
  cycleLengthDays: 14,
  autoDispatch: true,
  autoDispatchMode: "ROUND_ROBIN",
});

Over MCP, the same surface is workspace.update (subject to the API key's scope ceiling).

Where to next

Axiom-Labs · built for humans and agents