Key Concepts¶
This page introduces the core ideas behind ubCode and Sphinx-Needs so you can start working without switching between multiple documentation sites. Each section links to the full reference for deeper exploration.
What are “needs”?¶
A need is a structured, traceable item inside your documentation. Think of it as a requirement, specification, test case, user story, or any other artefact you want to track — but written in plain text alongside your docs.
Every need has at least:
A unique ID (e.g.
REQ_001) — used to reference it from other needs or from code.A title — a short, human-readable summary.
A type — which kind of artefact it represents (see Need types below).
Needs can also carry fields — metadata such as a status, tags, links to other needs, and custom attributes that you define (see Fields below).
Here is a minimal need written in reStructuredText:
.. req:: User must log in before accessing the dashboard
:id: REQ_001
:status: open
:tags: security
The system shall redirect unauthenticated users
to the login page.
In this example req is the directive (determined by the need type),
REQ_001 is the ID,
and status and tags are built-in metadata fields.
See also
Sphinx-Needs documentation for the full feature set of needs.
Need types¶
A need type defines a category of need and gives it its own RST directive. For example, you might define types like requirement, specification, test case, and user story — each with a different directive name, ID prefix, and diagram color.
Types are declared in ubproject.toml:
[[needs.types]]
directive = "req" # use as ``.. req::`` in RST
title = "Requirement"
prefix = "REQ_" # auto-generated IDs start with REQ_
[[needs.types]]
directive = "spec"
title = "Specification"
prefix = "SPEC_"
[[needs.types]]
directive = "test"
title = "Test Case"
prefix = "TC_"
When you write .. req:: in an RST file,
ubCode knows this is a Requirement need because of the type definition.
See Needs for all type options.
Link types¶
Links connect needs to one another and express relationships such as implements, tests, depends on, or is blocked by. Each link has an outgoing label and an incoming label, making the relationship readable from both sides.
Define link types in ubproject.toml using [needs.links]:
[needs.links.implements]
outgoing = "implements"
incoming = "implemented by"
[needs.links.tests]
outgoing = "tests"
incoming = "tested by"
Then use the link name as an option on a need to create the relationship:
.. spec:: Dashboard authentication check
:id: SPEC_010
:implements: REQ_001
.. test:: Verify redirect for unauthenticated user
:id: TC_042
:tests: SPEC_010
ubCode resolves these links in real time, warns about broken references, and visualises the traceability graph in the needs graph view.
Conditional links¶
A link value can include a condition — a filter expression in square brackets that makes the link active only when the target need satisfies the expression.
.. spec:: Dashboard auth check
:id: SPEC_010
:implements: REQ_001[status=="open"]
Here SPEC_010 implements REQ_001 only while REQ_001
has status equal to "open".
If the condition is not met,
ubCode reports a diagnostic so you can review the relationship.
Fields¶
Every need carries fields — named pieces of metadata
such as status, tags, or any custom attribute you define.
Some fields are built in (id, title, status, tags);
you can add your own through the [needs.fields] configuration.
Custom fields¶
Define project-specific fields in ubproject.toml
using [needs.fields].
Each key is the field name and the value describes
its default, description, and optional validation schema:
[needs.fields.priority]
description = "Priority level"
default = "medium"
[needs.fields.assignee]
description = "Assigned team member"
[needs.fields.effort]
description = "Story points"
schema = {type = "integer", minimum = 1, maximum = 13}
Once declared, these fields can be used on any need:
.. req:: Encrypt data at rest
:id: REQ_002
:status: open
:priority: high
:assignee: alice
:effort: 5
Schemas¶
The schema key on a field applies
JSON Schema validation
to every value entered for that field.
Invalid data is caught at index time,
before the docs are built.
Per-field schemas are set inside [needs.fields.<name>]:
[needs.fields.effort]
description = "Story points"
schema = {type = "integer", minimum = 1, maximum = 13}
[needs.fields.severity]
description = "Issue severity"
schema = {type = "string", enum = ["low", "medium", "high", "critical"]}
If a need sets :effort: 99,
ubCode reports a validation error because
99 exceeds the maximum of 13.
For project-wide validation —
for example constraining which types may link to which,
or requiring certain fields per type —
point schema_definitions_from_json to a JSON Schema file:
[needs]
schema_definitions_from_json = "schemas.json"
ubCode loads the definitions and validates every need against them as part of its indexing pipeline.
See Schema validation for the full schema reference.
Variants¶
Variants let a field or link value change depending on the
current build context.
You write a <<…>> expression inside a field value,
and ubCode evaluates it at index time to pick the right result.
This is useful when a single set of docs must produce different outputs — for example one build for customer A and another for customer B, each with different priorities or statuses.
Named variants are defined in ubproject.toml
together with build_tags that describe the current build:
build_tags = ["html", "draft"]
[needs.variants]
is_html = "'html' in build_tags"
is_open = "status == 'open'"
Then use the variant name in a field value:
.. req:: Encrypt data at rest
:id: REQ_002
:status: <<is_open: active, inactive>>
:priority: <<is_html: web_critical, medium>>
The first matching expression’s value is used; the last comma-separated value is the fallback when nothing matches.
You can also write inline filter expressions without pre-defining a variant:
.. req:: Another requirement
:id: REQ_003
:status: <<[status == 'open']: active, inactive>>
See Variants for
the full variant and build_tags reference.
What is reStructuredText?¶
reStructuredText (RST) is a lightweight markup language used by Sphinx to write documentation. If you have used Markdown, RST will feel similar — but it adds directives and roles for richer, structured content.
Directives¶
A directive is a block-level construct that starts with ..,
followed by the directive name and :::
.. note::
This is a simple built-in directive.
Sphinx-Needs adds its own directives —
every need type you define becomes a directive (.. req::, .. spec::, etc.).
Roles¶
A role is an inline construct written as :rolename:`text`.
For example, Sphinx-Needs provides the :need: role
to create a clickable reference to a need:
See :need:`REQ_001` for the authentication requirement.
ubCode understands a large set of Sphinx and Sphinx-Needs directives and roles out of the box. If your project uses additional directives from other extensions, you can register them in the configuration.
What is ubproject.toml?¶
ubproject.toml is the configuration file that tells ubCode
about your project — which need types exist, what link types to use,
where your source files are, and how linting should behave.
It uses the TOML format, which is declarative and human-readable.
Why TOML instead of ``conf.py``?
Sphinx projects are normally configured through a Python file (conf.py).
ubCode cannot execute Python —
that would be slow, insecure, and would require matching
the user’s exact Python environment.
A TOML file can be parsed in microseconds
and gives ubCode everything it needs
to index your project at language-server speed.
Starting from Sphinx-Needs 4.1 you can share configuration
between conf.py and ubproject.toml
via the needs_from_toml option,
so you do not need to maintain two copies.
A minimal ubproject.toml looks like this:
"$schema" = "https://ubcode.useblocks.com/ubproject.schema.json"
[[needs.types]]
directive = "req"
title = "Requirement"
prefix = "REQ_"
See Needs for the full reference, or Coming from Sphinx-Needs for migration guidance.
Source code tracing¶
Note
Supported in ubcode added in v0.29
ubCode can go beyond RST documentation and trace into your source code. Powered by Codelinks, you embed traceability markers directly in code comments, and ubCode’s Rust engine picks them up in real time.
This lets requirements live right next to the code that implements them.
One-line need definitions¶
Create a complete need in a single comment line using a comma-separated format:
# @Function Bar, IMPL_4, impl, [SPEC_1]
This creates an impl need with:
Title:
Function BarID:
IMPL_4Type:
implLinks:
SPEC_1
The field order and separators are configurable in ubproject.toml
under [codelinks.projects.<name>.analyse.oneline_comment_style].
Need ID references¶
Reference existing needs without creating new ones. This records that a particular code location is related to specific needs:
# @need-ids: REQ_001, REQ_002
The marker keyword (@need-ids by default)
is configurable in [codelinks.projects.<name>.analyse.need_id_refs].
The src-trace directive¶
The .. src-trace:: directive brings source-traced needs
into your documentation:
.. src-trace:: my_app
:directory: src/core
This tells ubCode to include all needs discovered in the src/core directory
of the codelinks project named my_app.
You can also use :file: to scope to a single file.
Configure the codelinks pipeline
in the [codelinks] section of your ubproject.toml.
See also
Codelinks documentation for the full reference on source code tracing.
Where to go next¶
Installation — install the VS Code extension or the
ubcCLI.Quickstart — create your first project and see ubCode in action.
Needs — set up need types, links, and other project settings.
Coming from Sphinx-Needs — migrate an existing Sphinx-Needs project.
Sphinx-Needs documentation — the full reference for needs, directives, and filters.
Codelinks documentation — the full reference for source code tracing markers and configuration.