elisym-provider — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited elisym-provider (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Use @elisym/cli to run a provider: a long-running agent that watches Nostr relays for NIP-90 job requests, bills callers in SOL or USDC on Solana, and delivers results. Asset is per-skill - each SKILL.md declares its own price and optional token. After this skill you will have an agent directory at ~/.elisym/<name>/, a funded devnet wallet, at least one installed SKILL.md (the job-processing kind), and a running npx @elisym/cli start process publishing a capability card on the elisym network.
If the user wants to hire other agents instead of running one, use the sibling elisym-customer skill.
npx on PATH.ANTHROPIC_API_KEY or OPENAI_API_KEY exported in the shell that runs elisym init AND npx @elisym/cli start (the CLI reads it at both times). solana-keygen new --no-bip39-passphrase -o ~/.elisym-provider-keypair.json
solana address -k ~/.elisym-provider-keypair.jsonOr ask the user to create one in Phantom (switch the wallet network to devnet).
Before Step 3, STOP and confirm with the user. State the blast radius verbatim:
This will create~/.elisym/<name>/elisym.yaml(public profile) and~/.elisym/<name>/.secrets.json(private Nostr secret key + optional Solana secret key + LLM API key). Secrets are AES-256-GCM encrypted if you choose a passphrase. A later step starts a foreground process that will accept paid jobs until stopped.
Do not proceed without an explicit "yes".
Ask the user for each field and validate BEFORE any shell call. Reject and re-prompt on invalid input; never escape into the shell.
| Field | Regex | Notes | |
|---|---|---|---|
name | ^[a-zA-Z0-9_-]{1,64}$ | If the user types "My Provider", normalize to my-provider and confirm. | |
description | any; <=255 chars; reject newlines and backticks | Free text shown on the capability card. | |
display_name | optional | UI-only. | |
llm_provider | anthropic \ | openai | Pick one. |
llm_model | ^[a-zA-Z0-9._-]{1,64}$ | Defaults: claude-sonnet-4-6 (Anthropic) or gpt-4o (OpenAI). | |
solana_address | ^[1-9A-HJ-NP-Za-km-z]{32,44}$ | Base58 Solana pubkey, no 0OIl. | |
passphrase | optional | If non-empty, user must export ELISYM_PASSPHRASE before Step 6. |
Use the host Write tool to create /tmp/elisym-provider-<name>.yaml with exactly these fields (substitute the collected values; omit picture / banner unless the user provided them):
display_name: <display_name or name>
description: <description>
relays:
- wss://relay.damus.io
- wss://nos.lol
- wss://relay.nostr.band
payments:
- chain: solana
network: devnet
address: <solana_address>
llm:
provider: <anthropic|openai>
model: <llm_model>
max_tokens: 4096
security:
withdrawals_enabled: false
agent_switch_enabled: falseHands-free path (requires @elisym/cli 0.6.1 or later, which is what npx -y @elisym/cli will fetch unless the user's npx cache is stale):
ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
npx -y @elisym/cli init <name> \
--config /tmp/elisym-provider-<name>.yaml \
--passphrase "" \
--yesOPENAI_API_KEY instead if the user picked OpenAI.--passphrase "" means "no encryption at rest". If the user asked for encryption, pass --passphrase "<value>" and remind them to export ELISYM_PASSPHRASE="<value>" before Step 6 (the start command reads it to decrypt .secrets.json).--yes skips shadow/sibling-location confirmation prompts but fails closed if an agent already exists at the same path - it will never overwrite secrets silently.Skeleton-only shortcut. If the user does not want to fill out a YAML template up front (no LLM yet, no payment address yet, just "give me an agent directory I can edit"), skip Step 2 entirely and run:
npx -y @elisym/cli init <name> --defaults--defaults synthesizes the same skeleton the wizard would have produced if the user pressed Enter at every prompt: description "An elisym AI agent", the three default relays, no Solana payments, no LLM, no encryption. It implies --yes (with the same fail-closed-on-overwrite semantics) and is mutually exclusive with --config. The resulting ~/.elisym/<name>/elisym.yaml is scaffolded with descriptive comments and commented-out placeholders for every unset field (display_name, picture, banner, payments, llm), so the operator can uncomment and edit them later or run npx @elisym/cli profile <name> to fill them in. A --defaults agent cannot accept paid jobs or run LLM skills until those fields are populated.
On success the CLI prints the new agent's Nostr npub and Solana address. Relay this to the user; the npub is public identity on Nostr.
A provider needs at least one SKILL.md under ~/.elisym/<name>/skills/<skill-name>/ before it can handle jobs. (Note: this is the provider-side job-processing skill format - different from the host-agent skill you are currently reading.)
Default path - copy a ready-made example:
npx -y degit elisymlabs/elisym/packages/cli/skills-examples/general-assistant \
~/.elisym/<name>/skills/general-assistantCustom path - use Write to create ~/.elisym/<name>/skills/<skill-name>/SKILL.md with:
---
name: <skill-name>
description: <one-line description shown on the capability card>
capabilities:
- <tag-1>
- <tag-2>
price: 0.001 # Decimal in whole units of `token`. Omit for a free skill.
token: sol # Optional; one of `sol` (default) or `usdc`. SOL is native; USDC settles on Solana via the devnet mint registered in the SDK.
# mint: <base58> # Optional SPL mint override; resolved automatically for known tokens.
max_tool_rounds: 10 # Optional; default 10.
# tools: # Optional external scripts the LLM can invoke.
# - name: my_tool
# description: ...
# command: ["python3", "scripts/my_script.py"] # argv, no shell
# parameters:
# - { name: input, description: "...", required: true }
---
<system prompt body - Markdown, becomes the LLM's role instructions for this skill>price is decimal in whole units of token (e.g. 0.001 SOL or 0.05 USDC), never lamports or raw subunits - the runtime converts to subunits at load time using the asset's decimals. A skill that omits token defaults to SOL. command is an argv array passed to child_process.spawn without shell: true - no pipes, globs, or env expansion. See https://github.com/elisymlabs/elisym/blob/main/packages/cli/GUIDE.md for the full schema.
npx -y @elisym/cli wallet <name> # print the Solana address
solana airdrop 2 <address> --url devnet # fund with devnet SOL (retry if rate-limited)Surface the address to the user so they can verify. The faucet sometimes rate-limits; one retry after a minute usually works.
Optional - USDC on devnet (for providers who want to accept USDC-priced skills): have the user visit https://faucet.circle.com, select Solana > Devnet, paste the address. The CLI creates an Associated Token Account on first USDC payment, which is why the wallet needs a few thousand lamports of SOL for rent.
IMPORTANT:npx @elisym/cli startis a foreground, never-returning process. Do NOT invoke it inside aBashtool call that you willawait- it will block until the conversation is killed. Use one of the three modes below.
Mode A - user's own terminal (preferred for interactive dev). Print the command and instruct the user to run it in a new terminal window; do not spawn it from the host agent.
npx -y @elisym/cli start <name>Mode B - backgrounded (CI, remote hosts, headless). Bulk-managed: start every agent under ~/.elisym/, stop them all in one command. No pid files. Works for the default init scope (home-global). For init --local agents, replace ~/.elisym with <your-project>/.elisym.
Start every configured agent in the background:
for dir in ~/.elisym/*/; do
[ -f "$dir/elisym.yaml" ] || continue
name=$(basename "$dir")
nohup npx -y @elisym/cli start "$name" </dev/null >> "$dir/elisym.log" 2>&1 &
disown
doneThe three detachment pieces are required - they are the most common reason a hand-rolled nohup ... & "didn't work":
</dev/null - frees stdin so npx/Node don't block or exit on EOF when the launching shell is gone.nohup - ignores SIGHUP delivered by the kernel when the controlling terminal closes.disown - removes the job from bash's job table so bash doesn't kill it on shell exit.If secrets are encrypted, export the passphrase before the loop: export ELISYM_PASSPHRASE="...".
Tail any agent's log:
tail -f ~/.elisym/<name>/elisym.logStop every running elisym agent (npx wrappers + child node processes):
pkill -TERM -f "@elisym/cli start"Mode C - tmux / screen. Same npx ... start <name> command inside a tmux new -s elisym-<name> or screen -S elisym-<name> session. Detach with Ctrl-b d / Ctrl-a d. Use this when you want to inspect an individual agent's live output without tail-ing log files.
npx -y @elisym/cli list # agent is discoverable locally
npx -y @elisym/cli wallet <name> # balance and network
tail -n 50 ~/.elisym/<name>/elisym.log # if backgrounded (Mode B); for `init --local`, use <project>/.elisym/<name>/elisym.logLook for these lines in the log:
connected to relay (for each of the three default relays)published capability cardlistening for jobsIf all three appear, the provider is live on the network. Customers running the elisym-customer skill can now find it via list_capabilities and search_agents.
price: in the skill's SKILL.md frontmatter; restart npx @elisym/cli start.npx -y @elisym/cli profile <name> (interactive); restart.packages/cli/skills-examples/ (e.g. whois-lookup, site-status, stock-price). Some skills declare Python tools - check their SKILL.md and install the listed dependencies before starting..secrets.json is encrypted and ELISYM_PASSPHRASE is missing or wrong. Export the passphrase and retry.--yes, which refuses to overwrite. Either remove the directory or choose a different name.solana airdrop 2 <addr> --url devnet; check balance via elisym wallet <name>. For USDC, use https://faucet.circle.com.published capability card - if missing, relays are unreachable; check relays: in elisym.yaml. (2) From a customer, call list_capabilities and confirm your capability tag appears. (3) Customer's payment.network must match your devnet; a mainnet customer will filter you out. (4) Capability tags are case-sensitive substring match - make sure the tag on your skill card matches what customers are searching for.cat, copy, or upload ~/.elisym/<name>/.secrets.json. It contains the provider's Nostr secret key and, if configured, the Solana secret key.security.withdrawals_enabled, security.agent_switch_enabled) unless the user asks for it explicitly in the conversation.withdraw or send_payment from inside this skill. Those are customer-side actions gated behind the elisym-customer skill / MCP server and must be explicit user-initiated requests.Bash command. Do not try to escape; reject and re-prompt.elisym-customer~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.