Codelinks (source code tracing)¶
Added in version 0.29.0.
The [codelinks] section configures source code tracing —
scanning your source files for traceability markers
and converting them into needs.
Use this when you want to create or link needs
directly from code comments,
without writing reStructuredText by hand.
See also
- Codelinks documentation
The full Sphinx-Codelinks documentation, covering the Sphinx extension, CLI, and marker formats in depth.
Minimal example¶
[codelinks]
set_remote_url = true
[codelinks.projects.my_app]
remote_url_pattern = "https://github.com/org/repo/blob/{commit}/{path}#L{line}"
[codelinks.projects.my_app.source_discover]
src_dir = "../src"
comment_type = "python"
[codelinks.projects.my_app.analyse]
get_oneline_needs = true
This tells ubCode to scan the ../src directory for Python files,
extract one-line need markers from comments,
and generate remote URLs pointing to GitHub.
In your reStructuredText files you then include the traced needs
with the .. src-trace:: directive:
.. src-trace::
:project: my_app
Global options¶
These options sit directly under [codelinks]
and apply to every project defined within it.
- set_local_url
Type:
boolean(default:false)When
true, ubCode computes afile://URL pointing to the local source file for every traced need. The URL is stored in the field named bylocal_url_field.[codelinks] set_local_url = true
- local_url_field
Type:
string(default:"local-url")Name of the need field that receives the local file URL. The field is auto-registered in
[needs.fields]whenset_local_urlis enabled; if it already exists with a non-string type, a diagnostic is emitted.[codelinks] local_url_field = "local-url"
- set_remote_url
Type:
boolean(default:false)When
true, ubCode computes a remote URL (e.g. GitHub, GitLab, Bitbucket) for every traced need using theremote_url_patterndefined on each project. The URL is stored in the field named byremote_url_field.[codelinks] set_remote_url = true
- remote_url_field
Type:
string(default:"remote-url")Name of the need field that receives the remote URL. The field is auto-registered in
[needs.fields]whenset_remote_urlis enabled; if it already exists with a non-string type, a diagnostic is emitted.[codelinks] remote_url_field = "remote-url"
- outdir
Type:
stringornull(default:null)Optional output directory for generated artifacts such as extracted markers and warnings (standalone use only). Most users do not need to set this.
[codelinks] outdir = "output"
Project-specific options¶
Each source code project is defined under
[codelinks.projects.<name>], where <name> is a unique identifier
you choose (e.g. my_app, backend).
You can define multiple projects when your repository
contains several codebases with different languages or configurations.
[codelinks.projects.my_app]
# options for "my_app"
[codelinks.projects.backend]
# options for "backend"
remote_url_pattern¶
Type: string or null (default: null)
URL pattern used to generate links to a remote source code repository. The pattern uses placeholders that ubCode replaces with the actual values at analysis time.
Placeholders:
{commit}— the current Git commit hash{path}— relative path to the source file (from the repository root){line}— 1-based line number of the marker
Common patterns:
GitHub:
https://github.com/user/repo/blob/{commit}/{path}#L{line}GitLab:
https://gitlab.com/user/repo/-/blob/{commit}/{path}#L{line}Bitbucket:
https://bitbucket.org/user/repo/src/{commit}/{path}#lines-{line}
[codelinks.projects.my_app]
remote_url_pattern = "https://github.com/org/repo/blob/{commit}/{path}#L{line}"
ref_url_field¶
Type: string (default: "code_url")
Name of the need field that receives the URL resolved from a
@need-ids: reference marker (see analyse.need_id_refs).
When a source file carries a @need-ids: REQ_X marker,
the marker’s remote URL (or its local URL, when no remote URL is configured)
is written onto the already existing need REQ_X under this field.
This differs from local_url_field / remote_url_field,
which receive the URLs of needs defined in the source code
(one-line markers and .. src-trace:: blocks);
ref_url_field receives the URL back-attached onto a referenced need.
Point a tests/-scoped project at a different field (e.g. test_url)
to keep links to test code separate from links to implementation code.
[codelinks.projects.my_app]
ref_url_field = "code_url"
[codelinks.projects.my_app_tests]
ref_url_field = "test_url"
source_discover¶
Configures how ubCode discovers source files within this project.
[codelinks.projects.my_app.source_discover]
src_dir = "../src"
include = ["**/*.cpp", "**/*.h"]
exclude = ["build/**"]
gitignore = true
comment_type = "cpp"
- src_dir
Type:
string(default:".")Root directory for source file discovery. Paths are resolved relative to the directory containing the
ubproject.tomlfile.[codelinks.projects.my_app.source_discover] src_dir = "../src"
- include
Type:
array of strings(default:[])Glob patterns for files to include. When non-empty, only files matching at least one pattern are processed. An empty list includes all files (subject to
excludeandgitignorefiltering).Files must match at least one
includepattern to be considered, butexcludepatterns andgitignorerules still apply afterward.[codelinks.projects.my_app.source_discover] include = ["**/*.py"]
- exclude
Type:
array of strings(default:[])Glob patterns for files and directories to exclude from discovery.
[codelinks.projects.my_app.source_discover] exclude = ["build/**", "vendor/**"]
- gitignore
Type:
boolean(default:true)When
true, files matched by.gitignore(and.ignore,.git/info/exclude, and global gitignore) are automatically excluded.[codelinks.projects.my_app.source_discover] gitignore = false
- follow_links
Type:
boolean(default:false)When
true, symbolic links are followed when traversing the source directory tree. By default, symbolic links are not followed.[codelinks.projects.my_app.source_discover] follow_links = true
- comment_type
Type:
stringornull(default:null)The programming language / comment style used in this project’s source files. This determines which file extensions are discovered and how comments are parsed for markers.
This field is required for file discovery. When
null, the discovery step fails with an error; set it to one of the supported values below.Supported values:
Language
Value
Comment syntax
Discovered file extensions
C / C++
"cpp"//(single-line),/* */(multi-line).cpp,.hpp,.h,.cc,.hh,.c++,.h++Python
"python"#(single-line),""" """(docstrings).pyRust
"rust"//(single-line),/* */(multi-line),///and//!(doc comments).rsC#
"csharp"//(single-line),/* */(multi-line),///(XML doc comments).csYAML
"yaml"#(single-line).yaml,.ymlBash / Shell
"bash"#(single-line).sh,.bash,.zsh,.ksh[codelinks.projects.my_app.source_discover] comment_type = "python"
analyse¶
Configures how ubCode analyses source files to extract markers from comments.
[codelinks.projects.my_app.analyse]
get_oneline_needs = true
get_need_id_refs = true
get_rst = false
- get_oneline_needs
Type:
boolean(default:true)Whether to extract one-line needs from comments. A one-line need is a compact marker like:
// @Function Bar, IMPL_4, impl, [SPEC_1]which ubCode converts to a need with title “Function Bar”, ID
IMPL_4, typeimpl, and a link toSPEC_1. The marker format is controlled byoneline_comment_stylebelow.- get_need_id_refs
Type:
boolean(default:true)Whether to extract need-ID reference markers from comments. A need-ID reference links a code location to existing needs without creating new ones:
// @need-ids: REQ_001, REQ_002The marker strings are configured via
need_id_refs.markers.- get_rst
Type:
boolean(default:false)Whether to extract marked RST blocks from comments. A marked RST block lets you embed full reStructuredText inside a source code comment:
// @rst // .. req:: My Requirement // :id: REQ_INLINE // // This requirement lives in source code. // @endrst
The start and end sequences are configured via
marked_rst.- git_root
Type:
stringornull(default:null)Explicit path to the Git repository root. Useful in non-standard layouts (e.g. Bazel builds, monorepo sub-projects) where auto-detection of
.gitwould fail. Whennull, ubCode traverses parent directories automatically. Paths are resolved relative to theubproject.tomlfile.[codelinks.projects.my_app.analyse] git_root = "/path/to/repo"
analyse.oneline_comment_style¶
Defines the format of one-line markers.
Fields are positional: the order in needs_fields
determines which comma-separated value maps to which need field.
[codelinks.projects.my_app.analyse.oneline_comment_style]
start_sequence = "@"
end_sequence = "\n"
field_split_char = ","
needs_fields = [
{ name = "title", type = "str" },
{ name = "id", type = "str" },
{ name = "type", type = "str", default = "impl" },
{ name = "links", type = "list[str]", default = [] },
]
With this configuration, the comment:
// @Function Bar, IMPL_4, impl, [SPEC_1, SPEC_2]
produces a need equivalent to:
.. impl:: Function Bar
:id: IMPL_4
:links: SPEC_1, SPEC_2
- start_sequence
Type:
string(default:"@")Character sequence that begins a one-line marker inside a comment.
- end_sequence
Type:
string(default:"\n")Character sequence that ends a one-line marker. The default (newline) means each marker occupies a single comment line.
- field_split_char
Type:
string(default:",")Character used to split the marker into individual field values.
- needs_fields
Type:
array of objects(at least 1 entry required)Ordered list of field definitions. Each entry describes one positional field in the marker:
- name
Type:
string(required)The need field to populate (e.g.
"title","id","type")."str"-typed fields must exist in[needs.fields], and"list[str]"-typed fields must exist in[needs.links]; missing entries produce a warning diagnostic at startup.- type
Type:
"str"or"list[str]"(default:"str")"str"— a plain string value."list[str]"— a bracketed, comma-separated list (e.g.[SPEC_1, SPEC_2]).
- default
Type:
string,array of strings, ornull(default:null)Default value when the field is omitted from the marker.
nullmeans the field is required.
Important
The
titleandtypefields (or their equivalents) must always be present inneeds_fields, as they are mandatory for every need.
analyse.need_id_refs¶
Configures how need-ID reference markers are recognised.
[codelinks.projects.my_app.analyse.need_id_refs]
markers = ["@need-ids:"]
- markers
Type:
array of strings(at least 1 entry required, default:["@need-ids:"])Marker strings that identify need-ID references in comments. When ubCode encounters a comment containing one of these markers, everything after the marker is parsed as a comma-separated list of need IDs.
// @need-ids: REQ_001, REQ_002
analyse.marked_rst¶
Configures the delimiters for marked RST blocks embedded in comments.
[codelinks.projects.my_app.analyse.marked_rst]
start_sequence = "@rst"
end_sequence = "@endrst"
- start_sequence
Type:
string(default:"@rst")Sequence that begins a marked RST block inside a comment.
- end_sequence
Type:
string(default:"@endrst")Sequence that ends a marked RST block.
analyse.preprocessor¶
Added in version 0.31.0.
By default, C/C++ files are scanned with a tree-sitter parser
that finds markers in every comment —
including comments inside #if / #ifdef branches
that the compiler would never build.
Adding the [codelinks.projects.<name>.analyse.preprocessor] table,
even when it is empty,
switches C/C++ files to a preprocessor-aware libclang engine
that sees the source as a compiler does:
markers in inactive #if / #ifdef branches are excluded,
and only markers in the branches that are actually compiled become needs.
[codelinks.projects.my_app.analyse.preprocessor]
# An empty table is enough — its presence selects the libclang engine.
Only files discovered as C/C++ (comment_type = "cpp") use this engine;
files of every other language continue to use tree-sitter.
- compile_commands
Type:
stringornull(default:null)Path to a
compile_commands.jsoncompilation database, from which each file’s real compiler flags are taken. Whennull, the database is discovered by walking up from each source file’s directory, stopping at the project root. Paths are resolved relative to theubproject.tomlfile.[codelinks.projects.my_app.analyse.preprocessor] compile_commands = "../build/compile_commands.json"
- defines
Type:
array of strings(default:[])Preprocessor defines, each written as
NAMEorNAME=VALUE, applied as-Dflags. These are the fallback used for files that nocompile_commands.jsonentry applies to.[codelinks.projects.my_app.analyse.preprocessor] defines = ["FEATURE_X", "MAX_ITEMS=32"]
- includes
Type:
array of strings(default:[])Include directories, applied as
-Iflags on the same fallback path asdefines. Paths are resolved relative to theubproject.tomlfile.[codelinks.projects.my_app.analyse.preprocessor] includes = ["../include", "../vendor/include"]
- std
Type:
string(default:"c++17")The C/C++ standard used on the fallback parse path (e.g.
"c++17","c++20","c11"); it also decides whether a file is parsed as C or as C++. Files matched by acompile_commands.jsonentry use that entry’s own flags instead, including its own standard.[codelinks.projects.my_app.analyse.preprocessor] std = "c++20"
A worked example — an out-of-source build directory for the flags, plus fallback flags for the headers the build does not compile directly:
[codelinks.projects.my_app.source_discover]
src_dir = "../src"
include = ["**/*.cpp", "**/*.h"]
comment_type = "cpp"
[codelinks.projects.my_app.analyse.preprocessor]
compile_commands = "../build/compile_commands.json"
defines = ["FEATURE_X=1", "NDEBUG"]
includes = ["../include"]
std = "c++17"
How the compilation database is applied:
For every C/C++ file, ubCode looks for a matching entry
in the applicable compile_commands.json
(the explicit compile_commands path, or the one found by walking up):
The file has an entry — it is parsed with that entry’s own flags, and
defines,includesandstdare not used for it.A translation-unit source (
.c,.cpp,.cc,.cxx) with no entry — it is skipped, and no markers are extracted from it. A compilation database lists every source the build compiles, so a source that is missing from it is one the build does not compile, and there is no correct set of flags to parse it with.A header (e.g.
.h,.hpp,.hh,.hxx) with no entry — it is parsed standalone withdefines,includesandstd. Compilation databases never list headers, so this is the normal case for them.
When no database is found at all,
every file is parsed standalone with defines, includes and std.
Warning
Only GCC/Clang-style flags in compile_commands.json are interpreted.
MSVC cl.exe syntax (/D NAME, /I dir, /std:c++17) is not:
such flags are dropped rather than translated,
and because the file does have a database entry
the defines / includes / std fallback does not apply to it either,
so it is parsed with no defines or include paths at all.
For MSVC projects, either generate a Clang-style database
(for example with clang-cl, or a CMake Ninja/Makefile generator),
or drop compile_commands and set defines, includes and std
explicitly.
Providing libclang:
The libclang engine needs a libclang library, version 16 or newer, the first time it parses a C/C++ file. It is located in this order:
LIBCLANG_PATH, if you have set it. This is treated as a deliberate choice: if the library it names cannot be loaded, or is older than version 16, the parse fails with an error rather than falling back.A libclang already installed on the system, provided it is version 16 or newer. An older system library is not used — ubCode falls through to the next step instead.
Otherwise, ubCode downloads the pinned
libclangwheel from PyPI, verifies it against pinned SHA-256 checksums, and caches the extracted library per user so later runs need no network access.
Once step 3 has run on a machine, the cached pinned library is used
in preference to a system libclang on every later run,
because it is the version extraction is verified against.
Set LIBCLANG_PATH if you want a specific library instead.
Note
For an internal mirror or an air-gapped environment,
point the download at a PyPI-compatible index
with UBC_LIBCLANG_INDEX_URL.
If it is unset, ubCode also honours the index variables
you may already have configured for your Python tooling,
in this order:
UV_DEFAULT_INDEX, UV_INDEX_URL, then PIP_INDEX_URL.
The index only decides where the library is fetched from —
what is accepted is fixed by the pinned checksums,
so a mirror serving a different artifact is rejected.
Alternatively, install libclang 16 or newer yourself
and set LIBCLANG_PATH to the directory containing the library.
The .. src-trace:: directive¶
Once you have configured a codelinks project,
include the traced needs in your documentation
using the .. src-trace:: directive:
.. src-trace::
:project: my_app
The directive accepts the following options:
:project:Required. The project name as defined under
[codelinks.projects.<name>].:file:Limit tracing to a single source file (relative to
src_dir)... src-trace:: :project: my_app :file: main.cpp
:directory:Limit tracing to files within a subdirectory (relative to
src_dir)... src-trace:: :project: my_app :directory: core/
When neither :file: nor :directory: is given,
all files under src_dir are included.
Multiple .. src-trace:: directives can appear in the same document
to combine needs from different projects or scopes.
Note
The :file: and :directory: options cannot be used together
on the same directive.
Automatic field registration¶
When set_local_url or set_remote_url is enabled,
ubCode automatically adds the corresponding URL field
(local_url_field / remote_url_field)
to [needs.fields] as a string field.
You do not need to declare it manually.
If the field already exists with a compatible string type, the existing definition is kept unchanged. If it exists with a non-string type, a warning diagnostic is emitted.
Similarly, "str"-typed entries in needs_fields
are cross-validated against [needs.fields],
and "list[str]"-typed entries are cross-validated against [needs.links].
Missing entries produce warning diagnostics at startup
so you can add the field or link type definition before tracing fails.
Complete example¶
"$schema" = "https://ubcode.useblocks.com/ubproject.schema.json"
[needs]
id_required = true
[[needs.types]]
directive = "impl"
title = "Implementation"
prefix = "IMPL_"
[[needs.types]]
directive = "req"
title = "Requirement"
prefix = "REQ_"
[needs.fields.source_file]
description = "Source file for codelinks needs"
[needs.links.implements]
incoming = "implemented by"
outgoing = "implements"
# --- Codelinks configuration ---
[codelinks]
set_remote_url = true
remote_url_field = "remote-url"
[codelinks.projects.my_app]
remote_url_pattern = "https://github.com/org/repo/blob/{commit}/{path}#L{line}"
[codelinks.projects.my_app.source_discover]
src_dir = "../src"
include = ["**/*.cpp", "**/*.h"]
gitignore = true
comment_type = "cpp"
[codelinks.projects.my_app.analyse]
get_oneline_needs = true
get_need_id_refs = true
get_rst = false
[codelinks.projects.my_app.analyse.oneline_comment_style]
start_sequence = "@"
field_split_char = ","
needs_fields = [
{ name = "title", type = "str" },
{ name = "id", type = "str" },
{ name = "type", type = "str", default = "impl" },
{ name = "implements", type = "list[str]", default = [] },
]
[codelinks.projects.my_app.analyse.need_id_refs]
markers = ["@need-ids:"]
[codelinks.projects.my_app.analyse.marked_rst]
start_sequence = "@rst"
end_sequence = "@endrst"
# Optional: use the preprocessor-aware libclang engine for the C/C++ files,
# so that markers in inactive #if / #ifdef branches are excluded.
[codelinks.projects.my_app.analyse.preprocessor]
compile_commands = "../build/compile_commands.json"
defines = ["FEATURE_X=1"]
includes = ["../include"]
std = "c++17"