> ## Content Index
> Fetch the complete content index at: https://www.pinglabz.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Advanced EEM: Tcl, Multi-Event Correlation, and EEM + Python
- URL: https://www.pinglabz.com/advanced-eem-tcl-python/
- Published: 2026-07-12T09:54:08.000Z
- Updated: 2026-08-24T05:13:21.000Z
- Description: Go past one-line EEM applets: multi-event correlation, Tcl policies, and EEM as the trigger for on-box Python. Includes a real applet firing and capturing device state in a CML lab.
- Author: Jaime
- Tags: Network Automation, Labs, CCIE, #Import 2026-08-01 19:54

EEM - the Embedded Event Manager - is the router's built-in automation engine, and it has been there, on every IOS device, since long before "network automation" was a buzzword. It watches for events and takes actions, entirely on the box, with no external system. Most engineers use it for one-line applets and stop there. The expert territory is multi-event correlation, Tcl policies, and EEM as the trigger for on-box Python - which is where EEM becomes genuinely powerful.

This article covers advanced EEM, with a real applet firing and capturing device state from a CML lab. It extends the [network automation guide](https://www.pinglabz.com/network-automation/).

## The EEM model: event → action

Every EEM policy is an event detector plus a set of actions. When the event fires, the actions run. The event detectors cover an enormous range - syslog patterns, SNMP thresholds, interface state, CLI commands, timers, counters, IP SLA results, and more - and the actions can run CLI commands, send syslog, set counters, email, or launch scripts.

## A single-event applet, fired for real

From the lab, an applet that watches for a loopback going down, then captures and logs the interface state:

```
event manager applet LOOP-FLAP-GUARD
 event syslog pattern "Loopback99, changed state to down" maxrun 60
 action 1.0 syslog msg "EEM triggered: Loopback99 went down"
 action 2.0 cli command "enable"
 action 3.0 cli command "show ip interface brief | include Loopback99"
 action 4.0 syslog msg "EEM captured state: $_cli_result"
 action 5.0 increment flapcount 1
```

We triggered it by shutting Loopback99, and it ran the full action chain:

```
R1#show logging | include EEM
%HA_EM-6-LOG: LOOP-FLAP-GUARD: EEM triggered: Loopback99 went down
%HA_EM-6-LOG: LOOP-FLAP-GUARD: EEM captured state:
   Loopback99  10.99.99.99  YES manual administratively down down

R1#show event manager history events | include LOOP
1  1  Actv success  Sun Jul12 09:39:58 2026  syslog  applet: LOOP-FLAP-GUARD
```

Read what happened: the event fired, the applet issued a live `show` command, and the crucial part - the **`$_cli_result`** built-in variable carried that command's output into the follow-up syslog message. The applet did not just react to the event; it *captured the device's state at the moment of the event* and logged it. That is the pattern that makes EEM a diagnostic tool: catch the state the instant something happens, before it changes.

## Multi-event correlation

A single event is easy. The expert feature is correlating *multiple* events - "act only if A *and* B happen within a window", or "act if A *or* B". This is how you avoid false-positive reactions and build genuinely intelligent triggers.

```
event manager applet MULTI-EVENT
 event tag EV1 syslog pattern "clock"
 event tag EV2 none
 trigger
  correlate event EV1 or event EV2
 action 1.0 syslog msg "EEM multi-event correlation fired"
```

Each event gets a **tag**, and the **trigger/correlate** block defines the logic - `and`, `or`, with optional timing windows. From the lab, the registration confirms the correlation:

```
R1#show event manager policy registered | include MULTI
2  applet  user  multiple  Off  ...  MULTI-EVENT
 EV2: none: policyname {MULTI-EVENT} sync {yes}
```

The event type `multiple` is the tell - this applet is watching several events and applying logic across them, not reacting to one. The real use cases are powerful: "shut the interface only if both the error counter is high *and* the link is flapping", or "alert if the primary *and* the backup both fail". Correlation turns EEM from a reflex into a decision.

## EEM Tcl policies: when applets are not enough

Applets are declarative and limited - a fixed list of actions. When you need real logic - loops, complex parsing, data structures, calculations - you write an EEM **Tcl policy**. Tcl (Tool Command Language) is a full scripting language, and IOS runs Tcl policies as EEM events:

```
event manager directory user policy flash:/eem_scripts
event manager policy monitor_bgp.tcl type user
```

Inside the Tcl policy, you have the EEM Tcl library - register for an event, run CLI commands, parse their output with Tcl's string handling, make decisions, and take actions. A Tcl policy can do things an applet cannot: iterate over all BGP neighbors and act on each, parse a complex show output, maintain state across runs. IOS also has an interactive `tclsh` for testing Tcl one-liners on the box.

Tcl is showing its age - Python is the modern choice - but it is deeply embedded in IOS and remains the way to do complex on-box logic within EEM on any platform, including the ones without Guest Shell.

## EEM + Python: the modern combination

On platforms with [Guest Shell](https://www.pinglabz.com/guest-shell-ios-xe/), EEM's most powerful pattern is launching an [on-box Python script](https://www.pinglabz.com/on-box-python-ios-xe/) as an action. The applet detects the event; Python does the heavy lifting:

```
event manager applet HIGH-CPU-DIAG
 event snmp oid 1.3.6.1.4.1.9.9.109.1.1.1.1.7.1 get-type exact entry-op ge entry-val 90 poll-interval 10
 action 1.0 cli command "guestshell run python /flash/cpu_diagnostics.py"
```

Now the router responds to a CPU spike by running a full Python diagnostic script - capturing process lists, top talkers, whatever the script does - autonomously. This is the best of both: EEM's rich event detection triggering Python's expressive logic. (It requires a Guest-Shell-capable platform, which our lightweight lab image lacks - the EEM side is fully real, the Python-launch side is documented reference, as covered in the on-box Python article.)

## Practical EEM patterns

State capture on event

The lab's pattern - catch `show` output the instant something fails, using `$_cli_result`. Invaluable for intermittent problems you cannot catch by hand.

Scheduled maintenance

A `cron` timer event runs a nightly config backup or a health check - the router schedules its own housekeeping.

Auto-remediation

Detect a known failure signature and fix it - clear a stuck process, bounce an interface, fail over - without waking anyone.

Threshold alerting

An SNMP-threshold event triggers a targeted alert with captured context, richer than a raw trap.

## Cautions

- **Set `maxrun`.** Bound how long an applet can run, or a misbehaving policy can hang. The lab used `maxrun 60`.
- **Beware self-triggering loops.** An applet that reacts to a syslog and generates a syslog can trigger itself. Match patterns carefully.
- **Test on a lab device.** An auto-remediation applet that gets the logic wrong can make an outage worse. Prove it before deploying.
- **Rate-limit destructive actions.** Use counters and `ratelimit` so a flapping condition does not trigger a destructive action dozens of times.

## Key takeaways

- EEM is the router's on-box automation engine - event detectors plus actions, no external system. It has been in IOS for two decades.
- The lab's real applet **captured device state at the moment of an event** using `$_cli_result` \- the pattern that makes EEM a diagnostic tool for intermittent problems.
- **Multi-event correlation** (event tags + a trigger/correlate block with and/or logic) turns EEM from a reflex into a decision. Registration shows event type `multiple`.
- **Tcl policies** give you full scripting logic when applets are too limited - loops, parsing, state - on any platform.
- **EEM + on-box Python** is the modern combination: rich event detection triggering expressive Python (on a Guest-Shell-capable platform).
- Always set `maxrun`, avoid self-triggering loops, rate-limit destructive actions, and test on a lab device first.

Next: [model-driven telemetry on IOS XE routers - gRPC dial-out in practice](https://www.pinglabz.com/model-driven-telemetry-ios-xe-routers/). The full cluster index lives on the [network automation pillar](https://www.pinglabz.com/network-automation/).