Automation: exec, wait, run, history

These operations are implemented by the agent Hub engine. The CLI sends requests; it does not implement expect/send logic locally (except parsing run YAML before calling the API).

Exec: one-shot vs session

This distinction is important.

Without session_id — historical one-shot

eve-iac console exec ./lab n_1 "show version"
  • Opens a separate one-shot Telnet connection via the internal console manager.
  • Does not join an open VSIX terminal or existing Hub.
  • Default timeout 10 s; maximum 60 s (timeout_ms on the API).
  • Connect timeout 5 s.

SDK equivalent (Python):

client.exec_console(ExecConsoleRequest(**{**packed.payload, "node": "n_1", "command": "show version"}))

With explicit session_id — Hub session

eve-iac console exec ./lab n_1 "show ip int brief" --session sess-7f3a
  • Uses the existing Hub/session.
  • No fallback to one-shot if the session is invalid or closed.
  • Shares the same EVE Telnet TCP as other leases on that session.

Use session-backed exec when a human terminal or an earlier createConsoleSession already holds the Hub open.

Wait

Wait is event-driven console matching — not polling.

  1. Scan retained Hub history.
  2. Then block on live console data until the pattern matches or time expires.
Property Value
Pattern Go regexp
Spanning reads Matches may span Telnet read boundaries
Max timeout 600 s (timeout_ms)
Output Bounded; timeout is distinguishable from cancel/error

CLI:

eve-iac console wait ./lab n_1 \
  --expect 'Router[#>]' \
  --timeout-ms 180000

Python:

client.wait_console(WaitConsoleRequest(**{
    **packed.payload,
    "node": "n_1",
    "pattern": r"Router[#>]",
    "timeout_ms": 180_000,
}))

TypeScript:

await client.waitConsole({
  ...packed,
  node: "n_1",
  pattern: "Router[#>]",
  timeout_ms: 180_000,
});

Go:

client.WaitConsole(ctx, eveiac.WaitConsoleRequest{
    Lab: packed.Lab, Node: eveiac.Ptr("n_1"),
    Pattern: eveiac.Ptr(`Router[#>]`), TimeoutMs: eveiac.Ptr(180_000),
})

Run / expect-send

Run executes an ordered list of steps on a Hub lease. Each step may expect a regexp, send text, or both.

Example YAML file (bootstrap.yaml):

steps:
  - expect: "Press RETURN"
    send: ""
  - expect: "Router>"
    send: "enable"
  - expect: "Password:"
    send_secret: "example-placeholder"
  - expect: "Router#"
    send: "terminal length 0"

CLI:

eve-iac console run ./lab n_1 bootstrap.yaml

Step semantics

Field Meaning
Omitted send Do not send anything (expect-only step)
send: "" Send RETURN (empty line)
send_secret Send value; never echoed in responses or transcripts
timeout_ms Per-step cap (optional)

Global run timeout maximum: 600 s. On failure, failed_step is 0-based (-1 when all steps succeed). Secret output is redacted in API and MCP responses.

Run uses the agent engine. The CLI only parses YAML and calls runConsole.

Python:

from eveiac import ConsoleRunStep, RunConsoleRequest

client.run_console(RunConsoleRequest(**{
    **packed.payload,
    "node": "n_1",
    "steps": [
        ConsoleRunStep(expect="Router>", send="enable"),
        ConsoleRunStep(expect="Password:", send_secret="example-placeholder"),
        ConsoleRunStep(expect="Router#", send="terminal length 0"),
    ],
}))

History

Hub history is a bounded tail of raw console bytes (after Telnet IAC filtering).

Layer Limit
Hub ring 64 KiB (65536 bytes)
MCP default request 8 KiB
MCP hard cap 32 KiB
CLI --bytes 1–65536

There is no persistent log collector. History is available only while the Hub exists (including the 60 s idle window after the last client leaves).

CLI:

eve-iac console history ./lab n_1 --bytes 16384

Python:

client.get_console_history(GetConsoleHistoryRequest(**{
    **packed.payload,
    "node": "n_1",
    "session_id": sess.session_id,
    "max_bytes": 16_384,
}))

MCP eve_iac_console_history applies the same bounds at the VSIX boundary (default 8 KiB, max 32 KiB) and sets truncated when output is cut.