Discovering Tests, Tasks and Suites
Before you can run, filter, or report on a Robot Framework project you usually want to know what's actually in it: which suites live in which directories, what tags each test carries, which .robot files Robot would even pick up. robotcode discover answers those questions without executing a single test.
It applies the same configuration and profile pipeline that robotcode robot would use to run the project — so what discover reports is exactly what robot would see — and surfaces the result either as a human-readable tree on the terminal or as structured data for scripts, CI pipelines, and editors.
Who this is for:
- Developers opening an unfamiliar project who want a one-shot overview before drilling in.
- CI/CD pipelines that need a stable inventory of tests / tags / files for sharding, reporting dashboards, or build-time validation.
- Editor and IDE integrations — the JSON output is what the RobotCode VS Code extension consumes to build its Test Explorer view.
- AI-driven workflows — coding agents (Claude Code, Cursor, Copilot, …), inventory analyses, test-selection assistants. Letting the agent grep through a tree of
.robotfiles is wasteful;discoverreturns just the slice the agent asked for (a tag list, a file list, the test tree under one path). - Test-selection scripts that build
-bl/--by-longnamelists forrobotcode robot— pre-filtering tests for sharded CI matrices, regression sets, or scheduled smoke runs.
Typical things you can do with it:
- get a tree view of every suite, sub-suite, test and task the active profile would discover
- list just the tests (or just the tasks) one per line, with source paths and tags
- list every distinct tag in the project with the tests it tags
- list the metadata names and values in use — of tests and tasks (Robot Framework 7.5+) and of suites — with the items that carry them
- list the
.robotand.resourcefiles of the project, honouring.gitignore/.robotignore - check the Robot Framework version, Python version and environment the tooling is running under
The eight subcommands share the same configuration, search, and output-format pipeline — once you've learned one the others follow:
| Subcommand | Use it when you want to … |
|---|---|
all |
… see the whole tree (workspace → suite → sub-suite → test/task) |
tests |
… list tests one per line (typed test) |
tasks |
… list tasks one per line (typed task, RPA mode) |
suites |
… list suites only — no per-test rows |
tags |
… build a tag → [tests] index for triage or dashboards |
metadata |
… see which metadata names and values are in use, and where (Robot Framework 7.5+) |
files |
… list every .robot / .resource file not excluded by .gitignore / .robotignore |
info |
… check the active Robot / Python / RobotCode versions and environment |
This guide is split in two:
- Part 1 — Using the commands walks through every subcommand from the terminal perspective: what it does, what shows up on the screen, and what filters and flags are available.
- Part 2 — JSON reference documents the structured output for scripts, CI pipelines, and editor integrations — the JSON schema of every subcommand plus jq-based recipes.
For the exhaustive option list see the auto-generated CLI reference.
Quick start
Section titled “Quick start”# Workspace tree — every suite, every test, with tagsrobotcode discover all
# Flat list of tests, one per linerobotcode discover tests
# Just the test names matching "Login", in the current profile's scoperobotcode discover tests --search Login
# A tag → tests dictionaryrobotcode discover tags
# Metadata names and values of tests and suites (Robot Framework 7.5+)robotcode discover metadata --values
# Every test for issue 4409 (Robot Framework 7.5+)robotcode discover tests --by-test-metadata Issue:4409
# Which source files would Robot even parse?robotcode discover files
# Active Robot / Python / RobotCode versions + environmentrobotcode discover infoIf you don't pass paths or filters, discover falls back to the default paths from your active robot.toml profile — the same logic robotcode robot uses.
How discover finds your project
Section titled “How discover finds your project”discover runs the same configuration pipeline as robotcode robot:
- Profile resolution.
robot.tomlis loaded and combined with any--profileselectors. The resulting profile contributes the default paths (paths = [...]), variables, library paths, and any other Robot Framework settings. - Argument layering. Positional
ROBOT_OPTIONS_AND_ARGSyou pass on the command line are appended after the profile's settings — Robot's normal precedence rules apply. Sorobotcode discover tests --include smoke ./tests/loginpicks up the profile'spathsunless you give explicit paths (then those win), and adds--include smokeon top of any profile-level includes. - Static parsing only.
discovernever executes a keyword. It walks the suite tree the same way Robot's--dryrunwould but stops earlier — at parse time. Library imports, variable files, listeners, and pre-run modifiers are loaded only as far as needed to resolve the tree.
If you want to discover something outside your profile (a one-off file, a specific directory), pass it as a positional argument:
robotcode discover tests path/to/suite.robotrobotcode discover all path/to/dir/ path/to/other/You can also pass any standard robot argument through — --include, --exclude, --suite, --test, --variable, --pythonpath, … See Robot-native filters below.
Output formats
Section titled “Output formats”The default TEXT output is meant for humans reading in a terminal — colourised, paginated. For pipelines, scripts, editor integrations, and AI agents, the global -f/--format flag — set before the subcommand — switches to a stable structured format:
robotcode discover all # default: human-readable TEXTrobotcode --format json discover all # compact JSON, one linerobotcode --format json_indent discover all # pretty-printed JSONrobotcode --format toml discover all # TOMLIf you only ever look at terminal output, the following sections cover everything you need. For the JSON shape of any subcommand, jump to the JSON reference.
Pager and colour handling is identical to results — see Pager and colour for the details.
all — the full tree
Section titled “all — the full tree”all prints the complete hierarchy the active profile resolves to: the workspace root, every suite and sub-suite below it, and every test or task inside those suites. It's the closest thing to "show me what's in this project".
robotcode discover allrobotcode discover all ./tests/login # restrict to a pathrobotcode discover all --include smoke # restrict to a tagSample output:
# All
- **MyProject** (`.`) - **MyProject.Tests** (`tests`) - **MyProject.Tests.Checkout** (`tests/checkout`) - **MyProject.Tests.Checkout.Test Checkout** (`tests/checkout/test_checkout.robot`) - **MyProject.Tests.Checkout.Test Checkout.Empty Cart** (`tests/checkout/test_checkout.robot:8`) - **MyProject.Tests.Login** (`tests/login`) - **MyProject.Tests.Login.Test Login** (`tests/login/test_login.robot`) - **MyProject.Tests.Login.Test Login.Bad Password** (`tests/login/test_login.robot:14`) - _Tags:_ `regression`, `smoke` - _Metadata:_ Author: Hans Müller, Issue: 4409 - **MyProject.Tests.Login.Test Login.Good Password** (`tests/login/test_login.robot:22`) - _Tags:_ `smoke` - _Metadata:_ Issue: 4410…
## Statistics
- _Suites:_ 8- _Suites with tests:_ 3- _Tests:_ 4Flag reference
Section titled “Flag reference”| Flag | Effect |
|---|---|
--show-tags / --no-show-tags |
Show or hide the Tags: line under each test/task. Default: on. |
--show-metadata / --no-show-metadata |
Show or hide a Metadata: line (name: value, …) under each test/task that has [Metadata] (Robot Framework 7.5+). Default: on. |
--full-paths / --no-full-paths |
Absolute source paths. Default: relative to the project root. |
--search TEXT / --search-regex PATTERN |
Prune the tree to tests matching the pattern; surviving tests keep their full ancestor chain. See Search. |
-bl NAME / -ebl NAME |
Include/exclude tests, tasks or suites by exact long name. See Robot-native filters. |
any standard robot flag |
--include, --exclude, --suite, --test, --variable, --pythonpath, … passed through to the discovery pipeline. |
A test or task that has [Metadata] is followed by one line listing all its entries (hide it with --no-show-metadata) — in the raw markdown output - _Metadata:_ Issue: 4409, Owner Team: core. Names keep the spelling from the source file; the lines of a multi-line value are joined with a space. Test metadata exists since Robot Framework 7.5; with an older version installed, --help does not list the flag and passing it has no effect. The same flag is available on tests and tasks, where it is off by default, like --show-tags.
A diagnostics footer is added to TEXT output when parsing emits warnings or errors (deprecated section headers, duplicate test names, unparseable files). In JSON they land in the diagnostics field — see diagnostics.
tests — flat list of tests
Section titled “tests — flat list of tests”tests collapses the hierarchy: one row per test, with full long name and source location. The natural input for scripts that need a list of test identifiers.
robotcode discover testsrobotcode discover tests --show-tags # add a `Tags: ...` line per testrobotcode discover tests --show-metadata # add a `Metadata: ...` line per test (RF 7.5+)robotcode discover tests --include smoke # filter by tagrobotcode discover tests --search "Login" # substring searchrobotcode discover tests path/to/suite.robot # one suite onlySample output:
# Tests
- **MyProject.Tests.Checkout.Test Checkout.Empty Cart** (`tests/checkout/test_checkout.robot:8`)- **MyProject.Tests.Login.Test Login.Bad Password** (`tests/login/test_login.robot:14`)- **MyProject.Tests.Login.Test Login.Good Password** (`tests/login/test_login.robot:22`)…
## Statistics
- _Suites:_ 8- _Suites with tests:_ 3- _Tests:_ 4Flag reference
Section titled “Flag reference”| Flag | Effect |
|---|---|
--show-tags / --no-show-tags |
Include a Tags: line per test. Default: off (tests are always one-line in TEXT). |
--show-metadata / --no-show-metadata |
Include a Metadata: line (name: value, …) per test that has [Metadata] (Robot Framework 7.5+). Default: off. |
--full-paths / --no-full-paths |
Absolute source paths. |
--search TEXT / --search-regex PATTERN |
Filter by name/source/body/tags. |
-bl NAME / -ebl NAME |
Long-name include/exclude. |
any standard robot flag |
Pass-through. |
Tasks defined with *** Tasks *** are intentionally not in this list — use tasks for those.
tasks — flat list of tasks
Section titled “tasks — flat list of tasks”tasks is the RPA twin of tests: one row per task. The TEXT output and flag set mirror tests; only the heading differs (# Tasks).
robotcode discover tasksrobotcode discover tasks --show-tagsIn a mixed-mode suite (rare — Robot doesn't recommend it), tests shows the *** Test Cases *** half and tasks shows the *** Tasks *** half. A project where the active robot.toml profile sets rpa = true puts everything under tasks.
suites — flat list of suites
Section titled “suites — flat list of suites”suites lists every suite the active profile resolves, one per line, no per-test detail. Useful when you want to know which suites exist without scrolling past hundreds of tests, or to build a suite-by-suite shard plan for CI.
robotcode discover suitesrobotcode discover suites --include smoke # only suites with a smoke testSample output:
# Suites
- **MyProject** (`.`)- **MyProject.Tests** (`tests`)- **MyProject.Tests.Checkout** (`tests/checkout`)- **MyProject.Tests.Checkout.Test Checkout** (`tests/checkout/test_checkout.robot`)- **MyProject.Tests.Login** (`tests/login`)- **MyProject.Tests.Login.Test Login** (`tests/login/test_login.robot`)- **MyProject.Tests.Search** (`tests/search`)- **MyProject.Tests.Search.Test Search** (`tests/search/test_search.robot`)
## Statistics
- _Suites:_ 8- _Suites with tests:_ 3- _Tests:_ 4A suite with no surviving tests after filtering disappears from the list — --include smoke against a suite where nothing is tagged smoke will drop that suite.
tags — tag → tests dictionary
Section titled “tags — tag → tests dictionary”tags builds an index of every distinct tag in the discovered suite tree. The default TEXT output is the tag list alone; --tests and --tasks expand each tag with the tests / tasks it covers.
robotcode discover tags # just the tagsrobotcode discover tags --tests # tag → tests, indentedrobotcode discover tags -i smoke # tags appearing in the smoke subsetrobotcode discover tags --not-normalized # keep the original tag spellingSample output (--tests):
# Tags
- **regression** - **MyProject.Tests.Login.Test Login.Bad Password** (`tests/login/test_login.robot:14`)- **smoke** - **MyProject.Tests.Login.Test Login.Bad Password** (`tests/login/test_login.robot:14`) - **MyProject.Tests.Login.Test Login.Good Password** (`tests/login/test_login.robot:22`)
## Statistics
- _Suites:_ 8- _Suites with tests:_ 3- _Tests:_ 4Flag reference
Section titled “Flag reference”| Flag | Effect |
|---|---|
--normalized / --not-normalized |
Whether tag keys are normalised (lowercase, no whitespace, no underscore). Default: on. Bug 1 / bug_1 / BUG1 collapse to a single bug1 entry; with --not-normalized the three variants stay separate. |
--tests / --no-tests |
Add the tests carrying each tag. Default: off. |
--tasks / --no-tasks |
Add the tasks carrying each tag. Default: off. |
--full-paths |
Absolute source paths in the expanded child rows. |
--search TEXT / --search-regex PATTERN |
Filter the underlying test set first; only tags surviving on at least one matching test appear. |
-bl / -ebl / any robot flag |
Pass-through. |
Normalisation in practice
Section titled “Normalisation in practice”The --normalized default matches Robot Framework's own tag-matching semantics: --include "bug 1" matches tests tagged bug_1 or BUG1. Disable it (--not-normalized) when you want to audit tag hygiene — three distinct dict keys for Bug 1 / bug_1 / BUG1 make accidental variants pop.
metadata — metadata index
Section titled “metadata — metadata index”metadata builds an index of the metadata in the discovered suite tree, in two sections: the [Metadata] of tests and tasks (Robot Framework 7.5+), and the Metadata of suites, including metadata you give Robot with --metadata NAME:VALUE. The default TEXT output lists the names; --values adds the values of each name, and --tests, --tasks and --suites add the items that carry them.
robotcode discover metadata # the names in userobotcode discover metadata --values # … with their valuesrobotcode discover metadata --values --tests # … and the tests under each valuerobotcode discover metadata -i smoke --values # the metadata of the smoke subsetSample output (--values --tests --suites, raw markdown):
# Metadata
## Tests and Tasks
- **Author** - Hans Müller - **MyProject.Tests.Login.Test Login.Bad Password** (`tests/login/test_login.robot:14`)- **Issue** - 4409 - **MyProject.Tests.Login.Test Login.Bad Password** (`tests/login/test_login.robot:14`) - 4410 - **MyProject.Tests.Login.Test Login.Good Password** (`tests/login/test_login.robot:22`)
## Suites
- **Version** - 1.2 - **MyProject.Tests.Login.Test Login** (`tests/login/test_login.robot`)How the index is built:
- The test section lists exactly the entries
--by-test-metadatamatches: every line of a multi-line value is a value of its own, while the cells of one[Metadata]row stay one value. Every value it shows can be selected with--by-test-metadata Name:Value. - Suite metadata is shown in its own section, but not selectable:
--by-test-metadatamatches a test's own metadata only. - Names that Robot Framework treats as the same — case, spaces and underscores are ignored — are one name, shown in the first spelling found; values are grouped the same way. Names and values are sorted.
- Values are shown as written; variables in them are not replaced.
- Robot's filters,
-bl/-ebl,-btm/-ebtmand--searchnarrow the discovered tests and suites first, as fortags. When nothing is left, the output says(no metadata matched).
Flag reference
Section titled “Flag reference”| Flag | Effect |
|---|---|
--values / --no-values |
Add the values of each name. Default: off. |
--tests / --no-tests |
Add the tests under each value, or under each name without --values. Default: off. |
--tasks / --no-tasks |
Add the tasks, like --tests. Default: off. |
--suites / --no-suites |
Add the suites under the values of the suite section. Default: off. |
--full-paths |
Absolute source paths in the item rows. |
--search TEXT / --search-regex PATTERN |
Filter the underlying tests first. |
-bl / -ebl / -btm / -ebtm / any robot flag |
Pass-through. |
files — flat list of source files
Section titled “files — flat list of source files”files lists every .robot and .resource file in the given paths (or the profile's default paths), honouring .gitignore / .robotignore. Files and folders whose names start with _ are listed too, although Robot Framework skips them when it collects suites.
robotcode discover files # respects profile pathsrobotcode discover files ./tests ./resources # explicit directoriesrobotcode discover files --search "checkout" # filename substring filterSample output:
# Files
- `tests/login/test_login.robot`- `tests/checkout/test_checkout.robot`- `tests/search/test_search.robot`
_Total:_ 3 file(s)Files under directories ignored by .gitignore / .robotignore are excluded automatically. Use this when you need to feed a list of files into another tool (linter, formatter, custom pre-commit hook).
Flag reference
Section titled “Flag reference”| Flag | Effect |
|---|---|
--full-paths / --no-full-paths |
Absolute paths. Default: relative to the project root. |
--search TEXT / --search-regex PATTERN |
Filter by path/filename substring or regex. |
info — environment and version
Section titled “info — environment and version”info reports the versions and platform robotcode is running under — useful for bug reports, CI metadata, and "does this build have the right Robot version" checks.
robotcode discover inforobotcode --format json discover infoTEXT output:
# Info
- _Robot Framework:_ 7.5- _RobotCode:_ 2.7.0- _Python:_ 3.13.12- _Executable:_ .venv/bin/python- _Machine:_ x86_64- _Platform:_ linux- _System:_ Linux…Set ROBOT_OPTIONS, ROBOT_SYSLOG_FILE, ROBOT_SYSLOG_LEVEL or ROBOT_INTERNAL_TRACES and they're echoed back under robotEnv, so you can verify the run environment matches expectations.
Robot-native filters
Section titled “Robot-native filters”Every discover subcommand (except info and files) passes through to Robot Framework's own filtering machinery. Anything you'd write on a robot command line works here:
| Flag | Effect |
|---|---|
-i / --include TAG_PATTERN |
Include tests with a matching tag. Supports Robot's AND/OR/NOT syntax and globs (*, ?). |
-e / --exclude TAG_PATTERN |
Exclude tests with a matching tag. |
-s / --suite NAME |
Limit to suites whose name matches the glob. |
-t / --test NAME |
Limit to tests whose name matches the glob (--task is the RPA alias). |
-bl / --by-longname NAME |
Exact long-name include — no glob expansion. |
-ebl / --exclude-by-longname NAME |
Exact long-name exclude. |
-btm / --by-test-metadata PATTERN |
Tests/tasks whose [Metadata] matches the pattern (Robot Framework 7.5+) — see Selecting by test metadata. |
-ebtm / --exclude-by-test-metadata PATTERN |
Exclusion side of --by-test-metadata (Robot Framework 7.5+). |
--variable NAME:VALUE, --pythonpath PATH, … |
Anything else Robot accepts. |
Filters compose — --include smoke --exclude wip means "smoke and not wip".
--by-longname vs --suite / --test
Section titled “--by-longname vs --suite / --test”-s/-tare glob matches.-bl/-eblare exact matches against the full long name. They mirrorrobotcode robot --by-longnameso you can hand the same names torobotanddiscover.
Use -bl when you have a precise name (often pasted from a failure list or a build log); use -s/-t when you want pattern matching.
Selecting by test metadata
Section titled “Selecting by test metadata”-btm/--by-test-metadata PATTERN and -ebtm/--exclude-by-test-metadata PATTERN (Robot Framework 7.5+) select tests and tasks by their [Metadata]: the issue a test verifies, who wrote or reviewed it, and other data you keep there rather than in tags. Both are repeatable. Several --by-test-metadata patterns select the tests matching any of them, --exclude-by-test-metadata removes every test matching one, and both narrow every other selection (--include, --suite, -bl, --search, …). They work the same with robotcode robot, robotcode robot-debug, every discover subcommand except files and info, and every results subcommand.
robotcode discover tests --by-test-metadata Issue:4409 # every test for issue 4409robotcode discover tests -btm "Author:Hans* OR Reviewer:Hans*" # written or reviewed by Hansrobotcode discover tests -btm "Author:Hans* NOT Reviewer:*" # by Hans, not reviewed yetrobotcode discover tests -ebtm "Owner:*" # tests without an ownerrobotcode robot -i smoke -btm Issue:4409 # run the smoke tests for issue 4409Pattern rules
Section titled “Pattern rules”A pattern is one or more terms NAME:VALUE, combined like a tag pattern:
- A test is matched by its entries,
Name:Value, one for every line of every metadata value. A term matches when it matches one of the entries. *,?and[…]work as in tag patterns:Issue:44*,*:4409(4409 in any metadata),Owner:*(anyOwner, also one without a value). For a literal[, write[[].- Case, spaces and underscores are ignored on both sides, so names compare the way Robot Framework compares metadata names:
owner_team:corematchesOwner Team: core. AND,ORandNOTcombine terms. As in Robot's tag patterns,ANDbinds beforeORandNOTlast:A OR B AND CmeansA OR (B AND C), andA NOT B NOT Cmatches whenAmatches and neitherBnorCdoes. A pattern that starts withNOTmatches every test that doesn't match the rest.- An operator is only a word of its own, in upper case with whitespace or the start or end of the pattern around it. So
Issue:CORE-123,Issue:ANDROID-5andAuthor:NORBERTstay literal, while Robot Framework 7.5 would read the same text as a tag pattern asIssue:C OR E-123and so on. - To match an operator word inside a value, write it in lower case:
Title:rock and rollmatchesRock AND Roll.
Several values of one name
Section titled “Several values of one name”Every line of a value is an entry of its own, so write several values of one name as continuation lines:
*** Test Cases ***Transfer Money [Metadata] Issue 4409 ... 5769 Transfer 100 EURIssue:4409 and Issue:5769 both select this test. Several cells in one row ([Metadata] Issue 4409 5769) stay one value: Robot Framework joins them keeping the separator of the source, so they can't be told apart from spaces inside a value. Issue:4409 doesn't select such a test; Issue:4409* does.
What is matched
Section titled “What is matched”- Only a test's own
[Metadata]. A suite'sMetadata, including metadata given with--metadata, is not part of its tests' entries;discover metadatalists it in its own section. - The values as the model holds them. Variables are replaced only when a test runs, so
robotanddiscoversee${BUILD}in[Metadata] Build ${BUILD}, whileresultssees the value the run used — as with tags.
Invalid patterns
Section titled “Invalid patterns”A term without : (Issue) or an operator without a term on one side (Issue:4409 AND) makes the pattern invalid. The command fails with an error that names the pattern and doesn't run or list anything.
With plain robot and in robot.toml
Section titled “With plain robot and in robot.toml”The selection is done by the pre-run modifiers robotcode.modifiers.ByTestMetadata and robotcode.modifiers.ExcludedByTestMetadata from the robotcode-modifiers package. They also work with plain robot; separate the pattern from the modifier name with ;, because the pattern contains ::
robot --prerunmodifier "robotcode.modifiers.ByTestMetadata;Issue:4409" testsIn robot.toml, a profile selects by metadata through pre-run-modifiers; RobotCode uses ; there on its own:
[profiles.issue-4409]pre-run-modifiers = { "robotcode.modifiers.ByTestMetadata" = ["Issue:4409"] }Given an invalid pattern, the modifiers report the error and select no test. Robot Framework would otherwise skip a modifier it cannot create and run every test.
Search
Section titled “Search”--search and --search-regex are mutually exclusive (passing both is a usage error). They prune the discovered tree to tests matching the pattern; surviving tests keep their full ancestor chain so discover all --search Login still shows MyProject → Tests → Login → Test Login → Bad Password with sibling suites pruned.
The search applies across:
- the test's
nameand full long name - the test's
sourcepath - the test's
[Documentation],[Template]and[Timeout] - the test's tags (Robot's normalisation rules apply)
- the test's
[Metadata]names and values (Robot Framework 7.5+) - every keyword call's name, arguments and assigned variables inside the test body
- FOR/WHILE/IF conditions, VAR/RETURN values, EXCEPT patterns, GROUP names
- any ancestor suite's
DocumentationorMetadata— a hit on a suite-level field keeps every test underneath it
| Flag | Semantics |
|---|---|
--search TEXT |
Case-insensitive substring match. No metacharacters; [ and * are literal. |
--search-regex PATTERN |
Python regex, case-sensitive by default. Prefix with (?i) for case-insensitive matching. |
Tag targets are matched with normalisation (lowercase, whitespace and underscores ignored), so --search "bug 1" matches tests tagged bug_1, Bug1, or BUG 1. All other targets are matched literally.
robotcode discover tests --search "Login"robotcode discover all --search-regex 'Login.*(Bad|Good)'robotcode discover tests --search-regex '(?i)checkout'robotcode discover tags --search smokerobotcode discover files --search "_keywords"Highlighting in the terminal
Section titled “Highlighting in the terminal”Matches are marked as inline code in the TEXT output so they're easy to scan. Structured output (JSON/TOML) is unchanged — searching only filters, it doesn't add markup.
Search on tags and files
Section titled “Search on tags and files”--search works on these too:
tagsfilters the underlying tests first; tag keys whose tests are all dropped disappear from the dictionary. Sodiscover tags --search Loginis "what tags are involved in the Login subset".filesmatches the filename / path itself — no body inspection. Sodiscover files --search "_keywords"is "every file whose path contains_keywords".
Invalid patterns
Section titled “Invalid patterns”An unparseable regex (e.g. [unclosed) yields a usage error pinpointing where the pattern failed to compile. The command exits non-zero before parsing any suite.
Tips for terminal use
Section titled “Tips for terminal use”- TEXT output is markdown. On a coloured TTY the markdown is rendered to themed ANSI via
rich(and paged if longer than your terminal); on pipes or with--no-colorthe raw markdown goes through verbatim — paste it into a PR description, a Slack message, or feed it straight to an LLM. - Quote your globs.
--suite "*.Login.*"and--test "Test ?"need quotes so the shell doesn't expand them against the local filesystem first. -blis for exact names,-tis for patterns. When you copy a test long-name out of another tool's output,-blis usually what you want — no need to escape glob characters.- Pre-filter before piping into
robot.robotcode -f json discover tests --include smoke | jq -r '.items[].longname'gives you a stable list of long names you can hand back torobotcode robot -bl ...for sharded CI runs. - Parse errors don't stop discovery. Files with syntax errors still appear in the tree; their problems land in the
diagnosticsfield. Pipe through--format jsonand check.diagnosticsfor build-time gating.
JSON reference
Section titled “JSON reference”When you set -f json (or -f json_indent for pretty-printed, or -f toml) between robotcode and the subcommand, every discover command emits structured data instead of the terminal-formatted text. This is what CI pipelines, scripts, editor integrations, and AI agents consume.
robotcode --format json discover allrobotcode --format json discover tests --include smokerobotcode --format json discover tags --testsSchema rules
Section titled “Schema rules”A few rules hold across every subcommand:
- camelCase keys.
relSource,supportsParseInclude,robotVersionString, etc. - Optional fields are omitted, not
null. Anullliteral never appears. If a field has no value (a test with no tags), the key is simply absent. - Empty array ≠ missing field. A field listed in the schema may be
[]if the section "exists but is empty"; a field absent entirely means the section wasn't computed for this run.// []in jq smooths over the difference. - Stability. Fields are appended over time, never renamed or removed in place. Existing consumers keep working.
TestItem — the common shape
Section titled “TestItem — the common shape”Every subcommand that returns tests/tasks/suites uses the same TestItem schema:
{ "type": "test", "id": "/abs/path/tests/login/test_login.robot;MyProject.Tests.Login.Test Login.Bad Password;14", "name": "Bad Password", "longname": "MyProject.Tests.Login.Test Login.Bad Password", "lineno": 14, "uri": "file:///abs/path/tests/login/test_login.robot", "relSource": "tests/login/test_login.robot", "source": "/abs/path/tests/login/test_login.robot", "tags": ["regression", "smoke"], "metadata": { "Author": "Hans Müller", "Issue": "4409" }, "range": { "start": { "line": 13, "character": 0 }, "end": { "line": 13, "character": 0 } }, "children": [ /* nested TestItems for type=suite/workspace */ ], "error": "Parse error message (when this item failed to parse)", "rpa": false}Field notes:
typeis one of"workspace","suite","test","task".workspaceis the synthetic root that wraps the actual project directory.idis a stable identifier (source;longname;linenofor tests/tasks;source;longnamefor suites). Editor integrations use this to track whichTestItemcorresponds to which on-disk artefact across reloads.linenois 1-based;range.start.line/range.end.lineare 0-based (LSP convention). Both refer to the same line of source.uriis afile://URI of the source file — same format the Language Server Protocol uses.tagsare normalised (Bug 1,bug_1,Bug1all come through as"bug1") and only present when the item has at least one tag.metadatais the[Metadata]of a test or task (Robot Framework 7.5+) as a name → value object. Names keep the spelling from the source file and values come through verbatim, the lines of a multi-line value joined with\n. A[Metadata]setting with nothing after it is no metadata and is left out. The key is absent when the test has no metadata and on Robot Framework versions older than 7.5;suiteandworkspaceitems never carry it. The--show-metadataflag is render-only for TEXT mode — it doesn't affect the JSON.descriptionis declared in the schema, butdiscovernever sets it, so the key does not appear in the output. A test's[Documentation]is not part of the item.childrenis the nested-tree field — present on theworkspaceitem and on thesuiteitems ofdiscover all([]when a suite is empty), absent ontest/taskitems.discover suiteslists its suites without it.rangefollows the LSPRangeshape so editors can highlight the source span.
all / tests / tasks / suites JSON
Section titled “all / tests / tasks / suites JSON”All four subcommands wrap their items in a ResultItem:
{ "items": [ /* TestItem(s) */ ], "diagnostics": { /* see below */ }, "filtersApplied": { "search": "Login" }, "supportsParseInclude": true}Per subcommand:
all—itemshas exactly one entry: theworkspaceroot, whosechildrenis the suite tree.tests/tasks—itemsis a flat list oftest/taskentries respectively.suites—itemsis a flat list ofsuiteentries (no children — drill into the source files separately if you want per-suite tests).
filtersApplied is optional and absent when unused. diagnostics is always present — an empty object {} when nothing fired.
supportsParseInclude is true when the project's Robot Framework version supports the --parseinclude (-I) option (RF ≥ 6.1). It is a property of the discovery environment, not of any single item, so it lives on the result envelope. Editor integrations use it to decide whether to pass -I when running a subset of tests. Omitted (treat as false) for RF < 6.1.
tags JSON
Section titled “tags JSON”{ "tags": { "bug1": [ /* TestItems carrying this tag */ ], "smoke": [ /* … */ ] }, "filtersApplied": { "search": "Login" }}Field notes:
tagsis always an object — possibly empty{}if no tag survived the filter chain.- Keys are tag names; normalised by default, original spellings preserved with
--not-normalized. - Each value is an array of
TestItemobjects (the tests / tasks carrying that tag). - A test with
ntags appears innentries.
metadata JSON
Section titled “metadata JSON”{ "metadata": { "Issue": { "4409": [ /* TestItems of the tests and tasks with this value */ ], "4410": [ /* … */ ] } }, "suiteMetadata": { "Version": { "1.2": [ /* suite TestItems */ ] } }}Field notes:
metadataholds the test and task metadata (Robot Framework 7.5+),suiteMetadatathe suite metadata. Both are always objects, possibly empty{}; on Robot Framework versions older than 7.5,metadatais always{}.- Keys are names in the first spelling found. Below each name, every value — one per line of a multi-line value — maps to the items that have it; an item is listed once per value.
- Items are
TestItems. Suite items carry nometadatafield. The JSON doesn't depend on--values,--tests,--tasksor--suites. - Every test for an issue:
robotcode -f json discover metadata | jq -r '.metadata.Issue["4409"][]?.longname'.
files JSON
Section titled “files JSON”[ "tests/login/test_login.robot", "tests/login/resources/login_keywords.resource", "tests/checkout/test_checkout.robot"]files is a plain JSON array of path strings — relative to the project root by default, absolute with --full-paths. No wrapper object, no per-file metadata. If you need richer info, use discover all and walk the tree.
info JSON
Section titled “info JSON”{ "robotVersionString": "7.5", "robotEnv": { "ROBOT_OPTIONS": "--include smoke" }, "robotcodeVersionString": "2.7.0", "pythonVersionString": "3.13.12", "executable": ".venv/bin/python", "machine": "x86_64", "processor": "x86_64", "platform": "linux", "system": "Linux", "systemVersion": "#1 SMP …"}Field notes:
robotEnvechoes back any ofROBOT_OPTIONS,ROBOT_SYSLOG_FILE,ROBOT_SYSLOG_LEVEL,ROBOT_INTERNAL_TRACESthat were set, and is absent (or{}) when none of them are.
diagnostics
Section titled “diagnostics”When parsing a file produces a warning or error (deprecated syntax, duplicate test names, unparseable file …), discover all/tests/tasks/suites reports it as an LSP-style diagnostic keyed by the source's file:// URI:
"diagnostics": { "file:///abs/path/parse_error.robot": [ { "range": { "start": { "line": 13, "character": 0 }, "end": { "line": 13, "character": 0 } }, "message": "Singular section headers like '*** Keyword ***' are deprecated. Use plural format like '*** Keywords ***' instead.", "severity": 2, "code": "discover", "source": "robotcode.discover" } ]}Field notes:
severityfollows LSP's enum:1= Error,2= Warning,3= Information,4= Hint.- A file whose parser failed entirely still contributes whatever tests Robot could recover; the unrecoverable parts come through here.
diagnosticsis an empty object{}when nothing fired.
filtersApplied
Section titled “filtersApplied”Every subcommand that accepts search flags includes a filtersApplied field when one was set:
"filtersApplied": { "search": "Login"}"filtersApplied": { "search-regex": "(?i)login"}The Robot-native filters (--include, --exclude, --suite, --test, -bl, -ebl) are not echoed here — they're handed straight to Robot Framework's filter pipeline and the effect is visible in the surviving items set.
CI recipes
Section titled “CI recipes”A grab-bag of jq-based recipes. Pin -f json between robotcode and the subcommand to lock the format.
Build a shard plan
Section titled “Build a shard plan”# List of suite long names → fed into a CI matrixrobotcode --format json discover suites \ | jq -r '.items[].longname'
# Long names of every smoke testrobotcode --format json discover tests --include smoke \ | jq -r '.items[].longname'Fail the build on parse errors
Section titled “Fail the build on parse errors”robotcode --format json discover all \ | jq -e '(.diagnostics // {}) | map(.[] | select(.severity == 1)) | length == 0'List every file the test pipeline would touch
Section titled “List every file the test pipeline would touch”robotcode --format json discover files | jq -r '.[]'Build a tag report
Section titled “Build a tag report”# tag → count of tests carrying itrobotcode --format json discover tags \ | jq '.tags | map_values(length)'
# Tags with fewer than 3 tests (candidates for cleanup)robotcode --format json discover tags \ | jq '.tags | to_entries | map(select(.value | length < 3)) | from_entries'Check the Robot version in CI
Section titled “Check the Robot version in CI”robotcode --format json discover info | jq -r .robotVersionStringFind tests touched by a specific keyword
Section titled “Find tests touched by a specific keyword”# Every test whose body calls `Open Browser`robotcode --format json discover tests --search "Open Browser" \ | jq -r '.items[].longname'For the per-flag reference, see the auto-generated CLI reference.
Released under the Apache-2.0. Copyright © 2022-present Daniel Biehl