Needs tutorial

This tutorial builds a small but complete traceability model, step by step, for the engineering programme behind an autonomous parcel-delivery drone. Along the way you will declare your own need types, write need items and connect them with links, refer to them from ordinary prose, and finally summarise and measure the whole set with tables, diagrams, and counts.

Every example below is shown twice — first as the source you would type, then as the result it produces — using the syntax-example directive (see Directives). The need items, roles, tables, and counts in those result panes are live — the ubCode engine resolves and renders them as you edit — and this published site renders every example, diagram views included, with Sphinx-Needs. (Where the two engines differ, the tutorial says so; see the note by the flow diagram below.)

Before you start

You will get the most from this walkthrough with ubCode already installed (Installation) and the vocabulary from Key concepts fresh in mind. A little reStructuredText helps too, though the examples are short enough to follow without it.

How ubCode handles a need

ubCode keeps a live model of your project and refreshes it on every keystroke, rather than computing everything once at the end of a build. Three things happen in the background as you type: it reads each need directive out of your source files and captures the fields you wrote; it connects the needs — matching links to their targets, resolving variant and dynamic values, and filling in back-links; and it checks the result — validating IDs, field values, and link targets against your configuration, and surfacing anything inconsistent as a diagnostic.

Running this loop continuously is what sets ubCode apart from a batch build: a broken link or a duplicate ID appears the instant you introduce it, not after a build. The table and count views you meet later read straight from this live model, so they always reflect the project’s current state.

Defining need types

A need type is a category of need that becomes a directive of the same name. ubCode does not assume a fixed set of types; you declare exactly the ones your project uses in ubproject.toml.

For the drone programme we want three types — a top-level Project, the Requirements it drives, and the Specifications that realise them. Each entry gives the directive name, a human-readable title, and a prefix for automatically generated IDs; the optional style and color keys control how the type appears in flow diagrams:

[[needs.types]]
directive = "dr-project"
title = "Project"
prefix = "P_"
style = "folder"
color = "#E8DAEF"

[[needs.types]]
directive = "dr-req"
title = "Requirement"
prefix = "R_"
color = "#D4EFDF"

[[needs.types]]
directive = "dr-spec"
title = "Specification"
prefix = "S_"
color = "#D6EAF8"

To make IDs predictable across the team, you can also require them explicitly and constrain their shape:

[needs]
id_required = true
id_regex = "^[A-Z]_[A-Z0-9]{4,}$"

With id_required set, ubCode reports any need that is missing an ID, and id_regex rejects IDs that do not match the pattern — both while you type, long before a build.

See also

Need types for every option a need type accepts, and Core options for the ID controls.

Creating a need item

With the types declared, a need is just a directive: its title is the argument, its fields are options, and its description is the body. Here is the programme’s root item:

The project need

.. dr-project:: Autonomous delivery drone
   :id: P_DRONE
   :tags: tutorial
   :status: open

   A rotor-based drone that carries small parcels between local depots
   and customer drop-points without a human pilot,
   planning its own route and holding station in wind.
Project: Autonomous delivery drone P_DRONE
status: open
tags: tutorial
supported by: R_LINK, R_SAFE

A rotor-based drone that carries small parcels between local depots and customer drop-points without a human pilot, planning its own route and holding station in wind.

Every field you add becomes part of the need’s metadata, so you can later filter, sort, and report on it. The tags field, in particular, is a convenient handle for selecting a related group of needs, as we will do below.

Referring to a need

Once a need has an ID, you can point at it from anywhere in your prose with the need role. By default it renders the need’s title and ID as a clickable link; supply an explicit label in angle brackets to show your own wording instead:

The need role

The overall goal is captured by :need:`P_DRONE`.

When the sentence reads better with your own words, label the reference
yourself, as in :need:`the delivery-drone programme <P_DRONE>`.

The overall goal is captured by Autonomous delivery drone (P_DRONE).

When the sentence reads better with your own words, label the reference yourself, as in the delivery-drone programme (P_DRONE).

ubCode resolves these references as you type, and flags the role if the ID does not exist — so a renamed or deleted need never leaves a dangling reference behind.

Linking needs together

Individual needs become a model once you connect them. The built-in links option records a generic relationship, and you can define named link types for relationships that read better in both directions.

For the drone programme we add one custom link type, dr_supports, so that each requirement records the programme objective it exists to serve:

[needs.links.dr_supports]
outgoing = "supports"
incoming = "supported by"
color = "#1A5276"

Now we can write the two requirements, each pointing at the project through the custom link:

Requirements with links

.. dr-req:: Collision-free flight
   :id: R_SAFE
   :tags: tutorial
   :status: open
   :dr_supports: P_DRONE

   The drone must detect and avoid obstacles in its flight path —
   buildings, wires, birds, and other aircraft —
   and hold a safe separation at all times.

.. dr-req:: Reliable telemetry link
   :id: R_LINK
   :tags: tutorial
   :status: open
   :dr_supports: P_DRONE

   The drone must stay in contact with the control centre throughout a
   flight, reporting position and health, and land safely if the link drops.
Requirement: Collision-free flight R_SAFE
status: open
tags: tutorial
supports: P_DRONE
links incoming: S_GEOFEN, S_VISION

The drone must detect and avoid obstacles in its flight path — buildings, wires, birds, and other aircraft — and hold a safe separation at all times.

Because dr_supports has an incoming label of supported by, the project need automatically gains a “supported by” back-link to each requirement — you write the relationship once, from the requirement, and see it from both sides.

Next we add the specifications that realise the safety requirement. Here we use the plain links option rather than a custom type, to show the generic form:

Specifications realising a requirement

.. dr-spec:: Vision-based obstacle detection
   :id: S_VISION
   :tags: tutorial
   :status: in_progress
   :links: R_SAFE

   Forward and downward cameras feed a model that segments obstacles from
   the background and estimates their distance, driving avoidance manoeuvres.

.. dr-spec:: Geofence enforcement
   :id: S_GEOFEN
   :tags: tutorial
   :status: open
   :links: R_SAFE

   The flight controller refuses commands that would take the drone outside
   its approved corridor or above its permitted altitude.
Specification: Vision-based obstacle detection S_VISION
status: in_progress
tags: tutorial
links outgoing: R_SAFE

Forward and downward cameras feed a model that segments obstacles from the background and estimates their distance, driving avoidance manoeuvres.

Specification: Geofence enforcement S_GEOFEN
status: open
tags: tutorial
links outgoing: R_SAFE

The flight controller refuses commands that would take the drone outside its approved corridor or above its permitted altitude.

See also

Link types for the full set of link-type options, and Roles for the other need reference roles.

Conditional content

Sometimes part of a document only applies to a particular build — a specific platform, market, or review stage. The if directive includes its body only when a condition holds, evaluated against the project’s variant data:

A conditional block

.. if:: var.stage == "review"

   .. note::

      This section is only shown while the ``stage`` variant is ``review``.
      Use it for notes that should not reach the published manual.

Note

This section is only shown while the stage variant is review. Use it for notes that should not reach the published manual.

The if directive is not specific to needs — it conditionally includes any block, needs included — which makes it the basis for building several product variants from a single “150 %” source (see Variant builds).

Summarising the model

With a handful of needs in place, we can start to view them as a whole. The Sphinx-Needs summary directives each select a subset of needs with a shared filter syntax and present it in a different form; this tutorial uses a table and a flow diagram.

A needtable lays the selected needs out as a sortable table. Here we select everything tagged tutorial and choose the columns to show:

A needs table

.. needtable::
   :tags: tutorial
   :columns: id, type, title, status
   :sort: id
   :style: table

ID

Type

Title

Status

P_DRONE

dr-project

Autonomous delivery drone

open

R_LINK

dr-req

Reliable telemetry link

open

R_SAFE

dr-req

Collision-free flight

open

S_GEOFEN

dr-spec

Geofence enforcement

open

S_VISION

dr-spec

Vision-based obstacle detection

in_progress

A needflow draws the same needs as a diagram, so the links between them become visible. Starting the flow at the project need and following the links outward gives a top-down picture of the programme:

A needs flow

.. needflow:: Drone programme overview
   :root_id: P_DRONE
   :show_link_names:

Drone programme overview

Note

needflow draws as a Mermaid flowchart in the ubCode preview and ubc build html alike — the same diagram this published Sphinx-Needs site shows (Sphinx renders it with Graphviz; ubCode renders it client-side with Mermaid, so the picture is equivalent rather than pixel-identical). The other needs diagram views — the needpie and needbar charts — still render as self-describing placeholders in ubCode for now. See Differences from a Sphinx build for the full register.

For larger models it is often tidier to tuck a secondary view away behind a disclosure widget, so the page is not dominated by diagrams:

Show the specifications only

A filtered table

.. needtable::
   :types: dr-spec
   :columns: id, title, status
   :sort: id
   :style: table

ID

Title

Status

S_GEOFEN

Geofence enforcement

open

S_VISION

Vision-based obstacle detection

in_progress

Counting and measuring

Beyond listing needs, you often want a single number — how many items are in a given state. The need_count role evaluates a filter expression and renders the size of the matching set inline, which is handy inside a status summary:

Counting needs

- Specifications in total: :need_count:`type == 'dr-spec'`
- Requirements still open: :need_count:`type == 'dr-req' and status == 'open'`
- Specifications in progress: :need_count:`status == 'in_progress'`
  • Specifications in total: 2

  • Requirements still open: 2

  • Specifications in progress: 1

Because the count is recomputed from the live model, the figures track your edits as you make them — add a specification and the total goes up on the next indexing pass.

Where to go next

You have now created a small traceable model — a project, its requirements, the specifications that realise them, and the links, references, tables, diagrams, and counts that tie them together. From here you can grow the model with confidence, because ubCode keeps every link and ID honest as you type.

Todo

Extend this tutorial with a section on importing existing needs from a JSON export, and on tracking progress over time with a metrics view.