Installer Specifications

Target Location

Flow Spec: Repository root detection FLSP_UBFLOW_INST_001
status: draft
tags: ubflow, installer

The installer shall determine the repository root by traversing parent directories from the current working directory until a .git directory is found, using the git rev-parse --show-toplevel command. If no Git repository is found, the installer shall exit with code 1 and the message: "Not inside a Git repository. Aborting.".

Flow Spec: Target folder prompt and validation FLSP_UBFLOW_INST_002
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_002
supported_by: FLSK_UBFLOW_INST_001

The installer shall present a Copier prompt target_docs_path with the default value docs/. The entered path must satisfy all of:

  • resolves to an absolute path inside the repository root

  • the directory exists (os.path.isdir returns True)

On failure, the prompt shall be repeated with an inline error. The resolved absolute path shall be stored as target_abs_path in the Copier context and written to .copier-answers.yml as target_docs_path.

Epic Management

Flow Spec: Epic enumeration from user-story tags FLSP_UBFLOW_INST_003
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_006

The installer template shall define epics via a YAML list in copier.yml under the key epics. Each entry has the fields:

epics:
  - id: "target_location"
    title: "Target Location"
    default: true
  - id: "conflict_detection"
    title: "Conflict Detection"
    default: true

The id value must match the epic tag applied to flow stories in the template’s RST sources.

Flow Spec: Epic selection prompt FLSP_UBFLOW_INST_004
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_006

Copier shall render a multiselect prompt selected_epics that lists all entries from epics (see FLSP_UBFLOW_INST_003). All epics default to selected. The resolved value is a list of epic IDs stored in .copier-answers.yml as selected_epics.

Flow Spec: Epic-filtered template rendering FLSP_UBFLOW_INST_005
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_006

Each RST snippet belonging to an epic shall be wrapped in a Jinja2 conditional in the template source:

{% if "conflict_detection" in selected_epics %}
.. flowstory:: Conflict detection
   :id: FLST_UBFLOW_INST_10
   ...
{% endif %}

Deactivated epics produce no output in the rendered file.

Determinism and Verification

Flow Spec: Deterministic Copier invocation from local source FLSP_UBFLOW_INST_006
status: draft
tags: ubflow, installer

The installer shall invoke Copier against the locally extracted package directory (see FLSP_UBFLOW_INST_026). No remote URLs or --vcs-ref flags are used:

copier copy \
  --trust \
  --data package_name=<name> \
  --data package_version=<version> \
  <extracted_tmp_dir> \
  <target_abs_path>

No prompts shall appear in replay mode. Two invocations with identical package zip contents and .copier-answers.yml shall produce identical output files.

Flow Spec: Installation manifest format FLSP_UBFLOW_INST_007
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_008
supported_by: FLSK_UBFLOW_INST_004

After a successful installation, the installer shall write a manifest file <target_abs_path>/.ubflow-manifest.json with the following schema:

{
  "schema_version": 1,
  "package_source": "families://aspice",
  "package_version": "0.1.0",
  "installed_at": "2026-03-14T10:00:00Z",
  "files": {
    "relative/path/to/file.rst": "sha256:<hex>"
  }
}

package_source is a URI of the form families://<name> identifying the local family. The files map contains every file written during installation, keyed by path relative to target_abs_path, with a SHA-256 hex digest.

Flow Spec: Verify command implementation FLSP_UBFLOW_INST_008
status: draft
tags: ubflow, installer

A ubflow-installer verify <target_abs_path> command shall read .ubflow-manifest.json, recompute SHA-256 for each listed file, and for each mismatch print a line:

FAIL  relative/path/to/file.rst  (expected abc123, got def456)

The command exits with code 0 if all digests match, code 2 otherwise.

Target Folder Layout

Flow Spec: Output confinement and folder structure FLSP_UBFLOW_INST_009
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_005
supported_by: FLSK_UBFLOW_INST_002

The Copier template copier.yml shall set:

_subdirectory: "template"

so that all rendered files are output exclusively inside the install directory. The installer shall always place the family into the fixed subdirectory ubflow/<family_name>/ relative to target_abs_path:

<target_abs_path>/
└── ubflow/
      └── <family_name>/
            ├── .ubflow-answers.yml
            ├── .ubflow-manifest.json
            ├── index.rst
            ├── user_stories.rst
            ├── specs.rst
            ├── instructions.rst
            ├── skills.rst
            └── traceability.rst

No files outside <target_abs_path>/ubflow/<family_name>/ shall be created or modified.

Template and Version Selection

Flow Spec: Package version from ubflow_package.json FLSP_UBFLOW_INST_010
status: draft
tags: ubflow, installer

The installer shall read the package version from the ubflow_package.json file inside the extracted package directory (see FLSP_UBFLOW_INST_024 and FLSP_UBFLOW_INST_026). The value of the package_version field is passed to Copier as a --data argument so that the template can embed the version in generated files:

copier copy --trust \
  --data package_version=<value from ubflow_package.json> \
  <extracted_tmp_dir> <target_abs_path>

No --vcs-ref flag is used. Version pinning is achieved by shipping a specific zip file with the ubCode extension.

Partial Agent Selection

Flow Spec: Per-agent selection prompt in Copier FLSP_UBFLOW_INST_011
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_003
supported_by: FLSK_UBFLOW_INST_005

copier.yml shall define a multiselect prompt selected_agents populated from a YAML list of available agents, each with an id and title. All agents default to selected. The resolved value is stored in .copier-answers.yml.

Template agent subdirectories are rendered only when the agent ID appears in selected_agents:

{% if "sys2" in selected_agents %}
{%- include "agents/sys2/index.rst.jinja" %}
{% endif %}

At least one agent must be selected; Copier validator raises a ValueError("At least one agent must be selected") otherwise.

Prerequisite Check and Auto-Install

Flow Spec: Pre-installation dependency check script FLSP_UBFLOW_INST_012
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_003
supported_by: FLSK_UBFLOW_INST_005

The installer template shall include a Copier task hook tasks/check_prerequisites.py that is executed before rendering. The script checks for the following imports and CLI commands:

Dependency

Check method

Minimum version

Python

sys.version_info

3.11

sphinx-needs

importlib.metadata.version("sphinx-needs")

2.0.0

copier

shutil.which("copier")

9.0.0

java

shutil.which("java")

any (for PlantUML)

The script prints all failures and exits with code 1 if any check fails, preventing Copier from rendering the template.

Flow Spec: Auto-install of Python prerequisites via pip FLSP_UBFLOW_INST_013
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_010

When check_prerequisites.py detects missing Python packages, it shall prompt: "Install missing packages now? [y/N]". On confirmation it shall invoke:

python -m pip install "sphinx-needs>=2.0.0" "copier>=9.0.0"

On decline it shall print the manual install command and exit with code 1. Missing system dependencies (java) are reported but never auto-installed.

Update and Upgrade

Flow Spec: Update invocation from local package source FLSP_UBFLOW_INST_014
status: draft
tags: ubflow, installer

To upgrade an existing installation, the installer shall:

  1. Extract the new package zip to a fresh temporary directory (see FLSP_UBFLOW_INST_026).

  2. Run copier copy with --overwrite and --defaults, pointing to the new temporary directory:

copier copy \
  --trust --overwrite --defaults \
  --data package_version=<new_version> \
  <new_extracted_tmp_dir> \
  <target_abs_path>
  1. Clean up the temporary directory.

Copier performs a three-way merge: base = previous template version, ours = current installed files, theirs = new package. Merge conflicts are surfaced as standard diff conflict markers in the affected files. No --vcs-ref flag is used.

Flow Spec: Pre-upgrade diff summary from local source FLSP_UBFLOW_INST_015
status: draft
tags: ubflow, installer

Before upgrading, the installer shall run Copier in pretend mode against the new extracted temporary directory:

copier copy \
  --trust --pretend --overwrite --defaults \
  --data package_version=<new_version> \
  <new_extracted_tmp_dir> \
  <target_abs_path>

and display the resulting diff. The installer shall require the developer to enter y to proceed or n to abort. Invocation without a TTY (sys.stdin.isatty() == False) shall skip confirmation and proceed.

Conflict Detection

Flow Spec: Sphinx-Needs ID collision detection FLSP_UBFLOW_INST_016
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_004
supported_by: FLSK_UBFLOW_INST_006

The installer task hook tasks/check_conflicts.py shall scan all *.rst files under the repository root for Sphinx-Needs IDs using the regex r'^\s+:id:\s+(\S+)' (multiline). It shall cross-reference detected IDs with all IDs defined in the template’s source RST files and print a conflict table:

CONFLICT  FLST_UBFLOW_INST_01  found in: docs/my_stories.rst:14

The hook exits with code 1 when one or more conflicts exist, blocking the Copier render step.

Flow Spec: File path collision detection and per-file confirmation FLSP_UBFLOW_INST_017
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_012

Before writing files, tasks/check_conflicts.py shall collect all output paths that already exist on disk. For each colliding path it shall print:

EXISTS  docs/aspice/index.rst  — overwrite? [y/N]

Files answered with N are excluded from the Copier render output via a skip_if condition rendered into the template or removed post-generation. If all colliding files are skipped, the installer exits with code 1 and reports incomplete installation.

Rollback and Uninstall

Flow Spec: Uninstall command using manifest FLSP_UBFLOW_INST_018
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_012

A ubflow-installer uninstall <target_abs_path> command shall read .ubflow-manifest.json and delete every file listed under files. After deletion, any empty directories under target_abs_path (excluding target_abs_path itself) shall also be removed. The manifest file and .copier-answers.yml are deleted last. Files modified since installation (digest mismatch) shall be skipped and reported:

SKIPPED  relative/path/file.rst  (modified since install — remove manually)
Flow Spec: Atomic write with auto-rollback on failure FLSP_UBFLOW_INST_019
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_009

The Copier post-generation task tasks/finalize.py shall write all rendered files to a temporary staging directory first, then move them atomically to target_abs_path. If any step fails (e.g. disk full, permission error), the task shall delete the staging directory and all partially copied target files, then exit with code 1 and:

Installation failed. All written files have been removed.
Repository state is unchanged.

Configuration Persistence

Flow Spec: Copier answers file location and schema FLSP_UBFLOW_INST_020
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_009

Copier shall write the answers file to <target_abs_path>/.copier-answers.yml, controlled by the copier.yml key:

_answers_file: ".copier-answers.yml"

The file shall contain at minimum:

package_name: "aspice"
package_version: "0.1.0"
target_docs_path: "docs/"
selected_agents:
  - orchestrator
  - sys2
selected_epics:
  - core
  - sw_change
family_name: "aspice"

No URL or git commit reference is stored. The installed version is recorded via package_version and in .ubflow-manifest.json (see FLSP_UBFLOW_INST_007).

Flow Spec: Answers file used for prompt pre-population FLSP_UBFLOW_INST_021
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_011
supported_by: FLSK_UBFLOW_INST_008

When .copier-answers.yml is present, the installer shall pass --answers-file .copier-answers.yml to Copier. Copier automatically uses stored values as defaults for each prompt. The developer may accept each default with Enter or type a new value.

Post-Install Validation

Flow Spec: ubflow_package.json schema FLSP_UBFLOW_INST_024
status: draft
tags: ubflow, installer

Every ubFlow package directory shall contain a file ubflow_package.json at its root. The file shall conform to the following JSON schema:

{
  "schema_version": 1,
  "package_name": "aspice",
  "package_version": "0.1.0",
  "display_name": "ASPICE Agent Family",
  "description": "...",
  "directories": [
    {
      "id": "orchestrator",
      "title": "Orchestrator",
      "description": "Main orchestrator agent",
      "default": true
    }
  ],
  "epics": [
    {
      "id": "core",
      "title": "Core Workflows",
      "description": "Fundamental process workflows",
      "default": true
    }
  ]
}

The directories array lists selectable Copier sub-directories. Only directories whose id is in selected_agents (passed via --data) are rendered by Copier. The epics array mirrors the epic structure in copier.yml and is the source of truth for epic metadata.

Flow Spec: Family source discovery (directory or zip) FLSP_UBFLOW_INST_025
status: draft
tags: ubflow, installer

The installer shall locate the family source by searching the following locations in order, returning the first that exists:

Priority

Location

Type

1

<repo_root>/families/<name>/

directory

2

<repo_root>/families/<name>.zip

zip archive

3

<ext_dir>/families/<name>/

directory

4

<ext_dir>/families/<name>.zip

zip archive

<ext_dir> is the ubCode VS Code extension directory resolved by globbing ~/.vscode/extensions/useblocks.ubcode-* and selecting the entry with the highest version suffix. An optional --extension-dir CLI argument overrides auto-discovery.

If no match is found in any location, the installer shall exit with code 1 and list all searched paths.

Flow Spec: Family source preparation (directory pass-through or zip extraction) FLSP_UBFLOW_INST_026
status: draft
tags: ubflow, installer

After finding the family source (see FLSP_UBFLOW_INST_025) the installer shall prepare a working directory for Copier:

Directory source: the directory is used directly as the Copier template source. No extraction is performed and no cleanup is needed after Copier exits.

Zip source: the zip file is extracted to a system temporary directory (tempfile.mkdtemp) before invoking Copier. The temporary directory is removed unconditionally — whether Copier succeeds or fails — as soon as Copier exits. No zip or extracted file shall remain on disk afterwards.

The preparation sequence is:

source   = resolve_family(family_name, repo_root, extension_dir)
work_dir, was_extracted = prepare_source(source)
try:
    # read ubflow_package.json from work_dir
    # invoke copier copy work_dir → target_abs_path
finally:
    if was_extracted:
        cleanup_source(work_dir)
Flow Spec: Undefined Sphinx-Needs reference scan FLSP_UBFLOW_INST_022
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_011
supported_by: FLSK_UBFLOW_INST_008

The Copier post-generation task tasks/validate.py shall parse all installed RST files and extract all link option values using the regex r':(?:satisfies|implements|supports|applies|employs|uses|covered_by):\s+(.+)'. Each referenced ID shall be looked up against the ubCode MCP server via find_needs(need_id=<id>) (or scanned locally if the MCP server is unavailable). Missing IDs shall be reported as:

UNDEF  FLSP_UBFLOW_INST_999  referenced in: aspice/specs.rst:42

The task exits with code 1 if undefined references exist.

Flow Spec: Sphinx build as final validation gate FLSP_UBFLOW_INST_023
status: draft
tags: ubflow, installer

After the undefined-reference scan passes, tasks/validate.py shall invoke:

sphinx-build -b html -W --keep-going \
  <docs_root> <docs_root>/_build/html

where <docs_root> is the documentation project root containing conf.py. The -W flag treats all warnings as errors. Exit code 0 indicates a valid installation. Any non-zero exit code causes the task to print the Sphinx output and exit with code 1, marking the installation as incomplete.

ubFlow Agent Stub

Flow Spec: Installer creates the ubFlow agent stub idempotently FLSP_UBFLOW_INST_027
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_015
supported_by: FLSK_UBFLOW_INST_009

During every install or upgrade the installer SHALL write the file .github/agents/ubflow.agent.md into the target repository root.

The file content SHALL be exactly:

---
description: ubFlow — needs-driven agent design for GitHub Copilot
applyTo: '**'
---

Fetch your full instruction and skill set from the ubCode MCP server
before doing anything else:

1. Call `get_schema_for_need_filter` with `agent="ubflow"` to verify
   the ubCode extension is reachable.
2. Call `query_needs` with `type="flowinst"`, `tags=["ubflow"]`, and
   `agent="ubflow"` to load all binding instructions.
3. Call `query_needs` with `type="flowskill"`, `tags=["ubflow"]`, and
   `agent="ubflow"` to load all skills.

If any call returns `{"error": "unknown_agent"}` or fails, stop and
ask the user to install or update the ubCode VS Code extension.

The operation SHALL be idempotent: if the file already exists with identical content, nothing is changed. If it exists with different content it SHALL be overwritten and the change reported to the user.

Flow Spec: Installer creates the companion bootstrap instructions file idempotently FLSP_UBFLOW_INST_028
status: draft
tags: ubflow, installer
implemented_by: FLIN_UBFLOW_INST_016
supported_by: FLSK_UBFLOW_INST_010

During every install or upgrade the installer SHALL write the file .github/instructions/<family_name>.instructions.md in the target repository root.

The file content SHALL be exactly:

---
applyTo: '**'
---
## ubFlow Bootstrap — <family_name> family

When operating as `@<family_name>`:

1. Call `mcp_ubcode_get_schema_for_need_filter` with
   `file_path: ubflow/<family_name>/ubproject.toml`.
2. Call `mcp_ubcode_get_data_for_single_need` with
   `id: <ORCHESTRATOR_AGT_ID>`.
3. Load every need linked via `:applies:` and `:employs:`.
4. Only then respond to the user request.

Do **not** skip these steps. If any MCP call fails, halt and ask
the user to check the ubCode extension.

The <family_name> and <ORCHESTRATOR_AGT_ID> SHALL be derived at install time from ubflow_package.json in the family source.

The operation SHALL be idempotent: if the file already exists with identical content, nothing is changed. If it exists with different content it SHALL be overwritten and the change reported to the user. The file SHALL not be removed during uninstall of the family.