| name | g-skl-workspace |
| description | Workspace-Control Mode skill. Reads .gald3r/linking/workspace_manifest.yaml as the canonical registry and provides STATUS, VALIDATE, MEMBER LIST, SPAWN, ADOPT, EXPORT/SYNC dry-run planning, and member `.gald3r/` marker bootstrap/remediate/validate operations for manifest-declared repositories. |
| operations | ["STATUS","VALIDATE","MEMBER_LIST","INIT_PLAN","INIT_APPLY","MEMBER_ADD_PLAN","MEMBER_ADD_APPLY","MEMBER_REMOVE_PLAN","MEMBER_REMOVE_APPLY","SPAWN_PLAN","SPAWN_APPLY","EXPORT_PLAN","SYNC_PLAN","PARSE_MANIFEST","ENFORCE_SCOPE","ADOPT_DISCOVER","ADOPT_DRY_RUN","ADOPT_APPLY","MEMBER_MARKER_BOOTSTRAP","MEMBER_MARKER_REMEDIATE","MEMBER_MARKER_VALIDATE","PROMOTE_PLAN","PROMOTE_APPLY"] |
| min_tier | slim |
| token_budget | medium |
| subsystem_memberships | ["WORKSPACE_COORDINATION"] |
g-skl-workspace
Files Read: .gald3r/linking/workspace_manifest.yaml, task/bug frontmatter when validating routing metadata, repository paths named by the manifest, and per-repository git status/worktree metadata.
Files Written: none by default. This skill is read-only for member repositories except for the explicit SPAWN_APPLY lifecycle operation, which may create a new minimal independent git root and update the control project's workspace manifest when an active task authorizes it. It may only update .gald3r/ task status when the active gald3r task workflow explicitly requires it.
Activate for: "workspace status", "workspace validate", "workspace manifest", "member list", "workspace export dry-run", "workspace sync dry-run", "workspace spawn", "spawn workspace member", "workspace adopt", "adopt gald3r project", @g-wrkspc, @g-wrkspc-status, @g-wrkspc-validate, @g-wrkspc-member-list, @g-wrkspc-init --dry-run, @g-wrkspc-member-add --dry-run, @g-wrkspc-member-remove --dry-run, @g-wrkspc-spawn --dry-run, @g-wrkspc-spawn --apply, @g-wrkspc-export --dry-run, @g-wrkspc-sync --dry-run, @g-wrkspc-adopt --discover, @g-wrkspc-adopt --dry-run, @g-wrkspc-adopt --apply, "promote member", "promote to autonomous_child", @g-wpac-promote --dry-run, @g-wpac-promote --apply, plus backwards-compatible @g-workspace-* aliases.
Canonical Registry: .gald3r/linking/workspace_manifest.yaml
Do not infer workspace members from sibling folder names, inferred gald3r_template_* siblings, git remotes, or docs artifacts. The Task 174 docs seed manifest is provenance only. The Task 179 YAML registry is the parseable source of truth.
Purpose
g-skl-workspace is the read-only Workspace-Control Mode entry point. It lets agents inspect a configured workspace, validate the manifest and routing metadata, list controlled members, and explain export/sync plans before any future task authorizes writes. Every manifest repository is treated as an independent git root with its own status, branch, remote, rollback, and worktree context.
Task 170 defines the shared worktree primitive for those git boundaries. When a workflow needs isolation, it must call the Gald3r worktree helper per repository, not once at the workspace root. In <gald3r_source> the helper is gald3r worktree; installed templates carry the same helper in the g-skl-git-commit/scripts/ skill directory for each IDE target. Worktree root defaults to $env:GALD3R_WORKTREE_ROOT or <repo-parent>/.gald3r-worktrees/<repo-name>, branch names use gald3r/{task_id}/{role}/{repo_slug}/{owner}-{suffix}, and cleanup may only remove directories that contain .gald3r-worktree.json ownership metadata.
g-go blast-radius clean gates (T495 / T496)
g-rl-33 Clean Controller and Pre-Reconciliation gates apply per git root in the computed touch set: always the orchestration checkout; plus manifest-resolved roots for task/bug workspace_repos: (v1); optionally extended_touch_repos:, swarm coordinator touch_repos:, and subsystem spec locations: entries that are absolute filesystem paths (v2). Each included root gets the same git status --short + explicit coordinator allowlist discipline described elsewhere in this skill for export/adopt/member-write preflights. Use this skill and workspace_manifest.yaml as the authoritative map from repository.id → local_path; report planned-missing members per lifecycle rules without expanding the touch set until paths exist.
Workspace-Control differs from PCAC:
- PCAC coordinates independent projects through topology, INBOX messages, orders, requests, dependencies, and peer snapshots.
- Workspace-Control routes local agent scope across an explicit member allow-list owned by one control project.
- PCAC state is not a filesystem write allow-list.
- Workspace-Control does not create member-local tasks or mutate member repositories unless a lifecycle operation such as
SPAWN_APPLY is explicitly requested and authorized by the active task.
Required Inputs
Manifest Path
Always look for:
.gald3r/linking/workspace_manifest.yaml
If the file is absent, report quietly:
Workspace-Control: inactive (no .gald3r/linking/workspace_manifest.yaml)
Scope: current repository only
Then stop unless the user explicitly asked for troubleshooting.
Operation: INIT PLAN / INIT APPLY
Usage: @g-wrkspc-init --dry-run or @g-wrkspc-init --apply
Initializes Workspace-Control in the current project by creating or promoting .gald3r/linking/workspace_manifest.yaml as the canonical registry.
INIT PLAN Steps
- Confirm the current project has
.gald3r/ and is a git root.
- If
.gald3r/linking/workspace_manifest.yaml exists, parse it and report that Workspace-Control is already active.
- If the canonical manifest is absent, look for an explicitly supplied seed file argument or a docs seed manifest such as
docs/*WORKSPACE_CONTROL_MANIFEST.yaml.
- Validate the seed with PARSE_MANIFEST rules before proposing promotion.
- Report planned creates/updates only. Do not write files in plan mode.
INIT APPLY Gate
Only write when the user supplies --apply and all of these are true:
- The active task explicitly authorizes Workspace-Control initialization.
.gald3r/linking/ exists or can be created inside the current project.
- The manifest parses successfully or the generated minimal manifest has owner repository data.
- Existing
.gald3r/linking/workspace_manifest.yaml is not overwritten unless --replace is explicitly supplied and the prior manifest is summarized first.
- The command writes only
.gald3r/linking/workspace_manifest.yaml; it never creates, deletes, moves, or edits member repository files.
Required apply output:
Workspace init applied: .gald3r/linking/workspace_manifest.yaml
Member repositories were not modified.
Operation: MEMBER ADD PLAN / MEMBER ADD APPLY
Usage: @g-wrkspc-member-add <path> --id <repo_id> --role <role> --dry-run|--apply
Adds a repository entry to the Workspace-Control manifest. The path may be absent, but apply mode must make that explicit in the lifecycle state.
Required Arguments
--id <repo_id>: stable manifest routing key, matching schema.parse_contract.repository_id_pattern or ^[a-z][a-z0-9_]*$.
--path <path> or first positional <path>: local repository path.
--role <control_project|controlled_member|migration_source>: workspace role.
--repo-role <freeform_role>: optional public role label; default from --role.
MEMBER ADD PLAN Checks
- Run PARSE_MANIFEST; if inactive, tell the user to run
@g-wrkspc-init --dry-run first.
- Reject duplicate repository IDs.
- Normalize the path for parser stability; do not infer IDs from folder names when
--id is absent.
- If the path exists, report symlink/junction status, git root, branch, dirty count, remotes, and worktree context.
- If the path is inside the control project, require
--role migration_source or block.
- Workspace-role choice (T1454): if
--role was NOT supplied, run the Member Role Choice Prompt before reporting the planned manifest fields. Do not silently default to controlled_member. When the role is supplied via --role, skip the prompt.
- Report the manifest fields that would be added, including
allowed_write_policy.default_policy and workspace_role.
- Default controlled members to
write_allowed: false unless the active task explicitly authorizes a write-enabled member.
Member Role Choice Prompt (T1454)
Before any flow writes workspace_role for a new member (MEMBER ADD, SPAWN, or conversational onboarding), and when the role was not already supplied as an explicit argument, present this choice to the user:
This repo will be registered as a workspace member. Pick its role:
[1] autonomous_child (recommended for new project repos)
Will this repo need its own tasks, bugs, and full IDE setup?
-> Independently workable; gets a full .gald3r/ + full gald3r install.
[2] controlled_member
Is it a read-only / source-only member (shared library, docs-only,
or a repo where the controller manages all the work)?
-> Marker-only .gald3r/ (.identity + PROJECT.md); all task tracking
stays in the controller.
Default [1] autonomous_child. Choose [1/2]:
-
The default recommended answer is autonomous_child for new project repos. Treat an empty/Enter response as autonomous_child.
-
For non-interactive / unattended flows (no TTY, or the operation was invoked with an explicit --role), do NOT prompt: honor the supplied --role, and only when neither a TTY nor --role is available fall back to the documented per-operation default (controlled_member for SPAWN's empty-repo bootstrap) and record that the default was auto-selected.
-
When the user (or the default) selects autonomous_child, after the manifest entry is written, automatically run the T1452 full-framework deploy on the target path:
# $memberPath = <absolute_member_path>
& "<<template_adv>_root>\setup_gald3r_project.ps1" -TargetPath $memberPath -Platforms cursor,claude
Verify .claude/, .cursor/, .gald3r_sys/, CLAUDE.md exist on the target afterward. For an already-populated gald3r repo prefer the PROMOTE path (@g-wpac-promote) which performs the same installer step.
-
When the user selects controlled_member, keep the marker-only bootstrap path (gald3r workspace member bootstrap) and do NOT run the full installer.
MEMBER ADD APPLY Gate
Apply may update only .gald3r/linking/workspace_manifest.yaml. It must not initialize git, create folders, copy files, set remotes, or write into the member path. If the member path is missing, record lifecycle_status: planned_clean_member and keep writes blocked.
Operation: SPAWN PLAN / SPAWN APPLY
Usage: @g-wrkspc-spawn <project_name> --id <repo_id> --path <path> --dry-run|--apply
Creates and registers a new local Workspace-Control member project. This mirrors the simplicity of @g-pcac-spawn, but it is strictly local workspace membership, not PCAC topology.
Use SPAWN when the destination folder is new or intentionally empty and the control project needs a clean independent git root for future work, such as example_desktop. Do not use SPAWN for existing gald3r projects with task/bug history; use @g-wrkspc-adopt. Do not use SPAWN for an already-created repo that only needs registry metadata; use @g-wrkspc-member-add.
Required Arguments
<project_name>: folder/display slug for the new member project.
--id <repo_id>: stable manifest routing key, matching schema.parse_contract.repository_id_pattern or ^[a-z][a-z0-9_]*$.
--path <path>: absolute local path for the new independent repository.
Optional arguments:
--description "...": one-line role/mission stored in the manifest description fields.
--template none|slim|full|adv: optional future gald3r template intent. Default none; this operation does not install gald3r templates unless a later task explicitly extends it.
--allow-existing-empty: permit an existing empty target directory.
--role autonomous_child|controlled_member: workspace role for the new member. When omitted, run the Member Role Choice Prompt (default recommended autonomous_child); do not silently assume controlled_member.
SPAWN PLAN Checks
- Run PARSE_MANIFEST; if inactive, tell the user to run
@g-wrkspc-init --dry-run first.
- Reject duplicate repository IDs.
- Normalize
--path and verify it is outside the control project working tree.
- Refuse symlink or junction targets.
- If the path exists, require it to be an empty directory unless
--allow-existing-empty is supplied; if it contains .git/, use MEMBER_ADD or ADOPT instead.
- Workspace-role choice (T1454): if
--role was NOT supplied, run the Member Role Choice Prompt before reporting the planned manifest entry. The default recommended answer is autonomous_child. When autonomous_child is chosen, the new member receives the full gald3r framework via the T1452 installer after the git root + manifest entry are created (see the prompt section); when controlled_member is chosen, only the marker-only .gald3r/ is bootstrapped.
- If the path is absent, report the exact folder that would be created.
- Report the manifest entry that would be added (
workspace_role reflects the chosen role):
- id: <repo_id>
display_name: <project_name>
local_path: <path>
workspace_role: controlled_member
repo_role: workspace_member
lifecycle_status: planned_clean_member
canonical_source_status: empty_member_repo
allowed_write_policy:
default_policy: no_direct_writes_until_task_authorized
inspect_allowed: true
write_allowed: false
- Report that no app runtime, generated template output, PCAC topology, remotes, tasks, bugs, PRDs, or source files will be created by SPAWN.
SPAWN APPLY Gate
SPAWN_APPLY may run only when all gates pass:
-
The user supplied explicit --apply.
-
The active task explicitly authorizes workspace spawning for <repo_id>.
-
PARSE_MANIFEST and SPAWN PLAN checks pass at apply time.
-
The target path is absent or is an existing empty directory with --allow-existing-empty.
-
The destination is not inside the control project and is not a symlink/junction.
-
The control project's manifest is cleanly writable and ENFORCE_SCOPE permits the manifest update.
-
Role-dependent .gald3r/ materialization (T1454 / g-rl-36):
-
controlled_member — marker-only guard (BUG-021 / Task 213 v1.1 / g-rl-36): run the guard helper in marker-init mode, then create the marker pair via the bootstrap helper.
# Confirm member-init is allowed
gald3r workspace member guard --target-path "<absolute_target_path>" --allow-marker-init
# Bootstrap .gald3r/.identity and .gald3r/PROJECT.md
gald3r workspace member bootstrap --member-path "<absolute_target_path>" --member-id "<repo_id>" --apply
The guard at exit 1 (BLOCK) refuses apply with BLOCK spawn_member_repo_gald3r_guard_block. Exit 2 (ERROR) refuses with BLOCK spawn_member_repo_gald3r_guard_error. Bootstrap may itself BLOCK with BLOCK spawn_member_gald3r_has_control_plane when the existing .gald3r/ already contains forbidden content — in that case point the user to gald3r workspace member remediate first. Only the combination of guard ALLOW + bootstrap success completes SPAWN_APPLY.
-
autonomous_child — full-framework deploy (T1452): the marker-only guard does NOT apply. After the git root and manifest entry are created, run the full installer on the target so the child gets .claude/, .cursor/, .gald3r_sys/, root docs, and a full .gald3r/:
# $memberPath = <absolute_target_path>
& "<<template_adv>_root>\setup_gald3r_project.ps1" -TargetPath $memberPath -Platforms cursor,claude
Verify .claude/, .cursor/, .gald3r_sys/, CLAUDE.md exist on the target afterward. setup_gald3r_project.ps1 lives at the root of any <template_adv> install (reuse the controller's copy when it was installed from an adv template).
Allowed apply writes:
- Create the target directory when absent.
- Run
git init inside the target directory.
- Write a minimal
.gitignore that blocks common secrets and local tooling output when no .gitignore exists.
- Write a minimal
README.md with the project name and workspace provenance when no README.md exists.
- Update only
.gald3r/linking/workspace_manifest.yaml in the control project.
Forbidden apply writes (for controlled_member targets):
- Do not install gald3r into the member repo (the full installer runs only for
autonomous_child targets per step 7).
- Do not create member
.gald3r/ task, bug, feature, PRD, subsystem, or linking files.
- Do not copy app scaffolds or runtime source.
- Do not create remotes, branches beyond the default initial branch, tags, commits, or worktrees.
- Do not write PCAC topology/INBOX/order files.
- Do not import/adopt existing history; ADOPT owns that flow.
Required apply output:
Workspace member spawned: <repo_id> at <path>
Created independent git root: yes
Manifest updated: .gald3r/linking/workspace_manifest.yaml
Member source/app files were not scaffolded.
PCAC topology was not modified.
Refusals
SPAWN raises any of the following BLOCK findings with a single-line remediation:
BLOCK workspace_manifest_inactive
BLOCK spawn_repo_id_duplicate
BLOCK spawn_path_inside_control_project
BLOCK spawn_path_symlink_or_junction
BLOCK spawn_path_non_empty
BLOCK spawn_existing_git_root_use_member_add_or_adopt
BLOCK spawn_apply_without_explicit_flag
BLOCK spawn_active_task_not_authorized
BLOCK spawn_manifest_write_policy_refused
BLOCK spawn_member_repo_gald3r_guard_block — gald3r workspace member guard returned exit 1 for the target path (member repos cannot receive live control plane; only .identity + PROJECT.md are allowed)
BLOCK spawn_member_repo_gald3r_guard_error — guard helper returned exit 2 (manifest unparseable or other error); resolve before retrying
BLOCK spawn_member_gald3r_has_control_plane — bootstrap helper refused because the existing .gald3r/ already contains forbidden content; run gald3r workspace member remediate (dry-run, then --apply) first
Operation: MEMBER REMOVE PLAN / MEMBER REMOVE APPLY
Usage: @g-wrkspc-member-remove <repo_id> --dry-run|--apply
Removes or deactivates a repository entry in the manifest. This is registry-only and never deletes files.
MEMBER REMOVE PLAN Checks
- Run PARSE_MANIFEST.
- Confirm the repository ID exists.
- Block removal of
workspace.owner_repository_id unless a replacement owner is explicitly part of a separate approved migration task.
- Report affected fields:
repositories[], controlled_members.repository_ids, expected_count, source/export relationships, and any task/bug routing references that still name the repository.
- Recommend
lifecycle_status: retired when historical routing references exist; recommend removal only when no references exist.
MEMBER REMOVE APPLY Gate
Apply may update only manifest registry fields. It must not delete the repository folder, .git/, branches, remotes, worktrees, tasks, bugs, or generated output. Output must include:
Member registry updated. No repository files were deleted.
Structured Parsing
Use a structured YAML parser when reading the manifest. Do not parse YAML by splitting lines, matching indentation manually, or scanning folder names.
Required top-level keys come from the manifest itself:
schema:
parse_contract:
required_top_level_keys:
- schema
- workspace
- repositories
- controlled_members
- routing_policy
- pcac_relationship
If schema.parse_contract.required_top_level_keys is missing, fall back to the six keys above and report that the parse contract was missing.
Operation: PARSE_MANIFEST
Usage: internal helper operation for all other operations.
- Load
.gald3r/linking/workspace_manifest.yaml with a YAML parser.
- Confirm the parsed value is a mapping/object.
- Read
schema.parse_contract.required_top_level_keys.
- Build a repository map keyed by
repositories[].id.
- Build a controlled member set from
controlled_members.repository_ids.
- Build valid touch-policy values from
routing_policy.workspace_touch_policy_values.
- Return:
manifest_path: .gald3r/linking/workspace_manifest.yaml
workspace_id: <workspace.id>
workspace_lifecycle_status: <workspace.lifecycle_status>
owner_repository_id: <workspace.owner_repository_id>
repositories_by_id: <map>
controlled_member_ids: <list>
valid_touch_policies: <list>
parse_findings: <list>
Parse Rejection Conditions
Reject the manifest for Workspace-Control use when any of these are true:
- The file cannot be parsed as YAML.
- The root value is not a mapping/object.
- Any required top-level key is missing.
repositories is absent or is not a list.
- A repository entry lacks
id, local_path, workspace_role, lifecycle_status, or allowed_write_policy.
- Two repository entries use the same
id.
workspace.owner_repository_id is not present in the repository map.
- A
controlled_members.repository_ids entry is not present in the repository map.
Use actionable findings: name the key, repository ID, and expected shape.
Operation: STATUS
Usage: @g-wrkspc-status or @g-workspace-status
STATUS gives a compact read-only summary of the configured workspace.
Steps
- Run PARSE_MANIFEST.
- If inactive, return the quiet current-repo-only message.
- Display workspace identity:
workspace.id
workspace.display_name
workspace.lifecycle_status
workspace.feature_id
workspace.owner_repository_id
- manifest path
- schema version (report
1.1.0+ features if present)
- Display member repositories:
id
display_name
workspace_role
repo_role
lifecycle_status
canonical_source_status
node_type (defaults to git_repo when absent)
local_path — check reachability; if os_paths is present, prefer the current-OS key over local_path
- path reachability (
present or missing)
- For
git_repo nodes: independent git root status, branch, dirty count, remotes, worktree context, rollback boundary
remote_access entries — show each as [remote:{label} via {method}:{host}]; mark [unreachable] (not an error) if the host is not pingable; never fail STATUS because a remote member is temporarily unreachable
allowed_write_policy.default_policy
allowed_write_policy.write_allowed
- Display clean-repo expectations from each repository.
- Display a concise boundary reminder:
Write boundary: this skill is report-only. Member writes require a later task with explicit workspace_repos, workspace_touch_policy, apply-mode authorization, and independently reviewed git status for each member repo.
Remote Member Display Rules (schema v1.1.0+)
- Local + remote present: show local path status first, then list
remote_access entries as annotations
- Local missing, remote present: show
[local path missing] + [remote:{label} via {method}:{host} path:{path}]
- Unreachable remote: show
[remote:{label} unreachable] — this is informational, not an error
- Non-git node types (
file_store, service_http, database, task_flow): skip git status fields; show endpoint or path from remote_access
OS Path Resolution (schema v1.1.0+)
When a repository has os_paths:
- On Windows: prefer
os_paths.windows over local_path
- On Linux: prefer
os_paths.linux over local_path
- On macOS: prefer
os_paths.mac over local_path
- Fall back to
local_path when the OS-specific key is absent
Suggested Output
Workspace: <gald3r_source> Workspace-Control Bootstrap (active_bootstrap) [schema v1.1.0]
Manifest: .gald3r/linking/workspace_manifest.yaml
Owner: <gald3r_source>
Repositories:
- <gald3r_source>: active, control_project, path present, git root present, branch main, dirty N, remotes N, writes allowed
- example_lib (git_repo): active_member, controlled_member, path present <ECOSYSTEM_ROOT>/example_lib, git root OK, branch main
✈️ [remote:wrm3-kubuntu via ssh:10.0.0.185 path:/data/repos/example_lib]
- <template_slim>: planned_clean_member, controlled_member, path missing (planned gap), writes blocked
- some_api_service (service_http): active_member, path N/A
✈️ [remote:prod via https:api.example.com/v1]
Keep STATUS concise. Do not print full manifest contents unless the user asks for detail.
Operation: MEMBER LIST
Usage: @g-wrkspc-member-list
Lists only repositories declared in repositories[]. Never discover extra members by scanning directories.
Render each manifest repository ID exactly once. Do not repeat a member block in the main table, detail section, or boundary reminder; if a rendering mistake is noticed, correct the output before returning it.
Output Fields
For each repository:
id
display_name
workspace_role
repo_role
local_path
lifecycle_status
canonical_source_status
- path reachability
- git root path
- branch/detached state
- dirty entry count
- remote count
- worktree count
inspect_allowed
write_allowed
Filters
If command arguments are available later, support these report-only filters:
--role control_project
--role controlled_member
--lifecycle active
--lifecycle active_member
--lifecycle adopted
--lifecycle planned_clean_member
--writes allowed|blocked
Unknown filters should be rejected with the supported list.
Operation: VALIDATE
Usage: @g-wrkspc-validate or @g-workspace-validate
VALIDATE checks manifest shape, routing metadata, and local path reachability without changing files.
Manifest Checks
Run all PARSE_MANIFEST checks, plus:
- Repository IDs match
schema.parse_contract.repository_id_pattern or ^[a-z][a-z0-9_]*$.
- No duplicate repository IDs.
- Every
repositories[].local_path is non-empty (except node_type non-git nodes where local_path may be absent).
- Every
repositories[].lifecycle_status is one of:
active
active_bootstrap
active_member
adopted
planned_clean_member
migration_source
deprecated
retired
- Every
allowed_write_policy.default_policy is present.
- Every
allowed_write_policy.allowed_touch_policies value appears in routing_policy.workspace_touch_policy_values.
- Every
allowed_write_policy.allowed_future_policies value appears in routing_policy.workspace_touch_policy_values.
controlled_members.expected_count equals the number of controlled member IDs.
controlled_members.repository_ids contains only repositories whose workspace_role is controlled_member.
workspace.bootstrap_member_ids contains the owner repository and every controlled member.
workspace.source_of_truth.canonical_machine_registry equals .gald3r/linking/workspace_manifest.yaml.
workspace.source_of_truth.seed_manifest_artifact may point to docs, but must not be treated as canonical.
Schema v1.1.0 Checks (when schema.version ≥ 1.1.0)
node_type when present must be one of: git_repo, file_store, service_http, database, task_flow.
- Each
remote_access[] entry must have label and method; SSH entries must also have host, user, path; HTTP entries must have host or endpoint.
os_paths when present must have at least one key from [windows, linux, mac] with a non-empty string value.
Local Path Checks
For each repository:
- Report whether
local_path exists.
- If it exists, reject symlink or junction paths unless the active task explicitly treats the path as a migration source for read-only inspection.
- If it exists, run
git rev-parse --show-toplevel from that path and verify the returned root equals repository.local_path. A nested checkout inside <gald3r_source> is a blocking member-boundary finding unless lifecycle_status: migration_source.
- If it exists, report branch or detached state,
git status --short dirty count, remotes, and git worktree list --porcelain count for that repository only.
- If it is a controlled member and missing, report as a planned/bootstrap gap, not a failure, when
lifecycle_status is planned_clean_member.
- If it is a controlled member and present but not an independent git root, block validation for member-write readiness.
- If it is the owner repository and missing or not an independent git root, reject the manifest for workspace use.
Routing Metadata Checks
When validating tasks or bugs, inspect only YAML frontmatter in .gald3r/tasks/*.md and .gald3r/bugs/*.md if the user asks for routing validation or a task/bug path is supplied. Use the canonical manifest repository map and touch-policy set from PARSE_MANIFEST; do not use hardcoded bootstrap IDs when the manifest exists.
Check:
- If
.gald3r/linking/workspace_manifest.yaml is absent, Workspace-Control is inactive and omitted metadata means current repository only.
- If the manifest exists, every
workspace_repos value must exist in repositories[].id; unknown member IDs are blocking findings.
workspace_touch_policy, when present, must be one of routing_policy.workspace_touch_policy_values.
- Omitted
workspace_repos means the owner/current repository only; it does not authorize sibling or controlled-member inspection or writes.
- Omitted
workspace_touch_policy on current-repo-only work defaults to normal source work; any task or bug naming a controlled member must set it explicitly.
- Multiple repository IDs require an explicit
workspace_touch_policy; controlled member IDs also require explicit task/bug authorization and cannot rely on legacy omitted metadata.
docs_only permits documentation, .gald3r/ planning metadata, task/bug records, manifest metadata, README, and CHANGELOG changes only; source, generated-output, and member-repo writes are outside scope.
source_only permits hand-maintained source changes only in declared repos whose manifest policy allows writes for the active task.
generated_output permits generated member output only in a future apply mode with canonical-source provenance and member clean-repo preflight.
multi_repo requires every inspected or modified repository to be listed and treats each git root as an independent boundary.
Operation: ENFORCE_SCOPE
Usage: internal gate reused by task, bug, implementation, review, and git sanity workflows. It checks a proposed or actual file-change set against the active task/bug routing metadata and .gald3r/linking/workspace_manifest.yaml.
Inputs:
item_type: task | bug | ad_hoc
item_path: .gald3r/tasks/taskNNN_name.md
workspace_repos: []
workspace_touch_policy: null
changed_paths: []
status_history_note: null
Algorithm:
- Run PARSE_MANIFEST. If inactive, allow only current-repository paths and treat workspace metadata as advisory no-op.
- Resolve the owner repository from
workspace.owner_repository_id. Treat omitted workspace_repos as [owner_repository_id].
- Validate all listed repository IDs against the manifest map. Any ID absent from
repositories[].id is BLOCK.
- Validate
workspace_touch_policy against routing_policy.workspace_touch_policy_values when present. Member repos or multiple repos without an explicit policy are BLOCK.
- Map each changed path to a manifest repository by
repository.local_path when absolute, or to the owner repository when repo-relative. Paths that resolve into a manifest repo not listed in workspace_repos are BLOCK.
- For controlled-member writes, require all of: member ID listed, explicit compatible policy, task/bug text authorizes member writes or generated output, manifest
allowed_write_policy.write_allowed: true or a task-specific override, and member git status reviewed independently from the owner repo. During bootstrap, planned clean members with write_allowed: false remain blocked.
- Enforce policy class:
docs_only: changed paths must be docs or metadata (docs/, .gald3r/, README.md, CHANGELOG.md, AGENTS.md, CLAUDE.md, command/skill documentation when the task is documentation-only).
source_only: changed paths must be hand-maintained source/config/docs in declared repos, not generated member output.
generated_output: require canonical source/provenance fields in the task/bug body and reject direct writes if member policy blocks them.
multi_repo: require every touched repo to be declared and report per-repo git boundaries; never assume a single commit spans repos; branch/worktree names must include the member repository ID when Tasks 170-172 worktree mode is used.
- If an update widens scope from omitted/current-only to a member repo, adds any controlled-member ID, or changes policy to
generated_output/multi_repo, require a Status History note or equivalent explicit instruction explaining why the scope widened. Without that note, return BLOCK.
Output findings use PASS, WARN, or BLOCK. Any BLOCK prevents task creation/update, bug creation/update, implementation handoff to [🔍], review pass, or commit preparation until resolved.
Git and Worktree Boundary Rules
- Resolve git roots per
repositories[].local_path; never derive a member repo root by walking upward from <gald3r_source>.
- Dirty/clean checks, branch checks, remotes, rollback instructions, and worktree metadata are per repository.
- Tasks 170-172 own the shared worktree primitive and coding/review integration. Workspace-Control only requires those primitives to run per manifest repository, with branch and worktree names that include the member ID for multi-repo work.
- Commit preparation must describe separate commits per member repository unless a later orchestration task explicitly coordinates a multi-repo release.
- A path nested inside the control project is a migration source folder, not a controlled member repo, unless the manifest explicitly marks it
lifecycle_status: migration_source.
Stale Routing Metadata References
Report stale references when:
- A task or bug names a repository ID that is not in the manifest.
- A task or bug uses a touch policy absent from manifest routing policy.
- A source-of-truth artifact path in the manifest no longer exists inside the control project.
- A repository
migration_source_path points to a missing path while the repository is marked ready for export.
- A member repo is marked
active but the local path is absent.
Validation Result Format
Workspace validation: PASS|FAIL
Manifest: .gald3r/linking/workspace_manifest.yaml
Findings:
- [PASS] required top-level keys present
- [FAIL] repositories[2].id duplicates <template_full>
- [INFO] <template_slim> path missing; allowed while lifecycle_status=planned_clean_member
Use PASS only when there are no blocking findings. Informational findings do not block.
Malformed Manifest Sample
This sample must be rejected because it has no repository list and cannot route member IDs:
schema:
name: gald3r_workspace_control_manifest
workspace:
id: broken_workspace
controlled_members:
repository_ids:
- <template_full>
Expected findings:
Workspace validation: FAIL
- [FAIL] missing required top-level key: repositories
- [FAIL] missing required top-level key: routing_policy
- [FAIL] missing required top-level key: pcac_relationship
Operation: EXPORT PLAN
Usage: @g-wrkspc-export --dry-run or @g-workspace-export --dry-run
EXPORT PLAN describes what an export would do. It never writes files.
Steps
- Run VALIDATE.
- Stop if manifest parsing has blocking findings.
- For each controlled member repository:
- Read
source_template_relationship.migration_source_path.
- Read destination
local_path.
- Read
allowed_write_policy.write_allowed and default_policy.
- Read clean-repo expectations.
- Report independent git root, branch, dirty status, remotes, and worktree context for each reachable destination.
- Report source and destination pairs.
- Report planned action class:
inspect only
would create generated output
blocked until apply task exists
- Report preflight gates that a future apply task must satisfy.
Required Dry-Run Language
Every EXPORT PLAN must include:
Dry-run only: no files were written. Member repository writes remain disabled until a later task explicitly authorizes apply mode.
Future Apply Gate Checklist
A future apply task must prove all of these before writing a member repo:
- The active task names the member ID in
workspace_repos.
- The active task has a compatible
workspace_touch_policy.
- The manifest
allowed_write_policy.write_allowed allows the operation or the task explicitly overrides it.
- The member repo path exists or creation is explicitly authorized.
- The member repo git status, branch, remotes, rollback boundary, and worktree context have been reviewed independently from
<gald3r_source>.
- No
.env, vault data, .git/, local-only personality assets, private backend state, caches, or logs are staged for output.
- Generated output names its canonical source and generation task.
- Parity/tier checks have been run when IDE template content is involved.
Task 184 Bootstrap/Export Helper
For <gald3r_source> maintainers implementing Task 184, the concrete dry-run/apply helper is:
.\custom_scripts\workspace_template_export.ps1
The helper uses uv run python custom_scripts/workspace_template_export.py to parse the canonical manifest with PyYAML, then plans or applies exports from:
<ECOSYSTEM_ROOT>/<template_slim>
<ECOSYSTEM_ROOT>/<template_full>
<ECOSYSTEM_ROOT>/<template_adv>
Default invocation is dry-run only. It reports source folders, destination member repo paths, planned creates/updates, unchanged files, skipped files, provenance output, symlink/junction checks, git-root, branch, clean-status, remote, worktree-context, rollback-boundary checks, hygiene findings, and apply blockers.
Apply mode exists only behind explicit helper flags and must rerun preflight immediately before writing. It never deletes destination files. Missing destination directories are initialized only with --create-missing; existing destinations must already be independent git roots with clean status. Manifest write_allowed: false remains a blocker unless a future task explicitly authorizes and passes --allow-manifest-write-policy-override.
Operation: ADOPT (Existing Gald3r Project Adoption)
Usage:
@g-wrkspc-adopt --discover {path} — preflight + read-only inventory; writes nothing.
@g-wrkspc-adopt --dry-run --source {path} --as {member_id} — generates .gald3r/reports/adoption_{adopt-id}.md.
@g-wrkspc-adopt --apply --source {path} --as {member_id} --plan {report-path} — gated apply that writes only the control project's .gald3r/ and the manifest.
ADOPT brings an existing gald3r-managed project (one that already has a populated .gald3r/ folder with tasks, bugs, features, PRDs, subsystem specs, plans, constraints, and linking data) into a Workspace-Control control project. It is the Workspace-Control mode operation for projects like example_app that pre-date adoption and must remain independent git roots with their own ongoing work.
ADOPT is not PCAC. It is not a task delegation. It does not write the source .gald3r/. It does not write member repository files. It only updates control-project state and the workspace manifest.
For the full design, see docs/20260426_090736_Cursor_WORKSPACE_CONTROL_PROJECT_ADOPTION.md.
Adoption Modes (Named — Mutually Exclusive)
ADOPT distinguishes four mutually-exclusive named modes so agents and reviewers can route a candidate path to the correct command surface without ambiguity. Pick exactly one before any preflight runs:
| Mode | Surface | When to choose | Key invariant |
|---|
clean_member_registration | @g-wrkspc-member-add | Path exists or is planned, contains no .gald3r/ control plane, no app source to import | Registry-only; never writes inside the member |
spawned_member_creation | @g-wrkspc-spawn | Path is absent or is an existing empty directory; needs a fresh independent git root | Creates the folder + git init + minimal .gitignore/README.md + member marker; no history |
marker_only_member_repair | MEMBER_MARKER_BOOTSTRAP/REMEDIATE/VALIDATE | Path exists, may have legacy .gald3r/ content, must end in marker-only shape | Bootstrap writes only .identity + PROJECT.md; remediation quarantines forbidden content |
populated_gald3r_adoption | @g-wrkspc-adopt --discover/--dry-run/--apply | Path is an existing full gald3r project with active .gald3r/ task/bug/feature history (e.g. example_app) — never empty, never just a marker | Source .gald3r/ is read-only at every phase; controller imports active items + archives terminal items + leaves source independent |
When a candidate path looks ambiguous (e.g. has .gald3r/.identity but no TASKS.md), default to refusing the operation and ask the user to choose explicitly. Do not silently route a populated source through SPAWN or MEMBER_ADD; doing so loses task/bug/feature/PRD history and breaks Task 213 / BUG-021 boundary policy.
The remaining ADOPT phases below all describe the populated_gald3r_adoption mode in detail. The other three modes are documented in their own sections.
Mode: populated_gald3r_adoption — Existing Full Gald3r Project Adoption
This is the only ADOPT submode at present. It is the canonical path for adopting mature standalone gald3r projects (the prototype target is <ECOSYSTEM_ROOT>/example_app) that already manage their own tasks, bugs, features, PRDs, releases, constraints, subsystems, plans, and PCAC linking data.
The mode name populated_gald3r_adoption is a stable identifier and may appear in:
- task/bug frontmatter as
adoption_mode: populated_gald3r_adoption
- the dry-run plan front-matter as
adoption_mode: populated_gald3r_adoption
- the manifest member entry's
adoption.adoption_mode field after apply
- the apply ledger and any adoption-related session-summary lines
Core invariants (re-asserted from BUG-021 / Task 213 / g-rl-36):
- Source
.gald3r/ is opened read-only at every phase. ADOPT never writes the source — not in discovery, not in dry-run, not in apply.
- The source remains an independent git root owning its own commits, branches, remotes, and worktrees. ADOPT never pushes to the source remote, never rebases the source branch, never copies source git history into the controller.
- Adoption may produce controller-visible mirrors and imports (active task/bug rows, archived terminal records, reference stubs) while the source continues to own its own source code and packaging.
- Final apply lands the source in marker-only shape (
.identity + PROJECT.md) only after explicit remediation + bootstrap helpers run with user confirmation. Apply must not silently quarantine forbidden content; remediation is its own gated step.
Discovery Inventory (Phase 2 — Read-Only)
ADOPT_DISCOVER MUST inventory every section of the source .gald3r/ so the dry-run report and apply plan are complete. The inventory is read-only — no file is opened in write mode at any point. The minimum inventory list:
| Area | What discovery records |
|---|
| Identity | .gald3r/.identity (or .project_id legacy file): project_id, project_name, gald3r_version, vault_location, user_id |
| Tasks | .gald3r/TASKS.md index + every .gald3r/tasks/task*.md: count, ID range, statuses, priorities, dependencies |
| Bugs | .gald3r/BUGS.md index + every .gald3r/bugs/bug*.md: count, ID range, severity, statuses |
| Features | .gald3r/FEATURES.md index + every .gald3r/features/feat*.md: staging lifecycle status, harvest sources |
| PRDs | .gald3r/PRDS.md index + every .gald3r/prds/prd*.md: governance lifecycle, supersedes-chain, freeze status |
| Releases | .gald3r/RELEASES.md index + every .gald3r/releases/release*.md: target dates, assigned tasks |
| Constraints | .gald3r/CONSTRAINTS.md index + definition blocks: scope, expiry fields |
| Subsystems | .gald3r/SUBSYSTEMS.md index + every .gald3r/subsystems/*.md: name, dependencies, locations, activity log size |
| Plans | .gald3r/PLAN.md headings + linked feature references |
| Project / mission | .gald3r/PROJECT.md: mission, goals, project linking section |
| Ideas | .gald3r/IDEA_BOARD.md: count, age distribution |
| Linking / PCAC | .gald3r/linking/INBOX.md, link_topology.md, sent_orders/*.md, pending_orders/*.md, peers/*, capabilities |
| Reports | .gald3r/reports/*.md: count, kinds (heartbeats, SWOTs, SPRINT, KPI, prior adoption ledgers if any) |
| Logs | .gald3r/logs/*.log: presence + sizes (never copied; flagged as transient) |
| Experiments | .gald3r/experiments/EXPERIMENTS.md, SELF_EVOLUTION.md, EXP-NNN.md: active stages, autopsies |
| Archive buckets | .gald3r/archive/archive_tasks_*.md, archive_bugs_*.md, archive/tasks/, archive/bugs/: bucket count + entry ordinals |
| Specifications collection | .gald3r/specifications_collection/*.md: count, mtimes |
| Learned facts | .gald3r/learned-facts.md: bullet count |
| Unknown / custom folders | Any other folder or file under .gald3r/ not listed above: enumerated verbatim with sizes; never silently skipped |
If discovery encounters a folder it does not recognize, it MUST list it in the dry-run report under "Unknown areas" rather than failing or silently ignoring it. The user decides whether the area is in-scope for adoption.
Source Git Status Report (Phase 1 / Phase 4)
Discovery and apply both produce an independent git status report for the source repository. They never derive source state from the controller's git status. The report records:
git rev-parse --show-toplevel — confirms independent root
- current branch or detached state
- ahead/behind count vs default upstream when available
git status --short dirty entry count
- list of untracked paths (truncated)
- remote count + names
git worktree list --porcelain count + the absolute path of each worktree
- rollback boundary: most recent commit SHA on the current branch
- whether the working tree contains any
.git/MERGE_HEAD, .git/REBASE_HEAD, or other in-progress operation
A dirty source repository is not an automatic block in discovery or dry-run, but it IS a block in apply unless the user supplies --allow-source-dirty and the dry-run report explicitly carries the dirty state forward. See refusals below.
Controller Manifest State Check (Phase 1)
Before any phase touches source data, ADOPT confirms controller manifest readiness:
.gald3r/linking/workspace_manifest.yaml exists and parses cleanly via PARSE_MANIFEST.
- The candidate
--as {member_id} does not collide with an existing repository ID unless --allow-readopt is supplied.
- The controller's git working tree is reviewed independently from the source. Apply requires the controller's
.gald3r/, manifest, and report-output paths to be writable; a dirty controller working tree is not an automatic block but is recorded for review and may be blocked by --require-clean-controller.
- PCAC inbox conflict gate:
g-hk-pcac-inbox-check.ps1 -BlockOnConflict is a hard prerequisite; an unresolved [CONFLICT] blocks apply (and is recorded as an advisory finding in discovery/dry-run).
Lifecycle State: planned_adopting_member
The manifest lifecycle_status vocabulary gains a new value, planned_adopting_member, for the in-flight state between the moment a candidate is registered (or earmarked) for populated adoption and the moment apply commits a final state. It is additive to the existing vocabulary and is recognized by VALIDATE.
Semantics:
- A repository may be entered into the manifest at
lifecycle_status: planned_adopting_member so VALIDATE and STATUS can surface it without authorizing any source-side write.
allowed_write_policy.write_allowed MUST be false while in this state.
- The manifest entry SHOULD include a placeholder
adoption: block with adoption_mode: populated_gald3r_adoption and adoption_operation_id left blank until discovery runs.
- ADOPT_DISCOVER and ADOPT_DRY_RUN may run against a member in
planned_adopting_member without any further manifest mutation.
- Successful ADOPT_APPLY transitions the member from
planned_adopting_member → adopted atomically with the rest of the apply transaction. A failed apply leaves the member at planned_adopting_member; partial writes roll back per the existing apply ledger discipline.
This state exists specifically so the manifest can model "adoption is in progress, dry-run report exists, user has not yet authorized apply" without requiring writes into the source member repository. Workflows using this state must never treat it as authorization to modify the source.
Decision Gate Between Discovery and Apply
ADOPT_DRY_RUN is the user's review checkpoint. After dry-run writes .gald3r/reports/adoption_{adopt-id}.md, all of the following remain blocked until the user explicitly authorizes apply:
- controller
.gald3r/tasks/* import writes
- controller
.gald3r/bugs/* import writes
- controller archive bucket writes (Task 204)
- controller
TASKS.md / BUGS.md row insertions
- manifest member entry transition from
planned_adopting_member → adopted
- any source-side cleanup (
gald3r workspace member remediate --apply)
- any source-side marker bootstrap (
gald3r workspace member bootstrap --apply)
The decision gate is "user supplies --apply AND --plan {report-path} AND the plan is fresh AND its signature matches a re-run discovery". Anything weaker is refused; see the existing BLOCK adoption_apply_without_explicit_flag and BLOCK adoption_plan_signature_mismatch refusals below.
Adoption Operation ID
Every ADOPT run produces a stable identifier:
adopt-YYYYMMDD-HHMMSS-{project_slug}
YYYYMMDD-HHMMSS is the UTC timestamp at the start of discovery.
{project_slug} is derived from the source .gald3r/.identity project_name field, lowercased, non-alphanumerics replaced by _. Falls back to source folder basename when .identity is missing.
The adoption_operation_id is written to the dry-run plan, the apply ledger, every imported/control-visible record's frontmatter, the per-adoption ID-map index, and the manifest member's adoption: block.
Provenance Metadata (every imported or control-visible record)
adoption:
source_project_id: ""
source_project_name: ""
source_project_path: ""
source_artifact_type: ""
source_artifact_id: ""
source_artifact_path: ""
source_artifact_archive_path: ""
adopted_as_id: ""
adoption_operation_id: ""
adoption_class: ""
member_id: ""
Provenance fields are never stripped on subsequent edits.
Archive-Aware Provenance (post-finalization adopted mirrors — BUG-034)
When an adopted member repository is later finalized to marker-only (.gald3r/ reduced to .identity + PROJECT.md per g-rl-36), the original task / bug / feature / PRD source files are preserved inside a finalization archive zip at the member repo root (e.g. .gald3r_archive_YYYYMMDD.zip) but no longer exist at the path captured in adoption.source_artifact_path. To preserve audit traceability, controller-side adopted mirrors carry an optional source_artifact_archive_path pointing into the archive:
adoption:
source_artifact_path: "<ECOSYSTEM_ROOT>/example_web/.gald3r/tasks/task013_features_comparison_page.md"
source_artifact_archive_path: "<ECOSYSTEM_ROOT>/example_web/.gald3r_archive_20260429.zip!tasks/task013_features_comparison_page.md"
Resolution order for verifiers, audit tooling, and @g-pcac-status lookups:
- Try
source_artifact_path on disk first — if it resolves, use it (pre-finalization sources, or sources that were never finalized).
- If on-disk does not resolve and
source_artifact_archive_path is present, resolve via the archive zip (parse <archive_zip>!<entry_path>; open the zip read-only and read the named entry).
- If neither resolves, surface a
provenance_unresolved finding — neither broken nor implicitly accepted.
The original source_artifact_path is never rewritten — it remains the authoritative pre-finalization record-of-origin. source_artifact_archive_path is purely additive.
Workspace-Control finalization MUST record source_artifact_archive_path on every controller-side adopted mirror whose source member it is finalizing, in the same finalization operation that produces the archive zip. Backfill of pre-existing adopted mirrors (e.g. T227–T232 from example_web per BUG-034) is a one-shot bug-fix operation and uses the same field shape.
Per-Artifact Adoption Plan (Five Classes)
| Class | Meaning | Default for |
|---|
active-control-visible | Full record copied; row appears in control TASKS.md/BUGS.md with [adopted:{member_id}] prefix | Active tasks/bugs |
archived-reference | Routed through Task 204 archive buckets; archived file body copied to bucket subfolder | Terminal tasks/bugs (completed/failed/cancelled/resolved/closed/wont-fix) |
link-only | Reference stub only; original lives in source repo; no file copy | Subsystems, plans, linking artifacts |
merge-candidate | Surfaced for human decision; never auto-applied | Active features/PRDs/constraints/subsystems with content overlap to local artifacts |
conflict-deferred | Listed in conflicts section; apply refuses to write until conflict-resolution flag is supplied | Subsystem name exact-match collisions, two-sided released PRD collisions |
ID Mapping & Provenance Schema (T215)
The full ID-mapping, collision-handling, provenance, and frontmatter-upgrade schema lives in docs/20260428_161456_Claude_GALD3R_ADOPTION_ID_MAPPING_PROVENANCE_SCHEMA.md. The summary below is the operational quick-reference. Apply MUST conform to the schema doc; any divergence is a bug in this skill.
Per-artifact mapping (default classes; reviewer may override per-record at dry-run):
| Source type | Default class | Controller representation | ID rule |
|---|
| Active task | active-control-visible | .gald3r/tasks/task{controller_id}_{slug}_adopted.md | Allocate next sequential controller task ID |
Active subtask (084-1) | active-control-visible | .gald3r/tasks/task{controller_id}-{suffix}_{slug}_adopted.md | Next controller parent ID; dotted suffix preserved verbatim |
| Terminal task | archived-reference | .gald3r/archive/tasks/tasks_{range}/task{controller_id}_{slug}_adopted.md | T204 ordinal slot; original ID in archive.original_task_id |
| Active bug | active-control-visible | .gald3r/bugs/bug{controller_id}_{slug}_adopted.md | Allocate next BUG-NNN |
| Terminal bug | archived-reference | .gald3r/archive/bugs/bugs_{range}/bug{controller_id}_{slug}_adopted.md | T204 ordinal slot; original BUG-NNN in archive.original_bug_id |
| Feature | active-control-visible / archived-reference / merge-candidate | .gald3r/features/feat{controller_id}_{slug}_adopted_{member_id}.md | Allocate next feat-NNN; slug suffixed _adopted_{member_id}_{source_id} |
| PRD (draft / review / approved / in-implementation) | active-control-visible | .gald3r/prds/prd{controller_id}_{slug}_adopted_{member_id}.md | Next prd-NNN; supersedes-chain rewritten via per-adoption ID map |
| PRD (released / superseded) | conflict-deferred | Refused without --resolve-conflict prd-{source_id}=mirror|skip | Frozen status preserved verbatim |
| Release (active) | active-control-visible | .gald3r/releases/release{controller_id}_{slug}_adopted_{member_id}.md | Next release-NNN; assigned_tasks rewritten via ID map |
| Release (shipped / cancelled) | archived-reference | .gald3r/archive/adopted/{member_id}/releases/release-{source_id}.md | Same |
| Constraint | active-control-visible / archived-reference | Definition block in CONSTRAINTS.md + index row | Next C-NNN; title suffixed (adopted from {member_id}); T120 scope: preserved |
| Subsystem (no name overlap) | link-only | .gald3r/adopted/{member_id}/subsystems/{name}.md.ref | Namespaced as {name}-{member_id}; never renumbered |
| Subsystem (name exact match) | conflict-deferred | Refused without --resolve-conflict subsystem-name={name}=keep-source|keep-controller|merge|skip | See collision #6 |
| Plan / mission / project identity | link-only | .gald3r/adopted/{member_id}/{filename}.ref | Source canonical; controller never copies mission/plan body |
Idea (IDEA_BOARD.md) | active-control-visible (open) / archived-reference (closed) | Section in controller IDEA_BOARD.md | Synthetic idea-{member_id}-{seq} ID for ID-map only |
| Linking / PCAC | link-only | .gald3r/adopted/{member_id}/linking/{filename}.ref | Source canonical |
| Report | link-only (default) / archived-reference (--copy-reports) | Stub or copy at .gald3r/archive/adopted/{member_id}/reports/ | Never an active queue item (T215 AC9) |
| Log | link-only (always) | .gald3r/adopted/{member_id}/logs/{filename}.ref | Bytes never copied |
| Experiment (active) | merge-candidate | .gald3r/experiments/exp{controller_id}_{slug}_adopted_{member_id}.md | Next EXP-NNN after merge accept |
| Experiment (terminal) | archived-reference | .gald3r/archive/adopted/{member_id}/experiments/EXP-{source_id}.md | Source ID preserved verbatim |
| Archive bucket (existing source) | archived-reference | .gald3r/archive/adopted/{member_id}/{tasks|bugs}/{source_range}/ | Source ranges preserved as a member-scoped sub-tree (collision #9) |
| Specifications collection | link-only | .gald3r/adopted/{member_id}/specifications_collection/{filename}.ref | Source canonical |
| Learned facts | link-only | .gald3r/adopted/{member_id}/learned-facts.ref | Source canonical |
| Unknown / custom folders | merge-candidate | Refused without --accept-unknown {pattern} as {class} | Apply never silently routes unknown areas |
Bidirectional record:
- Per-record frontmatter (
source_artifact_id, source_artifact_path, adopted_as_id, controller_artifact_id, controller_artifact_path).
- Per-adoption ID-map index at
.gald3r/reports/adoption_{adopt-id}_id_map.md with both forward (source → controller) and reverse (controller → source) tables.
- Optional verbatim source-frontmatter snapshots at
.gald3r/reports/adoption_{adopt-id}_snapshots/{source_artifact_id}.yaml (apply only).
Collision Matrix Summary (T215 §2)
13 deterministic collision types cover numeric ID, slug, title, project_id, duplicate-source-IDs, subsystem name (exact + fuzzy), release ID, archive bucket overlap, frozen-PRD adoption, member-id collision, source dirty, and plan-signature mismatch. Each has a fixed default decision (APPLY / WARN / BLOCK) and a documented override flag. The full table is in docs/20260428_161456_Claude_GALD3R_ADOPTION_ID_MAPPING_PROVENANCE_SCHEMA.md §2.
Frontmatter Upgrade Rules Summary (T215 §6)
Source artifacts are never rewritten in the first adoption pass (T215 AC7). Controller-side copies gain the following synthesized fields when missing on the source:
| Field | Default when missing |
|---|
blast_radius | medium |
requires_verification | true for tasks; true for bugs of severity ≥ high; otherwise default |
ai_safe | true |
spec_version | "1.0" |
execution_cost | medium |
workspace_repos | [{member_id}] |
workspace_touch_policy | docs_only (conservative; widens manually) |
| Status History (table) | Synthesized 2-row table from created_date / completed_date with Imported via adoption {adopt-id} message |
Every synthesis is logged in the ID-map's "Frontmatter Upgrade Report" (schema doc §6).
Logs & Reports Policy (T215 §8)
Logs and reports must not become active queue items in the controller. Logs are always link-only. Reports are link-only by default; --copy-reports {pattern} opts selected report patterns into archived-reference for compliance-grade SWOT/KPI capture only.
Import Policy: Active vs Terminal Artifact Classification (T216)
The full lifecycle classification + import policy matrix lives in docs/20260428_165201_Claude_GALD3R_ADOPTION_IMPORT_POLICY.md. The summary below is the operational quick-reference. Apply MUST conform to the policy doc; any divergence is a bug in this skill.
Per-artifact-type lifecycle classification — every source artifact maps to exactly one of five adoption classes based on its source status:
| Source artifact type | Active status → class | Terminal status → class | Notes |
|---|
| Tasks | active-control-visible | archived-reference | Subtasks inherit parent class unless parent terminal + subtask active (orphan rendering). |
| Bugs | active-control-visible | archived-reference | Severity inferred when missing; requires_verification: true forced for severity ≥ High. |
| Features | active-control-visible (staging/specced) / merge-candidate (committed) | archived-reference | committed features need --accept-merge feature={id} because controller may have overlapping work. |
| PRDs | active-control-visible (draft/review/approved/in-implementation) | conflict-deferred (released/superseded) / archived-reference (archived) | C-019 freeze: released/superseded require --resolve-conflict prd-{id}=mirror|link|skip. |
| Releases | active-control-visible (planned/in-progress) | archived-reference (shipped/cancelled) | assigned_tasks rewritten via T215 ID map; roadmap_visibility preserved. |
| Constraints | merge-candidate (active, no controller coverage) / archived-reference (auto-expired) | archived-reference | T120 scope: preserved; title suffixed (adopted from {member_id}). |
| Subsystems | link-only (no name overlap) / merge-candidate (fuzzy match) | conflict-deferred (exact name match) | Namespaced as {name}-{member_id}; adopted task subsystems: field rewritten. |
| Plan / mission / identity | link-only | n/a | Source-anchored; controller never absorbs project mission. |
| Ideas (per row) | active-control-visible | archived-reference | Synthetic idea-{member_id}-{seq} ID assigned at dry-run. |
| Linking / PCAC | link-only | n/a | Source's controller status (if any) → conflict-deferred unless --accept-source-controller-as-data-only. |
| Reports | link-only | link-only | Opt-in --copy-reports {pattern} upgrades to archived-reference. |
| Logs | link-only (always) | link-only | Cannot be promoted; bytes never copied. |
| Experiments | merge-candidate | archived-reference | Chain parents rewritten when both accepted. |
| Source archive sub-trees | n/a | archived-reference (preserved sub-tree) | NOT re-bucketed into controller ordinals; lives at .gald3r/archive/adopted/{member_id}/. |
| Specifications collection | link-only | n/a | Reviewer may PROMOTE individuals at dry-run. |
| Learned facts | link-only | n/a | Source's continual-learning belongs to source. |
| Unknown / custom folders | conflict-deferred | conflict-deferred | Apply REFUSES until --accept-unknown {pattern} as {class} or --reject-unknown {pattern}. |
Active index rendering (controller TASKS.md / BUGS.md / FEATURES.md / RELEASES.md / PRDS.md / CONSTRAINTS.md / IDEA_BOARD.md):
- Rows carry an
[adopted:{member_id}] prefix appended to existing emoji block; regenerated from frontmatter adoption.member_id, never hand-edited.
- PCAC + adoption stack:
[PCAC] [adopted:{member_id}] {title} when source task carries pcac_source block.
- Subsystems lists are rewritten through the per-adoption subsystem ID map (link-only =
{name}-{member_id}; keep-controller resolved = unprefixed).
- Every adopted active file gets a markdown-comment provenance footer (
<!-- ADOPTION PROVENANCE ... -->) so plain markdown viewers can trace lineage without parsing frontmatter.
Dependency remapping (T216 §3) introduces two new frontmatter fields on adopted active tasks/features/PRDs:
| Field | Meaning |
|---|
source_dependencies: [N, M, ...] | Original source IDs preserved verbatim; full source dependency list always recoverable. |
unresolved_source_dependencies: [K, ...] | Source dependencies with no controller mapping (target was link-only / conflict-deferred-skip / unknown-rejected). Surfaced in dry-run as advisory. |
Three-way mapping: active-active deps render as standard controller IDs; active-archived deps satisfy requires_verified_dependencies: true (T212 — archived = passed verification); missing deps drop from dependencies: and surface in unresolved_source_dependencies.
Terminal routing through T204 archives (T216 §4):
- Adopted terminal artifacts use controller's ordinal bucket sequence (T204 rule unchanged); source numeric ID preserved in
archive.original_task_id / archive.original_bug_id.
- Source's own archive sub-tree preserved verbatim under
.gald3r/archive/adopted/{member_id}/{tasks|bugs}/{source_range}/. Two parallel ordinal sequences; never re-bucketed.
- Archive pointer rows in
archive_{tasks|bugs}_{range}.md gain an Adopted From column ({member_id}:source-task-NNN); empty (—) for non-adoption archives.
Conflict resolution vocabulary (T216 §5) — every conflict-deferred item requires an explicit decision; no silent defaults:
| Decision | Effect |
|---|
keep-source | Replace controller artifact with source; existing controller version moved to .gald3r/{kind}/{name}.controller-orig.md. |
keep-controller | Skip source artifact; record link-only reference. |
merge | Held for human merge editor at .gald3r/{kind}/{name}.merged.md; apply REFUSES until merge file lands. |
skip | Record skip in adoption ledger; no source content lands. |
mirror (PRD released only) | Copy as archived-reference; frozen status preserved verbatim. |
link (PRD released/superseded only) | Link-only stub; no body copy. |
Apply CLI extends @g-wrkspc-adopt --apply --plan {report-path} with: --resolve-conflict {kind}-{id}={decision}, --accept-unknown {pattern} as {class}, --reject-unknown {pattern}, --accept-merge {kind}={id} as {class}, --skip-merge {kind}={id}, --copy-reports {pattern}, --shipped-features-as-link-only, --accept-source-controller-as-data-only.
The full 39-row import policy matrix (artifact-type × source-status × default class × required provenance × apply gate) and 7 worked examples are in docs/20260428_165201_Claude_GALD3R_ADOPTION_IMPORT_POLICY.md §6 and §8.
Active Index Visibility
Active imported tasks and bugs MUST appear in .gald3r/TASKS.md and .gald3r/BUGS.md so agents see open imported work without leaving the control project. Three rules prevent index bloat:
- Each adopted active row uses an
[adopted:{member_id}] prefix appended to the existing emoji block.
- Only
active-control-visible items appear in the active indexes. Terminal items go straight to Task 204 archive buckets and never cross the active index.
- Adopted rows are regenerated from per-record frontmatter, never hand-edited.
Archive Routing for Terminal Imports
Terminal items are written directly to the Task 204 archive structure:
- Bucket allocation by archive entry ordinal (T204 rule), not by original task/bug ID.
- A dedicated section heading per adoption operation:
## Adopted from {member_id} ({adoption_operation_id})
| Archive Slot | Task | Title | Final Status | Completed/Closed | Source Project | Workspace Repos | Archived File |
|--------------|------|-------|--------------|------------------|----------------|-----------------|---------------|
- Archived task/bug files live at
.gald3r/archive/tasks/tasks_{range}/task{adopted_id}_{slug}_adopted.md (and the bug equivalent), with BOTH the standard archive: block AND the adoption: block in frontmatter.
Manifest Member Status Update
After successful apply, the manifest member entry for {member_id} is updated atomically with the apply transaction. New fields:
- id: {member_id}
lifecycle_status: adopted
canonical_source_status: external_gald3r_project_managed_independently
adoption:
adopted_at: "YYYY-MM-DDTHH:MM:SSZ"
adoption_operation_id: adopt-YYYYMMDD-HHMMSS-{project_slug}
adoption_plan_path: ".gald3r/reports/adoption_{adopt-id}.md"
adoption_apply_ledger: ".gald3r/reports/adoption_{adopt-id}_apply.md"
artifacts_imported:
tasks_active: N
tasks_archived: N
bugs_active: N
bugs_archived: N
features_referenced: N
prds_referenced: N
subsystems_linked: N
constraints_referenced: N
artifacts_deferred:
merge_candidates: N
conflicts: N
allowed_write_policy:
default_policy: no_direct_writes_during_adoption
inspect_allowed: true
write_allowed: false
adopted is a new value in the validated lifecycle_status vocabulary. external_gald3r_project is recognized for repo_role. no_direct_writes_during_adoption is recognized for allowed_write_policy.default_policy. These are additive, backward compatible.
The manifest update is registry-only; no member repository file is touched.
Phase 1 — Preflight (ADOPT_DISCOVER prerequisite)
All must pass before discovery:
- Control project's
.gald3r/linking/workspace_manifest.yaml exists and parses cleanly via PARSE_MANIFEST.
- Source
{path} exists and is reachable.
- Source
{path} is an independent git root distinct from the control project root.
- Source
{path} is not a symlink or junction.
- Source
{path}/.gald3r/ exists and contains at minimum .identity (or .project_id) AND TASKS.md.
- Source path is not nested inside the control project working tree.
- If
{path} is already a manifest member with lifecycle_status: active, refuse without --allow-readopt.
Phase 2 — ADOPT_DISCOVER
Reads source .gald3r/ read-only. Builds inventory: source identity, per-type counts and ID ranges, first-pass per-artifact class assignment, draft ID mapping, draft conflict list. Writes nothing. Returns inventory and prints a compact summary.
Phase 3 — ADOPT_DRY_RUN
Re-runs discovery and writes a single Markdown report at .gald3r/reports/adoption_{adopt-id}.md. The report sections (fixed headings, parseable):
- Source Identity
- Artifact Counts by Type
- ID Collision Plan
- Active/Open Imports (active-control-visible)
- Completed/Closed Archive Imports (archived-reference)
- Merge Candidates
- Conflicts (
_No conflicts detected._ when empty)
- Reference Stubs (link-only)
- Manifest Member Status Delta
- Apply Decision Summary
- Provenance
The report is the single artifact a future apply consumes.
Phase 4 — ADOPT_APPLY (Gated)
Apply runs only when all gates pass; any failure aborts with no partial writes:
-
Active task explicitly authorizes adoption work for {member_id}.
-
--plan path exists, parses, and is fresh (mtime within --plan-max-age-hours, default 24h).
-
Plan's adoption_operation_id matches the recomputed ID for (source path, member_id) or the user supplied --reuse-id.
-
Preflight (Phase 1) passes again at apply time.
-
Discovery re-runs and matches the plan's artifact count and ID-mapping signature; any drift refuses with BLOCK adoption_plan_signature_mismatch.
-
The user supplied explicit --apply (no implicit apply).
-
Manifest allowed_write_policy permits the manifest update for the active task (re-checked via ENFORCE_SCOPE).
-
Member .gald3r/ marker-only guard (BUG-021 / Task 213 v1.1 / g-rl-36): ADOPT writes go to the control project, never to the member's live control plane. Apply must:
a. Run the validate helper against the source/member path: gald3r workspace member validate. If the member entry shows has_violations, refuse with BLOCK adoption_member_repo_live_control_plane and direct the user to gald3r workspace member remediate followed by re-adoption.