# 04 — writing green-eye plugins > **# TOOL IN DEVELOPMENT - NOT READY YET!** See 00 for status. A plugin is a Python module exposing `register(ge)`. It is loaded before the session runs (CLI `--plugin PATH`, `GREENEYE_PLUGINS`, or the bundled `plugins/` directory) and can add instrumentation, CLI commands and harness logic without touching green-eye itself. ## 1. The API object ```python def register(ge): # live objects ge.session # Session ge.memory # Memory ge.symbols # SymbolDB ge.recorder # Recorder | NullRecorder # instrumentation ge.hook(target, on_enter=None, on_leave=None, kind="sw") ge.watch(target, size=8, kind="w", callback=None) ge.on_event(kind, callback) # kind in {"*", "bp_hit", "watch_hit", ...} ge.resolve(target) # symbol/addr -> runtime address # CLI + logging ge.add_command("name", fn, help="…") # fn(session, args: list[str]) -> int ge.log("message", any="field") # recorded as a "plugin" event ge.commands # dict of registered commands ``` Everything a plugin records lands in the session's `events.jsonl`, so plugin findings are replayable and comparable like any other event. ## 2. Lifecycle and safety * `register()` runs once, immediately after the session is attached and symbols are loaded; the target is still stopped, so hooks are in place before the first instruction. * A plugin that raises is recorded as `plugin_error` and skipped; it never aborts the session or the other plugins. * Session close detaches all hooks/watchpoints, including plugin-installed ones. * Plugins must be stdlib-only unless the dependency is documented; they are development tooling and never shipped. ## 3. The four plugin classes **(a) Runtime RE tools** — add analysis that green-eye does not have: ```python def register(ge): def on_state(hit): ge.recorder.event("state_machine", result=hit.retval, pc=hit.pc) ge.hook("rpc_state", on_leave=on_state) ``` Useful additions: allocation graphs, ring-buffer watermarks, page-table walks, coverage collectors built from `on_event("stop")` plus the TCG trace, entropy or checksum probes over structures. **(b) Harnesses** — drive the firmware and assert: ```python def register(ge): def check(session, args): ctrl = session.symbols.lookup("gsp_ctrl") before = session.memory.read_u64(ctrl + 0x10) session.memory.write_u64(ctrl + 0x20, 1) # PING session.run(duration=0.3) after = session.memory.read_u64(ctrl + 0x10) assert after == before + 1, "PING did not dispatch" print("PING ok") return 0 ge.add_command("check-ping", check) ``` **(c) Virtualization-environment updates** — alter how the target is built or driven: extra QEMU args, a rehosting shim for uproc sources, a device-model stub, a replay layer that feeds recorded events back into a run. Keep such changes behind plugin-level flags and document them in the session metadata (`s.recorder.meta`). **(d) AI/harness integration** — export sessions/reports to external tools, generate probe specs, score runs. The **MCP server is implemented as a bundled plugin** (`../plugins/mcp_server.py`, see [20-MCP-SERVER](20-MCP-SERVER.md)): stdlib-only, read-only by default, no dependency added to the core package. ## 4. Example plugin `plugins/example_plugin.py` demonstrates (a), (b) and logging: ```python def register(ge): ge.log("example plugin loaded") def on_state(hit): ge.recorder.event("plugin_state_transition", result=hit.retval) if ge.symbols.get("rpc_state"): ge.hook("rpc_state", on_leave=on_state) ge.add_command("gehits", lambda session, args: print("…and 0"), help="…") ``` Run it with: ```bash ./greeneye.sh run examples/scripts/trace_rpc.py --plugin plugins/example_plugin.py ``` ## 5. Testing a plugin 1. Load it against the demo firmware (`./greeneye.sh demo --plugin …`) — the session must remain green and the plugin's events must appear in `events.jsonl`. 2. Unit-test pure logic outside green-eye; keep hooks small. 3. Never let a plugin assume a particular firmware: gate on `ge.symbols.get(name)` and log a skip instead of failing. ## 6. Distribution Plugins can live anywhere. For in-tree plugins that document the workflow, put them under `plugins/` in this tool directory; for local or target-specific tooling, use `GREENEYE_PLUGINS` and keep paths out of tracked docs (project rule).