@mysten-incubation/sui-agent-pass 0.1.2 → 0.1.4

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/docs/PLAYBOOK.md CHANGED
@@ -1,108 +1,127 @@
1
1
  # Agent playbook
2
2
 
3
- How an agent sets up a pass from a request, acts within its rules, reports its state and ends
4
- it. Any MCP client gets this text as the `agent-pass://playbook` resource; the contract
5
- interface for building transactions is the `agent-pass://guide` resource
6
- ([`docs/AGENT.md`](AGENT.md)).
7
-
8
- The owner's coins stay in the owner's own address. The owner signs once in their own wallet:
9
- that creates a pass holding the rules, issues allowances over the owner's balance that only the
10
- pass can spend, and hands the pass's receipt to the owner. You act with a separate agent key
11
- that the signer holds; you never see it. Every action you take is a transaction that draws on an
3
+ How an agent sets up a pass from an owner's request, acts within its rules, reports on it,
4
+ changes it and ends it. Every MCP client gets this text as the `agent-pass://playbook` resource;
5
+ the SDK and the contract interface are in `agent-pass://guide` ([`docs/AGENT.md`](AGENT.md)).
6
+
7
+ ## How a pass works
8
+
9
+ The owner's coins stay in the owner's address. The owner signs once in their own wallet, and
10
+ that one transaction creates a pass holding the rules, issues allowances over the owner's
11
+ balance that only the pass can spend, and gives the agent key its gas. You act with that agent
12
+ key, which the signer holds and you never see. Each action is a transaction that draws on an
12
13
  allowance and that the chain checks against the rules; proceeds go back to the owner's address,
13
- never to you. A position you open (a NAVI account, a stake) sits in the pass and only the owner
14
- can take it out. A signature from the signer is not permission; only a successful on-chain
15
- execution is.
16
-
17
- Respond in English. Amounts: SUI has 9 decimals, USDC has 6. USDC, the pools and the lending
18
- market are demo fixtures on localnet, devnet or testnet, not real money; transfers and staking
19
- are the real system.
20
-
21
- ## 1. From the request to rules
22
-
23
- Map what the owner says onto these rule sets. Anything they do not mention is **not allowed**
24
- (pass `null`). Never invent a recipient address: ask for it. Never invent amounts: if a limit is
25
- missing, ask, or propose a conservative default and say so. Every limit is required and must be
26
- above zero; there is no "no limit" value. A daily limit may not exceed the lifetime cap of its
27
- coin, so size `caps` to cover the days you set, and a little above the sum of the daily limits.
28
- Name a coin by its symbol when `list_passes` lists it for the network; any other coin the owner
29
- holds (`session_info.ownerCoins`, or a `listBalances` read) is named by its full type, and a pair
30
- the network list lacks needs the pool id of a DeepBook or Cetus pool holding exactly those two
31
- coins in `pools`. The server and the review page read that coin's symbol and decimals and that
32
- pool's venue and coin order from chain, never from you, and the page shows an unlisted coin with
33
- its type so the owner can tell a look-alike from the real one. Lending stays with the coins the
34
- network lists as NAVI reserves. About the sum of daily limits:
35
- the chain checks the lifetime cap before the daily meter, so a cap equal to one day's limits
36
- turns the owner's "daily limit" refusal into a "lifetime cap" one. Coins are named by symbol; `list_passes` shows
37
- each network's coins, pools (which pairs trade where) and lendable coins. One rule per coin,
38
- pair direction or lending coin; a coin without a rule cannot be touched.
39
-
40
- | Rule set | Fields (each entry one rule) | What the chain enforces |
41
- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
42
- | `transfers` | `coin`, named recipients (name + address), per transfer, per UTC day | only named recipients ever receive that coin |
43
- | `swaps` | `sell`, `buy`, optional `venues` (`deepbook`, `cetus`; default every listed pool for the pair), per trade, per UTC day, `minPrice` (bought coin per one sold coin) | only listed pools; caps on the sold coin; realised price at or above the floor; DeepBook fills nothing under the pool's minimum order (1 SUI on mainnet), so list Cetus too for small sales |
44
- | `lending` | `coin`, `allowBorrow`, per action, per UTC day, `minHealthFactor` (or null) | NAVI only; supply and withdraw, and borrow and repay when allowed; a borrow or withdraw that would breach the floor is refused |
45
- | `staking` | validator addresses (empty = any active validator), SUI per stake, per UTC day | only listed validators; the stake stays in the pass; 1 SUI minimum |
46
-
47
- Limits meter what leaves the owner's balance, not net exposure: a supply or a stake counts in
48
- full, and withdrawing or unstaking returns the funds to the owner without giving anything back
49
- to the day's or the lifetime's allowance. A stake-and-unstake or supply-and-withdraw cycle costs
50
- the allowance once, so size the staking and lending limits for the cycles the agent will run,
51
- and say so when the owner asks for "restake with a better validator".
52
-
53
- Plus: `days` (agent term, 1 to 30), `caps` (by symbol: the lifetime amount of each coin the
54
- key may ever withdraw; exactly the coins the rules spend, staking spends SUI), `gasSui`
55
- (default 0.05; a stipend to the agent's own address, outside the rules), `gasCapSui` (default
56
- 0.1; a separate allowance the agent uses to top up its gas) and `gasDailySui` (default a fifth
57
- of `gasCapSui`). Allowances draw only from the owner's address balance, never from coin
58
- objects, so the review page reads that balance and converts the owner's coins into it as far
59
- as each cap (plus `gasCapSui` for SUI) needs; the owner sees the amounts before signing, and
60
- converted coins stay theirs. Off mainnet the stablecoin is a test token the demo faucet mints. The owner needs that much SUI in total, address balance and coin objects together, plus `gasSui` and fees; nothing has to be a coin object. A stake needs a whole SUI.
61
-
62
- Before calling anything, show the owner the rule set you intend to propose in one short list and
63
- ask for a yes, unless they already stated everything explicitly.
64
-
65
- ## 2. Propose and get the signature
66
-
67
- These tools live on the stdio server (`agent-pass mcp`), which keeps every pass session on the
68
- machine; a per-session HTTP signer only has `session_info` and `sign_transaction`.
69
-
70
- Call `propose_authorization` with the rules. It returns `rules` (the exact text the review page
71
- shows), `reviewUrl` and `sessionAddress`, and opens the page in the browser. Paste the `rules`
72
- text to the owner verbatim. Tell them to connect their wallet, compare the page with that text
73
- and sign once. The page shows what their wallet holds against what the setup needs and links the
74
- faucet when it is short. Holdings have two sides: allowances draw from the owner's address
75
- balance only; coin objects stay out of their reach until the signature converts the shortfall;
76
- the owner's own transactions pay gas from either side. The page needs the owner's total SUI to
77
- cover the caps, the stipend and fees, nothing in coin objects specifically. If the browser did not open, give them `reviewUrl`.
78
-
79
- Then call `session_info` with the returned pass id and `wait: 120`, repeating while the status
80
- is `awaiting_authorization`. When it becomes `active`, the signer has already read the pass, the
81
- allowances and the policies back from chain and compared them with what was proposed. Report the
82
- pass id, the authorization digest, the owner's balances and what the key may still withdraw.
83
-
84
- A new pass goes on the network the owner names (`network`), from the deployments this package
85
- ships (`list_passes` lists them as `bundledNetworks`); with none named it goes on the first
86
- shipped one, or on a private `deployment.json` under the root when one exists. Only a private
87
- publish needs a `deployment` path.
14
+ never to you. A position you open (a NAVI account, a stake) sits in the pass, and only the owner
15
+ can take it out.
16
+
17
+ A signature from the signer is not permission. Only a successful on-chain execution is.
18
+
19
+ Respond in English. Amounts are exact decimals in each coin's own units; `list_passes` and
20
+ `session_info` give every coin's decimals. Dates are UTC, and a day is a UTC calendar day. Off
21
+ mainnet the stablecoin is a test token and the markets are stand-ins; transfers and staking are
22
+ real everywhere.
23
+
24
+ ## 1. Turn the request into rules
25
+
26
+ Map what the owner asks for onto the rule sets below. Anything they did not ask for is not
27
+ allowed: leave it out. One rule per coin, per swap direction and per lending coin; a coin without
28
+ a rule cannot be touched.
29
+
30
+ Three things only the owner can supply. Ask for them; never fill them in:
31
+
32
+ - **Recipients.** Every transfer goes to a named address the owner gave you.
33
+ - **Prices.** Every swap rule needs the owner's price limit. When they have not said one, show
34
+ them the pool's current price from `list_passes` and ask what they accept.
35
+ - **Amounts.** When a limit is missing, ask, or propose a conservative one and say that you did.
36
+
37
+ Every limit must be above zero; there is no "no limit".
38
+
39
+ | Rule set | Fields | What the chain enforces |
40
+ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
41
+ | `transfers` | `coin`, named recipients (name and address), per transfer, per day | only those recipients ever receive that coin |
42
+ | `swaps` | `sell`, `buy`, optional `venues` (`deepbook`, `cetus`; every listed pool for the pair when omitted), per trade, per day, `limitPrice` | only listed pools; limits on the sold coin; every fill at the price limit or better |
43
+ | `lending` | `coin`, `allowBorrow`, per action, per day, `minHealthFactor` (or null) | NAVI only; supply and withdraw, plus borrow and repay when allowed; a withdraw or borrow that would take the health factor under the floor is refused |
44
+ | `staking` | validators (empty for any active one), SUI per stake, per day | only those validators; at least 1 SUI per stake; the stake stays in the pass |
45
+
46
+ **Prices.** When one coin of a pair is a stablecoin, `limitPrice` is in that stablecoin per one
47
+ of the other coin: the most the agent pays when buying, the least it accepts when selling. For
48
+ other pairs it is the bought coin per one sold coin, the least accepted. The limit is fixed when
49
+ the owner signs, so a limit close to the market refuses every trade once the price moves past
50
+ it; say so when the owner picks one.
51
+
52
+ **Venues.** DeepBook fills nothing under a pool's minimum order (1 SUI on the mainnet SUI/USDC
53
+ pool), so list Cetus as well when trades will be small. A network may list no pools or no NAVI
54
+ reserves; `list_passes` says so, and swap or lending rules are refused there.
55
+
56
+ **Coins and pools.** Name a coin by symbol when `list_passes` lists it for the network. Name any
57
+ other coin the owner holds (`session_info.ownerCoins` for an existing pass, or a `listBalances`
58
+ read of the owner's address) by its full type, and give the id of a
59
+ DeepBook or Cetus pool holding exactly that pair in `pools`. The server and the review page read
60
+ such a coin's symbol and decimals and such a pool's venue from chain, never from you, and the
61
+ page shows an unlisted coin with its type so the owner can tell a look-alike from the real one.
62
+ Lending is limited to the coins the network lists as NAVI reserves.
63
+
64
+ **Lifetime caps.** `caps` gives, per coin, the total the key may ever withdraw, for exactly the
65
+ coins the rules spend (staking spends SUI). A daily limit may not exceed its coin's cap. Size
66
+ each cap to cover the days of the term, a little above the sum of the daily limits: the chain
67
+ checks the cap before the daily limit, so a cap equal to one day's limit turns a "daily limit"
68
+ refusal into a "lifetime cap" one.
69
+
70
+ **What counts against a limit.** Limits meter what leaves the owner's balance, not net exposure.
71
+ A supply or a stake counts in full, and withdrawing or unstaking returns the funds without giving
72
+ the allowance back. A supply-and-withdraw or stake-and-unstake cycle costs the allowance once, so
73
+ size lending and staking limits for the cycles the agent will run, and tell the owner when they
74
+ ask for something like "restake with a better validator".
75
+
76
+ **Term and gas.** `days` is the agent's term, 1 to 30. `gasSui` (default 0.05) is a stipend sent
77
+ to the agent key, outside the rules. `gasCapSui` (default 0.1) is a separate allowance the key
78
+ draws on to top up its gas, and `gasDailySui` (default a fifth of `gasCapSui`) its daily limit.
79
+
80
+ **What the owner needs.** Allowances draw only from the owner's address balance, never from coin
81
+ objects. The review page reads both, and the signature converts coin objects into the address
82
+ balance as far as each cap (plus `gasCapSui` for SUI) needs; the converted coins stay theirs. The
83
+ owner needs that much in total, address balance and coin objects together, plus `gasSui` and fees.
84
+
85
+ Before you call anything, show the owner the rules you intend to propose as one short list and
86
+ ask for a yes, unless they already stated every rule explicitly.
87
+
88
+ ## 2. Propose the pass and wait for the signature
89
+
90
+ `propose_authorization`, `propose_change`, `list_passes`, `revoke_pass` and `forget_pass` live on
91
+ the stdio server (`agent-pass mcp`), which keeps every session on the machine. A per-session HTTP
92
+ signer has only `session_info` and `sign_transaction`.
93
+
94
+ The pass goes on the network the owner names (`network`, one of `list_passes.networks`), else on
95
+ the first network listed. A private publish of one's own takes a `deployment` path instead.
96
+
97
+ Call `propose_authorization` with the rules. It returns `rules`, the exact text the review page
98
+ shows, plus `reviewUrl` and `sessionAddress`, and opens the page in the browser. Paste `rules` to
99
+ the owner word for word and never restate the amounts yourself. Tell them to connect their wallet,
100
+ check the page against that text and sign once. The page shows what their wallet holds against
101
+ what the pass needs. If the browser did not open, give them `reviewUrl`.
102
+
103
+ Then call `session_info` with the pass and `wait: 120`, again while the status is
104
+ `awaiting_authorization`. At `active` the signer has read the pass, the allowances and the
105
+ policies back from chain and checked them against the proposal. Report the pass id, the
106
+ authorization digest, the owner's balances and what the key may still withdraw.
88
107
 
89
108
  ## 3. Act within the rules
90
109
 
91
- Read `session_info` first: it lists the installed policies with today's remaining usage, the
92
- `coins` (type, symbol, decimals), the `venues` (each pool with its pair, both directions'
93
- entries and DeepBook's minimum order), the held stakes (`control.stakes`), the owner's
94
- holdings by coin (`addressBalance`, which allowances draw from, and `coinBalance`, which only the
95
- owner can move; a low address balance next to coin objects is not an owner out of money), the
96
- allowances, the session `directory`, `sdk` and `server` (version and build time; after an upgrade
97
- the client must restart this server).
110
+ Start with `session_info`. It returns:
98
111
 
99
- Before any swap, `quote(identity, pair, amountIn)` prices it on the venue itself without touching
100
- an allowance: `amountIn` is what the pool would take and `amountOut` what comes back. DeepBook
101
- pays its fee from the input and rounds the order down to its lot size, so sell at least one lot
102
- over its minimum. Set `minOut` a little under the quote, never from a mid price.
112
+ - `control`: the installed policies with today's usage, the held stakes and NAVI position;
113
+ - `allowances`: what the key may still withdraw under each;
114
+ - `ownerBalances`: per coin, `addressBalance` (what allowances draw from) and `coinBalance` (coin
115
+ objects only the owner can move), so a low address balance next to coin objects is not an owner
116
+ out of money;
117
+ - `gas`: the agent key's own SUI;
118
+ - `coins` and `venues`: each coin's type and decimals, and each pool with its pair, both
119
+ directions' entry functions and DeepBook's minimum order;
120
+ - `directory`, `sdk` and `server`: the session directory, how to install and import the SDK,
121
+ and this server's version (after an upgrade the client must restart the server).
103
122
 
104
- Act by writing a Node script against the SDK, as the guide shows. Run `sdk.install` once in
105
- your working directory, then:
123
+ Act by writing a Node script against the SDK. Run `sdk.install` once in your working directory,
124
+ then:
106
125
 
107
126
  ```ts
108
127
  import {
@@ -125,75 +144,85 @@ const usdc = agent.identity.deployment.coins.find((c) => c.symbol === 'USDC')!;
125
144
  const out = await agent.submit(send(agent.identity, usdc.type, units('5', usdc.decimals), 'alice'));
126
145
  ```
127
146
 
128
- `submit` signs through this server, submits to Sui and returns what the chain persisted. Read it
129
- three ways: `success` true is done; `success` false means the chain executed and refused, and
130
- `reason` is the owner's rule that stopped it (quote it); a throw means the transaction was not
131
- executed at all (a dry run or client error), which you never describe as on-chain enforcement.
132
- `submit` also tops up your gas from the gas allowance whenever your own balance is low, so you
133
- do not manage gas on this path. Before a `swap`, read the pool (the guide shows how) and pick a
134
- `minOut` from the current price; the owner's floor still applies underneath. Size a repayment
135
- from the live debt: an over-payment returns to the owner but still counts against the allowance.
136
-
137
- For anything the builders do not cover, build your own PTB with `@mysten/sui` following the
138
- guide, call `sign_transaction` with the base64 bytes, and submit with `executeTransaction`
139
- yourself. Every spend takes the allowance object and a withdrawal input right after the pass.
140
- On that path gas is yours to manage: when your own SUI balance is below 0.01 SUI, spend
141
- from the gas allowance to your own address as the guide describes; that allowance has its own
142
- cap and daily window and never touches the asset caps.
147
+ **Swaps.** Before every swap, `quote(identity, pair, amountIn)` prices it on the venue without
148
+ touching an allowance: `amountIn` is what the pool would take and `amountOut` what comes back.
149
+ Set `minOut` a little under `amountOut`, never from a mid price; the owner's price limit still
150
+ applies underneath. DeepBook takes its fee from the input and rounds down to its lot size, so
151
+ sell at least one lot over its minimum.
152
+
153
+ **Repayments.** Size a repayment from the live debt: an over-payment returns to the owner but
154
+ still counts against the allowance.
155
+
156
+ **Outcomes.** `submit` signs through this server, executes on Sui and returns what the chain
157
+ recorded. `success: true` means done. `success: false` means the chain executed the transaction
158
+ and refused it; `reason` is the owner's rule that stopped it, and you quote it. A thrown error
159
+ means nothing executed (a dry run or client error), which you never describe as on-chain
160
+ enforcement. `submit` tops up your gas from the gas allowance when it runs low.
161
+
162
+ **Hand-built transactions.** For anything the builders do not cover, build the PTB with
163
+ `@mysten/sui` following the guide, sign it with `sign_transaction` and execute it yourself. Every
164
+ spend takes the allowance object and a withdrawal input right after the pass. On this path gas is
165
+ yours: when the key holds under 0.01 SUI, draw on the gas allowance as the guide shows. That
166
+ allowance has its own cap and daily limit and never touches the asset caps.
143
167
 
144
168
  ## 4. Report the state
145
169
 
146
- Call `list_passes`, then `session_info` for each pass the owner cares about (all of them if
147
- unclear). Report: status (awaiting authorization, active, expired or revoked), the owner's SUI
148
- and USDC address balances, what the key may still withdraw under each allowance, your gas
149
- balance, whether a NAVI position is held in the pass (`control.naviPosition`), the stakes it
150
- holds (`control.stakes`, id and principal), and for every installed policy the limit and today's
151
- usage from `control.policies[*].usage.usedToday`. Quote the `rules` text as returned; do not
152
- recompute amounts. Dates are UTC.
153
-
154
- ## 4b. Change the rules
155
-
156
- When a limit, a recipient, a pool or the term no longer fits, do not propose a new pass. Call
157
- `propose_change` with the pass and the complete new rule set (every rule, not a diff), in the
158
- same shape as `propose_authorization` minus the name and the stipend. It opens the review page
159
- with the current rules beside the proposed ones; paste its `changes` text to the owner. One owner
160
- signature replaces the policies and reissues only the allowances whose cap or term changed. The
161
- agent key, its gas float and anything the pass holds stay; replaced policies start the day's
162
- counters at zero, kept allowances keep their lifetime spend. Until the owner signs, the old rules
163
- are in force and `session_info` reports `status: changing`; poll it with `wait` until it is
164
- `active` again, then read the rules back before acting.
165
-
166
- ## 5. End it
167
-
168
- Two endings, both on the pass page, which `revoke_pass` opens for the pass the owner names (or
169
- the only one). Called without a pass, it opens the owner page instead, which lists every pass
170
- of the owner and closes any number of them with one signature; prefer that when several passes
171
- are to be ended. **Stop the agent now** revokes the key and deletes the allowances in one signature
172
- and keeps the pass and its history on chain; it is the instant answer when something is wrong.
173
- **Close the pass** does that too, withdraws the NAVI position's collateral into the owner's wallet
174
- when it owes nothing (NAVI's own app cannot operate a pass's position, so the account cap alone
175
- would be useless), hands every held object (the NAVI account, stakes) back to the owner's wallet,
176
- destroys the policies, the pass and the receipt, and returns their storage deposit with the gas
177
- rebate; a position with debt is handed over as it is, and the owner page lists such accounts
178
- with their balances; it is the normal ending when the owner is done. Tell the owner both
179
- exist, including that closing returns the storage cost. Tell them to connect the wallet that
180
- created the pass, click the ending they want and sign. Then call `session_info` with `wait: 60`
181
- until `status` is `revoked`, and confirm that the chain refuses this key from now on. Do not
182
- describe the page opening as revocation; only the signed transaction revokes. The owner's coins
183
- never left their address. Once the pass is closed, the signer sends the key's unspent gas float
184
- back to the owner's address by itself the next time it runs; nothing stays with the key. Then
185
- call `forget_pass` for the session: it refuses while the pass is live, returns any
186
- float still there, and deletes the session directory with its key. Offer it for every pass
187
- `list_passes` reports as closed or stopped and for proposals the owner never signed. On a stopped pass each held object also has its own **Reclaim**
188
- button: the NAVI position is withdrawn into their wallet with its account cap (collateral first,
189
- when it owes nothing), and each stake as an ordinary `StakedSui`.
170
+ Call `list_passes`, then `session_info` for each pass the owner asks about (all of them when
171
+ unclear). Report the status (`awaiting_authorization`, `active`, `changing`, `expired`, `revoked`
172
+ or `closed`), the owner's address balances, what the key may still withdraw, its gas, any NAVI
173
+ position or stakes in the pass, and for each policy its limit and today's usage
174
+ (`control.policies[*].usage.usedToday`). Quote the `rules` text as returned; do not recompute
175
+ amounts.
176
+
177
+ ## 5. Change the rules
178
+
179
+ When a limit, a recipient, a pool, a price or the term no longer fits, change the pass instead of
180
+ proposing a new one. Call `propose_change` with the pass and the complete new rule set (every
181
+ rule, not just the changed ones), in the same shape as `propose_authorization` without the name
182
+ and the stipend. It opens the review page with the current rules beside the new ones; paste its
183
+ `changes` text to the owner. One signature replaces the policies and reissues only the
184
+ allowances whose cap or term changed. The agent key, its gas and what the pass holds stay;
185
+ replaced policies start the day's usage at zero, and kept allowances keep their lifetime spend.
186
+
187
+ Until the owner signs, the old rules apply and `session_info` reports `changing`. Poll it with
188
+ `wait` until it is `active` again, then read the rules back before acting.
189
+
190
+ ## 6. End it
191
+
192
+ There are two endings, both on the pass page, which `revoke_pass` opens for the pass the owner
193
+ names. Without a pass it opens the owner page, which lists all of the owner's passes and ends any
194
+ number of them with one signature; use that when several are to go.
195
+
196
+ - **Stop the agent now** revokes the key and deletes the allowances, and keeps the pass and its
197
+ history on chain. It is the instant answer when something is wrong.
198
+ - **Close the pass** does the same, then returns everything the pass holds to the owner's wallet
199
+ and deletes the pass, which refunds its storage deposit. A NAVI position that owes nothing is
200
+ withdrawn into the owner's wallet first, since NAVI's own app cannot operate a pass's position.
201
+ A position with debt is handed over as it is, and the owner page lists it with its balances.
202
+ This is the normal ending when the owner is done.
203
+
204
+ Tell the owner both exist and that closing refunds the storage cost. They connect the wallet that
205
+ created the pass, pick an ending and sign. Opening the page revokes nothing; only the signed
206
+ transaction does. Then call `session_info` with `wait: 60` until the status is `revoked` or
207
+ `closed`, and confirm that the chain now refuses the key. On a stopped pass, each held object has
208
+ its own **Reclaim** button: a NAVI position comes back with its account cap (collateral first
209
+ when it owes nothing), and a stake as an ordinary `StakedSui`.
210
+
211
+ Once a pass is closed, the signer returns the key's unspent gas to the owner the next time it
212
+ runs. Then call `forget_pass` for the session: it refuses while the pass is live, returns any gas
213
+ still there, and deletes the session directory with its key. Offer it for every pass
214
+ `list_passes` reports as closed or stopped, and for proposals the owner never signed.
215
+
216
+ `list_passes` may also report `unreadable` sessions from an earlier version of this package.
217
+ Their passes may still be live: tell the owner to stop or close each one from its pass page on
218
+ the site, which reads the chain and needs no session file.
190
219
 
191
220
  ## Rules of conduct
192
221
 
193
222
  - Confirm with the owner before the first transaction of a session and before any action they
194
- did not explicitly ask for. Recurring work they asked for (a daily sale, say) needs no
195
- re-confirmation per run.
223
+ did not explicitly ask for. Recurring work they asked for, such as a daily purchase, needs no
224
+ confirmation each time.
196
225
  - Save the digest of every submission. If a response times out, look the digest up before
197
- retrying; never rebuild and resubmit the same action while the original could still execute.
198
- - Never search for, read or copy key files. `sign_transaction` is the only signing path.
199
- - Report outcomes from chain state (`session_info`, the digest), not from a signature.
226
+ retrying; never resubmit an action while the original could still execute.
227
+ - Never search for, read or copy key files. `sign_transaction` is the only way to sign.
228
+ - Report outcomes from chain state (`session_info`, the digest), never from a signature.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mysten-incubation/sui-agent-pass",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "AI builds transactions. A session signer signs. Your pass enforces the rules.",
6
6
  "repository": {
@@ -0,0 +1 @@
1
+ @font-face{font-family:TWK Everett;src:url(/fonts/TWKEverett-Regular.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:TWK Everett Mono;src:url(/fonts/TWKEverettMono-Regular.otf) format("opentype");font-weight:400;font-style:normal;font-display:swap}:root{--page: #000000;--card: #131518;--lift: #222529;--edge: #343940;--ink: #f2faff;--body: rgba(242, 250, 255, .64);--muted: #89919f;--grey: #6c7584;--hairline: rgba(242, 250, 255, .08);--accent: #298dff;--sans: "TWK Everett", "Helvetica Neue", Arial, system-ui, sans-serif;--mono: "TWK Everett Mono", ui-monospace, "SF Mono", Menlo, monospace;font-family:var(--sans);font-weight:400;color:var(--ink);background:var(--page);font-synthesis:none}*{box-sizing:border-box;border-radius:0!important;font-weight:400}body{margin:0;background:var(--page)}main{max-width:1280px;margin:auto;padding:32px 48px}header{display:flex;justify-content:space-between;align-items:center;gap:24px}.brand{font-size:24px;letter-spacing:-.02em;text-decoration:none;color:var(--ink)}.wallet{display:flex;gap:16px;align-items:center}.network{font-family:var(--mono);font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);border:1px solid var(--edge);padding:8px 12px;background:var(--page)}select.network{appearance:none;-webkit-appearance:none;cursor:pointer;padding-right:28px;background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),linear-gradient(135deg,var(--muted) 50%,transparent 50%);background-position:calc(100% - 15px) 14px,calc(100% - 10px) 14px;background-size:5px 5px,5px 5px;background-repeat:no-repeat}select.network:hover{color:var(--ink)}.hero{padding:72px 0 40px}.eyebrow{font-family:var(--mono);letter-spacing:.08em;font-size:12px;text-transform:uppercase;color:var(--accent)}h1{font-size:72px;line-height:.98;letter-spacing:-.034em;margin:24px 0}h1 span{color:var(--accent)}.intro{font-size:20px;line-height:1.4;color:var(--body);max-width:880px;overflow-wrap:anywhere}.layout{display:grid;grid-template-columns:1.3fr 1fr;gap:2px}.panel{background:var(--card);padding:32px;margin-bottom:2px}.panel-heading{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:16px}h2{font-size:24px;letter-spacing:-.02em;margin:0 0 24px}.panel-heading h2{margin:0}.badge{font-family:var(--mono);font-size:12px;letter-spacing:.08em;text-transform:uppercase;background:var(--accent);color:var(--page);padding:8px 12px;white-space:nowrap;text-decoration:none}.badge.muted{background:var(--lift);color:var(--muted)}.rule{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:16px 0;border-bottom:1px solid var(--hairline);font-size:14px}.rule.starts{margin-top:28px}.rule>span{color:var(--muted)}.rule strong{text-align:right;max-width:60%;overflow-wrap:anywhere;color:var(--ink)}.fine{color:var(--muted);font-size:12px;line-height:1.5;margin-top:16px}.warn{color:var(--ink);border-left:2px solid var(--grey);padding-left:8px}.balance{font-size:40px;letter-spacing:-.034em;margin:8px 0}.balance span{font-size:16px;letter-spacing:0;color:var(--muted)}hr{border:0;border-top:1px solid var(--hairline);margin:24px 0 0}button{cursor:pointer;border:1px solid var(--edge);background:var(--lift);color:var(--ink);padding:16px 24px;font:inherit;font-size:14px}button:disabled{opacity:.4;cursor:not-allowed}button.inline{padding:4px 8px;margin-left:8px;font-size:12px}.primary,.revoke{width:100%;margin-top:24px;padding:16px}.primary{background:var(--accent);color:var(--page);border-color:var(--accent)}.revoke{background:var(--page);color:var(--ink);border-color:var(--grey)}pre{display:block;padding:12px 14px;font-family:var(--mono);font-size:13px;line-height:1.6;background:var(--lift);color:var(--ink);margin:10px 0 0;overflow-x:auto;white-space:pre}.nav{display:flex;gap:20px;margin-right:auto;margin-left:8px}.nav a{font-family:var(--mono);font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);text-decoration:none}.nav a:hover{color:var(--ink)}.home{max-width:960px;margin:0 auto;padding:24px 0 0;text-align:center}.home h1{font-size:56px;line-height:1;letter-spacing:-.034em;margin:0 0 16px}.home .intro{margin:0 auto;max-width:620px;font-size:18px;line-height:1.45}.command{display:flex;align-items:center;gap:16px;margin:28px auto 0;max-width:640px;padding:14px 16px 14px 22px;background:var(--lift);border:1px solid var(--edge);text-align:left}.command code{flex:1;display:block;padding:0;margin:0;background:none;font-size:14px;line-height:1.7;white-space:nowrap;overflow-x:auto}.command code span{display:block}.command code i{font-style:normal;color:var(--muted);margin-right:8px}.command button{flex:none;margin:0;padding:8px 14px;font-size:12px;width:auto;min-width:72px}.three{list-style:none;display:grid;grid-template-columns:repeat(3,1fr);gap:32px;margin:30px 0 0;padding:0;text-align:left}.three li{border-top:1px solid var(--edge);padding-top:16px}.three .n{display:block;font-family:var(--mono);font-size:12px;letter-spacing:.08em;color:var(--accent);margin-bottom:10px}.three h3{font-size:18px;margin:0 0 6px;letter-spacing:-.01em}.three p{margin:0;font-size:14px;line-height:1.5;color:var(--body)}.home-links{display:flex;justify-content:center;gap:24px;flex-wrap:wrap;margin:28px 0 0;font-size:13px;color:var(--muted)}.home-links a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--edge)}.home-links a:hover{border-bottom-color:var(--accent)}.steps{margin:0;padding-left:22px}.steps li{margin:0 0 18px;line-height:1.55}.steps li strong{display:block;margin-bottom:4px}.steps li p{margin:6px 0 0}.steps blockquote{margin:10px 0 0}.guide .panel{margin-top:16px}.guide p{line-height:1.6;margin:0 0 12px}.guide .rule strong{text-align:left;max-width:70%;font-weight:400}code{display:block;padding:4px 8px;font-family:var(--mono);font-size:12px;background:var(--lift);color:var(--ink);margin:2px 0;overflow-wrap:anywhere}.message{padding:24px;border-left:2px solid var(--accent);background:var(--card);margin:0 0 24px;overflow-wrap:anywhere;font-size:14px}.message.error{border-left-color:var(--grey);color:var(--ink)}.next p{font-size:16px;line-height:1.5;color:var(--body)}blockquote{margin:24px 0 0;border-left:2px solid var(--accent);padding:8px 24px;line-height:1.5;color:var(--ink)}details{font-size:12px;color:var(--muted);margin:24px 0}summary{cursor:pointer}dl{display:grid;grid-template-columns:184px 1fr;gap:16px;margin-top:24px}dd{margin:0;overflow-wrap:anywhere;font-family:var(--mono);color:var(--body)}a{color:var(--accent)}input{font:inherit}footer{margin-top:48px;border-top:1px solid var(--hairline);padding:24px 0;color:var(--muted);font-size:12px}.attempt{display:grid;grid-template-columns:24px 1fr;gap:16px;padding:16px 0;border-bottom:1px solid var(--hairline);font-size:14px}.attempt .mark{width:24px;height:24px;display:grid;place-items:center;font-size:12px}.attempt.ok .mark{background:var(--accent);color:var(--page)}.attempt.refused .mark{background:var(--grey);color:var(--ink)}.attempt p{margin:4px 0 0}.attempt .why{color:var(--ink);border-left:2px solid var(--grey);padding-left:8px}.attempt .moved{color:var(--accent)}.attempt .meta{color:var(--muted);font-family:var(--mono);font-size:12px}@media(max-width:760px){main{padding:24px 16px}.hero{padding:48px 0 32px}h1{font-size:48px}.layout{grid-template-columns:1fr}.panel{padding:24px}header{flex-wrap:wrap;gap:12px 16px}.brand{font-size:20px}.nav{order:3;width:100%;margin:0}.network{display:none}pre{font-size:12px}.guide .rule strong{max-width:100%}.home{padding-top:16px;text-align:left}.home h1{font-size:40px}.home .intro{margin:0}.command{margin-top:24px}.three{grid-template-columns:1fr;gap:16px;margin-top:24px}.home-links{justify-content:flex-start}.panel-heading{flex-wrap:wrap}dl{grid-template-columns:1fr;gap:8px}dd{margin-bottom:8px}}.search{display:flex;gap:8px;margin:8px 0 32px}.search input{flex:1;font-size:16px;padding:16px;border:1px solid var(--edge);background:var(--card);color:var(--ink);min-width:0}.search input::placeholder{color:var(--muted)}.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:2px}.card{display:block;background:var(--lift);border-left:2px solid transparent;padding:24px;text-decoration:none;color:inherit}.card:hover{border-left-color:var(--accent)}.card a{text-decoration:none;color:inherit}.card .pick{display:block;margin-bottom:8px;font-size:14px;color:var(--muted)}.card h3{font-size:20px;margin:0 0 8px;letter-spacing:-.014em}.card p{margin:4px 0;font-family:var(--mono);font-size:12px;color:var(--muted);overflow-wrap:anywhere}.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:2px;margin:0 0 2px}.stat{background:var(--card);padding:24px 32px}.stat span{display:block;font-family:var(--mono);font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}.stat strong{font-size:56px;letter-spacing:-.034em;color:var(--accent)}.stat.refused strong{color:var(--ink)}.booth h1{font-size:56px}.booth .attempt{font-size:16px;padding:16px 0}.crumbs{font-family:var(--mono);font-size:12px;color:var(--muted);margin:24px 0 0;overflow-wrap:anywhere}.crumbs a{color:inherit}.mono{font-family:var(--mono);font-size:12px;overflow-wrap:anywhere}.owner-actions button{margin-top:16px}.empty{color:var(--muted);font-size:14px;padding:24px 0}@media(max-width:760px){.stats{grid-template-columns:1fr}.booth h1{font-size:40px}}