All plugins

hermes-windows-process

Answer "what is still running, and who started it" on Windows: win_process_table reads the process table (PID, parent PID, image name) and adds each process's image path and creation time, then marks every row with whether its recorded parent is still the process that spawned it. Windows stores a parent PID rather than a handle, so a child that outlived its parent points at a PID that is either unused or reused by a newer process; a parent that started after its child cannot have spawned it, so both cases are reported as gone or reused instead of a plausible but wrong parent name. Filters cover one PID, several PIDs, a name or path substring, a parent PID, and an orphans-only view of what outlived its parent, with a result cap and an option to leave out Windows session processes. Use it for leftover gateway/backend/server children after a quit, for telling thirty python.exe rows apart by start time, and for checking whether a process started before or after the thing being debugged. Read-only: processes are opened with PROCESS_QUERY_LIMITED_INFORMATION for QueryFullProcessImageName and GetProcessTimes only - no memory reads (command lines are deliberately out of scope), no handle duplication, no writes, no child processes. Stdlib-only (ctypes): no Python dependencies, no network calls, no file writes, no self-update. Windows only. Disclosure - the tool reports image names, image paths and start times to the model, and those routinely include the user and machine name (C:\Users\<name>\...) and reveal which editor, shell or agent started which process; treat the output like a Task Manager screenshot.

Yicheng-MarkToolsv0.1.0Updated 12 days ago

About

Answer "what is still running, and who started it" on Windows: win_process_table reads the process table (PID, parent PID, image name) and adds each process's image path and creation time, then marks every row with whether its recorded parent is still the process that spawned it. Windows stores a parent PID rather than a handle, so a child that outlived its parent points at a PID that is either unused or reused by a newer process; a parent that started after its child cannot have spawned it, so both cases are reported as gone or reused instead of a plausible but wrong parent name. Filters cover one PID, several PIDs, a name or path substring, a parent PID, and an orphans-only view of what outlived its parent, with a result cap and an option to leave out Windows session processes. Use it for leftover gateway/backend/server children after a quit, for telling thirty python.exe rows apart by start time, and for checking whether a process started before or after the thing being debugged. Read-only: processes are opened with PROCESS_QUERY_LIMITED_INFORMATION for QueryFullProcessImageName and GetProcessTimes only - no memory reads (command lines are deliberately out of scope), no handle duplication, no writes, no child processes. Stdlib-only (ctypes): no Python dependencies, no network calls, no file writes, no self-update. Windows only. Disclosure - the tool reports image names, image paths and start times to the model, and those routinely include the user and machine name (C:\Users\<name>\...) and reveal which editor, shell or agent started which process; treat the output like a Task Manager screenshot.

hermes-windows-process

Answer "what is still running, and who started it" on Windows, from inside Hermes.

win_process_table({"process": "hermes"})
win_process_table({"orphans_only": True, "include_system": False})
win_process_table({"pid": 21432, "with_ancestry": True})

The tool reads the same process rows Task Manager does — CreateToolhelp32Snapshot gives
PID, parent PID, image name and thread count — then opens each process read-only for its
image path and start time. That last field is what makes the parent column mean
something: Windows stores a parent PID, not a handle, so once the parent exits its PID is
free for reuse, and a child that outlived it points at an unrelated newer process. A parent
that started after its child cannot have spawned it.

| parent_state | Meaning |
|---|---|
| alive | The parent PID belongs to a process that started before this one — the real parent. |
| gone | No process holds that PID any more: the parent exited and this one kept running. |
| reused | The PID is in use, but by a process that started later, so the original parent is gone. |
| unknown | The parent row exists but one of the two start times could not be read. |
| root | Parent PID 0 — the top of the table. |

Output

{
  "ok": true,
  "matched": 2,
  "total_processes": 308,
  "orphans": 9,
  "orphans_gone": 9,
  "orphans_reused": 0,
  "entries": [
    {"pid": 10004, "parent_pid": 8640, "process": "cc-switch.exe",
     "path": "C:\\Users\\warri\\AppData\\Local\\Programs\\CC Switch\\cc-switch.exe",
     "started": "2026-10-24T14:19:31Z", "age_seconds": 41040, "threads": 12,
     "parent_process": null, "parent_state": "gone", "system": false}
  ],
  "ancestry": [],
  "notes": ["2 of 308 process(es) matched"]
}

Ordering puts the oldest process first, which is how you find the survivor rather than the
thing you just started. ancestry carries the chain up to the top of the table for each
matched PID when with_ancestry is set, marked context: true.

Filters

| Argument | Effect |
|---|---|
| pid / pids | Match specific process IDs. |
| process | Case-insensitive substring of the image name or path. |
| parent | Only processes whose parent PID is this value. |
| orphans_only | Only gone and reused — what outlived its parent. |
| with_ancestry | Add the ancestor chain of each match. |
| include_system | Default true. false drops images under the Windows directory and processes this account cannot open. |
| limit | Default 100, max 500. |

Session and bootstrap processes (csrss, wininit, winlogon, services, explorer) are
started by a parent that exits by design, so they always read gone without being a leak.
They are flagged system: true, and the notes say how many of the flagged rows are theirs.

What it does not do

  • No command lines. Reading another process's command line on Windows means reading its
    memory (the PEB) through ReadProcessMemory. This plugin does not read process memory, so
    it reports the image path and start time instead. wmic process get commandline or
    PowerShell's Get-CimInstance Win32_Process still answer that, at a second or more per
    call and with a child process spawned each time.
  • No killing. Terminating a PID that may have been reused is a good way to kill the
    wrong thing; the tool is read-only on purpose.
  • No job-object membership. IsProcessInJob(handle, NULL) answers true for every
    process on Windows 8 and later (the system root job), so it cannot be used to tell whether
    a child would die with its parent.

Install

git clone https://github.com/Yicheng-Mark/hermes-windows-plugins /tmp/hermes-windows-plugins
cp -r /tmp/hermes-windows-plugins/windows-process ~/.hermes/plugins/hermes-windows-process
hermes plugins enable hermes-windows-process

Or install the catalog entry by name once it is listed: hermes plugins install hermes-windows-process.

Disclosures

The tool reads the process table and each process's image path and creation time, and hands
them to the model: image names and paths routinely carry the user name
(C:\Users\<name>\...), and the ancestry chain shows which editor, shell or agent started
which process. Treat the output like the Task Manager screenshot it replaces.

Everything is read-only: PROCESS_QUERY_LIMITED_INFORMATION only, no memory reads, no
handle duplication, no inheritance, no writes, no child processes, no network calls, no file
writes, no self-update. Stdlib-only (ctypes against kernel32).

Tests

python -m pytest tests/     # 14 unit + 4 live; the live ones skip off Windows

License

MIT.

README from the reviewed commit 5bad3fb; it updates when the author re-pins.

More by Yicheng-Mark

15 plugins by Yicheng-Mark in the catalog.

Yicheng-Markhermes-dpapi-secretsResolve Hermes environment variables at startup from a single secret file encrypted with the Windows Data Protection API, instead of keeping provider keys in plaintext in .env or auth.json. Config is secrets.dpapi.map, an ENV_VAR -> store-name mapping (bare names or dpapi:// names) plus an optional file path (default <HERMES_HOME>/secrets.dpapi). The file is one DPAPI blob keyed by the current Windows user profile, so it is unreadable by another Windows account and worthless off the machine; it is written by the bundled CLI (python -m hermes_dpapi_secrets set NAME, value read from a prompt or stdin, never from argv) and only read at runtime. Mapped names that are missing or empty are skipped with a warning; a file that is not ours, a blob this user cannot decrypt, or a payload that is not a flat string map is reported as an error with nothing injected. Disclosure - this source decrypts a file for every Hermes process that enables it: resolved values become environment variables of the Hermes process and its children, exactly like .env entries, so anything that can read that environment can see them. User-scope encryption only (the machine-wide flag is never used and is not exposed), and the at-rest protection is a bar for backups, cloud sync and dotfiles, not a boundary against code already running as the same user. Stdlib-only (ctypes): no Python dependencies, no subprocesses, no network calls, no self-update. Windows only. Applying fetched values stays the orchestrator's job; the plugin never writes os.environ itself. Disclosure — decrypts a DPAPI-encrypted secret file (default <HERMES_HOME>/secrets.dpapi) at startup for every Hermes process that enables it, and the resolved values become environment variables of Hermes and its child processes like `.env` entries; the encryption is per Windows user and protects backups, cloud sync and copied files, not against other code running as the same user. Local only: no network calls, no subprocesses.CommunitytoolsYicheng-Markhermes-wincredResolve Hermes environment variables from the current user's Windows Credential Manager at startup, instead of keeping provider keys in plaintext in .env or auth.json. Config is secrets.wincred.map, an ENV_VAR -> generic-credential-target mapping (bare names or wincred:// names); each value is read with CredReadW in the current user's vault and handed to the secret-source orchestrator, which applies it with the usual precedence, provenance and conflict rules. Values may be UTF-8 or UTF-16LE (cmdkey and the Credential UI write UTF-16); anything that does not decode to text, or that contains interior NULs, is skipped with a warning instead of being injected as a mangled key. Disclosure - this source reads your Windows Credential Manager: only the generic credentials named in the map, with no enumeration of the vault. Resolved values become environment variables of the Hermes process and its children, exactly like .env entries, so anything that can read that environment can see them. The package is read-only and stdlib-only (ctypes): it never creates, updates or deletes credentials, writes no files, starts no subprocesses, makes no network calls and does not self-update. Windows only. Credential Manager is user-scoped, so this raises the at-rest bar for backups, cloud sync and dotfiles; it is not a boundary against code already running as the same user. Applying fetched values stays the orchestrator's job; the plugin never writes os.environ itself. Disclosure — when enabled, reads only the Windows Credential Manager generic credentials named in secrets.wincred.map (no vault enumeration) and injects them as environment variables of the Hermes process and its children, exactly like .env entries; read-only, stdlib ctypes, no subprocesses, no network, no file writes; user-scoped at-rest protection, not a boundary against code already running as the same user.CommunitytoolsYicheng-Markhermes-windows-appsAnswer "what is installed on this Windows machine": the software inventory behind Apps & Features, swept straight from the four Uninstall registry keys (the machine's 64-bit and 32-bit views plus the user's), so a program is found even when the Settings page hides it - a per-user install that never shows on the machine page came from the user view on the writing machine. Each row carries version, publisher, size in MB, install date and which view it lives in; the same DisplayName in two views is a 32/64-bit dual install, marked instead of listed twice. Entries the publisher asked to hide (runtime packages, update rollups) are filtered out unless asked for. Details one program with every field its publisher wrote and a reading of the uninstall command (MSI product code, setup executable, appx, script) so the next step is known before anything is run; the install folder is checked against disk. Use it for "what did that installer actually register", for inventory before a cleanup, and for "which of the two installs does uninstalling remove". Read-only: registry keys are enumerated and uninstall strings are reported, never run; no network, no file writes, no elevation. The sweep is pure registry - 102 entries in seven milliseconds on the writing machine, the whole table in ten, no PowerShell, no WMI. The plugin declares no Python dependencies. Windows only. Disclosure - the tools report program names, versions, publishers, sizes, install folders and uninstall commands, and what is hidden from Apps & Features, to the model; treat the output like the machine's own Apps & Features page.CommunitytoolsYicheng-Markhermes-windows-devicesAnswer "which device on this Windows machine is unhappy, and what does it need" on Windows: win_device_table lists every present PnP device with its class (System, Net, HIDClass, Display), its status, its manufacturer, its stable device id, and its problem code in words - 28 is one with no driver installed, 10 one that cannot start, 43 one Windows stopped after it reported a failure, 22 one the person switched off on purpose and is not broken - filtering by name or id substring, by class, or to the devices that need attention; devices no longer plugged in are history, left out unless asked for. win_device_detail takes one device by id or name substring and adds the driver behind it from the signed-driver table - name, version, date, provider, signer, INF file, signed or not - or the absence of one, which for code 28 is the same fact said twice; a disabled device gets a note saying it is on purpose, not an alarm. Use it for the Device Manager yellow-mark question without opening Device Manager, for finding what an uninstalled program left behind, and for what changed after an update. Read-only: nothing is enabled, disabled, updated or reinstalled. Both answers come from CIM (Win32_PnPEntity and Win32_PnPSignedDriver, joined by device id), whose property names, enum values and ids do not change with the display language; the human-facing device names localize and are carried through as data, never parsed. The plugin declares no Python dependencies; there is no network call and no file write. Windows only. Disclosure — the tools report device names, manufacturers, device ids and driver versions to the model, and those reveal the machine's hardware inventory and what is plugged into it; treat the output like a Device Manager window opened on their machine.Communitytools

Developer Mode

Explore built-in Hermes toolsets and actions.

HermesAgent

Developer?

Create a Hermes extension for Desktop or agent workflows.

Developer Section