跳到主要内容

offpeak-bekci

❖ Communityv0.1.4★ 0

Makes Ollama Cloud's off-peak window visible and actionable in Hermes: a desktop status-bar chip shows the countdown and the queue item counts (Ollama off-peak hours: weekdays 18:00-12:00 UTC, weekends one block), a one-shot notice fires 30 minutes before the window opens, and approval is taken only from the user (`/offpeak-onayla <id,id>`) — work runs only if approved, and items never enter the queue by themselves. `/offpeak-durum` prints a readable report by default (machine-readable JSON with `/offpeak-durum json`), and `/offpeak-kur` prints the cron job it would install in full plus a `plan_hash`; nothing is installed without a hash-bound approval typed by the user, and the plugin never writes the cron store. One `llm_execution` middleware measures the call rate for Ollama Cloud calls during the peak window and ships measure-only (`kuru_kosu: true`): it records what it would delay and never delays. No network calls, no telemetry, no credential reads; the only local files it touches are the queue ledger and its own JSONL measurement log. Output language is English by default; `dil: tr` selects Turkish. Auto-delivery is host-dependent: in a classic CLI session the request enters the agent queue; on the Ink TUI / desktop-panel host the core asks for a persistent `session_key`, which the command handler does not receive, so the command prints the parameters as a single line of JSON. Injecting into a gateway additionally requires `plugins.entries.offpeak-bekci.allow_gateway_injection: true` (default off); the only in-process way to read that key is the private `gateway.session_context` module (rule 9 -> not used). Requires Hermes >= 0.22.2.

Open in Hermes Desktop
hermes plugins install offpeak-bekci

Screenshots

What it adds

Hooks 1

on_session_end

Middleware 1

llm_execution

README

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

offpeak-bekci

Makes Ollama Cloud's off-peak window visible and actionable: a status-bar chip shows the countdown and the queue item counts, a one-shot notice fires on_bildirim_dk minutes before the window opens, and approval is only ever taken from the user. On the body side an llm_execution middleware — only for Ollama Cloud calls and only inside the peak window — measures the per-minute call rate; with kuru_kosu: true (default) it measures and never sleeps.

Status-bar chip

Chip: window/countdown · APPROVED/TOTAL counter · quota state. (Image cropped from a real desktop status bar at measurement time; docs/rozet.png.)

Turkish documentation: README.tr.md. Command output is English by default and Turkish when dil: tr is set.

Install — one line

git clone https://github.com/onkanat/hermes-offpeak-bekci && hermes-offpeak-bekci/tools/kur.sh && hermes plugins enable offpeak-bekci

tools/kur.sh copies the repo into $HERMES_HOME/plugins/offpeak-bekci (idempotent, no remote download), prints the sha256 of the shipped surface and verifies it with hermes plugins validate.

The desktop half (the chip) is installed separately — a single file:

mkdir -p ~/.hermes/desktop-plugins/offpeak-bekci
cp desktop/plugin.js ~/.hermes/desktop-plugins/offpeak-bekci/plugin.js
# then: enable it under Settings ▸ Plugins · ⌘K → "Reload desktop plugins"

The chip reads its state through /offpeak-durum json, so update the server and desktop halves together (same version). For another profile: HERMES_HOME=~/.hermes/profiles/<profile> tools/kur.sh. Changing a value needs no code edit: settings live in config.yaml → the offpeak-bekci: block.

Catalog entry: see plugin-catalog/offpeak-bekci.yaml — submitted as PR #139797 (review in progress). Until it is listed, the source install above applies.

Commands

Command What it does
/offpeak-durum Window, countdown, sliding-window rate, quota and queue counters. Default: readable report; /offpeak-durum json is the machine output (the desktop chip reads that).
/offpeak-onayla <id,id> Marks queue items as onaylı/approved (the user is the only approver).
/offpeak-kur Prints the off-peak cron job that would be installed in full (job name, schedule, the whole prompt, monitor, workdir, toolsets, delivery) plus plan_hash. Installs nothing.
/offpeak-kur onayla <plan_hash> [duraklat] Continues only if plan_hash matches; leaves the install request to the session, and the agent's own cronjob_manage tool installs it (host-dependent — see Where is the request auto-delivered?).
/offpeak-kaldir Lists offpeak jobs in this profile (id · schedule · state · next run).
/offpeak-kaldir onayla <job_id> Leaves a removal request to the session, only with an id from that list (host-dependent — see Where is the request auto-delivered?).

Why "request"? The plugin API has no surface to create a cron job (register_command, hooks and middleware exist; a job installer does not). Installation is therefore left to the session as a user-approved message; the agent's cron tool makes the decision and the record. The plugin never writes jobs.json under any circumstance — it only reads it.

Where is the request auto-delivered? (measured limit)

ctx.inject_message(…) is routed by the core depending on the host (hermes_cli/plugins_injection.py:18-32):

Host What happens
Classic CLI (terminal REPL — the core installs the CLI reference here) The request enters the CLI queue, return is True; the agent installs it when the command finishes.
Ink TUI (hermes --tui) / desktop panel The core asks for a persistent session_key. That key is not given to the command handler (no session field on PluginContext; the pre_command hook is not invoked on the desktop command.dispatch path) → return is False.
Gateway session (when session_key or origin was handed to the plugin beforehand) The request is queued into that session — but the core first asks a gate: plugins.entries.offpeak-bekci.allow_gateway_injection: true (default off). If off, a warning is printed and the return is False (hermes_cli/plugins.py:622-630).

So on the desktop/Ink host the command falls into the "could not be left to the session in this channel" branch and prints the parameters to install as a single line of JSON: the job is still installed through the agent's cron tool, the only difference being that the user passes the request to the agent (paste the JSON, or use cronjob_manage).

The only in-process way to read the session key is gateway.session_context.get_session_env, and that module is not public surface for a plugin: the core's own checker reports an artificial from gateway.session_context import get_session_env import as a finding (private_import_findings), while hermes_constants.get_hermes_home does not. Per rule 9 that path is not used; hence on the desktop the command handler cannot reach the key and auto-delivery does not work (the resolution is a user/core decision: either a public read surface, or allow_gateway_injection + the key). Regression tests: tests/test_kurulum.py::HostKanaliTest (plus the wording side, HostBeyaniTest). Measured: core source lines, the core's own injection tests, and a real probe run. Not measured: the real Hermes.app host delivery (the plugin side catches it with a stub).

Dry run (try the job without keeping it):

/offpeak-kur onayla <plan_hash> duraklat     # creates the job with paused:true, never scheduled
hermes cron list                             # the job is visible
/offpeak-kaldir onayla <job_id>              # undo

Disclosure — what it reads, where it writes, what it keeps

Reads: only the single local file named by the kuyruk_dosyasi setting (default ~/.hermes/offpeak-bekci/kuyruk.md) — to count pending/approved/run items. The install commands additionally read-only the cron store (<profile>/cron/jobs.json); the store path is derived from public surface (hermes_constants.get_hermes_home()), the core's private cron.jobs module is not imported (catalog rule 9). load_jobs() is deliberately unused: that call runs ensure_dirs(), which creates directories (a side effect).

Writes: (1) the local JSONL log named by the olcum_dosyasi setting (default ~/.hermes/offpeak-bekci/olcum.jsonl): measurement/alert/approval records; (2) when the user runs /offpeak-onayla, only kuyruk_dosyasi — the plugin does not generate the file's content, it is the user's own file, and the write is atomic (temp file + os.replace). It writes nowhere else; jobs.json, config.yaml and site files are out of scope.

Keeps (settings): the table below. The single source of truth is plugin.yaml → config_schema; code defaults are read from there. A given install's own values live in config.yaml → the offpeak-bekci: block; no user-specific path is baked into the plugin.

Does not: no network calls, no telemetry, never reads or writes secrets/passwords/tokens, never runs a shell or spawns processes, never downloads remote code, never self-updates, never touches another profile or machine. The desktop half (desktop/plugin.js) uses only the plugin SDK surface: no prototype patching, no eval, no DOM querying.

Settings

Setting Default Meaning
dil en Language of command descriptions, command output and notices: en or tr.
kuru_kosu true While true it measures/records and never sleeps.
kuyruk_dosyasi ~/.hermes/offpeak-bekci/kuyruk.md Path of the queue ledger (the single read source).
schedule 5 18 * * 1-5 Opening of the off-peak window (cron, UTC) — used in the /offpeak-kur plan.
on_bildirim_dk 30 How long before the window the notice starts (minutes).
hedef_hiz_dk 6 Max calls per minute during peak (sliding pencere_sn window).
erteleme_tavani_sn 30.0 Max sleep for a single request (delay ceiling).
pencere_sn 60.0 Length of the sliding rate window (seconds).
kota_tavani 120 Max calls per quota window; exceeding it writes an alert record (the request is not cancelled).
kota_penceresi_sn 3600.0 Quota counter window (seconds).
kota_token_gun 0 Daily fresh-token ceiling; 0 = no ceiling.
cache_read_tavani_gun 0 Daily cache-read token ceiling; 0 = no ceiling.
off_peak_only_isler [] Names of jobs that must only run off-peak (a declaration).
olcum_dosyasi ~/.hermes/offpeak-bekci/olcum.jsonl Measurement/alert log (JSONL, local).

Development

python3 -m unittest discover -s tests -t .   # python gates
node --test tests/desktop/plugin.test.mjs    # desktop gates
node tools/build-desktop.mjs --check         # is the embedded plugin.js stale? (EXIT=0)
hermes plugins validate . --install-deps     # manifest validation

Dry-run/measurement tools: tools/kuru_kosu_olcum.py (dry-run measurement against the live config).

Limit: it never writes to a real queue ledger for measurement purposes; the install commands never create a job without user approval and never change the kuru_kosu setting.

← Back to the catalog · catalog built Oct 18, 2026