Command-line reference

Every ubc command, flag and exit code, generated from the command tree that ubc --help prints. Each command that does something of its own shows its maturity and what it does without a license. ubc agent-skill writes the same command tree as a SKILLS.md file for AI agents.

Exit codes

Every command exits with these codes; a command that adds or narrows one lists it under its heading.

Code

Meaning

0

Success. A command group run without a subcommand prints its help and exits 0 too.

1

The command ran and failed: findings at or above the --deny bar, a failed gate, a refused license, or an error while it ran.

2

The arguments are invalid: an unknown option, a missing value, a value out of range.

Common options

Most commands share these groups of options. A command that takes a group says so under its heading.

Logging

-v, --verbose

Show debug information

-q, --quiet

Only show errors and warnings

License

--license-key <TEXT>

Use a specific license key

Environment variable: UBCODE_LICENSE_KEY.

--license-user <TEXT>

Use a specific license user

Environment variable: UBCODE_LICENSE_USER.

Processing

--no-cache

Do not use on-disk cache reads

Environment variables

Each variable below changes what ubc does wherever it is set, in a shell, in CI, or in the environment of an editor that starts ubc serve.

UBCODE_CONFIG_OVERRIDE

The default value of:

  • --config: every command that has it

UBCODE_LICENSE_KEY

The default value of:

  • --key: ubc license show, ubc license activate

  • --license-key: every command that has it

UBCODE_LICENSE_USER

The default value of:

  • --license-user: every command that has it

  • --user: ubc license show, ubc license hash, ubc license activate

UBCODE_LICENSE_FILE

The path to an offline license file, instead of file in the [license] table of ubcode.toml (see Offline licenses).

UBCODE_LICENSE_CONFIG_DIR

The directory to read ubcode.toml from, instead of the platform’s configuration directory (see License configuration).

UBCODE_LICENSE_HTTPS_PROXY

The proxy for HTTPS requests to the license server, instead of https in the [proxy] table of ubcode.toml (see Proxies).

UBCODE_LICENSE_HTTP_PROXY

The proxy for HTTP requests to the license server, instead of http in the [proxy] table of ubcode.toml (see Proxies).

UBCODE_LICENSE_NO_PROXY

The hosts the license server requests reach without the proxy, instead of no in the [proxy] table of ubcode.toml (see Proxies).

UBCODE_LICENSE_CACHE_DIR

The directory of the license cache, instead of the platform’s cache directory (~/.cache/ublicense/ on Linux; see Caching).

UBCODE_INTERSPHINX_CACHE_DIR

The directory of the intersphinx inventory cache, instead of intersphinx in the platform’s ubCode cache directory (ubc intersphinx cache dir prints the one in use; see Intersphinx).

UBCODE_MERMAID_BROWSER

The browser ubc build pdf draws Mermaid diagrams with: a path, which takes precedence over browser in [build.mermaid] (see Mermaid diagrams).

UBCODE_MERMAID_DISCOVERY

off, 0, false or no stops ubc build pdf searching the install locations and PATH for a browser to draw Mermaid diagrams with (see Mermaid diagrams).

UBC_AGENT_RUNNER

Overrides command of [agent.runner] for ubc agent run (see The [agent.runner] table).

UBC_AGENT_RUNNER_MODEL

Overrides model of [agent.runner] for ubc agent run (see The [agent.runner] table).

UBC_AGENT_RUNNER_TIMEOUT

Overrides timeout_secs of [agent.runner] for ubc agent run (see The [agent.runner] table).

UBC_LIBCLANG_INDEX_URL

A PyPI-compatible index to download the pinned libclang from, for the preprocessor-aware C and C++ engine of codelinks (see analyse.preprocessor).

Commands

ubc

CLI for the ubcode project

ubc <COMMAND>

Options

--version

Show the version and exit

Subcommands

  • ubc completions: Generate shell completions

  • ubc check: Lint a ubcode project

  • ubc format: Run formatting on individual files or directories

  • ubc clean: Clear any caches in the directory and any subdirectories

  • ubc config: Show the nearest configuration in JSON format, resolving any extends and defaults

  • ubc script: Run a script defined in ubproject.toml

  • ubc quickstart: Create an example ubcode project

  • ubc agent-skill: Generate a SKILLS.md describing all CLI commands for AI agents

  • ubc build: Commands for building projects

  • ubc license: Commands for managing licenses

  • ubc schema: Commands for ontology schema validation

  • ubc query: Query a ubcode project: its needs graph, and what it can cross-reference

  • ubc intersphinx: Inspect Sphinx objects.inv inventories and manage the intersphinx cache

  • ubc report: Render a report template against the project’s needs index

  • ubc diff: Diff & impact analysis for local projects and needs.json

  • ubc serve: Run a ubcode server

  • ubc agent: Spec-driven V-model engine for AI authoring agents: workflow heartbeat, gap and impact analysis, release gating, and config-driven stage authoring (alpha)

ubc completions

Maturity:

Stable

Without a license:

No license needed

Generate shell completions

ubc completions [SHELL]

Arguments

[SHELL]

The shell to generate completions for. If not provided, the shell will be guessed from the environment

  • bash

  • elvish

  • fish

  • powershell

  • zsh

ubc check

Maturity:

Stable

Without a license:

Up to 5 source files; with --per-file: refused

Lint a ubcode project.

With no paths, checks the whole project discovered from the current directory. With paths, the whole project is still resolved so cross-file diagnostics are correct, but only diagnostics under the given paths are reported. Pass --per-file for the previous per-file, project-free behaviour.

ubc check [OPTIONS] [FILES]...

Arguments

[FILES]...

Files or directories to check.

With no paths, the whole project — discovered from the current directory — is checked. With paths, the whole project is still resolved (so cross-file diagnostics are correct) but only diagnostics located under the given paths are reported; project-level configuration diagnostics are always reported regardless of the paths. Pass --per-file to instead check each named file in isolation.

Options

--per-file

Check each named file in isolation, without project resolution.

The fast, project-free path: each named file is parsed on its own, so only per-file diagnostics are reported (no cross-file, reference, toctree, or schema checks) and the on-disk cache is neither read nor written. Non-RST files (e.g. Markdown) are skipped. Requires explicit paths.

--output-format <FORMAT>

Output format for the findings.

human (the default) prints diagnostic entries and a severity summary. json writes a single JSON document to stdout — the diagnostics and a severity tally — and demotes all other output to stderr, so the stdout stream is safe to pipe into a JSON consumer. The exit code and the --deny / --max-warnings policy are unaffected by the format.

  • human: Human-readable diagnostic entries and a severity summary (the default)

  • json: A single JSON document on stdout: the diagnostics and a severity tally, with all other output demoted to stderr

Default: human.

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--extend-ignore <CODES>

Comma-separated list of additional diagnostic codes to ignore

--isolated

Do not read any configuration files, use only the default configuration

--config-file <PATH>

The path to a specific configuration file to use for all files

Diagnostics

--deny <LEVEL>

Fail if any finding at or above this level is found.

none never fails on findings. Each command states its own default in its description, and a command that reads a bar from ubproject.toml ([build.html] deny, [build.pdf] deny, [linkcheck] deny) uses that key when this flag is absent — the flag always wins over the key. When combined with --max-warnings, the stricter of the two bounds wins: the command fails if either is exceeded.

  • none: Never fail the severity threshold, whatever the findings. An explicitly passed --max-warnings budget is a separate bound and still applies

  • info: Informational diagnostics and above

  • warning: Warning diagnostics and above

  • error: Error diagnostics only

--max-warnings <N>

Fail if the number of warning-level diagnostics exceeds this count.

Applied in addition to --deny: whichever bound is stricter wins.

Also takes the common Logging, License and Processing options.

ubc format

Maturity:

Beta

Without a license:

Refused

Run formatting on individual files or directories.

Each file will be processed against its nearest configuration file, or the default configuration if no configuration file is found.

ubc format [OPTIONS] <FILES>...

Arguments

<FILES>...

Files or directories to run formatting on

Options

--check

Avoid writing any formatted files back; instead, exit with a non-zero status code if any files would have been modified, and zero otherwise

--preview

Activate this command in preview mode: required while ubc format is in Beta.

Without it the command formats nothing and exits non-zero.

Configuration

--isolated

Do not read any configuration files, use only the default configuration

--config-file <PATH>

The path to a specific configuration file to use for all files

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

Also takes the common Logging and License options.

ubc clean

Maturity:

Stable

Without a license:

No license needed

Clear any caches in the directory and any subdirectories

ubc clean [PATH]

Arguments

[PATH]

The path to the directory to clean (defaults to the current directory)

ubc config

Maturity:

Stable

Without a license:

No license needed

Show the nearest configuration in JSON format, resolving any extends and defaults

ubc config [OPTIONS] [PATH]

Arguments

[PATH]

The path to start the config search from (defaults to the current directory)

Options

-i, --indent <INT>

Number of spaces to indent JSON

Default: 0.

--default

Show the default configuration instead

--schema

Show the configuration schema instead

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

ubc script

Maturity:

Stable

Without a license:

No license needed

Exit codes:

These, and otherwise the general codes:

  • 1-255: The script’s own non-zero exit code, passed through (1 when the script was stopped by a signal or its code does not fit).

Run a script defined in ubproject.toml

ubc script [OPTIONS] <KEY>

Arguments

<KEY>

The script key to execute

Options

--path <PATH>

The path to the project root (defaults to the current directory)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

ubc quickstart

Maturity:

Stable

Without a license:

No license needed

Create an example ubcode project

ubc quickstart [OPTIONS] [PATH]

Arguments

[PATH]

The path to write to (defaults to the current directory)

Options

-o, --overwrite

Overwrite existing files

-f, --flavor <FLAVOR>

The project flavor to scaffold

  • minimal: Minimal reStructuredText project (builds with Sphinx)

  • full: Full feature tour: RST + Markdown, variants, links, reports

  • markdown: Minimal Markdown (MyST) project

  • variants: Build-variant (“150% model”) project

Default: minimal.

ubc agent-skill

Maturity:

Beta

Without a license:

No license needed

Generate a SKILLS.md describing all CLI commands for AI agents.

Introspects the full CLI tree and produces a Markdown reference listing every command, sub-command, argument, and option together with the ubc version that generated the document.

ubc agent-skill [OPTIONS]

Options

-o, --output <PATH>

Path to write the SKILLS.md file. If omitted, prints to stdout

--sort-commands

Whether to sort commands alphabetically (default to order in help)

ubc build

Commands for building projects

ubc build <COMMAND>

Subcommands

ubc build list-documents

Maturity:

Stable

Without a license:

Up to 5 source files

Print out a list of the documents that would be indexed for this project

ubc build list-documents [OPTIONS] [PATH]

Arguments

[PATH]

The path to the project root (defaults to the current directory)

Options

--codelinks

Also list files for codelinks projects

--codelinks-project <TEXT>

Only list files for a specific codelinks project (implies --codelinks)

--source-documents

List the source documents (RST/MD files)

--parser

Print the parser name alongside each source document

--order <ORDER>

Order of the listed source documents. toctree (the default) lists documents reachable from the root toctree in depth-first toctree order, then all remaining documents sorted by path; path sorts every document by path (and skips the index pipeline entirely)

  • toctree: Documents reachable from the root toctree in depth-first toctree order, then all remaining documents sorted by path

  • path: All documents sorted by path

Default: toctree.

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc build index

Maturity:

Stable

Without a license:

Up to 5 source files

Index the project and report its diagnostics.

Findings are summarised by severity; by default any warning-or-worse finding yields a non-zero exit, tunable with --deny / --max-warnings. Pass --show-warnings to print the per-finding detail.

ubc build index [OPTIONS] [PATH]

Arguments

[PATH]

The path to the project root (defaults to the current directory)

Options

-w, --show-warnings

Print the detail of each finding (otherwise only the summary count is shown)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--lint-extend-ignore <CODES>

Comma-separated list of additional diagnostic codes to ignore

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Diagnostics

--deny <LEVEL>

Fail if any finding at or above this level is found.

none never fails on findings. Each command states its own default in its description, and a command that reads a bar from ubproject.toml ([build.html] deny, [build.pdf] deny, [linkcheck] deny) uses that key when this flag is absent — the flag always wins over the key. When combined with --max-warnings, the stricter of the two bounds wins: the command fails if either is exceeded.

  • none: Never fail the severity threshold, whatever the findings. An explicitly passed --max-warnings budget is a separate bound and still applies

  • info: Informational diagnostics and above

  • warning: Warning diagnostics and above

  • error: Error diagnostics only

--max-warnings <N>

Fail if the number of warning-level diagnostics exceeds this count.

Applied in addition to --deny: whichever bound is stricter wins.

Also takes the common Logging, License and Processing options.

ubc build needs

Maturity:

Stable

Without a license:

Up to 5 source files and 100 needs

Build the needs index and output to a file

ubc build needs [OPTIONS] [PATH]

Arguments

[PATH]

The path to the project root (defaults to the current directory)

Options

-f, --format <FORMAT>

The output format

  • json: JSON output (needs.json)

  • parquet: Apache Parquet output (needs.parquet)

Default: json.

-o, --outpath <PATH>

The path to the output file

--source-maps

Include source map information for each need

--content

Include the content field for each need

--pretty

Pretty print the JSON output

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc build validate-json

Maturity:

Stable

Without a license:

No license needed

Validate a needs.json file

ubc build validate-json [OPTIONS] <PATH> [ID]...

Arguments

<PATH>

The path to the needs.json file

[ID]...

Only validate certain need IDs

Also takes the common Logging options.

ubc build targets

Maturity:

Experimental

Without a license:

Up to 5 source files and 100 targets

Build the reference targets index and output to a file (experimental)

ubc build targets [OPTIONS] [PATH]

Arguments

[PATH]

The path to the project root (defaults to the current directory)

Options

-f, --format <FORMAT>

The output format

  • inv: Sphinx inventory output (objects.inv)

Default: inv.

-o, --outpath <PATH>

The path to the output file

--compress

Whether to compress the inv file with zlib

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc build html

Maturity:

Beta

Without a license:

Up to 5 source files

Build a static HTML site for the project.

Details such as an option or the emitted markup may still change between minor releases. Configuration lives under [build.html] in ubproject.toml.

The site is written first and then judged: the default bar is --deny warning, so any warning-or-worse finding — render-phase build warnings and indexing diagnostics alike — yields a non-zero exit. Move the bar with [build.html] deny in ubproject.toml, or with --deny / --max-warnings for one run.

ubc build html [OPTIONS] [PATH]

Arguments

[PATH]

The path to the project root (defaults to the current directory)

Options

-o, --output <DIR>

The output directory for the built site.

Defaults to _build/html under the project root (the directory containing ubproject.toml), mirroring Sphinx’s conventional _build/<builder> layout. A relative path is resolved against the current directory.

-w, --show-warnings

Print the detail of each build and indexing warning.

Without it both streams are counted but not listed. The flag covers the render-phase build.* findings and the index diagnostics alike.

A run that trips the quality gate prints the detail with or without the flag, so a failing build never has to be repeated just to read why. The default bar (--deny warning) already catches every warning-or-worse finding, so the flag changes what is printed mainly once that bar has been lowered — --deny error / --deny none, or [build.html] deny in ubproject.toml.

--fresh

Re-render every page, ignoring any existing build manifest.

Incremental builds normally skip pages whose inputs are unchanged; this forces a full re-render (a fresh manifest is still written). --no-cache implies --fresh.

--strict-sources

Fail if a source file changes during the build (the index/render window), instead of re-indexing and retrying once

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--lint-extend-ignore <CODES>

Comma-separated list of additional diagnostic codes to ignore

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Diagnostics

--deny <LEVEL>

Fail if any finding at or above this level is found.

none never fails on findings. Each command states its own default in its description, and a command that reads a bar from ubproject.toml ([build.html] deny, [build.pdf] deny, [linkcheck] deny) uses that key when this flag is absent — the flag always wins over the key. When combined with --max-warnings, the stricter of the two bounds wins: the command fails if either is exceeded.

  • none: Never fail the severity threshold, whatever the findings. An explicitly passed --max-warnings budget is a separate bound and still applies

  • info: Informational diagnostics and above

  • warning: Warning diagnostics and above

  • error: Error diagnostics only

--max-warnings <N>

Fail if the number of warning-level diagnostics exceeds this count.

Applied in addition to --deny: whichever bound is stricter wins.

Also takes the common Logging, License and Processing options.

ubc build pdf

Maturity:

Beta

Without a license:

Up to 5 source files

Exit codes:

These, and otherwise the general codes:

  • 1: The --need-id / --need-filter selection leaves nothing to print: it matches no need, or no document the root toctree reaches holds one. No PDF is written.

  • 2: The selection is malformed: a --need-id names no need of the project, or the --need-filter expression is empty, does not compile, or cannot run against the project (an unknown field, a *_back backlink).

Build a single PDF of the project.

One file, holding the documents the root toctree reaches, in the order it puts them: prose, headings and lists, tables (including a table that crosses a page boundary, whose header row is redrawn), images and figures, externally rendered PlantUML diagrams, need cards with their meta tables and links, needlist and needtable, version-change boxes, admonitions, and the inline chrome the site draws. There is no Sphinx and no LaTeX in the path: the same index the editor and ubc check use is typeset directly.

--need-id <ID> / --need-filter <EXPR> build a SELECTION instead of the whole project. The documents holding the selected needs come in whole, in toctree order, and the run reports how far it widened.

The document opens with a title page and every continuation page carries its document’s title in the top margin, both on by default; set [build.pdf] title_page = false or running_header = false to turn either off, and --title-page / --no-title-page decide the cover for one run, beating the key in both directions. What the cover carries is [build.pdf.cover]: a logo, a subtitle, an author, lines of your own, and switches for the version, date and selection-count lines. What each margin prints is [build.pdf.header] and [build.pdf.footer]: three slots apiece, in which {title}, {section}, {page}, {pages}, {project}, {version} and {date} are replaced — and running_header = false is the shorthand for emptying the header’s default slots. Two builds of unchanged sources are byte-identical.

A table of contents follows the title page, on by default: set [build.pdf.toc] enabled = false to turn it off, and --toc / --no-toc decide it for one run, beating the key in both directions. It lists every section heading down to depth levels with the page it starts on. Its sheets are front matter like the cover: they carry no running header and no page number, a reader’s page box numbers them i, ii, iii …, and the body is numbered from 1 on the sheet after them.

Authored mermaid diagrams are drawn with ubCode’s own Mermaid in a browser you already have — Chrome or Edge, found where it is installed, or the one [build.mermaid] browser or the UBCODE_MERMAID_BROWSER environment variable names (a chrome-headless-shell is the quietest) — started headless on a throwaway profile, with every request a diagram makes refused. Without one, or with [build.pdf.mermaid] enabled = false, each stays a placeholder box.

Some constructs are not typeset yet — a video without a readable :poster:, and a generated diagram no configured PlantUML draws, among them — and each is drawn as a labelled placeholder box and counted on a build.pdf_* warning (display and inline maths are typeset), and the guide lists them all. The PDF is written first and then judged: the default bar is --deny warning, so those warnings fail the command, and -w prints every finding’s detail. Move the bar with [build.pdf] deny in ubproject.toml, or with --deny / --max-warnings for one run.

Externally rendered PlantUML and drawn Mermaid diagrams are cached in the project’s cache directory (PlantUML shared with ubc build html); --no-cache re-renders every diagram and refreshes that cache.

Configuration lives under [build.pdf] in ubproject.toml. Details such as an option or the typeset output may still change between minor releases.

ubc build pdf [OPTIONS] [PATH]

Arguments

[PATH]

The path to the project root (defaults to the current directory)

Options

-o, --output <FILE>

The FILE to write the PDF to.

Defaults to _build/pdf/<root_doc>.pdf under the project root (the directory containing ubproject.toml), mirroring the _build/<builder> layout ubc build html uses. A relative path is resolved against the current directory, and any missing parent directories are created.

--title-page

Open the document with a title page, for this run.

Beats [build.pdf] title_page in both directions, so a project that has turned the cover off can still ask for one, and a project that has turned it on can still ask for the plain output. Without either flag the configuration decides, and it is on when the configuration says nothing. What the cover carries is [build.pdf.cover].

--no-title-page

Do not open the document with a title page, for this run

--toc

Print a table of contents in the front matter, for this run.

Beats [build.pdf.toc] enabled in both directions, so a project that has turned the table off can still ask for one, and a project that has left it on can still ask for the plain output. Without either flag the configuration decides, and there is a table when it says nothing. How deep the table goes and what heading it carries is [build.pdf.toc].

--no-toc

Do not print a table of contents, for this run

-w, --show-warnings

Print the detail of each build and indexing warning.

Without it both streams are counted but not listed. A run that trips the quality gate prints the detail with or without the flag, so a failing build never has to be repeated just to read why.

Selection

--need-id <ID>

Include the document that holds this need, whole (repeatable).

The documents that contain the selected needs are included whole, in toctree order, so a selection of a few needs can still be many pages — the build reports how much it widened. --need-id A --need-id B selects BOTH needs — the ids union — and is exactly --need-filter 'id in ["A", "B"]'. An ID that names no need in the project is an error. Cannot be combined with --need-filter; use one expression instead.

--need-filter <EXPR>

Include the documents that hold the needs this expression matches, whole.

The same Python-like expression over need fields that ubc query filter takes, for example ‘type == “req” and status != “done”’. The documents that contain the selected needs are included whole, in toctree order, so a selection of a few needs can still be many pages — the build reports how much it widened. A malformed expression exits 2; a selection that matches no need writes no file and exits 1. Cannot be combined with --need-id.

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--lint-extend-ignore <CODES>

Comma-separated list of additional diagnostic codes to ignore

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Diagnostics

--deny <LEVEL>

Fail if any finding at or above this level is found.

none never fails on findings. Each command states its own default in its description, and a command that reads a bar from ubproject.toml ([build.html] deny, [build.pdf] deny, [linkcheck] deny) uses that key when this flag is absent — the flag always wins over the key. When combined with --max-warnings, the stricter of the two bounds wins: the command fails if either is exceeded.

  • none: Never fail the severity threshold, whatever the findings. An explicitly passed --max-warnings budget is a separate bound and still applies

  • info: Informational diagnostics and above

  • warning: Warning diagnostics and above

  • error: Error diagnostics only

--max-warnings <N>

Fail if the number of warning-level diagnostics exceeds this count.

Applied in addition to --deny: whichever bound is stricter wins.

Also takes the common Logging, License and Processing options.

ubc build linkcheck

Maturity:

Beta

Without a license:

Refused

Check the project’s external links.

Every external URL the project references is requested once — however many times it is written — and every OCCURRENCE of a bad one is reported, so a dead link used in twelve files is twelve locations to fix rather than one.

Verdicts are richer than pass/fail: a 403 that a bot-blocker returned, somebody else’s 5xx outage and a permanent redirect are each their own class with their own severity. The default bar is --deny error, so only a VERIFIED-dead link fails the command; move it with [linkcheck] deny in ubproject.toml, or with --deny / --max-warnings for one run.

Results are cached per project under .ub_cache/linkcheck/, so a second run over an unchanged project makes no network requests at all. Failures are never cached, so a link that has been fixed is noticed immediately. Configuration lives under [linkcheck] in ubproject.toml. Details such as a verdict class or the report format may still change between minor releases.

ubc build linkcheck [OPTIONS] [PATH] [COMMAND]

Arguments

[PATH]

The path to the project root (defaults to the current directory)

Options

-w, --show-links

Print every occurrence of every finding (otherwise only the summary is shown for a passing run).

A FAILING run prints the findings that failed it — those at or above the bar it failed — without this flag, so a failing build never has to re-run to learn what failed. That bar is the deny threshold, or warning when the run exceeded --max-warnings (the lower of the two when it failed both). Findings below it are withheld so the failure is not buried in them; this flag prints them too.

--output-format <FORMAT>

Output format for the findings.

human (the default) groups findings by URL. json writes a single versioned JSON document to stdout and demotes everything else to stderr, so the stdout stream is safe to pipe; sarif writes a SARIF 2.1.0 document the same way, which GitHub code scanning renders inline on a pull-request diff. The exit code and the --deny / --max-warnings policy are unaffected by the format.

  • human: Findings grouped by URL, plus a summary line (the default)

  • json: A single JSON document on stdout — every link with its verdict and its occurrences — with all other output demoted to stderr

  • sarif: A SARIF 2.1.0 document on stdout, for upload to GitHub code scanning — one result per occurrence, with a machine-applicable fix for every permanent redirect. Everything else is demoted to stderr, as for json

Default: human.

Fixing

--fix-redirects

Rewrite permanently-redirected URLs in the source that wrote them.

Only 301/308 redirects to a different URL that no [linkcheck] allowed_redirects rule permits, and only where the URL can be located and verified byte-for-byte at the recorded position. Anything else is reported as unfixable, with the reason. The run’s FINDINGS are unchanged by fixing — they are what was measured — so re-run to verify.

--dry-run

Print what --fix-redirects would change, and write nothing

Cache

--refresh

Re-check every link, ignoring stored results.

Stored results are still WRITTEN, so the next ordinary run is warm again.

--offline

Never touch the network: serve stored results and report anything else as unchecked.

Ignores cache_days and serves EXPIRED results too — a stale answer beats no answer when there is no way to get a fresh one. The summary line and summary.stale in the JSON say how many, so a job that must not run on expired data can gate on that number.

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘linkcheck.workers = 4’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--lint-extend-ignore <CODES>

Comma-separated list of additional diagnostic codes to ignore

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Diagnostics

--deny <LEVEL>

Fail if any finding at or above this level is found.

none never fails on findings. Each command states its own default in its description, and a command that reads a bar from ubproject.toml ([build.html] deny, [build.pdf] deny, [linkcheck] deny) uses that key when this flag is absent — the flag always wins over the key. When combined with --max-warnings, the stricter of the two bounds wins: the command fails if either is exceeded.

  • none: Never fail the severity threshold, whatever the findings. An explicitly passed --max-warnings budget is a separate bound and still applies

  • info: Informational diagnostics and above

  • warning: Warning diagnostics and above

  • error: Error diagnostics only

--max-warnings <N>

Fail if the number of warning-level diagnostics exceeds this count.

Applied in addition to --deny: whichever bound is stricter wins.

Also takes the common Logging, License and Processing options.

Subcommands

ubc build linkcheck cache

Manage the stored link-check results

ubc build linkcheck cache <COMMAND>

Subcommands

ubc build linkcheck cache dir

Maturity:

Beta

Without a license:

No license needed

Print the project’s link-check result cache directory

ubc build linkcheck cache dir [OPTIONS]

Options

--path <PATH>

The path to the project root (defaults to the current directory)

ubc build linkcheck cache list

Maturity:

Beta

Without a license:

No license needed

List stored results (URL, verdict and age), in URL order

ubc build linkcheck cache list [OPTIONS]

Options

--path <PATH>

The path to the project root (defaults to the current directory)

ubc build linkcheck cache clean

Maturity:

Beta

Without a license:

No license needed

Remove one stored result (by URL) or the whole cache

ubc build linkcheck cache clean [OPTIONS] [URL]

Arguments

[URL]

The URL to forget; omit to clear the whole cache

Options

--path <PATH>

The path to the project root (defaults to the current directory)

ubc license

Commands for managing licenses

ubc license <COMMAND>

Subcommands

ubc license show

Maturity:

Stable

Without a license:

No license needed

Show information for the current license

ubc license show [OPTIONS]

Options

-k, --key <TEXT>

The license key to show information for, otherwise look in configuration

Environment variable: UBCODE_LICENSE_KEY.

-u, --user <TEXT>

The user identifier for user-based licenses

Environment variable: UBCODE_LICENSE_USER.

--dev

Use the development product

--json

Print output as JSON. Implies –quiet

--show-activated

Show activated machines

Also takes the common Logging options.

ubc license hash

Maturity:

Stable

Without a license:

No license needed

Show hash for a given user e-mail

ubc license hash [OPTIONS]

Options

-u, --user <TEXT>

User e-mail to hash. If not provided, look in configuration

Environment variable: UBCODE_LICENSE_USER.

Also takes the common Logging options.

ubc license activate

Maturity:

Stable

Without a license:

No license needed

Activate the current license

ubc license activate [OPTIONS]

Options

-k, --key <TEXT>

The license key to activate, otherwise look in configuration

Environment variable: UBCODE_LICENSE_KEY.

-u, --user <TEXT>

The license user to activate, otherwise look in configuration

Environment variable: UBCODE_LICENSE_USER.

--dev

Use the development product

Also takes the common Logging options.

ubc license config-file

Maturity:

Stable

Without a license:

No license needed

Show the path to the license configuration file

ubc license config-file

ubc license clean

Maturity:

Stable

Without a license:

No license needed

Clear the ublicense cache.

This is useful to refresh the license activation before going offline for a while.

ubc license clean

ubc schema

Commands for ontology schema validation

ubc schema <COMMAND>

Subcommands

ubc schema validate

Maturity:

Stable

Without a license:

Refused

Validate needs against the ontology schema

ubc schema validate [OPTIONS] [PATH]

Arguments

[PATH]

The path to the project root (defaults to the current directory)

Options

--show-warnings

Show all build warnings/diagnostics alongside validation results

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--lint-extend-ignore <CODES>

Comma-separated list of additional diagnostic codes to ignore

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc query

Query a ubcode project: its needs graph, and what it can cross-reference

ubc query <COMMAND>

Subcommands

  • ubc query filter: Filter and display needs using a Python-like expression

  • ubc query cypher: Run a read-only Cypher query over the needs graph

  • ubc query search: Search what the project can cross-reference, with a paste-ready role snippet per hit

ubc query filter

Maturity:

Beta

Without a license:

Refused

Exit codes:

These, and otherwise the general codes:

  • 2: The query, the filter, an option value or the configuration is invalid, or no license is active.

Filter and display needs using a Python-like expression

ubc query filter [OPTIONS] [FILTER_EXPR]

Arguments

[FILTER_EXPR]

Python-like filter expression, e.g. type == "req" and status == "open"

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--field <FIELD>

Field to include in output (repeatable). Defaults to id, type, title

-f, --format <FORMAT>

Output format

  • table: Human-readable column-aligned table

  • json: JSON array of objects

Default: table.

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc query cypher

Maturity:

Beta

Without a license:

Refused

Exit codes:

These, and otherwise the general codes:

  • 1: --strict found query vocabulary that matches nothing in the project, and the query was not run.

  • 2: The query, the filter, an option value or the configuration is invalid, or no license is active.

Run a read-only openCypher query over the needs graph.

Nodes are needs, labelled by their type (e.g. (:requirement)).

Relationships are typed links, typed by the link option name (e.g. -[:links]->).

Properties are a need’s fields plus the built-ins id, type, and content.

The engine is read-only: write clauses (CREATE/MERGE/SET/DELETE) are rejected.

A filter-style query projects a single node column, e.g. MATCH (n:requirement) WHERE n.status = 'open' RETURN n.

Multi-column and aggregation projections are allowed for tabular output, e.g. MATCH (n) RETURN n.type, count(*).

Pass --schema (instead of a query) to print the graph’s schema: node labels (need types), relationship types (link options), and node properties with their data types.

A query that references a label, relationship type, or property absent from the whole project prints a warning to stderr (with a did-you-mean suggestion); pass --strict to treat such warnings as an error instead of running the query.

See https://ubcode.useblocks.com/usage/ubquery.html for the query language reference.

ubc query cypher [OPTIONS] [QUERY]

Arguments

[QUERY]

Read-only Cypher query, e.g. MATCH (n:req)-[:links]->(m) RETURN n.id, m.id

Options

--schema

Print the needs graph schema (node labels, relationship types, and node properties with their data types) instead of running a query. Conflicts with providing a QUERY

--strict

Treat vocabulary warnings (an unknown label, relationship type, or property) as an error: list them and exit with code 1 instead of running the query. Distinct from the exit code 2 a malformed query or a config/license error returns

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

-f, --format <FORMAT>

Output format

  • table: Human-readable column-aligned table

  • json: JSON array of objects

Default: table.

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc intersphinx

Inspect Sphinx objects.inv inventories and manage the intersphinx cache

ubc intersphinx <COMMAND>

Subcommands

ubc intersphinx inspect

Maturity:

Stable

Without a license:

No license needed

Inspect a Sphinx objects.inv inventory (a local file or a URL)

ubc intersphinx inspect [OPTIONS] <FILE_OR_URL>

Arguments

<FILE_OR_URL>

Path or URL to an objects.inv inventory file.

Local paths are read from disk. HTTP(S) URLs are fetched through the central cache; if the URL’s final path segment is not objects.inv, it is appended automatically.

Options

-f, --format <FORMAT>

Output format

  • sphinx: Sphinx-style inspect output (default)

  • json: Structured JSON output (MyST-Parser compatible)

Default: sphinx.

-d, --domain <DOMAIN>

Filter by domain name (* = wildcard)

-o, --object-type <TYPE>

Filter by object type (* = wildcard)

-n, --name <NAME>

Filter by reference name (* = wildcard)

--refresh

Force revalidation of a cached URL even if it is still fresh.

The request is still conditional (If-None-Match / If-Modified-Since), so an unchanged inventory is a cheap 304. Only meaningful for URLs.

--offline

Never fetch: serve a cached copy of a URL, or fail if none exists.

Only meaningful for URLs (local files are always read directly).

ubc intersphinx diff

Maturity:

Stable

Without a license:

No license needed

Exit codes:

These, and otherwise the general codes:

  • 1: The two inventories differ.

  • 2: The comparison could not run: an argument, read or parse error.

Compare two Sphinx objects.inv inventories (local files or URLs)

Exits 0 when they are identical, 1 when they differ, and 2 when an inventory could not be read or parsed (or the report could not be written). The comparison is key-based on (domain:type, name), so row order is not a difference.

ubc intersphinx diff [OPTIONS] <FILE_OR_URL> <FILE_OR_URL>

Arguments

<FILE_OR_URL>

Path or URL to the FIRST inventory (the baseline)

<FILE_OR_URL>

Path or URL to the SECOND inventory (the one being compared)

Options

-f, --format <FORMAT>

Output format

  • table: Grouped, human-readable table (default)

  • json: One JSON object, for CI to assert on

Default: table.

-d, --domain <DOMAIN>

Filter by domain name (* = wildcard). Applied to BOTH inventories before comparing, so a filtered diff answers “are these equal within this scope?”

-o, --object-type <TYPE>

Filter by object type (* = wildcard). Applied to both inventories

-n, --name <NAME>

Filter by reference name (* = wildcard). Applied to both inventories

--refresh

Force revalidation of a cached URL even if it is still fresh.

The request is still conditional (If-None-Match / If-Modified-Since), so an unchanged inventory is a cheap 304. Only meaningful for URLs.

--offline

Never fetch: serve cached copies of URLs, or fail if none exist.

Only meaningful for URLs (local files are always read directly).

--exit-zero

Exit 0 even when differences are found (report-only mode), instead of the exit code 1 that “the inventories differ” otherwise returns. The report is unchanged; only the process status is. Does NOT mask the exit code 2 an unreadable or unparseable inventory returns — that means no comparison happened at all

ubc intersphinx list

Maturity:

Stable

Without a license:

No license needed

List the references of every intersphinx project configured for the current ubcode project

ubc intersphinx list [OPTIONS] [PROJECT]...

Arguments

[PROJECT]...

Limit the output to the named configured intersphinx project(s), i.e. the [intersphinx.projects.<name>] keys. Repeatable; omit to list every configured project

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

-f, --format <FORMAT>

Output format

  • sphinx: Sphinx-style inspect output (default)

  • json: Structured JSON output (MyST-Parser compatible)

Default: sphinx.

-d, --domain <DOMAIN>

Filter by domain name (* = wildcard)

-o, --object-type <TYPE>

Filter by object type (* = wildcard)

-n, --name <NAME>

Filter by reference name (* = wildcard)

--refresh

Force revalidation of every cached inventory URL, even if still fresh.

The requests are still conditional (If-None-Match / If-Modified-Since), so an unchanged inventory is a cheap 304. Only meaningful for URL locations, and rejected when the configuration sets [intersphinx] offline = true.

--offline

Never fetch: serve cached copies of URL locations, or report a miss.

Implied by [intersphinx] offline = true; local inventory files are always read directly.

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

ubc intersphinx cache

Inspect and manage the central inventory cache

ubc intersphinx cache <COMMAND>

Subcommands

ubc intersphinx cache dir

Maturity:

Stable

Without a license:

No license needed

Print the central inventory cache directory

ubc intersphinx cache dir

ubc intersphinx cache list

Maturity:

Stable

Without a license:

No license needed

List cached inventories (URL, size, and age), in stable order

ubc intersphinx cache list

ubc intersphinx cache clean

Maturity:

Stable

Without a license:

No license needed

Remove one cached inventory (by URL) or the whole cache bucket

ubc intersphinx cache clean [URL]

Arguments

[URL]

The inventory URL to remove; omit to clear the entire cache bucket

ubc report

Maturity:

Beta

Without a license:

Up to 5 source files and 100 needs

Exit codes:

These, and otherwise the general codes:

  • 2: The template or the configuration cannot be used: no template named, an invalid or unknown template name, or a configuration that does not load.

Render a report template against the project’s needs index

ubc report [OPTIONS] [INSIGHT_OR_TEMPLATE]

Arguments

[INSIGHT_OR_TEMPLATE]

Name of the insight ([reports.insights.<name>] in ubproject.toml) or of the .html.j2 template to render, looked up under the project’s reports directory ([reports].directory). Omit if using –list

Options

--need <ID>

Render the insight for this need (repeatable). Bound as $current_id / $current_ids in the insight’s queries and as current_need / current_needs in its template

--list

List the available .html.j2 templates and declared insights instead of rendering

-o, --outpath <PATH>

Path to write the rendered HTML to. Defaults to ‘<reports-dir>/_build/<template-stem>.html’, and for an insight to ‘<reports-dir>/_build/_insights/<name>.html’ (or ‘<name>/<need-id>.html’ when rendered for one need)

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc diff

Maturity:

Beta

Without a license:

Refused

Exit codes:

These, and otherwise the general codes:

  • 1: Differences were found. Also returned for an invalid combination of inputs, and when no license is active.

  • 2: The comparison failed while it ran.

Diff & impact analysis for local projects and needs.json

ubc diff [OPTIONS] [COMMAND]

Options

-n, --needs <PATH>

Needs.json file path (can be used twice for comparison)

-p, --project <PATH>

Project path (can be used twice for comparison)

-f, --format <FORMAT>

Output format

  • html: Render an HTML report

  • console: Render a colored console report

Default: console.

-o, --outpath <PATH>

Output file path (for HTML format)

--html-theme <HTML_THEME>

HTML theme for output

  • dark: Dark theme

  • light: Light theme

  • auto: Auto theme (follows system preference)

Default: auto.

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

Impact

--impact

Enable impact analysis

--impact-depth <INT>

Set impact analysis link depth

Default: 1.

--impact-direction <IMPACT_DIRECTION>

Set impact analysis direction

  • outgoing: Follow outgoing links

  • incoming: Follow incoming links

  • both: Follow links in both directions

Default: both.

--impact-max-chains <INT>

Maximum number of impact chains per changed need (0 = unlimited)

Default: 20.

Filters

--allow-type <TYPE>

Allow-filter for need types (repeatable)

--deny-type <TYPE>

Deny-filter for need types (repeatable)

--allow-core <FIELD>

Allow-filter for core fields (repeatable)

--deny-core <FIELD>

Deny-filter for core fields (repeatable)

--allow-extra <FIELD>

Allow-filter for extra fields (repeatable)

--deny-extra <FIELD>

Deny-filter for extra fields (repeatable)

--allow-link <LINK>

Allow-filter for link types (repeatable)

--deny-link <LINK>

Deny-filter for link types (repeatable)

--deny-externals

Deny-filter external needs

Also takes the common Logging, License and Processing options.

Subcommands

ubc diff git

Maturity:

Beta

Without a license:

Refused

Exit codes:

These, and otherwise the general codes:

  • 1: Differences were found.

  • 2: The comparison could not run, including when no license is active.

Git-based diff and impact analysis

ubc diff git [OPTIONS] [REF1] [REF2]

Arguments

[REF1]

First git reference (branch/tag/commit)

[REF2]

Second git reference (branch/tag/commit)

Options

-p, --project <PATH>

Project path. Defaults to the current working directory

-n, --needs <PATH>

Needs.json file path in the repository

--staged

Compare the staging area with HEAD

-f, --format <FORMAT>

Output format

  • html: Render an HTML report

  • console: Render a colored console report

Default: console.

-o, --outpath <PATH>

Output file path (for HTML format)

--html-theme <HTML_THEME>

HTML theme for output

  • dark: Dark theme

  • light: Light theme

  • auto: Auto theme (follows system preference)

Default: auto.

Impact

--impact

Enable impact analysis

--impact-depth <INT>

Set impact analysis link depth

Default: 1.

--impact-direction <IMPACT_DIRECTION>

Set impact analysis direction

  • outgoing: Follow outgoing links

  • incoming: Follow incoming links

  • both: Follow links in both directions

Default: both.

--impact-max-chains <INT>

Maximum number of impact chains per changed need (0 = unlimited)

Default: 20.

Filters

--allow-type <TYPE>

Allow-filter for need types (repeatable)

--deny-type <TYPE>

Deny-filter for need types (repeatable)

--allow-core <FIELD>

Allow-filter for core fields (repeatable)

--deny-core <FIELD>

Deny-filter for core fields (repeatable)

--allow-extra <FIELD>

Allow-filter for extra fields (repeatable)

--deny-extra <FIELD>

Deny-filter for extra fields (repeatable)

--allow-link <LINK>

Allow-filter for link types (repeatable)

--deny-link <LINK>

Deny-filter for link types (repeatable)

--deny-externals

Deny-filter external needs

Also takes the common Logging, License and Processing options.

ubc serve

Run a ubcode server

ubc serve <COMMAND>

Subcommands

  • ubc serve mcp: Run the Model Context Protocol (MCP) server over stdio

  • ubc serve lsp: Run the language server over stdio (or TCP with --port)

ubc serve mcp

Maturity:

Beta

Without a license:

Starts, but refuses the project tools

Run the Model Context Protocol (MCP) server over stdio

ubc serve mcp [OPTIONS]

Options

--default-config <PATH>

Path to the default ubproject.toml configuration file

-c, --config <TOML>

Configuration override (repeatable). Example: lint.ignore = ["W001"]

--projects-in-memory <N>

How many projects to keep in memory between graph-tool calls. Each call still re-scans its project for changed files, unless it passes assume_unchanged and its project is in memory; a project kept in memory skips reloading the index cache from disk. Least recently used projects are unloaded first; 0 keeps none in memory

Default: 2.

--unload-after-idle-minutes <MINUTES>

Minutes a project stays in memory without a graph-tool call before it is unloaded to give the memory back; its next call reloads the index cache from disk. 0 never unloads it

Default: 10.

Also takes the common License options.

ubc serve lsp

Maturity:

Stable

Without a license:

Starts, with the editor limits

Run the language server over stdio (or TCP with --port)

ubc serve lsp [OPTIONS]

Options

-p, --port <PORT>

Start a TCP instance of the language server listening on the given port

--log-to-output <LOG_TO_OUTPUT>

When to log to the output channel

  • always: Emit all messages

  • debug: Emit debug messages and above

  • info: Emit info messages and above

  • warning: Emit warning messages and above

  • error: Emit error messages only

  • off: Emit nothing

Default: info.

--show-notifications <SHOW_NOTIFICATIONS>

When to show notifications

  • always: Emit all messages

  • debug: Emit debug messages and above

  • info: Emit info messages and above

  • warning: Emit warning messages and above

  • error: Emit error messages only

  • off: Emit nothing

Default: error.

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

ubc agent

Spec-driven V-model engine for AI authoring agents: workflow heartbeat, gap and impact analysis, release gating, and config-driven stage authoring (alpha).

The command works today and is under active development. It is in alpha: the subcommand set, the options and the JSON output shapes may still change between releases. Configuration lives under [agent] in ubproject.toml.

ubc agent <COMMAND>

Subcommands

  • ubc agent next: Report the next actionable workflow stage (0 or 1) as JSON. Drives the ACTIVE STREAM — the entry-root and V-subtree derived from git diff (a dirty tree infers from the NEED files changed in its working tree, staged, unstaged, or untracked but not gitignored, and only a FULLY clean tree falls back to the branch’s changes since the merge-base), or the stream anchored on --id — not the whole graph. Pre-existing gaps in other streams are surfaced as non-blocking open_streams. A report, not a gate. It exits 0 on a readable graph, except a misused --id or --stage, which reports ok false with reason id_not_found or stage_not_found and exits non-zero, so a typo is never mistaken for progress. next only REPORTS. To execute the recommended stage through the runner use ubc agent run

  • ubc agent run: EXECUTE the recommended workflow stage through the configured AI runner ([agent.runner] / UBC_AGENT_RUNNER), then re-build and report what was produced plus the advanced next / gaps. Assembles a prompt from the recommended skill (or --skill <NAME> for a targeted intent such as the change-request cascade), the anchor need’s context --no-code briefing, and the resolved authoring route. The produced artefact is left UNCOMMITTED for human or UI approval. Drives the SAME active stream next reports (anchored on --id, else the git diff stream). A stage that declares no produces type and does not resolve as a code stage has no artefact to run for: that exits non-zero naming the stage, and spawns nothing

  • ubc agent prompt: Print the resolved instruction for the next workflow action as PLAIN TEXT: what ubc agent run would drive next, emitted on stdout instead of executed. An instruction is led by a === WORKING DIRECTORY === header naming the project root (run spawns its runner IN that directory, a reader of the printed text does not). The no-action arms carry no header, only their NO ACTION (<reason>) line. Not a byte-preview of what run pipes: an authoring instruction defers here to the author skill’s propose-first section, because a reader has a user to ask, while run keeps the unconditional order for a headless runner. Drives the SAME active stream next reports (anchored on --id, else the git diff stream) and resolves the SAME arm: an AUTHOR instruction for a ready need-producing or code stage, a REVIEW instruction for a review-held stage, a FIX instruction when every review target already failed, or a FIX (diagnostics) instruction when a reported diagnostic holds the stage. When no stage is actionable it prints the one action for that state (empty / done / blocked) and still exits 0. --stage <STAGE_ID> briefs an EXPLICIT stage instead of the computed recommendation (e.g. a global risks/decisions stage the cockpit Flow strip offered). A named stage that reads blocked for the active stream is reported instead of briefed, so the text can never order authoring past a layer the stage is itself blocked on. A named stage that reads done IS briefed, led by a line naming that state so the order is not read as the first artefact. A named CODE stage (one that authors no need and gates a type through require_code) is briefed only while a need of that gated type exists for it to implement, and reported otherwise. Executes nothing, writes nothing, and resolves no runner, so it needs no [agent.runner]. Exits non-zero when --id is not a need, when --stage names a stage absent from [workflow], or when a stage is actionable but no anchor need resolves from a graph that HAS needs (a clean tree with no --id). A graph with NO needs at all is briefed from its first stage instead, and exits 0

  • ubc agent status: Report per-stage workflow state as JSON (the heartbeat): one row per stage with its state (done / ready / blocked), coverage counts, failing gates, and route. A report, not a gate — always exits 0 on a readable graph

  • ubc agent gaps: Report the full gap list (structural and diagnostics) as JSON ({gaps, by_category, summary, ok}). Exits non-zero when any gap is found — the whole-graph gate used to capture and read a release-check baseline. --scope <NEED_ID> narrows the gate to one stream (the anchor’s entry root and its trace-subtree) and recomputes the tally, summary and exit code over that subset

  • ubc agent trace: Report the bidirectional trace-coverage matrix as JSON ({ok, edges}): one row per declared trace edge with the forward and backward covered/total counts and the surviving per-direction gap ids. Exits non-zero if any edge is uncovered in either direction. A presentation of the same per-edge obligation gaps computes, never a second model

  • ubc agent release-check: Gate NEW structural gaps against a ratcheting baseline of accepted debt. A baselined gap is reported as non-blocking debt; a gap absent from the baseline fails the gate. On a passing run the baseline ratchets DOWN to the gaps that still exist, so a fixed gap can never be readmitted. A diagnostics-gate gap always fails: accept a finding with [workflow.diagnostics] allow or [lint], never with the baseline. --with-verdicts folds the substance gate (the verdict-check verb) into the same pass: the combined gate is ok only when both the structural gaps and the substance problems are clear

  • ubc agent verdict-check: Report the AI-review substance gate as JSON ({ok, missing, failing, malformed, outdated, unverifiable, stale}). Reads the AI-authored review verdicts from the native .pharaoh/verdicts/ directory and reports which review-required needs block the release: a required need with no valid verdict (missing), a need whose verdict records a failing judgment (failing), a verdict file that is itself unusable (malformed), a need whose verdict was recorded against a stale review fingerprint (outdated), a need a verdict could not be evaluated for (unverifiable), and a leftover verdict for a need absent from the graph (stale, warn-only). The required need types are derived from the [workflow] review stages, not a hard-coded list. Exits non-zero whenever missing, failing, malformed, outdated, or unverifiable is non-empty; stale never blocks

  • ubc agent verdict-submit: Submit an evaluator-authored schema-2 verdict for ONE need id as JSON. Reads the axes (+ optional summary and the advisory agent / model provenance) from --file (- for stdin), then the ENGINE stamps schema, need, criteria, criteria_fingerprint, and reviewed_fingerprint (overwriting anything the evaluator supplied for those keys, so it cannot mis-stamp them), validates the stamped result against the need’s type’s quality policy, and on success writes .pharaoh/verdicts/<ID>.json and prints a short ack ({written, fresh}). On rejection prints a machine-readable error report naming why (unknown_need / no_quality_policy / unreadable_input / invalid_json / validation_failed, the last carrying every structural problems entry) and writes nothing. Exits non-zero on any rejection

  • ubc agent review-brief: Report the reviewer briefing for a need TYPE or explicit ids as JSON: the review skill, the absolute verdicts directory, the review-target need ids (after excluding already-fresh ones, see fresh_skipped), each target’s current one-hop review fingerprint, the produced type’s quality-pack projection (pack name, guidance, scored axes), the derived JSON Schema a submitted verdict must satisfy, and the verdict-submit invocation template. This is the SAME briefing ubc agent next attaches to a review-held stage, the shared build_review_brief builder the two verbs never duplicate or diverge on. <TYPE> selects every present need of that type. --ids selects explicit ids instead (mixed types allowed, grouped per type). --all includes already-fresh needs too. A report, not a gate: exits zero even when every candidate is fresh. Exits non-zero only on a genuine selection error (an unknown id, or a type/id with no review-carrying stage)

  • ubc agent audit: Inspect ONE need’s trace coverage as JSON: its id, title, type, status, body, and source pointer; a trace sub-object scoping the outgoing forward and incoming _back trace links to their target ids; and a full links map of every named link present (forward and _back), including non-trace links. A READ briefing for a single id — exits non-zero when the id is absent from the built graph, never substituting another need or an empty stand-in. Takes the need id via --id <NEED_ID> or the positional <NEED_ID> (kept for back-compat). --id wins when both are given, and neither given is a clear error

  • ubc agent context: Inspect ONE anchor need’s linked-need briefing as JSON: an anchor summary (id, type, title, body) plus a related list of every directly linked need, forward and _back, each carrying its own body and the relation label of the link it came in on (de-duplicated, with a count), and the same full links map audit emits. Reads the surrounding needs without opening each file; exits non-zero when the id is absent. The related_code field is an honestly-deferred capability: empty list when no code root is resolvable, but a non-zero REFUSAL when a code root DOES resolve, so a resolved-code-root project never reads a silent empty list as “this need has no related code”. The --no-code (alias --graph-only) opt-out asks for the graph briefing anyway: it returns the full briefing with related_code: null and code_omitted: true instead of refusing, so context is usable in a real code-linked project without a silent empty list. Takes the anchor need id via --id <NEED_ID> or the positional <NEED_ID> (kept for back-compat). --id wins when both are given, and neither given is a clear error

  • ubc agent impact: Report the seed-by-id BLAST RADIUS of ONE need as JSON: an anchor summary plus a reached list — the multi-hop up-and-down trace closure of every need that depends on the seed in either direction, to a --depth bound, each entry tagged with its depth and direction (up / down) and carrying its code_url / test_url (null when absent) so the code-and-test impact is visible — and a stale_gaps list holding the structural gap records already attributed to the anchor or any reached need, drawn from the same gap computation the gaps gate uses. A REPORT, not a gate: it exits zero on a present seed even with stale gaps, and exits non-zero only when the seed id is absent. Takes the seed need id via --id <NEED_ID> or the positional <NEED_ID> (kept for back-compat). --id wins when both are given, and neither given is a clear error

  • ubc agent change: The change-request lifecycle. plan drafts one from the impact analysis of an ANCHOR need, assess runs a skill over the draft to rule on each reached id, approve records the authorization, execute cascades the approved change down the V, and close reports what the implementation actually did against what was approved. show and list read the records back, and remove physically excises a need the change deletes

  • ubc agent config-validate: Cross-check the [workflow] process config against the ubproject.toml ontology as JSON ({ok, errors, warnings}). A pure pre-flight: every type a stage produces / a trace edge or obligation names must be a declared [[needs.types]] directive, every referenced link a declared [needs.links.*] table, and every transition from/to state a declared lifecycle state — each mismatch an error. A status value absent from the states, a blank per-stage skill slot, and a declared type no stage produces are warnings. ok is the emptiness of errors; exits non-zero on any error. Reads ONLY the config — never builds the graph, loads needs.json, or runs a coverage gate — so it stays disjoint from native ubc config

  • ubc agent doctor: Run the config preflight as JSON ({ok, checks:[...]}): a config-driven setup health check an agent runs BEFORE driving the loop, so it fails closed on a misconfiguration before spending a run’s tokens. The first check composes the config-validate pipeline (a config-validity error is one blocking error check, its warnings are warning checks). The remaining checks are tool probes admitted ONLY when the resolved [workflow] config requires the tool: mmdc when the diagram gate is enabled with engine mermaid/both, plantuml (plus its Java runtime) when enabled with engine plantuml/both, and codelinks when a stage configures the code-trace gate. A required-but-absent tool is a blocking error carrying a remediation fix; a tool no gate requires is not probed. ok is the absence of any error-status check (warnings never flip it) and the process exits non-zero exactly when not ok. Reads ONLY the config — never builds the graph, loads needs.json, or runs a coverage gate

  • ubc agent install: Bootstrap a project into the agentic loop from a named profile preset. Scaffolds the [workflow] process configuration and ontology into ubproject.toml, installs the profile’s AI-asset bundle (skills, commands, agents) into the host integration directories, and records every owned file in the install manifest at .pharaoh/agent/install-manifest. --profile <name> selects the preset (default vmodel); an unknown name writes nothing and exits non-zero listing the available profiles. --detect grounds the configuration in the existing needs graph instead of the blank profile defaults and exits non-zero on a graphless project. Non-destructive by default; --overwrite clobbers existing files scoped to the managed set

  • ubc agent update: Reconcile a previously installed project against the current preset, touching only the files the manifest records as install-owned. For each owned file it performs a three-way comparison between the preset’s current content, the recorded baseline, and the on-disk content: an unedited file is updated to the preset content, a locally edited file is PRESERVED and reported as a conflict (never blind-clobbered) unless --overwrite resolves it preset-wins. Refreshes the manifest afterwards. Exits non-zero when a conflict was not resolved by --overwrite, with the conflicts accompanying the exit

  • ubc agent reverse: Reverse recovery: reconstruct the V-model left arm (user stories, requirements, architecture) from the git surface. sources reports which recovery evidence exists for a scope. plan builds the recovery work order for one stage, and prompt renders it into the prompt a recovery run is dispatched with. record writes the one ledger shard a recovery run produced (the only ledger writer). status reports the combined ledger/graph/git recovery status for a scope. forget deletes one ledger shard, and rebaseline accepts reviewed changes to recovered source files

ubc agent next

Maturity:

Experimental

Without a license:

Up to 100 needs

Report the next actionable workflow stage (0 or 1) as JSON. Drives the ACTIVE STREAM — the entry-root and V-subtree derived from git diff (a dirty tree infers from the NEED files changed in its working tree, staged, unstaged, or untracked but not gitignored, and only a FULLY clean tree falls back to the branch’s changes since the merge-base), or the stream anchored on --id — not the whole graph. Pre-existing gaps in other streams are surfaced as non-blocking open_streams. A report, not a gate. It exits 0 on a readable graph, except a misused --id or --stage, which reports ok false with reason id_not_found or stage_not_found and exits non-zero, so a typo is never mistaken for progress. next only REPORTS. To execute the recommended stage through the runner use ubc agent run

ubc agent next [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

--id <NEED_ID>

Stateless stream anchor for next: a NEED id (not a stage or feature name) whose stream to select, bypassing the git diff query. Use it when the changed NEED files cannot seed a stream (a dirty tree infers from the working tree alone, and only a FULLY clean tree falls back to the branch’s changes since the merge-base), or to focus one of several in-flight streams. Supplying --id persists nothing: a later no-arg call again derives the stream from git diff. An --id that is not a need exits non-zero. (No --feature, no state file.)

--stage <STAGE_ID>

Brief an EXPLICIT stage instead of the computed recommendation: the stage id (from [workflow]) whose route, author skill and gates to brief. Used to drive a specific ready stage the cockpit Flow strip offered (e.g. a global risks/decisions stage). Still anchored on --id for feature/context resolution. An unknown stage exits non-zero

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent run

Maturity:

Experimental

Without a license:

Up to 100 needs

EXECUTE the recommended workflow stage through the configured AI runner ([agent.runner] / UBC_AGENT_RUNNER), then re-build and report what was produced plus the advanced next / gaps. Assembles a prompt from the recommended skill (or --skill <NAME> for a targeted intent such as the change-request cascade), the anchor need’s context --no-code briefing, and the resolved authoring route. The produced artefact is left UNCOMMITTED for human or UI approval. Drives the SAME active stream next reports (anchored on --id, else the git diff stream). A stage that declares no produces type and does not resolve as a code stage has no artefact to run for: that exits non-zero naming the stage, and spawns nothing

ubc agent run [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

--id <NEED_ID>

Stateless stream anchor: a NEED id (not a stage or feature name) the run briefs from and drives the stream of. Without it the stream is inferred from changed NEED files: on a dirty tree from the files changed in your working tree (staged, unstaged, or untracked but not gitignored), and only on a FULLY clean tree from the branch’s changes since the merge-base. A dirty tree whose changes include no need file infers nothing, so pass --id then, for example right after a review when only verdict files changed. And when your working tree carries changes from several streams they merge into one, so --id picks which one to drive. The anchor need the prompt briefs from is --id when given, else the stream’s first entry root. An --id that is not a need exits non-zero

--skill <NAME>

Run a NAMED skill on the anchor instead of the stage-recommended one. The assembled prompt carries <NAME>’s skill content (the installed .claude/skills/<NAME>/SKILL.md, or the profile asset when not installed) in place of the stage’s author_skill, while the anchor’s context --no-code briefing and the resolved route are unchanged. This is the execution surface for any targeted intent (e.g. change-request) without adding a verb — intents ARE skills. Without --skill, run executes the stage-recommended skill

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent prompt

Maturity:

Experimental

Without a license:

Up to 100 needs

Print the resolved instruction for the next workflow action as PLAIN TEXT: what ubc agent run would drive next, emitted on stdout instead of executed. An instruction is led by a === WORKING DIRECTORY === header naming the project root (run spawns its runner IN that directory, a reader of the printed text does not). The no-action arms carry no header, only their NO ACTION (<reason>) line. Not a byte-preview of what run pipes: an authoring instruction defers here to the author skill’s propose-first section, because a reader has a user to ask, while run keeps the unconditional order for a headless runner. Drives the SAME active stream next reports (anchored on --id, else the git diff stream) and resolves the SAME arm: an AUTHOR instruction for a ready need-producing or code stage, a REVIEW instruction for a review-held stage, a FIX instruction when every review target already failed, or a FIX (diagnostics) instruction when a reported diagnostic holds the stage. When no stage is actionable it prints the one action for that state (empty / done / blocked) and still exits 0. --stage <STAGE_ID> briefs an EXPLICIT stage instead of the computed recommendation (e.g. a global risks/decisions stage the cockpit Flow strip offered). A named stage that reads blocked for the active stream is reported instead of briefed, so the text can never order authoring past a layer the stage is itself blocked on. A named stage that reads done IS briefed, led by a line naming that state so the order is not read as the first artefact. A named CODE stage (one that authors no need and gates a type through require_code) is briefed only while a need of that gated type exists for it to implement, and reported otherwise. Executes nothing, writes nothing, and resolves no runner, so it needs no [agent.runner]. Exits non-zero when --id is not a need, when --stage names a stage absent from [workflow], or when a stage is actionable but no anchor need resolves from a graph that HAS needs (a clean tree with no --id). A graph with NO needs at all is briefed from its first stage instead, and exits 0

ubc agent prompt [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

--id <NEED_ID>

Stateless stream anchor: a NEED id (not a stage or feature name) the instruction briefs from and drives the stream of. Without it the stream is inferred from changed NEED files: on a dirty tree from the files changed in your working tree (staged, unstaged, or untracked but not gitignored), and only on a FULLY clean tree from the branch’s changes since the merge-base. A dirty tree whose changes include no need file infers nothing, so pass --id then, for example right after a review when only verdict files changed. And when your working tree carries changes from several streams they merge into one, so --id picks which one to drive. The anchor need the instruction briefs from is --id when given, else the stream’s first entry root. An --id that is not a need exits non-zero

--stage <STAGE_ID>

Brief an EXPLICIT stage instead of the computed recommendation: the stage id (from [workflow]) whose route, author skill and gates to brief. Used to drive a specific ready stage the cockpit Flow strip offered (e.g. a global risks/decisions stage). Still anchored on --id for feature/context resolution. An unknown stage exits non-zero, naming the stage it rejected. A KNOWN stage whose own dependency is not met yet reads blocked for the active stream, and that prints a report instead of an authoring order, so it never tells you to author past a layer the stage is itself blocked on. A stage that reads done for that stream is still briefed, led by a line naming the state, and for a need-producing stage that line says the artefact it orders is an additional one. A stage that still carries a gap or an unfinished review reads ready and is briefed with no such line. A CODE stage (it authors no need, it implements a require_code type in source) is briefed only while a need of that type exists for it to implement, and reported otherwise

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent status

Maturity:

Experimental

Without a license:

Up to 100 needs

Report per-stage workflow state as JSON (the heartbeat): one row per stage with its state (done / ready / blocked), coverage counts, failing gates, and route. A report, not a gate — always exits 0 on a readable graph

ubc agent status [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent gaps

Maturity:

Experimental

Without a license:

Up to 100 needs

Report the full gap list (structural and diagnostics) as JSON ({gaps, by_category, summary, ok}). Exits non-zero when any gap is found — the whole-graph gate used to capture and read a release-check baseline. --scope <NEED_ID> narrows the gate to one stream (the anchor’s entry root and its trace-subtree) and recomputes the tally, summary and exit code over that subset

ubc agent gaps [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

--scope <NEED_ID>

Narrow gaps / trace to one stream: pass a NEED_ID and the gate keeps only the gaps of that need’s stream, its entry root and the whole trace-subtree beneath, resolved through the trace graph (NOT a path convention, so it works on any on-disk layout). The tally, summary and exit code are recomputed over that subset. An anchor that resolves to no needs is an unknown scope and fails the gate. Scope is the TRACE-CONNECTED stream grown from the anchor, not everything co-located on disk: a fully disconnected need (no links in or out) is still caught by whole-graph gaps / release-check, not this scoped gate

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent trace

Maturity:

Experimental

Without a license:

Up to 100 needs

Report the bidirectional trace-coverage matrix as JSON ({ok, edges}): one row per declared trace edge with the forward and backward covered/total counts and the surviving per-direction gap ids. Exits non-zero if any edge is uncovered in either direction. A presentation of the same per-edge obligation gaps computes, never a second model

ubc agent trace [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

--scope <NEED_ID>

Narrow gaps / trace to one stream: pass a NEED_ID and the gate keeps only the gaps of that need’s stream, its entry root and the whole trace-subtree beneath, resolved through the trace graph (NOT a path convention, so it works on any on-disk layout). The tally, summary and exit code are recomputed over that subset. An anchor that resolves to no needs is an unknown scope and fails the gate. Scope is the TRACE-CONNECTED stream grown from the anchor, not everything co-located on disk: a fully disconnected need (no links in or out) is still caught by whole-graph gaps / release-check, not this scoped gate

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent release-check

Maturity:

Experimental

Without a license:

Up to 100 needs

Gate NEW structural gaps against a ratcheting baseline of accepted debt. A baselined gap is reported as non-blocking debt; a gap absent from the baseline fails the gate. On a passing run the baseline ratchets DOWN to the gaps that still exist, so a fixed gap can never be readmitted. A diagnostics-gate gap always fails: accept a finding with [workflow.diagnostics] allow or [lint], never with the baseline. --with-verdicts folds the substance gate (the verdict-check verb) into the same pass: the combined gate is ok only when both the structural gaps and the substance problems are clear

ubc agent release-check [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

--baseline <PATH>

Path to the accepted-gap baseline file: a JSON object mapping each gap key (id|category|link) to the have count it was accepted at. A gap in the baseline is reported as non-blocking debt unless its have dropped below that count; a gap absent from it fails the gate. A diagnostics-gate gap fails even when listed. Without --baseline the verb gates on every gap (the whole-graph behaviour)

--update-baseline

On a passing run, ratchet the baseline file DOWN to the gaps that still exist (drop fixed gaps so they can never be readmitted). No-op without --baseline. Read-only by default so the gate never mutates state on a reporting run

--with-verdicts

Also run the substance (verdict) gate beside the structural gates and fold its result into the combined ok / exit code. Reads the AI-authored review verdicts from the native .pharaoh/verdicts/ directory, derives the review-required need types from the same [workflow] review stages, and surfaces the per-category substance problems (verdicts) beside the structural ones. The combined gate passes only when both the structural gaps and the substance problems are clear

--verdicts-dir <PATH>

Directory of review verdict JSON files. Overrides the native <srcdir>/.pharaoh/verdicts default when given. Only consulted with --with-verdicts

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent verdict-check

Maturity:

Experimental

Without a license:

Up to 100 needs

Report the AI-review substance gate as JSON ({ok, missing, failing, malformed, outdated, unverifiable, stale}). Reads the AI-authored review verdicts from the native .pharaoh/verdicts/ directory and reports which review-required needs block the release: a required need with no valid verdict (missing), a need whose verdict records a failing judgment (failing), a verdict file that is itself unusable (malformed), a need whose verdict was recorded against a stale review fingerprint (outdated), a need a verdict could not be evaluated for (unverifiable), and a leftover verdict for a need absent from the graph (stale, warn-only). The required need types are derived from the [workflow] review stages, not a hard-coded list. Exits non-zero whenever missing, failing, malformed, outdated, or unverifiable is non-empty; stale never blocks

ubc agent verdict-check [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the heartbeat verbs’ --srcdir. When set, the verdict directory defaults to <srcdir>/.pharaoh/verdicts and the required types are derived from <srcdir>’s [workflow] review stages

--verdicts-dir <PATH>

Directory of review verdict JSON files. Overrides the native <srcdir>/.pharaoh/verdicts default when given. Named --verdicts-dir to match release-check --with-verdicts; --dir stays a hidden alias

--require-type <TYPE>

Force a single need type that must each carry a passing verdict. When omitted, the required types are derived from the [workflow] review-skill stages

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent verdict-submit

Maturity:

Experimental

Without a license:

Up to 100 needs

Submit an evaluator-authored schema-2 verdict for ONE need id as JSON. Reads the axes (+ optional summary and the advisory agent / model provenance) from --file (- for stdin), then the ENGINE stamps schema, need, criteria, criteria_fingerprint, and reviewed_fingerprint (overwriting anything the evaluator supplied for those keys, so it cannot mis-stamp them), validates the stamped result against the need’s type’s quality policy, and on success writes .pharaoh/verdicts/<ID>.json and prints a short ack ({written, fresh}). On rejection prints a machine-readable error report naming why (unknown_need / no_quality_policy / unreadable_input / invalid_json / validation_failed, the last carrying every structural problems entry) and writes nothing. Exits non-zero on any rejection

ubc agent verdict-submit [OPTIONS] --file <PATH> <NEED_ID>

Arguments

<NEED_ID>

The need id the submitted verdict is for

Options

--file <PATH>

Path to the evaluator-authored verdict JSON, or - to read stdin

--fingerprint <FINGERPRINT>

The one-hop review fingerprint the reviewer captured for this need from the review brief / next (its entry in the brief’s fingerprints). When given, arms the freshness race guard: the submit is REJECTED if the need’s content changed after it was scored, so a review can never green content the reviewer never saw. Omit it only for a deliberate manual submit

--criteria-fingerprint <CRITERIA_FINGERPRINT>

The criteria fingerprint the reviewer captured for this need’s type from the review brief / next (the brief’s criteria.fingerprint). When given, arms the criteria race guard: the submit is REJECTED if the [quality] pack changed after the need was scored, so a review can never green scores made against a stale rubric. Omit it only for a deliberate manual submit

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the heartbeat verbs’ --srcdir

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent review-brief

Maturity:

Experimental

Without a license:

Up to 100 needs

Report the reviewer briefing for a need TYPE or explicit ids as JSON: the review skill, the absolute verdicts directory, the review-target need ids (after excluding already-fresh ones, see fresh_skipped), each target’s current one-hop review fingerprint, the produced type’s quality-pack projection (pack name, guidance, scored axes), the derived JSON Schema a submitted verdict must satisfy, and the verdict-submit invocation template. This is the SAME briefing ubc agent next attaches to a review-held stage, the shared build_review_brief builder the two verbs never duplicate or diverge on. <TYPE> selects every present need of that type. --ids selects explicit ids instead (mixed types allowed, grouped per type). --all includes already-fresh needs too. A report, not a gate: exits zero even when every candidate is fresh. Exits non-zero only on a genuine selection error (an unknown id, or a type/id with no review-carrying stage)

ubc agent review-brief [OPTIONS] [TYPE]

Arguments

[TYPE]

The need TYPE to brief: every present need of that type with a review-carrying [workflow] stage. Mutually exclusive with --ids; exactly one of the two must be given

Options

--ids <ID>...

Explicit need ids to brief instead of a type (mixed types allowed — grouped per type internally, one entry per type in briefs). Mutually exclusive with <TYPE>

--all

Include already-fresh needs too, instead of excluding them via the freshness pre-filter (fresh_skipped in the output)

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the heartbeat verbs’ --srcdir

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent audit

Maturity:

Experimental

Without a license:

Up to 100 needs

Inspect ONE need’s trace coverage as JSON: its id, title, type, status, body, and source pointer; a trace sub-object scoping the outgoing forward and incoming _back trace links to their target ids; and a full links map of every named link present (forward and _back), including non-trace links. A READ briefing for a single id — exits non-zero when the id is absent from the built graph, never substituting another need or an empty stand-in. Takes the need id via --id <NEED_ID> or the positional <NEED_ID> (kept for back-compat). --id wins when both are given, and neither given is a clear error

ubc agent audit [OPTIONS] [NEED_ID]

Arguments

[NEED_ID]

Need id to audit (e.g. REQ_AUDIT_INSPECT). The historic positional shape, kept working for back-compat. Prefer --id, the same shape next / run accept

Options

--id <NEED_ID>

Need id to audit (e.g. REQ_AUDIT_INSPECT). Takes priority over the positional NEED_ID when both are given. One of --id or the positional form is required

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the spec workflow’s --srcdir

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent context

Maturity:

Experimental

Without a license:

Up to 100 needs

Inspect ONE anchor need’s linked-need briefing as JSON: an anchor summary (id, type, title, body) plus a related list of every directly linked need, forward and _back, each carrying its own body and the relation label of the link it came in on (de-duplicated, with a count), and the same full links map audit emits. Reads the surrounding needs without opening each file; exits non-zero when the id is absent. The related_code field is an honestly-deferred capability: empty list when no code root is resolvable, but a non-zero REFUSAL when a code root DOES resolve, so a resolved-code-root project never reads a silent empty list as “this need has no related code”. The --no-code (alias --graph-only) opt-out asks for the graph briefing anyway: it returns the full briefing with related_code: null and code_omitted: true instead of refusing, so context is usable in a real code-linked project without a silent empty list. Takes the anchor need id via --id <NEED_ID> or the positional <NEED_ID> (kept for back-compat). --id wins when both are given, and neither given is a clear error

ubc agent context [OPTIONS] [NEED_ID]

Arguments

[NEED_ID]

Anchor need id (e.g. REQ_CONTEXT_INSPECT). The historic positional shape, kept working for back-compat. Prefer --id, the same shape next / run accept

Options

--id <NEED_ID>

Anchor need id (e.g. REQ_CONTEXT_INSPECT). Takes priority over the positional NEED_ID when both are given. One of --id or the positional form is required

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the spec workflow’s --srcdir

--code-dir <PATH>

Code source directory for related_code. Supplying it makes a code root resolvable, which the verb REFUSES (exit non-zero) rather than emit a silently-empty related_code: [] — related_code semantic search is deferred (DEC_RELATED_CODE_DEFERRED)

--codelinks <PATH>

codelinks.toml for related_code. REFUSED for the same reason as --code-dir. Even without this flag, an adjacent <srcdir>/codelinks.toml declaring a source_discover.src_dir is auto-detected and likewise refused, so the default codelinks-bearing project never reads a silently empty related_code

--no-code

Request the graph-only briefing and OMIT related_code explicitly, instead of refusing when a code root resolves. With this flag context returns the full graph briefing (anchor + linked needs with bodies + links) and reports related_code as null with code_omitted: true — an explicit opt-out, never a silently-empty related_code: []. This makes context usable in a real code-linked project; the deferred semantic search (DEC_RELATED_CODE_DEFERRED) is still not run. Without the flag the refuse-on-resolvable-code-root default is unchanged

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent impact

Maturity:

Experimental

Without a license:

Up to 100 needs

Report the seed-by-id BLAST RADIUS of ONE need as JSON: an anchor summary plus a reached list — the multi-hop up-and-down trace closure of every need that depends on the seed in either direction, to a --depth bound, each entry tagged with its depth and direction (up / down) and carrying its code_url / test_url (null when absent) so the code-and-test impact is visible — and a stale_gaps list holding the structural gap records already attributed to the anchor or any reached need, drawn from the same gap computation the gaps gate uses. A REPORT, not a gate: it exits zero on a present seed even with stale gaps, and exits non-zero only when the seed id is absent. Takes the seed need id via --id <NEED_ID> or the positional <NEED_ID> (kept for back-compat). --id wins when both are given, and neither given is a clear error

ubc agent impact [OPTIONS] [NEED_ID]

Arguments

[NEED_ID]

Seed need id whose blast radius to report (e.g. REQ_CONTEXT_INSPECT). The historic positional shape, kept working for back-compat. Prefer --id, the same shape next / run accept

Options

--id <NEED_ID>

Seed need id whose blast radius to report (e.g. REQ_CONTEXT_INSPECT). Takes priority over the positional NEED_ID when both are given. One of --id or the positional form is required

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the spec workflow’s --srcdir

--depth <HOPS>

Maximum hop distance from the seed the closure walk reaches. A need at the bound is reported but not expanded further. Defaults to a small bound that still crosses the V

Default: 4.

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent change

The change-request lifecycle. plan drafts one from the impact analysis of an ANCHOR need, assess runs a skill over the draft to rule on each reached id, approve records the authorization, execute cascades the approved change down the V, and close reports what the implementation actually did against what was approved. show and list read the records back, and remove physically excises a need the change deletes.

plan resolves its destination through the configured [workflow.change_request] route and never guesses a path, and refuses an anchor that is itself a change request (the impact links sit outside the trace link set, so that closure is empty and a wrong anchor would otherwise succeed reporting “nothing is affected”). It reports the three closure tiers plus the tier 1 SIZE as its own field. approve refuses unless the three impact links cover the computed set exactly and no [NEEDS CLARIFICATION] marker stands anywhere the change request reaches, naming what failed and the ids on each side. An excluded id the body never mentions is a warning in the result, not a refusal. On acceptance the ENGINE stamps the decision, the approver, the timestamp and an appended status transition, overwriting anything the author supplied.

No verb here runs git: every edit is left UNCOMMITTED for a human to read as a diff before it becomes history.

ubc agent change <COMMAND>

Subcommands

  • ubc agent change plan: Draft a change request from the impact analysis of the anchor need(s), as JSON. Runs the change closure seeded from every --id, resolves the authoring destination through the configured [workflow.change_request] route, mints the next free id, writes the draft, and reports the three tiers (reached, potentially_affected, bound) plus the tier 1 size in reached_count. --id is REPEATABLE and takes the id of a need the change is AIMED AT, never a change request id: the impact links sit outside the trace link set, so a change request has no closure to walk and a wrong anchor there would succeed with an empty reach, which reads as “this change affects nothing”. The id is minted unless --cr-id chooses one, which must start with the type’s declared id prefix, carry no whitespace or path separator, match the project’s [needs] id_regex and be no existing need’s id. The draft is a whole document of its own, marked :orphan: and titled, so a freshly planned record raises neither toctree.not_included nor toctree.no_title. Exits non-zero, writing nothing, when ANY anchor is absent or is itself a change request, when --cr-id is refused, when the project declares no route for the type, when the type declares no id prefix, or when the destination file already exists. No path is ever guessed. Writes an UNCOMMITTED draft and runs no git

  • ubc agent change approve: Record the authorization decision over a change request as JSON, and stamp it into the change request’s own reStructuredText. An APPROVAL refuses unless the impact analysis names at least one id, the three impact links cover the computed impact set EXACTLY, and no [NEEDS CLARIFICATION] marker stands anywhere the change request reaches. Every failing condition is named at once, with the ids on each side. The body’s prose gates nothing: the excluded LINKS are the contract, so how a reason is worded never blocks an approval. An excluded id the body does not mention anywhere is only a warning, reported in excluded_without_mention beside the stamp. A rejected or deferred decision passes none of those: it is a person declining to proceed, it owes no complete impact analysis, and gating it would make the record unreachable on exactly the change requests most likely to be refused. --by is refused when it is empty or whitespace only, before anything is written: a status record requires an actor, so writing a blank one does not merely fail to authorize, it leaves a record no later verb can read or repair. On acceptance the ENGINE writes the decision, the approver, the timestamp and an appended status transition, OVERWRITING anything the author put in those slots. A rejected decision is recorded and KEPT: a rejected change request produces no commits at all, so if the refusal is not in this record it is recoverable from nowhere. Leaves the stamped file UNCOMMITTED and runs no git

  • ubc agent change execute: Cascade an APPROVED change request down the V, bounded by the approved scope. The cascade is anchored on the change request’s cr_anchor FIELD (the need a human edited), never on the change request id: no workflow stage produces a change_request, so a cascade anchored on the change request itself resolves no stage, falls into the “nothing to propagate” advisory, and EXITS 0 with an ok payload having reconciled nothing. Every downstream reconcile pass is handed the approved ids for its stage with their action, every id the change removes anywhere, and where a new artefact goes, so the runner is held to the approval rather than to its own judgement. Exits non-zero, spawning nothing, when the change request is absent, is not approved, names no anchor, or names an anchor the graph does not carry. When every pass succeeded (or there was nothing to cascade) it appends an executed stamp to the change request’s status log, by --by or else the repository’s git identity, and a pass that failed appends nothing. Allowed from approved and again from executed, so a re-run is a third transition rather than a refusal. Leaves every edit UNCOMMITTED and runs no git. Each pass is a SEPARATE headless process, which inside an editor agent session is a hidden second agent, so the pull forms exist for an agent that is already in the session: --print resolves no runner, spawns nothing and writes nothing, and prints as plain text ONE step per call (--step N, default 1): after the working-directory header, a === STEP <n>/<N>: <stage> (anchor <ID>) === section holding the exact prompt of that pass, in run order across the anchors. It is built from the project as it stands when it is called, so a step printed after earlier ones were carried out quotes their edits, and it ends with the exact command that continues: the next step while steps remain, --done after the last (one NO ACTION (nothing_to_cascade) line followed by the --done command when there is nothing to cascade). It refuses exactly where a run refuses, and a --step outside 1 to the number of steps is a usage error (exit 2) naming how many there are. --done then records executed for the work the agent did itself, with the stamp a successful run writes, refusing unless the record stands at approved or executed. --print and --done cannot be combined

  • ubc agent change close: Close a change request out, as JSON: run the checks and, when every one holds, append a closed stamp to its status log. The report has one entry per check (name, ok, detail) and a final ok that is true only when every check holds. The checks are that the record stands at approved or executed, that every id on cr_impact_remove is gone from the built index, that no need still links at a removed id, and that no [NEEDS CLARIFICATION] marker is left. All of them are reported on every run, so what is left is seen at once. When any check fails nothing is written and the verb exits non-zero. --by names who closes it out and is required unless --dry-run, which reports and never writes, with the exit code a real run would give. Nothing follows closed. It measures nothing about a need that stayed: whether that work was done is read off the uncommitted diff by a person. Leaves the stamped file UNCOMMITTED and runs no git

  • ubc agent change assess: Run the assessment skill over ONE change request: decide which of the reached needs the change modifies, removes or excludes, and write a rationale per exclusion. Its own verb rather than ubc agent run --skill because ANY --skill value dispatches unconditionally into the per-downstream-stage reconcile cascade, so there is exactly one prompt shape behind that flag and it is not this one: it opens with “You are reconciling ONE stage”, hands the skill a stage’s existing artefacts to edit in place, and spawns once per downstream stage. The prompt carries the change request id and its resolved path, the anchor, the three closure tiers WITH the file each id is written in, and a truncation caveat when a --bound actually cost the analysis a need. Nothing is parsed out of the runner (RunnerOutcome carries no stdout at all): the skill’s product is an uncommitted edit to the change request, and the engine reads it back by REBUILDING. Exits non-zero, spawning nothing, when the change request is absent, names no anchor, names an anchor the graph does not carry, or when the named skill resolves to nothing. Exits non-zero AFTER spawning, with reason: "no_assessment_written", when the runner edited the record’s file not at all: repeating that pass produces the same nothing, so it is named rather than reported as a success. A pass that made partial progress stays green with assessment_complete: false. The runner is a separate headless process, which inside an editor agent session is a hidden second agent, so --print is the pull form for an agent that is already in the session: it resolves no runner, spawns nothing and writes nothing, and prints as plain text, after the working-directory header, the exact prompt the run would hand its runner, refusing exactly where a run refuses. The agent carries the assessment out itself by editing the change request, which is also how a run’s assessment is recorded, so there is no --done

  • ubc agent change reassess: Reopen ONE change request for re-assessment, as JSON: back to square one, as if it were new. The impact is recomputed from the same anchors, and the three impact links, the decision and every body section but **Purpose** (the assessment’s prose about the withdrawn rulings) are dropped. The purpose is kept as the person wrote it, and so are the id, title, requester, external id and anchors. The append-only status log is kept whole with a draft transition appended (by --by, with --rationale or a factual default), so the earlier decisions stay on the record. Then assess it as any draft. Nothing assesses a change request again on its own when the graph moves after its assessment: this is how a person asks for a new one. Refused, writing nothing, on an executed or closed change request (that work is history; a follow-up change request covers it), when --by is empty, or when an anchor is gone. Leaves the rewritten record UNCOMMITTED and runs no git

  • ubc agent change show: Report ONE change request whole, as JSON: its own resolved path, its anchor, its non-link fields, its append-only status log, its impact sets, and a SOURCE POINTER PER ID in those sets in one call. The last part is not a convenience: ubc agent audit is one need per subprocess, so a closure of two hundred ids costs two hundred spawns, and that cost is what makes a driving skill reach for grep and break the rule that no skill constructs a path. audit reports a change request’s six links FORWARD, because they are declared links, but not their back-links: a change request’s back set lands on the need a change named and grows by one for every change request that ever names it, and context feeds runner prompts. What audit cannot reach is every NON-LINK field, since its result is a fixed shape with no arbitrary-option map. An id with no directive source (a codelinks marker authored it) keeps its place in the pointer map with a NULL value rather than being dropped or given an invented path, so a consumer can tell “no location” from “not looked up”

  • ubc agent change list: List every change request in the project with its state, as JSON, INCLUDING rejected ones. A rejected change request produces no commits at all, so git holds no trace of it and this listing is the only place the refusal survives. Read off the built index by TYPE rather than by walking the filesystem, which would mean guessing at a directory the project configures. --status narrows to one LIFECYCLE state and is a CLOSED value set: an unknown value is refused before any work happens, because a typo answering “no change requests” reads exactly like the truth and invites the most dangerous reading available, that nothing is open and nothing was refused. For the same reason a project whose config declares no [workflow.change_request] table is REFUSED with the same no_configured_route reason plan gives, rather than answered with an empty list it cannot hold anything to fill. Each row carries both the recorded decision (status, null until somebody makes one) and the lifecycle position (state, draft or assessed while undecided), and --status selects on the second. A record whose status log does not PARSE is listed with the read error in error and a null state, never as a silent omission and never as the undecided draft it would otherwise be indistinguishable from

  • ubc agent change remove: Physically remove one or more needs from the reStructuredText they are written in. The data-loss verb of the group, so it is a chain of refusals with an excision at the end, and every check runs over the whole requested set BEFORE the first line is touched. An absent id is a named error, never a no-op. A MARKER-AUTHORED need is refused: the refusal reports the marker’s own path and line range, because those ARE known, and explains that the extent of the CODE beneath the marker is recorded nowhere, so excising a guessed block of a source file is unrecoverable. A need whose span CONTAINS another need is refused naming it, unless that need is named for removal too. Measured: deleting a need by exactly the line range audit reports also destroyed a need nested inside it, taking a project from six needs to four with release-check still reporting ok: true and an empty new_gaps. The excision goes through rst_edit::remove_spans, which plans every target against an in-memory copy and commits only once the whole set has passed, so a refusal on one id cannot leave another already gone. Each target’s guard is the header line as the FILE writes it, checked against the directive TYPE the index reports for the id. Naming the same id twice removes it once. A document the removal empties is LEFT ON DISK: deleting it could break a toctree, and that is a human decision. Leaves every edit UNCOMMITTED and runs no git

ubc agent change plan

Maturity:

Experimental

Without a license:

Up to 100 needs

Draft a change request from the impact analysis of the anchor need(s), as JSON. Runs the change closure seeded from every --id, resolves the authoring destination through the configured [workflow.change_request] route, mints the next free id, writes the draft, and reports the three tiers (reached, potentially_affected, bound) plus the tier 1 size in reached_count. --id is REPEATABLE and takes the id of a need the change is AIMED AT, never a change request id: the impact links sit outside the trace link set, so a change request has no closure to walk and a wrong anchor there would succeed with an empty reach, which reads as “this change affects nothing”. The id is minted unless --cr-id chooses one, which must start with the type’s declared id prefix, carry no whitespace or path separator, match the project’s [needs] id_regex and be no existing need’s id. The draft is a whole document of its own, marked :orphan: and titled, so a freshly planned record raises neither toctree.not_included nor toctree.no_title. Exits non-zero, writing nothing, when ANY anchor is absent or is itself a change request, when --cr-id is refused, when the project declares no route for the type, when the type declares no id prefix, or when the destination file already exists. No path is ever guessed. Writes an UNCOMMITTED draft and runs no git

ubc agent change plan [OPTIONS] --id <NEED_ID>

Options

--id <NEED_ID>

The ANCHOR need id(s) the change is aimed at (e.g. REQ_LATENCY). REPEATABLE: a change request is a unit of work over the needs it changes, and a change touching two requirements at once is the ordinary case, so pass --id once per need being changed. The closure is seeded from all of them and its reach is their union.

Not a change request id: the impact links sit outside the trace link set, so a change request’s closure is empty and a wrong anchor there would report “nothing is affected” rather than fail.

One absent id refuses the WHOLE plan rather than being dropped, because a walk that quietly skipped a typo’d anchor would write a draft that looks complete and is missing an entire arm.

--title <TEXT>

Title for the drafted change request. Defaults to a title naming the anchor, which states what is true and leaves the author a visible TODO rather than a fabricated summary of a change nobody described yet

--cr-id <ID>

The id to give the change request, instead of a minted one. It must start with the id prefix the project declares for the change_request type (e.g. CR_), carry no whitespace or path separator (it becomes the file name), match [needs] id_regex, and not be the id of an existing need; otherwise the plan is refused and nothing is written. Without it the id is minted as <prefix><YYYYMMDD>_<4 hex>

--purpose <TEXT>

What the change is for, written under the draft’s **Purpose** heading in the body, where a person goes on editing it as markup. Without it the draft asks for one with a TODO there

--bound <HOPS>

Maximum hop distance the closure DESCENDS from each anchor. It does not bound the ascent, which is transitive and unbounded, so --bound 0 still reports every need above the seed. Off by default: the closure’s own direction rule (ascend transitively from each seed, descend transitively, never descending from what the ascent finds) holds the reach down: surveyed across a real 247-need graph, a mean of 4.5 with the same maximum the one-hop ascent had. Those figures were surveyed seeding ONE need; several anchors reach their union, which is bounded by the count times that and smaller wherever they share downstream artefacts. Either way a bound mostly buys a truncation caveat rather than a smaller answer

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent change approve

Maturity:

Experimental

Without a license:

Up to 100 needs

Record the authorization decision over a change request as JSON, and stamp it into the change request’s own reStructuredText. An APPROVAL refuses unless the impact analysis names at least one id, the three impact links cover the computed impact set EXACTLY, and no [NEEDS CLARIFICATION] marker stands anywhere the change request reaches. Every failing condition is named at once, with the ids on each side. The body’s prose gates nothing: the excluded LINKS are the contract, so how a reason is worded never blocks an approval. An excluded id the body does not mention anywhere is only a warning, reported in excluded_without_mention beside the stamp. A rejected or deferred decision passes none of those: it is a person declining to proceed, it owes no complete impact analysis, and gating it would make the record unreachable on exactly the change requests most likely to be refused. --by is refused when it is empty or whitespace only, before anything is written: a status record requires an actor, so writing a blank one does not merely fail to authorize, it leaves a record no later verb can read or repair. On acceptance the ENGINE writes the decision, the approver, the timestamp and an appended status transition, OVERWRITING anything the author put in those slots. A rejected decision is recorded and KEPT: a rejected change request produces no commits at all, so if the refusal is not in this record it is recoverable from nowhere. Leaves the stamped file UNCOMMITTED and runs no git

ubc agent change approve [OPTIONS] --id <CR_ID> --by <WHO> --decision <DECISION>

Options

--id <CR_ID>

The change request id to record a decision against

--by <WHO>

Who is recording the decision. Required: an authorization with no approver on it authorizes nothing

--decision <DECISION>

The decision to record

  • approved: Authorized. The implementation may proceed

  • rejected: Refused. No commit will ever carry this change

  • deferred: Put down without a verdict either way

--rationale <TEXT>

Why the decision was made. Defaults to a factual restatement of the decision and the approver, because the status log requires a non-empty rationale per transition and a synthesised one that claims a reason nobody gave would be worse than one that claims nothing

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent change execute

Maturity:

Experimental

Without a license:

Up to 100 needs

Cascade an APPROVED change request down the V, bounded by the approved scope. The cascade is anchored on the change request’s cr_anchor FIELD (the need a human edited), never on the change request id: no workflow stage produces a change_request, so a cascade anchored on the change request itself resolves no stage, falls into the “nothing to propagate” advisory, and EXITS 0 with an ok payload having reconciled nothing. Every downstream reconcile pass is handed the approved ids for its stage with their action, every id the change removes anywhere, and where a new artefact goes, so the runner is held to the approval rather than to its own judgement. Exits non-zero, spawning nothing, when the change request is absent, is not approved, names no anchor, or names an anchor the graph does not carry. When every pass succeeded (or there was nothing to cascade) it appends an executed stamp to the change request’s status log, by --by or else the repository’s git identity, and a pass that failed appends nothing. Allowed from approved and again from executed, so a re-run is a third transition rather than a refusal. Leaves every edit UNCOMMITTED and runs no git. Each pass is a SEPARATE headless process, which inside an editor agent session is a hidden second agent, so the pull forms exist for an agent that is already in the session: --print resolves no runner, spawns nothing and writes nothing, and prints as plain text ONE step per call (--step N, default 1): after the working-directory header, a === STEP <n>/<N>: <stage> (anchor <ID>) === section holding the exact prompt of that pass, in run order across the anchors. It is built from the project as it stands when it is called, so a step printed after earlier ones were carried out quotes their edits, and it ends with the exact command that continues: the next step while steps remain, --done after the last (one NO ACTION (nothing_to_cascade) line followed by the --done command when there is nothing to cascade). It refuses exactly where a run refuses, and a --step outside 1 to the number of steps is a usage error (exit 2) naming how many there are. --done then records executed for the work the agent did itself, with the stamp a successful run writes, refusing unless the record stands at approved or executed. --print and --done cannot be combined

ubc agent change execute [OPTIONS] --id <CR_ID>

Options

--id <CR_ID>

The APPROVED change request id to execute

--skill <NAME>

The reconcile skill each downstream pass runs with. Defaults to the shipped change-request skill. Not accepted with --done, which runs no pass

--by <WHO>

Who is running the cascade, recorded in the executed stamp. Defaults to the repository’s git identity, and to ubc agent change execute when git names nobody. Not accepted with --print, which stamps nothing

--print

Print the cascade instead of running it, ONE step per call: the exact prompt the headless run would hand its runner for that pass, as plain text. It is built from the project as it stands NOW, so a step printed after earlier steps were carried out quotes their edits, and it ends with the exact command that continues: the next step while steps remain, --done after the last. Resolves no runner and spawns nothing, so it works with no [agent.runner], and it writes nothing. For an agent that is already in a session and carries each step out itself, finishing one before it prints the next. Refuses exactly where a run refuses. Not accepted with --done

--step <N>

With --print: the step to print, counting from 1 in run order across each anchor’s cascade and each downstream stage. Defaults to 1. A number outside 1 to the number of steps is a usage error that names how many there are. Not accepted without --print, and not with --done

--done

Record executed without running anything, for a cascade that was carried out outside ubc (the steps --print handed out). Stamps exactly what a successful run stamps, by --by or else the repository’s git identity. Refuses unless the record stands at approved or executed. Not accepted with --print

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent change close

Maturity:

Experimental

Without a license:

Up to 100 needs

Close a change request out, as JSON: run the checks and, when every one holds, append a closed stamp to its status log. The report has one entry per check (name, ok, detail) and a final ok that is true only when every check holds. The checks are that the record stands at approved or executed, that every id on cr_impact_remove is gone from the built index, that no need still links at a removed id, and that no [NEEDS CLARIFICATION] marker is left. All of them are reported on every run, so what is left is seen at once. When any check fails nothing is written and the verb exits non-zero. --by names who closes it out and is required unless --dry-run, which reports and never writes, with the exit code a real run would give. Nothing follows closed. It measures nothing about a need that stayed: whether that work was done is read off the uncommitted diff by a person. Leaves the stamped file UNCOMMITTED and runs no git

ubc agent change close [OPTIONS] --id <CR_ID>

Options

--id <CR_ID>

The change request id to close out

--by <WHO>

Who is closing it out, recorded in the closed stamp. Required unless --dry-run: a status transition owes a person, and a blank one is refused before anything is written

--dry-run

Run the checks and report, but never write. The exit code is the one a real run would give

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent change assess

Maturity:

Experimental

Without a license:

Up to 100 needs

Run the assessment skill over ONE change request: decide which of the reached needs the change modifies, removes or excludes, and write a rationale per exclusion. Its own verb rather than ubc agent run --skill because ANY --skill value dispatches unconditionally into the per-downstream-stage reconcile cascade, so there is exactly one prompt shape behind that flag and it is not this one: it opens with “You are reconciling ONE stage”, hands the skill a stage’s existing artefacts to edit in place, and spawns once per downstream stage. The prompt carries the change request id and its resolved path, the anchor, the three closure tiers WITH the file each id is written in, and a truncation caveat when a --bound actually cost the analysis a need. Nothing is parsed out of the runner (RunnerOutcome carries no stdout at all): the skill’s product is an uncommitted edit to the change request, and the engine reads it back by REBUILDING. Exits non-zero, spawning nothing, when the change request is absent, names no anchor, names an anchor the graph does not carry, or when the named skill resolves to nothing. Exits non-zero AFTER spawning, with reason: "no_assessment_written", when the runner edited the record’s file not at all: repeating that pass produces the same nothing, so it is named rather than reported as a success. A pass that made partial progress stays green with assessment_complete: false. The runner is a separate headless process, which inside an editor agent session is a hidden second agent, so --print is the pull form for an agent that is already in the session: it resolves no runner, spawns nothing and writes nothing, and prints as plain text, after the working-directory header, the exact prompt the run would hand its runner, refusing exactly where a run refuses. The agent carries the assessment out itself by editing the change request, which is also how a run’s assessment is recorded, so there is no --done

ubc agent change assess [OPTIONS] --id <CR_ID>

Options

--id <CR_ID>

The change request id to assess

--skill <NAME>

The assessment skill to run with. Defaults to change-request-assess

--bound <HOPS>

Maximum hop distance the closure descends from the anchor. Off by default, matching change plan: the closure’s own direction rule already holds the reach to a measured mean of 4.2 and a max of 9 on a real 214-need graph, so a bound mostly buys a truncation caveat rather than a smaller answer

--print

Print the prompt instead of running it: the exact text the headless run would hand its runner (the assessment skill plus the briefing), as plain text led by the working-directory header. Resolves no runner and spawns nothing, so it works with no [agent.runner], and it writes nothing. For an agent that is already in a session and carries the assessment out itself, by editing the change request. There is no --done: the assessment is recorded by that edit, as it is after a run. Refuses exactly where a run refuses

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent change reassess

Maturity:

Experimental

Without a license:

Up to 100 needs

Reopen ONE change request for re-assessment, as JSON: back to square one, as if it were new. The impact is recomputed from the same anchors, and the three impact links, the decision and every body section but **Purpose** (the assessment’s prose about the withdrawn rulings) are dropped. The purpose is kept as the person wrote it, and so are the id, title, requester, external id and anchors. The append-only status log is kept whole with a draft transition appended (by --by, with --rationale or a factual default), so the earlier decisions stay on the record. Then assess it as any draft. Nothing assesses a change request again on its own when the graph moves after its assessment: this is how a person asks for a new one. Refused, writing nothing, on an executed or closed change request (that work is history; a follow-up change request covers it), when --by is empty, or when an anchor is gone. Leaves the rewritten record UNCOMMITTED and runs no git

ubc agent change reassess [OPTIONS] --id <CR_ID> --by <WHO>

Options

--id <CR_ID>

The change request id to reopen for re-assessment

--by <WHO>

Who asks for the re-assessment, recorded on the draft transition

--rationale <TEXT>

Why. Defaults to a factual statement of what the re-assessment does

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent change show

Maturity:

Experimental

Without a license:

Up to 100 needs

Report ONE change request whole, as JSON: its own resolved path, its anchor, its non-link fields, its append-only status log, its impact sets, and a SOURCE POINTER PER ID in those sets in one call. The last part is not a convenience: ubc agent audit is one need per subprocess, so a closure of two hundred ids costs two hundred spawns, and that cost is what makes a driving skill reach for grep and break the rule that no skill constructs a path. audit reports a change request’s six links FORWARD, because they are declared links, but not their back-links: a change request’s back set lands on the need a change named and grows by one for every change request that ever names it, and context feeds runner prompts. What audit cannot reach is every NON-LINK field, since its result is a fixed shape with no arbitrary-option map. An id with no directive source (a codelinks marker authored it) keeps its place in the pointer map with a NULL value rather than being dropped or given an invented path, so a consumer can tell “no location” from “not looked up”

ubc agent change show [OPTIONS] --id <CR_ID>

Options

--id <CR_ID>

The change request id to report

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent change list

Maturity:

Experimental

Without a license:

Up to 100 needs

List every change request in the project with its state, as JSON, INCLUDING rejected ones. A rejected change request produces no commits at all, so git holds no trace of it and this listing is the only place the refusal survives. Read off the built index by TYPE rather than by walking the filesystem, which would mean guessing at a directory the project configures. --status narrows to one LIFECYCLE state and is a CLOSED value set: an unknown value is refused before any work happens, because a typo answering “no change requests” reads exactly like the truth and invites the most dangerous reading available, that nothing is open and nothing was refused. For the same reason a project whose config declares no [workflow.change_request] table is REFUSED with the same no_configured_route reason plan gives, rather than answered with an empty list it cannot hold anything to fill. Each row carries both the recorded decision (status, null until somebody makes one) and the lifecycle position (state, draft or assessed while undecided), and --status selects on the second. A record whose status log does not PARSE is listed with the read error in error and a null state, never as a silent omission and never as the undecided draft it would otherwise be indistinguishable from

ubc agent change list [OPTIONS]

Options

--status <STATE>

Narrow the listing to one lifecycle state. A closed value set: an unknown value is refused rather than answered with an empty list, because a typo that reads as “nothing is open” is the most dangerous wrong answer this verb can give. draft and assessed are the two UNDECIDED positions and are read off the record’s own impact analysis, so a change request plan has only just written is found under draft

  • draft: Raised, nothing decided, and the impact analysis is not finished

  • assessed: The three impact links cover the computed set, and nobody has decided yet

  • approved: Authorized. The implementation may proceed

  • executed: The approved work was run (ubc agent change execute stamped it)

  • closed: Closed out (ubc agent change close stamped it). Nothing follows

  • rejected: Refused. No commit will ever carry this change

  • deferred: Assessed and put down without a verdict either way

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent change remove

Maturity:

Experimental

Without a license:

Up to 100 needs

Physically remove one or more needs from the reStructuredText they are written in. The data-loss verb of the group, so it is a chain of refusals with an excision at the end, and every check runs over the whole requested set BEFORE the first line is touched. An absent id is a named error, never a no-op. A MARKER-AUTHORED need is refused: the refusal reports the marker’s own path and line range, because those ARE known, and explains that the extent of the CODE beneath the marker is recorded nowhere, so excising a guessed block of a source file is unrecoverable. A need whose span CONTAINS another need is refused naming it, unless that need is named for removal too. Measured: deleting a need by exactly the line range audit reports also destroyed a need nested inside it, taking a project from six needs to four with release-check still reporting ok: true and an empty new_gaps. The excision goes through rst_edit::remove_spans, which plans every target against an in-memory copy and commits only once the whole set has passed, so a refusal on one id cannot leave another already gone. Each target’s guard is the header line as the FILE writes it, checked against the directive TYPE the index reports for the id. Naming the same id twice removes it once. A document the removal empties is LEFT ON DISK: deleting it could break a toctree, and that is a human decision. Leaves every edit UNCOMMITTED and runs no git

ubc agent change remove [OPTIONS] --id <NEED_ID>

Options

--id <NEED_ID>

A need id to remove. Repeatable, and repeating it is how a caller authorizes a nested removal: a need written inside another need’s body goes with it when the outer span is excised, so the outer one is refused unless the inner one is named here too

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent config-validate

Maturity:

Experimental

Without a license:

No license needed

Cross-check the [workflow] process config against the ubproject.toml ontology as JSON ({ok, errors, warnings}). A pure pre-flight: every type a stage produces / a trace edge or obligation names must be a declared [[needs.types]] directive, every referenced link a declared [needs.links.*] table, and every transition from/to state a declared lifecycle state — each mismatch an error. A status value absent from the states, a blank per-stage skill slot, and a declared type no stage produces are warnings. ok is the emptiness of errors; exits non-zero on any error. Reads ONLY the config — never builds the graph, loads needs.json, or runs a coverage gate — so it stays disjoint from native ubc config

ubc agent config-validate [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the heartbeat verbs’ --srcdir

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging options.

ubc agent doctor

Maturity:

Experimental

Without a license:

No license needed

Run the config preflight as JSON ({ok, checks:[...]}): a config-driven setup health check an agent runs BEFORE driving the loop, so it fails closed on a misconfiguration before spending a run’s tokens. The first check composes the config-validate pipeline (a config-validity error is one blocking error check, its warnings are warning checks). The remaining checks are tool probes admitted ONLY when the resolved [workflow] config requires the tool: mmdc when the diagram gate is enabled with engine mermaid/both, plantuml (plus its Java runtime) when enabled with engine plantuml/both, and codelinks when a stage configures the code-trace gate. A required-but-absent tool is a blocking error carrying a remediation fix; a tool no gate requires is not probed. ok is the absence of any error-status check (warnings never flip it) and the process exits non-zero exactly when not ok. Reads ONLY the config — never builds the graph, loads needs.json, or runs a coverage gate

ubc agent doctor [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the heartbeat verbs’ --srcdir

Configuration

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

Also takes the common Logging options.

ubc agent install

Maturity:

Experimental

Without a license:

No license needed; with --detect: up to 100 needs

Bootstrap a project into the agentic loop from a named profile preset. Scaffolds the [workflow] process configuration and ontology into ubproject.toml, installs the profile’s AI-asset bundle (skills, commands, agents) into the host integration directories, and records every owned file in the install manifest at .pharaoh/agent/install-manifest. --profile <name> selects the preset (default vmodel); an unknown name writes nothing and exits non-zero listing the available profiles. --detect grounds the configuration in the existing needs graph instead of the blank profile defaults and exits non-zero on a graphless project. Non-destructive by default; --overwrite clobbers existing files scoped to the managed set

ubc agent install [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the heartbeat verbs’ --srcdir

--profile <NAME>

Named profile preset to scaffold from (default vmodel). An unknown name writes nothing and exits non-zero listing the available profiles

Default: vmodel.

--detect

Brownfield mode: introspect the existing needs graph and ground the configuration in it instead of writing the blank profile defaults. Exits non-zero when the project has no introspectable requirement graph

--plan

Emit the derived workflow plan as JSON and write nothing (use with –detect)

--answers <FILE>

JSON map of open-question id → chosen value, applied to the derived workflow (use with –detect)

--from-needs-json <PATH>

Derive the workflow from a prebuilt needs.json instead of indexing (use with –detect)

--overwrite

Clobber existing destination files instead of skipping them, scoped to the set this command scaffolds. Non-destructive by default

--register-mcp <HARNESS_ID>

Register the ubCode MCP server with a terminal harness after installing (e.g. claude-code-cli)

Configuration

-c, --config <TOML>

Configuration override (repeatable), used only by --detect

--config-name <FILENAME>

Configuration file name to search for (used only by --detect)

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent update

Maturity:

Experimental

Without a license:

No license needed

Reconcile a previously installed project against the current preset, touching only the files the manifest records as install-owned. For each owned file it performs a three-way comparison between the preset’s current content, the recorded baseline, and the on-disk content: an unedited file is updated to the preset content, a locally edited file is PRESERVED and reported as a conflict (never blind-clobbered) unless --overwrite resolves it preset-wins. Refreshes the manifest afterwards. Exits non-zero when a conflict was not resolved by --overwrite, with the conflicts accompanying the exit

ubc agent update [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the heartbeat verbs’ --srcdir

--overwrite

Resolve conflicts in favour of the preset (preset-wins) for the manifest-owned set only, instead of preserving a locally edited owned file and reporting it as a conflict

Also takes the common Logging options.

ubc agent reverse

Reverse recovery: reconstruct the V-model left arm (user stories, requirements, architecture) from the git surface. sources reports which recovery evidence exists for a scope. plan builds the recovery work order for one stage, and prompt renders it into the prompt a recovery run is dispatched with. record writes the one ledger shard a recovery run produced (the only ledger writer). status reports the combined ledger/graph/git recovery status for a scope. forget deletes one ledger shard, and rebaseline accepts reviewed changes to recovered source files

ubc agent reverse <COMMAND>

Subcommands

  • ubc agent reverse sources: Report which recovery evidence kinds exist for a scope, plus the need-producing stages above the code anchor

  • ubc agent reverse plan: Report the recovery work order for one stage over one scope

  • ubc agent reverse prompt: Print the prompt a recovery run for one stage over one scope is dispatched with: the work order plan reports, rendered into the instruction an agent session runs

  • ubc agent reverse record: Write one .pharaoh/rev-eng/ ledger shard from a recovery run’s result. The only ledger writer

  • ubc agent reverse status: Report the combined ledger/graph/git recovery status for a scope

  • ubc agent reverse forget: Delete the one .pharaoh/rev-eng/ ledger shard recorded for --source. Never touches RST

  • ubc agent reverse rebaseline: Accept the current content of recovered source files, so their drift reads unchanged again. Never touches RST or source

ubc agent reverse sources

Maturity:

Experimental

Without a license:

Up to 100 needs

Exit codes:

These, and otherwise the general codes:

  • 3: The project configuration does not load.

Report which recovery evidence kinds exist for a scope, plus the need-producing stages above the code anchor

ubc agent reverse sources [OPTIONS] [SCOPE]

Arguments

[SCOPE]

The scope to discover recovery evidence for: a project-relative or absolute path to a source file or directory. Defaults to ., the whole project, which is what -p alone already means

Default: ..

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

--code-stage <STAGE_ID>

Workflow stage id to anchor the reverse climb at. Resolved from this flag, else the project’s [agent.reverse] code_stage, else "code", the shipped preset’s own anchor. Explicit, never inferred: the shipped preset’s code stage carries produces = "impl" (not None), so a “first stage with no produces” scan would silently find no anchor at all on the real preset

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent reverse plan

Maturity:

Experimental

Without a license:

Up to 100 needs

Exit codes:

These, and otherwise the general codes:

  • 3: The project configuration does not load.

Report the recovery work order for one stage over one scope

ubc agent reverse plan [OPTIONS] --stage <STAGE_ID> [SCOPE]

Arguments

[SCOPE]

The scope to build the recovery brief for: a project-relative or absolute path to a source file or directory. Defaults to ., the whole project, which is what -p alone already means

Default: ..

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

--stage <STAGE_ID>

The stage (a [workflow.stages] id) to build the brief for

--source <PATH_OR_ID>

The brief’s inputs: source file paths for an extraction stage, already-recovered lower-need ids for a synthesis stage, or recovered module paths for a structure stage. Repeatable. Omitting it auto-populates for EVERY stage kind. An extraction stage takes every in-scope file of any evidence kind (code, tests, docs, adrs or ci), from the same discovery reverse sources reports, except a document that already holds needs and, unless --include-recovered is passed, a source the ledger already records. A synthesis stage takes the recovered need ids the .pharaoh/rev-eng/ ledger already records in scope. A structure stage takes the modules in scope the recovered requirements came from, and only those whose recorded files include code or tests. Pass one or more --source to narrow to a subset instead

--sources-file <FILE>

Read further --source entries from FILE, one per line (blank lines are ignored). Combines with --source, which comes first. For a selection too long for the operating system’s command-line limit

--code-stage <STAGE_ID>

Workflow stage id --stage is classified relative to. Resolved from this flag, else the project’s [agent.reverse] code_stage, else "code", the shipped preset’s own anchor. Explicit, never inferred: the shipped preset’s code stage carries produces = "impl" (not None), so a “first stage with no produces” scan would silently find no anchor at all on the real preset

--include-recovered

Re-offer in-scope sources the .pharaoh/rev-eng/ ledger already records a recovery for. Off by default: an auto-populated extraction brief skips them and reports them under skipped_recovered, because re-running the extraction skill over an already-recovered file mints FRESH ids for the same behaviours and authors them into the same target document, which duplicates the requirements rather than updating them. Pass this to deliberately recover a scope again, for example after the code changed enough that the recorded needs no longer describe it. Naming files with --source is unaffected either way: an explicitly named source is always honoured

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent reverse prompt

Maturity:

Experimental

Without a license:

Up to 100 needs

Exit codes:

These, and otherwise the general codes:

  • 3: The project configuration does not load.

Print the prompt a recovery run for one stage over one scope is dispatched with: the work order plan reports, rendered into the instruction an agent session runs

ubc agent reverse prompt [OPTIONS] --stage <STAGE_ID> [SCOPE]

Arguments

[SCOPE]

The scope to build the recovery brief for: a project-relative or absolute path to a source file or directory. Defaults to ., the whole project, which is what -p alone already means

Default: ..

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

--stage <STAGE_ID>

The stage (a [workflow.stages] id) to build the brief for

--source <PATH_OR_ID>

The brief’s inputs: source file paths for an extraction stage, already-recovered lower-need ids for a synthesis stage, or recovered module paths for a structure stage. Repeatable. Omitting it auto-populates for EVERY stage kind. An extraction stage takes every in-scope file of any evidence kind (code, tests, docs, adrs or ci), from the same discovery reverse sources reports, except a document that already holds needs and, unless --include-recovered is passed, a source the ledger already records. A synthesis stage takes the recovered need ids the .pharaoh/rev-eng/ ledger already records in scope. A structure stage takes the modules in scope the recovered requirements came from, and only those whose recorded files include code or tests. Pass one or more --source to narrow to a subset instead

--sources-file <FILE>

Read further --source entries from FILE, one per line (blank lines are ignored). Combines with --source, which comes first. For a selection too long for the operating system’s command-line limit

--code-stage <STAGE_ID>

Workflow stage id --stage is classified relative to. Resolved from this flag, else the project’s [agent.reverse] code_stage, else "code", the shipped preset’s own anchor. Explicit, never inferred: the shipped preset’s code stage carries produces = "impl" (not None), so a “first stage with no produces” scan would silently find no anchor at all on the real preset

--include-recovered

Re-offer in-scope sources the .pharaoh/rev-eng/ ledger already records a recovery for. Off by default: an auto-populated extraction brief skips them and reports them under skipped_recovered, because re-running the extraction skill over an already-recovered file mints FRESH ids for the same behaviours and authors them into the same target document, which duplicates the requirements rather than updating them. Pass this to deliberately recover a scope again, for example after the code changed enough that the recorded needs no longer describe it. Naming files with --source is unaffected either way: an explicitly named source is always honoured

--evidence <KIND>

An evidence kind the requester selected for this run. Repeatable. The prompt tells the run to draw on these, resolves a commit reference only when its own kind is selected, and limits what run.sources may list

  • code

  • tests

  • docs

  • adrs

  • ci

  • commit_history

  • change_requests

  • issues

--intent-context <TEXT>

Free-text context from the requester, added to the prompt as its own section. May start with -, as a typed list does

--work-order-file <FILE>

Write the work order to FILE when it is too long to list in the prompt, and point the prompt at it. Without it the list is always inlined

--headless

State that nobody can answer the run’s questions, so it decides and reports instead of waiting. Without it the prompt says a user is there

--json

Print {brief, prompt, work_order_file} as JSON instead of the prompt text

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent reverse record

Maturity:

Experimental

Without a license:

No license needed

Write one .pharaoh/rev-eng/ ledger shard from a recovery run’s result. The only ledger writer

ubc agent reverse record [OPTIONS]

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the heartbeat verbs’ --srcdir

--input <FILE>

Path to a JSON file holding the RecoveryResult to record. Read from a file rather than argv: a recovery run’s payload (a source’s full recovered needs) can be large, and this is the shape the panel already writes (a temp file). Required unless --schema is given

--schema

Print the --input payload contract instead of recording anything. Conflicts with providing an --input

Configuration

--config-name <FILENAME>

Configuration file name to search for.

The two WRITING verbs offered no such flag while the three reading ones did, so a project driven with --config-name ubproject.dev.toml planned against one config and recorded against another.

Default: ubproject.toml.

Also takes the common Logging options.

ubc agent reverse status

Maturity:

Experimental

Without a license:

Up to 100 needs

Exit codes:

These, and otherwise the general codes:

  • 3: The project configuration does not load.

Report the combined ledger/graph/git recovery status for a scope

ubc agent reverse status [OPTIONS] [SCOPE]

Arguments

[SCOPE]

The scope to report recovery status for: a project-relative or absolute path to a source file or directory. Defaults to ., the whole project, which is what -p alone already means

Default: ..

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the Python reference’s --srcdir

--code-stage <STAGE_ID>

Workflow stage id the intent-gap climb is anchored at. Resolved from this flag, else the project’s [agent.reverse] code_stage, else "code", the shipped preset’s own anchor. Explicit, never inferred: the shipped preset’s code stage carries produces = "impl" (not None), so a “first stage with no produces” scan would silently find no anchor at all on the real preset

Configuration

-c, --config <TOML>

Configuration override (repeatable). Example: ‘lint.ignore = [“W001”]’

Environment variable: UBCODE_CONFIG_OVERRIDE.

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging, License and Processing options.

ubc agent reverse forget

Maturity:

Experimental

Without a license:

No license needed

Delete the one .pharaoh/rev-eng/ ledger shard recorded for --source. Never touches RST

ubc agent reverse forget [OPTIONS] --source <PATH>

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the heartbeat verbs’ --srcdir

--source <PATH>

The REPOSITORY-relative source path whose ledger shard to delete

Configuration

--config-name <FILENAME>

Configuration file name to search for.

The two WRITING verbs offered no such flag while the three reading ones did, so a project driven with --config-name ubproject.dev.toml planned against one config and recorded against another.

Default: ubproject.toml.

Also takes the common Logging options.

ubc agent reverse rebaseline

Maturity:

Experimental

Without a license:

No license needed

Accept the current content of recovered source files, so their drift reads unchanged again. Never touches RST or source

ubc agent reverse rebaseline [OPTIONS] <PATH>...

Arguments

<PATH>...

The source files whose current content to accept: repository-relative, or absolute inside the repository

Options

-p, --project <PATH>

Path to the project root or any file within it (defaults to cwd)

--srcdir <PATH>

Alias for --project, matching the heartbeat verbs’ --srcdir

Configuration

--config-name <FILENAME>

Configuration file name to search for

Default: ubproject.toml.

Also takes the common Logging options.