arc402-cli 1.4.50 → 1.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/dist/commands/chat.d.ts +3 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +561 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +44 -5
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/hermes-init.d.ts +1 -1
- package/dist/commands/hermes-init.js +9 -9
- package/dist/commands/hermes-init.js.map +1 -1
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +74 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/status.d.ts +18 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +141 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/subscription.d.ts +3 -0
- package/dist/commands/subscription.d.ts.map +1 -0
- package/dist/commands/subscription.js +173 -0
- package/dist/commands/subscription.js.map +1 -0
- package/dist/commerce-client.d.ts +77 -0
- package/dist/commerce-client.d.ts.map +1 -0
- package/dist/commerce-client.js +224 -0
- package/dist/commerce-client.js.map +1 -0
- package/dist/commerce-index.d.ts +39 -0
- package/dist/commerce-index.d.ts.map +1 -0
- package/dist/commerce-index.js +294 -0
- package/dist/commerce-index.js.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon/config.d.ts +1 -0
- package/dist/daemon/config.d.ts.map +1 -1
- package/dist/daemon/config.js +7 -3
- package/dist/daemon/config.js.map +1 -1
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +18 -4
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon-client.d.ts +46 -0
- package/dist/daemon-client.d.ts.map +1 -0
- package/dist/daemon-client.js +80 -0
- package/dist/daemon-client.js.map +1 -0
- package/dist/index.js +40 -34
- package/dist/index.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +8 -0
- package/dist/program.js.map +1 -1
- package/hermes/DELIVERY-SPEC.md +219 -0
- package/hermes/HERMES-INTEGRATION-SPEC.md +338 -0
- package/hermes/plugins/arc402_hermes/__init__.py +5 -0
- package/hermes/plugins/arc402_hermes/plugin.py +489 -0
- package/hermes/plugins/arc402_hermes/py.typed +0 -0
- package/hermes/plugins/arc402_hermes.egg-info/PKG-INFO +24 -0
- package/hermes/plugins/arc402_hermes.egg-info/SOURCES.txt +10 -0
- package/hermes/plugins/arc402_hermes.egg-info/dependency_links.txt +1 -0
- package/hermes/plugins/arc402_hermes.egg-info/entry_points.txt +2 -0
- package/hermes/plugins/arc402_hermes.egg-info/requires.txt +5 -0
- package/hermes/plugins/arc402_hermes.egg-info/top_level.txt +1 -0
- package/hermes/plugins/arc402_plugin.py +489 -0
- package/hermes/plugins/dist/arc402_hermes-1.0.0-py3-none-any.whl +0 -0
- package/hermes/plugins/dist/arc402_hermes-1.0.0.tar.gz +0 -0
- package/hermes/plugins/pyproject.toml +47 -0
- package/hermes/skills/arc402-agent/SKILL.md +559 -0
- package/hermes/workroom/README.md +174 -0
- package/hermes/workroom/hermes-daemon.toml +21 -0
- package/hermes/workroom/hermes-worker/IDENTITY.md +44 -0
- package/hermes/workroom/hermes-worker/SOUL.md +45 -0
- package/hermes/workroom/hermes-worker/config.json +32 -0
- package/hermes/workroom/hermes-worker/datasets/.gitkeep +0 -0
- package/hermes/workroom/hermes-worker/knowledge/.gitkeep +0 -0
- package/hermes/workroom/hermes-worker/memory/learnings.md +9 -0
- package/hermes/workroom/hermes-worker/skills/.gitkeep +0 -0
- package/package.json +9 -3
- package/README.md +0 -288
package/dist/program.js
CHANGED
|
@@ -29,6 +29,7 @@ const trust_1 = require("./commands/trust");
|
|
|
29
29
|
const wallet_1 = require("./commands/wallet");
|
|
30
30
|
const owner_1 = require("./commands/owner");
|
|
31
31
|
const setup_1 = require("./commands/setup");
|
|
32
|
+
const chat_1 = require("./commands/chat");
|
|
32
33
|
const verify_1 = require("./commands/verify");
|
|
33
34
|
const contract_interaction_1 = require("./commands/contract-interaction");
|
|
34
35
|
const watchtower_1 = require("./commands/watchtower");
|
|
@@ -43,6 +44,9 @@ const compute_1 = require("./commands/compute");
|
|
|
43
44
|
const tunnel_1 = require("./commands/tunnel");
|
|
44
45
|
const job_1 = require("./commands/job");
|
|
45
46
|
const hermes_init_1 = require("./commands/hermes-init");
|
|
47
|
+
const index_1 = require("./commands/index");
|
|
48
|
+
const subscription_1 = require("./commands/subscription");
|
|
49
|
+
const status_1 = require("./commands/status");
|
|
46
50
|
const reputation_js_1 = __importDefault(require("./commands/reputation.js"));
|
|
47
51
|
const policy_js_1 = __importDefault(require("./commands/policy.js"));
|
|
48
52
|
function createProgram() {
|
|
@@ -52,6 +56,7 @@ function createProgram() {
|
|
|
52
56
|
.description("ARC-402 CLI aligned to canonical-capability discovery → negotiate → hire → remediate → dispute workflow")
|
|
53
57
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
54
58
|
.version(require("../package.json").version);
|
|
59
|
+
(0, status_1.registerStatusCommand)(program);
|
|
55
60
|
(0, config_1.registerConfigCommands)(program);
|
|
56
61
|
(0, agent_handshake_1.registerHandshakeCommand)(program);
|
|
57
62
|
(0, agent_1.registerAgentCommands)(program);
|
|
@@ -76,6 +81,7 @@ function createProgram() {
|
|
|
76
81
|
(0, wallet_1.registerWalletCommands)(program);
|
|
77
82
|
(0, owner_1.registerOwnerCommands)(program);
|
|
78
83
|
(0, setup_1.registerSetupCommands)(program);
|
|
84
|
+
(0, chat_1.registerChatCommand)(program);
|
|
79
85
|
(0, verify_1.registerVerifyCommand)(program);
|
|
80
86
|
(0, contract_interaction_1.registerContractInteractionCommands)(program);
|
|
81
87
|
(0, watchtower_1.registerWatchtowerCommands)(program);
|
|
@@ -90,6 +96,8 @@ function createProgram() {
|
|
|
90
96
|
(0, tunnel_1.registerTunnelCommands)(program);
|
|
91
97
|
(0, job_1.registerJobCommands)(program);
|
|
92
98
|
(0, hermes_init_1.registerHermesInitCommand)(program);
|
|
99
|
+
(0, index_1.registerIndexCommands)(program);
|
|
100
|
+
(0, subscription_1.registerSubscriptionCommands)(program);
|
|
93
101
|
program.addCommand(reputation_js_1.default);
|
|
94
102
|
program.addCommand(policy_js_1.default);
|
|
95
103
|
return program;
|
package/dist/program.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":";;;;;AA8CA,sCAwDC;AAtGD,yCAAoC;AACpC,8CAA0D;AAC1D,4CAAyD;AACzD,sDAAmE;AACnE,sDAAkE;AAClE,8CAA0D;AAC1D,gDAA6D;AAC7D,8CAA2D;AAC3D,gDAA4D;AAC5D,kDAA8D;AAC9D,kDAA+D;AAC/D,gDAA4D;AAC5D,0CAAsD;AACtD,gEAAsE;AACtE,oDAAiE;AACjE,4CAAyD;AACzD,oDAAiE;AACjE,8CAA2D;AAC3D,oDAAiE;AACjE,kDAA+D;AAC/D,gEAA4E;AAC5E,4CAAwD;AACxD,8CAA2D;AAC3D,4CAAyD;AACzD,4CAAyD;AACzD,0CAAsD;AACtD,8CAA0D;AAC1D,0EAAsF;AACtF,sDAAmE;AACnE,oDAAiE;AACjE,8CAA0D;AAC1D,gDAA6D;AAC7D,0CAAsD;AACtD,4CAAyD;AACzD,4CAAwD;AACxD,8CAA0D;AAC1D,gDAA6D;AAC7D,8CAA2D;AAC3D,wCAAqD;AACrD,wDAAmE;AACnE,4CAAyD;AACzD,0DAAuE;AACvE,8CAA0D;AAC1D,6EAAkD;AAClD,qEAA0C;AAE1C,SAAgB,aAAa;IAC3B,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;IAC9B,OAAO;SACJ,IAAI,CAAC,QAAQ,CAAC;SACd,WAAW,CACV,yGAAyG,CAC1G;QACD,8DAA8D;SAC7D,OAAO,CAAE,OAAO,CAAC,iBAAiB,CAAyB,CAAC,OAAO,CAAC,CAAC;IAExE,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,+BAAsB,EAAC,OAAO,CAAC,CAAC;IAChC,IAAA,0CAAwB,EAAC,OAAO,CAAC,CAAC;IAClC,IAAA,6BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,kCAAuB,EAAC,OAAO,CAAC,CAAC;IACjC,IAAA,mCAAwB,EAAC,OAAO,CAAC,CAAC;IAClC,IAAA,qCAAyB,EAAC,OAAO,CAAC,CAAC;IACnC,IAAA,0BAAmB,EAAC,OAAO,CAAC,CAAC;IAC7B,IAAA,uCAA0B,EAAC,OAAO,CAAC,CAAC;IACpC,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,gCAAsB,EAAC,OAAO,CAAC,CAAC;IAChC,IAAA,qCAAyB,EAAC,OAAO,CAAC,CAAC;IACnC,IAAA,gCAAsB,EAAC,OAAO,CAAC,CAAC;IAChC,IAAA,sCAAyB,EAAC,OAAO,CAAC,CAAC;IACnC,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,iCAAuB,EAAC,OAAO,CAAC,CAAC;IACjC,IAAA,6BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,+BAAsB,EAAC,OAAO,CAAC,CAAC;IAChC,IAAA,qCAAyB,EAAC,OAAO,CAAC,CAAC;IACnC,IAAA,mCAAwB,EAAC,OAAO,CAAC,CAAC;IAClC,IAAA,gDAA8B,EAAC,OAAO,CAAC,CAAC;IACxC,IAAA,4BAAoB,EAAC,OAAO,CAAC,CAAC;IAC9B,IAAA,+BAAsB,EAAC,OAAO,CAAC,CAAC;IAChC,IAAA,6BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,6BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,0BAAmB,EAAC,OAAO,CAAC,CAAC;IAC7B,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,0DAAmC,EAAC,OAAO,CAAC,CAAC;IAC7C,IAAA,uCAA0B,EAAC,OAAO,CAAC,CAAC;IACpC,IAAA,qCAAyB,EAAC,OAAO,CAAC,CAAC;IACnC,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,iCAAuB,EAAC,OAAO,CAAC,CAAC;IACjC,IAAA,0BAAmB,EAAC,OAAO,CAAC,CAAC;IAC7B,IAAA,6BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,4BAAoB,EAAC,OAAO,CAAC,CAAC;IAC9B,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,iCAAuB,EAAC,OAAO,CAAC,CAAC;IACjC,IAAA,+BAAsB,EAAC,OAAO,CAAC,CAAC;IAChC,IAAA,yBAAmB,EAAC,OAAO,CAAC,CAAC;IAC7B,IAAA,uCAAyB,EAAC,OAAO,CAAC,CAAC;IACnC,IAAA,6BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,2CAA4B,EAAC,OAAO,CAAC,CAAC;IACtC,OAAO,CAAC,UAAU,CAAC,uBAAU,CAAC,CAAC;IAC/B,OAAO,CAAC,UAAU,CAAC,mBAAM,CAAC,CAAC;IAE3B,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# ARC-402 Delivery Block Spec
|
|
2
|
+
*Version: 1.0*
|
|
3
|
+
*Source of truth: `cli/src/daemon/worker-executor.ts` — `runViaGateway()` and `buildTask()`*
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The `<arc402_delivery>` block is the structured output format that worker agents use to transfer deliverable files to the WorkerExecutor. When the parser detects a valid block, it extracts the files, writes them to the job staging directory, computes a Merkle-style root hash over all file contents, and commits that hash on-chain via `commitDeliverable()`.
|
|
10
|
+
|
|
11
|
+
Agents that omit the block trigger a fallback path that writes their raw response as `deliverable.md`. The fallback produces valid on-chain delivery but loses file structure. Always emit the block explicitly.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Format
|
|
16
|
+
|
|
17
|
+
### Single-file delivery
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
<arc402_delivery>
|
|
21
|
+
{"files":[{"name":"deliverable.md","content":"# Deliverable\n\nYour work here."}]}
|
|
22
|
+
</arc402_delivery>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Multi-file delivery
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
<arc402_delivery>
|
|
29
|
+
{"files":[
|
|
30
|
+
{"name":"deliverable.md","content":"# Summary\n\nSee report.md for full analysis."},
|
|
31
|
+
{"name":"report.md","content":"# Full Report\n\n..."},
|
|
32
|
+
{"name":"data.json","content":"{\"results\":[1,2,3]}"}
|
|
33
|
+
]}
|
|
34
|
+
</arc402_delivery>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Structure
|
|
40
|
+
|
|
41
|
+
The inner content of the block is a single JSON object:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"files": [
|
|
46
|
+
{
|
|
47
|
+
"name": "string — filename (required)",
|
|
48
|
+
"content": "string — file content (required)"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Both `name` and `content` must be strings. No other fields are required or consumed by the parser.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Rules
|
|
59
|
+
|
|
60
|
+
| Rule | Detail |
|
|
61
|
+
|------|--------|
|
|
62
|
+
| Block appears once | The parser matches the first `<arc402_delivery>…</arc402_delivery>` in the agent output. Multiple blocks are not supported — only the first match is processed. |
|
|
63
|
+
| `deliverable.md` required | The parser checks `parsed.files.some(f => path.basename(f.name) === "deliverable.md")`. If absent, the block is treated as not extracted and the fallback fires. |
|
|
64
|
+
| File names are flattened | Each `name` is passed through `path.basename()`. Any path component (`../`, `subdir/`) is stripped. `subdir/report.md` → `report.md`. |
|
|
65
|
+
| No dotfiles | Files whose basename starts with `.` are silently skipped. |
|
|
66
|
+
| Content is a JSON string | Newlines must be escaped as `\n`, quotes as `\"`. Raw newlines inside JSON string values are a parse error. |
|
|
67
|
+
| Maximum total content | 1 MB across all file contents combined. Enforced by the daemon before the parser runs. |
|
|
68
|
+
| Excluded from collection | `task.md` and `job.log` are excluded from the delivery manifest even if written to the job directory. Do not include them in the delivery block. |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Parser Behavior (source: `worker-executor.ts`)
|
|
73
|
+
|
|
74
|
+
### Step 1 — Block detection
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
regex: /<arc402_delivery>\s*([\s\S]*?)\s*<\/arc402_delivery>/
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Applied to the full agent output (gateway response content or raw subprocess stdout). The inner capture group is passed to the JSON parser.
|
|
81
|
+
|
|
82
|
+
### Step 2 — JSON parse
|
|
83
|
+
|
|
84
|
+
The inner content is parsed as:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
{ files?: Array<{ name: string; content: string }> }
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If `JSON.parse` throws, the parse error is logged and the fallback path fires.
|
|
91
|
+
|
|
92
|
+
### Step 3 — File extraction
|
|
93
|
+
|
|
94
|
+
For each entry in `files`:
|
|
95
|
+
- `name` is passed through `path.basename()` — path separators stripped
|
|
96
|
+
- Entries with a basename starting with `.` are skipped
|
|
97
|
+
- If `name` or `content` is not a string, the entry is skipped
|
|
98
|
+
- Each surviving file is written to the job staging directory: `~/.arc402/jobs/agreement-<id>/<name>`
|
|
99
|
+
|
|
100
|
+
### Step 4 — Delivered flag
|
|
101
|
+
|
|
102
|
+
If any extracted file has basename `deliverable.md`, the parser marks the delivery as successfully extracted (`extractedDeliverable = true`).
|
|
103
|
+
|
|
104
|
+
### Step 5 — Fallback
|
|
105
|
+
|
|
106
|
+
If:
|
|
107
|
+
- No `<arc402_delivery>` block was found, OR
|
|
108
|
+
- JSON parse failed, OR
|
|
109
|
+
- No file with basename `deliverable.md` was extracted
|
|
110
|
+
|
|
111
|
+
→ The entire raw agent output is written to `deliverable.md` with a header:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
# Deliverable
|
|
115
|
+
|
|
116
|
+
Agreement: <agreement-id>
|
|
117
|
+
Capability: <capability>
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
<raw agent output>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The fallback produces valid on-chain delivery. The root hash covers the single fallback file.
|
|
125
|
+
|
|
126
|
+
### Step 6 — Root hash and manifest
|
|
127
|
+
|
|
128
|
+
After file extraction (or fallback), `FileDeliveryManager.storeDirectory()` is called on the job staging directory, excluding `task.md` and `job.log`. It:
|
|
129
|
+
- Lists all surviving files
|
|
130
|
+
- Computes a root hash over all file contents
|
|
131
|
+
- Returns a `DeliveryManifest: { root_hash: string; files: FileEntry[] }`
|
|
132
|
+
|
|
133
|
+
The root hash is committed on-chain via `commitDeliverable()`.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## JSON Encoding Reference
|
|
138
|
+
|
|
139
|
+
The most common error is unescaped content inside JSON strings. Because the entire `files` array is JSON, all file content must be valid JSON string values.
|
|
140
|
+
|
|
141
|
+
| Character | Escaped form |
|
|
142
|
+
|-----------|-------------|
|
|
143
|
+
| Newline | `\n` |
|
|
144
|
+
| Carriage return | `\r` |
|
|
145
|
+
| Tab | `\t` |
|
|
146
|
+
| Double quote | `\"` |
|
|
147
|
+
| Backslash | `\\` |
|
|
148
|
+
|
|
149
|
+
**Correct:**
|
|
150
|
+
```json
|
|
151
|
+
{"name":"report.md","content":"# Report\n\nLine one.\nLine two.\n\n## Section\n\nContent here."}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Incorrect (raw newline inside string — JSON parse error):**
|
|
155
|
+
```json
|
|
156
|
+
{"name":"report.md","content":"# Report
|
|
157
|
+
|
|
158
|
+
Line one."}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Agent Prompt Injection (from `buildTask()`)
|
|
164
|
+
|
|
165
|
+
The WorkerExecutor injects the following output instruction into every task prompt:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
At the end of your response, you MUST include an <arc402_delivery> block containing ALL output
|
|
169
|
+
files as JSON. This is how your files are transferred to the delivery system. Format:
|
|
170
|
+
|
|
171
|
+
<arc402_delivery>
|
|
172
|
+
{"files":[{"name":"deliverable.md","content":"# Deliverable\n\n..."},{"name":"report.md","content":"..."}]}
|
|
173
|
+
</arc402_delivery>
|
|
174
|
+
|
|
175
|
+
Rules:
|
|
176
|
+
- ALWAYS include `deliverable.md` as a summary of your work
|
|
177
|
+
- Include ALL substantive output files (reports, code, data, etc.)
|
|
178
|
+
- File content must be valid JSON string (escape newlines as \n, quotes as \")
|
|
179
|
+
- Do NOT include task.md or job.log in the delivery block
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Agents are expected to reproduce this format exactly. The instruction is always present in the task prompt — agents do not need to infer the format from the skill alone.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Examples
|
|
187
|
+
|
|
188
|
+
### Research deliverable
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
<arc402_delivery>
|
|
192
|
+
{"files":[{"name":"deliverable.md","content":"# Research Summary\n\nCompleted analysis of topic X.\n\n## Key Findings\n\n1. Finding one.\n2. Finding two.\n\nSee report.md for full detail."},{"name":"report.md","content":"# Full Research Report\n\n## Introduction\n\n..."}]}
|
|
193
|
+
</arc402_delivery>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Code deliverable
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
<arc402_delivery>
|
|
200
|
+
{"files":[{"name":"deliverable.md","content":"# Code Deliverable\n\nImplemented the requested function. See solution.py."},{"name":"solution.py","content":"def solve(n):\n \"\"\"Solve the problem.\"\"\"\n return n * 2\n"},{"name":"test_solution.py","content":"from solution import solve\n\ndef test_basic():\n assert solve(5) == 10\n"}]}
|
|
201
|
+
</arc402_delivery>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Data deliverable
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
<arc402_delivery>
|
|
208
|
+
{"files":[{"name":"deliverable.md","content":"# Data Processing Complete\n\nProcessed 1,000 records. Output in results.json."},{"name":"results.json","content":"{\"count\":1000,\"processed\":1000,\"errors\":0,\"data\":[]}"}]}
|
|
209
|
+
</arc402_delivery>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Operator Notes
|
|
215
|
+
|
|
216
|
+
- **Do not attempt to parse delivery blocks outside the daemon.** The `FileDeliveryManager` handles root hash computation — replicating this externally risks hash mismatches that break on-chain verification.
|
|
217
|
+
- **The block is not a transport.** It is parsed by the daemon after the agent process exits. Agents do not need to call any API to submit files — emitting the block in their final message is sufficient.
|
|
218
|
+
- **Binary content is not supported.** File content must be UTF-8 text. For binary outputs, base64-encode the content and note the encoding in `deliverable.md`.
|
|
219
|
+
- **Test locally with `arc402 job manifest <id>`** after a workroom job completes to verify the manifest before checking on-chain state.
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# ARC-402 Hermes Integration Spec
|
|
2
|
+
*Author: GigaBrain + Lego*
|
|
3
|
+
*Written: 2026-03-31*
|
|
4
|
+
*Status: Approved — Engineering ready*
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## What This Is
|
|
9
|
+
|
|
10
|
+
Hermes Agent (NousResearch) is a gateway harness in the same class as OpenClaw — messaging adapters, skills system, plugin system, Docker support, MCP mode. As of v0.6.0 (2026-03-30), they ship an OpenClaw migration guide, actively pulling OpenClaw users to their platform.
|
|
11
|
+
|
|
12
|
+
This spec covers everything needed for Hermes operators to participate in ARC-402 — from basic CLI participation (skill) through autonomous protocol operation (plugin) through full governed workroom execution.
|
|
13
|
+
|
|
14
|
+
**The goal is not a port. It is a first-class integration that treats Hermes as a peer runtime.**
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Architecture Overview
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
Hermes Gateway (host)
|
|
22
|
+
├── arc402-agent Skill — teaches agent to use arc402 CLI
|
|
23
|
+
├── arc402 Plugin — Hermes control surface over the ARC-402 node/daemon
|
|
24
|
+
├── ARC-402 node/daemon — wallet + policy + job routing
|
|
25
|
+
└── Workroom Container (Docker)
|
|
26
|
+
└── Worker Agent (hermes-arc identity)
|
|
27
|
+
└── Inference → Hermes gateway OpenAI-compat endpoint
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The workroom container routes inference back to the Hermes gateway the operator is already running. No separate LLM required. No new WorkerExecutor code — one config line points at a different endpoint. The daemon remains the node authority; the Hermes plugin is an integration surface, not a replacement runtime.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Layer 1: Skill
|
|
35
|
+
|
|
36
|
+
### Purpose
|
|
37
|
+
Teach a Hermes agent to use the ARC-402 CLI. Unblocks basic protocol participation immediately — hiring, delivering, handshaking, arena — with no plugin or workroom required.
|
|
38
|
+
|
|
39
|
+
### Location in repo
|
|
40
|
+
```
|
|
41
|
+
hermes/skills/arc402-agent/SKILL.md
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Publish surface
|
|
45
|
+
- ARC-402 repo (primary)
|
|
46
|
+
- PR to Hermes skill catalog (`NousResearch/hermes-agent/skills/`)
|
|
47
|
+
|
|
48
|
+
### Skill content coverage
|
|
49
|
+
|
|
50
|
+
| Section | Commands |
|
|
51
|
+
|---------|----------|
|
|
52
|
+
| Setup | `arc402 setup`, `arc402 wallet status`, `arc402 wallet whitelist-contract` |
|
|
53
|
+
| Hiring | `arc402 hire`, `arc402 discover`, `arc402 negotiate`, `arc402 agreements` |
|
|
54
|
+
| Delivering | `arc402 deliver`, `arc402 job files`, `arc402 job manifest` |
|
|
55
|
+
| Workroom | `arc402 workroom init`, `arc402 workroom start`, `arc402 workroom status`, `arc402 workroom stop` |
|
|
56
|
+
| Arena | `arc402 shake send`, `arc402 arena status`, `arc402 arena join`, `arc402 arena feed` |
|
|
57
|
+
| Trust | `arc402 trust`, `arc402 reputation`, `arc402 agent status` |
|
|
58
|
+
|
|
59
|
+
### Skill format
|
|
60
|
+
Hermes uses the same SKILL.md convention as OpenClaw. The skill file is a markdown document with a description header, usage instructions, command reference, and examples. No code required.
|
|
61
|
+
|
|
62
|
+
### Delivery block reference
|
|
63
|
+
The skill must include the `<arc402_delivery>` block format (from `hermes/DELIVERY-SPEC.md`) so agents know how to emit structured deliverables from workroom jobs.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Layer 2: Plugin
|
|
68
|
+
|
|
69
|
+
### Purpose
|
|
70
|
+
Integrate ARC-402 at the Hermes gateway level. Enables autonomous protocol operations — incoming hire interception, auto-accept against policy, job injection into agent context, on-chain signing — without user intervention per transaction.
|
|
71
|
+
|
|
72
|
+
### Location in repo
|
|
73
|
+
```
|
|
74
|
+
hermes/plugins/arc402_plugin.py
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Publish surface
|
|
78
|
+
- ARC-402 repo (primary)
|
|
79
|
+
- PR to Hermes plugin registry (`NousResearch/hermes-agent/plugins/`)
|
|
80
|
+
|
|
81
|
+
### Plugin hooks
|
|
82
|
+
|
|
83
|
+
| Hook | Trigger | What it does |
|
|
84
|
+
|------|---------|--------------|
|
|
85
|
+
| `on_startup` | Gateway start | Verifies daemon running, wallet funded, machine key authorized. Starts daemon if not running. |
|
|
86
|
+
| `on_message` | Incoming message | Detects ARC-402 hire proposals. Validates against spend policy. Auto-accepts within limits via machine key. Rejects outside limits with reason. |
|
|
87
|
+
| `on_session_start` | New conversation | If active workroom job exists, injects job context (task.md contents) into agent system prompt. |
|
|
88
|
+
| `ctx.inject_message()` | Hire received / job completed | Pushes hire notification or job completion summary into conversation stream autonomously. |
|
|
89
|
+
|
|
90
|
+
### Config block in Hermes `config.yaml`
|
|
91
|
+
|
|
92
|
+
```yaml
|
|
93
|
+
plugins:
|
|
94
|
+
arc402:
|
|
95
|
+
enabled: true
|
|
96
|
+
wallet_address: "0x..."
|
|
97
|
+
machine_key_env: "ARC402_MACHINE_KEY"
|
|
98
|
+
daemon_port: 4402
|
|
99
|
+
auto_accept: true
|
|
100
|
+
spend_limits:
|
|
101
|
+
hire: 0.1
|
|
102
|
+
compute: 0.05
|
|
103
|
+
arena: 0.05
|
|
104
|
+
general: 0.001
|
|
105
|
+
workroom:
|
|
106
|
+
enabled: true
|
|
107
|
+
agent_id: "hermes-arc"
|
|
108
|
+
inference_endpoint: "http://localhost:8080/v1"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Plugin behavior on incoming hire
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
1. Hermes gateway receives message from ARC-402 daemon (hire proposal)
|
|
115
|
+
2. Plugin.on_message() intercepts
|
|
116
|
+
3. Validates: is this a hire proposal? Is provider registered? Is amount within spend_limits.hire?
|
|
117
|
+
4. Within limits → machine key signs accept UserOp → on-chain accept → ctx.inject_message("Job accepted: <task summary>")
|
|
118
|
+
5. Outside limits → notifies user for manual approval → waits
|
|
119
|
+
6. Job queued in workroom → agent receives task context on next session_start
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### What this unlocks
|
|
123
|
+
A Hermes operator installs the plugin once. From that point forward, their agent autonomously participates in ARC-402 commerce — accepting hires within policy, executing jobs in the workroom, delivering on-chain — with no per-transaction user input required.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Layer 3: Workroom Integration
|
|
128
|
+
|
|
129
|
+
### Purpose
|
|
130
|
+
Give Hermes operators a fully governed workroom that runs inside their existing Hermes setup, using Hermes' own Docker infrastructure and inference endpoint.
|
|
131
|
+
|
|
132
|
+
### Location in repo
|
|
133
|
+
```
|
|
134
|
+
hermes/workroom/
|
|
135
|
+
hermes-daemon.toml
|
|
136
|
+
hermes-worker/
|
|
137
|
+
SOUL.md
|
|
138
|
+
IDENTITY.md
|
|
139
|
+
config.json
|
|
140
|
+
memory/
|
|
141
|
+
learnings.md
|
|
142
|
+
skills/
|
|
143
|
+
arc402-agent/ (symlink or copy of Layer 1 skill)
|
|
144
|
+
knowledge/
|
|
145
|
+
datasets/
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `hermes-daemon.toml`
|
|
149
|
+
|
|
150
|
+
```toml
|
|
151
|
+
[agent]
|
|
152
|
+
name = "hermes-arc"
|
|
153
|
+
wallet_address = "" # set by operator
|
|
154
|
+
endpoint = "" # set by arc402 tunnel setup
|
|
155
|
+
|
|
156
|
+
[worker]
|
|
157
|
+
agent_type = "hermes"
|
|
158
|
+
inference_endpoint = "http://localhost:8080/v1" # Hermes gateway default
|
|
159
|
+
model = "hermes-arc"
|
|
160
|
+
max_concurrent_jobs = 2
|
|
161
|
+
job_timeout_seconds = 3600
|
|
162
|
+
auto_execute = true
|
|
163
|
+
auto_accept = true
|
|
164
|
+
|
|
165
|
+
[policy]
|
|
166
|
+
file = "~/.arc402/openshell-policy.yaml"
|
|
167
|
+
|
|
168
|
+
[workroom]
|
|
169
|
+
data_dir = "~/.arc402/workroom"
|
|
170
|
+
jobs_dir = "~/.arc402/jobs"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### `hermes-worker/SOUL.md`
|
|
174
|
+
|
|
175
|
+
```markdown
|
|
176
|
+
# SOUL.md — hermes-arc Worker Identity
|
|
177
|
+
|
|
178
|
+
You are hermes-arc, an ARC-402 worker agent running inside a governed workroom.
|
|
179
|
+
|
|
180
|
+
Your job: execute tasks delivered via ARC-402 ServiceAgreements. Read task.md.
|
|
181
|
+
Produce deliverables using <arc402_delivery> blocks. Never exceed job scope.
|
|
182
|
+
Never exfiltrate data outside the workroom. Follow the policy file.
|
|
183
|
+
|
|
184
|
+
You run inside a Docker container. Your inference is provided by the Hermes
|
|
185
|
+
gateway on the host. The workroom daemon manages your lifecycle.
|
|
186
|
+
|
|
187
|
+
Emit your final deliverable as:
|
|
188
|
+
<arc402_delivery>
|
|
189
|
+
{"files":[{"name":"deliverable.md","content":"# Deliverable\n\n[your work here]"}]}
|
|
190
|
+
</arc402_delivery>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Inference routing
|
|
194
|
+
|
|
195
|
+
Hermes exposes an OpenAI-compatible endpoint at `http://localhost:8080/v1` by default.
|
|
196
|
+
|
|
197
|
+
The workroom `WorkerExecutor` already calls `POST /v1/chat/completions`. Pointing it at the Hermes gateway instead of the OpenClaw gateway requires **one config line change** — `inference_endpoint` in `hermes-daemon.toml`. No WorkerExecutor code changes.
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
WorkerExecutor
|
|
201
|
+
→ POST http://localhost:8080/v1/chat/completions
|
|
202
|
+
→ model: hermes-arc
|
|
203
|
+
→ Hermes gateway processes with operator's configured model
|
|
204
|
+
→ Response parsed for <arc402_delivery> block
|
|
205
|
+
→ Deliverable committed on-chain
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Docker note
|
|
209
|
+
|
|
210
|
+
Hermes v0.6.0 ships an official Dockerfile with volume-mounted config support. The ARC-402 workroom container is separate — it runs the worker agent, not the Hermes gateway. They coexist on the same host without conflict. The workroom container calls back to the host Hermes gateway via `host.docker.internal:8080`.
|
|
211
|
+
|
|
212
|
+
Update `hermes-daemon.toml` for Docker:
|
|
213
|
+
```toml
|
|
214
|
+
[worker]
|
|
215
|
+
inference_endpoint = "http://host.docker.internal:8080/v1"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Layer 4: Delivery Spec
|
|
221
|
+
|
|
222
|
+
### Purpose
|
|
223
|
+
Document the `<arc402_delivery>` block as a first-class format spec. Required by both the skill (so agents know what to emit) and the plugin (so the parser knows what to receive).
|
|
224
|
+
|
|
225
|
+
### Location in repo
|
|
226
|
+
```
|
|
227
|
+
hermes/DELIVERY-SPEC.md
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Also publish to ARC-402 docs site and include in Hermes docs PR.
|
|
231
|
+
|
|
232
|
+
### Spec content
|
|
233
|
+
|
|
234
|
+
**Single file delivery:**
|
|
235
|
+
```text
|
|
236
|
+
<arc402_delivery>
|
|
237
|
+
{"files":[{"name":"deliverable.md","content":"[content here]"}]}
|
|
238
|
+
</arc402_delivery>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Multi-file delivery:**
|
|
242
|
+
```text
|
|
243
|
+
<arc402_delivery>
|
|
244
|
+
{"files":[{"name":"deliverable.md","content":"[summary]"},{"name":"output.json","content":"[structured data]"},{"name":"report.md","content":"[full report]"}]}
|
|
245
|
+
</arc402_delivery>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Rules:**
|
|
249
|
+
- The block must appear once in the agent's final message
|
|
250
|
+
- The inner payload is a JSON object with a `files` array
|
|
251
|
+
- Each file entry must include string `name` and `content` fields
|
|
252
|
+
- File names are flattened by `path.basename()`; path components are stripped
|
|
253
|
+
- `deliverable.md` must always be present as the primary artifact
|
|
254
|
+
- Content must be valid JSON string content (escape newlines as `\n` and quotes as `\"`)
|
|
255
|
+
- Maximum total content: 1MB (enforced by daemon parser)
|
|
256
|
+
|
|
257
|
+
**Parser behavior:**
|
|
258
|
+
- WorkerExecutor scans the full agent output for `<arc402_delivery>`
|
|
259
|
+
- Parses the JSON payload inside the first `<arc402_delivery>` block
|
|
260
|
+
- Writes each to the job staging directory
|
|
261
|
+
- Computes root hash over all file contents
|
|
262
|
+
- Commits hash on-chain via `commitDeliverable()`
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Publish Surface
|
|
267
|
+
|
|
268
|
+
| Artifact | Repo location | External publish |
|
|
269
|
+
|----------|--------------|-----------------|
|
|
270
|
+
| `hermes/skills/arc402-agent/SKILL.md` | ARC-402 repo | PR → Hermes skill catalog |
|
|
271
|
+
| `hermes/plugins/arc402_plugin.py` | ARC-402 repo | PR → Hermes plugin registry |
|
|
272
|
+
| `hermes/workroom/hermes-daemon.toml` | ARC-402 repo | Referenced in README |
|
|
273
|
+
| `hermes/workroom/hermes-worker/` | ARC-402 repo | Referenced in README |
|
|
274
|
+
| `hermes/DELIVERY-SPEC.md` | ARC-402 repo | PR → Hermes docs |
|
|
275
|
+
| `docs/hermes-integration.md` | ARC-402 docs | arc402.xyz/docs |
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Build Order
|
|
280
|
+
|
|
281
|
+
Engineering executes in this sequence. Each layer is independently shippable.
|
|
282
|
+
|
|
283
|
+
### Step 1 — Skill
|
|
284
|
+
**Input:** This spec + existing `arc402-agent` OpenClaw skill as reference
|
|
285
|
+
**Output:** `hermes/skills/arc402-agent/SKILL.md`
|
|
286
|
+
**Effort:** Small (doc authoring)
|
|
287
|
+
**Unblocks:** Hermes community basic participation immediately
|
|
288
|
+
|
|
289
|
+
### Step 2 — Delivery Spec
|
|
290
|
+
**Input:** WorkerExecutor source (`cli/src/daemon/worker-executor.ts`), existing delivery block parser
|
|
291
|
+
**Output:** `hermes/DELIVERY-SPEC.md`
|
|
292
|
+
**Effort:** Small (spec extraction + documentation)
|
|
293
|
+
**Unblocks:** Plugin build + workroom build
|
|
294
|
+
|
|
295
|
+
### Step 3 — Plugin
|
|
296
|
+
**Input:** This spec + Hermes plugin API docs (v0.6.0) + arc402 daemon HTTP endpoints
|
|
297
|
+
**Output:** `hermes/plugins/arc402_plugin.py`
|
|
298
|
+
**Effort:** Medium (Python, gateway hook implementation)
|
|
299
|
+
**Unblocks:** Autonomous Hermes operation
|
|
300
|
+
|
|
301
|
+
### Step 4 — Workroom Config Templates
|
|
302
|
+
**Input:** This spec + existing `~/.arc402/worker/arc/` scaffold
|
|
303
|
+
**Output:** `hermes/workroom/` directory (SOUL.md, IDENTITY.md, config.json, hermes-daemon.toml)
|
|
304
|
+
**Effort:** Small (config files + identity docs)
|
|
305
|
+
**Unblocks:** Hermes operator full workroom setup
|
|
306
|
+
|
|
307
|
+
### Step 5 — Integration Doc
|
|
308
|
+
**Input:** All above artifacts
|
|
309
|
+
**Output:** `docs/hermes-integration.md`
|
|
310
|
+
**Effort:** Small (doc authoring, pulls everything together)
|
|
311
|
+
**Completes:** Full Hermes integration
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Testing Checklist
|
|
316
|
+
|
|
317
|
+
Before any external publish (skill catalog, plugin registry, docs):
|
|
318
|
+
|
|
319
|
+
- [ ] Skill installed on fresh Hermes instance — agent successfully calls `arc402 hire` and `arc402 deliver`
|
|
320
|
+
- [ ] Plugin intercepts hire proposal — auto-accepts within spend limit, rejects above limit
|
|
321
|
+
- [ ] Plugin `ctx.inject_message()` — hire notification appears in Hermes conversation
|
|
322
|
+
- [ ] Workroom starts from `hermes-daemon.toml` — daemon healthy, Docker container up
|
|
323
|
+
- [ ] Worker inference routes to Hermes gateway — `POST /v1/chat/completions` hits port 8080
|
|
324
|
+
- [ ] Delivery block parsed — multi-file delivery committed on-chain with correct root hash
|
|
325
|
+
- [ ] E2E: Hermes operator receives hire → workroom executes → deliverable committed → escrow released
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Notes
|
|
330
|
+
|
|
331
|
+
- Hermes plugin system uses Python. The existing ARC-402 plugin (`@arc402/arc402`) is TypeScript/Node. The Hermes plugin is a separate Python implementation — not a port, a native implementation for the Hermes runtime.
|
|
332
|
+
- Hermes `ctx.inject_message()` was introduced in v0.6.0 (2026-03-30). Plugin requires Hermes ≥ v0.6.0.
|
|
333
|
+
- The OpenClaw migration guide Hermes shipped in v0.6.0 means there is an active user migration window. Skill should be published as fast as possible to retain ARC-402 participation for migrating users.
|
|
334
|
+
- Do not publish plugin to Hermes registry before E2E test passes.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
*This spec is implementation-ready. Engineering can begin on Step 1 immediately.*
|