Changes and approvals
The Changes tab of the Runs page is the record of what the agent changed across every environment in the workspace. It lists the changes that ran, the ones waiting on a decision, and the ones an admin dismissed, with the environment, the mode in force at the time, and who asked. It is the audit trail for the agent.
The two tabs are one page because they are two views of the same work. A run is
a session of the agent on a machine, and a ledger entry is the one kind of step
that had to stop and ask a human first, so the run that wanted a change is one
click from the change itself. The tab shows how many entries are waiting on a
decision, and the older /changes address still opens it.
What lands in the ledger
The ledger lists changes and nothing else. A command the agent ran only to look at something is not an entry here. It appears in the steps of the run that ran it, so an environment in Read only mode leaves this tab empty.
| What the agent tried | What appears |
|---|---|
| A changing command in Manual mode | A pending proposal, until an admin decides. |
| A changing command in Auto mode | An applied entry. It ran immediately. |
| A changing command in Read only mode | Nothing. It is refused before it reaches the ledger. |
| Any command in a conversation a non-admin started | Nothing. It is refused before it reaches the ledger. |
A command that ran but was refused by the Wazuh API or the Wazuh indexer is recorded as Not applied, and nothing on the host changed.
A change that did not take effect shows no undo. A change that failed or timed out may be partly applied, so it offers no undo either, and the undo the agent stated before it ran stays under Show command. Check the host before reversing anything.
Which commands count as reads is decided by Vesper, not by the agent. See what Read only actually permits for the exact rule. A command an admin approved or dismissed stays in the ledger even if Vesper now counts it as a read, so the record of that decision is kept.
A run that asks to continue on a bigger budget is not a change either. That request and its answer appear inside the run.
An entry records what ran, the environment it targeted, the mode in force when it was requested, and the run that asked for it. Every entry today comes from an agent run, so the requester reads as that run's own identifier rather than as a person's name. The approver, where there was one, is a person.
The approval flow in Manual mode
When an environment is in Manual mode and the agent decides a change is needed, the run suspends and the proposed action is recorded as pending. An admin can decide it in either place:
- inline in the Agent page, where the proposal interrupts the conversation, or
- from the Changes tab, where every pending proposal across environments is listed first, with two actions, Approve and apply or Dismiss without applying.
On a distributed environment the proposal names the node the command runs on, such as "Run on w3 (Manager worker)", read from the ledger entry itself. A command is approved for that machine and no other.
Approving relays exactly the proposed action to that node's connector and resumes the agent run with the result. Dismissing resumes the run with the denial, so the agent can adjust its plan, or explain what would have been needed.
Only admins can approve or deny. A member without that role sees the proposal and is told it is waiting for an admin.
The only write channel
A change reaches an environment in one way: a shell command the agent runs on a
Wazuh node, as root. It can touch the whole host, including files, services,
packages and configuration. Only the agent asks for one, and only in a
conversation an admin started. The ledger names it host.exec.
The host has to permit it. Shell execution is off by default. On a
hand-installed connector it stays off until it is installed with --enable-exec. See connector configuration. On a
Wazuh Fleet node it stays off until an admin turns Shell commands on for that
host's node in Vesper and a Wazuh Fleet administrator allows a root shell for
Vesper on the host. See
shell commands on a Wazuh Fleet node.
That leaves a plain conclusion about a default install. Where exec.enabled is
false, the agent cannot change the environment in any mode, including Auto.
Enabling shell execution on the host is what makes the mode setting consequential.
Where each safeguard runs
The safeguards are not all in the same place, which matters when reasoning about what protects what.
| Safeguard | Where it runs |
|---|---|
| The run's own look-only scope | The Vesper API, fixed when the message was sent |
| Shell commands are admin-only | The Vesper API |
| The environment mode ceiling | The Vesper API, re-read on every command |
| Approval in Manual mode | The Vesper API, decided by an admin |
| The capability switches | The connector, in the config file on the host |
| The catastrophic-command denylist | The Vesper API, with a second copy on the host |
The first two rows differ from the third in a way worth noticing. The mode ceiling is re-read on every command, so changing it takes effect on a run already going, in both directions. A run's look-only scope is fixed when the message is sent and nobody can widen it afterwards, which is why it is the one safeguard a conversation can be shown to have had.
The denylist refuses a short list of whole-system destructive operations, such as reformatting a filesystem or shutting the host down, even in Auto mode. Vesper checks it before the command is recorded or sent, so a refused command never reaches the environment and never appears in the ledger. The refusal is shown in the conversation instead. The connector enforces the same list on the host itself, as a second line for anything that did not come through Vesper. It is a safety net. What actually decides whether a change happens is the mode ceiling plus approval.
See connector configuration for how to widen or narrow what a given host allows.