@calimero-network/agent-skills 0.3.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 -28
  3. package/package.json +1 -1
  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 +126 -31
  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 -92
  16. package/skills/calimero-client-js/rules/camelcase-api.md +10 -7
  17. package/skills/calimero-client-js/rules/token-refresh.md +11 -11
  18. package/skills/calimero-client-py/SKILL.md +25 -13
  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 +24 -19
  32. package/skills/calimero-desktop/references/sso-integration.md +2 -2
  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 +50 -39
  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 +9 -10
  71. package/skills/calimero-rust-sdk/rules/wasm-constraints.md +12 -10
  72. package/skills/calimero-sdk-js/SKILL.md +34 -26
  73. package/skills/calimero-sdk-js/references/build-pipeline.md +6 -6
  74. package/skills/calimero-sdk-js/references/collections.md +11 -11
  75. package/skills/calimero-sdk-js/references/events.md +7 -3
  76. package/skills/calimero-sdk-js/rules/crdt-only-state.md +18 -18
  77. package/skills/calimero-sdk-js/rules/no-console-log.md +6 -6
  78. package/skills/calimero-sdk-js/rules/view-decorator.md +6 -4
@@ -29,6 +29,9 @@ impl AppState {
29
29
  }
30
30
  ```
31
31
 
32
- **Why:** `#[app::state]` and `#[app::logic]` are proc macros that transform impl blocks to register the type with the SDK runtime. The struct itself only needs the derive macros (`Default`, `BorshDeserialize`, `BorshSerialize`).
32
+ **Why:** `#[app::state]` and `#[app::logic]` are proc macros that transform impl blocks to register
33
+ the type with the SDK runtime. The struct itself only needs the derive macros (`Default`,
34
+ `BorshDeserialize`, `BorshSerialize`).
33
35
 
34
- **Also:** `#[app::init]` marks the constructor — called once when the context is created. It must return the state type, not `Self`.
36
+ **Also:** `#[app::init]` marks the constructor — called once when the context is created. It must
37
+ return the state type, not `Self`.
@@ -22,6 +22,9 @@ pub struct AppState {
22
22
  }
23
23
  ```
24
24
 
25
- **Why:** `std::collections` types do not participate in the CRDT merge process. Data written to them by one node will never reach other context members. The bug is silent — the app compiles and runs correctly on one node, but state diverges in multi-member contexts.
25
+ **Why:** `std::collections` types do not participate in the CRDT merge process. Data written to them
26
+ by one node will never reach other context members. The bug is silent — the app compiles and runs
27
+ correctly on one node, but state diverges in multi-member contexts.
26
28
 
27
- **Applies to:** `HashMap`, `BTreeMap`, `HashSet`, `BTreeSet`, `Vec` (for shared state). `Vec` is fine for temporary local values inside a method, just not as a field in the state struct.
29
+ **Applies to:** `HashMap`, `BTreeMap`, `HashSet`, `BTreeSet`, `Vec` (for shared state). `Vec` is
30
+ fine for temporary local values inside a method, just not as a field in the state struct.
@@ -1,8 +1,7 @@
1
1
  # Rule: State struct must derive Default, BorshDeserialize, BorshSerialize
2
2
 
3
- The three derives are all required. Missing any one of them causes a **runtime panic**,
4
- not a compile error — the app will install and start, then crash when the context is
5
- first accessed.
3
+ The three derives are all required. Missing any one of them causes a **runtime panic**, not a
4
+ compile error — the app will install and start, then crash when the context is first accessed.
6
5
 
7
6
  ## WRONG — missing derives:
8
7
 
@@ -30,11 +29,11 @@ pub struct AppState {
30
29
 
31
30
  ## What each derive does
32
31
 
33
- | Derive | Required for |
34
- | --- | --- |
35
- | `Default` | `#[app::init]` calls `AppState::default()` as the baseline |
36
- | `BorshDeserialize` | Loading state from node storage on every method call |
37
- | `BorshSerialize` | Saving state to node storage after every mutation |
32
+ | Derive | Required for |
33
+ | ------------------ | ---------------------------------------------------------- |
34
+ | `Default` | `#[app::init]` calls `AppState::default()` as the baseline |
35
+ | `BorshDeserialize` | Loading state from node storage on every method call |
36
+ | `BorshSerialize` | Saving state to node storage after every mutation |
38
37
 
39
38
  ## Import
40
39
 
@@ -42,5 +41,5 @@ pub struct AppState {
42
41
  use calimero_sdk::borsh::{BorshDeserialize, BorshSerialize};
43
42
  ```
44
43
 
45
- Do not use `borsh` crate directly — import from `calimero_sdk::borsh` to ensure
46
- version compatibility.
44
+ Do not use `borsh` crate directly — import from `calimero_sdk::borsh` to ensure version
45
+ compatibility.
@@ -2,16 +2,16 @@
2
2
 
3
3
  Calimero apps run in a sandboxed WASM environment. The following are **not available**:
4
4
 
5
- | Forbidden | Use instead |
6
- | --- | --- |
7
- | `std::thread::spawn` | Not supported — WASM is single-threaded |
5
+ | Forbidden | Use instead |
6
+ | --------------------------------------------- | ----------------------------------------------- |
7
+ | `std::thread::spawn` | Not supported — WASM is single-threaded |
8
8
  | `tokio`, `async-std`, `async fn` in app logic | Not supported — all app methods are synchronous |
9
- | `std::fs`, file I/O | Use `env::private_storage_write/read` |
10
- | `std::net`, HTTP calls outbound | Not supported in WASM runtime |
11
- | `println!`, `eprintln!` | Use `calimero_sdk::env::log(&str)` |
12
- | System time (`std::time::SystemTime`) | Use `calimero_sdk::env::block_timestamp()` |
13
- | Environment variables | Not accessible from WASM |
14
- | Random number generation via `rand` | Use `calimero_sdk::env::random_seed()` |
9
+ | `std::fs`, file I/O | Use `env::private_storage_write/read` |
10
+ | `std::net`, HTTP calls outbound | Not supported in WASM runtime |
11
+ | `println!`, `eprintln!` | Use `calimero_sdk::env::log(&str)` |
12
+ | System time (`std::time::SystemTime`) | Use `calimero_sdk::env::block_timestamp()` |
13
+ | Environment variables | Not accessible from WASM |
14
+ | Random number generation via `rand` | Use `calimero_sdk::env::random_seed()` |
15
15
 
16
16
  ## Logging
17
17
 
@@ -32,4 +32,6 @@ let ts = env::block_timestamp(); // u64 nanoseconds
32
32
 
33
33
  ## Why
34
34
 
35
- The `merod` WASM runtime is deterministic by design. Non-deterministic operations (threads, I/O, time, random) would break the CRDT synchronization guarantees — every node must reach the same state given the same sequence of operations.
35
+ The `merod` WASM runtime is deterministic by design. Non-deterministic operations (threads, I/O,
36
+ time, random) would break the CRDT synchronization guarantees — every node must reach the same state
37
+ given the same sequence of operations.
@@ -1,12 +1,12 @@
1
1
  # calimero-sdk-js — Agent Instructions
2
2
 
3
3
  You are helping a developer **build a Calimero P2P application in TypeScript** using
4
- `@calimero-network/calimero-sdk-js`. The app compiles to WebAssembly and runs inside the
5
- `merod` node runtime.
4
+ `@calimero-network/calimero-sdk-js`. The app compiles to WebAssembly and runs inside the `merod`
5
+ node runtime.
6
6
 
7
- > **NOT this skill** if the developer is connecting a browser/Node.js *frontend* to a node
8
- > (that's `calimero-client-js` / `@calimero-network/calimero-client`). This skill is for
9
- > writing the application logic that *runs on the node*.
7
+ > **NOT this skill** if the developer is connecting a browser/Node.js _frontend_ to a node (that's
8
+ > `calimero-client-js` / `@calimero-network/calimero-client`). This skill is for writing the
9
+ > application logic that _runs on the node_.
10
10
 
11
11
  ## Install
12
12
 
@@ -15,18 +15,18 @@ pnpm add @calimero-network/calimero-sdk-js
15
15
  pnpm add -D @calimero-network/calimero-cli-js typescript
16
16
  ```
17
17
 
18
- The CLI's `postinstall` hook downloads QuickJS, WASI-SDK, and Binaryen automatically.
19
- If you used `--ignore-scripts`, re-run with `pnpm install --ignore-scripts=false`.
18
+ The CLI's `postinstall` hook downloads QuickJS, WASI-SDK, and Binaryen automatically. If you used
19
+ `--ignore-scripts`, re-run with `pnpm install --ignore-scripts=false`.
20
20
 
21
21
  ## Core concepts
22
22
 
23
- | Concept | What it is |
24
- | --- | --- |
25
- | `@State` class | Persisted data — fields must be CRDT types |
26
- | `@Logic(StateClass)` class | Entry points callable via JSON-RPC; must extend the state class |
27
- | `@Init` static method | Seeds the initial state when context is first created |
28
- | `@View()` method | Read-only — skips persistence; required for query methods |
29
- | CRDT collection | Conflict-free type (`Counter`, `UnorderedMap`, etc.) — all state fields must use these |
23
+ | Concept | What it is |
24
+ | -------------------------- | -------------------------------------------------------------------------------------- |
25
+ | `@State` class | Persisted data — fields must be CRDT types |
26
+ | `@Logic(StateClass)` class | Entry points callable via JSON-RPC; must extend the state class |
27
+ | `@Init` static method | Seeds the initial state when context is first created |
28
+ | `@View()` method | Read-only — skips persistence; required for query methods |
29
+ | CRDT collection | Conflict-free type (`Counter`, `UnorderedMap`, etc.) — all state fields must use these |
30
30
 
31
31
  ## Minimal app
32
32
 
@@ -61,16 +61,15 @@ export class KvLogic extends KvState {
61
61
 
62
62
  ## CRDT collections quick reference
63
63
 
64
- | Type | Use case | Key ops |
65
- | --- | --- | --- |
66
- | `Counter` | Distributed counting (returns `bigint`) | `increment()`, `incrementBy(n)`, `value()` |
67
- | `UnorderedMap<K,V>` | Key-value store (LWW per key) | `set()`, `get()`, `has()`, `remove()`, `entries()` |
68
- | `UnorderedSet<T>` | Unique membership (LWW per element) | `add()`, `has()`, `delete()`, `toArray()` |
69
- | `Vector<T>` | Ordered list | `push()`, `get(i)`, `pop()`, `len()` |
70
- | `LwwRegister<T>` | Single value (timestamp LWW) | `set()`, `get()` |
64
+ | Type | Use case | Key ops |
65
+ | ------------------- | --------------------------------------- | -------------------------------------------------- |
66
+ | `Counter` | Distributed counting (returns `bigint`) | `increment()`, `incrementBy(n)`, `value()` |
67
+ | `UnorderedMap<K,V>` | Key-value store (LWW per key) | `set()`, `get()`, `has()`, `remove()`, `entries()` |
68
+ | `UnorderedSet<T>` | Unique membership (LWW per element) | `add()`, `has()`, `delete()`, `toArray()` |
69
+ | `Vector<T>` | Ordered list | `push()`, `get(i)`, `pop()`, `len()` |
70
+ | `LwwRegister<T>` | Single value (timestamp LWW) | `set()`, `get()` |
71
71
 
72
- Nested collections (`Map<K, Set<V>>`) propagate changes automatically — no manual
73
- re-serialization.
72
+ Nested collections (`Map<K, Set<V>>`) propagate changes automatically — no manual re-serialization.
74
73
 
75
74
  ## Build & deploy
76
75
 
@@ -105,7 +104,8 @@ meroctl --node-name <NODE> call \
105
104
  - `@Init` must be a static method that returns the state class instance
106
105
  - `@Logic(StateClass)` must extend the state class
107
106
  - No async, no I/O, no threads in app logic — the WASM runtime is synchronous
108
- - **Windows: building is not supported natively — use WSL** (QuickJS/WASI-SDK toolchain requires Linux/macOS)
107
+ - **Windows: building is not supported natively — use WSL** (QuickJS/WASI-SDK toolchain requires
108
+ Linux/macOS)
109
109
 
110
110
  ## Events
111
111
 
@@ -131,7 +131,15 @@ const val = secret.get();
131
131
 
132
132
  Private entries are never broadcast to other nodes.
133
133
 
134
+ ## Related skills
135
+
136
+ - **`calimero-core`** — runtime concepts (context/app model, JSON-RPC protocol, WebSocket events,
137
+ CRDT type taxonomy)
138
+ - **`calimero-meroctl`** — full `meroctl` CLI reference for deploying and testing the app
139
+ - **`calimero-client-js`** — connecting a browser/React frontend to the node (not building app
140
+ logic)
141
+
134
142
  ## References
135
143
 
136
- See `references/` for CRDT collections, events, and build pipeline details.
137
- See `rules/` for hard constraints.
144
+ See `references/` for CRDT collections, events, and build pipeline details. See `rules/` for hard
145
+ constraints.
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Pipeline stages
6
6
 
7
- ```
7
+ ```text
8
8
  TypeScript → Rollup → QuickJS → WASI-SDK → Binaryen → .wasm
9
9
  Source Bundle C bytecode WASM Optimized
10
10
  ```
@@ -84,11 +84,11 @@ merobox bootstrap run examples/counter/workflows/counter-js.yml --log-level=trac
84
84
 
85
85
  ## Platform support
86
86
 
87
- | Platform | Supported |
88
- | --- | --- |
89
- | macOS (x64, arm64) | Yes |
90
- | Linux (x64, arm64) | Yes |
91
- | Windows (native) | No — use WSL |
87
+ | Platform | Supported |
88
+ | ------------------ | ------------ |
89
+ | macOS (x64, arm64) | Yes |
90
+ | Linux (x64, arm64) | Yes |
91
+ | Windows (native) | No — use WSL |
92
92
 
93
93
  ## Definition of done (before PR)
94
94
 
@@ -11,9 +11,9 @@ Distributed counting. The value is the sum across all contributing nodes.
11
11
  import { Counter } from '@calimero-network/calimero-sdk-js/collections';
12
12
 
13
13
  const counter = new Counter();
14
- counter.increment(); // +1
15
- counter.incrementBy(5n); // +5 (bigint)
16
- const total = counter.value(); // bigint
14
+ counter.increment(); // +1
15
+ counter.incrementBy(5n); // +5 (bigint)
16
+ const total = counter.value(); // bigint
17
17
  ```
18
18
 
19
19
  > Counter values are always `bigint`. Do not compare with `=== 0` — use `=== 0n`.
@@ -27,10 +27,10 @@ import { UnorderedMap } from '@calimero-network/calimero-sdk-js/collections';
27
27
 
28
28
  const map = new UnorderedMap<string, string>();
29
29
  map.set('key', 'value');
30
- const val = map.get('key'); // 'value' | undefined
31
- const exists = map.has('key'); // boolean
30
+ const val = map.get('key'); // 'value' | undefined
31
+ const exists = map.has('key'); // boolean
32
32
  map.remove('key');
33
- const all = map.entries(); // [['key', 'value'], ...]
33
+ const all = map.entries(); // [['key', 'value'], ...]
34
34
  ```
35
35
 
36
36
  ## UnorderedSet\<T\>
@@ -41,8 +41,8 @@ Set of unique values with Last-Write-Wins per element.
41
41
  import { UnorderedSet } from '@calimero-network/calimero-sdk-js/collections';
42
42
 
43
43
  const set = new UnorderedSet<string>();
44
- set.add('item'); // true on first insert, false if already present
45
- set.has('item'); // true
44
+ set.add('item'); // true on first insert, false if already present
45
+ set.has('item'); // true
46
46
  set.delete('item');
47
47
  const items = set.toArray();
48
48
  ```
@@ -57,9 +57,9 @@ import { Vector } from '@calimero-network/calimero-sdk-js/collections';
57
57
  const vec = new Vector<string>();
58
58
  vec.push('first');
59
59
  vec.push('second');
60
- const item = vec.get(0); // 'first'
61
- const last = vec.pop(); // 'second'
62
- const len = vec.len(); // 1 (bigint)
60
+ const item = vec.get(0); // 'first'
61
+ const last = vec.pop(); // 'second'
62
+ const len = vec.len(); // 1 (bigint)
63
63
  ```
64
64
 
65
65
  ## LwwRegister\<T\>
@@ -1,7 +1,7 @@
1
1
  # Events
2
2
 
3
- Events let your app push real-time notifications to all context members.
4
- They are emitted during mutation methods and received by clients via WebSocket.
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
5
 
6
6
  ## Emitting events
7
7
 
@@ -22,7 +22,11 @@ Events can only be emitted inside mutation methods (not `@View()` methods).
22
22
  Clients use `WsSubscriptionsClient` from `@calimero-network/calimero-client`:
23
23
 
24
24
  ```typescript
25
- import { WsSubscriptionsClient, getAppEndpointKey, getContextId } from '@calimero-network/calimero-client';
25
+ import {
26
+ WsSubscriptionsClient,
27
+ getAppEndpointKey,
28
+ getContextId,
29
+ } from '@calimero-network/calimero-client';
26
30
 
27
31
  const ws = new WsSubscriptionsClient(getAppEndpointKey()!, '/ws');
28
32
  await ws.connect();
@@ -1,18 +1,18 @@
1
1
  # Rule: All @State fields must be CRDT types
2
2
 
3
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
5
- persisted or synchronized.
4
+ `@calimero-network/calimero-sdk-js/collections`. Plain JavaScript types are not persisted or
5
+ synchronized.
6
6
 
7
7
  ## WRONG — plain JS types in state:
8
8
 
9
9
  ```typescript
10
10
  @State
11
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
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
16
  }
17
17
  ```
18
18
 
@@ -30,18 +30,18 @@ export class AppState {
30
30
 
31
31
  ## Why this matters
32
32
 
33
- Plain JS types are not serialized to the node's CRDT storage. State that uses
34
- `Map`, `Set`, `Array`, or primitives directly will be lost on the next call and
35
- will never sync to other nodes in the context.
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
36
 
37
37
  ## Choosing the right CRDT
38
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>` |
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>` |
@@ -1,13 +1,13 @@
1
1
  # Rule: Use env.log() — not console.log()
2
2
 
3
- `console` is not available in the QuickJS/WASM runtime. Calling `console.log()` will
4
- throw a runtime error. Use `env.log()` from the SDK's env module instead.
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
5
 
6
6
  ## WRONG:
7
7
 
8
8
  ```typescript
9
- console.log('Processing item:', key); // ✗ — throws at runtime
10
- console.error('Something went wrong'); // ✗ — throws at runtime
9
+ console.log('Processing item:', key); // ✗ — throws at runtime
10
+ console.error('Something went wrong'); // ✗ — throws at runtime
11
11
  ```
12
12
 
13
13
  ## CORRECT:
@@ -15,8 +15,8 @@ console.error('Something went wrong'); // ✗ — throws at runtime
15
15
  ```typescript
16
16
  import * as env from '@calimero-network/calimero-sdk-js/env';
17
17
 
18
- env.log(`Processing item: ${key}`); // ✓ — output appears in node logs
19
- env.log(`Error: ${error}`); // ✓
18
+ env.log(`Processing item: ${key}`); // ✓ — output appears in node logs
19
+ env.log(`Error: ${error}`); // ✓
20
20
  ```
21
21
 
22
22
  ## env.log() format
@@ -1,8 +1,8 @@
1
1
  # Rule: @View() is required on read-only methods
2
2
 
3
- Every method that does not modify state must be decorated with `@View()`. Without it,
4
- the runtime will persist state after every call — even when nothing changed — causing
5
- unnecessary storage writes and cross-node syncs.
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
6
 
7
7
  ## WRONG — read-only method without @View():
8
8
 
@@ -41,6 +41,8 @@ export class AppLogic extends AppState {
41
41
  ## How to tell if a method needs @View()
42
42
 
43
43
  A method is read-only if it:
44
- - Does not call any mutation methods on CRDT fields (`set`, `insert`, `add`, `push`, `increment`, etc.)
44
+
45
+ - Does not call any mutation methods on CRDT fields (`set`, `insert`, `add`, `push`, `increment`,
46
+ etc.)
45
47
  - Does not call `emit()` or `emitWithHandler()`
46
48
  - Only reads values and returns results