Skip to content
Agent Orchestration
Skill

/adopt-project-scope

Migrates an already-populated, unscoped Task Orchestrator database in place to the project-scoping convention — creates a project anchor root, re-parents existing work trees under it, and writes rootId back to config.yaml. Use when a user says: adopt project scope, migrate this

BOOST
From plugin
task-orchestrator
20929 skills4 agents2 commands
Install
$ npx -y skills add jpicklyk/task-orchestrator --skill adopt-project-scope --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/adopt-project-scope

Context preview

The summary Claude sees to decide when to auto-load this skill.

Migrates an already-populated, unscoped Task Orchestrator database in place to the project-scoping convention — creates a project anchor root, re-parents existing work trees under it, and writes rootId back to config.yaml. Use when a user says: adopt project scope, migrate this

SKILL.md

adopt-project-scope.SKILL.md
name: adopt-project-scope
description: "Migrates an already-populated, unscoped Task Orchestrator database in place to the project-scoping convention — creates a project anchor root, re-parents existing work trees under it, and writes rootId back to config.yaml. Use when a user says: adopt project scope, migrate this database to project scoping, make this DB multi-project, project-scope this workspace, adopt existing database, or set up project scoping for an existing DB."
argument-hint: "[project name] [--dry-run]"

Adopt Project Scope — In-Place Migration to Project Scoping

Take an existing, unscoped database (many depth-0 roots, no project anchor) and migrate it in place to the project-scoping convention: one `type=project` root that owns the workspace's work trees, with its UUID written back to `.taskorchestrator/config.yaml` under a `project:` block. Global containers (retrospectives, observations) stay at depth 0; test artifacts are flagged for cleanup, never moved or deleted.

This is a **destructive-by-execution** skill: the EXECUTE step re-parents real items. It defaults to a dry run and never mutates anything without an explicit confirmation. The only thing it ever deletes is its own throwaway server-probe tree.

For a fresh workspace with no existing unscoped work, use `/task-orchestrator:init` instead; this skill is for databases that already hold unscoped work trees.

**Non-goals:** cross-DB consolidation (merging items from a second database); merging multiple existing project anchors into one; any server-side enforcement of scope. This skill adopts a single workspace's single database.

---

Step 0 — Parse Arguments

  • **Project name** — the first non-flag token(s) in `$ARGUMENTS`. If absent, do not guess; ask for it in Step 3 (the dry-run plan) via `AskUserQuestion` before any mutation.
  • **`--dry-run`** — if present, the skill stops after Step 3 (the plan) and performs zero mutations regardless of confirmation. The dry run is ALSO always rendered before execution even without the flag; the flag only forces an early exit.

---

Step 1 — Preflight (abort gates)

Run these checks in order. Each abort prints a clear, user-facing reason and stops.

1a — Already adopted?

Read `.taskorchestrator/config.yaml`. If it contains a `project:` block with a non-empty `rootId:`, the workspace is already scoped:

◆ Workspace already adopted — config.yaml already points at project root <rootId>.
  Nothing to do. Use /work-summary to inspect the existing project tree.

Stop. (If the file is missing entirely, that is fine — a fresh unscoped DB has no config `project:` block. Continue.)

1b — Existing anchor already in the DB?

query_items(operation="search", type="project", depth=0)

(list mode — `query` omitted, filtering by `type` and `depth`.) Drop any result tagged `personal-root`: a personal root is not a project anchor and must never be adopted as one.

  • **No results** → continue to 1c.
  • **One or more results** → do NOT silently create a second anchor. Offer, via `AskUserQuestion`:

1. **Attach to existing** — write the existing anchor's UUID into `config.yaml` (skip anchor creation in EXECUTE; still re-parent MOVE roots under it) and continue. 2. **Abort** — stop and let the user resolve the ambiguity manually.

If the user picks "attach", record the existing anchor UUID as `ANCHOR_ID` and note that EXECUTE step (a) is skipped.

1c — Server capability probe (the depth-sweep fix)

Bulk re-parenting is exactly the scenario that a pre-fix server corrupts: on a pre-#219/#220 server, re-parenting a subtree does NOT recompute descendant depths (bug `99a3e642`), so this skill would silently leave the moved trees with wrong depths. Verify the fix is deployed with a disposable probe, then delete it.

Build a probe where a grandchild's depth MUST change when a middle node is re-parented deeper:

1. Create a throwaway root and a two-level branch under it in one call:

   manage_items(operation="create", items=[
     { title: "zzprobe-root",  type: "container", priority: "low" }
   ])

Capture its UUID as `P`. 2. Create the branch (sequential parentage, small tree). `manage_items` create has no ref/parentRef mechanism (only `create_work_tree` does), so a sibling's UUID does not exist until its own create call returns — M and G cannot be created in the same batch since G's `parentId` needs M's real UUID:

   manage_items(operation="create", items=[
     { title: "zzprobe-A",   parentId: P,  priority: "low" }     → capture as A (depth 1)
   ])
   manage_items(operation="create", items=[
     { title: "zzprobe-M",   parentId: P,  priority: "low" }     → capture as M (depth 1, sibling of A)
   ])

Capture M's returned UUID, then create G referencing it:

   manage_items(operation="create", items=[
     { title: "zzprobe-G",   parentId: "<M's real UUID>",  priority: "low" }     → capture as G (depth 2, child of M)
   ])

3. Re-parent the middle node M **under A** (making it deeper):

   manage_items(operation="update", items=[{ itemId: M, parentId: A }])

Post-fix, M becomes depth 2 and G becomes depth 3. 4. Read the grandchild's depth and capture it:

   query_items(operation="get", itemId=G)

5. Delete the probe **immediately, before acting on the result** — this runs on every path, pass or fail:

   manage_items(operation="delete", itemIds=[P], recursive=true)

6. Now evaluate the captured depth:

  • `depth == 3` → fix is present. Continue.
  • `depth == 2` (stale) → **abort** (probe already deleted):
     ⊘ Server is missing the reparent depth-sweep fix (bug 99a3e642).
       Bulk re-parenting on this server would corrupt subtree depths.
       Upgrade the Task Orchestrator server (PR #219/#220 or later) and retry.

**`--dry-run` skips this probe entirely** — no execution will happen, so the capability check is unnecessary an

Read more
Ships withtask-orchestrator

Server-enforced workflow discipline for AI agents. Prompt-based frameworks hope the LLM follows instructions. This one blocks the call if it doesn't.

Get the whole plugin

Other skills on task-orchestrator.