@calimero-network/agent-skills 0.2.0 → 0.4.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 (78) hide show
  1. package/README.md +137 -17
  2. package/SKILL.md +31 -23
  3. package/package.json +2 -2
  4. package/scripts/install.js +3 -3
  5. package/scripts/test.js +6 -15
  6. package/skills/calimero-abi-codegen/SKILL.md +121 -22
  7. package/skills/calimero-abi-codegen/references/abi-format.md +3 -5
  8. package/skills/calimero-abi-codegen/references/generated-output.md +12 -4
  9. package/skills/calimero-abi-codegen/rules/schema-version.md +11 -4
  10. package/skills/calimero-abi-codegen/rules/unique-names.md +2 -6
  11. package/skills/calimero-client-js/SKILL.md +127 -22
  12. package/skills/calimero-client-js/references/auth.md +18 -10
  13. package/skills/calimero-client-js/references/rpc-calls.md +15 -21
  14. package/skills/calimero-client-js/references/sso.md +9 -9
  15. package/skills/calimero-client-js/references/websocket-events.md +73 -59
  16. package/skills/calimero-client-js/rules/camelcase-api.md +10 -7
  17. package/skills/calimero-client-js/rules/token-refresh.md +59 -21
  18. package/skills/calimero-client-py/SKILL.md +26 -10
  19. package/skills/calimero-client-py/references/api.md +41 -43
  20. package/skills/calimero-client-py/references/auth.md +7 -7
  21. package/skills/calimero-client-py/rules/async-usage.md +27 -31
  22. package/skills/calimero-client-py/rules/stable-node-name.md +7 -7
  23. package/skills/calimero-core/SKILL.md +135 -0
  24. package/skills/calimero-core/references/architecture.md +101 -0
  25. package/skills/calimero-core/references/jsonrpc-protocol.md +192 -0
  26. package/skills/calimero-core/references/namespaces-groups.md +94 -0
  27. package/skills/calimero-core/references/storage-types.md +118 -0
  28. package/skills/calimero-core/references/websocket-events.md +142 -0
  29. package/skills/calimero-core/rules/context-is-not-app.md +35 -0
  30. package/skills/calimero-core/rules/crdt-types-only.md +55 -0
  31. package/skills/calimero-desktop/SKILL.md +25 -14
  32. package/skills/calimero-desktop/references/sso-integration.md +49 -22
  33. package/skills/calimero-desktop/rules/sso-fallback.md +3 -2
  34. package/skills/calimero-merobox/SKILL.md +255 -28
  35. package/skills/calimero-merobox/references/ci-integration.md +3 -2
  36. package/skills/calimero-merobox/references/workflow-files.md +7 -5
  37. package/skills/calimero-merobox/rules/docker-required.md +7 -6
  38. package/skills/calimero-meroctl/SKILL.md +68 -0
  39. package/skills/calimero-meroctl/references/commands.md +177 -0
  40. package/skills/calimero-meroctl/references/scripting.md +80 -0
  41. package/skills/calimero-meroctl/rules/call-view-flag.md +28 -0
  42. package/skills/calimero-meroctl/rules/register-node-once.md +34 -0
  43. package/skills/calimero-merod/SKILL.md +49 -0
  44. package/skills/calimero-merod/references/health-endpoints.md +90 -0
  45. package/skills/calimero-merod/references/init-flags.md +84 -0
  46. package/skills/calimero-merod/rules/init-before-run.md +40 -0
  47. package/skills/calimero-merod/rules/port-assignments.md +33 -0
  48. package/skills/calimero-node/SKILL.md +52 -35
  49. package/skills/calimero-node/references/context-lifecycle.md +34 -17
  50. package/skills/calimero-node/references/meroctl-commands.md +89 -99
  51. package/skills/calimero-node/rules/app-vs-context.md +4 -4
  52. package/skills/calimero-registry/SKILL.md +110 -31
  53. package/skills/calimero-registry/references/bundle-and-push.md +99 -34
  54. package/skills/calimero-registry/references/manifest-format.md +56 -35
  55. package/skills/calimero-registry/references/mero-sign.md +10 -9
  56. package/skills/calimero-registry/rules/key-security.md +3 -2
  57. package/skills/calimero-registry/rules/sign-before-pack.md +5 -5
  58. package/skills/calimero-rust-sdk/SKILL.md +154 -44
  59. package/skills/calimero-rust-sdk/references/blob-api.md +119 -0
  60. package/skills/calimero-rust-sdk/references/event-handlers.md +122 -0
  61. package/skills/calimero-rust-sdk/references/events.md +2 -1
  62. package/skills/calimero-rust-sdk/references/examples.md +81 -29
  63. package/skills/calimero-rust-sdk/references/migrations.md +123 -0
  64. package/skills/calimero-rust-sdk/references/nested-crdts.md +113 -0
  65. package/skills/calimero-rust-sdk/references/private-storage.md +76 -34
  66. package/skills/calimero-rust-sdk/references/state-collections.md +106 -21
  67. package/skills/calimero-rust-sdk/references/user-and-frozen-storage.md +169 -0
  68. package/skills/calimero-rust-sdk/rules/app-macro-placement.md +5 -2
  69. package/skills/calimero-rust-sdk/rules/no-std-collections.md +5 -2
  70. package/skills/calimero-rust-sdk/rules/state-derives.md +45 -0
  71. package/skills/calimero-rust-sdk/rules/wasm-constraints.md +12 -10
  72. package/skills/calimero-sdk-js/SKILL.md +145 -0
  73. package/skills/calimero-sdk-js/references/build-pipeline.md +98 -0
  74. package/skills/calimero-sdk-js/references/collections.md +132 -0
  75. package/skills/calimero-sdk-js/references/events.md +63 -0
  76. package/skills/calimero-sdk-js/rules/crdt-only-state.md +47 -0
  77. package/skills/calimero-sdk-js/rules/no-console-log.md +38 -0
  78. package/skills/calimero-sdk-js/rules/view-decorator.md +48 -0
@@ -0,0 +1,132 @@
1
+ # CRDT Collections
2
+
3
+ All persistent state in a `calimero-sdk-js` app must use CRDT types from
4
+ `@calimero-network/calimero-sdk-js/collections`.
5
+
6
+ ## Counter (G-Counter)
7
+
8
+ Distributed counting. The value is the sum across all contributing nodes.
9
+
10
+ ```typescript
11
+ import { Counter } from '@calimero-network/calimero-sdk-js/collections';
12
+
13
+ const counter = new Counter();
14
+ counter.increment(); // +1
15
+ counter.incrementBy(5n); // +5 (bigint)
16
+ const total = counter.value(); // bigint
17
+ ```
18
+
19
+ > Counter values are always `bigint`. Do not compare with `=== 0` — use `=== 0n`.
20
+
21
+ ## UnorderedMap\<K, V\>
22
+
23
+ Key-value store with Last-Write-Wins conflict resolution per key.
24
+
25
+ ```typescript
26
+ import { UnorderedMap } from '@calimero-network/calimero-sdk-js/collections';
27
+
28
+ const map = new UnorderedMap<string, string>();
29
+ map.set('key', 'value');
30
+ const val = map.get('key'); // 'value' | undefined
31
+ const exists = map.has('key'); // boolean
32
+ map.remove('key');
33
+ const all = map.entries(); // [['key', 'value'], ...]
34
+ ```
35
+
36
+ ## UnorderedSet\<T\>
37
+
38
+ Set of unique values with Last-Write-Wins per element.
39
+
40
+ ```typescript
41
+ import { UnorderedSet } from '@calimero-network/calimero-sdk-js/collections';
42
+
43
+ const set = new UnorderedSet<string>();
44
+ set.add('item'); // true on first insert, false if already present
45
+ set.has('item'); // true
46
+ set.delete('item');
47
+ const items = set.toArray();
48
+ ```
49
+
50
+ ## Vector\<T\>
51
+
52
+ Ordered list. Conflicts resolved by position.
53
+
54
+ ```typescript
55
+ import { Vector } from '@calimero-network/calimero-sdk-js/collections';
56
+
57
+ const vec = new Vector<string>();
58
+ vec.push('first');
59
+ vec.push('second');
60
+ const item = vec.get(0); // 'first'
61
+ const last = vec.pop(); // 'second'
62
+ const len = vec.len(); // 1 (bigint)
63
+ ```
64
+
65
+ ## LwwRegister\<T\>
66
+
67
+ Holds a single value. Last write wins based on timestamp.
68
+
69
+ ```typescript
70
+ import { LwwRegister } from '@calimero-network/calimero-sdk-js/collections';
71
+
72
+ const reg = new LwwRegister<string>();
73
+ reg.set('current value');
74
+ const current = reg.get(); // 'current value' | undefined
75
+ ```
76
+
77
+ ## UserStorage
78
+
79
+ User-owned signed data. Writes are verified by the owner's signature.
80
+
81
+ ```typescript
82
+ import { UserStorage } from '@calimero-network/calimero-sdk-js/collections';
83
+
84
+ const storage = new UserStorage<string>();
85
+ storage.set(executorId, 'my value');
86
+ const val = storage.get(executorId);
87
+ ```
88
+
89
+ ## FrozenStorage
90
+
91
+ Immutable, content-addressed storage. Write once; content never changes.
92
+
93
+ ```typescript
94
+ import { FrozenStorage } from '@calimero-network/calimero-sdk-js/collections';
95
+
96
+ const frozen = new FrozenStorage<string>();
97
+ const id = frozen.store('immutable content');
98
+ const val = frozen.get(id);
99
+ ```
100
+
101
+ ## Nested collections
102
+
103
+ Nested structures propagate changes automatically — no manual re-serialization needed.
104
+
105
+ ```typescript
106
+ // Map<projectId, Set<tags>> — just works
107
+ const projectTags = new UnorderedMap<string, UnorderedSet<string>>();
108
+
109
+ const tags = new UnorderedSet<string>();
110
+ tags.add('urgent');
111
+ projectTags.set('proj:123', tags);
112
+
113
+ // Modifying the inner set propagates automatically
114
+ projectTags.get('proj:123')?.add('high-priority');
115
+ ```
116
+
117
+ ## State field initialization
118
+
119
+ CRDT fields must be initialized inline in the `@State` class:
120
+
121
+ ```typescript
122
+ @State
123
+ export class AppState {
124
+ // ✅ Inline initialization
125
+ items: UnorderedMap<string, string> = new UnorderedMap();
126
+ count: Counter = new Counter();
127
+
128
+ // ❌ Never use plain JS types for state
129
+ // plainMap: Map<string, string> = new Map();
130
+ // array: string[] = [];
131
+ }
132
+ ```
@@ -0,0 +1,63 @@
1
+ # Events
2
+
3
+ Events let your app push real-time notifications to all context members. They are emitted during
4
+ mutation methods and received by clients via WebSocket.
5
+
6
+ ## Emitting events
7
+
8
+ ```typescript
9
+ import { emit, emitWithHandler } from '@calimero-network/calimero-sdk-js';
10
+
11
+ // Simple event — clients receive it and dispatch themselves
12
+ emit({ type: 'ItemAdded', key: 'foo', value: 'bar' });
13
+
14
+ // Event with a named handler — clients call `onItemAdded(event)` if defined
15
+ emitWithHandler({ type: 'ItemAdded', key: 'foo' }, 'onItemAdded');
16
+ ```
17
+
18
+ Events can only be emitted inside mutation methods (not `@View()` methods).
19
+
20
+ ## Receiving events on the client
21
+
22
+ Clients use `WsSubscriptionsClient` from `@calimero-network/calimero-client`:
23
+
24
+ ```typescript
25
+ import {
26
+ WsSubscriptionsClient,
27
+ getAppEndpointKey,
28
+ getContextId,
29
+ } from '@calimero-network/calimero-client';
30
+
31
+ const ws = new WsSubscriptionsClient(getAppEndpointKey()!, '/ws');
32
+ await ws.connect();
33
+ ws.subscribe([getContextId()!]);
34
+
35
+ ws.addCallback((event) => {
36
+ if (event.type === 'ExecutionEvent') {
37
+ for (const e of event.data.events) {
38
+ // e.kind — matches the `type` field from emit()
39
+ // e.data — the rest of the emitted object
40
+ console.log(e.kind, e.data);
41
+ }
42
+ }
43
+ });
44
+ ```
45
+
46
+ ## Event typing (recommended)
47
+
48
+ Define a discriminated union to type your events:
49
+
50
+ ```typescript
51
+ type AppEvent =
52
+ | { type: 'ItemAdded'; key: string; value: string }
53
+ | { type: 'ItemRemoved'; key: string };
54
+
55
+ // Emit
56
+ emit({ type: 'ItemAdded', key: 'foo', value: 'bar' } satisfies AppEvent);
57
+ ```
58
+
59
+ ## Important
60
+
61
+ - Events are best-effort — clients may miss them if disconnected
62
+ - Do not rely on events for state consistency — use RPC calls to query current state
63
+ - Emitting from a `@View()` method is not supported
@@ -0,0 +1,47 @@
1
+ # Rule: All @State fields must be CRDT types
2
+
3
+ Every field on a `@State` class must be a CRDT collection from
4
+ `@calimero-network/calimero-sdk-js/collections`. Plain JavaScript types are not persisted or
5
+ synchronized.
6
+
7
+ ## WRONG — plain JS types in state:
8
+
9
+ ```typescript
10
+ @State
11
+ export class AppState {
12
+ items: Map<string, string> = new Map(); // ✗ — not a CRDT, not synced
13
+ tags: string[] = []; // ✗ — not a CRDT, not synced
14
+ name: string = ''; // ✗ — use LwwRegister instead
15
+ count: number = 0; // ✗ — use Counter instead
16
+ }
17
+ ```
18
+
19
+ ## CORRECT — CRDT types:
20
+
21
+ ```typescript
22
+ @State
23
+ export class AppState {
24
+ items: UnorderedMap<string, string> = new UnorderedMap();
25
+ tags: UnorderedSet<string> = new UnorderedSet();
26
+ name: LwwRegister<string> = new LwwRegister();
27
+ count: Counter = new Counter();
28
+ }
29
+ ```
30
+
31
+ ## Why this matters
32
+
33
+ Plain JS types are not serialized to the node's CRDT storage. State that uses `Map`, `Set`, `Array`,
34
+ or primitives directly will be lost on the next call and will never sync to other nodes in the
35
+ context.
36
+
37
+ ## Choosing the right CRDT
38
+
39
+ | Data shape | Use |
40
+ | ------------------------- | -------------------- |
41
+ | Counting (monotonic) | `Counter` |
42
+ | Key-value lookup | `UnorderedMap<K, V>` |
43
+ | Unique membership | `UnorderedSet<T>` |
44
+ | Ordered list | `Vector<T>` |
45
+ | Single value (overwrites) | `LwwRegister<T>` |
46
+ | User-owned signed data | `UserStorage<T>` |
47
+ | Immutable content | `FrozenStorage<T>` |
@@ -0,0 +1,38 @@
1
+ # Rule: Use env.log() — not console.log()
2
+
3
+ `console` is not available in the QuickJS/WASM runtime. Calling `console.log()` will throw a runtime
4
+ error. Use `env.log()` from the SDK's env module instead.
5
+
6
+ ## WRONG:
7
+
8
+ ```typescript
9
+ console.log('Processing item:', key); // ✗ — throws at runtime
10
+ console.error('Something went wrong'); // ✗ — throws at runtime
11
+ ```
12
+
13
+ ## CORRECT:
14
+
15
+ ```typescript
16
+ import * as env from '@calimero-network/calimero-sdk-js/env';
17
+
18
+ env.log(`Processing item: ${key}`); // ✓ — output appears in node logs
19
+ env.log(`Error: ${error}`); // ✓
20
+ ```
21
+
22
+ ## env.log() format
23
+
24
+ `env.log()` accepts a single string. Use template literals for dynamic values:
25
+
26
+ ```typescript
27
+ env.log(`set called: key=${key}, value=${value}`);
28
+ env.log(`counter is now ${this.count.value()}`);
29
+ ```
30
+
31
+ ## Other env utilities
32
+
33
+ ```typescript
34
+ import * as env from '@calimero-network/calimero-sdk-js/env';
35
+
36
+ // Get the calling executor's public key (Uint8Array, 32 bytes)
37
+ const executorId = env.executorId();
38
+ ```
@@ -0,0 +1,48 @@
1
+ # Rule: @View() is required on read-only methods
2
+
3
+ Every method that does not modify state must be decorated with `@View()`. Without it, the runtime
4
+ will persist state after every call — even when nothing changed — causing unnecessary storage writes
5
+ and cross-node syncs.
6
+
7
+ ## WRONG — read-only method without @View():
8
+
9
+ ```typescript
10
+ @Logic(AppState)
11
+ export class AppLogic extends AppState {
12
+ // ✗ — no @View(), triggers persistence on every call
13
+ getItem(key: string): string | null {
14
+ return this.items.get(key) ?? null;
15
+ }
16
+
17
+ // ✗ — returning a count without @View()
18
+ getCount(): bigint {
19
+ return this.count.value();
20
+ }
21
+ }
22
+ ```
23
+
24
+ ## CORRECT:
25
+
26
+ ```typescript
27
+ @Logic(AppState)
28
+ export class AppLogic extends AppState {
29
+ @View()
30
+ getItem(key: string): string | null {
31
+ return this.items.get(key) ?? null;
32
+ }
33
+
34
+ @View()
35
+ getCount(): bigint {
36
+ return this.count.value();
37
+ }
38
+ }
39
+ ```
40
+
41
+ ## How to tell if a method needs @View()
42
+
43
+ A method is read-only if it:
44
+
45
+ - Does not call any mutation methods on CRDT fields (`set`, `insert`, `add`, `push`, `increment`,
46
+ etc.)
47
+ - Does not call `emit()` or `emitWithHandler()`
48
+ - Only reads values and returns results