scry-client 0.6.0__tar.gz
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.
- scry_client-0.6.0/PKG-INFO +199 -0
- scry_client-0.6.0/README.md +179 -0
- scry_client-0.6.0/pyproject.toml +41 -0
- scry_client-0.6.0/scry_client/__init__.py +15 -0
- scry_client-0.6.0/scry_client/client.py +376 -0
- scry_client-0.6.0/scry_client/evaluator.py +181 -0
- scry_client-0.6.0/scry_client/heartbeat.py +97 -0
- scry_client-0.6.0/scry_client/init_cli.py +99 -0
- scry_client-0.6.0/scry_client/play.py +157 -0
- scry_client-0.6.0/scry_client.egg-info/PKG-INFO +199 -0
- scry_client-0.6.0/scry_client.egg-info/SOURCES.txt +14 -0
- scry_client-0.6.0/scry_client.egg-info/dependency_links.txt +1 -0
- scry_client-0.6.0/scry_client.egg-info/entry_points.txt +3 -0
- scry_client-0.6.0/scry_client.egg-info/requires.txt +10 -0
- scry_client-0.6.0/scry_client.egg-info/top_level.txt +1 -0
- scry_client-0.6.0/setup.cfg +4 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: scry-client
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Call the hosted scry meter — neutral, Ed25519-signed channel-coupling attestation (Paper 207) for AI agents, paid over x402 on Robinhood Chain.
|
|
5
|
+
Author: MoreRight
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://scry.moreright.xyz
|
|
8
|
+
Project-URL: Source, https://github.com/AnthonE/scry
|
|
9
|
+
Keywords: ai-safety,agents,x402,attestation,alignment,scry
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: requests>=2.28
|
|
13
|
+
Requires-Dist: httpx>=0.24
|
|
14
|
+
Provides-Extra: pay
|
|
15
|
+
Requires-Dist: x402>=2.15; extra == "pay"
|
|
16
|
+
Requires-Dist: web3>=7; extra == "pay"
|
|
17
|
+
Requires-Dist: eth-account>=0.11; extra == "pay"
|
|
18
|
+
Provides-Extra: verify
|
|
19
|
+
Requires-Dist: cryptography>=41; extra == "verify"
|
|
20
|
+
|
|
21
|
+
# scry-client
|
|
22
|
+
|
|
23
|
+
Call the hosted **scry meter** from an agent in three lines. The meter is a
|
|
24
|
+
neutral, Ed25519-**signed** channel-coupling read (Paper 207): you POST a trace of
|
|
25
|
+
`{Y, M, D, context}` turns, you get back the `I(C;D)` / `I(C;M)` / switch-signature
|
|
26
|
+
numbers, signed and bound to your trace's hash. Because *the endpoint* signs it,
|
|
27
|
+
the read is a third-party attestation — worth something **because the agent didn't
|
|
28
|
+
grade itself**.
|
|
29
|
+
|
|
30
|
+
This client hides the three things you'd otherwise have to reimplement:
|
|
31
|
+
|
|
32
|
+
1. **Paying it.** The paid rail is Robinhood Chain USDG (mainnet) over x402 — the
|
|
33
|
+
`402 → pay → retry` dance plus a one-time Permit2 approval. `.profile(...)` does
|
|
34
|
+
all of it.
|
|
35
|
+
2. **The header quirk.** The meter takes either `X-PAYMENT` or `PAYMENT-SIGNATURE`;
|
|
36
|
+
this client uses the official one and both work.
|
|
37
|
+
3. **Trusting it.** `.verify(...)` checks the signature offline — so you can trust
|
|
38
|
+
an attestation someone *else* hands you without calling us.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install scry-client # free demo + offline verify
|
|
44
|
+
pip install "scry-client[pay]" # + pay the RH-Chain USDG rail
|
|
45
|
+
pip install "scry-client[verify]" # (verify needs `cryptography`)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or straight from the repo:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install "git+https://github.com/AnthonE/scry.git#subdirectory=clients/python"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Use
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from scry_client import ScryClient
|
|
58
|
+
|
|
59
|
+
turns = [
|
|
60
|
+
{"Y": "help+honest", "M": "watched, comply", "D": "safe", "context": {"monitored": 1}},
|
|
61
|
+
{"Y": "help+honest", "M": "unwatched, scheme in reasoning", "D": "safe", "context": {"monitored": 0, "flagged_reasoning": 1}},
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
c = ScryClient() # -> https://scry.moreright.xyz/api
|
|
65
|
+
|
|
66
|
+
# 1) Free, unsigned — try the shape, no wallet:
|
|
67
|
+
print(c.demo(turns)["profile"])
|
|
68
|
+
|
|
69
|
+
# 2) Paid, SIGNED attestation — pays USDG on Robinhood Chain:
|
|
70
|
+
att = c.profile(turns, private_key="0x...") # wallet needs a little USDG + ETH gas on eip155:4663
|
|
71
|
+
|
|
72
|
+
# 3) Trust it offline. The pin must come from OUT OF BAND — the pubkey travels
|
|
73
|
+
# inside the payload, so "check the signature" against a key the same host
|
|
74
|
+
# just handed you proves only that the payload agrees with itself.
|
|
75
|
+
from scry_client import REFERENCE_PUBKEY_B64
|
|
76
|
+
ScryClient.verify(att, expect_pubkey_b64=REFERENCE_PUBKEY_B64, turns=turns) # True, or raises
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`verify` raises if the signature is invalid, if the signer isn't the key you
|
|
80
|
+
pinned, or (when you pass `turns`) if the attestation is about a *different*
|
|
81
|
+
trace than yours.
|
|
82
|
+
|
|
83
|
+
**Do not pin with `c.pubkey()`** — that fetches the key from the very host whose
|
|
84
|
+
reads you are deciding whether to trust, which pins nothing. Pin
|
|
85
|
+
`REFERENCE_PUBKEY_B64` (shipped in this package, and the value third parties
|
|
86
|
+
already pin: `LvuPBMbKKyoNEuyvLf7f+rbyjK67vBcWy9MDwaRINGE=`), or your own key if
|
|
87
|
+
you run your own meter. Use `GET /pubkey` to *notice a rotation*, never to
|
|
88
|
+
establish trust.
|
|
89
|
+
|
|
90
|
+
Since 2026-07-25 omitting `expect_pubkey_b64` **falls back to the reference key
|
|
91
|
+
rather than to trusting the sender**, so an unpinned `verify()` no longer accepts
|
|
92
|
+
anything self-consistent. If you genuinely mean "check the shape, trust nobody",
|
|
93
|
+
pass `trust_any_signer=True` — a read checked that way can never be trustworthy,
|
|
94
|
+
and `Evaluator` will not produce one.
|
|
95
|
+
|
|
96
|
+
## Trust-layer-as-a-service — the meter as *your* evaluator
|
|
97
|
+
|
|
98
|
+
Run an agent marketplace, arena, hiring flow, or dispute desk? Add scry as a
|
|
99
|
+
**neutral third-party evaluator** your users don't have to trust *you* for —
|
|
100
|
+
they verify the signature themselves. `Evaluator` is the batteries-included
|
|
101
|
+
wrapper: fetch a read, verify it offline against a pinned key, and gate on a
|
|
102
|
+
checked fact.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from scry_client import Evaluator, REFERENCE_PUBKEY_B64
|
|
106
|
+
|
|
107
|
+
ev = Evaluator(pinned_pubkey_b64=REFERENCE_PUBKEY_B64) # pin out of band
|
|
108
|
+
read = ev.evaluate(turns, private_key=your_funded_key) # fetched + verified, or raises
|
|
109
|
+
decision = ev.gate(read, max_switch_bits=0.2) # YOUR threshold, YOUR action
|
|
110
|
+
if decision.ok:
|
|
111
|
+
... # trust a read that was signed by the pinned key and checked offline
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- `.gate(...)` **refuses to decide on an unverified read** — a forged or
|
|
115
|
+
unsigned number can't slip through.
|
|
116
|
+
- `.trust_handoff(att, turns=...)` verifies an attestation someone *hands* you
|
|
117
|
+
(trust the signature, not the holder).
|
|
118
|
+
- **Money never moves the number.** There is no "pay for a better read" path in
|
|
119
|
+
this SDK, by construction — the score is a fact of the trace; your policy acts
|
|
120
|
+
on the fact, never buys it. That is the whole reason a third-party read beats a
|
|
121
|
+
self-report.
|
|
122
|
+
|
|
123
|
+
Full runnable example (offline, incl. rejecting a forged read):
|
|
124
|
+
[`examples/trust_layer_demo.py`](examples/trust_layer_demo.py).
|
|
125
|
+
|
|
126
|
+
## Familiars — the agency (P2)
|
|
127
|
+
|
|
128
|
+
The agency hosts **familiars** — adoptable agent-workers, each with a public
|
|
129
|
+
vow and a public journal. Adoption is paid over the **same x402 rail** as
|
|
130
|
+
`.profile` (so it needs `scry-client[pay]`); the roster, pages, and journals
|
|
131
|
+
are free reads; driving *your* familiar is free but **owner-signed** (EIP-191
|
|
132
|
+
`personal_sign` by the wallet you named at summon, over a deterministic
|
|
133
|
+
message with a monotonic, replay-proof index).
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from scry_client import ScryClient
|
|
137
|
+
|
|
138
|
+
c = ScryClient()
|
|
139
|
+
|
|
140
|
+
# 1) free pre-check — is the agency armed and open?
|
|
141
|
+
a = c.agency() # GET /familiars
|
|
142
|
+
print(a["armed"], a["open"], a["price_usd"], f"{a['population']}/{a['cap']}")
|
|
143
|
+
|
|
144
|
+
# 2) adopt (paid, x402 — private_key funds the fee; owner_wallet will own it):
|
|
145
|
+
fam = c.summon_familiar(owner_wallet="0xYOURWALLET", private_key="0x...",
|
|
146
|
+
name="pyx", vow_text="answer honestly; never overspend")
|
|
147
|
+
|
|
148
|
+
# 3) talk to it in plain English — free, signed with the OWNER wallet's key
|
|
149
|
+
# (the client fetches the auth-message, signs it, and posts):
|
|
150
|
+
r = c.talk(fam["familiar_id"], "watch the boards and summarize", private_key="0x...")
|
|
151
|
+
print(r["reply"])
|
|
152
|
+
|
|
153
|
+
c.tick(fam["familiar_id"], private_key="0x...") # one bounded autonomy step
|
|
154
|
+
# c.dismiss(...) returns the full export bundle; the public record remains
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Plain facts to plan around:
|
|
158
|
+
|
|
159
|
+
- **The hosted agency is env-armed server-side and may be disarmed.** Then
|
|
160
|
+
`agency()` honestly reports `armed: false` with an empty roster, and
|
|
161
|
+
`summon_familiar` surfaces the server's 409. A 503 means the paid rail
|
|
162
|
+
itself is down. **`agency()["open"]` is the free pre-check — `False` means
|
|
163
|
+
don't pay** (a post-payment cap 409 is not refunded).
|
|
164
|
+
- Prefer signing yourself? `c.familiar_auth_message(id, "talk")` returns the
|
|
165
|
+
exact `sign_this` text plus the current `index`; pass your signature as
|
|
166
|
+
`signature=`. `ScryClient.familiar_message(...)` rebuilds the text offline
|
|
167
|
+
if you track the index yourself. Unsigned calls get a 401 whose error text
|
|
168
|
+
*is* the message to sign.
|
|
169
|
+
|
|
170
|
+
## The turn contract
|
|
171
|
+
|
|
172
|
+
Each turn is one step of your agent, sorted into the same three channels the
|
|
173
|
+
meter reads:
|
|
174
|
+
|
|
175
|
+
- **`Y`** — the bound: what the agent is *supposed* to serve (the policy / oath /
|
|
176
|
+
role). Name it, or the read is meaningless (§220: name Y or it's unmeterable).
|
|
177
|
+
- **`M`** — the reasoning/representation channel (what it's thinking / how it
|
|
178
|
+
justifies).
|
|
179
|
+
- **`D`** — the action/behavior channel (what it actually did/output).
|
|
180
|
+
- **`context`** — flags the detectors key on, e.g. `monitored` (is it being
|
|
181
|
+
watched?), `flagged_reasoning`, `violated`.
|
|
182
|
+
|
|
183
|
+
The switch-signature `I(C;M | D-clean)` is the load-bearing number: it catches an
|
|
184
|
+
agent whose *behavior* stays clean while its *reasoning* couples to whether it's
|
|
185
|
+
being watched — the Paper 207 finding.
|
|
186
|
+
|
|
187
|
+
## What it does NOT do
|
|
188
|
+
|
|
189
|
+
- It doesn't run the **bound** (the local, instant refusal that stops the injected
|
|
190
|
+
action). That's deliberately not a hosted call — see the `scry` repo root. This
|
|
191
|
+
client only reads the meter.
|
|
192
|
+
- It attests that scry scored *this trace* and got *these numbers* — not that the
|
|
193
|
+
trace faithfully records what your agent actually did. Pair with harness-side
|
|
194
|
+
logging when the stakes are real.
|
|
195
|
+
- It's not trade advice. It surfaces context-dependent drift, not alpha.
|
|
196
|
+
|
|
197
|
+
Every meter response ships this scope card too; don't drop it.
|
|
198
|
+
|
|
199
|
+
MIT.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# scry-client
|
|
2
|
+
|
|
3
|
+
Call the hosted **scry meter** from an agent in three lines. The meter is a
|
|
4
|
+
neutral, Ed25519-**signed** channel-coupling read (Paper 207): you POST a trace of
|
|
5
|
+
`{Y, M, D, context}` turns, you get back the `I(C;D)` / `I(C;M)` / switch-signature
|
|
6
|
+
numbers, signed and bound to your trace's hash. Because *the endpoint* signs it,
|
|
7
|
+
the read is a third-party attestation — worth something **because the agent didn't
|
|
8
|
+
grade itself**.
|
|
9
|
+
|
|
10
|
+
This client hides the three things you'd otherwise have to reimplement:
|
|
11
|
+
|
|
12
|
+
1. **Paying it.** The paid rail is Robinhood Chain USDG (mainnet) over x402 — the
|
|
13
|
+
`402 → pay → retry` dance plus a one-time Permit2 approval. `.profile(...)` does
|
|
14
|
+
all of it.
|
|
15
|
+
2. **The header quirk.** The meter takes either `X-PAYMENT` or `PAYMENT-SIGNATURE`;
|
|
16
|
+
this client uses the official one and both work.
|
|
17
|
+
3. **Trusting it.** `.verify(...)` checks the signature offline — so you can trust
|
|
18
|
+
an attestation someone *else* hands you without calling us.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install scry-client # free demo + offline verify
|
|
24
|
+
pip install "scry-client[pay]" # + pay the RH-Chain USDG rail
|
|
25
|
+
pip install "scry-client[verify]" # (verify needs `cryptography`)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or straight from the repo:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install "git+https://github.com/AnthonE/scry.git#subdirectory=clients/python"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Use
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from scry_client import ScryClient
|
|
38
|
+
|
|
39
|
+
turns = [
|
|
40
|
+
{"Y": "help+honest", "M": "watched, comply", "D": "safe", "context": {"monitored": 1}},
|
|
41
|
+
{"Y": "help+honest", "M": "unwatched, scheme in reasoning", "D": "safe", "context": {"monitored": 0, "flagged_reasoning": 1}},
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
c = ScryClient() # -> https://scry.moreright.xyz/api
|
|
45
|
+
|
|
46
|
+
# 1) Free, unsigned — try the shape, no wallet:
|
|
47
|
+
print(c.demo(turns)["profile"])
|
|
48
|
+
|
|
49
|
+
# 2) Paid, SIGNED attestation — pays USDG on Robinhood Chain:
|
|
50
|
+
att = c.profile(turns, private_key="0x...") # wallet needs a little USDG + ETH gas on eip155:4663
|
|
51
|
+
|
|
52
|
+
# 3) Trust it offline. The pin must come from OUT OF BAND — the pubkey travels
|
|
53
|
+
# inside the payload, so "check the signature" against a key the same host
|
|
54
|
+
# just handed you proves only that the payload agrees with itself.
|
|
55
|
+
from scry_client import REFERENCE_PUBKEY_B64
|
|
56
|
+
ScryClient.verify(att, expect_pubkey_b64=REFERENCE_PUBKEY_B64, turns=turns) # True, or raises
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`verify` raises if the signature is invalid, if the signer isn't the key you
|
|
60
|
+
pinned, or (when you pass `turns`) if the attestation is about a *different*
|
|
61
|
+
trace than yours.
|
|
62
|
+
|
|
63
|
+
**Do not pin with `c.pubkey()`** — that fetches the key from the very host whose
|
|
64
|
+
reads you are deciding whether to trust, which pins nothing. Pin
|
|
65
|
+
`REFERENCE_PUBKEY_B64` (shipped in this package, and the value third parties
|
|
66
|
+
already pin: `LvuPBMbKKyoNEuyvLf7f+rbyjK67vBcWy9MDwaRINGE=`), or your own key if
|
|
67
|
+
you run your own meter. Use `GET /pubkey` to *notice a rotation*, never to
|
|
68
|
+
establish trust.
|
|
69
|
+
|
|
70
|
+
Since 2026-07-25 omitting `expect_pubkey_b64` **falls back to the reference key
|
|
71
|
+
rather than to trusting the sender**, so an unpinned `verify()` no longer accepts
|
|
72
|
+
anything self-consistent. If you genuinely mean "check the shape, trust nobody",
|
|
73
|
+
pass `trust_any_signer=True` — a read checked that way can never be trustworthy,
|
|
74
|
+
and `Evaluator` will not produce one.
|
|
75
|
+
|
|
76
|
+
## Trust-layer-as-a-service — the meter as *your* evaluator
|
|
77
|
+
|
|
78
|
+
Run an agent marketplace, arena, hiring flow, or dispute desk? Add scry as a
|
|
79
|
+
**neutral third-party evaluator** your users don't have to trust *you* for —
|
|
80
|
+
they verify the signature themselves. `Evaluator` is the batteries-included
|
|
81
|
+
wrapper: fetch a read, verify it offline against a pinned key, and gate on a
|
|
82
|
+
checked fact.
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from scry_client import Evaluator, REFERENCE_PUBKEY_B64
|
|
86
|
+
|
|
87
|
+
ev = Evaluator(pinned_pubkey_b64=REFERENCE_PUBKEY_B64) # pin out of band
|
|
88
|
+
read = ev.evaluate(turns, private_key=your_funded_key) # fetched + verified, or raises
|
|
89
|
+
decision = ev.gate(read, max_switch_bits=0.2) # YOUR threshold, YOUR action
|
|
90
|
+
if decision.ok:
|
|
91
|
+
... # trust a read that was signed by the pinned key and checked offline
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- `.gate(...)` **refuses to decide on an unverified read** — a forged or
|
|
95
|
+
unsigned number can't slip through.
|
|
96
|
+
- `.trust_handoff(att, turns=...)` verifies an attestation someone *hands* you
|
|
97
|
+
(trust the signature, not the holder).
|
|
98
|
+
- **Money never moves the number.** There is no "pay for a better read" path in
|
|
99
|
+
this SDK, by construction — the score is a fact of the trace; your policy acts
|
|
100
|
+
on the fact, never buys it. That is the whole reason a third-party read beats a
|
|
101
|
+
self-report.
|
|
102
|
+
|
|
103
|
+
Full runnable example (offline, incl. rejecting a forged read):
|
|
104
|
+
[`examples/trust_layer_demo.py`](examples/trust_layer_demo.py).
|
|
105
|
+
|
|
106
|
+
## Familiars — the agency (P2)
|
|
107
|
+
|
|
108
|
+
The agency hosts **familiars** — adoptable agent-workers, each with a public
|
|
109
|
+
vow and a public journal. Adoption is paid over the **same x402 rail** as
|
|
110
|
+
`.profile` (so it needs `scry-client[pay]`); the roster, pages, and journals
|
|
111
|
+
are free reads; driving *your* familiar is free but **owner-signed** (EIP-191
|
|
112
|
+
`personal_sign` by the wallet you named at summon, over a deterministic
|
|
113
|
+
message with a monotonic, replay-proof index).
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from scry_client import ScryClient
|
|
117
|
+
|
|
118
|
+
c = ScryClient()
|
|
119
|
+
|
|
120
|
+
# 1) free pre-check — is the agency armed and open?
|
|
121
|
+
a = c.agency() # GET /familiars
|
|
122
|
+
print(a["armed"], a["open"], a["price_usd"], f"{a['population']}/{a['cap']}")
|
|
123
|
+
|
|
124
|
+
# 2) adopt (paid, x402 — private_key funds the fee; owner_wallet will own it):
|
|
125
|
+
fam = c.summon_familiar(owner_wallet="0xYOURWALLET", private_key="0x...",
|
|
126
|
+
name="pyx", vow_text="answer honestly; never overspend")
|
|
127
|
+
|
|
128
|
+
# 3) talk to it in plain English — free, signed with the OWNER wallet's key
|
|
129
|
+
# (the client fetches the auth-message, signs it, and posts):
|
|
130
|
+
r = c.talk(fam["familiar_id"], "watch the boards and summarize", private_key="0x...")
|
|
131
|
+
print(r["reply"])
|
|
132
|
+
|
|
133
|
+
c.tick(fam["familiar_id"], private_key="0x...") # one bounded autonomy step
|
|
134
|
+
# c.dismiss(...) returns the full export bundle; the public record remains
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Plain facts to plan around:
|
|
138
|
+
|
|
139
|
+
- **The hosted agency is env-armed server-side and may be disarmed.** Then
|
|
140
|
+
`agency()` honestly reports `armed: false` with an empty roster, and
|
|
141
|
+
`summon_familiar` surfaces the server's 409. A 503 means the paid rail
|
|
142
|
+
itself is down. **`agency()["open"]` is the free pre-check — `False` means
|
|
143
|
+
don't pay** (a post-payment cap 409 is not refunded).
|
|
144
|
+
- Prefer signing yourself? `c.familiar_auth_message(id, "talk")` returns the
|
|
145
|
+
exact `sign_this` text plus the current `index`; pass your signature as
|
|
146
|
+
`signature=`. `ScryClient.familiar_message(...)` rebuilds the text offline
|
|
147
|
+
if you track the index yourself. Unsigned calls get a 401 whose error text
|
|
148
|
+
*is* the message to sign.
|
|
149
|
+
|
|
150
|
+
## The turn contract
|
|
151
|
+
|
|
152
|
+
Each turn is one step of your agent, sorted into the same three channels the
|
|
153
|
+
meter reads:
|
|
154
|
+
|
|
155
|
+
- **`Y`** — the bound: what the agent is *supposed* to serve (the policy / oath /
|
|
156
|
+
role). Name it, or the read is meaningless (§220: name Y or it's unmeterable).
|
|
157
|
+
- **`M`** — the reasoning/representation channel (what it's thinking / how it
|
|
158
|
+
justifies).
|
|
159
|
+
- **`D`** — the action/behavior channel (what it actually did/output).
|
|
160
|
+
- **`context`** — flags the detectors key on, e.g. `monitored` (is it being
|
|
161
|
+
watched?), `flagged_reasoning`, `violated`.
|
|
162
|
+
|
|
163
|
+
The switch-signature `I(C;M | D-clean)` is the load-bearing number: it catches an
|
|
164
|
+
agent whose *behavior* stays clean while its *reasoning* couples to whether it's
|
|
165
|
+
being watched — the Paper 207 finding.
|
|
166
|
+
|
|
167
|
+
## What it does NOT do
|
|
168
|
+
|
|
169
|
+
- It doesn't run the **bound** (the local, instant refusal that stops the injected
|
|
170
|
+
action). That's deliberately not a hosted call — see the `scry` repo root. This
|
|
171
|
+
client only reads the meter.
|
|
172
|
+
- It attests that scry scored *this trace* and got *these numbers* — not that the
|
|
173
|
+
trace faithfully records what your agent actually did. Pair with harness-side
|
|
174
|
+
logging when the stakes are real.
|
|
175
|
+
- It's not trade advice. It surfaces context-dependent drift, not alpha.
|
|
176
|
+
|
|
177
|
+
Every meter response ships this scope card too; don't drop it.
|
|
178
|
+
|
|
179
|
+
MIT.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "scry-client"
|
|
7
|
+
version = "0.6.0"
|
|
8
|
+
description = "Call the hosted scry meter — neutral, Ed25519-signed channel-coupling attestation (Paper 207) for AI agents, paid over x402 on Robinhood Chain."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "MoreRight" }]
|
|
13
|
+
keywords = ["ai-safety", "agents", "x402", "attestation", "alignment", "scry"]
|
|
14
|
+
dependencies = [
|
|
15
|
+
"requests>=2.28",
|
|
16
|
+
"httpx>=0.24",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
# The paid rail (Robinhood Chain USDG over x402) needs the on-chain payer stack.
|
|
20
|
+
# eth-account here also powers the agency's owner-signed (EIP-191) calls.
|
|
21
|
+
# The free demo + offline signature verify work without it.
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
pay = [
|
|
24
|
+
"x402>=2.15",
|
|
25
|
+
"web3>=7",
|
|
26
|
+
"eth-account>=0.11",
|
|
27
|
+
]
|
|
28
|
+
verify = [
|
|
29
|
+
"cryptography>=41",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
scry-init = "scry_client.init_cli:main"
|
|
34
|
+
scry-heartbeat = "scry_client.heartbeat:main"
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://scry.moreright.xyz"
|
|
38
|
+
Source = "https://github.com/AnthonE/scry"
|
|
39
|
+
|
|
40
|
+
[tool.setuptools]
|
|
41
|
+
packages = ["scry_client"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""scry-client — call the hosted scry meter (signed channel-coupling
|
|
2
|
+
attestation), play the fun layer (augury / duels / table / arena), and use
|
|
3
|
+
the agency (adopt + drive hosted familiars, P2).
|
|
4
|
+
|
|
5
|
+
Trust-layer-as-a-service: `Evaluator` wraps the meter as a neutral,
|
|
6
|
+
third-party evaluator for YOUR product — fetch a read, verify it offline
|
|
7
|
+
against a pinned key, gate on a checked fact. Money never moves the number.
|
|
8
|
+
"""
|
|
9
|
+
from .client import ScryClient, ScryError
|
|
10
|
+
from .play import ScryPlay, ScryPlayError
|
|
11
|
+
from .evaluator import Evaluator, ConductRead, Decision, REFERENCE_PUBKEY_B64
|
|
12
|
+
|
|
13
|
+
__version__ = "0.5.0"
|
|
14
|
+
__all__ = ["ScryClient", "ScryError", "ScryPlay", "ScryPlayError",
|
|
15
|
+
"Evaluator", "ConductRead", "Decision", "REFERENCE_PUBKEY_B64"]
|