process:<program> capability: the user approves
the program, the IDE pins it by absolute path and content hash, and checks it again before
every start. On top of that, a plugin can:
Run detectors
A run detector is a static configuration offered in projects that contain one of its marker files at the root:process:<command> is granted
and starts the approved program. No code is needed.
Solidity
declares detectors for Foundry and Hardhat.
Configurations from code
When the configurations depend on the project’s content (scripts in apackage.json, say),
declare marker files and export run-configurations:
PluginRunConfiguration has id, name, program, args, an optional
project-contained cwd, test and an optional framework. Return the complete list for
the project root; it is refreshed when configurations are listed. The host keeps at most
1000 entries / 4 MiB, keeps the last valid list when the export fails, and doesn’t offer
entries whose program isn’t approved. The export runs without a window and can’t prompt.
Test results
Withframework = "plugin" (on a detector or a returned configuration), the IDE feeds the
run’s output to the test-results export. Register test_results and implement
TestResults:
parse(config, chunk)gets the short configuration id and sequential output chunks that need not end at a line break: keep partial lines between calls.- Events:
SuiteStarted,TestStarted,Passed,Failed(withexpected/actualfor a comparison),Skipped,Output. Test ids are scoped to the run; a parent must already exist. Locations are absolute project paths, 0-based lines, UTF-16 columns; durations are milliseconds. - Each batch runs under the editor provider budget and returns at most 10,000 events / 4 MiB. A missing, failing or invalid parser switches that run to the built-in parsers.
select_tests(config, tests)receives test-tree name paths (parent suite to test, as shown in the tree) and returns the full argument list that runs only them. It enables Rerun Failed Tests and Run / Debug on test tree entries. The default returnsNone(selection unsupported).
Start a run from code
host::start_run(config, &args, debug) (API 1.4) starts one of this plugin’s
configurations (a detector id or one the export returned; the short id or
plugin:<plugin-id>:<config-id>) in the invoking window’s Run tool window, appending
args. It returns an operation id; a run-exited event with {id, config, status, killed}
follows, delivered to the owning plugin even without a subscription. From the
Test Runner
example, where a gutter button passes the test name as the argument:
invalid without one. Only valid from a
command or event, not from activation or a provider.
Run targets
A run target is a project-scoped wrapper: every run, test, script and interpreter launch that selects it is rewritten to go through a program the plugin owns, such asddev, lando
or a container CLI. Targets appear in Settings › Build, Execution, Deployment › Run
Targets and in every run configuration’s Run on selector, labelled with their plugin.
How the command line is built
The host builds argv directly, without a shell:- No override:
program + args + workdir_args + command + command arguments. - An override whose name matches the command’s program name (basename without
.exe,.cmdor.bat):program + override + workdir_args + command arguments. The override replaces bothargsand the command name, so it includes the tool itself.
php x.php run from public/ becomes
ddev exec --dir=/var/www/html/public -- php x.php, and composer install becomes
ddev composer --dir=/var/www/html/public -- install.
- Each
workdir_argselement may contain{cwd}, replaced by the configuration’s working directory mapped undercontainer_root. Allworkdir_argsare omitted when there is nocontainer_rootor the working directory is outside the project. Withoutworkdir_argsthe wrapper manages its directory itself. - When
container_rootis set, project paths in argv are mapped under it. Local absolute tool paths outside the project become the tool’s basename. - The wrapper process always starts in the configuration’s local working directory, so tools like DDEV find their project. Configuration env and env files reach the wrapper; forwarding them into a container is up to the wrapper.
host::register_run_target_with_overrides
takes PluginRunTargetWithOverrides, whose commands are PluginCommandOverride { name, args, workdir_args }. workdir_args: None inherits the target’s list, Some(vec![]) omits
it, Some(args) replaces it for that command:
composer install becomes ddev composer install while php x.php keeps
ddev exec --dir=/var/www/html/public -- php x.php.
Selecting a target
Registration never changes a selection. The first registration asks the project’s windows “Use<name> for running PHP / Node / Composer in this project?” with Use and
Not now; the answer is remembered per project, plugin and target id. Use makes it
the project’s default run target and its PHP and Node run-target choice. Interpreters also
get a Run in target choice in Settings (default run target, Local machine, or a
named target). Explicit per-configuration targets win.
Rules and limits
- Each launch checks project trust, the wrapper’s process grant and its executable pin (including a per-project executable choice made in Settings › Plugins).
- Debugging on a plugin target returns
invalid; language servers, tool discovery and version probes stay local. - A missing target fails the run rather than silently running locally.
- At most 32 targets per plugin and project, 64 command overrides, 256 arguments per prefix (16 KiB each), 256 KiB of metadata per registration.
- Targets survive idle reclaim. Stopping, disabling, reloading or uninstalling the plugin
withdraws them;
host::unregister_run_target(&project, id)removes one. In remote projects registration and execution happen on the server.
Validating a launch (API 1.5)
Exportrun-target-validation to check the wrapper’s runtime state right before Run or
Test:
RunTargetLaunch has operation (Run or Test), the bare program being wrapped and the
absolute local cwd; arguments and environment are not passed. Err(message) refuses the
launch through the normal error path, prefixed with the plugin name (at most 4096 bytes). A
trap or timeout (5 seconds by default) also refuses it. Plugins without the export keep
launching as before.
Running programs
- Only the pinned program of a
process:grant runs, in a trusted project. In a remote project it is resolved and run on the server. - Environment entries only add variables: a name already in the prepared environment
(including the login-shell
PATH) is an error. At most 64 entries. - Calls are cancelled with the task or call and killed at timeout; run anything slow
inside
host::begin_task. Dropping aChildkills it, and disabling or reclaiming the plugin ends its children. - In Settings › Plugins the user can choose the executable of a
process:grant globally or per project; the plugin keeps calling its declared program name.