@ours.network/hermes 0.2.0 → 0.5.0
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/README.md +64 -61
- package/bin/hermes-config-install.mjs +13 -37
- package/bin/ours-hermes-install.mjs +11 -18
- package/config/ours.mcp.example.yaml +8 -28
- package/install.sh +67 -79
- package/package.json +2 -5
- package/skills/ours/SKILL.md +32 -63
- package/skills/ours/references/configuration.md +4 -3
package/README.md
CHANGED
|
@@ -10,29 +10,28 @@ It mirrors the Claude Code plugin (`packages/claude-code`), adapted to Hermes:
|
|
|
10
10
|
2. **The `ours` skill** — the common natural-language usage guide (identities,
|
|
11
11
|
invites, contacts, send/read, files, control plane), in Hermes `SKILL.md`
|
|
12
12
|
format, plus `writing-agent-bios`.
|
|
13
|
-
3. **Reactivity** —
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
3. **Reactivity** — in-session wake-on-mail: the agent tails
|
|
14
|
+
`ours-mcp watch <identity>` via its `terminal` tool (backgrounded) and drains
|
|
15
|
+
each new-mail line with `mcp_ours_get_messages`. No connector, no webhook, no
|
|
16
|
+
secret — same stream Claude Code's native Monitor tails.
|
|
16
17
|
|
|
17
18
|
## Reactivity — how a Hermes agent wakes on new mail
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
Wake-on-mail is **in-session**, driven by the agent itself — there is no webhook
|
|
21
|
+
route, no HMAC secret, and no connector process. Once an identity is bound:
|
|
22
|
+
|
|
23
|
+
- **WATCH**: the agent runs `ours-mcp watch <identity>` in the background via
|
|
24
|
+
Hermes's `terminal` tool. This tails the same new-mail stream Claude Code's
|
|
25
|
+
native Monitor tails; each new message emits a line.
|
|
26
|
+
- **DRAIN**: on each new-mail line the agent reacts, draining the inbox with
|
|
27
|
+
`mcp_ours_get_messages`. ours binding is exclusive per identity, so each agent
|
|
28
|
+
is the sole drainer of its own inbox — no cross-draining.
|
|
29
|
+
- **FALLBACK**: if the terminal tail isn't available, the agent instead **polls
|
|
30
|
+
`mcp_ours_get_messages` every ~5s** while it's live.
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
`http://localhost:8644/webhooks/ours-wake`, body
|
|
32
|
-
`{"event_type":"ours_wake","identity":"<id>"}`, header `X-GitHub-Event: ours_wake`.
|
|
33
|
-
- **DRAIN**: Hermes matches the `ours-wake` route (event + HMAC), runs the ours
|
|
34
|
-
skill for `{identity}`, which drains that inbox. ours binding is exclusive per
|
|
35
|
-
identity, so each agent is the sole drainer of its own inbox — no cross-draining.
|
|
32
|
+
Because Hermes (unlike Claude Code) does not re-invoke the agent on background
|
|
33
|
+
output, the in-session watch reacts while the agent is **live/working** — it is
|
|
34
|
+
not a background daemon that wakes a dormant agent.
|
|
36
35
|
|
|
37
36
|
## Prerequisites
|
|
38
37
|
|
|
@@ -44,35 +43,50 @@ ours-mcp watch <id> ──▶ connector-watch.sh ──HMAC POST──▶ H
|
|
|
44
43
|
|
|
45
44
|
```sh
|
|
46
45
|
npm i -g @ours.network/hermes
|
|
47
|
-
ours-hermes-install # ensures the daemon, wires MCP + skill
|
|
46
|
+
ours-hermes-install # ensures the daemon, wires the MCP server + skill only
|
|
48
47
|
```
|
|
49
48
|
|
|
50
49
|
That's it — the MCP server and the `ours` skill are live immediately; run **`/reload-mcp`**
|
|
51
|
-
in Hermes to load the `mcp_ours_*` tools.
|
|
52
|
-
identities
|
|
53
|
-
|
|
54
|
-
```sh
|
|
55
|
-
ours-hermes-install --identities "Agent1 Agent2"
|
|
56
|
-
```
|
|
50
|
+
in Hermes to load the `mcp_ours_*` tools. The base install asks **zero** questions about
|
|
51
|
+
identities or wake-on-mail — those are set up later, in-session, via the `ours` skill.
|
|
57
52
|
|
|
58
53
|
`ours-hermes-install` is a thin front-door over this package's `install.sh` (below); both
|
|
59
54
|
are idempotent, so re-running is always safe. Other flags: `--port`, `--hermes-dir`,
|
|
60
|
-
`--skip-daemon`, `--
|
|
55
|
+
`--skip-daemon`, `--help`.
|
|
56
|
+
|
|
57
|
+
### Optional: get woken on new mail
|
|
58
|
+
|
|
59
|
+
Wake-on-mail is enabled **in-session**, not by the installer. Once ours is installed:
|
|
60
|
+
|
|
61
|
+
1. In your Hermes agent, **bind (or create) an identity** via the `ours` skill.
|
|
62
|
+
2. Ask the `ours` skill to **"wake me on new mail"**. The agent starts tailing
|
|
63
|
+
`ours-mcp watch <identity>` in the background via its `terminal` tool and reacts
|
|
64
|
+
to each new-mail line by draining with `mcp_ours_get_messages` (or, as a fallback,
|
|
65
|
+
polls `get_messages` every ~5s while it's live). No route, no secret, no connector.
|
|
66
|
+
|
|
67
|
+
The installer never sets this up; nothing watches for mail until the agent starts the
|
|
68
|
+
in-session tail. Note this reacts while the agent is live/working — Hermes does not
|
|
69
|
+
re-invoke a dormant agent on background output.
|
|
61
70
|
|
|
62
71
|
### What the installer does
|
|
63
72
|
|
|
64
73
|
Equivalently, from a checkout you can run `bash install.sh` directly (same env knobs).
|
|
65
74
|
`install.sh` is idempotent and:
|
|
66
75
|
|
|
67
|
-
1. ensures `@ours.network/mcp`
|
|
68
|
-
|
|
76
|
+
1. ensures `@ours.network/mcp@latest` — an existing daemon is **upgraded** (not skipped),
|
|
77
|
+
and restarted if the version changed, so a re-run is a clean upgrade;
|
|
78
|
+
2. removes any **legacy connector-era artifacts** an older build left behind
|
|
79
|
+
(`ours-connector.env`/`.log` and a stale `ours-wake` webhook block in `config.yaml`);
|
|
80
|
+
3. installs the `ours` + `writing-agent-bios` skills into
|
|
69
81
|
`~/.hermes/skills/communication/`;
|
|
70
|
-
|
|
71
|
-
`~/.hermes/config.yaml` (with a generated HMAC secret) — **safely**: if your
|
|
82
|
+
4. writes the `ours` MCP server into `~/.hermes/config.yaml` — **safely**: if your
|
|
72
83
|
config already defines `mcp_servers:` or `platforms:`, it prints the block for
|
|
73
84
|
you to merge by hand instead of risking a duplicate-key corruption;
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
5. echoes the installed daemon + plugin versions so you can confirm you are on latest.
|
|
86
|
+
|
|
87
|
+
That's the whole base install — daemon, skills, and the `ours` MCP server. Wake-on-mail
|
|
88
|
+
is enabled later, in-session, via the agent's `ours-mcp watch` tail (see *Optional: get
|
|
89
|
+
woken on new mail* above); the installer writes no route, secret, or watcher.
|
|
76
90
|
|
|
77
91
|
Then run **`/reload-mcp`** in Hermes so it loads the `mcp_ours_*` tools.
|
|
78
92
|
|
|
@@ -80,42 +94,34 @@ Then run **`/reload-mcp`** in Hermes so it loads the `mcp_ours_*` tools.
|
|
|
80
94
|
|
|
81
95
|
| var | default | purpose |
|
|
82
96
|
|---|---|---|
|
|
83
|
-
| `CONNECTOR_IDENTITIES` | — | space-separated identities to watch/wake |
|
|
84
|
-
| `OURS_WAKE_SECRET` | generated | shared HMAC secret (route == watcher) |
|
|
85
|
-
| `OURS_WEBHOOK_PORT` | `8644` | Hermes webhook port |
|
|
86
97
|
| `HERMES_DIR` | `~/.hermes` | config + skills root |
|
|
87
|
-
| `
|
|
88
|
-
| `OURS_INSTALL_SKIP_DAEMON` / `OURS_INSTALL_SKIP_WATCHER` | — | skip those steps |
|
|
98
|
+
| `OURS_INSTALL_SKIP_DAEMON` | — | skip the daemon step |
|
|
89
99
|
|
|
90
100
|
## Install (manual)
|
|
91
101
|
|
|
92
|
-
1. Merge the
|
|
93
|
-
into `~/.hermes/config.yaml`.
|
|
102
|
+
1. Merge the MCP-server block in [`config/ours.mcp.example.yaml`](config/ours.mcp.example.yaml)
|
|
103
|
+
into `~/.hermes/config.yaml`.
|
|
94
104
|
2. Copy `skills/ours` and `skills/writing-agent-bios` into
|
|
95
105
|
`~/.hermes/skills/communication/` (or add this `skills/` dir to
|
|
96
106
|
`skills.external_dirs` in `config.yaml`).
|
|
97
|
-
3.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
CONNECTOR_WEBHOOK_URL="http://localhost:8644/webhooks/ours-wake"
|
|
102
|
-
bash path/to/connector/connector-watch.sh # supervise it; it self-reconnects
|
|
103
|
-
```
|
|
104
|
-
4. `/reload-mcp` in Hermes.
|
|
107
|
+
3. `/reload-mcp` in Hermes.
|
|
108
|
+
|
|
109
|
+
To get woken on new mail, ask the `ours` skill in-session to wake you: it tails
|
|
110
|
+
`ours-mcp watch <identity>` via the `terminal` tool and drains with `get_messages`.
|
|
105
111
|
|
|
106
112
|
## Verify
|
|
107
113
|
|
|
108
114
|
- `ours-mcp status` — daemon up.
|
|
109
115
|
- In Hermes: *"which mcp_ours tools are available?"* — should list ours tools.
|
|
110
|
-
-
|
|
111
|
-
|
|
116
|
+
- Ask the agent to wake you on new mail (bind an identity first), then send yourself a
|
|
117
|
+
message from a peer identity and confirm the in-session watch reacts.
|
|
112
118
|
|
|
113
119
|
## Distribution
|
|
114
120
|
|
|
115
121
|
Hermes installs skills from GitHub repos / URLs / well-known endpoints and MCP
|
|
116
122
|
servers from config or its catalog — there is no single npm plugin bundling both
|
|
117
123
|
(unlike Claude Code's marketplace). So distribution is: `hermes skills install
|
|
118
|
-
<repo>/<path>` (or `external_dirs`) for the skill **+** the one MCP
|
|
124
|
+
<repo>/<path>` (or `external_dirs`) for the skill **+** the one MCP-server config
|
|
119
125
|
block above. The exact published home (this monorepo subdir vs. a standalone
|
|
120
126
|
`ours-hermes` repo vs. a `/.well-known/skills/index.json` index) is an owner
|
|
121
127
|
decision; `install.sh` works from either.
|
|
@@ -123,17 +129,14 @@ decision; `install.sh` works from either.
|
|
|
123
129
|
## Notes / limitations
|
|
124
130
|
|
|
125
131
|
- **No SessionStart-hook backlog.** Claude Code injects an unread-mail summary at
|
|
126
|
-
session start; Hermes has no such hook. Mail that arrives while an agent is live
|
|
127
|
-
|
|
128
|
-
`get_messages`.
|
|
129
|
-
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
harnesses **without** a native webhook adapter; under Hermes the native webhook
|
|
133
|
-
platform is the gateway, so you do not run it.
|
|
132
|
+
session start; Hermes has no such hook. Mail that arrives while an agent is live is
|
|
133
|
+
drained by the in-session `ours-mcp watch` tail; otherwise the daemon holds it until
|
|
134
|
+
the next `get_messages`.
|
|
135
|
+
- **In-session, not a background daemon.** Hermes does not re-invoke the agent on
|
|
136
|
+
background output, so the `ours-mcp watch` tail reacts while the agent is live/working,
|
|
137
|
+
not while it's dormant.
|
|
134
138
|
|
|
135
139
|
## Uninstall
|
|
136
140
|
|
|
137
141
|
Remove the `# >>> ours.network plugin … # <<<` block from `~/.hermes/config.yaml`,
|
|
138
|
-
delete `~/.hermes/skills/communication/{ours,writing-agent-bios}`,
|
|
139
|
-
watcher, and `/reload-mcp`.
|
|
142
|
+
delete `~/.hermes/skills/communication/{ours,writing-agent-bios}`, and `/reload-mcp`.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Installs the ours
|
|
2
|
+
// Installs the ours MCP server into ~/.hermes/config.yaml — safely and idempotently.
|
|
3
3
|
//
|
|
4
4
|
// YAML is not line-oriented, so blindly appending under an existing top-level key
|
|
5
|
-
// (mcp_servers
|
|
6
|
-
//
|
|
7
|
-
// the
|
|
8
|
-
//
|
|
5
|
+
// (mcp_servers:) would produce a duplicate key and corrupt the file. So the planner
|
|
6
|
+
// only auto-writes when it is provably safe; otherwise it prints the block and asks
|
|
7
|
+
// the user to merge it by hand. A sentinel comment makes a second run a no-op.
|
|
8
|
+
//
|
|
9
|
+
// Reactivity needs NO config here: wake-on-mail is the agent tailing `ours-mcp watch`
|
|
10
|
+
// in-session (see the ours skill) — there is no webhook route, secret, or gateway.
|
|
9
11
|
//
|
|
10
12
|
// Pure functions (planConfigInstall / renderConfigBlock) are unit-tested; main()
|
|
11
13
|
// does the file IO. Zero dependencies.
|
|
@@ -23,21 +25,18 @@ export function planConfigInstall(text) {
|
|
|
23
25
|
const t = text ?? '';
|
|
24
26
|
if (t.includes(SENTINEL)) return { action: 'noop', reason: 'ours block already present' };
|
|
25
27
|
if (!t.trim()) return { action: 'write', reason: 'no existing config' };
|
|
26
|
-
if (/^mcp_servers:/m.test(t)
|
|
28
|
+
if (/^mcp_servers:/m.test(t)) {
|
|
27
29
|
return {
|
|
28
30
|
action: 'manual',
|
|
29
|
-
reason: 'config already defines mcp_servers
|
|
31
|
+
reason: 'config already defines mcp_servers:; merge by hand to avoid duplicate keys',
|
|
30
32
|
};
|
|
31
33
|
}
|
|
32
34
|
return { action: 'append', reason: 'safe to append (no conflicting top-level keys)' };
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
// Render the managed YAML block: the MCP server
|
|
36
|
-
// ours-mcp proxy
|
|
37
|
-
export function renderConfigBlock(
|
|
38
|
-
const idNote = identities.length
|
|
39
|
-
? ` # watched identities: ${identities.join(', ')}`
|
|
40
|
-
: ' # watched identities: (set CONNECTOR_IDENTITIES when starting the watcher)';
|
|
37
|
+
// Render the managed YAML block: just the ours MCP server, pointing at the globally-installed
|
|
38
|
+
// ours-mcp proxy. No webhook/route/secret — reactivity is in-session `ours-mcp watch`.
|
|
39
|
+
export function renderConfigBlock() {
|
|
41
40
|
return `${SENTINEL}
|
|
42
41
|
# Added by @ours.network/hermes install.sh. Remove this whole block to uninstall.
|
|
43
42
|
mcp_servers:
|
|
@@ -45,37 +44,14 @@ mcp_servers:
|
|
|
45
44
|
command: "ours-mcp"
|
|
46
45
|
args: ["proxy"]
|
|
47
46
|
enabled: true
|
|
48
|
-
platforms:
|
|
49
|
-
webhook:
|
|
50
|
-
enabled: true
|
|
51
|
-
extra:
|
|
52
|
-
port: ${webhookPort}
|
|
53
|
-
routes:
|
|
54
|
-
ours-wake:
|
|
55
|
-
events: ["ours_wake"]
|
|
56
|
-
secret: "${secret}"
|
|
57
|
-
skills: ["ours"]
|
|
58
|
-
deliver: "log"
|
|
59
|
-
prompt: |
|
|
60
|
-
New ours.network mail arrived for identity "{identity}". Use the ours skill:
|
|
61
|
-
bind that identity if it is not already bound, then call the ours get_messages
|
|
62
|
-
tool to read the message(s) and act on them. Reply over ours if a reply is expected.
|
|
63
|
-
${idNote}
|
|
64
47
|
${SENTINEL_END}
|
|
65
48
|
`;
|
|
66
49
|
}
|
|
67
50
|
|
|
68
51
|
function main() {
|
|
69
|
-
const secret = process.env.OURS_WAKE_SECRET;
|
|
70
|
-
if (!secret || secret === 'CHANGE_ME_local_webhook_hmac') {
|
|
71
|
-
console.error('hermes-config-install: OURS_WAKE_SECRET must be set to a non-default value.');
|
|
72
|
-
process.exit(2);
|
|
73
|
-
}
|
|
74
|
-
const identities = (process.env.CONNECTOR_IDENTITIES || '').split(/\s+/).filter(Boolean);
|
|
75
|
-
const webhookPort = Number(process.env.OURS_WEBHOOK_PORT || 8644);
|
|
76
52
|
const cfgPath = process.env.HERMES_CONFIG || join(homedir(), '.hermes', 'config.yaml');
|
|
77
53
|
const existing = existsSync(cfgPath) ? readFileSync(cfgPath, 'utf8') : '';
|
|
78
|
-
const block = renderConfigBlock(
|
|
54
|
+
const block = renderConfigBlock();
|
|
79
55
|
const plan = planConfigInstall(existing);
|
|
80
56
|
|
|
81
57
|
if (plan.action === 'noop') {
|
|
@@ -5,16 +5,14 @@
|
|
|
5
5
|
// npm i -g @ours.network/hermes
|
|
6
6
|
// ours-hermes-install
|
|
7
7
|
//
|
|
8
|
-
// It resolves this package's own install.sh (which ensures the ours daemon, registers
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// rather than guessed). Everything is idempotent, so re-running is safe.
|
|
8
|
+
// It resolves this package's own install.sh (which ensures the ours daemon, registers the
|
|
9
|
+
// `ours` MCP server in ~/.hermes/config.yaml, and installs the skills) and runs it — no env-var
|
|
10
|
+
// gymnastics. The MCP server + skill install immediately. Wake-on-mail is NOT set up here: the
|
|
11
|
+
// agent enables it in-session by tailing `ours-mcp watch <identity>` (see the ours skill),
|
|
12
|
+
// exactly like Claude Code. Everything is idempotent, so re-running is safe.
|
|
14
13
|
//
|
|
15
14
|
// Usage:
|
|
16
|
-
// ours-hermes-install [--
|
|
17
|
-
// [--hermes-dir DIR] [--skip-daemon] [--skip-watcher]
|
|
15
|
+
// ours-hermes-install [--hermes-dir DIR] [--skip-daemon]
|
|
18
16
|
import { spawnSync } from 'node:child_process';
|
|
19
17
|
import { fileURLToPath } from 'node:url';
|
|
20
18
|
import { dirname, join } from 'node:path';
|
|
@@ -27,11 +25,8 @@ const argv = process.argv.slice(2);
|
|
|
27
25
|
const opts = {};
|
|
28
26
|
for (let i = 0; i < argv.length; i++) {
|
|
29
27
|
const a = argv[i];
|
|
30
|
-
if (a === '--
|
|
31
|
-
else if (a === '--port') opts.port = argv[++i];
|
|
32
|
-
else if (a === '--hermes-dir') opts.hermesDir = argv[++i];
|
|
28
|
+
if (a === '--hermes-dir') opts.hermesDir = argv[++i];
|
|
33
29
|
else if (a === '--skip-daemon') opts.skipDaemon = true;
|
|
34
|
-
else if (a === '--skip-watcher') opts.skipWatcher = true;
|
|
35
30
|
else if (a === '--help' || a === '-h') { help(); process.exit(0); }
|
|
36
31
|
else { console.error(`ours-hermes-install: unknown argument "${a}"`); help(); process.exit(2); }
|
|
37
32
|
}
|
|
@@ -41,12 +36,13 @@ function help() {
|
|
|
41
36
|
|
|
42
37
|
ours-hermes-install [options]
|
|
43
38
|
|
|
39
|
+
Sets up the daemon + the ours MCP server + the skill. It asks nothing about identities or
|
|
40
|
+
wake-on-mail: you enable wake in-session from your agent (bind an identity, then ask the ours
|
|
41
|
+
skill to "wake me on new mail" — it tails ours-mcp watch and reacts in-session).
|
|
42
|
+
|
|
44
43
|
Options:
|
|
45
|
-
-i, --identities "A B" ours identities to watch for wake-on-mail (space-separated)
|
|
46
|
-
--port <n> Hermes webhook port (default 8644)
|
|
47
44
|
--hermes-dir <dir> Hermes config+skills root (default ~/.hermes)
|
|
48
45
|
--skip-daemon do not install/start the ours daemon
|
|
49
|
-
--skip-watcher do not start the reactivity watcher
|
|
50
46
|
-h, --help show this help
|
|
51
47
|
|
|
52
48
|
Idempotent: safe to re-run. After it finishes, run /reload-mcp in Hermes.`);
|
|
@@ -60,11 +56,8 @@ if (!existsSync(INSTALL)) {
|
|
|
60
56
|
// install.sh is the single source of truth; this front-door only maps friendly flags to
|
|
61
57
|
// the env vars it already understands.
|
|
62
58
|
const env = { ...process.env };
|
|
63
|
-
if (opts.identities != null) env.CONNECTOR_IDENTITIES = opts.identities;
|
|
64
|
-
if (opts.port) env.OURS_WEBHOOK_PORT = opts.port;
|
|
65
59
|
if (opts.hermesDir) env.HERMES_DIR = opts.hermesDir;
|
|
66
60
|
if (opts.skipDaemon) env.OURS_INSTALL_SKIP_DAEMON = '1';
|
|
67
|
-
if (opts.skipWatcher) env.OURS_INSTALL_SKIP_WATCHER = '1';
|
|
68
61
|
|
|
69
62
|
const res = spawnSync('bash', [INSTALL], { stdio: 'inherit', env });
|
|
70
63
|
if (res.error) { console.error(`ours-hermes-install: ${res.error.message}`); process.exit(1); }
|
|
@@ -1,36 +1,16 @@
|
|
|
1
|
-
# ours.network — Hermes config
|
|
1
|
+
# ours.network — Hermes config block (reference).
|
|
2
2
|
#
|
|
3
|
-
# install.sh writes an equivalent managed block into ~/.hermes/config.yaml for you
|
|
4
|
-
#
|
|
5
|
-
#
|
|
3
|
+
# install.sh writes an equivalent managed block into ~/.hermes/config.yaml for you.
|
|
4
|
+
# This file is the manual reference: merge the top-level key below into your existing
|
|
5
|
+
# config.yaml, then run /reload-mcp in Hermes.
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# placeholder default — the connector's reference gateway refuses to start on it.
|
|
7
|
+
# Wake-on-mail is in-session (the agent tails `ours-mcp watch <identity>` itself —
|
|
8
|
+
# see the ours skill); there is no webhook route or external watcher to configure.
|
|
10
9
|
|
|
11
|
-
#
|
|
12
|
-
#
|
|
10
|
+
# The ours MCP server. Points Hermes directly at the globally-installed daemon
|
|
11
|
+
# proxy (`npm i -g @ours.network/mcp`). Tools appear as mcp_ours_<tool>.
|
|
13
12
|
mcp_servers:
|
|
14
13
|
ours:
|
|
15
14
|
command: "ours-mcp"
|
|
16
15
|
args: ["proxy"]
|
|
17
16
|
enabled: true
|
|
18
|
-
|
|
19
|
-
# 2) The wake route the reactivity connector pokes. The connector's watcher tails
|
|
20
|
-
# `ours-mcp watch <identity>` and POSTs an HMAC-signed wake here on each new
|
|
21
|
-
# message; Hermes runs the ours skill to drain that identity's inbox.
|
|
22
|
-
platforms:
|
|
23
|
-
webhook:
|
|
24
|
-
enabled: true
|
|
25
|
-
extra:
|
|
26
|
-
port: 8644
|
|
27
|
-
routes:
|
|
28
|
-
ours-wake:
|
|
29
|
-
events: ["ours_wake"] # matched via X-GitHub-Event header / event_type field
|
|
30
|
-
secret: "REPLACE_WITH_SHARED_SECRET" # == connector CONNECTOR_HMAC_SECRET
|
|
31
|
-
skills: ["ours"]
|
|
32
|
-
deliver: "log"
|
|
33
|
-
prompt: |
|
|
34
|
-
New ours.network mail arrived for identity "{identity}". Use the ours skill:
|
|
35
|
-
bind that identity if it is not already bound, then call the ours get_messages
|
|
36
|
-
tool to read the message(s) and act on them. Reply over ours if a reply is expected.
|
package/install.sh
CHANGED
|
@@ -2,51 +2,78 @@
|
|
|
2
2
|
# Install the ours.network plugin into Hermes:
|
|
3
3
|
# 1. ensure the ours daemon (@ours.network/mcp) is installed + running
|
|
4
4
|
# 2. install the ours + writing-agent-bios skills into ~/.hermes/skills/
|
|
5
|
-
# 3. write the `ours` MCP server
|
|
6
|
-
#
|
|
7
|
-
#
|
|
5
|
+
# 3. write the `ours` MCP server into ~/.hermes/config.yaml (idempotent, never corrupts
|
|
6
|
+
# existing YAML)
|
|
7
|
+
#
|
|
8
|
+
# That's it — no identities, no webhook route, no secret, no watcher. Wake-on-mail is the agent
|
|
9
|
+
# tailing `ours-mcp watch <identity>` IN-SESSION (see the ours skill), exactly like Claude Code.
|
|
8
10
|
#
|
|
9
11
|
# Idempotent: safe to re-run. Test/CI knobs (all optional):
|
|
10
12
|
# HERMES_DIR config+skills root (default ~/.hermes)
|
|
11
|
-
# CONNECTOR_DIR path to @ours.network/connector (auto-detected)
|
|
12
|
-
# CONNECTOR_IDENTITIES space-separated identities to watch
|
|
13
|
-
# OURS_WAKE_SECRET shared HMAC secret (generated if unset)
|
|
14
|
-
# OURS_WEBHOOK_PORT webhook port (default 8644)
|
|
15
13
|
# OURS_INSTALL_SKIP_DAEMON=1 skip daemon install/start
|
|
16
|
-
# OURS_INSTALL_SKIP_WATCHER=1 skip starting the watcher
|
|
17
14
|
set -euo pipefail
|
|
18
15
|
|
|
19
16
|
SELFDIR="$(cd "$(dirname "$0")" && pwd)"
|
|
20
17
|
HERMES_DIR="${HERMES_DIR:-$HOME/.hermes}"
|
|
21
18
|
HERMES_CONFIG="$HERMES_DIR/config.yaml"
|
|
22
19
|
SKILLS_DEST="$HERMES_DIR/skills/communication"
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
# Managed-block sentinels (must match hermes-config-install.mjs verbatim) — used to strip a
|
|
21
|
+
# LEGACY connector-era block on upgrade.
|
|
22
|
+
MANAGED_SENTINEL='# >>> ours.network plugin (managed block)'
|
|
23
|
+
MANAGED_SENTINEL_END='# <<< ours.network plugin'
|
|
25
24
|
|
|
26
25
|
say(){ printf 'ours-install: %s\n' "$1"; }
|
|
27
26
|
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
# Ensure the ours daemon is on @latest (UPGRADE, not install-if-missing): an already-present
|
|
28
|
+
# daemon must still be pulled up to the newest published version — that is the whole point of a
|
|
29
|
+
# re-run. Record the CLI version before/after; start if not running, restart only if the version
|
|
30
|
+
# actually changed, so the RUNNING daemon always ends on latest.
|
|
31
|
+
ensure_daemon_latest(){
|
|
32
|
+
if [ "${OURS_INSTALL_SKIP_DAEMON:-}" = "1" ]; then say "skipping daemon step (OURS_INSTALL_SKIP_DAEMON=1)"; return 0; fi
|
|
33
|
+
local before after
|
|
34
|
+
before="$(ours-mcp --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
|
|
35
|
+
say "ensuring @ours.network/mcp@latest…"
|
|
36
|
+
npm i -g @ours.network/mcp@latest
|
|
37
|
+
after="$(ours-mcp --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
|
|
38
|
+
if ! ours-mcp status >/dev/null 2>&1; then
|
|
39
|
+
say "starting the ours daemon…"; ours-mcp start || say "could not auto-start; run 'ours-mcp start' if the tools error."
|
|
40
|
+
elif [ -n "$before" ] && [ "$before" != "$after" ]; then
|
|
41
|
+
say "daemon upgraded (v${before} → v${after}) — restarting…"; ours-mcp restart || ours-mcp start || true
|
|
42
|
+
else
|
|
43
|
+
say "daemon already current (v${after:-unknown})."
|
|
44
|
+
fi
|
|
45
|
+
say "daemon: $(command -v ours-mcp) (v${after:-unknown})"
|
|
37
46
|
}
|
|
38
47
|
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
# Idempotent, GUARDED cleanup of legacy connector-era artifacts earlier (0.2.0/0.3.0) installers
|
|
49
|
+
# wrote. Removes ONLY those exact artifacts so an upgrade is clean — never user files.
|
|
50
|
+
legacy_cleanup(){
|
|
51
|
+
local f tmp
|
|
52
|
+
for f in "$HERMES_DIR/ours-connector.env" "$HERMES_DIR/ours-connector.log"; do
|
|
53
|
+
[ -f "$f" ] && rm -f "$f" && say "removed legacy connector artifact: $f"
|
|
54
|
+
done
|
|
55
|
+
# Stop a leftover reactivity watcher the old installer may have launched.
|
|
56
|
+
pkill -f 'connector-watch.sh' 2>/dev/null && say "stopped a leftover connector watcher" || true
|
|
57
|
+
# Strip the managed config block ONLY when it is the LEGACY variant — i.e. it still carries the
|
|
58
|
+
# connector-era webhook wake route (`ours-wake`). The current block is mcp_servers.ours only, so
|
|
59
|
+
# this never touches an up-to-date block; config-install (step 3) then re-writes the current one.
|
|
60
|
+
if [ -f "$HERMES_CONFIG" ] && grep -qF "$MANAGED_SENTINEL" "$HERMES_CONFIG" 2>/dev/null \
|
|
61
|
+
&& grep -qiE 'ours-wake|ours_wake' "$HERMES_CONFIG" 2>/dev/null; then
|
|
62
|
+
tmp="$(mktemp)"
|
|
63
|
+
awk -v s="$MANAGED_SENTINEL" -v e="$MANAGED_SENTINEL_END" '
|
|
64
|
+
index($0,s){skip=1}
|
|
65
|
+
skip && index($0,e){skip=0; next}
|
|
66
|
+
!skip{print}
|
|
67
|
+
' "$HERMES_CONFIG" > "$tmp" && mv "$tmp" "$HERMES_CONFIG" \
|
|
68
|
+
&& say "removed legacy connector wake-route block from $HERMES_CONFIG (re-adding the current mcp-only block)"
|
|
44
69
|
fi
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# --- 1) daemon (ensure @latest + restart on change) ---
|
|
73
|
+
ensure_daemon_latest
|
|
74
|
+
|
|
75
|
+
# --- 1b) legacy connector-era cleanup (idempotent, guarded) ---
|
|
76
|
+
legacy_cleanup
|
|
50
77
|
|
|
51
78
|
# --- 2) skills ---
|
|
52
79
|
mkdir -p "$SKILLS_DEST"
|
|
@@ -56,57 +83,18 @@ for s in ours writing-agent-bios; do
|
|
|
56
83
|
say "installed skill: $SKILLS_DEST/$s"
|
|
57
84
|
done
|
|
58
85
|
|
|
59
|
-
# --- 3)
|
|
60
|
-
if [ -z "${OURS_WAKE_SECRET:-}" ] && [ -f "$ENV_FILE" ]; then
|
|
61
|
-
# Reuse ONLY the persisted secret so the route and the watcher never drift apart across
|
|
62
|
-
# re-runs. Extract it in a SUBSHELL so sourcing the env file cannot clobber the current
|
|
63
|
-
# environment — the file also `export`s CONNECTOR_IDENTITIES (from the prior run), and a
|
|
64
|
-
# naive `. "$ENV_FILE"` would overwrite a re-run's CLI-provided --identities, silently
|
|
65
|
-
# no-op'ing the watcher. The env file records the secret as CONNECTOR_HMAC_SECRET.
|
|
66
|
-
OURS_WAKE_SECRET="$(. "$ENV_FILE" >/dev/null 2>&1; printf '%s' "${CONNECTOR_HMAC_SECRET:-}")"
|
|
67
|
-
fi
|
|
68
|
-
if [ -z "${OURS_WAKE_SECRET:-}" ] || [ "${OURS_WAKE_SECRET:-}" = "CHANGE_ME_local_webhook_hmac" ]; then
|
|
69
|
-
OURS_WAKE_SECRET="$(openssl rand -hex 32)"
|
|
70
|
-
say "generated a new shared HMAC secret"
|
|
71
|
-
fi
|
|
86
|
+
# --- 3) config.yaml: register the ours MCP server (idempotent, safe merge) ---
|
|
72
87
|
mkdir -p "$HERMES_DIR"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
export CONNECTOR_HMAC_SECRET="$OURS_WAKE_SECRET"
|
|
77
|
-
export CONNECTOR_WEBHOOK_URL="http://localhost:$OURS_WEBHOOK_PORT/webhooks/ours-wake"
|
|
78
|
-
export CONNECTOR_EVENT="ours_wake"
|
|
79
|
-
export CONNECTOR_IDENTITIES="${CONNECTOR_IDENTITIES:-}"
|
|
80
|
-
EOF
|
|
81
|
-
say "wrote connector env: $ENV_FILE"
|
|
82
|
-
|
|
83
|
-
# --- 4) config.yaml (idempotent, safe merge) ---
|
|
84
|
-
OURS_WAKE_SECRET="$OURS_WAKE_SECRET" CONNECTOR_IDENTITIES="${CONNECTOR_IDENTITIES:-}" \
|
|
85
|
-
OURS_WEBHOOK_PORT="$OURS_WEBHOOK_PORT" HERMES_CONFIG="$HERMES_CONFIG" \
|
|
86
|
-
node "$SELFDIR/bin/hermes-config-install.mjs" || {
|
|
87
|
-
rc=$?; [ "$rc" = "3" ] && say "config needs a manual merge (see block above)"; [ "$rc" = "3" ] || exit "$rc";
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# --- 5) watcher ---
|
|
91
|
-
if [ "${OURS_INSTALL_SKIP_WATCHER:-}" = "1" ]; then
|
|
92
|
-
say "skipping watcher start (OURS_INSTALL_SKIP_WATCHER=1)"
|
|
93
|
-
elif [ -z "${CONNECTOR_IDENTITIES:-}" ]; then
|
|
94
|
-
say "no CONNECTOR_IDENTITIES set — not starting the watcher. Start it later with:"
|
|
95
|
-
say " CONNECTOR_IDENTITIES=\"Agent1 Agent2\" bash $SELFDIR/install.sh"
|
|
96
|
-
elif CONN="$(find_connector)"; then
|
|
97
|
-
if pgrep -f "connector-watch.sh" >/dev/null 2>&1; then
|
|
98
|
-
say "a connector watcher is already running — leaving it (restart it to pick up new identities)"
|
|
99
|
-
else
|
|
100
|
-
say "starting the reactivity watcher for: $CONNECTOR_IDENTITIES"
|
|
101
|
-
( set -a; . "$ENV_FILE"; set +a; nohup bash "$CONN/connector-watch.sh" >"$HERMES_DIR/ours-connector.log" 2>&1 & )
|
|
102
|
-
say "watcher started (logs: $HERMES_DIR/ours-connector.log)"
|
|
103
|
-
fi
|
|
104
|
-
else
|
|
105
|
-
say "could not locate @ours.network/connector — set CONNECTOR_DIR and re-run to start the watcher"
|
|
106
|
-
fi
|
|
88
|
+
HERMES_CONFIG="$HERMES_CONFIG" node "$SELFDIR/bin/hermes-config-install.mjs" || {
|
|
89
|
+
rc=$?; [ "$rc" = "3" ] && say "config needs a manual merge (see block above)"; [ "$rc" = "3" ] || exit "$rc";
|
|
90
|
+
}
|
|
107
91
|
|
|
108
92
|
say "done. Run /reload-mcp in Hermes to load the mcp_ours_* tools."
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
say "
|
|
93
|
+
# --- version echo: show the user they are on latest ---
|
|
94
|
+
if [ "${OURS_INSTALL_SKIP_DAEMON:-}" != "1" ]; then
|
|
95
|
+
say "versions:"
|
|
96
|
+
say " daemon: $(ours-mcp --version 2>/dev/null | head -1 || echo 'unknown')"
|
|
97
|
+
say " plugin: $(npm ls -g @ours.network/hermes 2>/dev/null | grep -oE '@ours\.network/hermes@[0-9][0-9.]*' | head -1 || echo '@ours.network/hermes (not a global install)')"
|
|
112
98
|
fi
|
|
99
|
+
say "next: in your agent, bind (or create) an identity and ask the ours skill to \"wake me on new"
|
|
100
|
+
say " mail\" — it tails ours-mcp watch in-session and reacts to new mail as it arrives."
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/hermes",
|
|
3
|
-
"version": "0.
|
|
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
|
|
3
|
+
"version": "0.5.0",
|
|
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",
|
|
7
7
|
"author": "Adapt Toolkit",
|
|
@@ -43,8 +43,5 @@
|
|
|
43
43
|
"scripts": {
|
|
44
44
|
"install-plugin": "bash install.sh",
|
|
45
45
|
"test": "node --test"
|
|
46
|
-
},
|
|
47
|
-
"dependencies": {
|
|
48
|
-
"@ours.network/connector": "0.2.0"
|
|
49
46
|
}
|
|
50
47
|
}
|
package/skills/ours/SKILL.md
CHANGED
|
@@ -85,17 +85,19 @@ Walk the user through these, checking each. Stop and help at the first one that
|
|
|
85
85
|
These run on the user's machine; if a step needs them at a terminal, suggest they
|
|
86
86
|
type `! ours-mcp status` etc.
|
|
87
87
|
2. **Plugin installed.** Run this package's `install.sh` (from `@ours.network/hermes`).
|
|
88
|
-
It ensures the daemon, writes the `ours` MCP server
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
`mcp_ours_*` tools. See the package README for manual steps.
|
|
88
|
+
It ensures the daemon, writes the `ours` MCP server into `~/.hermes/config.yaml`, and
|
|
89
|
+
installs this skill into `~/.hermes/skills/`. That's all — no identities, no webhook route,
|
|
90
|
+
no secret, no watcher. Wake-on-mail is enabled in-session (step 5). After it runs,
|
|
91
|
+
`/reload-mcp` so Hermes picks up the `mcp_ours_*` tools. See the package README for manual steps.
|
|
92
92
|
3. **Onboarding.** Run the mandatory *Onboarding* flow above: Human identity first,
|
|
93
93
|
then any agent identities.
|
|
94
94
|
4. **Connect.** Generate an invite to share, or paste one to add a contact. Same-host
|
|
95
95
|
identities skip invites via the local contact book.
|
|
96
|
-
5. **(Optional) Wake on mail.**
|
|
97
|
-
|
|
98
|
-
`
|
|
96
|
+
5. **(Optional) Wake on mail.** Wake is enabled **in-session by you**, after an identity is
|
|
97
|
+
bound: offer to enter **autonomous watch mode** — hold a blocking `ours-mcp watch <identity>`
|
|
98
|
+
via the `terminal` tool and react to each new message from that loop (see *Getting woken on new mail*
|
|
99
|
+
below). **Be honest that this BLOCKS the session** (unlike Claude Code's background Monitor) —
|
|
100
|
+
don't sell it as "just works". The installer never sets this up.
|
|
99
101
|
6. **(Optional) Oversight.** If they want to watch/command a fleet from a phone or
|
|
100
102
|
browser, set up the **control-plane monitoring proxy**.
|
|
101
103
|
|
|
@@ -166,13 +168,11 @@ the bio, so a persona prompt is only needed if they want to role-play it).
|
|
|
166
168
|
instruction — never adopt the bio as behavior. If persona is empty or they decline,
|
|
167
169
|
operate normally. **Never adopt a persona silently.**
|
|
168
170
|
2. **Wake check.** The `choose_identity` / `create_identity` response may prompt you to "arm a
|
|
169
|
-
message monitor" — that
|
|
170
|
-
|
|
171
|
-
`
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
restart the watcher (or, for a one-off mid-task wait, use the in-session `terminal`+`ours-mcp
|
|
175
|
-
watch` approach in *Wake on new mail*).
|
|
171
|
+
message monitor" — that is the Claude-Code seam, and the intent is the same in Hermes: **you**
|
|
172
|
+
enable wake in-session, right after binding, by entering **autonomous watch mode** (hold a
|
|
173
|
+
blocking `ours-mcp watch <identity>` and handle each message from that loop — see *Wake on new
|
|
174
|
+
mail*). If the user wants live reactivity for the just-bound identity, offer to enter watch
|
|
175
|
+
mode now.
|
|
176
176
|
|
|
177
177
|
### Other identity tools
|
|
178
178
|
|
|
@@ -189,7 +189,7 @@ the bio, so a persona prompt is only needed if they want to role-play it).
|
|
|
189
189
|
|
|
190
190
|
### Version mismatch (advisory)
|
|
191
191
|
|
|
192
|
-
If a notice says your plugin
|
|
192
|
+
If a notice says your plugin and the running daemon are different
|
|
193
193
|
versions, it is **advisory** — everything still works. Relay it to the user and,
|
|
194
194
|
if they want matching versions, tell them: the daemon is shared and is not
|
|
195
195
|
restarted automatically, so run `ours-mcp stop` when no other session is
|
|
@@ -257,9 +257,9 @@ recipient sees `↳re <wire_id>·s<n>`. It's a lightweight reference, not a thre
|
|
|
257
257
|
- "show my inbox" → `list_incoming_messages()` (full inbox, ids + status, read-only).
|
|
258
258
|
- Hermes has no SessionStart hook, so there is no auto-injected unread-backlog summary (that
|
|
259
259
|
is a Claude-Code seam). When the user returns to ours after a gap, offer to check: for each
|
|
260
|
-
relevant identity, `choose_identity` it and `get_messages()`.
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
relevant identity, `choose_identity` it and `get_messages()`. Autonomous watch mode (below)
|
|
261
|
+
keeps you draining mail in real time while you are on duty; the daemon holds anything received
|
|
262
|
+
while nothing was bound until you next `get_messages`.
|
|
263
263
|
|
|
264
264
|
### Send & receive files
|
|
265
265
|
Files are **distinct from text** (core's "files and text are distinct messages"): separate
|
|
@@ -298,49 +298,18 @@ tools, a separate store. To caption a file, also `send_message`.
|
|
|
298
298
|
- **Approval is Hermes's own tool-permission mode** — ours never decides whether a
|
|
299
299
|
`send_message` is auto-approved or prompted.
|
|
300
300
|
|
|
301
|
-
##
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
1. **OBSERVE** — the connector's watcher runs `ours-mcp watch <identity>` (non-binding,
|
|
311
|
-
non-draining). It tails that identity's `notifications.log` and emits one **body-free** line
|
|
312
|
-
per *new* message.
|
|
313
|
-
2. **WAKE** — on each line the watcher sends an HMAC-SHA256-signed `POST` to Hermes's webhook
|
|
314
|
-
route `ours-wake` (`http://localhost:8644/webhooks/ours-wake`), body
|
|
315
|
-
`{"event_type":"ours_wake","identity":"<identity>"}`, header `X-GitHub-Event: ours_wake`.
|
|
316
|
-
3. **DRAIN** — Hermes matches the `ours-wake` route (by event + HMAC), renders its prompt with
|
|
317
|
-
the poked `{identity}`, and runs a fresh agent turn with `skills: ["ours"]`. That turn binds
|
|
318
|
-
the identity and calls `get_messages` to read and act. Because ours binding is exclusive per
|
|
319
|
-
identity, that agent is the sole drainer of its inbox — no cross-draining.
|
|
320
|
-
|
|
321
|
-
**Setup is one-time, done by `install.sh`:** it writes the `ours-wake` route (with a generated
|
|
322
|
-
HMAC secret) into `~/.hermes/config.yaml` and starts the watcher for the configured identities
|
|
323
|
-
(`CONNECTOR_IDENTITIES`), sharing that same secret. To add an identity later, add it to
|
|
324
|
-
`CONNECTOR_IDENTITIES` and restart the watcher; the one route serves all identities.
|
|
325
|
-
|
|
326
|
-
> **Anti-pattern — do NOT do this.** Don't hand-roll reactivity with a `cronjob` that re-polls
|
|
327
|
-
> `get_messages` on a timer — that is busy-polling, latency-bound and wasteful. The event-driven
|
|
328
|
-
> watcher → `ours-wake` path is the correct mechanism. (A periodic non-consuming
|
|
329
|
-
> `list_incoming_messages` **backstop** for missed wakes is fine — the connector's reference
|
|
330
|
-
> gateway already includes one.)
|
|
331
|
-
|
|
332
|
-
**No wake just means no new mail — it is NOT a broken watcher.** If you expected mail and got
|
|
333
|
-
nothing for a long time, suspect *delivery*: check `ours-mcp status`, that the watcher process
|
|
334
|
-
is alive, that the webhook port matches on both ends, and that the peer actually sent.
|
|
335
|
-
|
|
336
|
-
**When actively awaiting a reply mid-task** (not relying on the background watcher), you can
|
|
337
|
-
watch in-session with Hermes's own tools: run `ours-mcp watch <identity>` via the `terminal`
|
|
338
|
-
tool with `background=true`, then drain with `get_messages` when a line appears (use the
|
|
339
|
-
`process` tool to poll/read it). Stop it when the exchange is done.
|
|
301
|
+
## Getting woken on new mail
|
|
302
|
+
|
|
303
|
+
When you bind an identity, offer the user, in plain language:
|
|
304
|
+
|
|
305
|
+
> "Want this session to **auto-wake** when a new message arrives, or **check manually**?"
|
|
306
|
+
|
|
307
|
+
- **Auto-wake** → arm the monitor: you hold a live `ours-mcp watch <id>` and react to each message as it arrives. **Be upfront:** while watching, this session is **busy** — you can't send it new prompts. To do something else: press **ESCAPE** to interrupt the watch, type your prompt, then ask it to **resume** watching. *(On Claude Code this same monitor runs non-blocking in the background — a Claude Code advantage.)*
|
|
308
|
+
- **Manual** → don't arm it; ask it to check `get_messages` whenever you want. No blocking.
|
|
340
309
|
|
|
341
310
|
## Control plane — bind a monitoring proxy (human oversight of a fleet)
|
|
342
311
|
|
|
343
|
-
This is **separate** from the
|
|
312
|
+
This is **separate** from the wake-on-mail watch above. The control plane lets a **person's
|
|
344
313
|
web-messenger account** (the ours web messenger, shipping as part of the upcoming ours-control-plane)
|
|
345
314
|
oversee and command all agents under this host's **Human identity** from a **Control
|
|
346
315
|
Panel**: view a **live monitoring feed** of monitored agents' traffic, create agents, edit
|
|
@@ -389,8 +358,8 @@ requests, and each agent's monitoring ON/off. Works whenever the Human identity
|
|
|
389
358
|
event (sender + id + date) to `$OURS_STATE_DIR/<identity>/notifications.log` (the wake
|
|
390
359
|
signal `ours-mcp watch` reads) and refreshes a body-free `unread.json`. Text lives in the
|
|
391
360
|
packet and leaves it solely via `get_messages`.
|
|
392
|
-
- **The wake
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
361
|
+
- **The wake signal is uniform.** `ours-mcp watch <identity>` is the common stream; each harness
|
|
362
|
+
drives it in-session. Claude Code uses its native `Monitor` tool; **Hermes uses autonomous watch
|
|
363
|
+
mode** — the agent holds a blocking `ours-mcp watch` via the `terminal` tool and reacts from that
|
|
364
|
+
loop (see *Getting woken on new mail*). The ours daemon, identities, and tools are identical across
|
|
365
|
+
harnesses — only how the agent runs the watch differs.
|
|
@@ -12,9 +12,10 @@ The daemon is a **shared, host-wide singleton** reachable only on `127.0.0.1`
|
|
|
12
12
|
| GC interval (ms) | `OURS_GC_INTERVAL_MS` | `gcIntervalMs` | `3600000` |
|
|
13
13
|
| Auto-start daemon | `OURS_AUTOSTART` | `autoStart` | `false` |
|
|
14
14
|
|
|
15
|
-
**The port is shared.**
|
|
16
|
-
|
|
17
|
-
**once in shared config**, never
|
|
15
|
+
**The port is shared.** Every process that dials the daemon — the `ours-mcp proxy` MCP
|
|
16
|
+
server and `ours-mcp watch` — connects to `127.0.0.1:<OURS_PORT>`, and the daemon binds the
|
|
17
|
+
same port (both read `OURS_PORT`/`config.json`). Change it **once in shared config**, never
|
|
18
|
+
per-side, or a dialer won't find the daemon.
|
|
18
19
|
|
|
19
20
|
**Changing config (consent-first — never on your own initiative):**
|
|
20
21
|
- Interactive: `ours-mcp config` (a survey). It needs a TTY, so ask the **user**
|