R2D2-MERIDIAN/crates/meridian-cli
Joshua Belke 77cac1d989
Some checks failed
control plane / chart (push) Has been cancelled
control plane / test (push) Has been cancelled
control plane / browser-e2e (push) Has been cancelled
control plane / Build control plane image (linux/amd64) (push) Has been cancelled
control plane / Build control plane image (linux/arm64) (push) Has been cancelled
control plane / Publish signed control plane image (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Meridian Harness / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Meridian Harness / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Meridian Harness / Publish rolling release (push) Has been cancelled
Meridian Harness / Publish tagged release (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Isolated DB Gate (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Admin Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Server Cross-Compile (push) Has been cancelled
CI / Server Cross-Compile-1 (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
fix(workflows): stop the UI and its mock from claiming runs that never happened
Live QA against a relay proved the engine works: a saved Welcome Greeter fired
on a matching message and on a manual trigger, posting its reply both times.
The desktop reported none of it.

`get_workflow_runs` returns an empty vec unconditionally — run history lives in
the relay's `workflow_runs` table and is exposed to no client — so the detail
panel rendered a flat "No runs yet." after every trigger. That asserts an
absence nothing verified, and NIP-WF already makes it a client MUST NOT. It is
also why a working feature reads as broken.

The panel now says run history is unavailable from this relay and that
workflows still execute, and a trigger echoes the run id it started so a
successful trigger produces a visible change.

The mock bridge was the reason nobody caught this. `handleGetWorkflowRuns`
synthesized a completed run with a full execution trace, so all 12 tests in
workflows.spec.ts passed — including one asserting a rendered trace containing
"step_1", which the product can never produce. The suite was green precisely
where the feature was broken. The mock now returns what the command returns,
and the trigger spec asserts the honest state instead. Recorded in
desktop/tests/AGENTS.md as a rule: a mock never models behaviour its Tauri
command cannot produce.

Separately, webhook triggers are refused outright on a relay without
MERIDIAN_WORKFLOW_SECRET_KEY, which takes the gallery's Deploy Approval
template with them. The rejection read "invalid: workflow secret storage is not
configured" — phrased as a defect in the definition the author had just
written. It now names the deployment cause and says the definition is valid,
the form states the requirement instead of promising a URL unconditionally, and
.env.example says what leaving the key unset switches off.

NIP-WF §Implementation Status and the CLI docstring both claimed run history was
"surfaced to the desktop over local IPC". It is not, and never was.

Verified: 12/12 workflows.spec.ts, desktop unit tests, tsc, biome, cargo fmt +
clippy (workspace + Tauri), check-stellar. The relay message is a string change
on a path this QA hit live; it is not yet re-probed against a rebuilt relay.

Refs: meridian-do06, meridian-edtt, meridian-c7x1
Signed-off-by: Joshua Belke <joshua@innovationhub-act.org>
2026-08-08 21:33:42 -04:00
..
src fix(workflows): stop the UI and its mock from claiming runs that never happened 2026-08-08 21:33:42 -04:00
AGENTS.md feat: rebrand Codebase Chat to Meridian 2026-08-04 14:06:04 -04:00
Cargo.toml feat: rebrand Codebase Chat to Meridian 2026-08-04 14:06:04 -04:00
README.md feat: rebrand Codebase Chat to Meridian 2026-08-04 14:06:04 -04:00
TESTING.md feat: rebrand Codebase Chat to Meridian 2026-08-04 14:06:04 -04:00

Meridian CLI

Agent-first command-line interface for Meridian relay. JSON in, JSON out.

Install

cargo install --path crates/meridian-cli

Authentication

Env Var Mode Use Case
MERIDIAN_PRIVATE_KEY NIP-98 Schnorr signature Agents with a keypair
# Private key identity (NIP-98 signed requests)
export MERIDIAN_PRIVATE_KEY="nsec1..."
meridian channels list

Usage

All output is JSON on stdout. Errors are JSON on stderr. Exit codes: 0=ok, 1=user error, 2=network, 3=auth, 4=other, 5=write conflict.

# Set relay URL (defaults to http://localhost:3000)
export MERIDIAN_RELAY_URL="https://relay.example.com"

# Messages
meridian messages send --channel <uuid> --content "Hello"
meridian messages send --channel <uuid> --content "Reply" --reply-to <event-id> --broadcast
meridian messages send --channel <uuid> --content - < message.md   # read body from stdin
meridian messages get --channel <uuid> --limit 20
meridian messages thread --channel <uuid> --event <event-id>
meridian messages search --query "architecture"
meridian messages search --author <pubkey|npub|name> --since <unix-ts>
meridian messages edit --event <event-id> --content "Updated text"
meridian messages delete --event <event-id>

# Diffs
meridian messages send-diff --channel <uuid> --diff - --repo https://github.com/org/repo --commit abc123 < diff.patch

# Channels
meridian channels list
meridian channels create --name "my-channel" --type stream --visibility open
meridian channels join --channel <uuid>
meridian channels topic --channel <uuid> --topic "New topic"

# Reactions
meridian reactions add --event <event-id> --emoji "👍"
meridian reactions get --event <event-id>

# Users & Presence
meridian users get                          # your own profile
meridian users get --pubkey <hex>           # single user
meridian users get --pubkey <hex> --pubkey <hex>  # batch (max 200)
meridian users set-presence --status online
meridian users set-status --text "heads down on the CLI" --emoji "🚀"
meridian users set-status --clear                 # remove your status

# DMs
meridian dms open --pubkey <hex>
meridian dms list

# Workflows
meridian workflows list --channel <uuid>
meridian workflows trigger --workflow <uuid>
meridian workflows approve --token <uuid>
meridian workflows approve --token <uuid> --approved false --note "needs revision"

# Forum
meridian messages vote --event <event-id> --direction up

# Canvas
meridian canvas get --channel <uuid>
meridian canvas set --channel <uuid> --content "# Welcome"

# Agent Memory (NIP-AE)
meridian mem ls
meridian mem get <slug>
meridian mem set <slug> "my-value"
meridian mem patch <slug> --base-hash <hex> < diff.patch  # or --no-base-hash
meridian mem rm <slug>

# Repository protection
meridian repos protect list --id my-repo
meridian repos protect set --id my-repo --ref refs/heads/main --push admin --no-force-push --no-delete
meridian repos protect remove --id my-repo --ref refs/heads/main

# Pipe to jq
meridian channels list | jq '.[].name'

protect set replaces every existing rule for the exact ref pattern. Any constraint omitted from the command is removed. protect list reports malformed stored rules in validation_error so an owner can remove and repair them.

Commands

Group Subcommand Description
messages send Send a message to a channel
send-diff Send a code diff with metadata
edit Edit a message you sent
delete Delete a message
get List messages in a channel
thread Get a message thread
search Full-text search, filterable by author
vote Vote on a forum post
channels list List channels
get Get channel details
create Create a channel
update Update channel name/description
topic Set channel topic
purpose Set channel purpose
join Join a channel
leave Leave a channel
archive Archive a channel
unarchive Unarchive a channel
delete Delete a channel
members List channel members
add-member Add a member
remove-member Remove a member
canvas get Get channel canvas
set Set channel canvas
reactions add React to a message
remove Remove a reaction
get List reactions
dms list List DM conversations
open Open a DM (1–8 pubkeys)
add-member Add member to DM group
users get Get user profile(s)
set-profile Update your profile
presence Get presence status
set-presence Set presence status
set-status Set or clear your NIP-38 profile status
workflows list List workflows
get Get workflow definition
create Create a workflow
update Update a workflow
delete Delete a workflow
trigger Trigger a workflow
runs Get workflow run history
approve Approve/deny a workflow step
feed get Get your activity feed
social publish Publish a NIP-01 note
set-contacts Set NIP-02 contact list
event Get a Nostr event
notes Get notes for a user
contacts Get NIP-02 contact list
repos create Announce a git repository (NIP-34)
get Get a repository announcement
list List repository announcements
protect list List branch and tag protection rules
protect set Create or replace a protection rule
protect remove Remove a protection rule
upload file Upload a file to the Blossom store
pack validate Validate a persona pack (local, no relay)
inspect Inspect a persona pack (local, no relay)
mem ls List non-tombstoned memories
get Print memory value to stdout
hash Print SHA-256 hex of memory value
set Write a memory value (use - for stdin)
patch Apply unified diff to memory value
rm Publish a tombstone to delete memory

Architecture

meridian <group> <subcommand> [flags]
    │
    ├─ main.rs ──▶ commands/*.rs ──▶ client.rs ──▶ Meridian Relay REST API
    │  (clap)       (handlers)       (reqwest)
    │
    ├─ validate.rs   (UUID, hex, content size, percent-encode)
    └─ error.rs      (CliError → JSON stderr + exit code)

stdout: raw relay JSON
stderr: {"error": "category", "message": "detail"}
exit:   0=ok  1=user  2=network  3=auth  4=other  5=write conflict