Plugin code inside the gateway
Hooks, tools and injected turns of every chat and every local session (CLI, TUI, Desktop) run in the one gateway process, not in the client you launched. Some process-level habits from the classic CLI do not carry over: os.getcwd() is the gateway's own directory, shared by every session; Hermes never changes it. Use ctx.session_cwd() for the working directory of the session the hook or tool runs for: the workspace a CLI/TUI/Desktop session was started in, or the profile's terminal cwd for a chat ( "" when there is none). Pass it as cwd= to subprocesses. It reads the session from the running turn, so it works in code that runs for a session: turn hooks, tool handlers and approval hooks. Ingress hooks such as pre_gateway_dispatch run before the message is admitted to any session; there it returns the profile's terminal cwd, or "" when none is configured. ctx.session_surface() names the calling session's client: "cli" , "tui" , "desktop" , "acp" , or the messaging platform ( "telegram" , …); "" outside a session. print() output goes to the gateway's gateway-stdio.log , not to your terminal. Use logging instead. input() gets end-of-file: the gateway has no terminal. Ask through a tool…
From the official Hermes Agent documentation.