- 1. Feature Context
- 2. Actor Flows (CDSL)
- 3. Processes / Business Logic (CDSL)
- 4. States (CDSL)
- 5. Definitions of Done
- 6. Implementation Modules
- 7. Acceptance Criteria
-
p1- ID:cpt-cypilot-featstatus-workspace
-
p1-cpt-cypilot-feature-workspace
Multi-repo workspace federation enabling nested sub-directory repo discovery, source configuration (standalone or inline), cross-repo artifact traceability, and graceful degradation when sources are unreachable. Projects without workspace config continue operating in single-repo mode with zero behavioral changes.
Enables teams working across multiple repositories to federate their Cypilot-managed artifacts — discovering repos in nested sub-directories, resolving cross-repo artifact paths, and collecting IDs across workspace boundaries — without merging adapters or modifying individual project configs. Addresses PRD requirement for workspace federation (cpt-cypilot-fr-core-workspace) and extends the core traceability system (cpt-cypilot-fr-core-traceability) with cross-repo resolution.
Delegation context note: When Cypilot delegates execution to an external executor (e.g., ralphex), the delegated execution uses the same workspace/source-resolved context as the primary Cypilot session. Workspace source paths, adapter bindings, and cross-repo artifact resolution remain authoritative for delegated tasks. This feature does not own delegation logic — that belongs to cpt-cypilot-feature-ralphex-delegation — but it provides the context foundation that delegation consumers rely on (see cpt-cypilot-adr-ralphex-delegation-skill).
| Actor | Role in Feature |
|---|---|
cpt-cypilot-actor-user |
Runs workspace-init, workspace-add (with --inline flag for inline mode), workspace-info, workspace-sync; uses validate --local-only and list-ids --source |
cpt-cypilot-actor-cypilot-cli |
Discovers workspace config during context loading, resolves cross-repo paths, loads source contexts |
- PRD: PRD.md —
cpt-cypilot-fr-core-workspace,cpt-cypilot-fr-core-traceability,cpt-cypilot-fr-core-workspace-git-sources,cpt-cypilot-fr-core-workspace-cross-repo-editing - Design: DESIGN.md —
cpt-cypilot-component-config-manager,cpt-cypilot-component-traceability-engine - Design Principles:
cpt-cypilot-principle-traceability-by-design,cpt-cypilot-principle-determinism-first,cpt-cypilot-principle-zero-harm - Design Constraints:
cpt-cypilot-constraint-python-stdlib - CLI Spec: cli.md
- Dependencies:
cpt-cypilot-feature-core-infra,cpt-cypilot-feature-traceability-validation
The following quality domains are not applicable to this feature:
- Performance: Core operations (init, add, info) are local filesystem reads/writes on small TOML configs. Git URL source resolution clones on first access only; subsequent reads reuse the cached checkout without network operations. Explicit updates via
workspace-syncdelegate to the user's git CLI with a 300-second (5 min) default timeout, configurable viaGIT_TIMEOUTenvironment variable; no custom performance-sensitive code paths beyond subprocess delegation - Security: Local-path mode has no network access. Git URL sources perform
git clone(first access) andgit fetch(only via explicitworkspace-sync) using the user's existing Git CLI credentials — no custom authentication or credential handling. CLI arguments parsed by argparse with no untrusted input - Compliance: No regulatory, privacy, or audit requirements
- Usability (UI): CLI-only interaction with structured JSON output; no graphical UI
- Operations: No deployment, observability, or infrastructure concerns; standalone CLI commands
- Workspace-level aggregate linting or test orchestration across sources
- Remote source authentication beyond Git CLI credentials
- Workspace-level dependency resolution between source packages
- Live file-watching or automatic re-discovery of sources
- Cross-source manifest layer discovery and component merging (belongs to project-extensibility — see "Relationship with Workspace Federation" in PROJECT-EXTENSIBILITY guide)
-
p1- ID:cpt-cypilot-flow-workspace-init
Actors:
cpt-cypilot-actor-usercpt-cypilot-actor-cypilot-cli
Success Scenarios:
- User runs
workspace-init→ nested sub-directories scanned for repos, workspace config generated with discovered sources - User runs
workspace-init --inline→ workspace config written inline intoconfig/core.toml - User runs
workspace-init --dry-run→ shows what would be generated without writing
Error Scenarios:
- No project root found → error with instructions
- Scan root not found → error with path
- No repos discovered in nested sub-directories → creates empty workspace (sources: {})
--inlinewith existing standalone workspace → error (prevents parallel configs)- Standalone init with existing inline workspace → error (prevents parallel configs)
- Re-init without
--forcewhen workspace already exists → error suggesting--force
Steps:
- -
p1- User invokescypilot workspace-init [--root DIR] [--output PATH] [--inline] [--force] [--max-depth N] [--dry-run]-inst-user-workspace-init - -
p1- Find project root from current directory -inst-find-project-root - -
p1- IF no project root found RETURN error: "No project root found" (exit 1) -inst-if-no-root - -
p1- Determine scan root:--rootargument or project root itself -inst-determine-scan-root - -
p1- IF scan root not found RETURN error (exit 1) -inst-if-no-scan-root - -
p1- Algorithm: discover repos in nested sub-directories usingcpt-cypilot-algo-workspace-discover-nested(limited to--max-depthlevels, default 3) -inst-discover-nested - -
p1- Build workspace data with version and discovered sources (may be empty) -inst-build-workspace-data - -
p1- IF--dry-runRETURN DRY_RUN status with workspace preview (exit 0) -inst-if-dry-run - -
p1- IF existing workspace config found: IF cross-type conflict (inline vs standalone) RETURN error (exit 1); IF same type and no--forceRETURN error suggesting--force(exit 1) -inst-if-existing-ws - -
p1- IF--inlinewrite workspace inline to core.toml -inst-if-inline - -
p1- ELSE write standalone.cypilot-workspace.toml-inst-else-standalone - -
p1- RETURN JSON:{status: CREATED, config_path, sources_count, sources}(exit 0) -inst-return-init-ok - -
p1- Implementation: write workspace config inline to core.toml -inst-write-inline-impl - -
p1- Implementation: write standalone.cypilot-workspace.tomlfile -inst-write-standalone-impl - -
p1- Helper functions: output directory resolution, existing workspace conflict detection -inst-init-helpers - -
p1- Human-friendly formatter for workspace init output -inst-init-human-fmt
-
p1- ID:cpt-cypilot-flow-workspace-add
Actors:
cpt-cypilot-actor-usercpt-cypilot-actor-cypilot-cli
Success Scenarios:
- User runs
workspace-add --name N --path P→ local source added to standalone workspace config - User runs
workspace-add --name N --url U [--branch B]→ Git URL source added to standalone workspace config - User runs
workspace-add --inline --name N --path P→ source added inline to core.toml
Error Scenarios:
- No project root → error
- No workspace config found without
--inline→ error with init hint - Source name already exists without
--force→ error: "Source '{name}' already exists. Use --force to replace." - Git URL source with inline workspace → error (URLs not supported inline)
--inlineflag with existing standalone workspace → error (prevents parallel configs)
Steps:
- -
p1- User invokesworkspace-add --name N (--path P | --url U) [--branch B] [--role R] [--adapter A] [--force]orworkspace-add --inline --name N --path P [--role R] [--adapter A] [--force]-inst-user-workspace-add - -
p1- Find project root -inst-add-find-root - -
p1- IF no project root RETURN error (exit 1) -inst-add-if-no-root - -
p1- IF--inlineflag set: check for existing standalone workspace; IF standalone exists RETURN error (exit 1); ELSE add to inline config -inst-add-if-inline-flag - -
p1- ELSE find existing workspace config usingcpt-cypilot-algo-workspace-find-config-inst-add-find-ws - -
p1- IF no workspace config found RETURN error: "Run workspace-init first" (exit 1) -inst-add-if-no-ws - -
p1- IF existing workspace is inline, auto-route to inline add (no--inlineflag required) -inst-add-auto-detect-inline - -
p1- IF source name already exists AND--forcenot specified RETURN error: "Source '{name}' already exists. Use --force to replace." (exit 1) -inst-add-check-collision - -
p1- Add source entry to config -inst-add-source - -
p1- Save updated config -inst-add-save - -
p1- RETURN JSON:{status: ADDED, source}(exit 0) -inst-add-return-ok - -
p1- Implementation: inline source addition to core.toml -inst-add-inline-impl - -
p1- Human-friendly formatter for workspace add output -inst-add-human-fmt
-
p1- ID:cpt-cypilot-flow-workspace-info
Actors:
cpt-cypilot-actor-usercpt-cypilot-actor-cypilot-cli
Success Scenarios:
- User runs
workspace-info→ workspace config displayed with per-source reachability, artifact counts, traceability settings
Error Scenarios:
- No project root → error
- No workspace config → ERROR status with hint
- Workspace config parse error → ERROR status
Steps:
- -
p1- User invokescypilot workspace-info-inst-user-workspace-info - -
p1- Find project root -inst-info-find-root - -
p1- IF no project root RETURN error (exit 1) -inst-info-if-no-root - -
p1- Find workspace config usingcpt-cypilot-algo-workspace-find-config-inst-info-find-ws - -
p1- IF config error RETURN ERROR status (exit 1) -inst-info-if-error - -
p1- IF no workspace RETURN ERROR status with hint (exit 1) -inst-info-if-no-ws - -
p1- FOR EACH source build status info (path, reachability, adapter, artifact counts) -inst-info-foreach-source - -
p1- Load workspace context if available, enrich with cross-repo stats -inst-info-load-context - -
p1- RETURN JSON:{status: OK, version, sources, traceability}(exit 0) -inst-info-return-ok - -
p1- Helper functions: source adapter probing, status building, artifact counting -inst-info-helpers - -
p1- Build result dict with config path, sources info, traceability settings -inst-info-build-result - -
p1- Human-friendly formatter for workspace info output -inst-info-human-fmt
-
p1- ID:cpt-cypilot-flow-workspace-sync
Actors:
cpt-cypilot-actor-usercpt-cypilot-actor-cypilot-cli
Success Scenarios:
- User runs
workspace-sync→ all Git URL sources fetched and worktrees updated to match remote - User runs
workspace-sync --source N→ only named source synced - User runs
workspace-sync --dry-run→ shows which sources would be synced without network operations
Error Scenarios:
- No project root found → error with instructions
- No workspace config found → error with init hint
- Named source not found → error listing available sources
- Named source has no Git URL (local path only) → error explaining only Git URL sources can be synced
- Git fetch or update fails → warning per source, continue with remaining sources
Steps:
- -
p1- User invokescypilot workspace-sync [--source NAME] [--dry-run]-inst-user-workspace-sync - -
p1- Find project root from current directory -inst-sync-find-root - -
p1- IF no project root found RETURN error (exit 1) -inst-sync-if-no-root - -
p1- Find workspace config usingcpt-cypilot-algo-workspace-find-config-inst-sync-find-ws - -
p1- IF no workspace config found RETURN error with init hint (exit 1) -inst-sync-if-no-ws - -
p1- Collect Git URL sources: IF--sourceis set, look up single source by name; ELSE collect all sources withurlset -inst-sync-collect-sources - -
p1- IF--sourceset AND source not found RETURN error listing available sources (exit 1) -inst-sync-if-source-not-found - -
p1- IF--sourceset AND source has no URL RETURN error (exit 1) -inst-sync-if-no-url - -
p1- IF no Git URL sources found RETURN status with message "no git sources to sync" (exit 0) -inst-sync-if-no-git-sources - -
p1- IF--dry-runRETURN DRY_RUN status listing sources that would be synced (exit 0) -inst-sync-if-dry-run - -
p1- FOR EACH Git URL source: algorithmcpt-cypilot-algo-workspace-sync-git-source, collect per-source result -inst-sync-foreach-source - -
p1- RETURN JSON:{status: OK, synced, failed, results: [{name, status, error?}]}(exit 0, or exit 2 if all failed) -inst-sync-return-ok - -
p1- Human-friendly formatter for workspace sync output -inst-sync-human-fmt
-
p1- ID:cpt-cypilot-algo-workspace-find-config
Input: Project root path
Output: (WorkspaceConfig, None) or (None, error_message) or (None, None) if no workspace
Steps:
- -
p1- Load project config fromcore.toml(via AGENTS.md cypilot_path) -inst-find-load-project-config - -
p1- IF project config not found: IF config file exists but failed to parse RETURN(None, error); ELSE fall through to standalone auto-discovery (step 5) -inst-find-if-no-config - -
p1- IF project config hasworkspacekey as string path -inst-find-if-ws-string- -
p1- Resolve path relative to project root and load as standalone TOML -inst-find-load-standalone - -
p1- RETURN(WorkspaceConfig, None)or(None, error)-inst-find-return-standalone
- -
- -
p1- IF project config hasworkspacekey as dict -inst-find-if-ws-dict- -
p1- Parse inline workspace config withresolution_baseset to project root -inst-find-parse-inline - -
p1- RETURN(WorkspaceConfig, None)-inst-find-return-inline
- -
- -
p1- IFworkspacekey absent or config not loaded: check for standalone.cypilot-workspace.tomlat project root; IF file exists load and RETURN(WorkspaceConfig, None)or(None, error); ELSE RETURN(None, None)— no workspace, single-repo mode -inst-find-return-none - -
p1- Data model:WorkspaceConfigclass, factory methods, serialization -inst-find-config-datamodel - -
p1- Implementation: parse inline workspace from core.toml[workspace]section -inst-find-parse-inline-impl - -
p1- Implementation: discover standalone.cypilot-workspace.tomlat project root -inst-find-standalone-impl
-
p1- ID:cpt-cypilot-algo-workspace-discover-nested
Input: Scan root directory, output directory (for relative path computation), max_depth (default 3)
Output: Dict of source_name -> {path, adapter?, role}
Steps:
- -
p1- IF current depth exceeds max_depth RETURN empty dict -inst-disc-check-depth - -
p1- List entries in scan root, sorted alphabetically -inst-disc-list-entries - -
p1- FOR EACH directory entry (skip hidden dirs and symlinks) -inst-disc-foreach-entry- -
p1- Check if directory is a project (has.gitorAGENTS.mdwith@cpt:root-agentsmarker) -inst-disc-check-project - -
p1- IF not a project, recurse into subdirectory (depth + 1) and merge results, then skip to next entry -inst-disc-if-not-project - -
p1- Find adapter path: readcypilot_pathfrom AGENTS.md, fallback tofind_cypilot_directory-inst-disc-find-adapter - -
p1- IF no adapter found, skip directory -inst-disc-if-no-adapter - -
p1- Compute relative source path from output location -inst-disc-compute-path - -
p1- Algorithm: infer role usingcpt-cypilot-algo-workspace-infer-role-inst-disc-infer-role - -
p1- Add to discovered sources dict -inst-disc-add-source
- -
- -
p1- RETURN discovered sources -inst-disc-return - -
p1- Helper functions: project directory detection, adapter path finding, source path computation -inst-disc-helpers
-
p1- ID:cpt-cypilot-algo-workspace-resolve-source
Input: Source name, workspace config
Output: Absolute filesystem path or None
Steps:
- -
p1- Look up source entry by name -inst-resolve-lookup - -
p1- IF source not found RETURN None -inst-resolve-if-not-found - -
p1- Determine base directory:resolution_baseif set (inline mode), else workspace file's parent directory, else return None -inst-resolve-determine-base - -
p1- IFsource.pathis set RETURN(base / source.path).resolve()(pathtakes precedence overurl) -inst-resolve-return - -
p1- IFsource.urlis set, delegate tocpt-cypilot-algo-workspace-resolve-git-url-inst-resolve-git-url-delegate - -
p1- RETURN None -inst-resolve-fallback - -
p1- Data model:SourceEntryclass, workspace imports, constants -inst-resolve-datamodel
-
p1- ID:cpt-cypilot-algo-workspace-infer-role
Input: Repository path
Output: Role string ("artifacts", "codebase", "kits", "full")
Steps:
- -
p1- Check for source directories:src/,lib/,app/,pkg/-inst-role-check-src - -
p1- Check for documentation directories:docs/,architecture/,requirements/-inst-role-check-docs - -
p1- Check for kits directory:kits/-inst-role-check-kits - -
p1- IF multiple capabilities present (more than one of src/docs/kits) RETURN"full"-inst-role-if-multi - -
p1- IF has kits AND no source dirs RETURN"kits"-inst-role-if-kits - -
p1- IF has docs AND no source dirs RETURN"artifacts"-inst-role-if-artifacts - -
p1- IF has source dirs AND no docs RETURN"codebase"-inst-role-if-codebase - -
p1- ELSE RETURN"full"-inst-role-return-full
-
p1- ID:cpt-cypilot-algo-workspace-load-context
Input: Primary CypilotContext
Output: WorkspaceContext or None (if no workspace config found)
Steps:
- -
p1- Find workspace config usingcpt-cypilot-algo-workspace-find-config-inst-ctx-find-config - -
p1- IF config error, emit warning to stderr -inst-ctx-if-error - -
p1- IF no config found RETURN None -inst-ctx-if-no-config - -
p1- FOR EACH source in config -inst-ctx-foreach-source- -
p1- Resolve source path -inst-ctx-resolve-path - -
p1- IF path not found or not a directory, create unreachable SourceContext -inst-ctx-if-unreachable - -
p1- ELSE find adapter directory, load ArtifactsMeta, extract registered systems -inst-ctx-load-source-meta
- -
- -
p1- Build WorkspaceContext with primary context, loaded sources, traceability settings -inst-ctx-build - -
p1- RETURN WorkspaceContext -inst-ctx-return
-
p1- ID:cpt-cypilot-algo-workspace-resolve-artifact
Input: Artifact (with optional source attribute), fallback root path
Output: Optional[Path] — resolved absolute path or None
Steps:
- -
p1- Check if artifact has asourceattribute naming a workspace source -inst-art-check-source - -
p1- IF source is set -inst-art-if-source- -
p1- Look up SourceContext by name -inst-art-lookup-source - -
p1- IF source reachable RETURN(source.path / artifact.path).resolve()-inst-art-if-reachable - -
p1- ELSE RETURN None (prevent silent fallback to local path) -inst-art-return-none
- -
- -
p1- ELSE RETURN(fallback_root / artifact.path).resolve()-inst-art-return-local
-
p1- ID:cpt-cypilot-algo-workspace-collect-ids
Input: WorkspaceContext
Output: Set of all definition IDs across primary and remote sources
Steps:
- -
p1- Collect definition IDs from primary context artifacts -inst-ids-collect-primary - -
p1- IFcross_repoANDresolve_remote_idsare enabled -inst-ids-if-cross-repo- -
p1- FOR EACH reachable source with loaded metadata and roleartifactsorfull-inst-ids-foreach-source- -
p1- FOR EACH artifact in source, scan for ID definitions -inst-ids-scan-source-artifacts - -
p1- Add discovered IDs to the set (emit warning on scan failure) -inst-ids-add-with-warning
- -
- -
- -
p1- RETURN collected ID set -inst-ids-return
-
p1- ID:cpt-cypilot-algo-workspace-resolve-git-url
Input: SourceEntry (with url set), ResolveConfig, workspace file parent path
Output: Absolute filesystem path to the resolved local directory
Steps:
- -
p1- Delegate fromresolve_source_pathwhen source hasurlset -inst-resolve-git-url-delegate - -
p1- Parse URL into host, org, repo components -inst-git-parse-url - -
p1- Look up namespace rule by exact host match inresolve.namespace-inst-git-lookup-namespace - -
p1- IF no matching rule, use default template{org}/{repo}-inst-git-if-no-rule - -
p1- Apply template substitution: replace{org}and{repo}placeholders -inst-git-apply-template - -
p1- Compute local path:(workspace_parent / resolve.workdir / templated_path).resolve()(defaultresolve.workdir:.workspace-sources) -inst-git-compute-path - -
p1- Determine branch: sourcebranchfield if set, else"HEAD"-inst-git-determine-branch - -
p1- IF local path exists AND is a git repo, RETURN local path (no network operation — useworkspace-syncto update) -inst-git-if-exists-fetch - -
p1- ELSE rungit clone --branch {branch} {url} {local_path}-inst-git-else-clone - -
p1- IF git command fails or times out (300s default, override viaGIT_TIMEOUTenv var), mark source as unreachable with error message -inst-git-if-fail - -
p1- RETURN resolved local path -inst-git-return-path - -
p1- Data model:TraceabilityConfig,NamespaceRule,ResolveConfigclasses and URL patterns -inst-git-datamodel - -
p1- Clone or return existing local path via subprocess -inst-git-clone-or-fetch - -
p1- Run git command via subprocess with timeout -inst-git-run-command
-
p1- ID:cpt-cypilot-algo-workspace-sync-git-source
Input: SourceEntry (with url set), ResolveConfig, workspace file parent path
Output: {status: "synced"|"failed", error?} — result of syncing one Git URL source
Steps:
- -
p1- Resolve local path usingcpt-cypilot-algo-workspace-resolve-git-url(clone-only, no fetch) -inst-sync-resolve-path - -
p1- IF resolved path is None RETURN{status: "failed", error: "resolve failed"}-inst-sync-if-no-path - -
p1- IF local path does not exist or is not a git repo RETURN{status: "failed", error: "not a git repo"}-inst-sync-if-not-repo - -
p1- Rungit fetch --quiet origin [branch]-inst-sync-fetch - -
p1- IF fetch fails RETURN{status: "failed", error}-inst-sync-if-fetch-fail - -
p1- Determine branch: sourcebranchfield if set, else"HEAD"-inst-sync-determine-branch - -
p1- IF branch == "HEAD": rungit reset --hard FETCH_HEAD-inst-sync-if-head - -
p1- ELSE: rungit checkout -B {branch} origin/{branch}-inst-sync-else-branch - -
p1- IF update fails, emit warning RETURN{status: "failed", error}-inst-sync-if-update-fail - -
p1- RETURN{status: "synced"}-inst-sync-return-ok
-
p1- ID:cpt-cypilot-algo-workspace-resolve-adapter-context
Input: SourceContext (reachable, with adapter_dir set)
Output: CypilotContext loaded from the source's adapter, or None
Steps:
- -
p1- IF source is not reachable RETURN None -inst-adapter-if-unreachable - -
p1- IFadapter_diris None RETURN None -inst-adapter-if-no-dir - -
p1- Verify adapter directory exists:source.adapter_dir(already resolved to absolute path during source loading) -inst-adapter-compute-path - -
p1- IF adapter directory does not exist RETURN None with warning -inst-adapter-if-missing - -
p1- LoadCypilotContextfrom the adapter path (config, kits, templates, rules, constraints) -inst-adapter-load-context - -
p1- IF loading fails, emit warning to stderr RETURN None -inst-adapter-if-load-fail - -
p1- Cache the loaded context onSourceContext.adapter_context-inst-adapter-cache - -
p1- RETURN loadedCypilotContext-inst-adapter-return - -
p1- Helper: return source meta with autodetect expanded; lazy-load full context via steps 1-8 on first access, return cachedadapter_context.metaon repeat calls, fall back to rawmetawhen adapter unavailable -inst-adapter-expand-meta
-
p1- ID:cpt-cypilot-algo-workspace-determine-target
Input: Target file path, WorkspaceContext
Output: (SourceContext, CypilotContext) for the source owning the target file, or (None, primary_context) if the file belongs to the primary repo
Steps:
- -
p1- Resolve target file to absolute path -inst-target-resolve-abs - -
p1- FOR EACH source inworkspace.sources(ordered by path length descending for longest-prefix match) -inst-target-foreach-source- -
p1- IF target path starts with source absolute path -inst-target-if-match- -
p1- Resolve adapter context usingcpt-cypilot-algo-workspace-resolve-adapter-context-inst-target-resolve-adapter - -
p1- IF adapter context loaded RETURN(source, adapter_context)-inst-target-return-source - -
p1- ELSE RETURN(source, primary_context)— source matched but no adapter available -inst-target-return-source-no-adapter
- -
- -
- -
p1- RETURN(None, primary_context)— file belongs to primary repo -inst-target-return-primary - -
p1-validate --source/--artifactoverride: narrow working context to the matched source adapter for registry and project root, while retaining the originalWorkspaceContextfor workspace-level operations (cross-repo path routing, ID expansion, config validation) -inst-validate-source-flag
-
p1- ID:cpt-cypilot-state-workspace-source-reachability
States: REACHABLE, UNREACHABLE
Initial State: UNREACHABLE (before path resolution)
Transitions:
- -
p1- FROM UNREACHABLE TO REACHABLE WHEN resolved source path exists and is a directory -inst-source-becomes-reachable - -
p1- FROM REACHABLE TO UNREACHABLE WHEN source directory is removed or becomes inaccessible between invocations -inst-source-becomes-unreachable
-
p1- ID:cpt-cypilot-state-workspace-config-lifecycle
States: NO_WORKSPACE, STANDALONE, INLINE
Initial State: NO_WORKSPACE
Transitions:
- -
p1- FROM NO_WORKSPACE TO STANDALONE WHENworkspace-initcreates.cypilot-workspace.toml-inst-config-create-standalone - -
p1- FROM NO_WORKSPACE TO INLINE WHENworkspace-init --inlinewrites[workspace]section tocore.toml-inst-config-create-inline - -
p1- FROM STANDALONE TO STANDALONE WHENworkspace-addupdates existing standalone config -inst-config-update-standalone - -
p1- FROM INLINE TO INLINE WHENworkspace-add --inlineupdates existing inline config -inst-config-update-inline - -
p1- FROM STANDALONE TO STANDALONE WHENworkspace-init --forcereinitializes existing standalone config -inst-config-reinit-standalone - -
p1- FROM INLINE TO INLINE WHENworkspace-init --inline --forcereinitializes existing inline config -inst-config-reinit-inline - -
p1- Config utility methods: resolve_source_adapter, validate, add_source, save -inst-config-methods - -
p1- Implementation: inline config loading utility for workspace operations -inst-config-load-inline-impl
Guards (illegal transitions — always rejected):
- FROM STANDALONE TO INLINE —
workspace-init --inlineorworkspace-add --inlinewhen standalone exists - FROM INLINE TO STANDALONE —
workspace-init(no--inline) when inline exists
-
p1- ID:cpt-cypilot-dod-workspace-init
The system MUST provide a workspace-init command that scans nested sub-directories for repositories (identified by .git or AGENTS.md with @cpt:root-agents marker), infers roles, discovers adapter paths, and generates workspace configuration. Scanning depth MUST be limited by a --max-depth parameter (default 3) to prevent unbounded filesystem traversal and symlink loops; symlinks MUST be skipped during directory iteration. The command MUST support standalone file output (.cypilot-workspace.toml), inline output (--inline into config/core.toml), dry-run preview (--dry-run), and forced reinitialization (--force). The command MUST reject cross-type conflicts (e.g., --inline when standalone exists) and MUST require --force to overwrite an existing same-type workspace config. Config discovery MUST first check core.toml workspace key (string path or inline dict), then fall back to well-known standalone file .cypilot-workspace.toml at the project root — no implicit parent directory traversal.
Implements:
cpt-cypilot-flow-workspace-initcpt-cypilot-algo-workspace-find-configcpt-cypilot-algo-workspace-discover-nestedcpt-cypilot-algo-workspace-infer-role
Covers (PRD):
cpt-cypilot-fr-core-workspace
Covers (DESIGN):
cpt-cypilot-component-config-manager
-
p1- ID:cpt-cypilot-dod-workspace-source-mgmt
The system MUST provide a workspace-add command (with --inline flag for inline mode) to add sources to existing workspace configs. Each source entry MUST include name, path, optional adapter path, and role. workspace-add MUST operate on standalone config by default, and on inline config when --inline is specified. Type mismatches MUST produce errors directing users to the correct flag. If a source with the same name already exists, workspace-add MUST return an error unless --force is specified; with --force, the existing entry is silently replaced. All config writes MUST preserve existing entries and settings.
Implements:
cpt-cypilot-flow-workspace-addcpt-cypilot-algo-workspace-resolve-source
Covers (PRD):
cpt-cypilot-fr-core-workspace
Covers (DESIGN):
cpt-cypilot-component-config-manager
-
p1- ID:cpt-cypilot-dod-workspace-cross-repo
The system MUST upgrade CypilotContext to WorkspaceContext when workspace config is found, loading SourceContext per source with reachability status. resolve_artifact_path MUST return Optional[Path] — None when a source is explicitly set but unreachable, preventing silent fallback. Two traceability settings (cross_repo, resolve_remote_ids) MUST independently control path resolution and remote ID expansion. validate --local-only MUST skip cross-repo resolution. list-ids --source MUST filter by source name.
Implements:
cpt-cypilot-algo-workspace-load-contextcpt-cypilot-algo-workspace-resolve-artifactcpt-cypilot-algo-workspace-collect-ids
Covers (PRD):
cpt-cypilot-fr-core-workspacecpt-cypilot-fr-core-traceability
Covers (DESIGN):
cpt-cypilot-component-traceability-enginecpt-cypilot-principle-traceability-by-designcpt-cypilot-principle-determinism-first
-
p1- ID:cpt-cypilot-dod-workspace-graceful-degradation
The system MUST continue operating when workspace sources are unreachable. Unreachable sources MUST be marked with reachable: false in the source context. Scan failures for individual artifacts MUST emit warnings to stderr rather than terminating. Operations MUST proceed with available sources and produce valid results for the reachable subset.
Implements:
cpt-cypilot-algo-workspace-load-contextcpt-cypilot-algo-workspace-collect-ids
Covers (PRD):
cpt-cypilot-fr-core-workspace
Covers (DESIGN):
cpt-cypilot-principle-zero-harm
-
p1- ID:cpt-cypilot-dod-workspace-backward-compat
The system MUST operate identically for projects without workspace configuration. Context loading MUST return CypilotContext (not WorkspaceContext) when no workspace is found. All existing CLI commands MUST function without modification in single-repo mode. No workspace-related warnings MUST appear for non-workspace projects.
Implements:
cpt-cypilot-algo-workspace-find-configcpt-cypilot-algo-workspace-load-context
Covers (PRD):
cpt-cypilot-fr-core-workspace
Covers (DESIGN):
cpt-cypilot-principle-zero-harmcpt-cypilot-constraint-python-stdlib
-
p1- ID:cpt-cypilot-dod-workspace-git-url-sources
The system MUST support Git URL sources in standalone workspace files (.cypilot-workspace.toml). SourceEntry MUST accept an optional url field for remote Git repositories and an optional branch field for ref pinning. An optional [resolve] section in workspace config MAY define the working directory and namespace resolution rules mapping Git URL host to local directory path templates. Namespace lookup MUST use exact host match. When no matching rule is found (or no [resolve] section exists), the system MUST fall back to the default template {org}/{repo} — producing a/b for github.com/a/b.git and a/b/c/d/e for gitlab.example.com/a/b/c/d/e.git. Source resolution MUST clone repos on first access and return existing local paths without network operations on subsequent accesses — use workspace-sync to update worktrees. Inline workspace definitions in core.toml MUST reject url fields during validation. Git operations MUST use subprocess calling the git CLI directly (stdlib-only constraint).
Implements:
cpt-cypilot-algo-workspace-resolve-git-url
Covers (PRD):
cpt-cypilot-fr-core-workspace-git-sources
Covers (DESIGN):
cpt-cypilot-component-config-managercpt-cypilot-constraint-python-stdlib
-
p1- ID:cpt-cypilot-dod-workspace-cross-repo-editing
The system MUST load a remote source's own adapter context (rules, templates, constraints) when editing files in that source, instead of applying the primary repo's adapter. SourceContext MUST gain an adapter_context field populated lazily on first access. The system MUST determine which source owns a target file by matching file paths against resolved source paths (longest-prefix match) — auto-detection makes an explicit --source flag unnecessary for most operations. Validation commands MAY support an optional --source flag for explicit source targeting when auto-detection is not desired. When a remote source has no Cypilot adapter, the system MUST fall back to the primary repo's adapter for that source. The primary repo's adapter MUST remain active for workspace-level operations and its own files.
Implements:
cpt-cypilot-algo-workspace-resolve-adapter-contextcpt-cypilot-algo-workspace-determine-target
Covers (PRD):
cpt-cypilot-fr-core-workspace-cross-repo-editing
Covers (DESIGN):
cpt-cypilot-component-traceability-enginecpt-cypilot-component-validator
-
p1- ID:cpt-cypilot-dod-workspace-sync
The system MUST provide a workspace-sync command that explicitly fetches and updates worktrees for Git URL sources. The command MUST iterate all Git URL sources (or a single --source if specified) and for each: run git fetch origin [branch], then update the worktree via git checkout -B {branch} origin/{branch} (or git reset --hard FETCH_HEAD for HEAD mode). The command MUST support --dry-run to preview without network operations. Source resolution (resolve_source_path) MUST NOT perform network operations for existing repos — it only clones on first access and returns local paths for subsequent accesses. This separation ensures read operations (validate, list-ids, workspace-info) are fast, deterministic, and work offline.
Implements:
cpt-cypilot-flow-workspace-synccpt-cypilot-algo-workspace-sync-git-source
Covers (PRD):
cpt-cypilot-fr-core-workspace-git-sources
Covers (DESIGN):
cpt-cypilot-component-config-managercpt-cypilot-constraint-python-stdlib
| Module | Path | Responsibility |
|---|---|---|
| Workspace Config | skills/.../utils/workspace.py |
Data types (SourceEntry, TraceabilityConfig, WorkspaceConfig), config loading/saving, path resolution, validation |
| Workspace Context | skills/.../utils/context.py |
SourceContext, WorkspaceContext, context upgrade, artifact path resolution, cross-repo ID collection |
| Workspace Init | skills/.../commands/workspace_init.py |
workspace-init command: nested sub-directory scanning, role inference, config generation |
| Workspace Add | skills/.../commands/workspace_add.py |
workspace-add command (with --inline flag for inline mode) |
| Workspace Info | skills/.../commands/workspace_info.py |
workspace-info command: status display, per-source probe |
| Workspace Sync | skills/.../commands/workspace_sync.py |
workspace-sync command: fetch and update Git URL source worktrees |
| Git Utils | skills/.../utils/git_utils.py |
Git URL parsing, namespace resolution, clone operations, sync operations |
| Artifacts Meta | skills/.../utils/artifacts_meta.py |
Source field support on Artifact dataclass |
-
workspace-initscans nested sub-directories and generates.cypilot-workspace.tomlwith discovered sources -
workspace-init --max-depth Nlimits scanning depth (default 3); symlinks are skipped -
workspace-init --inlinewrites workspace config intoconfig/core.toml[workspace]section -
workspace-init --dry-runshows preview without writing files -
workspace-add --name N --path Padds a source to standalone workspace config -
workspace-add --inline --name N --path Padds a source inline tocore.toml -
workspace-add --name N --path Pwith existing name N returns error without--force -
workspace-add --name N --path P --forcereplaces existing source N - Type mismatch (standalone add on inline config) produces error with correct command hint
-
workspace-infodisplays workspace status with per-source reachability and artifact counts - Workspace config discovery checks
core.tomlworkspacekey first, then falls back to standalone.cypilot-workspace.tomlat project root (no parent directory walk-up) - Source paths resolve relative to workspace file parent (standalone) or project root (inline)
- Context loading upgrades to
WorkspaceContextwhen workspace config is found -
resolve_artifact_pathreturnsNonefor unreachable sources (no silent fallback) - Unreachable sources emit stderr warnings; operations continue with available sources
- Projects without workspace config operate in single-repo mode with zero behavioral changes
- All workspace commands output JSON to stdout and use exit codes 0/1/2
- Standalone workspace config supports Git URL sources with
urlfield onSourceEntry - Workspace config supports
[resolve]section withworkdirand namespace resolution rules - Namespace rules map Git URL host/path to local directory paths (e.g.,
gitlab.com/org/repo.git→org/repo) - Per-source and workspace-level branch/ref configuration supported
- Git URL sources are cloned on first access under the configured working directory; subsequent accesses return local path without network operations
- Inline workspace config (
core.toml) remains local-paths-only — Git URL sources not supported inline - Cross-repo editing applies the remote source's own adapter rules/templates/constraints, not the primary repo's
-
SourceContextresolves per-source adapter context independently for validation and generation -
validate --artifactauto-detects which workspace source owns the artifact viadetermine_target_source()(longest-prefix path match) — no explicit--sourceflag required -
validateusesWorkspaceContext.get_all_artifact_ids()for cross-repo ID expansion instead of inline aggregation -
where-definedandwhere-usedwork transparently in workspace mode viacollect_artifacts_to_scan— no per-command source flags needed -
WorkspaceConfig.resolve_source_adapter()is used by context loading andworkspace-infoto resolve adapter paths centrally -
workspace-syncfetches and updates worktrees for all Git URL sources -
workspace-sync --source Nsyncs only the named source -
workspace-sync --dry-runshows which sources would be synced without network operations -
workspace-syncreports per-source sync results (synced/failed with error details) -
resolve_source_pathdoes not performgit fetchfor existing repos (clone-only on first access)