Innerscape for Hermes
You're talking to your agent at the end of a long day and you want to note how it went, but opening another app breaks the moment. This plugin lets Hermes save a quick check-in or a journal entry to your own Innerscape server, and look back on today with you. It logs only what you say about yourself, asks before it saves any reflection, and never scores, labels or diagnoses a mood.
What it adds
- Four agent tools.
innerscape_checkinsaves one check-in in your words: energy from 0 to 100, whether it feels pleasant, unpleasant or neutral, and an optional feeling word and body note. It saves only when you asked to log it or said yes; the tool refuses unlessuser_confirmedis true.innerscape_journalsaves one journal entry, exactly as written. The agent must show you the text and any tags and get a yes first; the tool refuses unlessuser_confirmedis true.innerscape_captureparks one item in your Innerscape inbox, such as a task you're putting down, an idea or a note for later. The agent shows you the exact words and asks first; the tool refuses unlessuser_confirmedis true.innerscape_todayreads today's counts (check-ins, journal entries, habits, tasks, captures) and your latest check-in with its date. A check-in the app inferred, rather than one you logged, is left out.
- A slash command.
/innerscape today | checkin <0-100> <pleasant|unpleasant|neutral> [feeling] | journal <text> | capture <text> | status | help. Typingjournalorcapturewith your text is your yes to saving it. - A Desktop page. In Hermes Desktop, Innerscape gets its own page in the sidebar: today's counts and your latest check-in, an Unstuck Coach card, a check-in form, and a journal box. A journal entry is saved only after a dialog shows you the exact text and tags and you press Save. Get unstuck opens a new chat with your note in the composer, ready for the coach; nothing is sent until you press send. The command palette has Innerscape: open, check in, write in journal and get unstuck, and a small cairn in the status bar opens the page (you can hide it in Settings ▸ Plugins ▸ Innerscape).
- The Unstuck Coach. The bundled
unstuckskill is an executive-function coach for when you want to do the thing and can't start, switch or stop. It names what's in the way without blame, gives one next move small enough to start in under two minutes, and holds the rest, offering to park it in your inbox. It reads your latest check-in to size the move, never diagnoses or advises on medication, never acts on your accounts, and stops coaching to point you to 988 or emergency services in a crisis. Adapted from Unstuck Coach (KyaniteLabs/unstuck-coach-live, MIT). - A reflection skill. The bundled
innerscapeskill keeps the agent to one grounding observation, one small next step and one place to capture a follow-up. It carries the Innerscape guardrails: no diagnosis, no automated life decisions, consent before anything sensitive becomes a record, and small reversible steps when you're overwhelmed.
Install
hermes plugins install KyaniteLabs/Innerscape/plugins/innerscape-hermes
hermes plugins enable innerscape
You need a running Innerscape backend (see the main README) and a token. Hermes asks for INNERSCAPE_TOKEN when you install.
On a fresh server, create your account first. The password needs at least 12 characters:
curl -s -X POST http://127.0.0.1:3001/api/v1/auth/register \
-H 'content-type: application/json' -d @-
Then log in to get a token:
curl -s -X POST http://127.0.0.1:3001/api/v1/auth/login \
-H 'content-type: application/json' -d @- | jq -r .token
Type {"email":"you@example.com","password":"..."}, press Ctrl-D, and put the printed token in INNERSCAPE_TOKEN (for example in ~/.hermes/.env). Reading the body from the terminal keeps your password out of your shell history.
Then restart Hermes and try it:
/innerscape status
/innerscape checkin 60 pleasant rested
The second line should answer Saved a check-in: energy 60, pleasant, rested.
Turn on the Desktop page. Hermes Desktop installs the page with the plugin but leaves it off. Open Capabilities ▸ Plugins, search for Innerscape, open it and switch it on. The Innerscape page then shows in the sidebar, and the cairn shows in the status bar. If your Desktop app connects to Hermes on another machine, install the plugin on both: the tools run where Hermes runs, and the page loads from the app's own machine.
Tokens last 7 days by default. /innerscape status shows whether the token is set, when it expires, and whether the server is up. It never prints the token.
What it does on your machine
- It talks only to your server. Each call goes to
base_urlover the Innerscape REST API, using the Python standard library. Plainhttpis allowed only to this machine (127.0.0.1,::1,localhost); anywhere else needshttps, so your token never crosses a network in clear text. - Your token stays put. It is sent only as the
Authorizationheader tobase_url. Proxy settings in the environment are ignored and redirects are not followed, so neither a proxy nor a redirect can pick up the token. A token with spaces or control characters is refused before any request, and error messages have the token scrubbed out. - The token is a full-account key. Innerscape has no read-only or scoped tokens yet, so the one in
INNERSCAPE_TOKENcan read and change everything in your account. Keep it in~/.hermes/.env, not in a shared config. - It keeps nothing, but Hermes does. The plugin writes no files and keeps no copy of what it sends; your entries live in your Innerscape database. What a tool returns goes to your model provider like any other tool result, and Hermes keeps it in the session history.
- Mood text is sensitive. Before your first check-in, check your model provider's privacy policy and retention terms; what you log about how you feel travels with your chat.
- It reads back only what you logged.
innerscape_todaydrops the server's derived state labels, its low-energy streak count and any check-in the app inferred. The agent reflects; it doesn't classify you. - A save means a saved record. The plugin reports a save only when the server answers with the new record. If the reply is missing or odd, it says the entry may or may not be saved.
- The Desktop page uses the same client. Its routes (
dashboard/plugin_api.py, under/api/plugins/innerscape/) call the agent half's own functions, so the same token handling, limits and loopback rule apply. Hermes serves them only to an authenticated Desktop or dashboard session, and only while the plugin is enabled. The Get unstuck card has no route of its own: it hands your note to a new chat through the Desktop composer, and the coach runs there with the same tools and gates. The page keeps its own unsaved drafts in memory and forgets them when you quit or disable the plugin. Get unstuck moves your note into a Hermes chat draft, which Hermes stores like any other unsent message; once you send it, it is part of that chat. It stores one setting, whether the status-bar cairn shows. While the page is open it refreshes today's counts and the connection once a minute. - Nothing runs in the background. No telemetry, no scheduled check-ins, no automatic journaling. The plugin acts only when you or the agent call a tool or the slash command, and it refuses to save anything during a scheduled (cron) run.
Settings
Set these under plugins.entries.innerscape.settings. The two allow_ settings turn on only for a real true; a string such as "false" or "yes" leaves them off.
| Key | Default | What it does |
|---|---|---|
| base_url | http://127.0.0.1:3001 | Your Innerscape API server. Plain http only to this machine |
| allow_reads_on_gateway | false | Allows reading today's counts and latest check-in from chat platforms |
| allow_writes_on_gateway | false | Allows saving check-ins, journal entries and inbox items from chat platforms such as Telegram or Discord |
| timeout_seconds | 10 | Overall time limit for each API call, including reading the reply (2 to 60) |
Known issues
- Off on chat platforms. A Telegram or Discord chat can include other people, so reading
todayand saving check-ins, journal entries or inbox items are refused there unless you setallow_reads_on_gateway: trueorallow_writes_on_gateway: true. Think about who else is in the chat before you turn either on. - A slow save may still land. If the server times out after a check-in or journal entry was sent, it may already be saved. The error says so; check Innerscape before trying again.
- Tokens expire. After 7 days (or your server's
JWT_EXPIRES_IN), calls fail with a message that says how to log in again. Hermes readsINNERSCAPE_TOKENwhen it starts, so restart it after you change the token. - "Today" is the server's today. The daily summary counts from midnight in the server's time zone, which may differ from yours.
- The guardrails are instructions to the agent. The save tools refuse unless
user_confirmedis true, but the model sets that flag after it asks you; Hermes has no separate approval step for plugin tools. So the consent check is a code guard backing the model's instructions, not a guarantee. A/innerscapecommand you type yourself is your own yes. "Reflect, don't label" and the crisis guidance are likewise instructions, not guarantees. - Pasted text reaches the model. Anything you paste into the coach, such as a message you haven't answered, goes to the model with the save tools available. Text written to steer an AI could try to get it to save something; the model still has to show you the words and ask first.
- Not a crisis service. Innerscape and this plugin are for everyday reflection. The tools and the skill tell the agent to stop and point to local emergency services or a crisis line (in the US, call or text 988) if you mention self-harm or a crisis.
statusdoesn't test the token. The server has no "who am I" endpoint, sostatusreads the token's expiry date and checks/health. A wrong token shows up on the first real call.- Platforms. Tested on Linux (agent, dashboard and browser-hosted Desktop) and in Hermes Desktop on macOS. Windows is unverified.
Tests
cd plugins/innerscape-hermes
python -m pytest tests -q
The tests run against a fake Innerscape API on 127.0.0.1 that checks request bodies the way the real server does, and the Hermes v0.21.6 gateway/session_context.py, vendored verbatim under tests/hermes_runtime/ with its MIT license. They need pytest; the Desktop page's route tests also need fastapi and httpx and are skipped without them.
The Desktop half has its own check, on Node 18 or later:
cd plugins/innerscape-hermes/desktop
node --test tests/plugin.test.mjs
It runs the real plugin.js against stubbed SDK and React modules and checks what it registers, how it handles stored settings, that it forgets drafts on unload, and that it uses no eval, raw network calls or browser storage. It does not render the page. The page was rendered in headless Chrome, against a stand-in host with the Desktop theme, at 320 to 1440 px wide and with its journal dialog open.
After changing the fonts or the cairn, rebuild the embedded copies with python3 tools/embed-assets.py.
License: MIT, the same as Innerscape. The unstuck skill is adapted from Unstuck Coach (KyaniteLabs/unstuck-coach-live, MIT License © Kyanite Labs); its notice carries over.
README from the reviewed commit 709dc6a; it updates when the author re-pins.

KyaniteLabs

