Features
- analyze: Add --code filter to code subcommand (4bfc339)
--code restricts the result to the given diagnostic codes (e.g.
KeywordNotFound), repeatable and comma-separated, matched
case-insensitively like the modifiers. Unlike -mi "*" + re-include, it
filters without changing the severity of what remains. It affects the
output, summary and exit code, and combines with --severity using AND.
- analyze: Add --severity filter to code subcommand (f565c16)
--severity restricts the analysis result to the listed severities
(repeatable and comma-separated; error/warn/info/hint). Filtered-out
severities are dropped from the output, the summary counts and the exit
code alike, so all three stay consistent. It's orthogonal to
--exit-code-mask (which only masks the exit code) and complements the
diagnostic modifiers (which remap rather than filter).
- analyze: Add SARIF, GitHub and GitLab output formats (7103836)
robotcode analyze code gains a local --output-format flag (overrides
the global --format for this command) with these values:
concise(default): the human-readable text outputjson/json-indent: structured result (diagnostics + summary)sarif: SARIF 2.1.0 log for GitHub code scanning and other consumersgithub: GitHub Actions workflow annotations (::error file=...)gitlab: GitLab Code Quality report (JSON array)
--output-file FILE writes the report to a file instead of stdout (for
the json/json-indent/sarif/github/gitlab formats), which is handy for CI
artifact upload. A missing target directory raises a clear UsageError and
other I/O errors surface as a ClickException instead of a traceback.
Mapping details shared across the machine formats:
- LSP 0-based ranges become the 1-based positions SARIF/GitHub expect
- severities collapse onto each format's levels (e.g. SARIF error/warning/ note, GitHub error/warning/notice, GitLab major/minor/info)
- artifact paths are POSIX and relative to the project root (what the CI
integrations expect);
--full-pathsswitches to absolute paths - SARIF and GitLab results carry a stable fingerprint (independent of line number) so alerts survive unrelated edits
-
GitHub property/message values are escaped per the @actions/toolkit rules
-
analyze: Add JSON output and --full-paths to code subcommand (fc76cf3)
robotcode --format json analyze code (and --format json_indent) now
emit a structured result instead of falling back to plain text:
diagnostics: a map of source path to LSP diagnostics, using the same shape as thediscover/resultscommands so editor and CI integrations can reuse their parsers. Workspace-level diagnostics key on ".".summary: file count and per-severity totals.
The JSON always carries the full diagnostic message (tracebacks included);
--show-tracebacks only affects the text output.
New --full-paths/--no-full-paths flag (mirroring discover) switches
between root-relative and absolute paths in both text and JSON output.
JSON keys are always rendered POSIX-style for cross-platform stability.
-
analyze: Polish code subcommand output (1049b79)
-
Output is now sorted by (file, line, column) so warnings and errors appear in source order instead of mixed by analyzer pass.
- Severity is rendered as a full word, e.g.
[ERROR]instead of[E], matching the convention from Robocop, ruff, mypy and friends. - Robot Framework's appended Python tracebacks and PYTHONPATH dumps are
no longer printed by default; the new
--show-tracebacksflag opts back into the full message. - Multi-line diagnostic messages (e.g.
MultipleKeywordslisting the alternative names) are re-indented with a consistent prefix. -
Related-information entries are prefixed with
->to set them apart visually, and they fall back to(see related location)when Robot Framework provides no secondary message. -
cli: Detect GitHub Copilot agent sessions (dbc5603)
Adds two markers to the AI-agent auto-detection so terminal commands invoked from Copilot get the same clean-output defaults (no color, no pager, REPL plain backend) as sessions from Claude Code, Cursor, Codex, and friends:
- COPILOT_AGENT — set by VS Code Copilot Chat / agent mode in terminals launched via run_in_terminal (microsoft/vscode#311734).
-
COPILOT_AGENT_SESSION_ID — set on every shell command and MCP server the standalone GitHub Copilot CLI spawns (>= 0.0.429).
-
cli: Adapt automatically to AI agent sessions (8b34a33)
When robotcode is invoked from inside an AI agent (Claude Code,
Cursor, Copilot CLI, OpenCode, Codex, Gemini, …) it now drops
coloured output, the pager, and the REPL's interactive prompt
features — so the agent sees clean line-by-line text instead of
ANSI escapes and popup ghosts.
Explicit flags and the usual environment variables (NO_COLOR,
FORCE_COLOR, ROBOTCODE_REPL_PLAIN, ROBOTCODE_REPL_BACKEND)
still override the detection. ROBOTCODE_NO_AI_AGENT=1 opts out
when you want the full experience anyway; ROBOTCODE_FORCE_AI_AGENT=1
turns the agent-mode on for local repros.
- cli: Auto-detect when to emit colors, honor NO_COLOR and FORCE_COLOR (4bbf944)
ANSI escape codes no longer leak into piped output, files, log captures or
CI artefacts — colors are auto-disabled when stdout/stderr isn't a TTY.
The NO_COLOR and FORCE_COLOR environment variables are now respected.
stdout and stderr are decided independently, so warnings keep their colour
when stdout is piped but stderr is still on the terminal. Explicit --color
/ --no-color still override everything.
- discover: Show a diagnostics summary, full list only on demand (4b96656)
robotcode discover no longer prints Robot's parsing errors and warnings
by default. When a suite has parse issues, a compact Diagnostics section
with the error/warning counts now appears after the statistics, separate
from the discovery statistics.
Pass --diagnostics to list the full messages; they are printed before
the discovered results, with file paths shown the same project-relative
way as the rest of the output. The machine-readable JSON output keeps
including the full diagnostics regardless, so editors are unaffected.
- discover:
robotcode discoverTEXT output is now markdown (a7ef8bc)
robotcode discover subcommands now emit markdown for human
output. On a coloured TTY rich renders it to themed ANSI and
pages if needed; in a pipe (or with --no-color) the raw markdown
is emitted verbatim. JSON output is unchanged.
- info renders as a field/value table.
- files, suites, tests, tasks emit as bullet lists; tags shows one bullet per tag with nested tests/tasks when --tests / --tasks is on.
- all keeps the workspace → suites → tests tree as a nested markdown list, each level indented two spaces.
- Statistics blocks are markdown tables.
The generic markdown helpers used by results — md_table,
bold_status, path_paren, display_width, the search highlighter
— move from results/_render.py to a shared
cli/_markdown.py so both commands import them from one place.
Same commit aligns the existing results renderer on the new
label convention: bold is reserved for entities (test/suite
/tag names, status); italic marks labels (Tags, Total,
Extracted, Summary, metadata keys); (path:line) references
are wrapped in inline-code spans so they read as code tokens.
- docs: Add interactive hero image carousel with responsive lightbox (edd6d22)
- language-server: Use the SemanticModel for the "Create Keyword" and "Assign Result to Variable" code actions (6a3d5a3)
When the experimental SemanticAnalyzer is enabled, the "Create Keyword" quick fix (offered for unknown keywords) and the "Assign keyword result to variable" refactor read the keyword call's namespace, library entry and assignment state from the SemanticModel instead of walking the AST and re-resolving via ModelHelper. Output unchanged — covered by dedicated equivalence test files for both code actions.
- language-server: Use the SemanticModel for the "Open Documentation" code action (0768c84)
When the experimental SemanticAnalyzer is enabled, the "Open Documentation" code action reads the pre-resolved keyword data and SemanticTokens from the model instead of looking the keyword up again on every request. Output is unchanged — verified by the existing E2E suite under both paths and a new equivalence test file.
- language-server: Use the SemanticModel for signature help (9415e86)
When the experimental SemanticAnalyzer is enabled, signature help reads the pre-resolved keyword data from the SemanticModel instead of looking the keyword up again on every request. Output is unchanged — verified by running the existing regression suite under both paths and a dedicated equivalence test file.
- repl: Suggest the setting-import aliases in tab-completion (6507af5)
Typing at the prompt now suggests Library, Resource, and Variables next to the keywords, and completing their argument offers the same libraries, resources, and variable files as Import Library / Import Resource / Import Variables — so the Settings-style aliases are as discoverable as the keywords they stand for. Offered only at the interactive prompt, where they apply.
- repl: Make the interactive shell and debugger more consistent (1a11c80)
Several rough edges in the interactive shell and its command-line debugger are smoothed out, so it behaves consistently — both with the rest of Robot Framework and within itself:
- Failures behave like a shell, not a debugger. A failing keyword prints its error and leaves you at the prompt; the debugger only steps in when asked for, and switching it off keeps your breakpoints so switching it back on picks up where you were. (
robotcode robot-debugis unchanged for debugging a real run.) - Imports work like they do in a suite. Write
Library,Resource, orVariablesat the prompt just as under*** Settings ***; saved sessions keep that familiar layout. -
The debugger speaks one language. Its commands and messages now follow one short, uniform style instead of a mix of phrasings and cryptic notes.
-
repl: Add an interactive command-line debugger (8e62733)
Debug Robot Framework runs straight from the terminal — pause a run, see where you are, inspect and change state, run keywords in the live context, and step through execution, no editor required. It's the scriptable, terminal-native counterpart to the VS Code extension's graphical debugger.
- Two ways in.
robotcode robot-debug <paths>(aliasrun-debug) runs a real suite through the normal runner with the debugger attached — same output, options and arguments asrobotcode robot, and the run keeps streaming as you step, continue or detach.robotcode repl(aliasshell) now has the debugger built in too, so breakpoints fire while you try keywords at the prompt. - Pause where you want. Line and keyword breakpoints (
--break login.robot:42,--break "Open Browser"), an embeddedBreakpointstep in a.robotfile,--stop-on-entry, and breaking on failures (uncaught failures by default, plus--break-on-all-exceptions,--break-on-failed-testand--break-on-failed-suite). Every stop shows why, which keyword, and where. - Step through it.
.step/.next/.return/.continue/.until, plus.detach(stop debugging but let the run finish) and.abort(end it now). - Inspect and change state. Walk the call stack (
.where/.up/.down/.frame), list variables by scope (.vars), evaluate in the selected frame (.print/.pprint/.whatis), auto-show expressions at every stop (.display), set variables (.set), and run any keyword right at the prompt in the paused context. - Manage breakpoints live. List them and add conditional, one-shot,
logpoint or command-list breakpoints; set conditions, ignore N hits, delete,
and disable/enable by number (
.breakpoints/.condition/.ignore/.delete/.disable/.enable/.commands/.tbreak). Arm exception breakpoints on the fly with.catch. - Read source and docs in place.
.listshows the source at the stop,.source <kw>a named keyword's definition; the full shell command set (.kw,.doc,.imports,.save, …) works at the debug prompt too. On the rich prompt these open in a scrollable full-screen viewer with search and links; on the plain prompt they print inline. - Built for humans and agents alike. Context-aware completion, syntax
highlighting, persistent history and multi-line editing on the rich prompt;
--plain(or--backend/ROBOTCODE_REPL_*) gives a bare prompt that reads commands from stdin, and the rich prompt falls back to plain automatically on piped input — so the debugger drives cleanly from scripts, CI or AI agents. -
Long commands accept any unambiguous prefix; one-letter aliases mirror pdb.
-
repl: Browse and search keywords from .kw (a884736)
.kw does more than show a single keyword now. With no argument it
lists every keyword you have imported, grouped by the library or
resource it comes from. With text that isn't an exact keyword name it
lists the keywords whose name contains that text, so you can find a
keyword without remembering its full name or leaving the REPL. Giving an
exact keyword name still shows that keyword's full documentation as
before.
In the interactive documentation viewer the listed keyword names are
links: Tab to one and press Enter to open its documentation, and press
[ to go back to the list — the same navigation the cross-reference
links inside a library page already use. On the plain backend the list
comes back as text.
- repl: Document imported resources and aliased/argument libraries in .doc and .kw (3d1665d)
The .doc and .kw commands show documentation for the libraries,
resources, and keywords you are working with in the REPL. They now cover
everything the current session has imported and match how it was imported.
.doc documents imported resource files, not just libraries — the
resource introduction plus every keyword with its arguments and
description. It also works for libraries that were imported with
arguments, which previously could not be shown. Libraries and resources
are addressed by the name they were imported under, so a library imported
with an alias (AS, or the older WITH NAME) is found by that alias.
.kw accepts the explicit Owner.Keyword form, e.g. .kw BuiltIn.Log,
to pick a specific keyword when the same name is provided by more than one
import; names resolve the same way they do in a suite. It now also shows
full documentation for resource keywords, including the argument table.
Running .doc or .kw on something you haven't imported tells you it
isn't loaded instead of showing an empty page. The built-in help for both
commands has been rewritten to read as user help rather than internal notes.
- repl: Show a startup banner (73eb26a)
When the REPL starts in an interactive terminal it now prints a
Python-style banner with the RobotCode, Robot Framework, and Python
versions, plus a hint about .help and .exit. The banner is skipped
when stdin is piped/redirected or when running --files without
--inspect.
- repl: Documentation viewer and themed prompt out of the box (dda4258)
.help, .kw, and .doc (or F1 for help) open a built-in
documentation viewer — a tiny terminal browser for Robot Framework
docs without leaving your REPL session.
- Search with
/, jump between matches withn/N. - Click a link, or use Tab/Shift-Tab to step between them. Anchor links jump to the right section, web links open in your browser.
- Walk back and forward through your reading history with
[and]. - Scroll with the mouse wheel, or with j/k, PgUp/PgDn, g/G.
- Pages use the same renderer the editor shows on hover: signature, argument table with types and defaults, tags, docstring, headings, lists, tables, code blocks.
A single color theme covers the prompt, syntax highlighting, log
lines (INFO, WARN, ERROR, …), and the documentation viewer.
prompt_toolkit and rich are bundled with robotcode-repl, so the
rich prompt experience is available out of the box. --plain (or
--backend=plain) is available for AI-agent sessions and pipe
workflows that need clean stdin/stdout.
- repl: Same prompt experience on Linux, macOS, and Windows (f8b8b15)
The interactive REPL ships with a single editor that behaves the
same way on every platform. Install the [prompt-toolkit] extra
to enable it:
pip install 'robotcode-repl[prompt-toolkit]'
You get a completion popup, syntax highlighting, signature toolbar,
persistent history and Ctrl-R search. Without the extra the prompt
degrades to a plain input() line read.
The previously implemented readline-based path has been removed — its behaviour differed too much across platforms and had platform- specific bugs that weren't worth maintaining.
- repl: --backend flag to force a specific input backend (372afca)
Lets you exercise the readline (or plain) code path without uninstalling the prompt_toolkit extra:
robotcode repl --backend=readline
- repl: Dot-commands, ${_} last-result, signature hints, session export (75cbdfd)
A grab-bag of power-user features for the interactive REPL:
- Dot-commands intercepted before Robot's parser sees them —
.help(with per-command drill-down via.help <cmd>),.imports,.vars,.kw <name>,.doc <library>,.history/.history clear/.history del <N>,.cwd,.clear,.save [-a] [-t name] <file>,.exit. Help text on each command documents its flags and shows examples. ${_}mirrors the last keyword's non-None return value, like Python's interactive_. Works in the next argument with no${tmp}=step.- F1 invokes
.helpfrom the prompt; Ctrl-R reverse-search now documented (was already wired via prompt_toolkit defaults). - Bottom row shows the active keyword's signature with the current
argument highlighted when the cursor sits in an argument cell.
Named-arg syntax (
html=True) follows the spec position, not the positional cell index. Outside an argument cell the row is hidden so the prompt stays uncluttered. - Embedded-argument completion:
Literal[...]-typed parameters on RF 7+ expose their allowed values as completion candidates aftername=. Silently no-ops on RF 5/6. .savewrites the session to a runnable.robotfile with imports hoisted into a*** Settings ***section.
All features are prompt_toolkit-aware where it matters but degrade cleanly on the readline and plain backends.
- repl: Session-context toolbar + completion/popup polish (7e0c881)
Adds the bottom-toolbar feature from the original plan plus the last round of UX polish on the prompt_toolkit candidate popup that we shaved down through testing:
- Bottom toolbar shows the running RF version and the cwd at all times — orientation info that's useful when juggling several venvs / project directories.
- Esc closes the candidate popup and reverts any preview text
that arrow-navigation had pinned, restoring the user's literal
pre-popup buffer. Bound only when the popup is open
(
has_completionsfilter) so Esc keeps its Alt-chord prefix role everywhere else. - Enter on a highlighted candidate accepts it (popup closes, preview becomes permanent). For keyword completions Enter also cleans up the cell — deletes any leftover text after the cursor in the same cell (so a mid-cell completion replaces the whole keyword) and appends a cell separator if no argument follows.
- Tab is smart: cycles through the popup when one is open, inserts a cell separator in argument context, opens the popup otherwise.
- Multi-line history survives a session restart as one entry
(newlines are escaped to
\\non disk so the file stays readline-compatible). - Mid-keyword preview renders cleanly —
${Lo}cursor beforeo, pickingLog To Consolenow showsLog To Console, notLog To Consoleog(we trim the forward-cell tail from the state'soriginal_documentbefore prompt_toolkit applies the preview). - TEXT_FRAGMENT in compound variable lookups (
${PREFIX_${X}}) renders with the variable-name colour, not the argument colour, so the eye reads the whole concatenated name as one identifier. - EOL / EOS tokens from Robot's tokenizer are dropped from the
rendered fragments —
\\ninside a fragment would otherwise show as^Jat the end of every multi-line buffer line. - Trailing whitespace is padded out to the document's actual length so the cursor stays in sync with the buffer (was sticking at column 0 when the user kept typing spaces).
_completion.pyis consolidated —candidates_for()is now a thin projection overcandidates_for_rich(), ~200 lines of duplicated helpers removed (was an artefact of how the rich variant was added in the previous commit).-
CELL_SEPARATOR+find_cell_end()added to_completion.pyas named constants and a shared helper, used by the smart-Tab / Enter-cleanup paths. -
repl: Doc hints next to completion popup candidates (c891215)
The prompt-toolkit candidate popup now shows a short context line
next to each candidate (prompt_toolkit's display_meta), so you
know what a candidate is before picking it:
- Keywords: first line of the keyword's docstring next to the
name (
Log a message with the given levelnext toLog, etc.) - Library / resource / variables imports: the discovery kind —
MODULE_INTERNALfor built-ins,MODULEfor third-party,RESOURCEfor.resourcefiles,FILEfor filesystem hits - Variables (
${…}/@{…}/&{…}):repr(value)[:40]of the current value in the live suite scope - Environment variables (
%{…}):repr(os.environ[name])[:40]
Backed by a new candidates_for_rich() API parallel to the
existing candidates_for() — keeps the readline backend's path
zero-cost (it can't render two-column popups anyway). Works on
RF 5/6/7+ with the same attribute-name version-switch
(short_doc ↔ shortdoc) the rest of the package already uses.
- repl: Robot-aware syntax highlighting at the prompt (a35b252)
When the prompt-toolkit extra is installed, the prompt now paints
Robot Framework syntax in colour. Keywords, arguments, assigns,
comments, block constructs (FOR, IF, END, …), BDD prefixes
(Given, When, Then, … plus localised variants from RF 6+) and
variables all render distinctly.
Variables decompose to the part level: sigil and braces, base name,
type hints (${age: int}), default values (%{HOME=default}),
subscripts (${dict}[key]), nested forms (${${inner}}), and
inline-Python expressions (${{expr}}) all get their own colour.
The highlighter uses Robot's own production tokenizer
(robot.api.get_tokens) plus the robotcode semantic analyzer's
variable decomposer — the same code path the RobotCode VS Code
extension uses for semantic-token rendering. Colour assignments
mirror the LSP semantic-token mapping, so the REPL prompt and the
VS Code editor use a consistent palette.
No additional dependency: Robot is already required by
robotcode-repl, and the variable decomposer ships with
robotcode-robot. Works on RF 5, 6, and 7+ (BDD-prefix
localisation requires RF 6+; English defaults apply on RF 5).
- repl: Multi-line buffer with block-aware auto-indent (8cfcc4c)
When you open a Robot block (FOR, WHILE, IF, TRY, GROUP),
the next line of input is auto-indented to the matching depth.
END pops one level. Nested blocks stack — IF inside FOR lands
at depth 2.
Behaviour differs slightly between backends:
- readline (always available): each continuation line is its own
input()call. The...prompt seeds the buffer with the right number of spaces viaset_pre_input_hook. You type from there. - prompt-toolkit (with the optional extra): one multi-line
buffer per top-level statement. Plain Enter is smart — submits
when the block is balanced, otherwise inserts a newline +
auto-indent so you keep typing inside. Alt-Enter (
EscEnter) and Ctrl-J always insert a newline + auto-indent, even when balanced. Cursor-Up/Down navigates inside the buffer.
Shift-Enter is intentionally not bound — most terminals can't deliver it distinctly from plain Enter. Alt-Enter and Ctrl-J cover the use case portably.
- repl:
--plainflag to skip all prompt enhancements (bf9fc5b)
robotcode repl --plain (or ROBOTCODE_REPL_PLAIN=1) bypasses the
prompt-toolkit / readline cascade and falls back to a bare input()
call — no history, no Tab-completion, no candidate popup, no
auto-suggest, no syntax highlighting.
Recommended for:
- AI-agent invocations where ANSI escapes from the candidate popup would corrupt the stdout capture the agent reads back
- Automation pipelines and CI that pipe input via heredoc
- Wrapper scripts that need a deterministic, side-effect-free prompt
--plain and --no-history are orthogonal — plain mode has no
history file anyway, but combining the two is safe and does not
raise.
- repl: Live as-you-type completion with prompt_toolkit (b449e1b)
pip install 'robotcode-repl[prompt-toolkit]' swaps the readline
frontend for one driven by PromptSession:
- Live candidate popup under the cursor as you type — no Tab
needed (though Tab still works). Arrow-keys pick, Enter accepts.
The verbose
Import Library Foo/Import Library Barrow layout is replaced by just the labels. - Fish-style auto-suggest — last matching line you typed shows greyed-out behind the cursor, right-arrow accepts it.
- Ctrl-R reverse search with a dedicated UI, bracket auto-match, multi-line cursor movement inside open blocks.
The completer runs in a background thread (complete_in_thread=True)
so the popup never blocks the UI, and Robot's expensive
complete_*_import(None, …) filesystem / sys.path discovery is
cached for the session — even with hundreds of importable modules,
only the first keystroke pays the walk cost.
Candidate sourcing reuses the same Robot-aware logic the readline backend uses, and the history file is shared on disk between the two backends — swapping extras (or having neither) doesn't lose arrow-up recall.
- repl: Tab completion for keywords, variables, imports (72cdbc2)
Tab now completes Robot-aware:
- keyword names at the start of a cell, sourced from every loaded library and imported resource (case + whitespace + underscore insensitive — matches Robot's own resolution rules)
${...}/@{...}/&{...}variables from the live suite scope, and%{...}environment variables from the process environmentImport Libraryarguments — plain identifiers (Coll<Tab>→Collections), dotted module paths (robot.libraries.Coll<Tab>→robot.libraries.Collections), and filesystem paths (./libs/My<Tab>→./libs/MyLib.py)Import Resourcearguments —.robot/.resourcefiles onlyImport Variablesarguments —.py/.yaml/.yml/.jsonvariable files plus discoverable variables modules
Works across Robot Framework 5, 6, and 7+.
On Pythons whose stdlib readline is backed by libedit (macOS system
Python, some uv / python-build-standalone builds), install the
gnureadline extra for full GNU readline behaviour:
pip install robotcode-repl[gnureadline].
- repl:
--no-historyflag for ephemeral sessions (1c28b57)
robotcode repl --no-history skips loading and saving the persistent
history file. Arrow-up still recalls lines from the current session;
nothing leaks across sessions. Useful for AI-agent invocations, quick
spike sessions, or working with secrets you don't want sitting in
.robotcode_cache/repl_history. Also picked up from the
ROBOTCODE_REPL_NO_HISTORY env var, which is handier when the REPL
is launched by a wrapper script.
- repl: Fish-style history dedup and configurable size (1c93402)
Re-running a command that's already in the history no longer leaves the older copy behind — only the most recent invocation survives, so arrow-up cycles through unique commands (the same behaviour fish shell ships). Legacy history files with duplicates are cleaned up on first load.
The buffer size is now configurable via the ROBOTCODE_REPL_HISTORY_SIZE
environment variable; default stays at 1000 entries.
- repl: Persistent line history across sessions (9c99f43)
robotcode repl now remembers the lines you typed and recalls them
with Pfeil-hoch / Ctrl-R, just like Python's own shell or bash. The
history file lands in your project's .robotcode_cache/ when one is
detected, otherwise in the per-user cache directory. ROBOTCODE_CACHE_DIR
overrides both.
- results:
robotcode resultsTEXT output is now markdown (4b94d66)
robotcode results subcommands now emit markdown for human
output. On a coloured TTY rich renders it to themed ANSI and
pages if needed; in a pipe (or with --no-color) the raw
markdown is emitted verbatim — ideal for pasting into PRs,
Slack, or feeding to an LLM. JSON output is unchanged.
- summary, show, log, stats and diff open with a markdown heading and lay out content as tables, bullet lists, blockquotes for failure messages, and inline code for log output.
- Each status shows both an icon and the bold word
(✅ PASS, ❌ FAIL, ⏭ SKIP, ⏸ NOT RUN, ⚪ NOT SET). summary
and stats tables are column-padded so the raw markdown stays
aligned under
cat/less. - log renders each test body as a nested list: keywords,
control flow (FOR, WHILE, IF, TRY, VAR, GROUP), setups and
teardowns. Argument values appear as inline-code spans;
failure messages as blockquotes between a keyword and its
children. Log output renders as
- `[INFO] text`; multi-line messages get a fenced code block. -
Artefacts attached to log messages render as markdown: images as
so GitHub, Slack and VS Code show them inline; other files as[path](url)so OSC 8-aware terminals (rich, wezterm, iTerm2) make them clickable. Link targets prefer paths relative to cwd and fall back tofile://URLs when the artefact lives outside cwd;--full-pathsforcesfile://URLs everywhere. -
results: Unify failure vocabulary across results subcommands (e3a0bd3)
summary uses --failed/--no-failed for the failures listing (with
failed as the matching JSON field), lining the wording up with
--status fail everywhere else.
show, log, and stats gain --failed, --passed, and
--skipped as additive shortcuts for --status fail|pass|skip.
They stack with each other and with --status, so
results show --failed --skipped is --status fail --status skip
without the typing.
- robot: Enable bottom-up navigation in the SemanticModel (a87fc79)
Every SemanticNode now carries a parent back-pointer, so LSP features
that start from a token or statement can walk up to the enclosing block,
section, or definition without re-querying the model by line. Comes with
helpers enclosing_definition_block, enclosing_block_of_kind,
enclosing_section, and path_from_root on SemanticModel.
Parent is typed as SemanticNode (not SemanticBlock) so it can also
point at a Statement — RunKeywordCallStatement.inner_calls are
parented to their outer Run-Keyword statement.
- robot: Pre-resolve more semantic data so LSP features can read it once (be36e61)
Inlay Hints now read from the SemanticModel instead of doing a second analysis pass. The model gains a real block hierarchy (FOR/WHILE/IF/TRY/ GROUP), pre-resolved init keyword docs on Library/Variables imports, and consolidated header-token construction so future LSP feature migrations stop re-walking the AST.
The old AST-walk path stays as fallback while
robotcode.experimental.semanticModel is off; both paths must produce
identical hints (covered by parametrized equivalence tests across all
supported RF versions).
- robot: Implement cross-platform file locking for data cache (8ae4aec)
Replace the Unix-only flock-based locking with a platform-dispatched
implementation using LockFileEx/UnlockFileEx (Windows) and fcntl.flock
(Unix/macOS). The Windows path previously had no-op early returns,
meaning the exclusive lock used by cache prune provided no actual
protection on Windows.
- robot: Introduce SemanticModel for richer Robot Framework analysis (Part 1) (23a538c)
Introduce the first part of an opt-in SemanticModel that provides deeper static analysis of Robot Framework files, available behind a feature flag.
Enable via robot.toml:
[tool.robotcode-analyze]
semantic-model = true
or in VS Code settings:
"robotcode.experimental.semanticModel": true
- Nested variable resolution: variables like ${DICT_${key}} are now statically resolved where possible, with diagnostics when resolution fails
- Richer semantic highlighting: token classification driven by the semantic model instead of syntactic heuristics
- RF 7.4 type hint support: KeywordName/KeywordArgument annotations are recognized for run-keyword detection
- Log output to verify which analyzer is active
- Robust deserialization of cached library data when new fields are added
The SemanticModel is disabled by default. Further parts will add additional LSP feature migrations and extended analysis capabilities.
- runner: Extend
results&discoversearch and addlog --keyword-info/--suite-info(9559316)
--search / --search-regex reach more places now. On top of the
existing test name / body / tags targets, they also hit:
- every executed keyword's
[Documentation],[Tags]and[Timeout]— answer questions like "which tests touched a keyword taggedslow" or "which tests called a keyword whose docstring mentions rate-limiting". - any ancestor suite's
DocumentationorMetadata— a hit on a suite-level field keeps every test underneath, so--search "API tests"picks up every test in a suite whose docstring reads "API tests" without enumerating names.
Both rules apply to results and discover alike.
results log gains two opt-in views (default off — the plain log
stays compact):
--keyword-infoprints each executed keyword's[Documentation],[Tags]and[Timeout]under its header, so the log shows what each keyword is, not just what it was called with.--suite-infogroups tests under aSuite:header that carries the suite's name, source, status,DocumentationandMetadata— useful when scanning a multi-suite run to see at a glance which suite a test belongs to and what it's about.
They compose: log --suite-info --keyword-info gives a structured
view that mirrors the layout of the original .robot files.
- runner: Add
--search/--search-regextodiscovercommands (ce8c783)
discover all / tests / tasks / suites / tags / files now
support the same search flags as the results family. Filtering runs
through a SearchModifier SuiteVisitor wired into the existing
prerunmodifier slot, so the Collector only ever sees the surviving
tree — statistics, ancestor suites and the tag aggregate fall out of
that automatically.
Search targets per test: name, full name, source path, documentation,
template, timeout, tags (normalisation-aware), and the full body —
keyword names, arguments, assigned variables, FOR/WHILE/IF conditions,
VAR/RETURN values, EXCEPT patterns, GROUP names, plus setup/teardown.
TEXT output highlights matches in name/source/tags/path; JSON output
echoes the pattern in filtersApplied.
To avoid duplication, the search infrastructure moves into a shared
runner/cli/_search.py module: SearchMatcher (with a model-agnostic
matches_body method that walks both robot.running and robot.result
body trees via duck-typing), make_search_matcher, make_highlighter
and the new SearchModifier. results.py and _render.py switch to
the shared module and drop their local copies.
- runner: Add the standard result filters to
results diff(a10f6ce)
results diff now accepts the same filter options as the other results
subcommands: --status, -i/--include, -e/--exclude, -s/--suite,
-t/--test, -bl/--by-longname, -ebl/--exclude-by-longname, plus
--search / --search-regex. Each filter is applied identically to
both baseline and current before the diff, so the comparison can be
scoped to a single suite, tag pattern, name, or message snippet:
robotcode results diff baseline.xml -s "MyProject.Login"
robotcode results diff baseline.xml -i smoke
robotcode results diff baseline.xml --search TimeoutError
robotcode results diff baseline.xml -bl "MyProject.Login.Bad Password"
DiffResult gains a filtersApplied field (additive, optional) so the
JSON output records the filters in the same shape used by the other
result models.
- runner: Add
-bl/--by-longnameand-ebl/--exclude-by-longnameto results filters (33697cb)
robotcode results now accepts long-name filters alongside the existing
--status, -i/--include, -e/--exclude, -s/--suite, -t/--test
options. Pick a specific test or suite by its full long name (exact
match), or exclude a branch of the tree the same way:
robotcode results show -bl "MyProject.Login.Bad Password"
robotcode results summary -ebl "MyProject.Slow Suite"
robotcode results stats --by tag -bl "MyProject.Smoke"
robotcode results log -bl "MyProject.Login" -bl "MyProject.Logout"
Both options compose with the existing filters and --search /
--search-regex, and surface in JSON filtersApplied as by-longname
/ exclude-by-longname for CI consumption. Available on summary,
show, log, and stats.
Along the way, trimmed redundant "repeat for OR" notes from option help
texts — Click already shows the * marker on repeatable options.
- runner: Split
--searchand--search-regex, add tosummaryandstats(89c2952)
--search-regex is now a standalone option that accepts a pattern instead
of a boolean flag — you no longer have to spell out both --search TEXT
--search-regex. The two options are mutually exclusive:
--search TEXT— case-insensitive substring match (open browser,TimeoutError, …)--search-regex PATTERN— Python regex, honoured as written. Use(?i)patternfor case-insensitive matching, just like in any regex engine.
Both options now work on summary, show, log, and stats, so the
same search vocabulary applies across the whole results family:
robotcode results summary --search TimeoutError
robotcode results stats --by tag --search Browser
robotcode results show --search-regex "AssertionError.*"
robotcode results log --search "Open Browser"
Search traverses the raw output tree (test attributes plus keyword names, arguments, and log messages), so a single search reaches into the execution body without first materialising the full per-test log.
- runner: Add
results difffor comparing two runs (bbdcf33)
results diff BASELINE [CURRENT] compares two output.xml / output.json
files and reports tests whose status changed, plus tests that appeared or
disappeared between the runs. Categories:
- New failures — passed in baseline, fails in current
- New passes — failed or skipped in baseline, passes in current
- Status changes — any other status flip
- Added — only in current
- Removed — only in baseline
If CURRENT is omitted, it falls back to the active profile's auto-
discovered output file, so the common pattern is robotcode results diff
/path/to/baseline.xml after the latest run. Use --only new-failures
(repeatable) to narrow the view; combined with --format json this gives
CI pipelines a clean signal for PR feedback without parsing output.xml
themselves.
Exit code is always 0 — the command is for inspection, not gating.
- runner: Add
--search/--search-regextoresults showandlog(1e90209)
results log and results show now accept --search TEXT to narrow the
output to tests that mention the given text — searched across test name,
failure message, keyword names, keyword arguments, and log messages.
Case-insensitive substring match by default; pass --search-regex to use
a Python regular expression instead.
In log's TEXT output, every match is highlighted with a yellow background
so the relevant lines stand out at a glance — handy for tracking down
which test triggered a particular TimeoutError without reopening
log.html. JSON output records the search pattern in filtersApplied for
auditability but stays free of markup.
--search composes with the existing filters (--status, -i/-e/-s/-t),
so combinations like "failures that mention AssertionError" or "smoke
tests where Open Browser was called" come naturally.
- runner: Add
results statssubcommand (d1fa30f)
results stats aggregates a finished run by --by tag, --by suite, or
--by status — the same dimensions report.html exposes in its
"Statistics by Tag" / "Statistics by Suite" panels. Repeat --by to render
multiple sections in one call.
Each section is a table with pass/fail/skip counts and total elapsed time
per group, sorted by failures (descending) by default. Switch to --sort
elapsed, --sort total, or --sort name, and limit rows with --top N.
The standard --status, -i/--include, -e/--exclude, -s/--suite,
-t/--test filters narrow the test set before aggregation, so combinations
like "tag stats for the smoke suite, top 10 by failures" come out of the
box.
JSON output exposes a stable StatsResult / StatsSection / StatsGroup
schema for CI consumption.
- runner: Add
--sortand--reversetoresults show(e4d693c)
results show can now sort tests by name, suite, status, elapsed,
or start before display. Pair with --top N for triage views like "the
slowest 10 tests" or "failures first". --reverse flips the order; without
--sort, execution order is preserved (the existing behaviour).
status orders FAIL → SKIP → PASS → NOT RUN (matching report.html's
custom sort), and elapsed defaults to longest-first so the most expensive
tests bubble to the top. A dim footer line Sorted by FIELD (desc) is
emitted in TEXT mode when a sort is active; JSON output reflects the order
in the tests array.
- runner: Unify
results logfilters and add--max-depth(02bb47b)
results log now uses the same filter options as results show and results
summary — pick tests by --status, -i/--include, -e/--exclude,
-s/--suite, or -t/--test. The old TEST_PATTERN positional and
--failures-only flag are gone; use -t "*Login*" and --status fail
instead.
A new --max-depth N collapses deeply nested keyword calls. The keyword
header still prints, and a dim … N hidden (--max-depth N) marker takes the
place of the body so nothing disappears silently. Default 0 keeps the
behaviour unchanged (full tree). The previous --keywords/--no-keywords
toggle is dropped — without keyword grouping the output overlapped with
results show.
See docs/03_reference/cli.md for the refreshed option reference.
- runner: Add
resultscommand to inspect Robot Framework runs (cf67abf)
After running tests, robotcode results lets you explore the output
without opening report.html or re-running the suite — handy for CI
logs, agent-driven workflows, and quick failure inspection from the
terminal.
Three subcommands:
robotcode results summary— overall status, pass/fail/skip counts, run duration, and the total number of error and warning messages.--failuresadds the list of failed tests above the counts.robotcode results show— one line per test with its status, source link, and failure message. Filter by status, tags, suite or test name pattern.robotcode results log— the full execution tree: every keyword call, control structure, and log message, just like Robot'sreport.htmlbut in your terminal.--failures-only,--level WARN,--extract DIR(pulls out screenshots and embedded artefacts), and more.
The output file is auto-discovered from your active robot.toml
profile; override with -o/--output PATH. Test names carry a
(path:line) suffix that VS Code's integrated terminal turns into a
clickable goto-source link. Pass --format json (or toml) for a
structured, agent-friendly payload.
See docs/03_reference/cli.md and robotcode results --help for the
full reference.
- vscode: Add commands to register the chat plugins marketplace (0e2b02f)
Two new Command Palette commands let you pull the RobotCode chat plugins marketplace into VS Code without editing settings by hand:
- "RobotCode: Add Chat Plugins Marketplace"
- "RobotCode: Remove Chat Plugins Marketplace"
They add or remove robotcodedev/robotframework-agent-plugins in the
user-level chat.plugins.marketplaces setting, so GitHub Copilot Chat
can discover and install RobotCode plugins (and future ones from that
marketplace). This is the marketplace route — separate from the plugin
the extension already bundles via contributes.chatPlugins.
If you install the robotcode plugin from the marketplace, disable the
bundled one by turning off robotcode.ai.enableChatPlugins to avoid
running two copies of the same plugin.
Only the applicable command is shown: Add when the marketplace is not registered, Remove when it is. Removing also clears the entry when it was added as a GitHub URL rather than the owner/repo shorthand.
- vscode: Bundle AI chat plugins (4018a4f)
The extension now bundles chat plugins for GitHub Copilot Chat in VS Code.
When enabled, the agent uses the project's robotcode CLI to answer Robot
Framework questions and run tasks, honoring the project's robot.toml,
profiles, and Python environment.
For example:
- "run the smoke tests with the ci profile" runs them through the selected profile and reports pass/fail counts
- "why did Login Works fail?" inspects the existing run results instead
of loading
output.xmlinto the chat - "what tests and tags exist?" uses
robotcode discover, which resolves the real set (paths, profiles, variables, pre-run modifiers) rather than grepping.robotfiles - "what arguments does this keyword take?" looks it up with
libdocagainst the installed libraries and local resources - "try this keyword" runs it in the REPL
Enabled by default; toggle with robotcode.ai.enableChatPlugins.
For other AI agents (Claude Code, Codex, and other Open-Plugin-compatible tools), the same plugins are published as a marketplace: https://github.com/robotcodedev/robotframework-agent-plugins
- vscode: Disable chat language model tools by default (3c47b48)
RobotCode now includes a robotcode CLI-based chat plugin for chat assistance. They use the same CLI workflows RobotCode users already know for setup, configuration, profiles, discovery, analysis, test runs, result inspection, and REPL usage.
The existing VS Code Chat language model tools are now turned off by default. They provide chat access to RobotCode information such as keyword documentation, library documentation, document imports, and environment details.
Users who still need these tools can enable robotcode.ai.enableLanguageModelTools.
The setting remains visible in VS Code for now and notes that the language model tools are planned for deprecation and later removal.
- vscode: Add global setting to disable What's New notification (fa03c08)
Allow users to turn off the update notification that appears after
RobotCode has been updated. The new robotcode.showWhatsNewOnUpdate
setting can be found in the global VS Code settings under
RobotCode > General.
- Add inline documentation and examples to robot.toml.json (825f891)
Users now get rich documentation directly in their editor when editing robot.toml configurations through JSON schema integration. The schema works seamlessly with the Even Better TOML VS Code extension (https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml), which is powered by Taplo.
Enhancements to robot.toml.json:
- Comprehensive inline documentation (markdownDescription) for every field
- TOML code examples extracted from configuration docs
- Direct links to RobotCode documentation via Taplo integration
- Full compatibility with Even Better TOML and other Taplo-based editors
Improvements to schema generator:
- Complete type hints for all inner functions
- Detailed docstrings for better code clarity
- More robust TOML code block extraction regex
Bug Fixes
- analysis: Respect diagnosticMode for workspace files (d2f8114)
Diagnostics for closed workspace files could appear (or be suppressed) inconsistently in openFilesOnly mode, depending on which file the workspace diagnostics loop happened to iterate last.
Also clarify the diagnosticMode description so it no longer implies that background analysis is restricted -- the setting only controls which files diagnostics are reported for.
- analyze: Run unused diagnostics through the diagnostic modifier (f13b678)
collect_unused_keywords / collect_unused_variables returned their
diagnostics directly, bypassing the diagnostic modifier. As a result the
KeywordNotUsed / VariableNotUsed diagnostics could not be ignored or
restyled via -mi/-mX or # robotcode: comments, unlike every other
diagnostic. Pass their result through modify_diagnostics, the same way
collect_diagnostics does.
-
analyze: Tighten path filtering and refine code output (b0b8820)
-
Path arguments to
robotcode analyze codeare now matched segment-wise: passingtests/apino longer pulls in siblings liketests/api_v2. - Workspace-level diagnostics (e.g. variable/library import errors) are
now prefixed with
.:instead of being printed without any source marker; their related-information lines keep their line/column. - The summary line picks its color from the highest severity present (red/yellow/blue/cyan) instead of only highlighting errors.
-
Unused-keyword/variable collectors are only registered when
--collect-unusedis set, and empty document reports from the analysis pass are no longer emitted. -
analyze: Ignore intentionally unused variables in CLI diagnostics (9cba5b0)
Treat variable names starting with "_" as intentionally unused in CLI unused-variable diagnostics, matching the language server behavior.
- bundled: Quote arguments in robotcode script to handle spaces correctly (4311747)
- config: Allow "NONE" string for max-error-lines in robot.toml (6f2e5e1)
You can now set max-error-lines = "NONE" to show the full error message, matching Robot Framework's --maxerrorlines NONE. Integers keep working as before; any other string is rejected with a clear error.
- discover: Render arbitrarily deep suite trees in markdown output (3825939)
robotcode discover all (and any other markdown output) now renders
the full workspace tree no matter how deeply suites are nested.
Previously, projects nested past ~8 levels had everything below the
limit silently dropped — including the trailing ## Statistics
block — because rich's markdown parser caps nesting at 20 and every
list level consumes two of that budget.
Markdown is now rendered through a parser configured for deep nesting, so the whole tree and its statistics always appear. Headings are left-aligned and tables render without the extra blank lines rich inserts by default.
rich is now a direct dependency of the plugin package (the lowest package that renders markdown); the repl package picks it up transitively instead of declaring it separately.
- docs: Fix sidebar links treated as external URLs (9b393ec)
vitepress-sidebar generates base:"/" with links starting with "/", causing VitePress to produce protocol-relative URLs ("//path") that browsers interpret as external links. Remove the redundant base:"/" from the root sidebar group so absolute links resolve correctly.
- language-server: Honor semantic model setting changes (782d83d)
- packages: Pin internal robotcode dependencies to exact version (7e4e9f2)
Updating a single robotcode package now pulls the matching versions of its robotcode dependencies along with it. Previously the inter-package dependencies were unconstrained, so upgrading one package could leave its siblings on an older release and break the installation.
The pins are kept in sync automatically on each release.
- plugin: Suppress mypy type-arg warning on click.ParamType subclass (ecf88e7)
A recent mypy / click version bump started flagging
AddressPortParamType(click.ParamType) as 'Missing type arguments
for generic type ParamType'. Suppress with # type: ignore[type-arg]
inline — the class deliberately omits the type parameter because the
value shape is heterogenous (parsed by convert).
- plugin: Make click help-text generation deterministic (b45757c)
The MutuallyExclusiveOption help text joined a Set[str] and
EnumChoice returned set(choices).difference(excluded) — both
produced non-deterministic ordering, so regenerating cli.md always
re-shuffled the option lists. Sort the mutex set; preserve enum
definition order via a list comprehension. Regenerate cli.md so the
typo fix from eeb8979a actually lands in the docs and the option
ordering is stable across future runs.
- repl: Handle all return-value assignment forms in completion and argument hints (bad6e14)
Keyword completion and the status-bar argument hint now work after any return-value assignment Robot Framework allows — including item assignment (${x}[0], ${d}[key]) and type hints (${x: int}), not just a plain ${x} =. The keyword is resolved with Robot Framework's own variable parser, so the REPL matches real assignment syntax exactly. The status-bar hint, which previously showed nothing once an assignment was present, is fixed too.
- repl: Keep keyword completion working after a return-value assignment (dc5d0be)
Starting a line with a return-value assignment — ${result}= Some Keyword, or several targets like ${a} ${b}= … — no longer turns off keyword completion in the keyword cell. Completion and Tab now skip the assignment targets and complete the keyword (and then its arguments) just as they would without an assignment.
- repl: Prevent multiple concurrent REPL executions (1edfe13)
- repl: ${_} now mirrors every keyword result, including None (45ec8fa)
In the REPL, ${_} holds the result of the last keyword. Previously
keywords that return None (such as Log) left ${_} untouched, so the
most natural first step — Log hello then Log ${_} — failed with
"Variable '${_}' not found".
${_} now always reflects the most recent keyword and is set to None
when a keyword returns nothing. It's also seeded to None at startup, so
${_} resolves even before the first keyword runs.
- repl: Resolve relative import paths against the working directory (8a34747)
Imports such as Import Resource foo/my.resource typed at the REPL
prompt now resolve relative to the REPL's working directory, just like
the same import does in a .robot file. Previously such imports only
worked when the path was absolute, prefixed with ${CURDIR}/, or
reachable via the module search path.
This matches Robot Framework's own resolution since RF 7.4. The REPL
docs also note that on RF < 7.4 bare relative paths still fail (RF
itself doesn't resolve them that way on those versions); use
${CURDIR}/... or put the directory on the module search path
instead.
- repl: Keep REPL startup working on pyreadline3 (Windows) (7ba1a01)
robotcode repl crashed on startup on Windows when launched against
pyreadline3 and a history file that still had legacy duplicates —
pyreadline3 doesn't expose remove_history_item, so the dedup pass
tripped on AttributeError before the prompt ever appeared.
History dedup and .history del <N> now feature-detect
remove_history_item and fall back to a clear_history + re-add_history
rebuild when the running readline shim doesn't expose it. CPython's
GNU readline path is unchanged.
- repl: Preserve backslashes in dot-command argument paths (ed2b91a)
.save C:\Users\…\scratch.robot mangled the path on Windows because
shlex.split consumes backslashes as escape characters. Switch to a
custom shlex with escape="" so paths arrive intact while shell-style
quoting (for spaces in paths) still works.
- repl:
-d/--outputdirwas silently ignored (06bc85d)
robotcode repl -d ./results -o output.xml used to write the file
into the working directory instead of ./results. The directory now
honours -d, the output-dir setting in robot.toml, and robot's
default precedence in that order. Both repl and repl-server are
fixed.
- repl, repl-server:
-v/--variableand-V/--variablefilenow work (7ecdd82)
Both flags on robotcode repl and robotcode repl-server were broken
— -v BASE_URL:staging did not register the variable, and -V vars.yaml
did not load the file. They now behave the same as the matching robot
flags: -v sets inline name/value pairs, -V reads variables from
.yaml / .py / .json files. Repeat either flag to set multiple at
once.
- robot: Fix Run Keyword If nested run keyword handling in all branches (1d283aa)
All three Run Keyword If branches (IF, ELSE, ELSE IF) now use skip_args() + _analyze_keyword_call(analyze_run_keywords=True) so nested run keywords receive only branch-local tokens instead of consuming ELSE/ELSE IF markers.
- robot: Correct type-hint handling in semantic analyzer (ecfde21)
strip variable type hints only in declaration contexts preserve typed names in usage lookups resolve nested typed variable declarations correctly stop splitting type hints on additional colons in tokenizer add regression tests for variables, VAR, assignments and arguments
- runner: Keep
relSourceinresultsJSON regardless of--full-paths(e4ff456)
Aligns results with discover, which always carries both source
(absolute) and relSource in its JSON output. Two changes:
_make_test_item/_make_diff_change/LogTeststop conditionally settingrel_source=Nonewhen--full-pathsis on. The flag is now purely a TEXT-rendering hint._rel_to_cwdfalls back to the original path (instead ofNone) when the source isn't anchored under cwd, mirroringdiscover.get_rel_source. Consumers like the VS Code extension can now rely onrelSourcebeing present wheneversourceis.
_make_diff_change and _make_test_item no longer take full_paths,
since the parameter became unused after the change. Call sites updated.
Plus acceptance tests covering the harmonised behaviour on summary,
show, log and diff, and a TEXT-only --full-paths test on
discover tags (the last subcommand without coverage).
- runner: Chdir into root_folder in
discover files(b92acdc)
The other discover subcommands wrap their work in
with app.chdir(root_folder) via handle_options, so get_rel_source
produces paths relative to the project root. discover files skipped
that step, which made its default (non---full-paths) output depend on
the caller's process cwd: if cwd was outside the project, paths fell
back to absolute, breaking the documented semantics.
Wrap the body in the same chdir context so the output is consistent
with the rest of discover. Also flips a fragile test_files_default_
relative from ordering-dependent (it would fail in the full suite
when an earlier test left cwd in a tmp dir) to robust.
- runner: Honour subcommand semantics in
discoverJSON output (0f26a3f)
Two discover subcommands silently differed between their TEXT and
JSON renderers because the type filter only ran in the TEXT path:
discover tests -f jsonreturned every item incollector.test_and_tasks— i.e. tasks slipped in too, even though the TEXT render correctly filtered totype == "test". Same shape bug ondiscover tasks. Filter the list before handing it toResultItemso JSON and TEXT agree.discover tags --not-normalized -f jsonignored the flag and always returned the normalised tag dict; only the TEXT path consulted--normalized. Pick the right collector dict (tagsvsnormalized_tags) for both renderers.
Both surfaced while wiring up the new discover acceptance tests.
- runner: Page
discoveroutput through a single pager invocation (069c34e)
Each discover subcommand opened the system pager multiple times in
sequence — once for the main listing, then once for the statistics block
(and once per key for discover info). The fix routes everything through
a single echo_via_pager call so the user only sees one pager instance.
- runner: Normalise tags in
resultscommands (8f93500)
Robot Framework treats tags as equal when they differ only in case,
whitespace, or underscores (Bug 1 ≡ bug_1 ≡ Bug1). The new
results commands didn't honour that:
stats --by tagshowed each spelling variant as its own bucket, even though they referred to the same semantic tag.tests[].tagsinshow/summary --failuresechoed the raw form from the result file, so the same tag could appear with different spellings on different tests.--search/--search-regexagainst tags compared the raw strings, so--search "bug 1"missed tests literally taggedbug_1.filtersApplied.include/excludeechoed the user input verbatim, which didn't reflect how Robot actually interpreted the pattern.
Every tag-handling spot now uses Robot's normalize(..., ignore="_"):
- Stats buckets group by the normalised form and display the normalised label too.
_make_test_itememits already-normalised tags in JSON / TEXT._SearchMatchercarries a separate tag-aware predicate that normalises both haystack and needle (substring) or just the haystack (regex)._canonical_tag_patternnormalises plain single-tag patterns infiltersApplied; patterns containing an uppercaseAND/OR/NOToperator are echoed verbatim because each operand would need individual normalisation.
Tests added: stats merges equivalent tags into one bucket; show
emits normalised tags; --search is normalisation-aware against
tags; filtersApplied echoes the canonical pattern form. The
tagged.robot fixture grew three new tests (norm tag, norm_tag,
NormTag) so the regression case is exercised end-to-end.
- runner: Make
resultscommands work against older Robot Framework outputs (20bb597)
robotcode results failed on output.xml files generated by Robot
Framework 5 and 6 — the older models use different attribute names than
RF 7 (elapsedtime vs elapsed_time, starttime/endtime as the
YYYYMMDD HH:MM:SS.fff string, no variables on WhileIteration, …).
Each accessor now falls back to the legacy spelling and the iteration
helper limits loop-variable lookups to ForIteration via isinstance,
so summary, show, log, stats, and diff produce identical
output regardless of which Robot version wrote the file. Timestamps in
the legacy string format are normalised to ISO 8601 in the JSON
contract.
Smoke-tested across RF 5.0, 6.0, 7.0, 7.3, and 7.4.
- runner: Escape
<errors>inresults loghelp to prevent VitePress build error (7dc79ef)
The --execution-messages help text contained a raw <errors> tag that
VitePress' Vue parser interpreted as an unclosed HTML element, breaking
the generated cli.md docs page. Wrap it in backticks so it renders as
inline code and is ignored by the template compiler.
- schema: Revert robot.toml json-schema, because older versions of robotcode need this (fafb168)
- vscode: Let Tab accept Copilot inline edit suggestions (f724aa2)
When "4 Spaces Tab" was enabled, pressing Tab inserted four spaces instead of accepting or jumping to Copilot's inline edit (Next Edit) suggestions. Tab now yields to those suggestions and only inserts spaces when none is pending.
- vscode: Update stale RF version UI strings from 4.1 to 5.0 (#605) (f846483)
The quick-pick dialog shown when environment validation fails still referenced 'robotframework version 4.1 or higher' in both the 'Select Python Interpreter' detail and the 'Retry' detail text. The actual enforced minimum has been 5.0 since commit 02cf495f (refactor: introduce RF_VERSION constant and remove RF < 5.0 dead code).
Documentation
- analyze: Document the
-mi "*"allow-list pattern (b5b2444)
Show that * matches every code, so -mi "*" plus re-introducing
specific codes builds an allow-list — and point out it remaps severity,
unlike the --code filter.
- analyze: Document the --code filter (e72ac55)
Fold --code into the "reporting only some diagnostics" section next to --severity, noting that both filter (rather than remap) and combine with AND.
-
analyze: Document --severity filter and unused diagnostic control (2da8116)
-
describe the new --severity output filter alongside the modifiers
-
note that KeywordNotUsed/VariableNotUsed can now be remapped or ignored like any other diagnostic
-
analyze: Streamline and correct analyze-code guide (0272ab9)
-
drop the flag table; defer to the CLI reference
- move the JSON reference to the end
- trim implementation internals from the SARIF section and give every output format a consistent invocation + example
- note that the CI examples assume project setup via its package manager
- fix a dead anchor link
Corrections after review:
- no paths analyzes/reports the whole project, not the profile's default paths; paths/--filter narrow the reported per-file diagnostics while import/library resolution always covers the whole project
- explain why --collect-unused is opt-in (needs whole-project reference data, extra pass, slower with many keywords/variables)
- note that a real run or discovery can surface errors static analysis misses (suite-wide checks like duplicate test names, PreRunModifier)
-
show how to read the bitwise exit code from the shell
-
analyze: Document CI workflows, drop scratch workflow (fcb0caa)
Replace the fragmentary CI snippets in the analyze-code guide with full,
copy-pasteable workflows for GitHub code scanning (SARIF upload), GitHub
inline annotations, and GitLab Code Quality — including the
security-events: write permission and current action versions
(checkout@v5, upload-sarif@v4) that the manual trial surfaced.
Remove the throwaway .github/workflows/analyze-code.yml now that the examples live in the documentation.
- analyze: Add reference guide for analyze code (095b52a)
Add a task-oriented guide for robotcode analyze code under
docs/03_reference, in the style of the discover/results guides: what it
checks, severities and diagnostic modifiers, exit codes and masks, all
output formats (concise, json, sarif, github, gitlab), a flag reference,
JSON/SARIF/GitHub/GitLab output references, CI recipes, and the cache
subcommands. Link it from the reference index.
- cli: Enhance command options documentation for severity and code filters (422d466)
- cli: Document core, results and testdoc commands (b48a58d)
Add the missing commands to the package overview: the core
robotcode package now lists config and profiles, and the runner
package lists results and testdoc. Close the reference with help
hints and links to the related configuration, discovery, results and
REPL pages.
- config: Show TOML examples in robot.toml reference (c53da77)
The "Examples:" blocks were carried over verbatim from Robot Framework's CLI help, so they showed --flags instead of TOML. Add a curated TOML_EXAMPLES map in generate_rf_options.py (with extend- prefix rewriting for extend-* variants) and regenerate model.py and config.md.
- contributing: Add agent workflow guide and update contribution guide (9a024a2)
- contributing: Clarify DCO vs GPG signing and unify branding (a1f116d)
Reference the DCO in the CONTRIBUTING Legal Notice and recommend
git commit -s. Clarify in both places that the DCO sign-off is
separate from the GPG/SSH commit signature (git commit -S) required
for merges.
In AI_POLICY.md, drop the duplicated DCO statement and link to the Legal Notice instead. Align the PR template's tests/lint/signed-commits bullets with the CONTRIBUTING checklist, and unify the project name spelling to "RobotCode" across the three files (URLs and CLI names unchanged).
- contributing: Add AI policy and refine contribution guide (688e6ae)
Add a project-wide AI and Automated Contribution Policy (AI_POLICY.md) covering human responsibility, disclosure, low-context submissions, and enforcement.
Restructure CONTRIBUTING.md:
- new "Project-Wide Rules" section linking the AI policy and the payment/bounty rule
- add a pre-commit hooks section (uvx / uv tool install / pipx)
- mention uv / uvx alongside pipx for installing hatch
- rewrite the Running Tests section: `hatch run test:test` as the recommended default, correct RF versions (5.0–7.4) and matrix size (5×8=40), clarify that bare `hatch run test` only runs in the default env
- consolidate PR guidelines into a PR checklist + description + review process, referencing the new PR template
- fix TOC duplicates and the empty Payment link
Add a GitHub pull request template with checklist and AI/tooling disclosure block, and add the same disclosure block to the bug, enhancement, and question issue templates.
- home: Refresh landing page (8dc70e0)
Mirrors the reworked README pitch: tightened hero, consolidated feature cards, and a "Sponsor RobotCode" section with Individual/Corporate split.
Adds a RandomTagline component, analogous to RandomHeroImage, so the hero tagline rotates randomly on each page load.
- news: Add v2.6.0 release notes (7d6a701)
-
readme: Restructure and refresh (69c881b)
-
Sharpen What-is intro with Foundation / Core-Team partnership note
- Restructure Key Features into Editor/IDE, Configuration, Command line groups with marketing-oriented bullets
- Tighten Requirements (correct VS Code 1.108 / IntelliJ 2025.3, prominent LSP-editor note)
- Add Command Line installation block for CI / non-IDE users
- Fix broken doc links (troubleshooting page never existed, /support/ → /05_contributing/)
-
Split Sponsor RobotCode and Get Involved into separate sections
-
repl: Clarify REPL scripts are body-only .robotrepl files, not full suites (a169d86)
Reword the file-execution section so it no longer implies a full .robot
suite can be run. These inputs are REPL scripts — a test-case body only,
with no *** Settings *** / *** Test Cases *** sections — and use the
.robotrepl / .robotscript extension instead of .robot. A file with
section headers fails with "No keyword with name ' Settings '
found"; import libraries and resources from inside the body with
Import Library / Import Resource.
Also note that .save only guarantees the export parses cleanly —
REPL-only variables like ${_} still need an edit to run standalone — and
tidy up wording, hyphenation, and a duplicated shortcuts list.
- repl: Document the prompt-toolkit extra (2660b7b)
New section in the REPL reference covers:
- the
prompt-toolkitextra (pip install 'robotcode-repl[prompt-toolkit]') and the upgrades it lights up — live as-you-type candidate popup, fish-style auto-suggest, Ctrl-R reverse search UI, bracket auto-match, multi-line cursor movement - the threaded completer + session cache that keep the popup
responsive even with hundreds of importable modules on
sys.path - the fact that history is shared on disk between backends, so swapping extras doesn't lose arrow-up recall
-
the
[prompt-toolkit,gnureadline]combined extras as a sensible setup for libedit-backed Pythons -
repl: Document history persistence and tab completion (1374da7)
New "Prompt features" section in the REPL reference covers:
- where the history file lives (project
.robotcode_cache/vs. the per-user cache directory,ROBOTCODE_CACHE_DIRoverride), how the fish-style dedup behaves, and the--no-history/ROBOTCODE_REPL_NO_HISTORY/ROBOTCODE_REPL_HISTORY_SIZEescape hatches - what Tab completes — keywords from loaded libraries and imported
resources, suite-scope variables (
${...}/@{...}/&{...}),%{...}environment variables, and the threeImportarguments with plain / dotted / filesystem prefixes - the
gnureadlineextra for macOS' system Python andpython-build-standaloneinterpreters (uv/rye/ …) where the stdlibreadlineis libedit-backed and Tab would otherwise be degraded
Also adds the REPL reference to the index page.
- repl, repl-server: Correct misleading
--sourcehelp text (87402e3)
The flag only uses the parent directory of FILE as the REPL's
working directory — it does not read or write the file, and does not
set a suite name.
- runner: Task-oriented guide for
robotcode discover(f69fd9a)
A new discovering-tests.md page covers the discover family the same
way analyzing-results.md covers results. It walks every subcommand
from the terminal perspective — all, tests, tasks, suites,
tags, files, info — with examples and flag tables, then the
shared Robot-native filters and --search / --search-regex
behaviour, and finally the full JSON schema reference for scripts,
CI pipelines, and editor integrations (TestItem, ResultItem,
TagsResult, Info, diagnostics, filtersApplied) plus a set of
jq-based CI recipes for sharding, tag reports, and parse-error gates.
-
runner: Cover extended search and
results log --keyword-info/--suite-info(a7395f6) -
analyzing-results.md: search-target list mentions test doc/template/timeout, keyword [Documentation]/[Tags]/[Timeout] (result-tree-only), and ancestor-suite Documentation/Metadata. New--keyword-info and --suite-infosubsection explains what each flag adds to TEXT and JSON, with a combined example.logJSON schema shows the newsuitesarray and per-testsuitecross-reference plus a table for the keyword doc/tags/timeout fields. -
cli.md: regenerated fromhatch run create-cmd-line-docsto pick up the new--keyword-info/--suite-infoflags onresults logand the updated--searchhelp text acrossresultsanddiscover. -
runner: Fix "releative" typo in
discover --help(eeb8979) - website: Use bundler module resolution (dd6f358)
- website: Improve hero image navigation (09a8975)
- Split REPL reference into shell and command-line debugger pages (7f0577f)
The REPL reference mixed the interactive shell with the command-line debugger. It is now two pages:
- "Interactive Robot Framework with robotcode repl" — the shell.
- "Command-line debugging with robotcode robot-debug" — a dedicated page for the debugger: ways to pause a run (line, keyword, embedded Breakpoint keyword, exceptions, stop-on-entry), the debug command set (stepping, call stack, inspecting and setting variables, breakpoint management, exception filters, log-and-continue), a worked example with the embedded Breakpoint keyword, and how it relates to the VS Code debugger.
Other improvements:
- Each command reference page now states which optional package to install to run it: robotcode[repl], [runner], or [analyze].
- The CLI reference now documents robotcode robot-debug (alias run-debug) and lists it under the repl package.
- Fixed the .doc command description: it shows documentation for libraries and resources the session has imported, not on demand.
- Add "Working with AI Agents" reference page (e7c8d68)
Describe how RobotCode lets AI coding agents work through the project's own robotcode CLI instead of guessing:
- the chat plugin (a skill) and what it teaches the agent — discover, libdoc, REPL, results, analyze on the resolved project
- the bundled VS Code plugin and its enableChatPlugins toggle, plus the extension shipping the robotcode CLI on the integrated terminal PATH
- installing the plugin in other agents via the Open Plugins marketplace
- recommended project-context setup (AGENTS.md / CLAUDE.md): environment, library init steps, the system under test, conventions
- the CLI's AI-agent detection and its override env vars/flags
- troubleshooting
-
Refine contribution guide and AI policy (b93cbf6)
-
AI_POLICY: welcoming, principle-led intro; clarify that what matters is human ownership, not whether an autonomous agent was involved; frame the purpose around protecting maintainer time, which is what ultimately keeps RobotCode sustainable
- CONTRIBUTING: add a "find your path" orientation block and a warmer Project-Wide Rules intro; lead commit-signing setup with the low-effort SSH path; document that documentation-only changes need neither the test matrix nor linting (there is no Markdown linter); remove decorative emoji
- PULL_REQUEST_TEMPLATE: mark the tests and linting checks N/A for documentation-only / non-code changes
- Add
resultsanalysis guide (ebb2d12)
A task-oriented user guide for the robotcode results family of
commands, split into two parts:
- Using the commands — what each subcommand does in the terminal, its useful flags, sort/filter semantics, and the pager / colour handling. Recipes for the common day-to-day questions: "what failed", "which test took longest", "drill into one test", "regression vs main".
- JSON reference — schema rules (omitted vs
nullvs[]), per-subcommand JSON shape, the body-item-type vocabulary used bylog, thefiltersAppliedecho, and CI/jq recipes for pass-fail gates, slow-test reports, notification payloads and artefact gathering. Includes a note specifically for AI-driven workflows on why streaming the focused JSON beats parsing rawoutput.xml.
Also linked from the reference index page.
- Update json schema for robot.toml validations (6d4fd6d)
Performance
- vscode: Smoother test explorer refreshes and live test updates (bc488d0)
The Test Explorer used to flicker on every keystroke when the tree was expanded, slow to a crawl during multi-file edits (e.g. when an AI agent applies many edits at once), and sometimes show "AbortError" as a workspace entry at startup. Newly added or removed tests didn't appear in the tree until the refresh button was pressed.
What's different now:
- The tree only re-renders when the discovered tests actually change; identical re-discoveries leave the UI untouched.
- One refresh runs at a time — newer edits cancel the in-flight subprocess instead of queuing up behind it.
- Many edits in a short window collapse into a single workspace refresh.
- External file changes no longer collapse expanded tree nodes.
- Tests added or removed in a saved file appear/disappear immediately.
- A workspace refresh no longer runs a redundant per-document discover for every open file.
Also fixes a non-deterministic tag order from the discover command so the TS side can reliably detect real tag changes.
Refactor
- diagnostics: Unify number-literal detection helpers (4dcb22f)
Replace the direct robot.variables.finders.NumberFinder dependency and
the two duplicated _try_resolve_number_literal static methods with
shared try_resolve_number_literal / is_number_literal helpers in
robot.utils.variables, consumed from model_helper, namespace_analyzer
and the semantic analyzer.
- language-server: Pure SemanticModel for signature help and code action (2a4e728)
Both LSP feature paths now read everything off the SemanticModel — no
RF AST walks, no ModelHelper position helpers. SemanticToken carries a
precomputed LSP Range so consumers can use native operators
(pos in tok.range, range in tok.range, tok.range.extend(...))
instead of per-coordinate arithmetic. Output unchanged.
- repl: Unify the setting-alias flag and tidy completion internals (c3d50fe)
Review follow-up, no behaviour change:
- Use one name,
setting_import_aliases, for the flag everywhere (it wasinclude_setting_aliasesoncandidates_for_rich). - Make
_RobotCompleter's flag public so the_smart_tabkey binding reads it off the active completer without reaching into a private attribute. - Move the assignment-target helpers above their first caller so there is no forward reference.
-
Add completer-level tests: the
>>>completer forwards the flag into the candidate service, and Tab after a setting alias opens completion instead of inserting a cell separator. -
runner: Extract
discoverdata models and aligninfoJSON casing (95c119b)
The TestItem / ResultItem / Statistics / TagsResult / Info
classes move out of discover.py into a dedicated _models.py,
matching the layout the results family already uses. discover.py
imports them from there, keeping the command file focused on click
wiring and traversal.
Info was the only discover model without CamelSnakeMixin, so
discover info was emitting robot_version_string / python_version_string
/ system_version / robot_env while every other discover and
results JSON key was already camelCase. It now uses the mixin too,
so -f json discover info (and the TEXT key:value rendering) speaks
the same robotVersionString / pythonVersionString / systemVersion
/ robotEnv shape as the rest. Tests and the reference docs follow.
- runner: Adopt SuiteVisitor for body traversal in
_search(000f2e9)
Replace _body_matches' manual recursion + string-based item.type
dispatch with a SuiteVisitor subclass that overrides one start_X per
body-item type. Robot's own visitor handles the recursion; returning
False from each hook short-circuits the rest of the traversal once a
match is found.
This drops every getattr in the file: the fully-qualified keyword name
comes from the inherited Keyword.name property (which already composes
libname.kwname on RF <7 result trees), result-tree-only .message is
guarded with isinstance(item, StatusMixin), template (running-model
only) is guarded with isinstance(test, RunningTestCase), and the
For.assign vs For.variables rename is handled by one top-level
RF_VERSION gate. RF 7+ Var/Group/Error types come in via a
TYPE_CHECKING import with # type: ignore[attr-defined,unused-ignore].
As a side-effect Error.values is now part of the searched fields —
the old type-string dispatch silently skipped Error items.
- runner: Adopt ResultVisitor for body traversal in
results(5e5c88f)
Replace manual body recursion (_collect_test_body's build-pattern and
_count_all_messages' inline walk) with ResultVisitor subclasses that
override the per-type end_X methods Robot's dispatch already provides.
This removes the string-based item.type checks, eliminates the
remaining getattr calls on stable Robot attributes, and lets every body
item flow through one well-typed code path.
Side cleanups in the same pass: hoist RF-version-conditional access
(kwname/libname vs name/owner, For.assign vs For.variables,
Result.elapsed_time vs elapsedtime, StatusMixin time fields) into
top-level helpers gated on RF_VERSION, switch the Var/Group/Error
imports to a TYPE_CHECKING-only # type: ignore[attr-defined,unused-ignore]
form, and drop _eval_str — the profile is already evaluated before it
reaches this code, and StringExpression.__str__ covers the rest.
- runner: Drop more
Anyfromresults.py(15 → 6) (8b4f059)
Three more rounds of tightening on top of the previous pass:
_eval_str/_isoacceptobject(we use genericisinstance/getattr/str()on them, no type-specific access)._make_message_entrytakesMessage— it's only called for MESSAGE-typed body items, so the static type is precise._start_time/_end_timenow returnOptional[object](forwarded unchanged to_iso, which acceptsobject).- The four RF-version-gated helpers (
_iter_all_tests,_get_full_name,_keyword_name_and_owner,_loop_variables) get properTestSuite/TestCaseparameters where the polymorphism isn't on the input type. Internally they usegetattrfor the attributes whose existence depends on the runtime RF version, so mypy stays happy across the whole RF matrix without# type: ignore. Same behaviour, just less guesswork at call sites.
Any remains on the six positions where it's the only honest answer:
the heterogeneous body-item helpers (_keyword_name_and_owner,
_loop_variables, _elapsed_seconds, _start_time, _end_time,
inner build). Each item type carries different attributes; we
dispatch by type string and getattr. Typing them as a Union of 9+
result-tree classes would be heavier than the type safety it provides.
- runner: Replace
Anywith proper Robot types inresults.py(e70314f)
Twenty-one stable-API positions get real type hints. Any survives only
where it's genuinely the right answer:
- The four RF-version-gated helpers (
_iter_all_tests,_get_full_name,_keyword_name_and_owner,_loop_variables) — each branch accesses attributes that exist only on the matching RF version, and mypy sees only the installed one. - Body-item helpers and the inner
build(item)in_collect_test_body— body items are aKeyword | For | If | Try | While | Var | Return | Group | Messageunion and we dispatch bygetattr(item, "type"). _elapsed_seconds/_start_time/_end_time— called on suites, tests and keywords; truly polymorphic._iso,_eval_str,msg— string-or-something accepting helpers.
For everything else, the actual Robot class lands in the signature:
TestSuite and TestCase from robot.result, Result for the loaded
execution result, ExecutionErrors for the errors collection,
RobotBaseProfile for the resolved profile, and SuiteVisitor for the
modifier list. No behaviour change; mypy is happy on every RF version
in the matrix.
- runner: Collapse
resultsfilter pipeline into a single pass (93c3cf6)
Every results subcommand used to filter twice: first delegating
include/exclude/suite/test to TestSuite.filter() via
_apply_tree_filters, then re-walking the (still-full) tree inline to
apply --status and --search. The matcher and the status-set lived
in each command body; helpers like _collect_counts /
_collect_failures took the matcher and status filters as parameters.
Collapse that into one pre-pass and one pre-pass only:
- Add a
ByStatusSuiteVisitorin_search.py(Robot has no native status filter, so this stays ours, but in the same shape asByLongName/SearchModifier). - Extend
_apply_tree_filtersto also acceptstatus_filtersand the search matcher, bundling every project-specific filter into a singleModelModifierpass that visits the tree once. - After the pre-pass, every surviving test has cleared every filter, so
_collect_countsand_collect_failuresshrink to a plain tally /[t for t in suite ... if t.status == "FAIL"]. The_normalise_statuses/_raw_test_search_matcheshelpers and the_STATUS_KEY_MAPconstant lose their last callers and go away too. -
One subtle behaviour shift: search now matches
test.nameandtest.longnameseparately (viaSearchModifier), where the old_raw_test_search_matchesonly saw the full name. That's a strict superset — an anchored regex like^Pass.*now matches a test literally namedPassing Test Three. Updatedtest_search_regex_anchors_and_alternationto pick a pattern that matches no field instead of relying on the old narrower contract. -
runner: Polish
results statsUX and docstrings (36e3996) -
--bynow displays the actual choices ([tag|suite|status]) in--helpinstead of the placeholderDIMENSIONmetavar, so the allowed values are discoverable without reading the docs. stats --by suitegroups by the suite's full name (e.g.MyProject.Login) rather than the bare leaf name. Suites that share an end name in different parts of the tree are now distinguished.-
Drop internal
report.html/ "Mirrors X" justifications from user-facing docstrings — that's plan-rationale, not help text. -
tests: Standardize on pytest-mock and shared analyzer fixtures (441618c)
Replaces direct unittest.mock usage with the project's existing pytest-mock convention so tests are stricter (autospec) and new tests need less boilerplate.
- Drop three orphaned private symbols (38a7995)
Dead code surfaced by an unused-symbol sweep across packages/:
_BRANCHES(repl/_indent.py): a frozenset that was only there to document which Robot keywords (ELSE,ELSE IF,EXCEPT,FINALLY) the indent counter ignores. Replaced with a short inline comment — same self-documenting effect, no orphan symbol._split_comma(analyze/code/cli.py): a click callback added alongside the--xm/--xeexit-code-mask options, then superseded by_parse_exit_code_maskand never wired up._cancel_all_running_tasks(core/concurrent.py): originally the publiccancel_running_callables; the FutureEx → Task rename privatised it but no caller followed.