@oneie/claude 0.1.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.
Files changed (59) hide show
  1. package/.claude-plugin/plugin.json +16 -0
  2. package/.mcp.json +12 -0
  3. package/README.md +204 -0
  4. package/agents/w1-recon.md +102 -0
  5. package/agents/w2-decide.md +164 -0
  6. package/agents/w3-edit.md +91 -0
  7. package/agents/w4-verify.md +416 -0
  8. package/commands/browser.md +55 -0
  9. package/commands/cc-connect.md +67 -0
  10. package/commands/claw.md +135 -0
  11. package/commands/close.md +143 -0
  12. package/commands/create.md +78 -0
  13. package/commands/deploy.md +415 -0
  14. package/commands/do-autonomous.md +80 -0
  15. package/commands/do-improve.md +51 -0
  16. package/commands/do-show.md +89 -0
  17. package/commands/do.md +226 -0
  18. package/commands/improve.md +99 -0
  19. package/commands/kill.md +45 -0
  20. package/commands/release.md +144 -0
  21. package/commands/see.md +161 -0
  22. package/commands/setup.md +75 -0
  23. package/commands/sync.md +185 -0
  24. package/hooks/hooks.json +90 -0
  25. package/hooks/lib/signal.sh +28 -0
  26. package/hooks/scripts/design-check.sh +83 -0
  27. package/hooks/scripts/post-edit-check.sh +32 -0
  28. package/hooks/scripts/session-end-verify.sh +51 -0
  29. package/hooks/scripts/session-start.sh +88 -0
  30. package/hooks/scripts/stop-reflect.sh +95 -0
  31. package/hooks/scripts/sync-todo-docs.sh +46 -0
  32. package/hooks/scripts/task-complete-verify.sh +52 -0
  33. package/hooks/scripts/tool-signal.sh +48 -0
  34. package/package.json +33 -0
  35. package/rules/api.md +50 -0
  36. package/rules/astro.md +206 -0
  37. package/rules/design.md +221 -0
  38. package/rules/documentation.md +218 -0
  39. package/rules/engine.md +297 -0
  40. package/rules/react.md +137 -0
  41. package/rules/ui.md +82 -0
  42. package/scripts/cc-connect.sh +345 -0
  43. package/scripts/do-analyze.sh +42 -0
  44. package/scripts/do-folder.sh +63 -0
  45. package/scripts/do-prove.sh +51 -0
  46. package/scripts/do-reconcile.sh +28 -0
  47. package/scripts/do-smoke.sh +60 -0
  48. package/scripts/do-survey.sh +30 -0
  49. package/scripts/do-tier.sh +43 -0
  50. package/skills/build/SKILL.md +52 -0
  51. package/skills/cloudflare/SKILL.md +503 -0
  52. package/skills/dev/SKILL.md +58 -0
  53. package/skills/do/SKILL.md +24 -0
  54. package/skills/oneie/SKILL.md +51 -0
  55. package/skills/perf/SKILL.md +45 -0
  56. package/skills/signal/SKILL.md +108 -0
  57. package/skills/sui/SKILL.md +441 -0
  58. package/skills/tutorial/SKILL.md +96 -0
  59. package/skills/typecheck/SKILL.md +66 -0
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: perf
3
+ description: Iterative perf tuning — instrument, measure quantiles, attack the biggest bin, re-measure. Use when latency or throughput targets are missed and the bottleneck is unknown.
4
+ ---
5
+
6
+ # /perf — Performance Optimization Loop
7
+
8
+ Enforces Rule 3 on perf work: quantiles, not averages; bottleneck rank, not slowest call.
9
+
10
+ ## The loop (one iteration)
11
+
12
+ 1. **Instrument** — bracket every async boundary; extend `packages/sdk/src/telemetry.ts` before inventing a new surface. No target → no work.
13
+ 2. **Run** — production-shaped load (real signal sizes, real receiver distribution). Capture every trace row.
14
+ 3. **Analyse** — script reports per-op `count / p50 / p95 / p99 / total = count × p50`. Sort by total; the top 1–2 lines are the next cycle. Optimize the *biggest* op, not the *slowest*.
15
+ 4. **Propose → measure** — one change per iteration. Re-run 2–3. Compare quantiles, not averages.
16
+
17
+ **Symptom → likely cause:**
18
+
19
+ | Symptom | Cause |
20
+ |---|---|
21
+ | High p99, low p50 | tail latency — locks, GC, retries |
22
+ | High flat distribution | algorithmic — wrong data structure |
23
+ | Many short calls dominate | call overhead — fan-out, async hop, JSON parse |
24
+ | Memory-bound | redundant copies, missing buffer reuse |
25
+ | Network-bound | round-trips — coalesce, cache |
26
+
27
+ **Stop:** target hit, or 3 iterations with <10% delta on the top bin.
28
+
29
+ ## Receipt (Rule 3)
30
+
31
+ ```json
32
+ { "receiver": "perf:session:ok", "data": { "weight": 1, "content": {
33
+ "path": "<surface>", "target_us": N,
34
+ "before": { "p50_us": N, "p95_us": N, "p99_us": N },
35
+ "after": { "p50_us": N, "p95_us": N, "p99_us": N },
36
+ "delta_pct": { "p50": -N, "p95": -N, "p99": -N },
37
+ "wins": [ { "iter": N, "change": "...", "p50_delta_pct": -N } ]
38
+ }}}
39
+ ```
40
+
41
+ Negative `delta_pct` = faster. Pheromone marks the path; substrate learns which optimization shapes pay off where.
42
+
43
+ ## Targets
44
+
45
+ `50ms` agent wallet · `<10ms` gateway · `3s` buy · `30s` list. From root `CLAUDE.md`.
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: Signal
3
+ description: Signal system — receiver naming, weight conventions, four outcomes (result/timeout/dissolved/failure), emitters (bash/TypeScript/React), and observability endpoints. Use when working with signals, mark/warn/fade, the /api/signal route, or hook-emitted pheromones.
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # Signal — The Universal Primitive
8
+
9
+ **Receiver names the edge. Weight deposits pheromone. Tags classify. Everything else is convention.**
10
+
11
+ ```ts
12
+ type Signal = { receiver: string; data?: unknown }
13
+ ```
14
+
15
+ Two fields. The type is frozen — never narrow it. Everything below is a pattern for filling those two fields, not a contract.
16
+
17
+ ## Data convention (router reads these, not the type)
18
+
19
+ ```ts
20
+ data = { tags?: string[], weight?: number, content?: unknown }
21
+ ```
22
+
23
+ - **`weight`** — `+1` marks, `-1` warns, omitted = `+1`, `0` = neutral. Gradations (`-0.5` for dissolved, chain-depth multipliers for marks) are discretion, not rules.
24
+ - **`tags`** — classification. Queries filter on these. Not required.
25
+ - **`content`** — opaque payload. Router never reads it for routing.
26
+
27
+ ## The four outcomes (Rule 1)
28
+
29
+ Every loop closes in exactly one of these. Pick the weight; the substrate does the rest.
30
+
31
+ | Outcome | Weight | When |
32
+ |-------------|----------|----------------------------------------|
33
+ | result | `+1` | success |
34
+ | timeout | `0` | slow, not the agent's fault |
35
+ | dissolved | `-0.5` | missing unit/capability, server down |
36
+ | failure | `-1` | agent produced nothing |
37
+
38
+ If in doubt: `+1` on success, `-1` on failure. The gradations are discretion.
39
+
40
+ ## Receiver naming
41
+
42
+ `receiver` matches `/^[a-zA-Z0-9:_-]+$/`, max 255 chars. The first colon-delimited segment is the **surface** — prefixes are **query-partitioning hints**, not a type contract. Any string works; these are the conventions in use:
43
+
44
+ | Prefix | Example | Emitter |
45
+ |--------------|-------------------------------|---------------------------------------------------------|
46
+ | `ui:*` | `ui:chat:copy` | React `onClick` via `emitClick()` |
47
+ | `tool:*` | `tool:Edit:ok`, `tool:Bash:fail` | `.claude/hooks/tool-signal.sh` on PostToolUse |
48
+ | `hook:*` | `hook:post-edit:warn` | other hook scripts via `emit_signal` (`hooks/lib/signal.sh`) |
49
+ | `cli:*` | `cli:signal:send` | `oneie` CLI verbs |
50
+ | `bridge:*` | `bridge:mirrorMark` | `src/engine/bridge.ts` |
51
+ | `l4:*` | `l4:payment:settle` | L4 economic loop |
52
+ | `w4:*` | `w4:verify:ok` | W4 rubric gate outcomes |
53
+ | `do:*` | `do:close` | `/do` wave/cycle boundaries |
54
+ | `loop:*` | `loop:feedback` | `/close` per-task rubric feedback |
55
+ | `unit:skill` | `scout:observe` | substrate tasks (plain unit + skill name) |
56
+
57
+ Format: `<surface>:<subject>:<action-or-outcome>`. New surfaces are fine — pick a prefix, stick with it.
58
+
59
+ ## Emitters
60
+
61
+ ### Bash hook
62
+ ```bash
63
+ source "$CLAUDE_PROJECT_DIR/.claude/hooks/lib/signal.sh"
64
+ emit_signal "hook:post-edit:ok" 1 "file=$FILE"
65
+ ```
66
+
67
+ Fire-and-forget, 2s max. Silent on dev-server-down.
68
+
69
+ ### TypeScript (API route)
70
+ ```ts
71
+ import { signalSend } from '@/lib/signalSender'
72
+ await signalSend({ receiver: 'w4:verify:ok', data: { tags: ['verify'], weight: 1, content: { passed: 320 } } })
73
+ ```
74
+
75
+ ### React click
76
+ ```tsx
77
+ import { emitClick } from '@/lib/ui-signal'
78
+ <Button onClick={() => emitClick('ui:chat:copy')}>Copy</Button>
79
+ ```
80
+
81
+ ### Substrate task
82
+ ```ts
83
+ unit('scout').on('observe', async (data, emit) => {
84
+ emit({ receiver: 'analyst:classify', data: { content: data } })
85
+ return data
86
+ })
87
+ ```
88
+
89
+ ## What `POST /api/signal` validates
90
+
91
+ Three deterministic pre-checks (no LLM): receiver format regex + length, toxicity (`isToxic(edge)` with cold-start protection), ADL gates (lifecycle → 410, network allowedHosts → 403). All cached 5 min. Full list: `src/pages/api/signal.ts`.
92
+
93
+ ## Observability
94
+
95
+ - `/api/export/paths` — all edges
96
+ - `/api/export/highways` — top by strength
97
+ - `/api/export/toxic` — blocked by resistance
98
+ - `/api/signals?since=T` — raw history
99
+
100
+ ## See Also
101
+
102
+ - `docs/dictionary.md` § Three Slots of Data — canonical convention
103
+ - `docs/routing.md` § Four Outcomes — weight semantics
104
+ - `src/engine/CLAUDE.md` § Rule 1 — code-level contract
105
+ - `.claude/hooks/lib/signal.sh` — bash helper
106
+ - `src/lib/signalSender.ts` — TS helper
107
+ - `src/lib/ui-signal.ts` — `emitClick`
108
+ - `src/pages/api/signal.ts` — the one receiver
@@ -0,0 +1,441 @@
1
+ # Sui Move Skill
2
+
3
+ Build secure, production-ready Move contracts for the ONE substrate and agent ecosystem.
4
+
5
+ **Status:** Phase 1 (testnet) ✅ · Phase 2 (identity & wallets) ✅ shipped 2026-04-18 · Phase 3 (escrow) scaffolding shipped, W3-W4 ready per `docs/SUI-todo.md`. Phase 4-6 next.
6
+
7
+ **Package versions (locked):** `@mysten/sui@^2.16.0`, `@mysten/dapp-kit@^1.0.4`. SDK is **v2** — imports are NOT backward-compatible with v1. See "SDK Imports (Sui v2)" below before writing any Sui code.
8
+
9
+ ## What This Skill Does
10
+
11
+ - **Generate Move modules** — scaffolding, best practices, gas optimization
12
+ - **Agent wallet integration** — keypair derivation, signing, address generation (Sui + ONE)
13
+ - **Envelope contracts** — payment channels, multi-sig, conditional execution
14
+ - **TypeDB ↔ Sui sync** — contract state ↔ substrate knowledge (paths, units, skills) via `bridge.ts`
15
+ - **Testing & deployment** — Move test suites, devnet/testnet/mainnet
16
+ - **ONE patterns** — pheromone trails as contract state, agent reputation on-chain
17
+
18
+ ## Phases (from docs/SUI-todo.md)
19
+
20
+ | Phase | What | Status |
21
+ |-------|------|--------|
22
+ | 1 | Testnet, contract publish, protocol funded | ✅ DONE |
23
+ | 2 | Deterministic keypair derivation, agent identity, `syncAgentWithIdentity()` | ✅ DONE (2026-04-18) |
24
+ | 3 | Escrow (`createEscrow/releaseEscrow/cancelEscrow`), x402 settlement, treasury fee 50 bps | 🟡 Scaffolding shipped in `sui.ts`; W3-W4 wiring next |
25
+ | 4 | On-chain fade, harden highways, frozen Path objects | 📋 Next |
26
+ | 5 | Group economics, treasury, federation | 📋 Next |
27
+ | 6 | Mainnet, audit, SDK, multi-chain | 📋 Next |
28
+
29
+ ## When to Use
30
+
31
+ - Writing Move smart contracts for ONE agents or payment flows (Phase 2-6)
32
+ - Generating agent wallets and keypairs from substrate identity (Phase 2)
33
+ - Syncing on-chain state back to TypeDB (via `src/engine/bridge.ts` absorb loop)
34
+ - Building envelope payment channels or multi-agent coordination contracts (Phase 3)
35
+ - Deploying to Sui (devnet, testnet, mainnet)
36
+ - Auditing Move code for security, gas, or ONE patterns
37
+
38
+ ## Core Components (What's Built)
39
+
40
+ | File | Lines | What |
41
+ |------|------:|------|
42
+ | `src/move/one/sources/one.move` | 691 | Move contract: Unit, Signal, Path, Escrow, fade, harden |
43
+ | `src/lib/sui.ts` | 652 | Sui client: Six Verbs + escrow + wallet derivation + faucet |
44
+ | `src/engine/bridge.ts` | 479 | Mirror/absorb: Runtime ↔ Sui ↔ TypeDB sync |
45
+ | `src/schema/world.tql` | — | `sui-unit-id`, `sui-path-id`, `wallet` attributes on unit/path |
46
+ | `src/engine/persist.ts` | — | Auto-mirror on mark/warn/actor |
47
+
48
+ **Exported API surface (from `src/lib/sui.ts` — read before reinventing):**
49
+
50
+ | Category | Functions |
51
+ |----------|-----------|
52
+ | Client | `getClient()` — returns cached `SuiJsonRpcClient` |
53
+ | Wallet | `deriveKeypair(uid)`, `addressFor(uid)`, `platformKeypair()`, `signAndExecute()` |
54
+ | Units | `createUnit()`, `registerTask()`, `getOwnedUnits()`, `getObject()`, `resolveUnit(uid)` |
55
+ | Paths (Six Verbs) | `mark()`, `warn()`, `send()`, `consume()`, `pay()`, `createPath()`, `harden()` |
56
+ | Escrow | `createEscrow()`, `releaseEscrow()`, `cancelEscrow()`, `viewEscrow()` + `*Tx()` builders |
57
+ | Ops | `ensureFunded()` (faucet) |
58
+
59
+ **Testnet Package:** `0xa5e6bddae833220f58546ea4d2932a2673208af14a52bb25c4a603492078a09e`
60
+ **Protocol Object:** `SUI_PROTOCOL_ID` (treasury, fee_bps = 50 → 0.5%)
61
+
62
+ ---
63
+
64
+ ## SDK Imports (Sui v2) — LOCKED
65
+
66
+ The SDK is v2 since commit `74c15a0`. The JSON-RPC client moved out of `/client` and was renamed. **The v1 imports silently survive editor autocomplete from stale docs — they do not exist at runtime.** Vite throws `does not provide an export named 'SuiClient'` and cascades up through `src/pages/api/signal.ts`, taking down every page that routes a UI click.
67
+
68
+ ### Rename map (v1 → v2)
69
+
70
+ | v1 (removed) | v2 (use this) |
71
+ |-------------------------------------------|-------------------------------------------------------|
72
+ | `SuiClient` from `@mysten/sui/client` | `SuiJsonRpcClient` from `@mysten/sui/jsonRpc` |
73
+ | `getFullnodeUrl` from `@mysten/sui/client` | `getJsonRpcFullnodeUrl` from `@mysten/sui/jsonRpc` |
74
+ | `SuiClientOptions` | `SuiJsonRpcClientOptions` |
75
+ | `SuiHTTPTransport` | `JsonRpcHTTPTransport` |
76
+ | `isSuiClient` | `isSuiJsonRpcClient` |
77
+ | `SuiTransactionBlockResponse` (either path) | Same name, now also exported from `/jsonRpc` |
78
+ | `SuiClientProvider` (dapp-kit) | **Same name — unchanged.** dapp-kit 1.0.4+ already uses v2 types internally |
79
+
80
+ Migration guide: `node_modules/@mysten/sui/docs/migrations/sui-2.0/sui.md`.
81
+
82
+ ### Constructor now requires `network`
83
+
84
+ ```ts
85
+ // WRONG (v1 — crashes with type error in v2)
86
+ const client = new SuiClient({ url: getFullnodeUrl('testnet') })
87
+
88
+ // RIGHT (v2)
89
+ import { SuiJsonRpcClient, getJsonRpcFullnodeUrl } from '@mysten/sui/jsonRpc'
90
+ const client = new SuiJsonRpcClient({
91
+ url: getJsonRpcFullnodeUrl('testnet'),
92
+ network: 'testnet', // REQUIRED — used by MVR resolver and future multi-network tooling
93
+ })
94
+ ```
95
+
96
+ Same applies to every `NetworkConfig` entry passed to `createNetworkConfig({...})` in dapp-kit — each entry must include `network: 'testnet'` (or 'mainnet'/'devnet'/'localnet') alongside `url`.
97
+
98
+ ### Use `@/lib/sui`, not the raw SDK
99
+
100
+ If you find yourself importing directly from `@mysten/sui/jsonRpc` outside `src/lib/sui.ts` or `src/components/pay/PayPage.tsx`, you are probably reinventing something. `getClient()` in `src/lib/sui.ts` returns the singleton; every Six-Verb function (`mark`, `warn`, `send`, `pay`, etc.) already exists. Two legitimate exceptions:
101
+ - `PayPage.tsx` — needs `getJsonRpcFullnodeUrl` for the dapp-kit `createNetworkConfig` call
102
+ - New contract tooling that reads types like `SuiTransactionBlockResponse`
103
+
104
+ ### Defensive pattern: lazy-import `@/lib/sui` from hot routes
105
+
106
+ `src/pages/api/signal.ts` (applied 2026-04-18) imports `@/lib/sui` **dynamically inside the Sui-mirror try block** rather than at module scope:
107
+
108
+ ```ts
109
+ // Top of signal.ts: no @/lib/sui import
110
+
111
+ // Inside the POST handler, after TypeDB write:
112
+ try {
113
+ const { resolveUnit, send: suiSend } = await import('@/lib/sui')
114
+ // ...Sui mirror...
115
+ } catch {
116
+ // Sui not configured, SDK broken, or tx failed — TypeDB signal still recorded
117
+ }
118
+ ```
119
+
120
+ **Why:** `/api/signal` is imported transitively by every page that routes a UI click. A top-level `import { ... } from '@/lib/sui'` means any Sui SDK type break bricks the entire API route (and thus every dependent page). Lazy import contains the blast radius to just the mirror step. Apply this same pattern to any other hot route that touches Sui only as fire-and-forget.
121
+
122
+ ---
123
+
124
+ ## Works With /typedb — The Same Ontology, Two Deterministic Fires
125
+
126
+ `src/schema/sui.tql:1` already put it best: **"The same ontology. Two deterministic fires."** Move is the permanent, economic fire (path revenue, escrow, treasury — expensive to write, cheap to trust). TypeDB is the learning, classification fire (hypotheses, frontiers, tags — cheap to write, rich to query). The runtime is the fast nervous system between them. Both skills speak the same vocabulary by design — `strength`, `resistance`, `revenue`, `path`, `unit` — so the bridge is a **1:1 rename, not a translation**.
127
+
128
+ ### Canonical crosswalk
129
+
130
+ `src/schema/sui.tql` (336 lines) is the Rosetta Stone — every Move struct has a matching TQL entity, every Move function has a matching TQL `fun`. Read it when names or shapes drift. The runtime schema is `src/schema/world.tql`; `sui.tql` is the parallel declaration that proves the two layers agree.
131
+
132
+ ### Attribute mapping (Move struct ⇌ TypeDB attribute)
133
+
134
+ | Move field (`one.move`) | TQL attribute (`world.tql`) | Move type | TQL type | Direction |
135
+ |---------------------------------|--------------------------------|-------------|----------|-------------------------------|
136
+ | `Unit.id` (address) | `unit.sui-unit-id` | address | string | Sui → TQL on `mirrorActor()` |
137
+ | *derived by* `addressFor(uid)` | `unit.wallet` | address | string | Runtime → TQL on agent sync |
138
+ | `Unit.name` | `unit.name` | String | string | bidirectional |
139
+ | `Unit.balance` | `unit.balance` | u64 | double | Sui → TQL via `absorb()` |
140
+ | **`Path.strength`** | **`path.strength`** | u64 | double | bidirectional — load-bearing |
141
+ | **`Path.resistance`** | **`path.resistance`** | u64 | double | bidirectional — load-bearing |
142
+ | `Path.revenue` | `path.revenue` | u64 | double | Sui → TQL via `absorb()` |
143
+ | `Path.id` (address) | `path.sui-path-id` | address | string | Sui → TQL on mirror |
144
+ | `Highway.id` (address) | `path.sui-highway-id` | address | string | Sui → TQL on `mirrorHarden()` |
145
+ | `Signal.payload` (vector<u8>) | `signal.data` | bytes | string | one-way, usually TQL-only |
146
+
147
+ **Name drift to know about:** Move still has `struct Colony` (one.move:71). TypeDB moved to `entity group` per `docs/dictionary.md`, but the Move contract hasn't been migrated yet because that requires a package upgrade. When bridging, read Move `Colony` → TQL `group`.
148
+
149
+ **Load-bearing invariant:** `strength` and `resistance` share the same name in both layers. If you rename one, rename both — `bridge.ts` is a pass-through, there's no translation logic. Type-width (`u64` ↔ `double`) is handled by JSON serialization at the bridge; don't write logic that depends on sub-integer precision.
150
+
151
+ ### Bridge contract (`src/engine/bridge.ts`, 479 lines)
152
+
153
+ | Function | Fires when | Maps |
154
+ |-----------------------------------|-----------------------------|------------------------------------------------------------------------|
155
+ | `mirrorMark(from, to, amount?)` | every `persist.mark()` | Runtime strength++ → Sui `mark_path()` |
156
+ | `mirrorWarn(from, to, amount?)` | every `persist.warn()` | Runtime resistance++ → Sui `warn_path()` |
157
+ | `mirrorPay(from, to, amount)` | L4 payment signal | Runtime payment → Sui `pay()` → `Path.revenue +=` |
158
+ | `mirrorHarden(from, to)` | L6 highway promotion | TQL harden → Sui `harden_path()` → Highway object created |
159
+ | `mirrorActor(uid, name)` | `/api/agents/register` | `addressFor(uid)` + `createUnit()` → writes `wallet` + `sui-unit-id` back |
160
+ | `resolve(uid)` | before any outbound Sui call | TQL lookup → `{ wallet, unitId }` — no on-chain twin? dissolve |
161
+ | `resolvePath(from, to)` | on-chain path ops | TQL `sui-path-id` lookup — memoized via edge cache |
162
+ | `absorb(cursor?)` | `/api/absorb` cron (1 min) | Sui events → TQL writes: UnitCreated, Marked, Warned, Paid, Hardened |
163
+ | `settleEscrow(...)` *(Phase 3)* | `releaseEscrow()` succeeds | on-chain settlement → TQL `path.revenue` + `path.strength` mark |
164
+
165
+ **Guarantee:** `mirror*` functions are fire-and-forget. They never block the TypeDB write or the runtime signal loop. If Sui is down, TypeDB still learns; pheromone re-converges when `absorb()` catches up.
166
+
167
+ ### When to load /typedb alongside this skill
168
+
169
+ - Writing or reading any attribute prefixed with `sui-*` in TQL
170
+ - Querying `unit.wallet` — the value comes from `addressFor(uid)` in `src/lib/sui.ts`, not stored by default
171
+ - Editing `src/engine/bridge.ts` — every function there touches both worlds
172
+ - Adding a TQL entity that has a Move twin — name alignment is a maintenance contract
173
+
174
+ ---
175
+
176
+ ## Canonical Move Reference (move-book.com)
177
+
178
+ The Move Book (https://move-book.com — source `github.com/MystenLabs/move-book`) is the canonical learning source for Move on Sui. **Read it before adding to `one.move`.** Our existing structs and verbs already implement named patterns from the book; future work should keep names aligned so the contract reads idiomatically.
179
+
180
+ ### Pattern crosswalk (`one.move` → Move Book chapter)
181
+
182
+ | What `one.move` does | Move Book chapter |
183
+ |---|---|
184
+ | `Treasury` object gates protocol fee + balance mutation | `programmability/capability` — the object IS the permission token |
185
+ | `Marked`, `Warned`, `Paid`, `Hardened`, `UnitCreated` events | `programmability/events` — past tense; no sender/timestamp fields (framework adds them) |
186
+ | `Escrow` must settle in one tx (release or cancel — never dropped) | `programmability/hot-potato-pattern` — types without `drop` force settlement |
187
+ | `init(otw, ctx)` creates the singleton `Protocol` once at publish | `programmability/module-initializer` + `programmability/one-time-witness` |
188
+ | `Unit`, `Path`, `Highway`, `Escrow` are storable objects | `storage/key-ability`, `storage/store-ability`, `storage/uid-and-id` |
189
+ | `Unit` owned (fast path) · `Path` / `Protocol` shared (consensus) | `object/ownership`, `object/fast-path-and-consensus` |
190
+ | `Path.revenue` accumulated on `pay()` | `programmability/transaction-context` — split/merge `Coin<SUI>` via PTBs |
191
+ | Future: per-Path analytics without breaking layout | `programmability/dynamic-fields` — anchor pattern |
192
+
193
+ When `one.move` grows, name the pattern from the book in the function doc comment so reviewers can audit against a known shape rather than reading the whole module.
194
+
195
+ ### Move 2024 syntax — required for new code
196
+
197
+ Our package is Move 2024 edition. The book's `guides/code-quality-checklist` lists the canonical style. Load-bearing items for `one.move`:
198
+
199
+ - `public struct`, never bare `struct` (2024 makes structs internal by default)
200
+ - Error constants: `EToxicPath` — PascalCase with leading `E`
201
+ - Regular constants: `MAX_FEE_BPS` — ALL_CAPS
202
+ - `public fun` or `entry fun`, never `public entry fun`
203
+ - Struct methods over module functions: `path.mark()`, not `path::mark(path)`
204
+ - Vector literals: `vector[a, b, c]`, not `vector::empty<T>()` + push loop
205
+ - Macros over while loops: `n.do!(|i| ...)`, `vec.do_ref!(|x| ...)`, `vec.fold!(init, |acc, x| ...)`
206
+ - Option: `opt.do!(|x| ...)` / `opt.destroy_or!(default)`, not branchy `is_some`/`borrow`
207
+ - Events named past tense (we already comply: `Marked`, `Warned`, `Hardened`)
208
+ - Capability structs end in `Cap` — `Treasury` is borderline because it also holds `Balance<SUI>`; document the dual role in the struct doc comment rather than rename
209
+
210
+ ### Upgradeability — what `one.move` cannot change
211
+
212
+ `guides/upgradeability-practices` rules apply on every package upgrade:
213
+
214
+ - Modules cannot be removed
215
+ - **Public struct layouts are frozen** — every field in `Unit`, `Path`, `Escrow`, `Protocol`, `Highway`, `Signal` is permanent once published. Adding a field requires either a new struct or a dynamic field.
216
+ - **Public function signatures are frozen** — add new functions; never change `mark_path(path: &mut Path, ...)` parameters
217
+ - Private / `public(package)` functions and non-public dependencies can change freely
218
+
219
+ **Practical rule:** before adding a field to any public struct, design it as a dynamic field on the existing UID (`df::add(&mut path.id, key, value)`). New analytics like `Path.hits_per_epoch` should attach this way. The boundary in `src/move/one/sources/one.move` — the public structs — IS the upgrade contract.
220
+
221
+ ### gRPC as alternative to JSON-RPC for the absorb loop
222
+
223
+ `github.com/MystenLabs/sui-apis` ships the protobuf gRPC interface for Sui (under `proto/`). Our current `absorb()` in `src/engine/bridge.ts` polls JSON-RPC `queryEvents` every minute. If event volume outgrows that budget — or we need lower-latency `Marked`/`Hardened` propagation — port the absorb loop to gRPC event streaming using the proto definitions. JSON-RPC is fine until then; sui-apis is the right reference when designing high-throughput indexing.
224
+
225
+ ### Working examples to mine
226
+
227
+ | Repo | Useful for |
228
+ |---|---|
229
+ | `github.com/MystenLabs/move-book` (`packages/`) | Every chapter ships runnable code; cite a chapter file when arguing for a refactor |
230
+ | `github.com/MystenLabs/solitaire` | Owned-object game + native randomness API + dapp-kit integration; reference shape when designing a per-agent owned object (e.g. inbox, score sheet) |
231
+
232
+ ---
233
+
234
+ ## Capabilities
235
+
236
+ ### 1. Mirror to Sui (mark/warn auto-propagate)
237
+
238
+ ```typescript
239
+ // From src/engine/bridge.ts
240
+ mirrorMark(from, to, strength) // Runtime → Sui: fire-and-forget
241
+ mirrorWarn(from, to, strength) // Runtime → Sui: fire-and-forget
242
+ ```
243
+
244
+ - Called automatically by `persist.ts` on every `mark()` or `warn()`
245
+ - Creates Signal object on-chain, fires Marked event
246
+ - Zero latency (async, doesn't block signal loop)
247
+ - Graceful fallback (Sui down? Signal completes anyway)
248
+
249
+ ### 2. Absorb from Sui (events → TypeDB)
250
+
251
+ ```typescript
252
+ // /api/absorb { cursor? }
253
+ absorb(cursor?) // Sui → TypeDB: poll events, write state
254
+ ```
255
+
256
+ - Polls on-chain events (Marked, UnitCreated, SignalSent)
257
+ - Writes back to TypeDB (strength updates, new units)
258
+ - Cursor-based pagination (resume from last event)
259
+ - Runs every 1 min via `/grow` tick
260
+
261
+ **Events queryable:**
262
+ ```typescript
263
+ queryEvents() // Returns all events since genesis
264
+ getPath(from, to) // Resolve TypeDB unit ↔ Sui path
265
+ ```
266
+
267
+ ### 3. Agent Wallet Derivation (Phase 2 — shipped)
268
+
269
+ ```typescript
270
+ // From src/lib/sui.ts (shipped 2026-04-18)
271
+ addressFor(uid) // UID → stable Sui address (Promise<string>)
272
+ deriveKeypair(uid) // UID → Ed25519 keypair (Promise<Ed25519Keypair>)
273
+ // Seed read from SUI_SEED env, never passed as arg
274
+ ```
275
+
276
+ - Deterministic: same `SUI_SEED + uid` → same SHA-256 secret → same keypair, always
277
+ - No private key storage: derives on-the-fly per call
278
+ - `syncAgentWithIdentity()` in `src/engine/agent-md.ts` wires wallet into TypeDB unit on markdown sync
279
+ - Multi-chain-ready (same pattern could emit Ethereum/Solana addresses)
280
+
281
+ ### 4. Payment Flow (Phase 3: escrow)
282
+
283
+ ```move
284
+ // Move contract functions (one.move)
285
+ create_escrow(unit, receiver, amount) // Lock tokens, await settlement
286
+ release_escrow(escrow, result?) // Success: pay + mark + fee (atomic)
287
+ cancel_escrow(escrow) // Timeout: return tokens, warn path
288
+ ```
289
+
290
+ - Atomic: fee + mark + transfer in single transaction
291
+ - Revenue: protocol collects `fee_bps` (50 = 0.5%)
292
+ - Idempotent: releasing same escrow twice fails safely
293
+ - Enables x402 workflow (402 → create escrow → execute → release)
294
+
295
+ ### 5. Path Strength on-Chain (permanent learning)
296
+
297
+ ```move
298
+ // Every path is a Sui object with:
299
+ Path {
300
+ from: address,
301
+ to: address,
302
+ strength: u64, // Marked increments
303
+ resistance: u64, // Warned increments
304
+ hits: u64, // Total signals
305
+ type: String, // "interaction", "payment", etc.
306
+ }
307
+ ```
308
+
309
+ - Strength = gas rewards (proportional to agent value)
310
+ - Resistance = slashing (accumulates from failures)
311
+ - Toxic when: `resistance >= 10 && resistance > 2x strength && (r+s) > 5`
312
+ - Read by `/api/highways` → mirrors to TypeDB → guides future signals
313
+
314
+ ## Phase 2 — Shipped (2026-04-18)
315
+
316
+ Already exported from `src/lib/sui.ts`. **Do not reimplement.**
317
+
318
+ ```typescript
319
+ import { deriveKeypair, addressFor, platformKeypair } from '@/lib/sui'
320
+
321
+ // Deterministic Ed25519 keypair from SUI_SEED + uid (SHA-256 → 32-byte secret)
322
+ const kp = await deriveKeypair('marketing:creative')
323
+ const addr = await addressFor('marketing:creative') // stable forever
324
+
325
+ // Integrated into agent sync: syncAgentWithIdentity() in src/engine/agent-md.ts
326
+ // writes `wallet` attribute to TypeDB unit on markdown → TypeDB sync
327
+ ```
328
+
329
+ **Verified:** 14 tests pass — determinism + uniqueness + idempotency. Unblocks Phase 3 (escrow on-chain) and marketplace on-chain discovery. Browser-side wallet connect uses `@mysten/dapp-kit` `ConnectButton` + `WalletProvider` (see `src/components/pay/PayPage.tsx`).
330
+
331
+ ## Phase 3 — Escrow (W3-W4 ready)
332
+
333
+ Transaction builders and high-level wrappers already in `src/lib/sui.ts`:
334
+
335
+ ```typescript
336
+ import { createEscrow, releaseEscrow, cancelEscrow, viewEscrow } from '@/lib/sui'
337
+
338
+ // Poster locks tokens
339
+ const { escrowId } = await createEscrow(posterUid, workerUnitId, amountMist, pathId)
340
+
341
+ // Worker settles (atomic: pay + mark + protocol fee)
342
+ await releaseEscrow(posterUid, escrowId, workerUnitId, pathId)
343
+
344
+ // Timeout path
345
+ await cancelEscrow(posterUid, escrowId, posterUnitId, pathId)
346
+
347
+ // Read current state
348
+ const view: EscrowView | null = await viewEscrow(escrowId)
349
+ ```
350
+
351
+ Protocol fee: **50 bps (0.5%)** collected to treasury on every `releaseEscrow`. W3 wires the UI side (claim button → `ui:chat:claim` signal); W4 adds deterministic sandwich gates (isToxic → skip escrow creation).
352
+
353
+ ## Real Examples (from Testnet)
354
+
355
+ ### Agent Created on-Chain
356
+
357
+ ```typescript
358
+ // Scout was created with this call:
359
+ const unitId = await createUnit("scout", "agent")
360
+ // Sui object ID: 0x6fd45656222db69f81dbf61c70873fd466ebd8b157bf6694f81314e3e0c13af8
361
+ // TypeDB marked: sui-unit-id = "0x6fd4..."
362
+ ```
363
+
364
+ ### Signal Sent & Path Created
365
+
366
+ ```typescript
367
+ // Signal from scout → analyst using the exported `send` wrapper
368
+ import { send } from '@/lib/sui'
369
+ const { digest } = await send(
370
+ 'scout', // sender uid (keypair derived)
371
+ scoutUnit.objectId,
372
+ analystUnit.objectId,
373
+ analystUnit.wallet,
374
+ 'default', // task type
375
+ new TextEncoder().encode('hello from scout'),
376
+ 0, // amount in MIST (0 = no payment attached)
377
+ )
378
+ // Sui Signal object created; Path (scout → analyst) strength += 1
379
+ // Absorb loop reads the event and writes strength delta back to TypeDB
380
+ ```
381
+
382
+ *(The Phase 3 escrow example is in the "Phase 3 — Escrow (W3-W4 ready)" section above with the accurate 4-arg signature — don't duplicate it here.)*
383
+
384
+ ## Safety (Deterministic Sandwich)
385
+
386
+ ```
387
+ PRE: isToxic(edge)? → skip contract call (no Sui interaction)
388
+ PRE: capability exists? → TypeDB lookup → skip if missing
389
+ LLM: (if applicable) generates response
390
+ POST: success? → mark(). timeout? → neutral. dissolved? → warn(0.5).
391
+ ```
392
+
393
+ - **No private keys in code** — use `$SUI_SEED` environment variable (derives on-the-fly)
394
+ - **Pre-flight checks** — isToxic(), capability exists? before contract call (prevents wasted gas)
395
+ - **Gas limits** — escrow functions must settle within gas budget
396
+ - **Auditability** — all math is deterministic; randomness only from LLM prompts
397
+
398
+ ## Env & Setup
399
+
400
+ ```bash
401
+ # .env (required for Phase 2+)
402
+ SUI_NETWORK=testnet
403
+ SUI_SEED=<32 bytes base64> # Generates all agent keypairs
404
+
405
+ SUI_PACKAGE_ID=0xa5e6... # Published contract package
406
+ SUI_PROTOCOL_ID=0x... # Protocol object (treasury, fee_bps)
407
+
408
+ # Verify setup
409
+ sui client object $SUI_PROTOCOL_ID
410
+ # Output: Protocol { treasury: 0, fee_bps: 50 }
411
+ ```
412
+
413
+ ## When This Skill Is Invoked
414
+
415
+ The `/sui` skill is a reading guide, not a CLI. When loaded, Claude should:
416
+
417
+ 1. **Before writing any Sui code**, re-read "SDK Imports (Sui v2)" above — the v1 patterns in `node_modules/@mysten/sui/docs/migrations/sui-2.0/sui.md` have been removed from the SDK but linger in every older doc, blog post, and Anthropic-era training snapshot. Autocomplete will suggest them. **Do not use them.**
418
+ 2. **Before adding a function to `@/lib/sui`**, check the "Exported API surface" table above. The Six Verbs plus escrow are already there; new work should compose them.
419
+ 3. **Before importing from `@mysten/sui/jsonRpc` directly**, check whether `getClient()` + an existing wrapper already covers the use case. The only legitimate direct importers are `src/lib/sui.ts` and `src/components/pay/PayPage.tsx`.
420
+ 4. **Before adding a top-level Sui import to any API route**, consider the lazy-import defense: if the route handles Sui as fire-and-forget (like `/api/signal`), `await import('@/lib/sui')` inside the relevant try block keeps the route resilient to SDK breakage.
421
+ 5. **For contract work**, read `src/move/one/sources/one.move` — all 691 lines define six object types (Unit, Signal, Path, Escrow, Highway, Treasury) and the six on-chain verbs. New Move should fit this surface, not grow a parallel one.
422
+ 6. **Before editing `one.move`**, cite the Move Book pattern your change implements (capability / hot-potato / OTW / dynamic-field / events) and check the upgradeability rules above — public struct layouts and function signatures are permanent once published.
423
+
424
+ ## Reference
425
+
426
+ - **Live contract:** `src/move/one/sources/one.move`
427
+ - **Client API:** `src/lib/sui.ts` (always use this, never the raw SDK)
428
+ - **Bridge:** `src/engine/bridge.ts` (mirror/absorb/resolve)
429
+ - **Integration point:** `src/engine/persist.ts` (auto-mirror on mark/warn)
430
+ - **Schema:** `src/schema/world.tql` (sui-unit-id, sui-path-id, wallet attributes)
431
+ - **Testnet explorer:** `https://suiscan.xyz/testnet/object/{OBJECT_ID}`
432
+ - **Full roadmap:** `docs/SUI-todo.md` (phases 1-6, all tasks)
433
+ - **v2 migration guide:** `node_modules/@mysten/sui/docs/migrations/sui-2.0/sui.md`
434
+ - **dapp-kit reference:** `node_modules/@mysten/dapp-kit/docs/sui-client-provider.md`
435
+ - **Move language canon:** https://move-book.com — source: `github.com/MystenLabs/move-book`
436
+ - **Sui gRPC interface (alt to JSON-RPC):** `github.com/MystenLabs/sui-apis` — protobufs in `proto/`
437
+ - **Owned-object example:** `github.com/MystenLabs/solitaire` — owned objects, native randomness, dapp-kit + TS SDK integration
438
+
439
+ ---
440
+
441
+ **ONE + Sui = agent wallets, envelope routing, pheromone as on-chain rewards, and deterministic contract security.**