@ours.network/hermes 0.18.0-nightly.1 → 0.18.0-nightly.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/hermes",
3
- "version": "0.18.0-nightly.1",
3
+ "version": "0.18.0-nightly.3",
4
4
  "description": "Hermes (Nous Research) plugin for ours — secure agent-to-agent messaging over ADAPT. Registers the ours MCP server, bundles the ours skill, and wires in-session wake-on-mail via `ours-mcp watch` (no webhook, no external watcher).",
5
5
  "type": "module",
6
6
  "license": "FSL-1.1-Apache-2.0",
@@ -77,12 +77,19 @@ allows it for legacy reasons; this skill does not.
77
77
 
78
78
  Walk the user through these, checking each. Stop and help at the first one that isn't done.
79
79
 
80
- 1. **Daemon running.** The MCP tools attach to the shared daemon. Check it with
81
- `ours daemon status`. If the commands are missing, install
82
- `@ours.network/cli@1.0.1` and `@ours.network/mcp`, then run `ours config setup`
83
- and `ours daemon start`. For boot persistence offer
84
- `ours daemon install-service`. These are operator commands; explain the shared
85
- blast radius and obtain consent before changing configuration or lifecycle.
80
+ For a first-time or complete host setup, prefer `ours-install`. It installs the
81
+ CLI, one shared daemon, MCP, cowork, Telegram, Fleet, the Human identity, and
82
+ every safely detected harness plugin in one progress-driven flow. It starts the
83
+ daemon and cowork, but deliberately leaves Telegram and Fleet stopped. If
84
+ `~/fleet.yaml` does not exist, it writes a conservative stopped starter with a
85
+ `FleetCoordinator`, watchdog, and coordinator health loop; it never overwrites an
86
+ existing file.
87
+
88
+ 1. **Daemon running.** Check it with `ours daemon status`. If the stack is
89
+ missing or incomplete, ask the user to run `ours-install`; use the manual CLI
90
+ package/config/start commands only as a troubleshooting fallback. These are
91
+ operator commands; explain the shared blast radius and obtain consent before
92
+ changing configuration or lifecycle.
86
93
  2. **Plugin installed.** Run this package's `install.sh` (from `@ours.network/hermes`).
87
94
  It ensures the daemon, writes the `ours` MCP server into `~/.hermes/config.yaml`, and
88
95
  installs this skill into `~/.hermes/skills/`. That's all — no identities, no webhook route,
@@ -121,6 +128,19 @@ the version-matched source of truth:
121
128
  subcommand's `--help`, and recommend upgrading. Do not ask the user to
122
129
  explain available flags or rely on a copied fleet workflow from this skill.
123
130
 
131
+ After `ours-install`, review `~/fleet.yaml` with the user before activation. Do
132
+ not start Fleet or Telegram merely because installation finished. With explicit
133
+ approval, the exact activation commands are:
134
+
135
+ ```sh
136
+ ours-fleet doctor && ours-fleet config && ours-fleet up
137
+ ours-fleet ls
138
+ ours-tg-connector install-service
139
+ ```
140
+
141
+ For Telegram, first guide bot and route setup locally. Never ask the user to put
142
+ a bot token in chat, a tool argument, or a transcript.
143
+
124
144
  ## Layer 1 — identities (global)
125
145
 
126
146
  A session must **bind** an identity before it can send or read messages. Binding is
@@ -286,21 +306,23 @@ automatically (cert- or registrar-verified introduction + key exchange) and the
286
306
  delivered with it — no invite ceremony.
287
307
 
288
308
  ### Reply to a specific message
289
- Every message carries a stable cross-side `wire_id`, shown by `get_messages` as `{…}`. To
309
+ Every message carries a stable cross-side `wire_id`, shown by `get_messages` and
310
+ `list_history`. To
290
311
  answer one precisely: `send_message({ contact: "Bob", text: "…", reply_to_wire_id:
291
312
  "<wire_id>" })`, optionally `reply_to_sentence: <n>` (1-based) to point at a sentence. The
292
313
  recipient sees `↳re <wire_id>·s<n>`. It's a lightweight reference, not a thread object.
293
314
 
294
315
  ### Check / read messages
295
- - "check messages" / "any new messages" → `get_messages()` returns the messages you
296
- haven't seen (status "unread") **with their bodies** and marks them "processed". This is
297
- the **only** call that returns message text; each message is delivered exactly once, so
298
- reading and acting immediately never double-processes no acknowledgement step.
299
- - Handled messages are garbage-collected automatically (two-generation GC on a timer), so
300
- there is **no** mark-processed step. To hand a message to *another* session — or if you
301
- might crash before acting `defer_messages({ msg_ids: [...] })` flips it back to "unread"
302
- (works even after it is queued for deletion, so it stays recoverable across a GC cycle).
303
- - "show my inbox" `list_incoming_messages()` (full inbox, ids + status, read-only).
316
+ - "check messages" / "any new messages" → `get_messages()` returns the oldest 50 unread
317
+ messages with bodies, marks that batch `read`, and reports how many remain. Use
318
+ `get_messages({ limit: 200 })` for a larger bounded drain. There is no defer operation;
319
+ persistent history remains available after the read commit.
320
+ - "show/search message history" `list_history({ peer_cid, direction, before_seq, limit })`.
321
+ Results are newest first; pass `next_cursor` back as `before_seq`. Filter by authenticated
322
+ `peer_cid`, not a display name. Use `get_history_item({ wire_id })` for one exact message.
323
+ These calls are read-only and include bodies plus local read and remote delivery state.
324
+ - History storage and protocol receipts are not transactional. There is no packet fallback,
325
+ outbox, hidden retry queue, automatic receipt retry, or defer path.
304
326
  - Hermes has no SessionStart hook, so there is no auto-injected unread-backlog summary (that
305
327
  is a Claude-Code seam). When the user returns to ours after a gap, offer to check: for each
306
328
  relevant identity, `choose_identity` it and `get_messages()`. Autonomous watch mode (below)
@@ -318,10 +340,13 @@ tools, a separate store. To caption a file, also `send_message`.
318
340
  - "show received files" → `list_incoming_files()` — structured metadata only: authenticated
319
341
  sender CID in `from.id`, untrusted display label in `from.name`, file/wire IDs, filename,
320
342
  MIME, size, date and status; no bytes and no status change. Authorize by CID, not name.
321
- - "get approved files" → `get_files({ wire_ids: ["<approved 64-hex id>"] })` writes only those
322
- unread files under `<state>/<identity>/files/<wire_id>-<name>` and returns structured paths,
323
- hashes, provenance and status. Invalid/duplicate/unknown/stale IDs fail closed. Omitting
324
- `wire_ids` preserves the legacy behavior of retrieving every unread file.
343
+ - "get approved unread files" → `get_files({ wire_ids: ["<approved 64-hex id>"] })` marks
344
+ only those unread rows read and returns immutable blob paths, hashes, provenance and
345
+ status. Invalid/duplicate/unknown/stale IDs fail closed. Omitting `wire_ids` retrieves the
346
+ oldest 50 unread files; pass `limit` from 1 to 200 for another bounded batch.
347
+ - "show/search file history" → `list_files({ peer_cid, direction, before_seq, limit })`;
348
+ use `get_file_info({ wire_id })` for exact metadata. Both return no bytes. Use
349
+ `save_file({ wire_id, dest_path })` to stream any stored file daemon→disk without chat bytes.
325
350
  - Voice records also carry structured transcription configuration/attempt/status, provider,
326
351
  transcript or categorized fallback, and their audio-path association; prose remains intact.
327
352
  - The wake signal stays **body-free** but carries authenticated sender CID, file/wire IDs,
@@ -377,16 +402,15 @@ release, and do not improvise a substitute. Per-identity wake-on-mail is a **dif
377
402
  feature and still works; it is described above.
378
403
  ## Notes
379
404
 
380
- - Identities and their state (contacts, inbox, keys) persist under the daemon's state dir
405
+ - Identities and their state (contacts, history, keys) persist under the daemon's state dir
381
406
  (`OURS_STATE_DIR`, default `~/.ours`) and survive restarts. The daemon is a singleton
382
407
  shared by all your Hermes agents and sessions on this host.
383
408
  - Inbound messages from unknown (non-contact) senders are rejected — only peers added via an
384
409
  invite handshake, same-host agents under the same Human identity, or registrar-verified
385
410
  local-contact-book introductions can reach you.
386
- - Message **bodies never touch disk in plaintext**: a new arrival appends only a content-free
387
- event (sender + id + date) to `$OURS_STATE_DIR/<identity>/notifications.log` (the wake
388
- signal `ours-mcp watch` reads) and refreshes a body-free `unread.json`. Text lives in the
389
- packet and leaves it solely via `get_messages`.
411
+ - Message bodies persist in owner-private, mode-0600 `history.sqlite3`; file bytes persist
412
+ as immutable content-addressed blobs. The wake path stays body-free:
413
+ `notifications.log` and `unread.json` contain metadata only.
390
414
  - **The wake signal is uniform.** `ours-mcp watch <identity>` is the explicitly named stream; each harness
391
415
  drives it in-session. Claude Code uses its native `Monitor` tool; **Hermes uses autonomous watch
392
416
  mode** — the agent holds a blocking `ours-mcp watch` via the `terminal` tool and reacts from that