yuzu

agent_actions

What it doesAgent runtime actions — set log level, query agent info
Version0.1.0
KindAction · mutating · gathered (device.agent_actions.set_log_level, device.agent_actions.info)
PlatformsWindows ✅ · macOS ✅ · Linux ✅
Actionsinfo (definition device.agent_actions.info) · set_log_level (definition device.agent_actions.set_log_level)
Securityset_log_level: securable Infrastructure · operation Write · risk Medium · dispatch Mutating · approval gate None; info: securable Infrastructure · operation Read · risk Low · dispatch ReadOnly · approval gate None
Rolesexecute: set_log_level: endpoint-admin; info: endpoint-admin, endpoint-operator · author: content-author

How it works

set_log_level reads the required level parameter, lowercases it, and validates it through spdlog’s own from_str before calling spdlog::set_level() in-process — no OS call, no subprocess. On success it writes two key|value lines, status|ok then level|<normalized>; on a missing or unrecognized level it instead writes a single error|<message> line and returns 1, never touching the status/level shape. info reads five agent.* keys from the agent’s config context and echoes each as key|value, substituting the literal (not set) for anything unpopulated. Both actions run identically on Windows, macOS, and Linux — the descriptor declares the same spdlog_runtime/agent_config_read mechanism at rung 1 on all three legs, because neither reaches the OS. The plugin deliberately is not a log reader or shipper: it only changes the live logger’s verbosity and reads config already held in memory — no file writes, no subprocesses, no network.

flowchart LR
  OP["Operator / workflow"] --> SRV["Server - authz: Infrastructure.Write or Infrastructure.Read"]
  SRV -->|"gRPC mTLS"| HOST["Agent plugin host"] --> EX["agent_actions.execute"]
  EX --> WIN["Windows leg - spdlog_runtime / agent_config_read"]
  EX --> MAC["macOS leg - spdlog_runtime / agent_config_read"]
  EX --> LIN["Linux leg - spdlog_runtime / agent_config_read"]
  WIN & MAC & LIN --> ROWS["key|value rows"] --> RS[("ResponseStore")] --> API["REST /api/responses"]

OS capability

ActionWindowsmacOSLinux
info✅ supported · rung 1 · agent_config_read✅ supported · rung 1 · agent_config_read✅ supported · rung 1 · agent_config_read
set_log_level✅ supported · rung 1 · spdlog_runtime✅ supported · rung 1 · spdlog_runtime✅ supported · rung 1 · spdlog_runtime

Privileges and prerequisites

OSRuns asExtra grant neededMeasuredIf the read is refused
Windowsnot documented for this plugin (no row in docs/agent-privilege-model.md); captured as SYSTEMNone — both actions are in-process calls, no subprocess on either leg2026-09-07, bare-metal, SYSTEM (docs/samples/windows.txt:1)N/A — no OS permission check exists
macOSnot documented; captured unprivileged, euid 501 (jsmith)None2026-09-07, bare-metal, euid 501 (docs/samples/macos.txt:1)N/A — same as above
Linuxnot documented; captured as root, euid 0, containerNone2026-09-06, container, euid 0 (docs/samples/linux.txt:1)N/A — same as above

None. Both actions execute in-process — no subprocess and no network call on any OS (agent_actions_plugin.cpp:27-29 states “no subprocess on any OS — rung 1 on all three legs”).

Data contract

Inputs

DefinitionParameterTypeRequiredDefaultConstraintsDescription
device.agent_actions.set_log_levellevelstringyes-pattern: ^(?i:trace|debug|info|warn|warning|err|error|critical|off)$The desired spdlog log level, case-insensitive: trace, debug, info, warn, error, critical, or off (e.g. “info”, “INFO” and “Info” are all accepted). The agent also accepts “warning” and “err” (spdlog’s long and short names), and the pattern admits them. Declared as a case-insensitive pattern rather than an enum because the server’s enum check is case-sensitive.

Outputs

Both actions emit write_output() lines of the form key|value rather than disk-plugin-style single pipe-delimited rows. set_log_level writes exactly two lines on success (status, then level); a validation failure instead writes one error|<message> line that matches neither declared column. info writes exactly five lines, one per config key, in a fixed order; an unpopulated key renders the literal (not set) rather than being omitted.

device.agent_actions.info — agent_id|agent_version|server_address|heartbeat_interval|plugins_count

FieldTypeValuesAvailableExampleDescription
agent_idstring-Windows, Linux, macOS(not set)The agent’s agent.id config value, or the literal “(not set)” when the config context has not populated it. Values: free text, or literal “(not set)”.
agent_versionstring-Windows, Linux, macOS(not set)The agent’s agent.version config value, or the literal “(not set)” when unpopulated. Values: free text, or literal “(not set)”.
server_addressstring-Windows, Linux, macOS(not set)The agent’s agent.server_address config value, or the literal “(not set)” when unpopulated. Values: free text, or literal “(not set)”.
heartbeat_intervalstring-Windows, Linux, macOS(not set)The agent’s agent.heartbeat_interval config value, or the literal “(not set)” when unpopulated. Values: free text, or literal “(not set)”.
plugins_countint32-Windows, Linux, macOS(not set)The agent’s agent.plugins.count config value. Always emitted as text, never a JSON number — the raw config string or the literal “(not set)”. Values: free text, or literal “(not set)”.

device.agent_actions.set_log_level — status|level

FieldTypeValuesAvailableExampleDescription
statusstringokWindows, Linux, macOSokLiteral “ok” once the level was applied. A missing or unrecognized level instead produces a single “error|” line that carries neither this column nor level.
levelstringtrace debug info warn error critical offWindows, Linux, macOSinfoThe log level the agent applied — a lowercased echo of the level parameter.

Result status

This plugin does not set a typed result status; the agent records UNDECLARED and every sample shows UNDECLARED / UNKNOWN / for both actions on all three OSes (docs/samples/windows.txt, docs/samples/macos.txt, docs/samples/linux.txt).

Where the data goes

Sample output

Windows — captured: windows Microsoft Windows NT 10.0.26200.0 x64 · bare-metal · 2026-09-07 · SYSTEM · leg-hash 2688724a5dd5

== action=set_log_level level=info
status|ok
level|info
[result_status] UNDECLARED / UNKNOWN

== action=info
agent.id|(not set)
agent.version|(not set)
agent.server_address|(not set)
agent.heartbeat_interval|(not set)
agent.plugins.count|(not set)
[result_status] UNDECLARED / UNKNOWN

macOS — captured: macos macOS 26.6.2 arm64 · bare-metal · 2026-09-07 · euid 501 (jsmith) · leg-hash 2688724a5dd5

== action=set_log_level level=info
status|ok
level|info
[result_status] UNDECLARED / UNKNOWN

== action=info
agent.id|(not set)
agent.version|(not set)
agent.server_address|(not set)
agent.heartbeat_interval|(not set)
agent.plugins.count|(not set)
[result_status] UNDECLARED / UNKNOWN

Linux — captured: linux Debian GNU/Linux 13 (trixie) aarch64 · container · 2026-09-06 · euid 0 · leg-hash 2688724a5dd5

== action=set_log_level level=info
status|ok
level|info
[result_status] UNDECLARED / UNKNOWN

== action=info
agent.id|(not set)
agent.version|(not set)
agent.server_address|(not set)
agent.heartbeat_interval|(not set)
agent.plugins.count|(not set)
[result_status] UNDECLARED / UNKNOWN

Caveats and known gaps

  1. No typed result status. The plugin never calls a result-status setter; every capture on every OS shows UNDECLARED / UNKNOWN / for both actions (docs/samples/{windows,macos,linux}.txt).
  2. The info capture artifact is real production behavior with the config sync skipped, not a broken leg. do_info reads config through the module-global g_ctx, populated by init() and then kept current by agent.cpp’s sync_master_config_to_plugins; tests/unit/test_plugin_loader.cpp:411-417 states this sync is “the only thing that makes agent_actions::info return a populated agent.plugins.count instead of (not set).” The capture driver loads the plugin without going through that agent-boot sync path, so every sample legitimately shows all five keys as (not set).
  3. Validation failures don’t match the declared schema. A missing or unrecognized level emits one error|<message> line (agent_actions_plugin.cpp:83-86, 94-97) instead of the declared status/level columns — the YAML result.columns describe only the success path.
  4. plugins_count is declared int32 but always emitted as text. Every info line, plugins_count included, is a key|value string (agent_actions_plugin.cpp:121-124); the code never emits a numeric type.
  5. No privilege-model row. docs/agent-privilege-model.md carries no entry for this plugin; the identities above are only what each sample capture measured, not a documented production guarantee.

Source and tests