@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.
- package/README.md +137 -17
- package/SKILL.md +31 -23
- package/package.json +2 -2
- package/scripts/install.js +3 -3
- package/scripts/test.js +6 -15
- package/skills/calimero-abi-codegen/SKILL.md +121 -22
- package/skills/calimero-abi-codegen/references/abi-format.md +3 -5
- package/skills/calimero-abi-codegen/references/generated-output.md +12 -4
- package/skills/calimero-abi-codegen/rules/schema-version.md +11 -4
- package/skills/calimero-abi-codegen/rules/unique-names.md +2 -6
- package/skills/calimero-client-js/SKILL.md +127 -22
- package/skills/calimero-client-js/references/auth.md +18 -10
- package/skills/calimero-client-js/references/rpc-calls.md +15 -21
- package/skills/calimero-client-js/references/sso.md +9 -9
- package/skills/calimero-client-js/references/websocket-events.md +73 -59
- package/skills/calimero-client-js/rules/camelcase-api.md +10 -7
- package/skills/calimero-client-js/rules/token-refresh.md +59 -21
- package/skills/calimero-client-py/SKILL.md +26 -10
- package/skills/calimero-client-py/references/api.md +41 -43
- package/skills/calimero-client-py/references/auth.md +7 -7
- package/skills/calimero-client-py/rules/async-usage.md +27 -31
- package/skills/calimero-client-py/rules/stable-node-name.md +7 -7
- package/skills/calimero-core/SKILL.md +135 -0
- package/skills/calimero-core/references/architecture.md +101 -0
- package/skills/calimero-core/references/jsonrpc-protocol.md +192 -0
- package/skills/calimero-core/references/namespaces-groups.md +94 -0
- package/skills/calimero-core/references/storage-types.md +118 -0
- package/skills/calimero-core/references/websocket-events.md +142 -0
- package/skills/calimero-core/rules/context-is-not-app.md +35 -0
- package/skills/calimero-core/rules/crdt-types-only.md +55 -0
- package/skills/calimero-desktop/SKILL.md +25 -14
- package/skills/calimero-desktop/references/sso-integration.md +49 -22
- package/skills/calimero-desktop/rules/sso-fallback.md +3 -2
- package/skills/calimero-merobox/SKILL.md +255 -28
- package/skills/calimero-merobox/references/ci-integration.md +3 -2
- package/skills/calimero-merobox/references/workflow-files.md +7 -5
- package/skills/calimero-merobox/rules/docker-required.md +7 -6
- package/skills/calimero-meroctl/SKILL.md +68 -0
- package/skills/calimero-meroctl/references/commands.md +177 -0
- package/skills/calimero-meroctl/references/scripting.md +80 -0
- package/skills/calimero-meroctl/rules/call-view-flag.md +28 -0
- package/skills/calimero-meroctl/rules/register-node-once.md +34 -0
- package/skills/calimero-merod/SKILL.md +49 -0
- package/skills/calimero-merod/references/health-endpoints.md +90 -0
- package/skills/calimero-merod/references/init-flags.md +84 -0
- package/skills/calimero-merod/rules/init-before-run.md +40 -0
- package/skills/calimero-merod/rules/port-assignments.md +33 -0
- package/skills/calimero-node/SKILL.md +52 -35
- package/skills/calimero-node/references/context-lifecycle.md +34 -17
- package/skills/calimero-node/references/meroctl-commands.md +89 -99
- package/skills/calimero-node/rules/app-vs-context.md +4 -4
- package/skills/calimero-registry/SKILL.md +110 -31
- package/skills/calimero-registry/references/bundle-and-push.md +99 -34
- package/skills/calimero-registry/references/manifest-format.md +56 -35
- package/skills/calimero-registry/references/mero-sign.md +10 -9
- package/skills/calimero-registry/rules/key-security.md +3 -2
- package/skills/calimero-registry/rules/sign-before-pack.md +5 -5
- package/skills/calimero-rust-sdk/SKILL.md +154 -44
- package/skills/calimero-rust-sdk/references/blob-api.md +119 -0
- package/skills/calimero-rust-sdk/references/event-handlers.md +122 -0
- package/skills/calimero-rust-sdk/references/events.md +2 -1
- package/skills/calimero-rust-sdk/references/examples.md +81 -29
- package/skills/calimero-rust-sdk/references/migrations.md +123 -0
- package/skills/calimero-rust-sdk/references/nested-crdts.md +113 -0
- package/skills/calimero-rust-sdk/references/private-storage.md +76 -34
- package/skills/calimero-rust-sdk/references/state-collections.md +106 -21
- package/skills/calimero-rust-sdk/references/user-and-frozen-storage.md +169 -0
- package/skills/calimero-rust-sdk/rules/app-macro-placement.md +5 -2
- package/skills/calimero-rust-sdk/rules/no-std-collections.md +5 -2
- package/skills/calimero-rust-sdk/rules/state-derives.md +45 -0
- package/skills/calimero-rust-sdk/rules/wasm-constraints.md +12 -10
- package/skills/calimero-sdk-js/SKILL.md +145 -0
- package/skills/calimero-sdk-js/references/build-pipeline.md +98 -0
- package/skills/calimero-sdk-js/references/collections.md +132 -0
- package/skills/calimero-sdk-js/references/events.md +63 -0
- package/skills/calimero-sdk-js/rules/crdt-only-state.md +47 -0
- package/skills/calimero-sdk-js/rules/no-console-log.md +38 -0
- package/skills/calimero-sdk-js/rules/view-decorator.md +48 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Scripting with meroctl
|
|
2
|
+
|
|
3
|
+
## Capturing output for use in scripts
|
|
4
|
+
|
|
5
|
+
Most `create` commands print an ID on stdout. Capture it with shell variable assignment:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
APP_ID=$(meroctl app install --path app.wasm | grep -oP '(?<=application-id: )[\w-]+')
|
|
9
|
+
CTX_ID=$(meroctl context create --application-id "$APP_ID" | grep -oP '(?<=context-id: )[\w-]+')
|
|
10
|
+
meroctl call "$CTX_ID" set --args '{"key":"hello","value":"world"}'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
> Check the actual output format of your `merod` version — the label text may vary. Use `--as-json`
|
|
14
|
+
> if available to get machine-readable output.
|
|
15
|
+
|
|
16
|
+
## JSON output (if supported)
|
|
17
|
+
|
|
18
|
+
Some `meroctl` commands support a `--as-json` flag for machine-readable output:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
meroctl --as-json context ls
|
|
22
|
+
meroctl --as-json app ls
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Minimal CI script (GitHub Actions)
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
- name: Deploy and test
|
|
29
|
+
run: |
|
|
30
|
+
# Register node (assumes merod is running in a service container)
|
|
31
|
+
meroctl node add ci http://localhost:2428
|
|
32
|
+
meroctl node use ci
|
|
33
|
+
|
|
34
|
+
# Install app
|
|
35
|
+
APP_ID=$(meroctl app install --path app.wasm)
|
|
36
|
+
echo "APP_ID=$APP_ID" >> $GITHUB_ENV
|
|
37
|
+
|
|
38
|
+
# Create context
|
|
39
|
+
CTX_ID=$(meroctl context create --application-id "$APP_ID")
|
|
40
|
+
echo "CTX_ID=$CTX_ID" >> $GITHUB_ENV
|
|
41
|
+
|
|
42
|
+
- name: Run integration tests
|
|
43
|
+
run: |
|
|
44
|
+
meroctl call "$CTX_ID" set --args '{"key":"test","value":"1"}'
|
|
45
|
+
RESULT=$(meroctl call "$CTX_ID" get --args '{"key":"test"}' --view)
|
|
46
|
+
echo "$RESULT" | grep -q '"1"' || (echo "FAIL: unexpected value" && exit 1)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Dev-mode hot reload
|
|
50
|
+
|
|
51
|
+
Use `--watch` during development to automatically reinstall the WASM and update the context whenever
|
|
52
|
+
the file changes:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Watches app.wasm, reinstalls on change
|
|
56
|
+
meroctl context create --watch path/to/app.wasm
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Calling methods in a loop
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
for key in foo bar baz; do
|
|
63
|
+
meroctl call "$CTX_ID" set --args "{\"key\":\"$key\",\"value\":\"$key-val\"}"
|
|
64
|
+
done
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Multi-node scripting
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Node A: setup
|
|
71
|
+
meroctl --node node1 namespace create
|
|
72
|
+
NS_ID=<paste namespace-id>
|
|
73
|
+
meroctl --node node1 context create --application-id "$APP_ID"
|
|
74
|
+
CTX_ID=<paste context-id>
|
|
75
|
+
INVITE=$(meroctl --node node1 namespace invite "$NS_ID")
|
|
76
|
+
|
|
77
|
+
# Node B: join
|
|
78
|
+
meroctl --node node2 namespace join "$NS_ID" "$INVITE"
|
|
79
|
+
meroctl --node node2 group join-context "$CTX_ID"
|
|
80
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Rule: Use --view for Read-Only Methods
|
|
2
|
+
|
|
3
|
+
**Always pass `--view` when calling a method that only reads state.**
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Without `--view`, the node treats the call as a mutation — it persists the state after the call and
|
|
8
|
+
broadcasts a `StateMutation` event to all context members. For read-only methods this is wasteful
|
|
9
|
+
(unnecessary writes and network traffic) and may cause unexpected state mutation events in
|
|
10
|
+
subscribers.
|
|
11
|
+
|
|
12
|
+
## How to identify view methods
|
|
13
|
+
|
|
14
|
+
- **Rust SDK**: method takes `&self` (not `&mut self`)
|
|
15
|
+
- **JS SDK**: method is annotated with `@View()`
|
|
16
|
+
- **meroctl call**: you cannot tell from the CLI alone — check the app source
|
|
17
|
+
|
|
18
|
+
## Correct usage
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Read-only — use --view
|
|
22
|
+
meroctl call <ctx-id> get_posts --args '{}' --view
|
|
23
|
+
meroctl call <ctx-id> get --args '{"key":"foo"}' --view
|
|
24
|
+
|
|
25
|
+
# Mutation — no --view
|
|
26
|
+
meroctl call <ctx-id> create_post --args '{"title":"Hello"}'
|
|
27
|
+
meroctl call <ctx-id> set --args '{"key":"foo","value":"bar"}'
|
|
28
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Rule: Register Node Once, Then Use by Name
|
|
2
|
+
|
|
3
|
+
**Run `meroctl node add` + `meroctl node use` once. After that, omit `--node` from all commands.**
|
|
4
|
+
|
|
5
|
+
## Pattern
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# One-time setup:
|
|
9
|
+
meroctl node add node1 /path/to/calimero/home # or http://url for remote
|
|
10
|
+
meroctl node use node1
|
|
11
|
+
|
|
12
|
+
# All subsequent commands use the active node automatically:
|
|
13
|
+
meroctl app install --path app.wasm # no --node needed
|
|
14
|
+
meroctl context ls # no --node needed
|
|
15
|
+
meroctl call <ctx-id> get --args '{}' --view # no --node needed
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Don't do this
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Repetitive and error-prone:
|
|
22
|
+
meroctl --node node1 app install --path app.wasm
|
|
23
|
+
meroctl --node node1 context create --application-id <id>
|
|
24
|
+
meroctl --node node1 call <ctx-id> get --args '{}' --view
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Exception: multiple nodes
|
|
28
|
+
|
|
29
|
+
When scripting across multiple nodes in one session, use explicit `--node` to avoid ambiguity:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
meroctl --node node1 namespace invite <ns-id> # Node A generates invite
|
|
33
|
+
meroctl --node node2 namespace join <ns-id> ... # Node B accepts
|
|
34
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# calimero-merod — Agent Instructions
|
|
2
|
+
|
|
3
|
+
You are helping a developer run and configure the **`merod` Calimero node daemon**.
|
|
4
|
+
|
|
5
|
+
## What merod is
|
|
6
|
+
|
|
7
|
+
`merod` is the Calimero node runtime. It:
|
|
8
|
+
|
|
9
|
+
- Executes WASM applications inside isolated contexts
|
|
10
|
+
- Manages persistent CRDT storage
|
|
11
|
+
- Exposes a JSON-RPC + WebSocket HTTP API (default port 2428)
|
|
12
|
+
- Participates in the P2P swarm for state sync with other nodes (default port 2528)
|
|
13
|
+
- Issues and validates JWT tokens for client authentication
|
|
14
|
+
|
|
15
|
+
`merod` is a long-running daemon. Use `meroctl` for administration after startup.
|
|
16
|
+
|
|
17
|
+
## Two-step startup
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Step 1 — initialise (run ONCE on a fresh home directory)
|
|
21
|
+
merod --node node1 init --server-port 2428 --swarm-port 2528
|
|
22
|
+
|
|
23
|
+
# Step 2 — run (run every time)
|
|
24
|
+
merod --node node1 run
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Never run `merod run` on an uninitialised home.** Run `init` first.
|
|
28
|
+
|
|
29
|
+
## Key flags
|
|
30
|
+
|
|
31
|
+
| Flag | Purpose | Default |
|
|
32
|
+
| ---------------------- | --------------------------------------------------- | ----------------- |
|
|
33
|
+
| `--node <name>` | Node identity name (used to namespace config files) | required |
|
|
34
|
+
| `--home <path>` | Base directory for all config and data | system config dir |
|
|
35
|
+
| `--server-port <port>` | HTTP/WS API port (init only) | `2428` |
|
|
36
|
+
| `--swarm-port <port>` | P2P swarm port (init only) | `2528` |
|
|
37
|
+
|
|
38
|
+
## Port responsibilities
|
|
39
|
+
|
|
40
|
+
| Port | What connects to it |
|
|
41
|
+
| ---------------------- | --------------------------------------------------------------- |
|
|
42
|
+
| `--server-port` (2428) | meroctl, app clients, browser frontends, Python client |
|
|
43
|
+
| `--swarm-port` (2528) | Other `merod` nodes (P2P state sync, namespace invite protocol) |
|
|
44
|
+
|
|
45
|
+
Both ports must be open / reachable for multi-node setups.
|
|
46
|
+
|
|
47
|
+
## References
|
|
48
|
+
|
|
49
|
+
See `references/` for init flags, config file schema, health endpoints, and Docker setup.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Health Endpoints and API Discovery
|
|
2
|
+
|
|
3
|
+
## Health check
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
GET http://localhost:2428/health
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Returns `200 OK` with a JSON body when the node is running and ready.
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{ "status": "alive" }
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
> **Note:** The status value is `"alive"`, not `"healthy"`. Code that checks for `"healthy"` will
|
|
16
|
+
> incorrectly treat a live node as unhealthy.
|
|
17
|
+
|
|
18
|
+
## Wait for node ready (shell)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
until curl -sf http://localhost:2428/health > /dev/null; do
|
|
22
|
+
echo "waiting for node..."
|
|
23
|
+
sleep 1
|
|
24
|
+
done
|
|
25
|
+
echo "node is ready"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Wait for node ready (CI — GitHub Actions)
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
- name: Wait for node
|
|
32
|
+
run: |
|
|
33
|
+
for i in $(seq 1 30); do
|
|
34
|
+
if curl -sf http://localhost:2428/health; then
|
|
35
|
+
echo "Node ready"
|
|
36
|
+
break
|
|
37
|
+
fi
|
|
38
|
+
echo "Waiting... ($i/30)"
|
|
39
|
+
sleep 2
|
|
40
|
+
done
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## API base URL
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
http://localhost:2428/api/v0/
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
All management endpoints are under `/api/v0/`. Clients must authenticate with
|
|
52
|
+
`Authorization: Bearer <accessToken>` on all endpoints except `/api/v0/identity/login`.
|
|
53
|
+
|
|
54
|
+
## Key API paths
|
|
55
|
+
|
|
56
|
+
| Path | Method | Purpose |
|
|
57
|
+
| ------------------------------- | ------ | -------------------------------------- |
|
|
58
|
+
| `/health` | GET | Node liveness check (no auth required) |
|
|
59
|
+
| `/api/v0/identity/login` | POST | Get access + refresh tokens |
|
|
60
|
+
| `/api/v0/identity/refresh` | POST | Refresh access token |
|
|
61
|
+
| `/api/v0/contexts` | GET | List contexts |
|
|
62
|
+
| `/api/v0/contexts` | POST | Create context |
|
|
63
|
+
| `/api/v0/contexts/{id}/execute` | POST | Call app method |
|
|
64
|
+
| `/api/v0/applications` | GET | List installed apps |
|
|
65
|
+
| `/api/v0/applications` | POST | Install app (multipart) |
|
|
66
|
+
|
|
67
|
+
WebSocket: `ws://localhost:2428/ws`
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Docker health check
|
|
72
|
+
|
|
73
|
+
```dockerfile
|
|
74
|
+
HEALTHCHECK --interval=5s --timeout=3s --retries=10 \
|
|
75
|
+
CMD curl -sf http://localhost:2428/health || exit 1
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Docker Compose health check
|
|
79
|
+
|
|
80
|
+
```yaml
|
|
81
|
+
services:
|
|
82
|
+
node:
|
|
83
|
+
image: calimero/merod:latest
|
|
84
|
+
healthcheck:
|
|
85
|
+
test: ['CMD', 'curl', '-sf', 'http://localhost:2428/health']
|
|
86
|
+
interval: 5s
|
|
87
|
+
timeout: 3s
|
|
88
|
+
retries: 10
|
|
89
|
+
start_period: 10s
|
|
90
|
+
```
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# merod Init and Run Flags
|
|
2
|
+
|
|
3
|
+
## merod init
|
|
4
|
+
|
|
5
|
+
Initialises a new node home directory: generates key material, writes the config file, and creates
|
|
6
|
+
the storage directory. Run **once** per node, before the first `merod run`.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
merod --node <name> init [flags]
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
### Flags
|
|
13
|
+
|
|
14
|
+
| Flag | Required | Default | Description |
|
|
15
|
+
| ---------------------- | -------- | ------------- | ------------------------------------------------------------------- |
|
|
16
|
+
| `--node <name>` | Yes | — | Node identity name. Namespaces config files under `<home>/<name>/`. |
|
|
17
|
+
| `--home <path>` | No | OS config dir | Base directory. All node data lives under `<home>/<name>/`. |
|
|
18
|
+
| `--server-port <port>` | No | `2428` | HTTP/WS API port. Clients and meroctl connect here. |
|
|
19
|
+
| `--swarm-port <port>` | No | `2528` | P2P port. Other merod nodes connect here for state sync. |
|
|
20
|
+
|
|
21
|
+
### Examples
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Minimal (uses defaults)
|
|
25
|
+
merod --node node1 init
|
|
26
|
+
|
|
27
|
+
# Custom ports
|
|
28
|
+
merod --node node1 init --server-port 3000 --swarm-port 3001
|
|
29
|
+
|
|
30
|
+
# Custom home directory
|
|
31
|
+
merod --home ./data --node node1 init --server-port 2428 --swarm-port 2528
|
|
32
|
+
|
|
33
|
+
# Multiple nodes on the same machine (must use different ports)
|
|
34
|
+
merod --home ./data --node node1 init --server-port 2428 --swarm-port 2528
|
|
35
|
+
merod --home ./data --node node2 init --server-port 2429 --swarm-port 2529
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## merod run
|
|
41
|
+
|
|
42
|
+
Starts the node daemon. The home directory must already be initialised.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
merod --node <name> run [flags]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Run flags
|
|
49
|
+
|
|
50
|
+
| Flag | Required | Default | Description |
|
|
51
|
+
| --------------- | -------- | ------------- | --------------------------------------- |
|
|
52
|
+
| `--node <name>` | Yes | — | Must match the name used during `init`. |
|
|
53
|
+
| `--home <path>` | No | OS config dir | Must match the home used during `init`. |
|
|
54
|
+
|
|
55
|
+
### Run examples
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Run in foreground
|
|
59
|
+
merod --node node1 run
|
|
60
|
+
|
|
61
|
+
# Run in background (Unix)
|
|
62
|
+
merod --node node1 run &
|
|
63
|
+
|
|
64
|
+
# Run with custom home
|
|
65
|
+
merod --home ./data --node node1 run
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Data directory layout
|
|
71
|
+
|
|
72
|
+
After `init`, the following structure is created under `<home>/<node-name>/`:
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
<home>/
|
|
76
|
+
└── <node-name>/
|
|
77
|
+
├── config.toml # node configuration (server port, swarm port, etc.)
|
|
78
|
+
├── identity/ # Ed25519 node keypair
|
|
79
|
+
└── data/ # CRDT storage, application binaries
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Do not edit `config.toml` manually unless you know what you are changing.** Port numbers are
|
|
83
|
+
written to config during `init` and cannot be changed without re-initialising or manually editing
|
|
84
|
+
the config.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Rule: Always Init Before Run
|
|
2
|
+
|
|
3
|
+
**`merod init` must be run once before `merod run` on any new home directory.**
|
|
4
|
+
|
|
5
|
+
## Correct order
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# 1. Init (ONCE — creates config, keypair, storage dirs)
|
|
9
|
+
merod --node node1 init --server-port 2428 --swarm-port 2528
|
|
10
|
+
|
|
11
|
+
# 2. Run (every time after)
|
|
12
|
+
merod --node node1 run
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## What goes wrong without init
|
|
16
|
+
|
|
17
|
+
Running `merod run` on an uninitialised home fails immediately — the node has no config file, no
|
|
18
|
+
keypair, and no storage directory. The error will be something like `config not found` or
|
|
19
|
+
`identity not found`.
|
|
20
|
+
|
|
21
|
+
## Re-initialising loses all data
|
|
22
|
+
|
|
23
|
+
Running `merod init` on a home that already has data will **overwrite the config and generate a new
|
|
24
|
+
keypair**, effectively destroying the node's identity and making all existing contexts unreachable
|
|
25
|
+
(their members' trust roots refer to the old keypair).
|
|
26
|
+
|
|
27
|
+
**Never re-init a production node home.**
|
|
28
|
+
|
|
29
|
+
## Multiple nodes on one machine
|
|
30
|
+
|
|
31
|
+
Each node needs its own `--node` name and different ports:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
merod --home ./data --node node1 init --server-port 2428 --swarm-port 2528
|
|
35
|
+
merod --home ./data --node node2 init --server-port 2429 --swarm-port 2529
|
|
36
|
+
|
|
37
|
+
# Run both (separate terminals or background)
|
|
38
|
+
merod --home ./data --node node1 run &
|
|
39
|
+
merod --home ./data --node node2 run &
|
|
40
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Rule: Understand Port Assignments
|
|
2
|
+
|
|
3
|
+
**`merod` uses two distinct ports with different roles. Both matter.**
|
|
4
|
+
|
|
5
|
+
## Port roles
|
|
6
|
+
|
|
7
|
+
| Flag | Default | Connected by |
|
|
8
|
+
| --------------- | ------- | ----------------------------------------------------------------------- |
|
|
9
|
+
| `--server-port` | `2428` | `meroctl`, app clients (browser, Python, JS), all HTTP/WS API consumers |
|
|
10
|
+
| `--swarm-port` | `2528` | Other `merod` nodes — P2P state sync, namespace invite protocol |
|
|
11
|
+
|
|
12
|
+
## What fails when a port is wrong or blocked
|
|
13
|
+
|
|
14
|
+
| Problem | Symptom |
|
|
15
|
+
| ----------------------- | ------------------------------------------------------------------------------------ |
|
|
16
|
+
| Server port unreachable | `meroctl` cannot connect; clients get connection refused; apps cannot make API calls |
|
|
17
|
+
| Swarm port unreachable | Multi-node sync silently fails; namespaces cannot be joined; nodes appear isolated |
|
|
18
|
+
|
|
19
|
+
## Multiple nodes on the same machine
|
|
20
|
+
|
|
21
|
+
Each `merod` instance needs unique ports:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
merod --home ./data --node node1 init --server-port 2428 --swarm-port 2528
|
|
25
|
+
merod --home ./data --node node2 init --server-port 2429 --swarm-port 2529
|
|
26
|
+
merod --home ./data --node node3 init --server-port 2430 --swarm-port 2530
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Ports are set at init time
|
|
30
|
+
|
|
31
|
+
Port assignments are written into the config file during `merod init`. You cannot change them with
|
|
32
|
+
`merod run` flags — edit `config.toml` in the node home or re-init if you need different ports
|
|
33
|
+
(re-init destroys the node identity, so prefer editing `config.toml`).
|
|
@@ -4,7 +4,8 @@ You are helping a developer manage a **Calimero node** using `merod` and `meroct
|
|
|
4
4
|
|
|
5
5
|
## Key concepts
|
|
6
6
|
|
|
7
|
-
- `merod` — the node runtime. Runs as a daemon. Hosts WASM apps, manages storage, exposes JSON-RPC +
|
|
7
|
+
- `merod` — the node runtime. Runs as a daemon. Hosts WASM apps, manages storage, exposes JSON-RPC +
|
|
8
|
+
WebSocket
|
|
8
9
|
- `meroctl` — the CLI for administrating a running node (contexts, apps, identities)
|
|
9
10
|
- **Context** — an isolated application instance with its own members, state, and storage
|
|
10
11
|
- **Application** — the WASM code; one app can power many contexts
|
|
@@ -13,60 +14,76 @@ You are helping a developer manage a **Calimero node** using `merod` and `meroct
|
|
|
13
14
|
## Node setup (first time)
|
|
14
15
|
|
|
15
16
|
```bash
|
|
16
|
-
# Initialize node
|
|
17
|
-
merod --
|
|
17
|
+
# Initialize node (creates key material and config)
|
|
18
|
+
merod --node node1 init --server-port 2428 --swarm-port 2528
|
|
18
19
|
|
|
19
20
|
# Start the node
|
|
20
|
-
merod --
|
|
21
|
+
merod --node node1 run
|
|
21
22
|
# Node listens on http://localhost:2428 by default
|
|
22
23
|
```
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
`--home <PATH>` is optional; defaults to the system config directory. Use it to specify a custom
|
|
26
|
+
data directory: `merod --home ./data --node node1 init`.
|
|
27
|
+
|
|
28
|
+
## Connecting meroctl to a node
|
|
25
29
|
|
|
26
30
|
```bash
|
|
27
|
-
#
|
|
28
|
-
meroctl
|
|
29
|
-
--path myapp.mpk
|
|
30
|
-
# → prints app-id
|
|
31
|
+
# Register a local node by name (one-time)
|
|
32
|
+
meroctl node add node1 /path/to/calimero/home
|
|
31
33
|
|
|
32
|
-
#
|
|
33
|
-
meroctl
|
|
34
|
-
--app-id <app-id>
|
|
35
|
-
# → prints context-id
|
|
34
|
+
# Or register a remote node
|
|
35
|
+
meroctl node add mynode http://node.example.com
|
|
36
36
|
|
|
37
|
-
#
|
|
38
|
-
meroctl
|
|
39
|
-
--args '{"key":"hello","value":"world"}'
|
|
37
|
+
# Set as default (so you don't need --node on every command)
|
|
38
|
+
meroctl node use node1
|
|
40
39
|
|
|
41
|
-
#
|
|
42
|
-
meroctl
|
|
43
|
-
|
|
40
|
+
# List configured nodes
|
|
41
|
+
meroctl node ls
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
After setup, use `--node node1` or rely on the active node:
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
meroctl --node
|
|
46
|
+
```bash
|
|
47
|
+
meroctl --node node1 context ls # explicit
|
|
48
|
+
meroctl context ls # uses active node
|
|
47
49
|
```
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
Alternatively, pass a direct URL without registering:
|
|
50
52
|
|
|
51
53
|
```bash
|
|
52
|
-
|
|
53
|
-
meroctl --node-url http://localhost:2428 context invite \
|
|
54
|
-
<context-id> --identity <identity-on-node-A>
|
|
55
|
-
# → prints invitation payload (JSON)
|
|
56
|
-
|
|
57
|
-
# On node B — accept the invitation
|
|
58
|
-
meroctl --node-url http://localhost:2429 context join \
|
|
59
|
-
--invitation '<paste-invitation-payload>'
|
|
60
|
-
# → node B syncs state from node A
|
|
54
|
+
meroctl --api http://localhost:2428 context ls
|
|
61
55
|
```
|
|
62
56
|
|
|
63
|
-
##
|
|
57
|
+
## Complete workflow: app → context → call
|
|
64
58
|
|
|
65
59
|
```bash
|
|
66
|
-
meroctl
|
|
67
|
-
|
|
60
|
+
# (Assumes: meroctl node add node1 ... && meroctl node use node1 already done)
|
|
61
|
+
|
|
62
|
+
# 1. Install an app
|
|
63
|
+
meroctl app install --path myapp.wasm
|
|
64
|
+
# → prints application-id
|
|
65
|
+
|
|
66
|
+
# 2. Create a context (instantiate the app — init() is called)
|
|
67
|
+
meroctl context create --application-id <application-id>
|
|
68
|
+
# → prints context-id
|
|
69
|
+
|
|
70
|
+
# 3. Call a mutation (changes state)
|
|
71
|
+
meroctl call <context-id> set --args '{"key":"hello","value":"world"}'
|
|
72
|
+
|
|
73
|
+
# 4. Call a view (read-only)
|
|
74
|
+
meroctl call <context-id> get --args '{"key":"hello"}' --view
|
|
68
75
|
```
|
|
69
76
|
|
|
77
|
+
## Related skills
|
|
78
|
+
|
|
79
|
+
- **`calimero-merod`** — deep-dive on `merod` daemon: all init flags, config file schema, health
|
|
80
|
+
endpoints, Docker setup
|
|
81
|
+
- **`calimero-meroctl`** — complete `meroctl` CLI reference: every subcommand, every flag, scripting
|
|
82
|
+
patterns, multi-node namespace/group workflow
|
|
83
|
+
- **`calimero-core`** — context/app/identity model, JSON-RPC protocol, WebSocket events, CRDT
|
|
84
|
+
storage types
|
|
85
|
+
|
|
70
86
|
## References
|
|
71
87
|
|
|
72
|
-
See `references/` for
|
|
88
|
+
See `references/` for context lifecycle detail and multi-node namespace/group setup. For the full
|
|
89
|
+
`meroctl` command reference, use the `calimero-meroctl` skill.
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
# Context Lifecycle
|
|
2
2
|
|
|
3
|
-
A **context** is an isolated instance of an application with its own members, CRDT state, and
|
|
3
|
+
A **context** is an isolated instance of an application with its own members, CRDT state, and
|
|
4
|
+
storage.
|
|
4
5
|
|
|
5
6
|
## App vs Context
|
|
6
7
|
|
|
7
|
-
| Concept
|
|
8
|
-
|
|
|
9
|
-
| Application | WASM binary + manifest
|
|
10
|
-
| Context
|
|
8
|
+
| Concept | What it is | Analogy |
|
|
9
|
+
| ----------- | -------------------------- | -------------------- |
|
|
10
|
+
| Application | WASM binary + manifest | A class / template |
|
|
11
|
+
| Context | Running instance of an app | An object / instance |
|
|
11
12
|
|
|
12
13
|
One application can power many independent contexts. Each context has completely isolated state.
|
|
13
14
|
|
|
14
15
|
## Lifecycle
|
|
15
16
|
|
|
16
|
-
```
|
|
17
|
+
```text
|
|
17
18
|
App installed on node
|
|
18
19
|
│
|
|
19
20
|
▼
|
|
20
21
|
Context created (init() called → initial state set)
|
|
21
22
|
│
|
|
22
23
|
▼
|
|
23
|
-
Members
|
|
24
|
+
Members join via namespace/group membership
|
|
24
25
|
│
|
|
25
26
|
├─ Methods called (mutations + views)
|
|
26
27
|
├─ Events emitted to members
|
|
@@ -33,23 +34,38 @@ Context deleted (state and storage wiped)
|
|
|
33
34
|
## Creating a context
|
|
34
35
|
|
|
35
36
|
```bash
|
|
36
|
-
meroctl context create --
|
|
37
|
+
meroctl --node node1 context create --application-id <application-id>
|
|
37
38
|
# Returns: context-id
|
|
38
39
|
```
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
Dev mode — auto-reinstalls when the WASM file changes:
|
|
41
42
|
|
|
42
43
|
```bash
|
|
43
|
-
|
|
44
|
-
meroctl context invite <context-id> --identity <identity-on-node-A>
|
|
45
|
-
# Returns: invitation payload (share this with the new member)
|
|
46
|
-
|
|
47
|
-
# On node B — accept the invitation
|
|
48
|
-
meroctl context join --invitation <paste-invitation-payload>
|
|
44
|
+
meroctl --node node1 context create --watch path/to/app.wasm
|
|
49
45
|
```
|
|
50
46
|
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
## Multi-node participation (namespace + group model)
|
|
48
|
+
|
|
49
|
+
Nodes join a context via **namespaces** (root groups). The inviting node creates a namespace
|
|
50
|
+
invitation; joining nodes accept it, then join the context via group membership.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# ── Node A (creator) ──
|
|
54
|
+
meroctl --node node1 namespace create
|
|
55
|
+
# → <namespace-id>
|
|
56
|
+
|
|
57
|
+
meroctl --node node1 context create --application-id <app-id>
|
|
58
|
+
# → <context-id>
|
|
59
|
+
|
|
60
|
+
meroctl --node node1 namespace invite <namespace-id>
|
|
61
|
+
# → invitation JSON — share with Node B
|
|
62
|
+
|
|
63
|
+
# ── Node B (joiner) ──
|
|
64
|
+
meroctl --node node2 namespace join <namespace-id> '<invitation-json>'
|
|
65
|
+
|
|
66
|
+
meroctl --node node2 group join-context <context-id>
|
|
67
|
+
# Node B now participates and syncs CRDT state from Node A
|
|
68
|
+
```
|
|
53
69
|
|
|
54
70
|
## State synchronization
|
|
55
71
|
|
|
@@ -57,3 +73,4 @@ participate in CRDT state synchronization.
|
|
|
57
73
|
- All context members receive mutations from all other members
|
|
58
74
|
- Conflicts are resolved deterministically by the CRDT engine
|
|
59
75
|
- Sync works offline — changes queue up and merge when reconnected
|
|
76
|
+
- Manual sync: `meroctl --node node1 context sync <context-id>`
|