Configuring a project with ubproject.toml

The ubproject.toml file is a TOML configuration file that tells ubCode how to analyse and validate your project. Every setting — need types, link types, custom fields, linting rules, formatting preferences — lives in this single declarative file.

You can find the schema at https://ubcode.useblocks.com/ubproject.schema.json, and it is recommended that you add this to the top of your file for use with the taplo toolkit:

"$schema" = "https://ubcode.useblocks.com/ubproject.schema.json"

Please also see the detailed ubproject.toml schema reference.

For a complete example, see the Sphinx-Needs Demo project.

Configuration sections

The ubproject.toml file is organized into logical sections. Each section controls different aspects of ubCode’s behaviour:

  • Needs — need types, link types, custom fields, statuses, tags, external needs, variants, dynamic functions, filter_data, and import_keys

  • Schema validation — schema validation with schemas.json, local and network validation rules

  • Deprecated needs options — deprecated options retained for backward compatibility with older sphinx-needs versions

  • Parsing — custom directives, roles, and ignore lists

  • Linting — ignore codes, per-file-ignores, and message-ignores

  • Formatting — reStructuredText formatting options

  • Server — language server behaviour and performance settings

  • Project, source & scripts — project metadata, source file discovery, scripts, and needs_json

Each section includes sensible defaults, so you only need to specify the options you want to customise.

Configuration file discovery

Hierarchical configuration is supported, such that the “closest” config file in the directory hierarchy is used for every individual file, with all paths in the config file being resolved relative to the directory containing that config file.

For example, given the following directory structure:

project/
├── docs1/
│   ├── doc1.rst
│   └── ubproject.toml
├── docs2/
│   └── doc2.rst
└── ubproject.toml

The configuration for doc1.rst will be read from project/docs1/ubproject.toml, whereas for doc2.rst it will be read from project/ubproject.toml.

See also the source configuration for how file-discovery works for reStructuredText source files.

Configuration redirect with ubproject.redirect.toml

When processing files that are “outside” the documentation project folder (e.g. source code files referenced via the code links feature), the normal directory walk may fail because no ubproject.toml exists in any ancestor directory.

To handle this, you can place a redirect file called ubproject.redirect.toml in a directory. When found during the configuration file search, it tells ubCode to continue looking for ubproject.toml from a different location.

The redirect file has a minimal TOML schema:

path = "../docs"

The path value is resolved relative to the directory containing the redirect file. It can point to either:

  • A directory — the search continues from that directory, looking for ubproject.toml there.

  • A file — the file is used directly as the ubproject.toml.

For example, given the following directory structure:

project/
├── docs/
│   ├── doc1.rst
│   └── ubproject.toml
└── src/
    ├── main.py
    └── ubproject.redirect.toml   # contains: path = "../docs"

When processing main.py, the search finds ubproject.redirect.toml in src/, follows the redirect to docs/, and uses the ubproject.toml there.

Note

If a ubproject.toml file exists in the same directory as a redirect file, the ubproject.toml takes precedence and the redirect is ignored.

Circular redirects (two redirect files pointing at each other) are detected and treated as if no configuration was found.

Sharing configuration

To share configuration between multiple projects, you can use the extend option to reference another ubproject.toml file.

# Extend the `ubproject.toml` file in the parent directory...
extend = "../ubproject.toml"

[needs]
# ...but use a different ID regex.
id_regex = "^[a-zA-Z0-9_]{5,}"

Top-level options

The configuration file supports several top-level options that control the overall behaviour:

# Extend another configuration file
extend = "path/to/ubproject.toml"
# Virtual configurations do not correspond to an actual project.
# They are used for providing shared configuration defaults.
virtual = true
# Tags describing the current build target (e.g. builder, environment)
build_tags = ["html"]
extend

Type: string (optional)

The path to another ubproject.toml file to extend. This allows you to create a hierarchy of configuration files where child configurations can inherit settings from parent configurations. Paths are resolved relative to the current configuration file.

# Extend the configuration from the parent directory
extend = "../ubproject.toml"

# Or extend from a specific shared configuration
extend = "~/.config/ubcode/base.toml"
virtual

Type: boolean (default: false)

When set to true, this configuration is marked as virtual and does not correspond to an actual project. Virtual configurations are used for providing shared configuration defaults or for workspaces that are not themselves projects. This is particularly useful when creating base configurations that will be extended by other projects.

# In a shared base configuration file
virtual = true

[needs]
id_required = true
id_regex = "^[A-Z0-9_]{5,}"
build_tags

Type: array of strings (default: [])

A list of tags describing the current build target or environment. This replicates Sphinx’s tags configuration, making the same set of tags available as the build_tags variable inside variant filter expressions (see Variants), enabling build-target-conditional field values.

For example, you can use build_tags to vary need fields depending on the output format or deployment stage:

build_tags = ["html", "draft"]

[needs.variants]
is_html = "'html' in build_tags"

Tags can also be overridden from the CLI without modifying ubproject.toml:

ubc build index -c "build_tags = ['html', 'production']"

Complete configuration examples

This section provides complete, real-world configuration examples for different types of projects.

Basic documentation project

A minimal configuration for a simple documentation project:

"$schema" = "https://ubcode.useblocks.com/ubproject.schema.json"

[project]
name = "My Documentation"
version = "1.0.0"
description = "User documentation for our product"

[needs]
id_required = true
id_regex = "^[A-Z]{3}_[0-9]{3}$"  # Format: ABC_123

[[needs.types]]
directive = "requirement"
title = "Requirement"
prefix = "REQ_"
color = "#BFD8D2"

Software development project

Configuration for a software project with comprehensive need tracking:

"$schema" = "https://ubcode.useblocks.com/ubproject.schema.json"

[project]
name = "MyApp"
version = "2.1.0"
description = "Mobile application requirements"
srcdir = "docs"

[needs]
id_required = true
id_regex = "^[A-Z0-9_]{5,}$"
id_length = 8

# Define comprehensive need types
[[needs.types]]
directive = "epic"
title = "Epic"
prefix = "EPIC_"
color = "#FF6B6B"

[[needs.types]]
directive = "story"
title = "User Story"
prefix = "STORY_"
color = "#4ECDC4"

[[needs.types]]
directive = "task"
title = "Task"
prefix = "TASK_"
color = "#45B7D1"

[[needs.types]]
directive = "bug"
title = "Bug"
prefix = "BUG_"
color = "#F39C12"

# Define relationships (dict-based, sphinx-needs v7+)
[needs.links.implements]
incoming = "implemented by"
outgoing = "implements"
color = "#2ECC71"

[needs.links.blocks]
incoming = "blocked by"
outgoing = "blocks"
color = "#E74C3C"

# Constrain status values via field schema (sphinx-needs v7+)
[needs.fields.status]
schema = {enum = ["draft", "review", "approved", "done"]}
default = "draft"
predicates = [
    ["type == 'bug'", "review"],
    ["priority == 'critical'", "review"]
]

# Custom fields (dict-based, sphinx-needs v7+)
[needs.fields.priority]
description = "Priority level"
default = "medium"

[needs.fields.effort]
description = "Story points"
schema = {type = "integer", minimum = 1, maximum = 13}

[needs.fields.assignee]
description = "Assigned team member"

Multi-team enterprise configuration

Configuration for large organisations with multiple teams and external dependencies:

"$schema" = "https://ubcode.useblocks.com/ubproject.schema.json"
extend = "../shared/base-config.toml"

[project]
name = "Platform API"
version = "3.2.0"
description = "Core platform API requirements"

[needs]
# Import from other team's exports
[needs.import_keys]
backend = "../backend-team/needs.json"
frontend = "../frontend-team/needs.json"

# Load external needs from other projects
[[needs.external_needs]]
json_path = "../security-team/security-requirements.json"
id_prefix = "SEC"
base_url = "https://security-docs.company.com"
target_url = "requirements/{{ id }}.html"

[[needs.external_needs]]
json_url = "https://compliance.company.com/api/needs.json"
id_prefix = "COMP"
base_url = "https://compliance.company.com"
css_class = "compliance-need"

# Relationships (dict-based, sphinx-needs v7+)
[needs.links.validates]
incoming = "validated by"
outgoing = "validates"
color = "#9B59B6"

[needs.links.derives_from]
incoming = "parent of"
outgoing = "derives from"
color = "#34495E"

# Rich metadata with schema validation
[needs.fields.component]
description = "System component"
parse_variants = true

[needs.fields.risk_level]
description = "Security risk assessment"
default = "low"
predicates = [
    ["compliance_level == 'strict'", "medium"],
    ["environment == 'production'", "high"]
]

[needs.fields.environment]
parse_variants = true

[needs.fields.test_coverage]
description = "Test coverage percentage"

# Additional context for conditional defaults
filter_data = {environment = "production", compliance_level = "strict"}

[format_rst]
# Enforce consistent formatting
paragraph_line_length = 88
paragraph_semantic_wrap = true
validate = true
fail_on_warning = ["rst.malformed_table"]

[lint]
# Project-specific linting rules
ignore = ["needs.id_not_found"]  # Allow forward references
lsp_select = ["needs.title_missing", "rst.malformed_table"]

[server]
# Optimize for large project
index_on_save = false
hover_need_refs = true

[source]
# Multi-format support
extend_include = ["*.md"]
extend_exclude = ["archive/**", "drafts/**"]

[scripts]
# Team workflows
validate = "ubc lint --fail-on-error"
export = "ubc build needs-json --output needs.json"
"docs:build" = { chain = ["validate", "export"], terminal = "docs-build" }

Sphinx integration example

Configuration optimised for Sphinx documentation projects:

"$schema" = "https://ubcode.useblocks.com/ubproject.schema.json"

[project]
name = "API Documentation"
srcdir = "source"

[needs]
# Integrate with Sphinx-Needs
external_needs = []

[[needs.types]]
directive = "requirement"
title = "Requirement"
prefix = "R_"
color = "#BFD8D2"

[[needs.types]]
directive = "specification"
title = "Specification"
prefix = "S_"
color = "#FEDCD2"

# Link to API documentation
[needs.links.api]
incoming = "documented by"
outgoing = "documents API"

[parse]
# Sphinx directive support
[parse.extend_directives.automodule]
argument = true
options = true
description = "Auto-document Python module"
extension = "sphinx.ext.autodoc"

[parse.extend_directives.automodule.named_options]
members = {description = "Include module members"}
undoc-members = {description = "Include undocumented members"}

[parse.extend_roles.py-func]
description = "Reference to Python function"
extension = "sphinx.domains.python"

[format_rst]
# Sphinx-friendly formatting
paragraph_line_length = 79  # PEP 8 line length
directive_indent = 3
field_list_indent = 2

[scripts]
# Sphinx build commands
html = "sphinx-build -b html {{confdir}} {{confdir}}/_build/html"
linkcheck = "sphinx-build -b linkcheck {{confdir}} {{confdir}}/_build/linkcheck"
"docs:live" = { cmd = "sphinx-autobuild {{confdir}} {{confdir}}/_build/html --host 0.0.0.0", terminal = "docs-server" }