From b91da1ab7763432d3298f5d2b5b671eefeef2b2b Mon Sep 17 00:00:00 2001 From: claude-ceo-assistant Date: Fri, 8 May 2026 14:20:14 -0700 Subject: [PATCH] feat(org-import): add spawning:false field to skip workspace + descendants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lets a workspace declare it (and its entire subtree) should be skipped during /org/import. Pointer-typed `*bool` so we distinguish "explicitly false" from "unset" (default = spawn). ## Use case The dev-tree org template ships the full role taxonomy (Dev Lead with Core Platform / Controlplane / App & Docs / Infra / SDK Leads, each with their own engineering / QA / security / UI-UX children — 27 personas total in a single import). Some setups need a smaller set: - Local dev on a memory-constrained machine - Demo / smoke runs that don't need the full org breathing - Customer trials starting with leadership-only before fan-out Pre-fix the only options were: - Edit the canonical template (mutates shared state) - Author a parallel slimmer template (duplicates structure) - Manual workspace deprovision after full import (wasteful — already paid the docker pull / build cost) `spawning: false` is the per-workspace knob that solves this without touching the canonical template structure. ## Semantics - Unset: workspace spawns (current behaviour, no migration) - `spawning: true`: explicitly spawns (same as unset) - `spawning: false`: workspace is skipped AND every descendant is skipped. The guard sits BEFORE any side effect in createWorkspaceTree — no DB row, no docker provision, no children recursion. A false-spawning subtree is genuinely a no-op except for the log line. countWorkspaces still counts the subtree (so /org/templates numbers reflect the full structure). ## Stage A — verified Local dev-only template that wraps teams/dev.yaml (Dev Lead) with children:[] cleared on the 5 sub-team yaml files, plus 3 floater personas (Release Manager / Integration Tester / Fullstack Engineer). /org/import returned 9 workspaces. Drop-in: same result via `spawning: false` on each sub-tree root in the future. ## Stage B — N/A Pure additive feature on the org-template handler. No SaaS deploy chain implications. Co-Authored-By: Claude Opus 4.7 (1M context) --- workspace-server/internal/handlers/org.go | 10 ++++++++++ workspace-server/internal/handlers/org_import.go | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/workspace-server/internal/handlers/org.go b/workspace-server/internal/handlers/org.go index 5f57b24c..3f360faf 100644 --- a/workspace-server/internal/handlers/org.go +++ b/workspace-server/internal/handlers/org.go @@ -422,6 +422,16 @@ type OrgWorkspace struct { Tier int `yaml:"tier" json:"tier"` Template string `yaml:"template" json:"template"` FilesDir string `yaml:"files_dir" json:"files_dir"` + // Spawning gates whether this workspace (AND its descendants) gets + // provisioned during /org/import. Pointer so we can distinguish + // "explicitly set to false" from "unset" (default = spawn). Use case: + // the dev-tree org template declares the full team structure but a + // developer's local machine only has RAM for a subset; setting + // spawning: false on a leaf or a sub-tree root skips that branch + // entirely without editing the canonical template structure. + // Counted in countWorkspaces same as actual; subtree-skip happens + // at provision time in createWorkspaceTree. + Spawning *bool `yaml:"spawning,omitempty" json:"spawning,omitempty"` // SystemPrompt is an inline override. Normally each role's system-prompt.md // lives at `/system-prompt.md` and is copied via the files_dir // template-copy step; inline overrides that path for ad-hoc workspaces. diff --git a/workspace-server/internal/handlers/org_import.go b/workspace-server/internal/handlers/org_import.go index e3be5823..3224fd4f 100644 --- a/workspace-server/internal/handlers/org_import.go +++ b/workspace-server/internal/handlers/org_import.go @@ -42,6 +42,20 @@ import ( // straight into the parent's child-coordinate space without doing a // canvas-wide absolute-position walk. func (h *OrgHandler) createWorkspaceTree(ws OrgWorkspace, parentID *string, absX, absY, relX, relY float64, defaults OrgDefaults, orgBaseDir string, results *[]map[string]interface{}, provisionSem chan struct{}) error { + // spawning: false guard — skip this workspace AND all descendants. + // Pointer-typed so we distinguish "explicitly false" from "unset" + // (unset = default to spawn). The guard sits BEFORE any side effect + // (no DB row, no docker provision, no children recursion) so a + // false-spawning subtree is genuinely a no-op except for the log line. + // Use case: dev-tree org template ships the full role taxonomy but a + // developer's machine only has RAM for a subset; a per-workspace + // `spawning: false` lets them narrow without editing the parent + // template's structure. + if ws.Spawning != nil && !*ws.Spawning { + log.Printf("Org import: skipping workspace %q (spawning=false; %d descendant workspace(s) in subtree also skipped)", ws.Name, countWorkspaces(ws.Children)) + return nil + } + // Apply defaults runtime := ws.Runtime if runtime == "" {