@elisym/cli 0.3.2 → 0.5.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 CHANGED
@@ -21,7 +21,10 @@ npx @elisym/cli start # Start provider mode
21
21
 
22
22
  ### Docker
23
23
 
24
- The wallet, job ledger, and recovery state live in `~/.elisym/agents/<name>/` and are bind-mounted into the container, so the same identity works across `bun add -g @elisym/cli` and the docker image - you generate it once, both entry points read it.
24
+ Each agent lives in its own directory: `elisym.yaml` (public config), `.secrets.json` (encrypted keys), `.media-cache.json` (uploaded image URLs), `.jobs.json` (ledger), and a `skills/` subfolder. Two locations are supported, and the CLI resolves by walking up from the current working directory:
25
+
26
+ - **Project-local**: `<project>/.elisym/<name>/` - shareable, committed to git (except the dotfiles, which the init command auto-gitignores).
27
+ - **Home-global**: `~/.elisym/<name>/` - private, use for ad-hoc or MCP-created agents.
25
28
 
26
29
  **1. Bootstrap an agent** (one-time, interactive wizard):
27
30
 
@@ -31,18 +34,25 @@ docker run --rm -it \
31
34
  ghcr.io/elisymlabs/cli init
32
35
  ```
33
36
 
34
- The wizard walks you through agent name, Solana network, wallet funding, and LLM provider, and writes everything to `~/.elisym/agents/<chosen-name>/` on the host.
37
+ The wizard walks you through agent name, Solana network, wallet funding, and LLM provider, and writes everything to `~/.elisym/<chosen-name>/` on the host.
35
38
 
36
- **2. Start provider mode** with your skills directory mounted:
39
+ **2. Start provider mode.** The container needs access to the agent directory - mount home if the agent lives there, or mount your project if it's project-local:
37
40
 
38
41
  ```bash
42
+ # Home-global agent
39
43
  docker run --rm -it \
40
44
  -v "$HOME/.elisym:/root/.elisym" \
41
- -v "$PWD/skills:/app/skills" \
45
+ ghcr.io/elisymlabs/cli start
46
+
47
+ # Project-local agent (from the project root)
48
+ docker run --rm -it \
49
+ -v "$HOME/.elisym:/root/.elisym" \
50
+ -v "$PWD/.elisym:/app/.elisym" \
51
+ -w /app \
42
52
  ghcr.io/elisymlabs/cli start
43
53
  ```
44
54
 
45
- Omit `<agent-name>` to pick interactively from agents in `~/.elisym/agents/`. The container reads your config and skills from the mounts, subscribes to Nostr relays for jobs, and writes the ledger (`jobs.json`) back to `~/.elisym/agents/<agent-name>/`. A `docker run` restart resumes interrupted jobs through the same crash-recovery loop as a host install.
55
+ Omit `<agent-name>` to pick interactively. Skills load from `<agentDir>/skills/`, which is inside the mount. The ledger (`.jobs.json`) is written back next to the YAML. A `docker run` restart resumes interrupted jobs through the same crash-recovery loop as a host install.
46
56
 
47
57
  ### Skill runtime dependencies
48
58
 
@@ -79,29 +89,39 @@ docker run --rm -it \
79
89
 
80
90
  ## Commands
81
91
 
82
- | Command | Description |
83
- | ----------------------- | -------------------------------------------- |
84
- | `elisym init` | Interactive wizard - create agent identity |
85
- | `elisym start [name]` | Start agent in provider mode |
86
- | `elisym list` | List all agents |
87
- | `elisym profile [name]` | Edit agent profile, wallet, and LLM settings |
88
- | `elisym wallet [name]` | Show Solana wallet balance |
89
- | `elisym delete <name>` | Delete an agent |
92
+ | Command | Description |
93
+ | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
94
+ | `elisym init [name]` | Interactive wizard - create agent identity |
95
+ | `elisym init [name] --config <path>` | Non-interactive - load fields from an `elisym.yaml` template |
96
+ | `elisym init [name] --local` | Create in project `.elisym/<name>/` (default: `~/.elisym/<name>/`) |
97
+ | `elisym start [name]` | Start agent in provider mode |
98
+ | `elisym start [name] --verbose` | Start with structured debug logs to stderr (publish acks, pool resets, heartbeat, config resolution). Also togglable via `ELISYM_DEBUG=1` or `LOG_LEVEL=debug`. |
99
+ | `elisym list` | List all agents (project-local + home-global) |
100
+ | `elisym profile [name]` | Edit agent profile, wallet, and LLM settings |
101
+ | `elisym wallet [name]` | Show Solana wallet balance |
90
102
 
91
- The agent loads skills from `./skills/` in the current working directory. Each skill is a subdirectory with a `SKILL.md` file:
103
+ Skills live inside each agent directory at `<agentDir>/skills/<skill-name>/SKILL.md`:
92
104
 
93
105
  ```
94
106
  my-project/
95
- skills/
96
- youtube-summary/
97
- SKILL.md
98
- scripts/
99
- summarize.py
100
- general-assistant/
101
- SKILL.md
102
- ...
107
+ .elisym/
108
+ .gitignore # auto-generated; excludes .secrets.json / .media-cache.json / .jobs.json
109
+ my-agent/
110
+ elisym.yaml # public - name, description, payments, LLM config, relays
111
+ avatar.png # referenced from elisym.yaml by relative path
112
+ skills/
113
+ youtube-summary/
114
+ SKILL.md
115
+ scripts/summarize.py
116
+ general-assistant/
117
+ SKILL.md
118
+ .secrets.json # encrypted Nostr/LLM keys (gitignored)
119
+ .media-cache.json # sha256 -> uploaded URL cache (gitignored)
120
+ .jobs.json # crash-recovery ledger (gitignored)
103
121
  ```
104
122
 
123
+ `elisym.yaml` is the source of truth - edit it in place and restart the agent; the CLI never writes back. The agent name comes from the folder name, not a YAML field (there's an optional `display_name` for UI).
124
+
105
125
  ## Skills
106
126
 
107
127
  Skills are defined in `SKILL.md` files inside `./skills/<skill-name>/`. Each file has YAML frontmatter (between `---` delimiters) that describes the skill, followed by a markdown body that becomes the LLM system prompt.
@@ -132,16 +152,16 @@ then return a concise overview and key points.
132
152
 
133
153
  ### Frontmatter fields
134
154
 
135
- | Field | Required | Type | Description |
136
- | ----------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------- |
137
- | `name` | yes | string | Unique skill identifier. Shown in the marketplace and used internally. |
138
- | `description` | yes | string | Short one-line description. Used in discovery - customers match skills by this text, so be specific about the use case. |
139
- | `capabilities` | yes | string[] | Non-empty list of capability tags for NIP-89 discovery. Customers filter agents by these tags. |
140
- | `price` | no | number | Price per job in SOL (e.g. `0.01`). Converted to lamports internally. Omit or set `0` for a free skill. |
141
- | `image` | no | string | Hero image URL. Shown in the marketplace card. Takes priority over `image_file`. |
142
- | `image_file` | no | string | Local file path (relative to the skill directory). Uploaded on first `elisym start`, the resulting URL is written back. |
143
- | `tools` | no | object[] | External scripts the LLM can call via tool-use. Omit if the skill is pure prompt + LLM. |
144
- | `max_tool_rounds` | no | number | Max LLM-tool interaction rounds per job. Default: `10`. Raise for multi-step flows (e.g. chunked transcripts). |
155
+ | Field | Required | Type | Description |
156
+ | ----------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
157
+ | `name` | yes | string | Unique skill identifier. Shown in the marketplace and used internally. |
158
+ | `description` | yes | string | Short one-line description. Used in discovery - customers match skills by this text, so be specific about the use case. |
159
+ | `capabilities` | yes | string[] | Non-empty list of capability tags for NIP-89 discovery. Customers filter agents by these tags. |
160
+ | `price` | no | number | Price per job in SOL (e.g. `0.01`). Converted to lamports internally. Omit or set `0` for a free skill. |
161
+ | `image` | no | string | Hero image URL. Shown in the marketplace card. Takes priority over `image_file`. |
162
+ | `image_file` | no | string | Local file path (relative to the skill directory). Uploaded on `elisym start` and cached by sha256 in `<agentDir>/.media-cache.json`; the SKILL.md itself is not modified. |
163
+ | `tools` | no | object[] | External scripts the LLM can call via tool-use. Omit if the skill is pure prompt + LLM. |
164
+ | `max_tool_rounds` | no | number | Max LLM-tool interaction rounds per job. Default: `10`. Raise for multi-step flows (e.g. chunked transcripts). |
145
165
 
146
166
  ### Tool definition
147
167
 
@@ -206,7 +226,7 @@ The script receives parameters as a JSON object on `stdin` and must write its re
206
226
 
207
227
  ### Idempotency: jobs may be re-executed
208
228
 
209
- The runtime tracks each job through `paid -> executed -> delivered` states in `~/.elisym/agents/<name>/jobs.json`. If the agent crashes **between** `skill.execute()` returning and the ledger being flushed, the job stays marked as `paid` - so on restart, the recovery loop will call your script **again** for the same job. This is at-least-once delivery, not exactly-once.
229
+ The runtime tracks each job through `paid -> executed -> delivered` states in `<agentDir>/.jobs.json`. If the agent crashes **between** `skill.execute()` returning and the ledger being flushed, the job stays marked as `paid` - so on restart, the recovery loop will call your script **again** for the same job. This is at-least-once delivery, not exactly-once.
210
230
 
211
231
  What this means for skill authors:
212
232
 
@@ -222,6 +242,23 @@ If you cannot make a side effect idempotent, document the risk clearly in the sk
222
242
 
223
243
  See `skills-examples/` for working skills: `youtube-summary`, `github-repo`, `stock-price`, `whois-lookup`, `site-status`, `trending`, `general-assistant`.
224
244
 
245
+ ## Troubleshooting
246
+
247
+ If `elisym start` prints `* Running. Press Ctrl+C to stop.` but no jobs ever arrive (common on WSL and Windows when outbound relay connectivity is blocked by the firewall or NAT), run with `--verbose`:
248
+
249
+ ```
250
+ elisym start --verbose
251
+ ```
252
+
253
+ The debug firehose on stderr includes:
254
+
255
+ - `config_resolved` - resolved agent dir, relays, RPC URL, Solana address.
256
+ - `publish_ack` / `publish_failed` - one per kind:0 profile event and per kind:31990 capability card. If every `publish_failed` row has `error: "Failed to publish to all N relays"`, outbound WebSocket to relays is being blocked.
257
+ - `pool_reset` with `reason: probe_failed` or `self_ping_failed` - the watchdog rebuilt the relay pool; sustained resets mean connectivity is unstable.
258
+ - `heartbeat_failed` - periodic republish calls are failing.
259
+
260
+ Optional deeper network diagnostics (DNS + TCP probe per relay host) are available via `ELISYM_NET_DIAG=1` (see `elisym start --help`).
261
+
225
262
  ## Commands
226
263
 
227
264
  ```bash