Download the PHP package survos/command-bundle without Composer
On this page you can find all versions of the php package survos/command-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package command-bundle
Command Bundle
Run, background, and monitor Symfony console commands. Four things:
- Web command runner — run any
#[AsCommand]from a web page (with the Symfony profiler available), for easier debugging. - Background runner —
bg:run "<cmd>"dispatches a command to an always-on Messenger worker so long jobs survive logout / container teardown. - Process registry + monitor — every background run is recorded as a
CommandProcess(status, timing, output, named "slots"); watch them live in a TUI (bg:monitor) or the web list (/…/processes). - Agent tools (MCP) — opted-in commands become MCP tools on symfony/mcp-bundle's server, with the schema derived from the command's own
#[Argument]/#[Option]attributes. See Agent tools.
Requirements
- PHP 8.4+, Symfony 8.1+
- Doctrine ORM (ships the
CommandProcessentity) symfony/messenger(forbg:runand background recording)survos/tui-extras-bundle— optional, only for thebg:monitorTUI (require-dev/suggest)
Commands
| Command | What |
|---|---|
bg:run "<cmd>" |
Dispatch <cmd> to the command Messenger worker. One message per command (fan out). |
bg:monitor (alias monitor) |
Live TUI of background runs, grouped by command, status by glyph, most-recent-first. Needs survos/tui-extras-bundle. |
bg:run requires the app to route RunCommandMessage to an async transport and run a worker:
Verbosity note: captured output inherits the worker's verbosity.
messenger:consume -qmakes the run's output QUIET (nothing captured); run at normal verbosity to record output.
Process registry & slots
Background runs are recorded in the command_process table (only bg:run runs — plain CLI/web runs are not recorded). A command can push a styled, named status fragment to the monitor with plain PSR-3 logging:
Configuration
Upgrading (process registry)
This bundle now ships the CommandProcess Doctrine entity and requires doctrine/orm, survos/field-bundle, symfony/messenger, and symfony/uid. After updating, create the table:
- SQLite (dev):
bin/console doctrine:schema:update --force - PostgreSQL / shared:
bin/console doctrine:migrations:diff→ review → migrate
Routes default to off — set survos_command.routes_enabled: true (under a secured prefix) to use the web UI/monitor.
Agent tools (MCP)
Agents run commands you'd otherwise run over SSH. With symfony/mcp-bundle installed, explicitly opted-in commands become tools on its MCP server. Nothing else is exposed.
Why this exists, next to symfony/mcp-bundle
symfony/mcp-bundle is the MCP server: transports (HTTP, stdio), sessions, the #[McpTool] attribute,
debug:mcp, the profiler panel. This bundle does not replace any of it; it adds what that server
does not have: a tool that is a console command.
#[McpTool] (symfony/mcp-bundle) |
#[AsAgentTool] (this bundle) |
|
|---|---|---|
| What you write | a method for the agent, separate from any command | nothing extra: one attribute on the command |
| Inputs declared | in the method signature, again | once, on the command (#[Argument]/#[Option], #[MapInput] DTOs) |
| Grouped inputs (a DTO) | not supported by the SDK's schema generator | yes, via #[MapInput] |
| Run it yourself | no CLI equivalent | bin/console <command> --format=json is the same call |
Vendor commands (messenger:stats) |
would need a wrapper | one line of config |
| Access control | none built in; an open /mcp exposes every tool |
ROLE_ADMIN per tool unless marked public |
| Record of calls | profiler, in dev | CommandProcess rows: caller, command line, status (agent:calls) |
| Long-running work | blocks the request | the same command can go through bg:run |
Use #[McpTool] for things that are not commands (a search over an index, a resource). Use
#[AsAgentTool] for anything you would otherwise ask an agent to run over SSH.
Opting a command in
Your own command: #[AsAgentTool] next to #[AsCommand]:
A command you can't annotate (vendor or another bundle's): config.
A bundle should not decide for an app what is exposed, so bundle commands (like state-bundle's
state:stats) carry no attribute: they provide --format=json, and each app opts in by config.
What the agent is told about a tool
Agents discover tools from the server and choose by what each tool says about itself, so say it well:
| Field | Comes from |
|---|---|
| name | AsAgentTool::$name, or the command name (app:add-page → app_add_page) |
| title | AsAgentTool::$title, or the name humanised ("Add page") |
| description | AsAgentTool::$description (config: description), else the command's one-line description. Write it for an agent: what it does, when to use it, what comes back, in terms of parameter names. The command's CLI help is never sent: it is written for a terminal (php bin/console …, --flags). |
| parameters | the command's InputDefinition: names, descriptions, required arguments, defaults |
| parameter types | the PHP signature: int → integer, float → number, flags → boolean, repeatable options → array, BackedEnum → enum of its values. Config-listed commands only have what the console knows (strings, flags, arrays). |
| read-only / destructive / idempotent hints | AsAgentTool (config: readOnly, destructive, idempotent); clients use them to decide what needs confirmation |
Server-wide guidance (how the tools fit together) goes in symfony/mcp-bundle's mcp.servers.<name>.instructions.
Check the result with bin/console debug:mcp and bin/console debug:mcp <tool>.
How a call runs
- The command runs in-process (
ConsoleCommandExecutor), with--format=jsonwhen it has a--formatoption. The decoded JSON is the tool result; other output comes back as{output: "…"}.--format=jsonis also how you debug the same call from the CLI: same command, different caller. - Errors (exceptions, non-zero exit, unknown parameters) come back to the agent as readable tool errors.
Security
Access is decided per tool, closed by default: every tool requires ROLE_ADMIN (or the role: it names), checked on every call. That is for HTTP callers: over stdio the server is a local process started by someone who already has a shell on the machine, so roles are not checked there and the call is recorded as stdio:<user>. A tool that exposes nothing sensitive opts out with public: true, and only a readOnly tool may (enforced at container compile):
The check fails closed: without symfony/security-bundle, a non-public tool is denied. Plain #[McpTool] methods are not gated by the bridge, and with an open /mcp they're open to everyone, so on such a server write lookups as commands with #[AsAgentTool] too: one gate for every tool, and each one is a CLI command you can debug.
Signing in: a stateless access_token firewall on /mcp. AgentTokenHandler signs the bearer token in as a real user from your provider, so calls carry that user's roles. The endpoint itself stays open, so read tools work without a token:
Connect: claude mcp add --transport http myapp https://myapp.example/mcp --header "Authorization: Bearer $AGENT_TOKEN"
Seeing what agents can do, and did
bin/console debug:mcp(symfony/mcp-bundle) lists every tool on the server;debug:mcp <tool>shows its description and input schema.bin/console agent:callslists the calls agents made: caller, status, and the equivalent command line so any call can be re-run by hand. Options:--command,--caller,--failed,--output,--limit,--format=json. It is itself an admin-only tool (agent_calls).
With survos_command.track on (the default), every tool call is a CommandProcess row in mode agent, refused calls included (failed, "Access denied…", caller anonymous when no token was sent). After upgrading, add the new column: command_process.caller (doctrine:migrations:diff).
OAuth (for claude.ai web/mobile connectors) is not wired: mcp/sdk ships resource-server middleware (JWT validation, protected-resource metadata), but it needs an identity provider to issue the tokens.
Web command runner
Long-running commands: see https://github.com/symfony/symfony/discussions/59696. The run form also has a "Dispatch via Messenger (async)" checkbox.
Purpose
Use assert(), dump() and dd() are quick and easy debug tools when debugging a Symfony web page. But it's often difficult to use within the console, since the formatting is for a web page.
For example, in the official Symfony Demo, there is a command to send the list of users to an email address.
Debugging this is much easier with Symfony's Debug Toolbar, this bundle wraps the console commands with a web interface so that the toolbar is available.
Now go to /admin/commands and see what's available
Select list-users, and fill in the email.
Submit the form and open the debug toolbar:
With dumps and asserts, this is even more helpful.
Example with Symfony Demo
composer config extra.symfony.allow-contrib true composer config extra.symfony.endpoint --json '["https://raw.githubusercontent.com/symfony/recipes-contrib/flex/pull-1708/index.json", "flex://defaults"]'
Defining commands
Symfony 8.1+ lets you mark methods on any service with #[AsCommand], with arguments and options described via attributes. The web form rendered by this bundle introspects the same metadata the CLI uses, so no separate command class is required.
The same form supports a "Dispatch via Messenger (async)" checkbox for long-running work — wire up Messenger and the command runs in a worker rather than the request cycle.
with castor
Add attribute to AppCastorTest.php
All versions of command-bundle with dependencies
symfony/config Version ^7.4||^8.1
symfony/console Version ^7.4||^8.1
symfony/dependency-injection Version ^7.4||^8.1
symfony/form Version ^7.4||^8.1
symfony/framework-bundle Version ^7.4||^8.1
symfony/http-kernel Version ^7.4||^8.1
twig/twig Version ^3.4|^4.0
doctrine/orm Version ^3.7
survos/field-bundle Version ^2.5
survos/kit-bundle Version ^2.5
symfony/messenger Version ^7.4||^8.1
symfony/uid Version ^7.4||^8.1