@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.
- package/.claude-plugin/plugin.json +16 -0
- package/.mcp.json +12 -0
- package/README.md +204 -0
- package/agents/w1-recon.md +102 -0
- package/agents/w2-decide.md +164 -0
- package/agents/w3-edit.md +91 -0
- package/agents/w4-verify.md +416 -0
- package/commands/browser.md +55 -0
- package/commands/cc-connect.md +67 -0
- package/commands/claw.md +135 -0
- package/commands/close.md +143 -0
- package/commands/create.md +78 -0
- package/commands/deploy.md +415 -0
- package/commands/do-autonomous.md +80 -0
- package/commands/do-improve.md +51 -0
- package/commands/do-show.md +89 -0
- package/commands/do.md +226 -0
- package/commands/improve.md +99 -0
- package/commands/kill.md +45 -0
- package/commands/release.md +144 -0
- package/commands/see.md +161 -0
- package/commands/setup.md +75 -0
- package/commands/sync.md +185 -0
- package/hooks/hooks.json +90 -0
- package/hooks/lib/signal.sh +28 -0
- package/hooks/scripts/design-check.sh +83 -0
- package/hooks/scripts/post-edit-check.sh +32 -0
- package/hooks/scripts/session-end-verify.sh +51 -0
- package/hooks/scripts/session-start.sh +88 -0
- package/hooks/scripts/stop-reflect.sh +95 -0
- package/hooks/scripts/sync-todo-docs.sh +46 -0
- package/hooks/scripts/task-complete-verify.sh +52 -0
- package/hooks/scripts/tool-signal.sh +48 -0
- package/package.json +33 -0
- package/rules/api.md +50 -0
- package/rules/astro.md +206 -0
- package/rules/design.md +221 -0
- package/rules/documentation.md +218 -0
- package/rules/engine.md +297 -0
- package/rules/react.md +137 -0
- package/rules/ui.md +82 -0
- package/scripts/cc-connect.sh +345 -0
- package/scripts/do-analyze.sh +42 -0
- package/scripts/do-folder.sh +63 -0
- package/scripts/do-prove.sh +51 -0
- package/scripts/do-reconcile.sh +28 -0
- package/scripts/do-smoke.sh +60 -0
- package/scripts/do-survey.sh +30 -0
- package/scripts/do-tier.sh +43 -0
- package/skills/build/SKILL.md +52 -0
- package/skills/cloudflare/SKILL.md +503 -0
- package/skills/dev/SKILL.md +58 -0
- package/skills/do/SKILL.md +24 -0
- package/skills/oneie/SKILL.md +51 -0
- package/skills/perf/SKILL.md +45 -0
- package/skills/signal/SKILL.md +108 -0
- package/skills/sui/SKILL.md +441 -0
- package/skills/tutorial/SKILL.md +96 -0
- package/skills/typecheck/SKILL.md +66 -0
package/rules/engine.md
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "agents/src/**/*.ts"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Engine Rules
|
|
7
|
+
|
|
8
|
+
Apply to `src/engine/*.ts`
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## The Three Locked Rules (non-negotiable)
|
|
13
|
+
|
|
14
|
+
These three rules compound. Breaking any one breaks the flywheel.
|
|
15
|
+
|
|
16
|
+
### Rule 1 — Closed Loop
|
|
17
|
+
|
|
18
|
+
**Every signal closes its loop.** `mark()` on result, `warn()` on failure,
|
|
19
|
+
`dissolve` on missing unit/capability. No silent returns. No orphan signals.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
const { result, timeout, dissolved } = await net.ask({ receiver: next })
|
|
23
|
+
if (result) net.mark(edge, chainDepth) // success → path strengthens
|
|
24
|
+
else if (timeout) /* neutral — not the agent's fault */
|
|
25
|
+
else if (dissolved) net.warn(edge, 0.5) // mild — path doesn't exist
|
|
26
|
+
else net.warn(edge, 1) // failure — agent produced nothing
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Why: pheromone is the only thing that compounds. A handler that returns
|
|
30
|
+
silently leaks learning. Width (parallelism) only compounds if every
|
|
31
|
+
parallel branch deposits a mark or warn on the path it used.
|
|
32
|
+
|
|
33
|
+
### Rule 2 — Structural Time Only
|
|
34
|
+
|
|
35
|
+
**Plan in tasks → waves → cycles.** Never days, hours, weeks, sprints,
|
|
36
|
+
or any wall-clock unit.
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
task = atomic unit of work (one .on() handler, one file edit)
|
|
40
|
+
wave = phase within a cycle (W1 recon → W2 decide → W3 edit → W4 verify)
|
|
41
|
+
cycle = full W0-W4 sandwich, exits at rubric >= 0.65
|
|
42
|
+
path = what remembers across cycles (pheromone strength / resistance)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Why: the substrate measures **width** by tasks-per-wave, **depth** by
|
|
46
|
+
waves-per-cycle, **learning** by cycles-per-path. Calendar time can't be
|
|
47
|
+
`mark()`d, so it doesn't compound. Genuine external deadlines (merge
|
|
48
|
+
freezes, release cuts) are the only wall-clock exception — they come
|
|
49
|
+
from outside the substrate.
|
|
50
|
+
|
|
51
|
+
### Rule 3 — Deterministic Results in Every Loop
|
|
52
|
+
|
|
53
|
+
**Every loop reports verified numbers, not vibes.** Tests passed/total.
|
|
54
|
+
Build time in ms. Deploy time per service. Health check latency. Rubric
|
|
55
|
+
dimension scores. These are the deterministic signals that calibrate pheromone.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// Every loop ends like this — not "done", but "done with receipts"
|
|
59
|
+
{
|
|
60
|
+
passed: 320,
|
|
61
|
+
failed: 0,
|
|
62
|
+
buildMs: 22995,
|
|
63
|
+
deployMs: { gateway: 13705, sync: 8249, nanoclaw: 9163, pages: 17391 },
|
|
64
|
+
health: { gateway: 292, sync: 270, nanoclaw: 270 },
|
|
65
|
+
// /do code rubric — security/stability/simplicity/speed, gate ≥ 0.65
|
|
66
|
+
rubric: { security: 0.92, stability: 0.85, simplicity: 0.90, speed: 0.80 }
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Why: path strength without verification is superstition; with verification
|
|
71
|
+
it's learning. A loop that can't report deterministic results can't
|
|
72
|
+
`mark()` — it's just noise. This is the POST check of the deterministic
|
|
73
|
+
sandwich applied to every automation skill.
|
|
74
|
+
|
|
75
|
+
**Where it shows up:**
|
|
76
|
+
- `/work` — reports task count, tests passed, time spent
|
|
77
|
+
- `/wave` — reports dissolved/marked/warned agent counts per wave
|
|
78
|
+
- `/sync` — reports tasks synced, hash-delta, KV writes
|
|
79
|
+
- `/deploy` — reports W0 results, build ms, per-service deploy ms, health
|
|
80
|
+
- `/done` — reports rubric score (security + stability + simplicity + speed, composite ≥ 0.65)
|
|
81
|
+
- growth tick — reports per-loop timings (L1-L7 lastAtMs, nextAtMs)
|
|
82
|
+
|
|
83
|
+
If you can't measure it, you can't route around it.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## The Substrate
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
~90 lines. Zero returns. Two fields. Queue.
|
|
91
|
+
|
|
92
|
+
{ receiver, data }
|
|
93
|
+
|
|
94
|
+
That's all that flows.
|
|
95
|
+
The runtime moves signals. TypeDB remembers.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Two Layers
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
NERVOUS SYSTEM (runtime) BRAIN (TypeDB)
|
|
104
|
+
signals, strength, resistance, queue paths, units, skills, knowledge
|
|
105
|
+
loops L1-L3 (ms to minutes) loops L4-L7 (hours to weeks)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The runtime handles what moves. TypeDB handles what remains.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Tasks = Handlers, Dependencies = Continuations
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Tasks are .on() handlers on units
|
|
116
|
+
// Dependencies are .then() continuations
|
|
117
|
+
const bob = net.add('bob')
|
|
118
|
+
.on('schema', async (data, emit) => buildSchema(data))
|
|
119
|
+
.then('schema', r => ({ receiver: 'bob:api', data: r }))
|
|
120
|
+
.on('api', async (data, emit) => buildAPI(data))
|
|
121
|
+
.then('api', r => ({ receiver: 'bob:test', data: r }))
|
|
122
|
+
|
|
123
|
+
// No task entities. No dependency relations. No trail relations.
|
|
124
|
+
// Pheromone accumulates on paths automatically.
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Agent Self-Improvement
|
|
130
|
+
|
|
131
|
+
Units have `model`, `system-prompt`, `generation`.
|
|
132
|
+
The substrate measures performance. When it's bad enough, the agent evolves.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// TypeDB detects
|
|
136
|
+
needs_evolution(unit) → success-rate < 0.50, sample-count >= 20
|
|
137
|
+
|
|
138
|
+
// Agent responds
|
|
139
|
+
unit.system-prompt = rewrite(old-prompt, failures)
|
|
140
|
+
unit.generation++
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Two layers of learning:
|
|
144
|
+
- **Substrate** — pheromone on paths. World gets smarter.
|
|
145
|
+
- **Agent** — prompt/model evolution. Individual gets smarter.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Signal
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
type Signal = {
|
|
153
|
+
receiver: string // "unit" or "unit:task"
|
|
154
|
+
data?: unknown // { tags?, weight?, content? } by convention
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The universal primitive. `data` is untyped — convention shapes it:
|
|
159
|
+
`tags` (routing/classification), `weight` (pheromone deposit), `content` (payload).
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Unit
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
unit(id, route?)
|
|
167
|
+
.on(name, fn) // define task (handler)
|
|
168
|
+
.then(name, template) // define continuation (dependency)
|
|
169
|
+
.role(name, task, ctx) // context-bound task
|
|
170
|
+
.has(name) // introspection
|
|
171
|
+
.list() // introspection
|
|
172
|
+
.id // identity
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Task Signature
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
(data, send, ctx) => result
|
|
179
|
+
|
|
180
|
+
data // the data
|
|
181
|
+
send // (signal) => void — fan out
|
|
182
|
+
ctx // { from: string, self: string }
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## World
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
world()
|
|
191
|
+
.add(id) // create unit (auto-drains queued signals)
|
|
192
|
+
.remove(id) // remove unit (trails remain, fade naturally)
|
|
193
|
+
.signal(signal, from?) // route signal, mark pheromone
|
|
194
|
+
.enqueue(signal) // queue for later processing
|
|
195
|
+
.drain() // shift from queue, signal it
|
|
196
|
+
.pending() // queue length
|
|
197
|
+
.mark(edge, strength?) // strengthen path
|
|
198
|
+
.warn(edge, strength?) // weaken path
|
|
199
|
+
.sense(edge) // read strength
|
|
200
|
+
.danger(edge) // read resistance
|
|
201
|
+
.follow(type) // best path (deterministic)
|
|
202
|
+
.select(type?) // best path (probabilistic, ant-like)
|
|
203
|
+
.fade(rate?) // decay all paths (resistance 2x faster)
|
|
204
|
+
.highways(limit?) // top weighted paths
|
|
205
|
+
.has(id) // introspection
|
|
206
|
+
.list() // introspection
|
|
207
|
+
.get(id) // direct access
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Persist
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
persist() // extends world with TypeDB
|
|
216
|
+
.actor(id, kind?, opts?) // add + persist
|
|
217
|
+
.flow(from, to) // mark/warn wrapper
|
|
218
|
+
.open(n?) // top paths as {from, to, strength}
|
|
219
|
+
.blocked() // toxic paths
|
|
220
|
+
.know() // promote highways to knowledge
|
|
221
|
+
.recall(match?) // query knowledge from TypeDB
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Zero Returns
|
|
227
|
+
|
|
228
|
+
Positive flow only. Silence is valid.
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// GOOD
|
|
232
|
+
task?.(data, emit, ctx).then(result =>
|
|
233
|
+
next[name] && route?.(next[name](result), receiver)
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
// BAD
|
|
237
|
+
if (!task) return reject(...)
|
|
238
|
+
if (!target) throw new Error(...)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Missing handler? Signal dissolves. Group continues.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## The Tick
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const next = net.select() // follow pheromone
|
|
249
|
+
next && net.signal({ receiver: next }) // execute
|
|
250
|
+
net.drain() // process queue
|
|
251
|
+
net.fade(0.05) // decay
|
|
252
|
+
// evolve every 10min, know every hour
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Signal Flow
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
signal(sig, from='entry')
|
|
261
|
+
→ unit(sig, from)
|
|
262
|
+
→ task(data, send, {from, self})
|
|
263
|
+
→ send(sig) // fan out
|
|
264
|
+
→ signal(sig, from=self)
|
|
265
|
+
→ mark(edge) // path remembers
|
|
266
|
+
→ .then(task) // continuation fires
|
|
267
|
+
→ signal(next) // chain continues
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Concurrency safe. No global state.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Multi-Machine Collaboration
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
Machine A Machine B
|
|
278
|
+
┌──────────┐ ┌──────────┐
|
|
279
|
+
│ router │──signal──→ TypeDB ←──signal──│ router │
|
|
280
|
+
│ │←─paths───→ ←──paths──│ │
|
|
281
|
+
└──────────┘ └──────────┘
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Each machine runs one router process. TypeDB is shared.
|
|
285
|
+
Pheromone builds across machines. The substrate learns end-to-end paths.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
*Signal. Mark. Warn. Follow. Fade. Highway. Queue. Evolve. Know.*
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Verb Contracts
|
|
294
|
+
|
|
295
|
+
Each of the 6 verbs has a **pre / post / invariant** contract. Spec lives in `plans/contracts.md` — loaded only when editing a verb implementation, not every session.
|
|
296
|
+
|
|
297
|
+
New verb? You need: contract block in `plans/contracts.md`, row in `one-ie/CLAUDE.md` § The 6 verbs, contract gate in `.claude/agents/w4-verify.md` step 2.5. If you can't write the contract, you can't ship the verb.
|
package/rules/react.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.tsx"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# React 19 Rules
|
|
7
|
+
|
|
8
|
+
Apply to `*.tsx`
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Types
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
interface Props {
|
|
16
|
+
agent: Agent
|
|
17
|
+
onSelect?: (id: string) => void
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function AgentCard({ agent, onSelect }: Props) { ... }
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Always type props. Always.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Structure
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
// 1. Imports
|
|
31
|
+
import { useState } from 'react'
|
|
32
|
+
import { Card } from '@/components/ui/card'
|
|
33
|
+
|
|
34
|
+
// 2. Types
|
|
35
|
+
interface Props { ... }
|
|
36
|
+
|
|
37
|
+
// 3. Component
|
|
38
|
+
export function Component({ prop }: Props) {
|
|
39
|
+
// Hooks
|
|
40
|
+
const [state, setState] = useState()
|
|
41
|
+
|
|
42
|
+
// Handlers
|
|
43
|
+
const handle = () => { ... }
|
|
44
|
+
|
|
45
|
+
// Render
|
|
46
|
+
return ( ... )
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## React 19
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
// Actions (not onSubmit)
|
|
56
|
+
<form action={formAction}>
|
|
57
|
+
|
|
58
|
+
// use() for promises
|
|
59
|
+
const data = use(promise) // in Suspense
|
|
60
|
+
|
|
61
|
+
// Transitions
|
|
62
|
+
const [isPending, startTransition] = useTransition()
|
|
63
|
+
|
|
64
|
+
// Optimistic
|
|
65
|
+
const [optimistic, addOptimistic] = useOptimistic(state, fn)
|
|
66
|
+
|
|
67
|
+
// ref as prop (no forwardRef)
|
|
68
|
+
function Input({ ref, ...props }) { ... }
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## State
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
// Simple
|
|
77
|
+
const [open, setOpen] = useState(false)
|
|
78
|
+
|
|
79
|
+
// Complex
|
|
80
|
+
const [state, dispatch] = useReducer(reducer, init)
|
|
81
|
+
|
|
82
|
+
// Async (React 19)
|
|
83
|
+
const [state, action, pending] = useActionState(fn, init)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Styling
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { cn } from '@/lib/utils'
|
|
92
|
+
|
|
93
|
+
<div className={cn(
|
|
94
|
+
"base-classes",
|
|
95
|
+
isActive && "active-classes",
|
|
96
|
+
className
|
|
97
|
+
)} />
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Exports
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
// Named (good)
|
|
106
|
+
export function AgentCard() { ... }
|
|
107
|
+
|
|
108
|
+
// Default (avoid)
|
|
109
|
+
export default function AgentCard() { ... }
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## With Substrate
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
import { colony } from '@/engine/substrate'
|
|
118
|
+
|
|
119
|
+
export function SwarmView() {
|
|
120
|
+
const [net] = useState(() => colony())
|
|
121
|
+
const [highways, setHighways] = useState([])
|
|
122
|
+
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
const interval = setInterval(() => {
|
|
125
|
+
net.fade(0.1)
|
|
126
|
+
setHighways(net.highways(10))
|
|
127
|
+
}, 1000)
|
|
128
|
+
return () => clearInterval(interval)
|
|
129
|
+
}, [net])
|
|
130
|
+
|
|
131
|
+
return <Graph edges={highways} />
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
*React 19. Typed. Clean.*
|
package/rules/ui.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "one.ie/web/src/components/**/*.tsx"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UI Rules
|
|
7
|
+
|
|
8
|
+
Apply to `src/components/**/*.tsx`
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Every onClick Is a Signal
|
|
13
|
+
|
|
14
|
+
Every interactive onClick handler MUST call `emitClick(id, payload?)` before the local handler.
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { emitClick } from '@/lib/ui-signal'
|
|
18
|
+
|
|
19
|
+
// GOOD
|
|
20
|
+
<Button onClick={() => { emitClick('ui:chat:copy'); handleCopy() }}>Copy</Button>
|
|
21
|
+
|
|
22
|
+
// BAD — no signal emitted
|
|
23
|
+
<Button onClick={handleCopy}>Copy</Button>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Receiver naming: `ui:<surface>:<action>` where surface is the component or page name (lowercase) and action is an intent verb.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Receiver Naming
|
|
31
|
+
|
|
32
|
+
| Surface | Actions | Examples |
|
|
33
|
+
|---------|---------|---------|
|
|
34
|
+
| `chat` | copy, stop, claim, send, retry | `ui:chat:copy`, `ui:chat:stop` |
|
|
35
|
+
| `settings` | close, save, reset | `ui:settings:close`, `ui:settings:save` |
|
|
36
|
+
| `memory` | reveal, forget, expand | `ui:memory:reveal`, `ui:memory:forget` |
|
|
37
|
+
| `demo` | run, reset, next | `ui:demo:run`, `ui:demo:reset` |
|
|
38
|
+
|
|
39
|
+
Format: `ui:<surface>:<action>` — all lowercase, colon-delimited.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Exemptions
|
|
44
|
+
|
|
45
|
+
onClick handlers that do NOT need `emitClick`:
|
|
46
|
+
|
|
47
|
+
- **Purely visual toggles** with no semantic meaning (accordion open/close, tooltip show/hide)
|
|
48
|
+
- **Internal navigation** that calls `router.push` — the route change is the signal
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## ADL Contract
|
|
53
|
+
|
|
54
|
+
`ui:*` receivers have `sensitivity=public`, `lifecycle=active` by convention.
|
|
55
|
+
|
|
56
|
+
No TypeDB entry needed — the ADL lifecycle gate passes through for unknown receivers.
|
|
57
|
+
|
|
58
|
+
See `docs/ADL-integration.md` for gate shape, `docs/rich-messages.md` for RichMessage contract.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Rich Payload
|
|
63
|
+
|
|
64
|
+
Use `payload` for clicks that carry semantic data: payment actions, embed interactions.
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { emitClick } from '@/lib/ui-signal'
|
|
68
|
+
|
|
69
|
+
// Claim button — carries payment metadata
|
|
70
|
+
<Button onClick={() => emitClick('ui:chat:claim', {
|
|
71
|
+
type: 'payment',
|
|
72
|
+
payment: { receiver, amount, action: 'claim' }
|
|
73
|
+
})}>
|
|
74
|
+
Claim
|
|
75
|
+
</Button>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
See `docs/rich-messages.md` for the full `RichMessage` type definition.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
*Signal first. Then handle.*
|