Contributing

This page explains how the ubFlow documentation is structured, what the data model looks like, and how to write high-quality Sphinx-Needs objects.

Documentation Philosophy

Every agent rule in ubFlow must be fully traceable to a documented need. The documentation is the single source of truth — no instruction or skill may exist without a chain of evidence that leads back to a flow story.

The workflow always follows this order:

  1. Write a Flow Story (the why).

  2. Derive one or more Specifications (the what, testable).

  3. Author Instructions and/or Skills that implement the spec (the how).

  4. Only then write or update the .agent.md file.

The Meta-Model

The meta-model uses the prefix flow for all its artifact types to avoid naming collisions with object types used in end-user projects and their documentation — for example, “user story” in a SCRUM-based software development project.

To keep names concise, types are abbreviated: an instruction is written as flowinst, a skill as flowskill, and so on.

Objects and their relationships form a strict hierarchy:

agentfamily                              (FAM_)
  └── agent                              (AGT_)
        ├── flowstory                    (FLST_)   ← agent is realized by flow stories
        │     └── flowspec               (FLSP_)  satisfies FLST_
        │           ├── flowinst         (FLIN_)  implements FLSP_
        │           └── flowskill        (FLSK_) supports FLSP_
        ├── flowinst                     (FLIN_)  applies (direct link)
        ├── flowskill                    (FLSK_)  employs (direct link)
        └── flowtool                     (FLTL_)  uses    (direct link)
        flowchart TD
    FAM["agentfamily (FAM_)"]
    AGT["agent (AGT_)"]
    UST["flowstory (FLST_)"]
    SPEC["flowspec (FLSP_)"]
    INST["flowinst (FLIN_)"]
    SKILL["flowskill (FLSK_)"]
    TOOL["flowtool (FLTL_)"]

    FAM -->|has_agents| AGT
    UST -->|covered_by| AGT
    SPEC -->|satisfies| UST
    INST -->|implements| SPEC
    SKILL -->|supports| SPEC
    AGT -->|applies| INST
    AGT -->|employs| SKILL
    AGT -->|uses| TOOL
    

ID Conventions

IDs follow the pattern <PREFIX>_<NAMESPACE>_<NUMBER>, e.g. FLST_UBFLOW_001.

Type

Prefix

Example

Remarks

Agent Family

FAM_

FAM_ASPICE_001

Exactly one per project; defined in root index.rst

Agent

AGT_ or AGENT_

AGT_ASPICE_001 / AGENT_INSTALLER

AGT_<NS>_NNN for fully-qualified family agents; AGENT_<NAME> for short standalone agent IDs

Flow Story

FLST_

FLST_UBFLOW_035

Sequential, never reuse a retired ID

Specification

FLSP_

FLSP_UBFLOW_001

Sequential per project namespace

Instruction

FLIN_

FLIN_UBFLOW_001

Sequential per project namespace

Skill

FLSK_

FLSK_UBFLOW_001

Sequential per project namespace

Tool

FLTL_

FLTL_UBFLOW_001

Sequential per project namespace

Allowed status values: draft | approved | deprecated. New objects start as draft; set to approved after peer review.

Writing Good Sphinx-Needs Objects

Flow Story (FLST_)

A flow story answers: As a <role>, I want <goal>, so that <benefit>.

Rules:

  • Use one sentence per clause — role, goal, benefit.

  • The title is a short noun phrase (3–6 words), not a full sentence.

  • Do not describe implementation details — keep it goal-oriented.

  • Link covered_by to the responsible agent once it exists.

.. flowstory:: Template and version selection
   :id: FLST_UBFLOW_INST_06
   :status: approved
   :tags: ubflow, installer
   :covered_by: AGENT_INSTALLER

   As an installing developer, I want to select the agent family template
   and its version before installation, so that I can reproduce the same
   installation at any later point.

Specification (FLSP_)

A spec answers: The system / agent SHALL <observable behaviour>.

Rules:

  • Start the body with “The agent shall” or “The installer shall”.

  • Keep it testable — avoid vague terms like “fast” or “easy”.

  • One spec = one verifiable requirement. Split compound specs.

  • Link satisfies to the parent flow story.

.. flowspec:: Present available template versions
   :id: FLSP_UBFLOW_INST_001
   :status: approved
   :satisfies: FLST_UBFLOW_INST_06

   The installer shall present all available template versions retrieved
   from the configured source and require the developer to confirm the
   selected version before proceeding.

Instruction (FLIN_)

An instruction states what the agent shall do — a binding behavioral obligation. It must not describe procedure steps (that belongs in a skill).

Rules:

  • Use imperative mood: “Always confirm …”, “Never proceed without …”.

  • One instruction = one behavioral rule.

  • Link implements to the parent spec.

  • An instruction MAY stand alone without a companion skill.

.. flowinst:: Confirm template version before writing files
   :id: FLIN_UBFLOW_INST_001
   :status: approved
   :implements: FLSP_UBFLOW_INST_001

   Always present the resolved template version to the developer and require
   explicit confirmation before writing any files to the target repository.

Skill (FLSK_)

A skill describes how the agent performs a task — a step-by-step procedure or reference knowledge. Use a skill when the how is non-trivial or reusable across multiple instructions.

Rules:

  • Write numbered steps or clearly structured prose.

  • Link supports to the parent spec.

  • If a non-trivial procedure is implied by an instruction but no skill exists yet, create a draft skill with a TODO body immediately.

.. flowskill:: Resolve template version from source
   :id: FLSK_UBFLOW_INST_001
   :status: draft
   :supports: FLSP_UBFLOW_INST_001

   TODO: Describe how to query available template versions from the
   configured source (local path, git tag, registry).

   1. Read the ``source`` field from the installer answers file.
   2. List available versions (git tags or directory names).
   3. Sort versions semantically (newest first).
   4. Return the list to the calling instruction for display.

Tool (FLTL_)

A tool represents an external capability the agent can invoke — an MCP server, CLI command, or API.

Rules:

  • Title = the canonical tool name.

  • Body describes purpose, invocation method, and any known constraints.

  • Link agents to tools via :uses:.

.. flowtool:: ubCode MCP Server
   :id: FLTL_UBFLOW_001
   :status: approved
   :tags: mcp, ubcode

   The ubCode MCP server provides read access to the indexed Sphinx-Needs
   project. Agents invoke it to retrieve instructions, skills, and need
   relationships at runtime without reading RST files directly.

Agent (AGT_)

An agent node declares the identity and purpose of a Copilot agent.

Rules:

  • The body is a concise capability statement (2–4 sentences).

  • Link applies to every instruction the agent is bound by.

  • Link employs to every skill the agent consults.

  • Link uses to every tool the agent invokes.

.. agent:: Installer Agent
   :id: AGENT_INSTALLER
   :status: draft
   :tags: ubflow, installer
   :applies: FLIN_UBFLOW_INST_001
   :employs: FLSK_UBFLOW_INST_001
   :uses: FLTL_UBFLOW_001

   The Installer Agent guides developers through the interactive setup of
   an ubFlow agent family inside their repository. It validates prerequisites,
   resolves conflicts, and writes a deterministic, reproducible installation.

File and Folder Layout

Each agent family lives in its own top-level directory (e.g. aspice/). Inside it, every agent gets its own subdirectory:

<family>/
├── ubproject.toml        ← sphinx-needs config for this family project
├── conf.py
├── index.rst             ← FAM_ need
└── <agent>/
      ├── index.rst       ← AGT_ need
      ├── user_stories.rst
      ├── specs.rst
      ├── instructions.rst
      ├── skills.rst
      └── traceability/
            ├── index.rst
            └── overview.rst

The docs/ directory describes ubFlow itself and follows the same layout.

Creating and Maintaining a Family Package

A family package lives under families/<name>/ and is the unit that ubflow-installer copies into a target repository. The aspice family (families/aspice/) is the reference example.

Directory layout

families/<name>/
├── conf.py              ← Sphinx project root (documentation only)
├── index.rst            ← FAM_ need; documents the family for developers;
│                           links into family/ via toctree
├── ubproject.toml       ← Sphinx-Needs schema + ubCode server config
├── copier.yml           ← Copier manifest (_subdirectory: "family")
└── family/              ← installable content — everything in here is
      ├── index.rst        copied into the target repository by copier
      └── agents/
            └── <agent>/
                  ├── index.rst
                  ├── user_stories.rst
                  ├── specs.rst
                  ├── instructions.rst
                  ├── skills.rst
                  └── traceability/

The split between root and family/ is deliberate:

  • Root items (conf.py, ubproject.toml, index.rst) are the developer-facing Sphinx project for the family author. They are never copied to the user’s repository.

  • ``family/`` contains only the RST files the end user receives. copier.yml points exclusively to this subdirectory via _subdirectory: "family".

Step-by-step: adding a new family

  1. Create the directory families/<name>/.

  2. Add the Sphinx project files at the root:

    • conf.py — standard Sphinx config; add sphinx_needs to extensions; exclude copier.yml from exclude_patterns.

    • ubproject.toml — copy from families/aspice/ubproject.toml and update [project] section (name, description). The need schema (link types, need types, statuses) is intentionally shared and should remain compatible with the ubFlow meta-model.

    • index.rst — define the agentfamily need (FAM_<NS>_001), optionally list agents via :has_agents:, and add a toctree that points into family/index.

  3. Create ``copier.yml`` at the root with at minimum:

    _subdirectory: "family"
    _answers_file: ".ubflow-answers.yml"
    
    package_name:
      type: str
      default: "<name>"
    
    package_version:
      type: str
      default: "0.1.0"
    
  4. Add ``ubflow_package.json`` at the root. This file is read by the installer CLI before invoking Copier:

    {
      "schema_version": 1,
      "package_name": "<name>",
      "package_version": "0.1.0",
      "display_name": "My Agent Family",
      "description": "One-sentence description.",
      "directories": [],
      "epics": []
    }
    
  5. Populate ``family/`` with the RST content to be installed:

    • family/index.rst — top-level entry; must include a toctree that references each agent subdirectory.

    • family/agents/<agent>/ — one directory per agent, containing index.rst, user_stories.rst, specs.rst, instructions.rst, skills.rst, and traceability/.

  6. Build the family documentation to verify zero warnings:

    sphinx-build -b html -W families/<name> families/<name>/_build/html
    
  7. Test the installation locally without committing:

    make test-install          # scaffolds tests/temp/host_project/
    ubflow-installer install <name> tests/temp/host_project --repo-root .
    ubflow-installer verify tests/temp/host_project
    make clean_tests           # removes tests/temp/
    

Maintaining an existing family

  • Increment package_version in both ubflow_package.json and copier.yml after every change to family/ content, so installed projects can detect that an update is available.

  • Never rename or remove a Sphinx-Needs ID that has already been released — retire it by setting :status: deprecated instead.

  • Run make test-install after any content change to confirm the installation flow still works end-to-end.

Build and Validation

make venv        # create / update shared .venv
make html        # build docs/
make aspice      # build aspice/
make all-html    # build both projects

After every change to any .rst file, the build must succeed with zero errors and zero warnings before the change is considered complete.

Testing a Family Installation Locally

Before committing changes to a family package, verify the full installation flow in an isolated scratch project under tests/temp/.

Step 1 — Scaffold the test host project

make test-install

This runs tests/run_install_test.sh, which:

  1. Deletes any existing tests/temp/host_project/ directory.

  2. Copies tests/templates/host_project/ (a minimal Sphinx project with conf.py, index.rst, and ubproject.toml) into tests/temp/host_project/.

The resulting directory is git-ignored and can be wiped at any time.

Step 2 — Install the family

Using the CLI directly:

ubflow-installer install aspice tests/temp/host_project --repo-root .

Or via the Installer Agent in Copilot Chat:

@installer install aspice family in tests/temp/host_project

Both options run the same sequence: locate the family source under families/aspice/, check prerequisites, scan for conflicts, invoke Copier, write the manifest, and run post-install validation.

Step 3 — Verify the installation

ubflow-installer verify tests/temp/host_project

The verify command re-computes SHA-256 digests for every file listed in .ubflow-manifest.json and reports any mismatch. Exit code 0 means the installation is intact.

Step 4 — Clean up

make test-clean

This removes tests/temp/ entirely. Run make test-install again whenever you need a fresh scaffold.

Summary of available make targets

Target

Description

make test-install

Scaffold tests/temp/host_project/ from the test template

make test-clean

Remove tests/temp/ entirely

make test-installer

Run the installer unit-test suite (tools/installer/tests/)

make test

Alias for make test-installer

Mermaid Integration

Mermaid diagrams can be embedded directly in Sphinx documentation using the .. mermaid:: directive.

Marp does not natively support Mermaid diagrams, so you must export them as SVG or PNG files for inclusion.

To do this:

  1. Save your Mermaid code in /docs/_mermaid/MY_FILE.mmd.

  2. Reference the file in Sphinx docs with .. mermaid:: /_mermaid/MY_FILE.mmd.

  3. Export to SVG using npx @mermaid-js/mermaid-cli -i input.mmd -o output.svg -c config.json. Adjust file paths as needed.

  4. Include the exported SVG in Marp presentations with ![](../docs/_mermaid/MY_FILE.svg).

The config.json file defines color rules for the black Useblocks theme used in Marp presentations. If omitted, the default background is white and colors are optimized for light themes.

Hint

There is a known issue with background styling: the background remains white regardless of theme settings. Colors are currently optimized for readability on a white background.