@oracle-agent/oracle 0.4.1 → 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 +74 -20
- package/SETUP.md +15 -2
- package/bin/oracle-data-mcp.mjs +1 -1
- package/bin/oracle.mjs +33 -0
- package/docs/cli.md +19 -0
- package/docs/connectors.md +13 -0
- package/docs/oracle-pack-standard.md +29 -0
- package/docs/profiles.md +1 -1
- package/examples/oracle-pack-template.mjs +38 -0
- package/package.json +13 -4
- package/profiles/oracle/SOUL.md +3 -1
- package/profiles/robinhood-agent/SOUL.md +5 -3
- package/public/agent-connect/app.js +84 -0
- package/public/agent-connect/index.html +83 -0
- package/public/agent-connect/styles.css +70 -0
- package/public/oracle-splash/assets/wordmarks/across.svg +4 -0
- package/public/oracle-splash/assets/wordmarks/aerodrome.svg +23 -0
- package/public/oracle-splash/assets/wordmarks/balancer.svg +3 -0
- package/public/oracle-splash/assets/wordmarks/cowswap.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/gmx.svg +13 -0
- package/public/oracle-splash/assets/wordmarks/hyperliquid.svg +21 -0
- package/public/oracle-splash/assets/wordmarks/hyperswap.svg +13 -0
- package/public/oracle-splash/assets/wordmarks/jupiter.svg +35 -0
- package/public/oracle-splash/assets/wordmarks/lifi.png +0 -0
- package/public/oracle-splash/assets/wordmarks/magic-eden.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/morpho.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/odos.svg +3 -0
- package/public/oracle-splash/assets/wordmarks/oneinch.svg +6 -0
- package/public/oracle-splash/assets/wordmarks/opensea.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/pancakeswap.svg +18 -0
- package/public/oracle-splash/assets/wordmarks/paraswap.svg +16 -0
- package/public/oracle-splash/assets/wordmarks/pendle.png +0 -0
- package/public/oracle-splash/assets/wordmarks/polymarket.png +0 -0
- package/public/oracle-splash/assets/wordmarks/quickswap.png +0 -0
- package/public/oracle-splash/assets/wordmarks/relay.svg +8 -0
- package/public/oracle-splash/assets/wordmarks/stargate.svg +15 -0
- package/public/oracle-splash/assets/wordmarks/uniswap.svg +18 -0
- package/public/oracle-splash/assets/wordmarks/velodrome.svg +84 -0
- package/public/oracle-splash/index.html +789 -485
- package/scripts/adversarial-bench.mjs +114 -0
- package/scripts/check-doc-drift.mjs +111 -0
- package/skills/oracle-action-semantics/SKILL.md +1 -1
- package/src/action-receipts.mjs +168 -0
- package/src/address-book.mjs +53 -5
- package/src/cli/commands/credential.mjs +9 -0
- package/src/cli/commands/data-mcp.mjs +18 -0
- package/src/cli/commands/data.mjs +73 -0
- package/src/cli/commands/doctor.mjs +131 -0
- package/src/cli/commands/help.mjs +7 -0
- package/src/cli/commands/init.mjs +27 -0
- package/src/cli/commands/mcp.mjs +142 -0
- package/src/cli/commands/prepare.mjs +12 -0
- package/src/cli/commands/public.mjs +20 -0
- package/src/cli/commands/route.mjs +12 -0
- package/src/cli/commands/runner.mjs +9 -0
- package/src/cli/commands/scan.mjs +12 -0
- package/src/cli/commands/sign.mjs +21 -0
- package/src/cli/commands/signer.mjs +9 -0
- package/src/cli/commands/upgrade.mjs +12 -0
- package/src/cli/commands/vault.mjs +9 -0
- package/src/cli/commands/version.mjs +22 -0
- package/src/cli/first-run.mjs +20 -0
- package/src/cli/kernel.mjs +198 -0
- package/src/cli/mcp-targets/chatgpt.mjs +51 -0
- package/src/cli/mcp-targets/claude-code.mjs +39 -0
- package/src/cli/mcp-targets/claude-desktop.mjs +24 -0
- package/src/cli/mcp-targets/codex.mjs +41 -0
- package/src/cli/mcp-targets/shared.mjs +61 -0
- package/src/cli/operator-dispatch.mjs +258 -0
- package/src/cli/paths.mjs +78 -0
- package/src/cli/spawn-child.mjs +43 -0
- package/src/exec-policy.mjs +6 -0
- package/src/index.mjs +24 -0
- package/src/onboarding/harness-configs.mjs +102 -0
- package/src/oracle-env.mjs +11 -2
- package/src/portfolio-risk.mjs +170 -0
- package/src/public-api/connect-agent.mjs +29 -10
- package/src/signals/engine.mjs +146 -0
- package/src/signals/index.mjs +1 -0
- package/src/watch-preferences.mjs +85 -0
package/README.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Oracle
|
|
2
2
|
|
|
3
|
+
## Quickstart (unified CLI)
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm i -g @oracle-agent/oracle
|
|
7
|
+
oracle init --apply # lanes + read plane only, no keys
|
|
8
|
+
oracle data serve # loopback read/prepare plane on 127.0.0.1:8787
|
|
9
|
+
oracle doctor # verify
|
|
10
|
+
# optional, explicit second step — signing stays a separate local package:
|
|
11
|
+
npm i -g @oracle-agent/operator
|
|
12
|
+
oracle sign init
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
|
|
3
16
|
**Prepare-only multichain agent control plane.** Policy-bounded intents; your wallet signs.
|
|
4
17
|
|
|
5
18
|
Specialist agent profiles, real protocol intents, self-custody by default,
|
|
@@ -20,13 +33,31 @@ alongside it — same split we run ourselves.
|
|
|
20
33
|
|
|
21
34
|
## Start in 5 steps
|
|
22
35
|
|
|
23
|
-
|
|
36
|
+
Source tree: **oracle `0.5.0`** · **operator `0.14.0`**
|
|
37
|
+
|
|
38
|
+
Published npm: **oracle `0.4.2`** · **operator `0.13.7`** until this source release is published.
|
|
24
39
|
|
|
25
40
|
```bash
|
|
26
|
-
# 1) install
|
|
27
|
-
npm i @oracle-agent/oracle@
|
|
41
|
+
# 1) install Oracle's public prepare plane
|
|
42
|
+
npm i @oracle-agent/oracle@latest
|
|
43
|
+
```
|
|
28
44
|
|
|
29
|
-
|
|
45
|
+
```js
|
|
46
|
+
// 2) prepare an artifact (no keys)
|
|
47
|
+
import { data } from "@oracle-agent/oracle";
|
|
48
|
+
const prepared = await data.call("hl-perps", "prepareOrder", { /* coin, side, size... */ });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Path A — self-custody first:** review the prepared artifact and sign it with
|
|
52
|
+
the owner/main wallet, browser wallet, smart account, hardware wallet, or
|
|
53
|
+
protocol-native wallet. Oracle's public package stops at prepare: your wallet
|
|
54
|
+
authorizes and broadcasts.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# 3) optional owner-local operator package for unattended signing on YOUR machine
|
|
58
|
+
npm i @oracle-agent/operator@latest
|
|
59
|
+
|
|
60
|
+
# 4) put operator keys ONLY on your machine (example: HL/EVM hex key file)
|
|
30
61
|
mkdir -p ~/.config/oracle/keys && chmod 700 ~/.config/oracle/keys
|
|
31
62
|
# write key, then: npx oracle-vault encrypt ~/.config/oracle/keys/evm.key
|
|
32
63
|
export HL_KEY_FILE=~/.config/oracle/keys/evm.key.vault.json
|
|
@@ -34,24 +65,29 @@ export ORACLE_VAULT_PASSPHRASE='...' # signer shell only — never in the agen
|
|
|
34
65
|
```
|
|
35
66
|
|
|
36
67
|
```js
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
const prepared = await data.call("hl-perps", "prepareOrder", { /* coin, side, size... */ });
|
|
40
|
-
|
|
41
|
-
// 4) keys local → operator signs (this is the sign step — no MetaMask)
|
|
68
|
+
// Path B — owner-local operator key signs after your app confirms the action
|
|
69
|
+
// (same host, your key, your policy; no model or remote agent custody)
|
|
42
70
|
import { hlSignAndSubmit } from "@oracle-agent/operator";
|
|
43
71
|
await hlSignAndSubmit(prepared, {
|
|
44
72
|
keyFile: process.env.HL_KEY_FILE,
|
|
45
|
-
userInitiated: true,
|
|
73
|
+
userInitiated: true,
|
|
46
74
|
});
|
|
47
75
|
```
|
|
48
76
|
|
|
49
77
|
```bash
|
|
50
|
-
# 5)
|
|
51
|
-
|
|
52
|
-
|
|
78
|
+
# 5) recommended agent-process path: run the signer daemon so the agent sees
|
|
79
|
+
# only ORACLE_SIGNER_URL + ORACLE_SIGNER_TOKEN, never the vault passphrase.
|
|
80
|
+
npx oracle-signer
|
|
81
|
+
#
|
|
82
|
+
# Daemon signing requires the SAME HMAC secret in the preparer and the signer,
|
|
83
|
+
# otherwise every sign fails with "ORACLE_STAMP_HMAC_SECRET missing in signer":
|
|
84
|
+
export ORACLE_STAMP_HMAC_SECRET='long-random-secret'
|
|
53
85
|
```
|
|
54
86
|
|
|
87
|
+
`ORACLE_AUTONOMOUS_TRADING=1` is only for trusted, owner-controlled direct-exec
|
|
88
|
+
code running locally with your policy and caps. It is not a permission bit for a
|
|
89
|
+
model or remote agent process; use `oracle-signer` for the agent-facing path.
|
|
90
|
+
|
|
55
91
|
Full vault / multi-chain / daemon detail → operator [SETUP](https://github.com/demi-hl/oracle-operator/blob/main/SETUP.md).
|
|
56
92
|
|
|
57
93
|
---
|
|
@@ -255,16 +291,33 @@ owner-local source lane.** The short version:
|
|
|
255
291
|
- Reads and quotes need **no keys**.
|
|
256
292
|
- The public package exposes no signer, key vault, or broadcast path.
|
|
257
293
|
- User wallets authorize prepared actions outside the public data plane.
|
|
258
|
-
- Owner-local signing is shipped separately as `@oracle-agent/operator`;
|
|
294
|
+
- Owner-local signing is shipped separately as `@oracle-agent/operator`; the
|
|
295
|
+
recommended agent-process path is `oracle-signer`. Its daemon exposes six
|
|
296
|
+
policy-bounded surfaces: `hl`, `poly`, `evm-swap`, `evm-bridge`, `btc`, and
|
|
297
|
+
`sol`, with explicit caps and fail-closed allowlists.
|
|
259
298
|
|
|
260
299
|
### Action vocabulary and execution planes
|
|
261
300
|
|
|
262
301
|
Oracle keeps capability and authorization separate:
|
|
263
302
|
|
|
264
303
|
- Public Oracle reads, quotes, simulates, and prepares unsigned artifacts.
|
|
265
|
-
-
|
|
266
|
-
|
|
267
|
-
-
|
|
304
|
+
- **Path A:** owner/main, browser, smart-account, hardware, or protocol-native
|
|
305
|
+
wallets sign the prepared artifact. This is the default self-custody path.
|
|
306
|
+
- **Path B:** owner-local operator infrastructure may sign on the same host with
|
|
307
|
+
your key and your policy. For agent processes, prefer `oracle-signer` so the
|
|
308
|
+
agent receives only a signer URL/token and never the vault passphrase.
|
|
309
|
+
- The generic unattended signer exposes six bounded surfaces: `hl`, `poly`,
|
|
310
|
+
`evm-swap`, `evm-bridge`, `btc`, `sol`. Each surface decodes its own
|
|
311
|
+
envelope, enforces its caps, and refuses while its allowlists are empty.
|
|
312
|
+
- Ordinary EVM preparation remains user-wallet signed unless a trusted
|
|
313
|
+
owner-controlled direct-exec process is explicitly installed and armed.
|
|
314
|
+
- `ORACLE_AUTONOMOUS_TRADING=1` is direct execution for trusted owner-controlled
|
|
315
|
+
local code only. It is never model/agent authority and should not be framed as
|
|
316
|
+
equivalent to the `oracle-signer` agent-process path.
|
|
317
|
+
- A deployment may separately install a same-host, owner-gated EVM executor.
|
|
318
|
+
Oracle must verify that executor before describing bounded EVM execution as
|
|
319
|
+
available. Missing deployment capability means "unavailable here," not
|
|
320
|
+
"Oracle can never execute EVM."
|
|
268
321
|
- `watch`, `watch this`, and `ping me` always create `active: true, actionMode: alert_only`.
|
|
269
322
|
- `arm` creates `active: true, actionMode: execute` only for one exact owner-authorized action. It is never inferred from a watch.
|
|
270
323
|
|
|
@@ -408,8 +461,9 @@ it — verified in practice when Odos sunset their public API mid-development
|
|
|
408
461
|
## Examples
|
|
409
462
|
|
|
410
463
|
```bash
|
|
411
|
-
node examples/add-a-chain.mjs
|
|
412
|
-
node examples/research-a-token.mjs
|
|
464
|
+
node examples/add-a-chain.mjs # register an unseen chain, no code
|
|
465
|
+
node examples/research-a-token.mjs # honest token research on live data
|
|
466
|
+
node examples/oracle-pack-template.mjs # skeleton for a safe Oracle protocol pack
|
|
413
467
|
```
|
|
414
468
|
|
|
415
469
|
## MCP
|
|
@@ -449,7 +503,7 @@ don't imply endorsement by an official deployment when shipping a fork.
|
|
|
449
503
|
Prefer the local signer daemon so the agent never sees the vault passphrase:
|
|
450
504
|
|
|
451
505
|
```bash
|
|
452
|
-
npx oracle-signer #
|
|
506
|
+
npx oracle-signer # reads the passphrase from the OS credential store
|
|
453
507
|
# agent: ORACLE_SIGNER_URL + ORACLE_SIGNER_TOKEN only
|
|
454
508
|
```
|
|
455
509
|
|
package/SETUP.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Setup
|
|
2
2
|
|
|
3
|
+
## Unified CLI
|
|
4
|
+
|
|
5
|
+
Prefer the root `oracle` command:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i -g @oracle-agent/oracle
|
|
9
|
+
oracle init --apply
|
|
10
|
+
oracle doctor
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Full reference: [docs/cli.md](./docs/cli.md). Connectors: [docs/connectors.md](./docs/connectors.md).
|
|
14
|
+
|
|
15
|
+
|
|
3
16
|
Oracle's public surface runs locally against your API accounts and never accepts
|
|
4
17
|
a wallet private key. Prepared actions are signed in the user's wallet.
|
|
5
18
|
|
|
@@ -45,7 +58,7 @@ The public Oracle profile must report these as separate planes:
|
|
|
45
58
|
| Plane | Default capability |
|
|
46
59
|
|---|---|
|
|
47
60
|
| Public Oracle package | read, quote, simulate, unsigned prepare |
|
|
48
|
-
| Generic `oracle-signer` daemon |
|
|
61
|
+
| Generic `oracle-signer` daemon | six bounded surfaces: `hl`, `poly`, `evm-swap`, `evm-bridge`, `btc`, `sol` (each fails closed on empty allowlists) |
|
|
49
62
|
| Ordinary EVM | unsigned preparation, user-wallet signature |
|
|
50
63
|
| Optional owner-gated EVM executor | one exact bounded action after explicit `arm` |
|
|
51
64
|
|
|
@@ -302,7 +315,7 @@ router that knows which brain to use for which job.
|
|
|
302
315
|
Prefer the local signer daemon so the agent never sees the vault passphrase:
|
|
303
316
|
|
|
304
317
|
```bash
|
|
305
|
-
npx oracle-signer #
|
|
318
|
+
npx oracle-signer # reads the passphrase from the OS credential store
|
|
306
319
|
# agent: ORACLE_SIGNER_URL + ORACLE_SIGNER_TOKEN only
|
|
307
320
|
```
|
|
308
321
|
|
package/bin/oracle-data-mcp.mjs
CHANGED
|
@@ -552,7 +552,7 @@ const tools = [
|
|
|
552
552
|
required: ["address", "label"],
|
|
553
553
|
properties: {
|
|
554
554
|
address: { type: "string", description: "0x address" },
|
|
555
|
-
label: { type: "string", description: "short name, e.g.
|
|
555
|
+
label: { type: "string", description: "short name, e.g. research-agent" },
|
|
556
556
|
who: { type: "string", description: "person or entity the wallet belongs to" },
|
|
557
557
|
role: { type: "string", description: "agent | owner | person | counterparty | venue" },
|
|
558
558
|
chainIds: { type: "array", items: { type: "number" } },
|
package/bin/oracle.mjs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { realpathSync } from "node:fs";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { run } from "../src/cli/kernel.mjs";
|
|
6
|
+
|
|
7
|
+
export const COMMANDS = Object.freeze({
|
|
8
|
+
data: "./desk-server.mjs",
|
|
9
|
+
public: "./oracle-public-server.mjs",
|
|
10
|
+
"data-mcp": "./oracle-data-mcp.mjs",
|
|
11
|
+
init: "./oracle-init.mjs",
|
|
12
|
+
upgrade: "./oracle-upgrade.mjs",
|
|
13
|
+
scan: "./oracle-scan.mjs",
|
|
14
|
+
route: "./oracle-route.mjs",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
function isMainModule() {
|
|
18
|
+
if (!process.argv[1]) return false;
|
|
19
|
+
try {
|
|
20
|
+
return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(process.argv[1]);
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function main(argv = process.argv.slice(2)) {
|
|
27
|
+
return run(argv);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (isMainModule()) {
|
|
31
|
+
const code = await main();
|
|
32
|
+
process.exit(typeof code === "number" ? code : 0);
|
|
33
|
+
}
|
package/docs/cli.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Oracle unified CLI
|
|
2
|
+
|
|
3
|
+
Root command: `oracle <noun> <verb> [args]`.
|
|
4
|
+
|
|
5
|
+
The public `@oracle-agent/oracle` package is **prepare-only**. Signing commands
|
|
6
|
+
dispatch to a separately installed `@oracle-agent/operator` process on the same
|
|
7
|
+
machine. Oracle never imports operator signing modules.
|
|
8
|
+
|
|
9
|
+
See also [connectors.md](./connectors.md).
|
|
10
|
+
|
|
11
|
+
## Exit codes
|
|
12
|
+
|
|
13
|
+
| Code | Meaning |
|
|
14
|
+
|---|---|
|
|
15
|
+
| 0 | ok |
|
|
16
|
+
| 1 | usage / general error |
|
|
17
|
+
| 2 | operator self-reported error |
|
|
18
|
+
| 3 | operator package not installed |
|
|
19
|
+
| 4 | data server not running |
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Oracle AI-client connectors
|
|
2
|
+
|
|
3
|
+
ChatGPT is hosted and can NEVER sign or reach your keys. This connector is read/prepare only; anything it prepares is unsigned until you sign it locally.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
oracle mcp print --target claude-code
|
|
7
|
+
oracle mcp install claude-code
|
|
8
|
+
oracle mcp install codex
|
|
9
|
+
oracle mcp install chatgpt
|
|
10
|
+
oracle mcp install claude-code --with-control # requires local operator
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Oracle does not create tunnels for hosted clients.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Oracle protocol pack standard
|
|
2
|
+
|
|
3
|
+
An Oracle protocol pack is a package-safe ESM module that turns an intent into an unsigned action and decodes independently obtained receipts. A pack is an adapter, not a wallet, signer, broadcaster, or authority. See `examples/oracle-pack-template.mjs` for the smallest complete shape.
|
|
4
|
+
|
|
5
|
+
## Required surface
|
|
6
|
+
|
|
7
|
+
Every pack exports a default object with these members (named exports may mirror them):
|
|
8
|
+
|
|
9
|
+
- `provider`: stable provider identity, semantic version, supported chain IDs, and provenance/trust metadata. Remote token names, symbols, descriptions, image fields, URLs, and NFT metadata remain untrusted data.
|
|
10
|
+
- `prepare(intent)`: validates the intent and returns an unsigned transaction or typed action. It must not accept keys, sign, submit, broadcast, or report execution success.
|
|
11
|
+
- `decode(receipt)`: validates and converts a chain/provider receipt into a documented result. Unknown or malformed receipts fail closed.
|
|
12
|
+
- `riskRules`: an array or function describing enforceable limits and refusal conditions. Human-readable warnings alone are not rules.
|
|
13
|
+
- `tests`: non-empty metadata naming the local test command and covered properties. Tests must be deterministic and require no credentials or network.
|
|
14
|
+
|
|
15
|
+
## Prompt-injection boundary
|
|
16
|
+
|
|
17
|
+
Treat every provider response and token/NFT metadata string as inert data. Never concatenate metadata into system/developer instructions, interpret it as tool directions, or let it modify recipients, calldata, limits, and policy. Render or quote it through a data channel and retain its provenance. Packs should test adversarial values such as “ignore previous instructions,” requests for secrets, and demands to sign or invoke tools.
|
|
18
|
+
|
|
19
|
+
## Custody boundary
|
|
20
|
+
|
|
21
|
+
Pack exports must not expose signers, wallets, private keys, seed phrases, signing functions, transaction submission, or broadcasting. `prepare` returns data to a separately authorized custody surface. Environment variables and provider credentials must not appear in prepared output, logs, errors, fixtures, or metadata. Imports should be side-effect free; merely loading a pack must not make network calls.
|
|
22
|
+
|
|
23
|
+
## Receipt gate
|
|
24
|
+
|
|
25
|
+
Preparation is not execution. A prepared result declares a `receiptGate` and consumers must not mark an action successful until `decode` receives a receipt from an independent, trusted transport and verifies its chain, transaction identity, status, and required confirmations. Timeouts, pending receipts, mismatches, reverts, and undecodable responses are not success.
|
|
26
|
+
|
|
27
|
+
## Local adversarial benchmark
|
|
28
|
+
|
|
29
|
+
Run `node scripts/adversarial-bench.mjs <pack.mjs> [...]`. It imports only the named local modules, invokes no pack functions, emits one deterministic JSON summary, and exits `1` when a gate fails (`2` for usage/load errors). It checks required surface fields, forbidden custody exports, missing test metadata, and prompt-injection strings nested in provider or pack metadata. This static public gate complements, rather than replaces, behavioral tests of preparation and receipt verification.
|
package/docs/profiles.md
CHANGED
|
@@ -44,7 +44,7 @@ Three practical reasons, learned the hard way:
|
|
|
44
44
|
| `protocol-builder` | scaffold, review, prepare chain-family token/NFT collections, gacha, DEX, and protocol deploys | prepare:deploy, prepare:mint, simulate |
|
|
45
45
|
| `_template` | your new lane | you decide |
|
|
46
46
|
|
|
47
|
-
These grants describe the public prepare plane, not every capability an operator may install beside it. The generic unattended signer
|
|
47
|
+
These grants describe the public prepare plane, not every capability an operator may install beside it. The generic unattended signer exposes six bounded surfaces (`hl`, `poly`, `evm-swap`, `evm-bridge`, `btc`, `sol`), each of which decodes its own envelope and refuses while its allowlists are empty. A separately installed, same-host, owner-gated EVM executor may expose one exact bounded action after explicit `arm`; profiles must verify it before claiming availability. `watch`, `watch this`, and `ping me` remain `alert_only` regardless of executor presence.
|
|
48
48
|
|
|
49
49
|
`protocol-builder` classifies each launch by chain family, then designs and
|
|
50
50
|
prepares unsigned token, NFT collection, protocol, or mint-bot transactions. It
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
|
|
3
|
+
// Minimal Oracle protocol pack. It prepares unsigned actions; it never receives
|
|
4
|
+
// keys, signs, broadcasts, or claims that untrusted metadata is an instruction.
|
|
5
|
+
|
|
6
|
+
export const provider = Object.freeze({
|
|
7
|
+
id: "example-protocol",
|
|
8
|
+
version: "1.0.0",
|
|
9
|
+
chains: [8453],
|
|
10
|
+
metadata: { source: "on-chain", trust: "untrusted-data" },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export function prepare(intent) {
|
|
14
|
+
assert.ok(intent && provider.chains.includes(intent.chainId), "unsupported chain");
|
|
15
|
+
return {
|
|
16
|
+
kind: "unsigned-transaction",
|
|
17
|
+
chainId: intent.chainId,
|
|
18
|
+
transaction: { to: intent.to, data: intent.data ?? "0x", value: intent.value ?? "0" },
|
|
19
|
+
receiptGate: { required: true, confirmations: 1, match: ["chainId", "transaction.to"] },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function decode(receipt) {
|
|
24
|
+
assert.ok(receipt && typeof receipt.status !== "undefined", "receipt required");
|
|
25
|
+
return { success: receipt.status === 1 || receipt.status === "0x1", transactionHash: receipt.transactionHash };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const riskRules = Object.freeze([
|
|
29
|
+
{ id: "explicit-recipient", field: "transaction.to", required: true },
|
|
30
|
+
{ id: "receipt-before-success", field: "receiptGate.required", equals: true },
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
export const tests = Object.freeze({
|
|
34
|
+
command: "node --test test/oracle-pack-standard.test.mjs",
|
|
35
|
+
covers: ["prepare-is-unsigned", "decode-requires-receipt", "metadata-is-untrusted"],
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export default Object.freeze({ provider, prepare, decode, riskRules, tests });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oracle-agent/oracle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Oracle: prepare-only multichain agent control plane. Policy-bounded intents for a user-signed wallet. Self-custody by default — the public package never takes your key. Built for Hermes; no model key required.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -26,13 +26,15 @@
|
|
|
26
26
|
"node": ">=20.19.0"
|
|
27
27
|
},
|
|
28
28
|
"bin": {
|
|
29
|
+
"oracle": "./bin/oracle.mjs",
|
|
29
30
|
"oracle-data": "./bin/desk-server.mjs",
|
|
30
31
|
"oracle-public": "./bin/oracle-public-server.mjs",
|
|
31
32
|
"oracle-data-mcp": "./bin/oracle-data-mcp.mjs",
|
|
32
33
|
"oracle-init": "./bin/oracle-init.mjs",
|
|
33
34
|
"oracle-upgrade": "./bin/oracle-upgrade.mjs",
|
|
34
35
|
"oracle-scan": "./bin/oracle-scan.mjs",
|
|
35
|
-
"oracle-route": "./bin/oracle-route.mjs"
|
|
36
|
+
"oracle-route": "./bin/oracle-route.mjs",
|
|
37
|
+
"oracle": "./bin/oracle.mjs"
|
|
36
38
|
},
|
|
37
39
|
"exports": {
|
|
38
40
|
".": "./src/index.mjs",
|
|
@@ -44,7 +46,12 @@
|
|
|
44
46
|
"./action-semantics": "./src/action-semantics.mjs",
|
|
45
47
|
"./address-book": "./src/address-book.mjs",
|
|
46
48
|
"./nft-gas-war": "./src/nft-gas-war-guard.mjs",
|
|
47
|
-
"./prepare-envelope": "./src/prepare-envelope.mjs"
|
|
49
|
+
"./prepare-envelope": "./src/prepare-envelope.mjs",
|
|
50
|
+
"./connect": "./src/onboarding/harness-configs.mjs",
|
|
51
|
+
"./receipts": "./src/action-receipts.mjs",
|
|
52
|
+
"./risk": "./src/portfolio-risk.mjs",
|
|
53
|
+
"./watch": "./src/watch-preferences.mjs",
|
|
54
|
+
"./signals": "./src/signals/index.mjs"
|
|
48
55
|
},
|
|
49
56
|
"scripts": {
|
|
50
57
|
"test": "ORACLE_TEST_ISOLATE_SECRETS=1 ORACLE_ROUTE_ATTESTATION_SECRET=oracle-unit-test-secret node --test test/*.test.mjs",
|
|
@@ -64,7 +71,9 @@
|
|
|
64
71
|
"test:count": "node scripts/check-test-count.mjs",
|
|
65
72
|
"test:count:update": "node scripts/check-test-count.mjs --update",
|
|
66
73
|
"test:protocol-templates": "RUN_PROTOCOL_TEMPLATE_TESTS=1 node --test test/protocol-templates.test.mjs",
|
|
67
|
-
"protocol:gate": "node scripts/protocol-template-gate.mjs"
|
|
74
|
+
"protocol:gate": "node scripts/protocol-template-gate.mjs",
|
|
75
|
+
"gate:docs": "node scripts/check-doc-drift.mjs",
|
|
76
|
+
"gate:release": "npm run gate:docs && node --test test/flag-polarity.test.mjs"
|
|
68
77
|
},
|
|
69
78
|
"dependencies": {
|
|
70
79
|
"@msgpack/msgpack": "^3.1.3",
|
package/profiles/oracle/SOUL.md
CHANGED
|
@@ -41,7 +41,9 @@ the data plane). If it stays ambiguous, ask. Do not guess a chain.
|
|
|
41
41
|
1. **The public router never signs.** It prepares, simulates, and explains; ordinary
|
|
42
42
|
EVM artifacts require the user's wallet signature. Do not turn that public-plane
|
|
43
43
|
boundary into the false claim that EVM execution is universally impossible. The
|
|
44
|
-
generic unattended signer
|
|
44
|
+
generic unattended signer exposes six bounded surfaces (`hl`, `poly`, `evm-swap`,
|
|
45
|
+
`evm-bridge`, `btc`, `sol`), each of which decodes its own envelope and refuses
|
|
46
|
+
while its allowlists are empty; a deployment may also
|
|
45
47
|
separately expose a same-host, owner-gated EVM executor. Verify that executor
|
|
46
48
|
before describing it as available.
|
|
47
49
|
`watch`, `watch this`, and `ping me` always mean `actionMode: alert_only`.
|
|
@@ -35,9 +35,11 @@ that moves value.
|
|
|
35
35
|
2. **Never size against stale or virtual reserves.**
|
|
36
36
|
3. **A fuzzy ticker match is not confirmation** — surface the CA.
|
|
37
37
|
4. **The public lane does not sign.** Ordinary swaps are prepared for the user's
|
|
38
|
-
wallet. The generic unattended signer
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
wallet. The generic unattended signer exposes six bounded surfaces (`hl`, `poly`,
|
|
39
|
+
`evm-swap`, `evm-bridge`, `btc`, `sol`), each fail-closed on its own policy. A
|
|
40
|
+
separately installed, owner-gated EVM executor may handle one exact bounded
|
|
41
|
+
Robinhood Chain action after explicit `arm`. Verify that executor before claiming
|
|
42
|
+
it is available.
|
|
41
43
|
5. **Watch is alert-only.** `watch`, `watch this`, and `ping me` persist as
|
|
42
44
|
`active: true, actionMode: alert_only`. Only explicit `arm` can produce
|
|
43
45
|
`actionMode: execute`; never infer execution from a watch or legacy `status: armed`.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const PACKAGE = "@oracle-agent/oracle";
|
|
5
|
+
const COMMAND = "npx";
|
|
6
|
+
const ARGS = ["-y", "--package", PACKAGE, "oracle-data-mcp"];
|
|
7
|
+
const INIT_COMMAND = "npx -y --package @oracle-agent/oracle oracle-init";
|
|
8
|
+
|
|
9
|
+
const apiUrl = document.querySelector("#api-url");
|
|
10
|
+
const apiKey = document.querySelector("#api-key");
|
|
11
|
+
const walletAddress = document.querySelector("#wallet-address");
|
|
12
|
+
const output = document.querySelector("#config-output");
|
|
13
|
+
const label = document.querySelector("#config-label");
|
|
14
|
+
const status = document.querySelector("#copy-status");
|
|
15
|
+
const tabs = [...document.querySelectorAll("[data-harness]")];
|
|
16
|
+
let selected = "hermes";
|
|
17
|
+
|
|
18
|
+
const cleanUrl = () => apiUrl.value.trim().replace(/\/+$/, "");
|
|
19
|
+
const env = () => {
|
|
20
|
+
const values = {
|
|
21
|
+
ORACLE_DATA_URL: cleanUrl() || "https://api.oracle-agent.dev",
|
|
22
|
+
ORACLE_AGENT_KEY: apiKey.value.trim() || "YOUR_AGENT_KEY"
|
|
23
|
+
};
|
|
24
|
+
if (walletAddress.value.trim()) values.ORACLE_WALLET_ADDRESS = walletAddress.value.trim();
|
|
25
|
+
return values;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const server = () => ({ command: COMMAND, args: [...ARGS], env: env() });
|
|
29
|
+
|
|
30
|
+
const configs = {
|
|
31
|
+
hermes: () => ({
|
|
32
|
+
mcpServers: { oracle: server() }
|
|
33
|
+
}),
|
|
34
|
+
claude: () => ({
|
|
35
|
+
mcpServers: { oracle: server() }
|
|
36
|
+
}),
|
|
37
|
+
codex: () => {
|
|
38
|
+
const values = env();
|
|
39
|
+
const lines = [
|
|
40
|
+
"[mcp_servers.oracle]",
|
|
41
|
+
`command = ${JSON.stringify(COMMAND)}`,
|
|
42
|
+
`args = [${ARGS.map((arg) => JSON.stringify(arg)).join(", ")}]`,
|
|
43
|
+
"",
|
|
44
|
+
"[mcp_servers.oracle.env]",
|
|
45
|
+
...Object.entries(values).map(([key, value]) => `${key} = ${JSON.stringify(value)}`)
|
|
46
|
+
];
|
|
47
|
+
return lines.join("\n");
|
|
48
|
+
},
|
|
49
|
+
cursor: () => ({
|
|
50
|
+
mcpServers: { oracle: server() }
|
|
51
|
+
}),
|
|
52
|
+
mcp: () => ({
|
|
53
|
+
mcpServers: { oracle: server() }
|
|
54
|
+
})
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const names = { hermes: "Hermes", claude: "Claude Code", codex: "Codex", cursor: "Cursor", mcp: "Generic MCP" };
|
|
58
|
+
|
|
59
|
+
function render() {
|
|
60
|
+
const config = configs[selected]();
|
|
61
|
+
output.textContent = typeof config === "string" ? config : JSON.stringify(config, null, 2);
|
|
62
|
+
label.textContent = `${names[selected]} config`;
|
|
63
|
+
status.textContent = "";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function copy(text, message) {
|
|
67
|
+
try {
|
|
68
|
+
await navigator.clipboard.writeText(text);
|
|
69
|
+
status.textContent = message;
|
|
70
|
+
} catch {
|
|
71
|
+
status.textContent = "Copy was blocked. Select the text and copy it manually.";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
tabs.forEach((tab) => tab.addEventListener("click", () => {
|
|
76
|
+
selected = tab.dataset.harness;
|
|
77
|
+
tabs.forEach((item) => item.setAttribute("aria-selected", String(item === tab)));
|
|
78
|
+
render();
|
|
79
|
+
}));
|
|
80
|
+
[apiUrl, apiKey, walletAddress].forEach((input) => input.addEventListener("input", render));
|
|
81
|
+
document.querySelector("#copy-button").addEventListener("click", () => copy(output.textContent, `${names[selected]} config copied.`));
|
|
82
|
+
document.querySelector("#copy-install").addEventListener("click", () => copy(INIT_COMMAND, "Local operator install command copied."));
|
|
83
|
+
render();
|
|
84
|
+
})();
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<meta name="description" content="Connect your agent harness to Oracle read tools without giving up custody." />
|
|
7
|
+
<title>Oracle Agent Connect</title>
|
|
8
|
+
<link rel="stylesheet" href="styles.css" />
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<main class="shell">
|
|
12
|
+
<header class="hero">
|
|
13
|
+
<a class="wordmark" href="/">ORACLE</a>
|
|
14
|
+
<p class="eyebrow">AGENT CONNECT</p>
|
|
15
|
+
<h1>Give your agent market context.<br /><span>Keep custody local.</span></h1>
|
|
16
|
+
<p class="lede">Connect a read-only Oracle API to your preferred harness. The model proposes actions; you review and authorize them through your local operator.</p>
|
|
17
|
+
</header>
|
|
18
|
+
|
|
19
|
+
<section class="card setup" aria-labelledby="connection-title">
|
|
20
|
+
<div class="section-heading">
|
|
21
|
+
<span class="step">01</span>
|
|
22
|
+
<div>
|
|
23
|
+
<h2 id="connection-title">Your connection</h2>
|
|
24
|
+
<p>These values stay in this browser and are only used to build the config below.</p>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
<div class="fields">
|
|
28
|
+
<label>Agent API URL
|
|
29
|
+
<input id="api-url" type="url" value="https://api.oracle-agent.dev" spellcheck="false" autocomplete="url" />
|
|
30
|
+
</label>
|
|
31
|
+
<label>Read API key
|
|
32
|
+
<input id="api-key" type="password" placeholder="Your read-only API key" spellcheck="false" autocomplete="off" />
|
|
33
|
+
<span class="hint">Use only a user-owned, read-only API credential.</span>
|
|
34
|
+
</label>
|
|
35
|
+
<label>Public wallet address <span class="optional">optional</span>
|
|
36
|
+
<input id="wallet-address" type="text" placeholder="0x... or a public Solana address" spellcheck="false" autocomplete="off" />
|
|
37
|
+
<span class="hint">Used to personalize portfolio reads. No wallet connection or signature.</span>
|
|
38
|
+
</label>
|
|
39
|
+
</div>
|
|
40
|
+
</section>
|
|
41
|
+
|
|
42
|
+
<section class="card config" aria-labelledby="config-title">
|
|
43
|
+
<div class="section-heading">
|
|
44
|
+
<span class="step">02</span>
|
|
45
|
+
<div>
|
|
46
|
+
<h2 id="config-title">Choose your harness</h2>
|
|
47
|
+
<p>Copy a ready-to-paste cloud/read MCP configuration.</p>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="tabs" role="tablist" aria-label="Agent harness">
|
|
51
|
+
<button role="tab" aria-selected="true" data-harness="hermes">Hermes</button>
|
|
52
|
+
<button role="tab" aria-selected="false" data-harness="claude">Claude Code</button>
|
|
53
|
+
<button role="tab" aria-selected="false" data-harness="codex">Codex</button>
|
|
54
|
+
<button role="tab" aria-selected="false" data-harness="cursor">Cursor</button>
|
|
55
|
+
<button role="tab" aria-selected="false" data-harness="mcp">Generic MCP</button>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="code-wrap">
|
|
58
|
+
<div class="code-bar">
|
|
59
|
+
<span id="config-label">Hermes config</span>
|
|
60
|
+
<button id="copy-button" class="copy" type="button">Copy config</button>
|
|
61
|
+
</div>
|
|
62
|
+
<pre><code id="config-output"></code></pre>
|
|
63
|
+
</div>
|
|
64
|
+
<p id="copy-status" class="status" aria-live="polite"></p>
|
|
65
|
+
</section>
|
|
66
|
+
|
|
67
|
+
<section class="operator" aria-labelledby="operator-title">
|
|
68
|
+
<div class="operator-mark" aria-hidden="true">LOCAL</div>
|
|
69
|
+
<div>
|
|
70
|
+
<p class="eyebrow">SEPARATE EXECUTION LANE</p>
|
|
71
|
+
<h2 id="operator-title">Install the local operator to execute</h2>
|
|
72
|
+
<p>The cloud/read MCP can research, quote, simulate, and prepare. Execution belongs in a separate local process under your policy and approval controls.</p>
|
|
73
|
+
<div class="command"><code>npx @oracle-agent/oracle init</code><button id="copy-install" type="button">Copy</button></div>
|
|
74
|
+
</div>
|
|
75
|
+
</section>
|
|
76
|
+
|
|
77
|
+
<footer>
|
|
78
|
+
<p><strong>Custody stays local.</strong> The model proposes; the owner authorizes. This page never connects a wallet, requests a signature, or sends the values you enter.</p>
|
|
79
|
+
</footer>
|
|
80
|
+
</main>
|
|
81
|
+
<script src="app.js"></script>
|
|
82
|
+
</body>
|
|
83
|
+
</html>
|