Skip to main content

decisions

❖ Communityv0.1.0

Predicate Decisions API tools with background jobs and session-owned structured JSON results.

Open in Hermes Desktop
hermes plugins install decisions

What it adds

Tools 2

decisions_submitdecisions_status

Environment variables it needs 1

OPENAI_API_KEY

README

From the reviewed commit eeac2ea ↗; it updates when the author re-pins.

Decisions for Hermes

A standalone, predicate-only Hermes Agent plugin for the OpenAI Decisions API. Submit text and yes/no questions, get probabilities, and retrieve the original decoded JSON result with session-owned status. Background execution is the default; foreground execution uses the same bounded transport. MIT licensed; not an official OpenAI or Nous plugin.

Requirements and installation

  • Hermes 0.22.5 or newer, Python within Hermes's supported range (3.11–3.14). Integration tests exercised Hermes v0.22.5, revision bf0203a794a07aac3ff764972ab9087baa4e4f4e, with Python 3.14.7. Older Hermes releases and other Python versions have not been tested here.
  • An API key authorized for Decisions. The public defaults are https://api.openai.com/v1/decisions, model gpt-6-luna, scoped secret OPENAI_API_KEY. A ChatGPT/Codex subscription sign-in is not an API key.
  • Runtime dependency: httpx>=0.23,<0.29, declared in plugin.yaml. The HTTPX 0.23 API supports the async streaming/raw-byte client used here; tests used 0.28.1, compatible with Hermes's 0.28.1 core pin. Hermes's package manager owns dependency admission. No OpenAI SDK or other runtime package is needed.

Obtain a source checkout or downloaded source directory from this repository and review it before installing. From your existing Hermes environment:

hermes plugins install /absolute/path/to/hermes-decisions-plugin --yes-deps
hermes plugins enable decisions

Installation may prepare dependencies through Hermes's package manager; --yes-deps is explicit consent. Use the installer's native API-key prompt or Hermes Desktop's plugin settings secret field to configure OPENAI_API_KEY for the active profile. Do not put the key in config.yaml, tool arguments, or source files. Restart your Hermes session through your normal operator procedure to pick up the enabled tools. No catalog listing is assumed: installation by catalog name is available only after maintainer admission. Current manifest version is 0.1.0, a pre-release candidate.

Configuration

Merge into your existing Hermes configuration, preserving other plugins/settings:

plugins:
  enabled: [decisions]
  entries:
    decisions:
      allow_gateway_injection: false
      settings:
        endpoint: https://api.openai.com/v1/decisions
        decision_model: gpt-6-luna
        credential_ref: OPENAI_API_KEY
        credential_endpoint: https://api.openai.com/v1/decisions
        timeout: 120

Settings are read anew for each submission. decision_model avoids Hermes's reserved model setting. credential_ref is a scoped secret name, never its value. The manifest's api_key secret field maps to OPENAI_API_KEY through Hermes's native credential route, not an ordinary setting. The plugin calls agent.secret_scope.get_secret inside each submission's preserved context; it never reads credential files, caches a startup key, or reads credentials directly from the environment. Missing scoped credentials fail closed under multiplexing.

Alternate operator-approved HTTP(S) endpoints and model identifiers remain supported. Set both endpoint and credential_endpoint to the exact same URL after reviewing where the credential may be sent. Changing only the endpoint fails before secret retrieval or network I/O. This equality check is not a network allowlist or egress approval. URLs cannot include credentials, queries, or fragments. Use HTTPS except on an explicitly trusted local/private transport: HTTP exposes the bearer credential and request contents to the network. Configure an alternate credential_ref through Hermes's native credential management; the default secret UI/prompt still names OPENAI_API_KEY and does not dynamically provision alternate secret names.

Timeout is total wall-clock request seconds, greater than zero and at most 600 (default 120). No proxy or environment authentication is inherited; TLS verification is on. No retries, redirects (even same-host), fallback endpoint or fallback model.

Tools and wire contract

Call decisions_submit:

{"input":"The package arrived.","questions":[{"type":"predicate","instructions":"Did the package arrive?"}]}

The default background:true returns promptly:

{"job_id":"…","state":"running"}

Call decisions_status with {"job_id":"…"} to retrieve the owned snapshot:

{"job_id":"…","state":"completed","result":{"answers":[{"type":"predicate","name":null,"probability":0.95}]},"notification_accepted":false}

background:false waits and returns the status snapshot directly. Failed operations have state:"failed" and a safe error, never the remote response body. Admission, configuration and ownership errors return {"error":"…"}. A foreground wait error may include a job ID for polling; do not resubmit automatically.

The request body is {model,input,questions}: string input and 1–64 unnamed predicate questions, each with string instructions. This is intentionally a subset of the upstream API: no choice, score, images, structured input, named questions, or extra request controls. Responses must contain one predicate answer per question in order, with null name and numeric probability in [0,1]. The official create-decision reference defines optional question names and nullable answer names, so unnamed predicates keep this contract. Upstream refusals are rejected as unsupported answers, not interpreted as probability zero or a successful partial result. Invalid/nonfinite JSON also fails. Additional response fields are retained unchanged in result: decoded JSON fidelity, not raw byte/format fidelity. Probabilities are model estimates, not guarantees; choose and validate application thresholds separately.

A captured session key or session ID is required; tool arguments cannot choose an origin. Jobs belong to the canonical Hermes home plus session key, or a separately namespaced session ID when no key exists. Foreign, unknown and evicted jobs produce the same not-found error.

Background notices, safety and lifecycle

Completion attempts a concise ctx.inject_message notice at the captured origin when the originating transport supports async delivery. Foreground calls use the same completion path. Gateway/TUI injection requires separate native operator consent (allow_gateway_injection) and a live injector. The default above does not grant that consent. notification_accepted:true means the host accepted the call, not proof of chat delivery or a completed turn. Denial/error leaves status usable. The notice includes a job ID and state, not the input, result or credential. A host may process an accepted notice as another agent turn. One-shot/stateless sessions cannot be relied on to receive later notices or retain a background worker.

Installation disclosures:

  • Network: each accepted job sends the full supplied text/questions, model identifier and bearer credential to the configured endpoint (OpenAI by default). Usage may be billable and is subject to that provider's terms and data policy. Nothing is sent until a tool submission; import/registration makes no inference request.
  • Background: one context-preserving continuing asyncio loop on a daemon thread per loaded plugin, with native supervised task leases; no shell children or service.
  • State: volatile in-memory jobs only. No persistence, scheduler, database, telemetry, credential storage, automatic updater, core overrides, or filesystem content reads by the plugin. Hermes itself owns configuration and credential retrieval.
  • Bounds: at most 4 active requests, foreground included, no waiting queue; retain the latest 32 terminal results plus active jobs. These conservative local caps permit interactive overlap/recent polling, not endpoint quotas.
  • Requests are limited to 262144 serialized ASCII JSON bytes, responses to 1048576 raw JSON bytes, streamed in chunks of at most 65536 bytes. Only identity content encoding is accepted; oversized data fails without retaining a result. Retained response wire content is at most 32 MiB plus 4 MiB active content. Decoded Python objects, parsing and serialization add overhead: this is not an exact RSS cap.
  • Unload cancels/drains requests on their owning loop, closes clients, joins the worker and drops results. Restart/process loss loses jobs. A timeout, transport failure, unload or process loss can leave the remote outcome uncertain. No durable, exactly-once or recovery guarantee. Do not automatically retry/resubmit.

Host API compatibility and admission warnings

The plugin uses native register_tool, spawn_task, on_unload and inject_message surfaces, plus agent.memory_provider.spawn_context_thread, agent.secret_scope.get_secret, hermes_constants.get_hermes_home and gateway.session_context helpers. The public threading contract requires context-preserving threads; the plugin guide documents session identity through get_session_env and message injection. The released source supplies async_delivery_supported, spawn_task and on_unload; not all helpers have a dedicated public documentation section. The released native validator reports a private-core-import warning for worker.py:11 gateway.session_context.async_delivery_supported and worker.py:11 gateway.session_context.get_session_env, even though get_session_env is documented. Its security scan reports safe, with no runtime core rebinds found. Keep these warnings visible for review rather than replacing context-safe native APIs with environment reads or hiding imports. Plugin-host subprocess isolation is not claimed; Hermes's validator reports its own host-readiness assessment.

Reproduce isolated tests

Use an existing Hermes v0.22.5 source checkout and its compatible interpreter with httpx, pytest and PyYAML already available. Tested versions: Python 3.14.7, httpx 0.28.1, pytest 9.1.1, PyYAML 6.0.3. No installation or live credentials are needed by these tests. From this plugin source directory, set real paths:

HERMES=/absolute/path/to/hermes-agent
PYTHON=/absolute/path/to/compatible/python
SCRATCH="$PWD/outputs/test-runtime"
mkdir -p "$SCRATCH/home" "$SCRATCH/empty-plugins"
env -i PATH=/usr/bin:/bin HOME="$SCRATCH/home" HERMES_HOME="$SCRATCH/home" \
  DECISIONS_TEST_SCRATCH="$SCRATCH" HERMES_BUNDLED_PLUGINS="$SCRATCH/empty-plugins" \
  HERMES_ENABLE_PROJECT_PLUGINS=false PYTHONPATH="$HERMES" PYTHONDONTWRITEBYTECODE=1 \
  "$PYTHON" -m pytest -q -p no:cacheprovider \
  -o log_file="$SCRATCH/pytest.log" --basetemp="$SCRATCH/pytest" tests

Choose an owned disposable scratch path. The harness discovers only its synthetic-home copy of this plugin, disables installed plugin entrypoints and suppresses automatic discovery while importing model_tools. An audit hook rejects SQLite opens, non-loopback socket connections/binds and file writes outside scratch. It exercises real native discovery/registry/async bridges and deterministic loopback HTTP with synthetic scoped credentials: background liveness, JSON results, ownership, context, consent, foreground, failures, limits, retention, capacity and unload. It does not prove live OpenAI inference, installation dependency resolution, or actual chat delivery.

For catalog admission, separately run the official command in a disposable Hermes development environment, after reviewing its effects:

hermes plugins validate /absolute/path/to/hermes-decisions-plugin --install-deps

--install-deps can create and select a dependency environment generation; a synthetic HOME alone does not isolate Hermes's package manager. Do not run it against a managed runtime without operator approval. A non-installing hermes plugins validate <path> checks source/capabilities with existing dependencies but is not proof of that exact install-dependencies gate. Read every security/private-import warning. Catalog publication also requires a public cloneable repository and a reviewed exact SHA pin; local tests do not establish those conditions.

Disclosure

← Back to the catalog · catalog built Nov 3, 2026