Skip to content

Releases: BkashJEE/hermes-bot-forge

Bot Forge 0.20.0

Choose a tag to compare

@BkashJEE BkashJEE released this 12 Oct 10:12

A Bot stuck at a sign-in asks for you

A Bot that hits a login, a 2FA prompt or a CAPTCHA can now call request_takeover and say so, instead of failing at the wall where nobody sees it.

It writes a blocked journal entry — already the thing that mails you, already what what's waiting on you reads — carrying the reason and the command that opens that Bot's screen:

hermes -p marlow computer-use screen open

You sign in on the Bot's screen, not in chat. Hermes' desktop lease discards any frame captured across the hand-over, so what you type never reaches the Bot, and the tool tells the Bot not to ask you for a password.

It refuses rather than sending you to look at nothing: no running screen, a Hermes without Bot Screen support, a status call that failed, the main profile asking (it already has your attention), or no reason given — the reason is what you read before deciding to get up. The caller is resolved from the session, never a tool argument, so one Bot cannot summon you in another's name.

It does not resume on hand-back. The entry says so in words rather than implying otherwise; lease.on_change is the hook for building that, and it is the next piece.


Seventeen tools. 391 tests, lint clean, Linux and macOS.

hermes plugins update bot-forge

Bot Forge 0.19.1

Choose a tag to compare

@BkashJEE BkashJEE released this 11 Oct 03:07

A correction to v0.19.0. If you read that release and went looking for enforce_approvals, it was not there.

What v0.19.0 got wrong

Its notes said the policy layer was "shipped into every Bot the way the reaction companion is" and could be turned "off with enforce_approvals: false". Neither was true of that tag. sentinel/ shipped; the code that installs it did not, because the pull request adding it was closed unmerged when its base branch was deleted.

So v0.19.0 shipped a policy plugin and nothing that turned it on.

What 0.19.1 does

create_agent installs the layer the way it installs the reaction companion, and writes the policy that Bot's own declared approvals imply.

  • A Bot that declared no approvals gets the layer with no categories active — enforcing rules it never claimed would be inventing its policy rather than holding it to its word.
  • An operator edit is never overwritten: the derived policy merges under whatever is already in that Bot's config, so a refuse you added by hand survives a re-creation.
  • enforce_approvals: false turns the whole thing off.

Everything else about Sentinel is as v0.19.0 described: hooks only, no new tools for the Bot, answering Hermes' own pre_tool_call gate, and failing closed — an unreadable policy refuses rather than permits.

It is still not a sandbox. It governs tool calls, so a Bot with shell access can act outside it; per-Bot sandboxes remain the separate control.


376 tests, lint clean, Linux and macOS.

hermes plugins update bot-forge

Bot Forge 0.19.0

Choose a tag to compare

@BkashJEE BkashJEE released this 10 Oct 22:13

Correction (11 Oct): this release shipped the policy layer but not the code that installs it, and no enforce_approvals setting. The pull request adding those was closed unmerged when its base branch was deleted. v0.19.1 fixes it. The description below of what Sentinel does is accurate; the claim that every Bot gets it was not true of this tag.

Sixteen tools. The headline: a Bot's rules can be enforced outside the model.

Approvals are enforced, not requested

Every Bot Forge Bot has carried approval rules in its SOUL.md — ask before you send, spend or delete — as prose that nothing checked. A Bot that ignored them met no obstacle and left no record. That was tolerable when a Bot wrote files and answered questions. It stopped being tolerable once bot_screen gave one a real browser and its own desktop.

Hermes already had the gate; Bot Forge had never used it. The new sentinel/ companion — hooks only, no tools, shipped into every Bot — answers pre_tool_call with directives Hermes acts on: refuse the call outright, or route it to the human approval gate.

The policy a Bot gets is the one its own declared approvals imply. A Bot that promised nothing is given no categories, because enforcing rules it never claimed would be inventing its policy rather than holding it to its word.

It fails closed: an unreadable policy refuses rather than permits, and says so.

"May email me, not anyone else"

A tool-name gate cannot express that. Limits can:

bot-forge-sentinel:
  limits:
    send_email:
      to: ["me@example.com"]

Within the limit, the call runs without asking — the user already said that shape is fine. Outside it, refused, with the argument and value named. Unreadable input is a question, not a yes.

Bots hand work to each other

handoff_agent(to, task, context) moves ownership, not just a question. The receiving Bot works in its own Bot Chat, the outcome is read from its acknowledgement emoji rather than guessed from prose, and check_agents lists every handoff that has not ended in ✅ — the first answer to "where did that task go?". Only words cross between Bots: the task and context are secret-scanned, and the sender is the calling profile, never a tool argument.

Write a rule once, every Bot picks it up

~/.hermes/shared/BOT-POLICY.md is inlined into each new Bot's SOUL.md, with a fingerprint so drift is visible and check_policies to report it. By @gittyforthehub, built in a fork and upstreamed on request, with the design and its rejected alternatives written down.

macOS actually runs now

It had never run once. It does now, on 3.11 and 3.12 — and the platform claim is derived from the CI workflow rather than asserted in a constant, after the previous check went green while a test failed deterministically on macOS.

Two bugs that only showed up there, both found by people who ran it on hardware the maintainer does not have: ask_agent dropping USER so the Claude CLI saw no login (@akinduroifedayo), and a test comparing an unresolved temp path against a resolved one (@ChrisCarlCao).

Also

check_agents now says which Bots hold a readable login. Reuse-first provisioning and multiplex readiness from @sealca. A demo loop at the top of the README. Coverage reported per module in CI — never gated, because the number is a floor.


369 tests, lint clean, green on Linux and macOS. Ten contributors are named in the README; four of them found things on machines nobody here owns.

hermes plugins update bot-forge

Bot Forge 0.18.0

Choose a tag to compare

@BkashJEE BkashJEE released this 06 Oct 08:00

Share a Bot as a link

share_agent with publish: true posts the Bot template as an unlisted gist through your own gh and hands back a link; import_agent takes one in. The result says plainly who can read it — "unlisted" reads as private and is not — and that it carries no chats and no credentials. The secret scanner runs on the way in as well as out, so someone else's leaked key is refused rather than imported. Only https is fetched, with a 512 KB cap.

The waiting queue can deliver itself

notify.schedule() installs a hermes cron --no-agent --script entry, so the digest of what is waiting on you arrives on a schedule with no model turn and no email setup — stdout is delivered verbatim, and an empty queue prints nothing rather than mailing you noise. The active profile is read from the ◆ marker in profile list, and the script is installed where that profile will actually look for it.

A green CI that means something

Two releases have shipped unable to load while CI passed. Both times the cause was the same: unittest discover runs from inside the checkout, where '' on sys.path resolves a bare import forge that Hermes cannot.

  • A new job loads the plugin the way Hermes does — as a package, from outside the directory — and fails if any tool or hook named in plugin.yaml stops registering, if a handler is not callable, or if the doctor CLI command cannot run. It currently proves 14 tools, 2 hooks, 1 skill, 1 CLI command.
  • ruff runs pinned. Its first pass found three unused imports in shipped modules, a duplicate entry in a stopword set, a zip() quietly depending on the shorter side, and a raise inside except attaching an irrelevant traceback to a user-facing message.
  • Five test classes had been skipping themselves whenever the plugin failed to import, turning the single most important failure into 22 silent skips. They now import outright, and the suite checks itself for the shape: no assertion-free test, no except ImportError that becomes None, no skip conditioned on our own code importing.
  • Two except Exception blocks that had been hiding exactly this are narrowed.

Honest platform claims

The skill advertised Windows. No Windows machine has ever run this suite, every Windows path is exercised by patching sys.platform, and both reports that have come from Windows were the plugin failing outright. The skill now claims linux and macos, the README says Windows is not supported and why, and a test keeps the claim from drifting ahead of the evidence.

Also

Per-Bot artwork and a monochrome house-style mark. The 2,300-line test file is eight topic modules; the same 170 tests exist, verified by name.


203 tests. Verified at this commit that the plugin loads as a package from outside its own directory with only PyYAML installed.

Bot Forge 0.17.1

Choose a tag to compare

@BkashJEE BkashJEE released this 06 Oct 07:44

If you installed Bot Forge from the Hermes catalog, update. The commit the catalog pinned could fail to load entirely.

The plugin failed to load on an install without PyYAML

forge.py and manage.py import yaml, and no manifest ever declared it. On a machine where some unrelated package happened to provide PyYAML, everything worked. On a clean install, the loader logged one line —

WARNING hermes_cli.plugins: Failed to load plugin 'bot-forge': No module named 'yaml'

— and dropped all 14 tools and both hooks. hermes plugins list still printed bot-forge enabled, because enabled is a config flag, not a load result, so the failure was easy to miss entirely.

plugin.yaml now declares python_dependencies: [PyYAML>=6.0,<7], which hermes plugins install puts into the environment the plugin runs in and re-applies after later updates.

Found by @zhaees, on Windows, against the exact commit the catalog had pinned, with a full reproduction (#38, rebased as #49).

hermes bot-forge-doctor crashed on Windows

forge.load_yaml() read every manifest with no encoding, so on Windows it used the ANSI code page. The plugin's own plugin.yaml and marks/plugin.yaml both carry emoji, so it raised UnicodeDecodeError on the first read — and that is a ValueError, not an OSError, so it escaped an except (OSError, yaml.YAMLError) and took the caller down with it.

Found and fixed by @Plub-Supanut (#41).

CI could not have caught either

The workflow installed PyYAML by hand instead of from the manifest, so the missing declaration was never exercised — and the manifest-parsing step imports yaml, so the job supplied the dependency to itself. Test dependencies now come from requirements-dev.txt, and tests/test_declared_dependencies.py asserts every third-party import in the shipped plugin is declared with an upper bound.


Both of these were found on hardware the maintainer does not have, against the published pin. Thank you.

Bot Forge 0.16.0

Choose a tag to compare

@BkashJEE BkashJEE released this 02 Oct 09:11
43073b3

Seven releases of work since the last one published here (0.9.0). The short version: a Bot now knows where it landed, says what state your request is in, tells you when it is stuck, and cannot be built twice by accident.

Watch it

Both clips are attached below.

  • video.mp4 — 16s: the claim, the live catalog listing, the install line.
  • reaction.mp4 — 15s: 👀 lands on your message the moment a Bot picks it up, then becomes the outcome.

Since 0.9.0

It knows where it landed. create_agent surveys the workspace the Bot was born into — the directory Hermes runs in and the repos under it, plus this install's own Bots, skills and plugins — and writes the result into the Bot's memory. It knows which repo holds its work on turn one; nobody researches the machine. Deterministic word matching, no model call. It also refuses to build a Bot you already have, naming the one that covers the job.

It says where your request stands. A reaction lands on your own message as the turn runs, chosen from what you asked — 🔧 a fix, 🔎 research, ✍️ writing, 📊 numbers, ⏳ scheduling, 📋 a review, 🛠️ something to build — and becomes what happened when it ends: 🚀 shipped, 📝 written, 📈 numbers, 🗓️ scheduled, 💡 found out, ✅ done, ✋ needs you, ⚠️ blocked. Placed by a hook that ships inside each Bot, so it does not depend on the model choosing to.

It tells you when it is stuck. check_agents leads with everything waiting on you, gathered from the Bots' own journals with how long each has sat. A blocked Bot can also email you, using the mail Hermes already has — outbound only, to your address and no other, never a recipient from a tool call.

It can inherit your plugins, when asked. Opt-in, and a blanket request stops at any plugin that declares requires_env: reach into an account has to be asked for by name.

Plus teams in one call, per-Bot work journals, an install doctor, per-Bot Docker sandboxes, five starter templates, and secret-scanned sharing.

Fixed

A full catalog security review (thanks @teknium1) and a second review pass found: the plugin failing to load at all and dropping its 14 tools, SMTP that could send a password in cleartext, mail switches that silently did nothing, adoption writing into profiles it did not create, a credential store shared between profiles by symlink, and a notification default that behaved as off. hermes plugins validate reports capability probe ✓ and security scan — safe.

@samideckers-cmd found that ask_agent forwarded the caller's whole environment to a different Bot, and reported the package-import problem days before it bit. @sealca found that creation claimed a gateway it never started.

174 tests.

Bot Forge 0.9.0

Choose a tag to compare

@BkashJEE BkashJEE released this 24 Sep 17:43
7d7f9bf

The acknowledgement now lands on your own message, the moment you send it: 👀 while the Bot works, then ✅ / ✋ / ⚠️ for how the turn ended.

The plugin places that reaction itself. Leaving it to the model was never going to work — Hermes' react_to_message tells the model it is a human touch, "never as a status signal", so a Bot asked to signal status with it did nothing at all.

Desktop sessions only (the tool exists nowhere else), needs Settings → Appearance → Message Reactions, off with ack_tapback: false, and a failed reaction can never break a turn. The reply prefix from 0.8.0 still covers CLI, editor clients, cron and messaging.

83 tests.

Bot Forge 0.8.0

Choose a tag to compare

@BkashJEE BkashJEE released this 24 Sep 17:31
333d246

Every reply now says where your request stands. A Bot begins its answer with one emoji — 👀 started · 💬 answering · ✅ done · ✋ needs your approval · ⚠️ blocked · ⏳ scheduled — then answers as normal.

This replaces the emoji tapbacks from 0.7.0, which could not do the job. Hermes' own react_to_message tells the model it is a human touch, "never as a status signal"; it exists only in desktop sessions; and it is gated behind an opt-in Appearance setting. Tested live with the setting on and the tool available, a Bot still never used it. The reply prefix needs no setting and behaves the same in Desktop, editor clients, the CLI, cron and messaging.

Switching a Bot on now replaces any older convention block instead of stacking a contradictory second one.

78 tests.

Bot Forge 0.7.2

Choose a tag to compare

@BkashJEE BkashJEE released this 24 Sep 17:12
6af6dd1

A Bot created by Bot Forge could never react in Hermes Desktop — the acknowledgements added in 0.7.0 looked broken for exactly the Bots this plugin makes.

Its canonical Bot Chat was created with chat -c "Bot Chat" --create-if-missing, which hardcodes source="cli" upstream. A session's stored source decides its client surface, and the Desktop toolset holding react_to_message is granted only to desktop sessions — so the tool was never offered, whatever the persona said. Bots created through Desktop were fine; Bots created here were not.

On a Bot Mode install the chat is now started with --source desktop and then given the canonical title, matching what Desktop does. Existing chats are continued unchanged, and installs without Bot Mode keep a plain CLI session.

76 tests.

Bot Forge 0.7.1

Choose a tag to compare

@BkashJEE BkashJEE released this 24 Sep 09:45
cf2647f

Acknowledgement reactions were written into a Bot's persona at creation, so only new Bots got them — while reactions come from the Bot you talk to, which on any existing install predates the feature. It looked broken because it was.

  • check_agents reports acknowledges per Bot and lists not_acknowledging
  • hermes bot-forge-doctor counts acknowledging Bots and names the ones that don't
  • the bundled skill tells an agent to check the current Bot first when reactions aren't happening

Switch one on: ask an agent to "turn on acknowledgements for " (update_agent(ack_reactions: true)).

72 tests.