npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@seed-hypermedia/cli

v0.0.11

Published

Command-line interface for Seed Hypermedia

Readme

Seed Hypermedia CLI

A command-line interface for interacting with the Seed Hypermedia network. Create, read, update, and delete documents; manage accounts, comments, contacts, and capabilities; sign content with Ed25519 keys — all from your terminal.

Package: @seed-hypermedia/cli Version: 0.1.1 License: MIT Requires: Node.js >= 18.0.0

Table of Contents


Installation

# Install globally via npm
npm install -g @seed-hypermedia/cli

# Or run directly with npx (no install needed)
npx -y @seed-hypermedia/cli --help

After installation, the CLI is available as both seed-cli and seed-hypermedia.

Development Mode

cd frontend/apps/cli

# Run directly with bun
bun run src/index.ts [command]

# Or use the dev script
bun run dev [command]

Quick Start

# 1. Generate a signing key
seed-cli key generate -n mykey --show-mnemonic

# 2. Create a document
seed-cli document create z6MkrbYs... --title "My First Document" --body "Hello, world!"

# 3. Read it back
seed-cli document get hm://z6MkrbYs.../my-first-document --md

# 4. Search for content
seed-cli search "hello world"

# 5. List all accounts
seed-cli account list

Global Options

These options apply to every command and must appear before the subcommand:

| Option | Description | | -------------------- | ------------------------------------------------------------- | | -s, --server <url> | Server URL (default: https://hyper.media or $SEED_SERVER) | | --json | JSON output (default) | | --yaml | YAML output | | --pretty | Pretty-formatted colorized output | | -q, --quiet | Minimal output (tab-separated values for scripting) | | --dev | Use development keyring (seed-daemon-dev) | | -V, --version | Display version number | | -h, --help | Display help |

Examples:

# Use a different server
seed-cli --server http://localhost:4000 account list

# Get YAML output
seed-cli account list --yaml

# Pretty-printed colorized JSON
seed-cli account get z6Mk... --pretty

# Quiet mode for piping
seed-cli account list -q | head -5

# Use development keyring
seed-cli --dev key list

Configuration

The CLI stores configuration in ~/.seed/config.json (mode 0600).

config

Manage CLI configuration.

| Option | Description | | ---------------- | -------------------------- | | --server <url> | Set default server URL | | --show | Show current configuration |

# Show current config
seed-cli config --show

# Set default server
seed-cli config --server https://my-server.example.com

Config fields:

| Field | Description | | ---------------- | ------------------------------------- | | server | Default server URL | | defaultAccount | Account ID of the default signing key |


Document Commands

All document commands live under seed-cli document <subcommand>.

document get

Fetch a document, comment, or entity by Hypermedia ID.

seed-cli document get <id> [options]

| Option | Description | | ---------------- | ------------------------------------------------------- | | -m, --metadata | Fetch metadata only (faster, skips content) | | --md | Output as Markdown | | --frontmatter | Include YAML frontmatter (requires --md) | | -r, --resolve | Resolve embeds, mentions, and queries (requires --md) | | -q, --quiet | Print document title only (or ID if untitled) |

Examples:

# Get full document as JSON
seed-cli document get hm://z6Mk.../my-doc

# Get as Markdown
seed-cli document get hm://z6Mk.../my-doc --md

# Get as Markdown with YAML frontmatter and resolved embeds
seed-cli document get hm://z6Mk.../my-doc --md --frontmatter --resolve

# Get metadata only (name, summary, etc.)
seed-cli document get hm://z6Mk.../my-doc -m

# Get a specific version
seed-cli document get "hm://z6Mk.../my-doc?v=bafy2bzace..."

# Get a nested child document
seed-cli document get hm://z6Mk.../projects/alpha

# Get just the title
seed-cli document get hm://z6Mk.../my-doc -q

# Also works for comments
seed-cli document get "hm://z6Mk...?c=bafy..."

Behavior:

  • When the resource is a document, outputs document content.
  • When the resource is a comment, outputs comment content.
  • With --md, converts block content to GitHub-flavored Markdown.
  • With --md --resolve, fetches embedded documents and query results, inlining their content.
  • With --metadata, fetches only the lightweight metadata payload.

document create

Create a new document from Markdown or HMBlockNodes JSON.

seed-cli document create <account> [options]

| Option | Description | | ---------------------- | ---------------------------------------- | | --title <title> | Required. Document title | | -p, --path <path> | Document path (default: slugified title) | | --body <text> | Markdown content (inline) | | --body-file <file> | Read Markdown content from a file | | --blocks <json> | HMBlockNodes JSON (inline) | | --blocks-file <file> | Read HMBlockNodes JSON from a file | | -k, --key <name> | Signing key name or account ID |

Constraints:

  • Exactly one content source is required: --body, --body-file, --blocks, or --blocks-file.
  • --body/--body-file and --blocks/--blocks-file are mutually exclusive.
  • The --title option is required.

Examples:

# Create with inline Markdown
seed-cli document create z6Mk... --title "My Article" --body "# Introduction\n\nHello!"

# Create from a Markdown file
seed-cli document create z6Mk... --title "My Article" --body-file article.md

# Create from HMBlockNodes JSON
seed-cli document create z6Mk... --title "Structured Doc" --blocks-file blocks.json

# Create with custom path
seed-cli document create z6Mk... --title "My Article" --path "articles/2024/my-article" --body "content"

# Create with a specific signing key
seed-cli document create z6Mk... --title "My Article" --body "content" --key author

Under the hood:

  1. Creates a genesis change blob (empty, signed).
  2. Creates a document change blob containing the title and content operations.
  3. Creates a version ref blob pointing to the change.
  4. Publishes all three blobs to the server.

Output:

✓ Document created: hm://z6Mk.../my-article
ℹ Title: My Article
ℹ Path: /my-article
ℹ Genesis CID: bafy2bzace...
ℹ Change CID: bafy2bzace...

document update

Update document metadata, append content, replace content, or delete blocks.

seed-cli document update <id> [options]

| Option | Description | | ----------------------- | -------------------------------------------------------------------------------------- | | -f, --file <path> | Input file (format detected by extension: .md, .json). Diffs against existing content. | | --title <title> | Set document title | | --summary <summary> | Set document summary | | --parent <blockId> | Parent block ID for new content (default: root) | | --delete-blocks <ids> | Comma-separated block IDs to delete | | -k, --key <name> | Signing key name or account ID |

Constraints:

  • At least one update option must be specified.

Examples:

# Update the title
seed-cli document update hm://z6Mk.../my-doc --title "New Title"

# Update content from a Markdown file (smart diff — only changed blocks are submitted)
seed-cli document update hm://z6Mk.../my-doc -f updated.md

# Delete specific blocks
seed-cli document update hm://z6Mk.../my-doc --delete-blocks "blk-abc123,blk-def456"

# Combine metadata and content updates
seed-cli document update hm://z6Mk.../my-doc --title "Updated" --summary "A summary" -f content.md

Smart diff (-f):

When -f is used, the CLI performs a per-block diff against the existing document:

  1. Each input block's ID is checked against the old document's block map.
  2. If the ID exists: content is compared, and only changed blocks get a ReplaceBlock op.
  3. If the ID doesn't exist: the block is treated as new (emits ReplaceBlock).
  4. Old blocks whose IDs are absent from the input are deleted (DeleteBlocks).
  5. Block ordering is updated via MoveBlocks.

This means editing a document exported with document get (which includes <!-- id:... --> comments in Markdown, or block IDs in JSON) produces minimal updates. Plain Markdown without ID comments results in a full body replacement, since none of the generated IDs will match the existing document.


document delete

Delete a document by publishing a tombstone ref.

seed-cli document delete <id> [options]

| Option | Description | | ------------------ | ------------------------------ | | -k, --key <name> | Signing key name or account ID |

seed-cli document delete hm://z6Mk.../my-doc --key author

The document isn't physically removed — a tombstone ref is published, which tells clients the document has been intentionally deleted.


document fork

Fork a document to a new location (creates a copy).

seed-cli document fork <sourceId> <destinationId> [options]

| Option | Description | | ------------------ | ------------------------------ | | -k, --key <name> | Signing key name or account ID |

seed-cli document fork hm://z6Mk.../original hm://z6Mk.../copy --key author

Behavior:

  • Creates a version ref at the destination pointing to the source's genesis and version.
  • Does not create a redirect at the source (unlike move).
  • The fork is an independent copy that shares the same genesis.

document move

Move a document to a new location (fork + redirect at source).

seed-cli document move <sourceId> <destinationId> [options]

| Option | Description | | ------------------ | ------------------------------ | | -k, --key <name> | Signing key name or account ID |

seed-cli document move hm://z6Mk.../old-path hm://z6Mk.../new-path --key author

Behavior:

  1. Creates a version ref at the destination (same as fork).
  2. Creates a redirect ref at the source pointing to the destination.
  3. Clients following the source URL will be transparently redirected.

document redirect

Create a redirect from one document to another.

seed-cli document redirect <id> [options]

| Option | Description | | ------------------ | ------------------------------------------------- | | --to <targetId> | Required. Target Hypermedia ID to redirect to | | --republish | Republish target content at this location | | -k, --key <name> | Signing key name or account ID |

# Simple redirect
seed-cli document redirect hm://z6Mk.../old-page --to hm://z6Mk.../new-page

# Redirect with content republishing
seed-cli document redirect hm://z6Mk.../mirror --to hm://z6Mk.../original --republish

document changes

List document change history (version DAG).

seed-cli document changes <targetId> [options]

| Option | Description | | ------------- | -------------------------------- | | -q, --quiet | Output CID<tab>author per line |

# Full change history
seed-cli document changes hm://z6Mk.../my-doc

# Compact: CID and author per line
seed-cli document changes hm://z6Mk.../my-doc -q

Output includes:

  • Change ID (CID)
  • Author account ID
  • Dependencies (parent changes in the DAG)
  • Create time
  • Latest version CID

document stats

Get interaction statistics for a document.

seed-cli document stats <id>
seed-cli document stats hm://z6Mk.../my-doc

Output includes:

  • Citation count (incoming links)
  • Comment count
  • Change count (edit history)
  • Child document count
  • Per-block citation and comment counts

document cid

Fetch a raw IPFS block by its CID.

seed-cli document cid <cid>
seed-cli document cid bafy2bzace...

Returns the decoded IPLD block data as JSON.


Account Commands

All account commands live under seed-cli account <subcommand>.

account get

Get account information.

seed-cli account get <uid> [options]

| Option | Description | | ------------- | --------------------------------------- | | -q, --quiet | Print name only (or UID if no name set) |

# Full account info
seed-cli account get z6MkrbYs...

# Pretty print
seed-cli account get z6MkrbYs... --pretty

# Just the name
seed-cli account get z6MkrbYs... -q

account list

List all known accounts on the server.

seed-cli account list [options]

| Option | Description | | ------------- | ----------------------------- | | -q, --quiet | Output ID<tab>name per line |

# Full JSON
seed-cli account list

# Compact for scripting
seed-cli account list -q

account contacts

List contacts for an account.

seed-cli account contacts <uid> [options]

| Option | Description | | ------------- | ----------------- | | -q, --quiet | Output names only |

seed-cli account contacts z6Mk...
seed-cli account contacts z6Mk... -q

account capabilities

List access control capabilities for a resource.

seed-cli account capabilities <id>
seed-cli account capabilities hm://z6Mk...

Output includes: capability ID, issuer, delegate, role, path restrictions, recursive flag.


Comment Commands

All comment commands live under seed-cli comment <subcommand>.

comment get

Get a single comment by ID.

seed-cli comment get <id>
seed-cli comment get "hm://z6Mk...?c=bafy..."

comment list

List all comments on a document.

seed-cli comment list <targetId> [options]

| Option | Description | | ------------- | ----------------------------------- | | -q, --quiet | Output ID<tab>authorName per line |

seed-cli comment list hm://z6Mk.../my-doc
seed-cli comment list hm://z6Mk.../my-doc -q

comment create

Create a comment on a document.

seed-cli comment create <targetId> [options]

| Option | Description | | --------------------- | ---------------------------------------- | | --body <text> | Comment text (inline) | | --file <path> | Read comment text from file | | --reply <commentId> | Reply to an existing comment (threading) | | -k, --key <name> | Signing key name or account ID |

Examples:

# Top-level comment
seed-cli comment create hm://z6Mk.../my-doc --body "Great article!" --key reviewer

# Reply to a comment (creates a thread)
seed-cli comment create hm://z6Mk.../my-doc --body "Thanks!" --reply bafy... --key author

# Comment on a specific block (block-level annotation)
seed-cli comment create "hm://z6Mk.../my-doc#blk-abc123" --body "This paragraph needs work" --key editor

# Read comment from file
seed-cli comment create hm://z6Mk.../my-doc --file review.txt --key reviewer

Inline mentions:

Comment text supports inline mentions using the format @[DisplayName](hm://accountId). Mentions are converted to Embed annotations with a U+FFFC object replacement character.

seed-cli comment create hm://z6Mk.../doc --body "cc @[Alice](hm://z6MkAlice...)" --key bob

Block-level comments:

When the target ID includes a #blockId fragment, the comment body is automatically wrapped in an Embed block referencing the specific block. This matches the behavior of the desktop and web apps for block-level annotations.

Threading:

When --reply is specified, the CLI fetches the parent comment to determine the thread root. If the parent is already a reply, the thread root is inherited. Otherwise, the parent comment itself becomes the thread root.


comment edit

Edit an existing comment.

seed-cli comment edit <commentId> [options]

| Option | Description | | ------------------ | ------------------------------ | | --body <text> | Updated comment text (inline) | | --file <path> | Read updated text from file | | -k, --key <name> | Signing key name or account ID |

Examples:

# Edit inline
seed-cli comment edit z6MkAuthor.../zb2rComment... --body "Updated wording" --key reviewer

# Edit from file
seed-cli comment edit z6MkAuthor.../zb2rComment... --file review-update.txt --key reviewer

The CLI preserves reply threading metadata for replies and keeps the block-level anchor wrapper for comments that were originally attached to a specific block.


comment delete

Delete a comment by publishing a tombstone.

seed-cli comment delete <commentId> [options]

| Option | Description | | ------------------ | ------------------------------ | | -k, --key <name> | Signing key name or account ID |

seed-cli comment delete bafy... --key reviewer

comment discussions

List threaded discussions on a document.

seed-cli comment discussions <targetId> [options]

| Option | Description | | -------------------- | --------------------------- | | -c, --comment <id> | Filter to a specific thread |

# All discussions
seed-cli comment discussions hm://z6Mk.../my-doc

# A specific thread
seed-cli comment discussions hm://z6Mk.../my-doc --comment bafy...

Contact Commands

All contact commands live under seed-cli contact <subcommand>.

contact create

Create a contact (a named reference to another account).

seed-cli contact create [options]

| Option | Description | | ----------------------- | ------------------------------------------ | | --subject <accountId> | Required. Account ID being described | | --name <name> | Required. Display name for the contact | | -k, --key <name> | Signing key name or account ID |

seed-cli contact create --subject z6MkAlice... --name "Alice" --key mykey

Output: Contact record ID in authority/tsid format.


contact delete

Delete a contact by publishing a tombstone.

seed-cli contact delete <contactIdOrCid> [options]

| Option | Description | | ------------------ | ------------------------------ | | -k, --key <name> | Signing key name or account ID |

Accepts either a record ID (authority/tsid) or a CID. If given a CID, the CLI fetches the blob to compute the record ID.

seed-cli contact delete z6Mk.../zQ3sh... --key mykey
seed-cli contact delete bafy... --key mykey

contact list

List contacts for an account.

seed-cli contact list [accountId] [options]

| Option | Description | | ----------- | --------------------------------------------------- | | --account | Only show contacts signed by the account | | --subject | Only show contacts where the account is the subject |

By default, shows contacts in both directions (signed by and about the account).

# Both directions
seed-cli contact list z6Mk...

# Only contacts this account created
seed-cli contact list z6Mk... --account

# Only contacts about this account
seed-cli contact list z6Mk... --subject

Capability Commands

All capability commands live under seed-cli capability <subcommand>.

capability create

Create a capability (delegate access to another account).

seed-cli capability create [options]

| Option | Description | | ------------------------ | --------------------------------------- | | --delegate <accountId> | Required. Account receiving access | | --role <role> | Required. Role: WRITER or AGENT | | --path <path> | Path scope for the capability | | --label <label> | Human-readable label | | -k, --key <name> | Signing key name or account ID |

# Grant full write access
seed-cli capability create --delegate z6MkBob... --role WRITER --key alice

# Grant write access scoped to a path
seed-cli capability create --delegate z6MkBot... --role AGENT --path /blog --label "Blog bot" --key alice

Key Management Commands

All key commands live under seed-cli key <subcommand>. The keys alias also works.

Keys are stored in the OS keyring (macOS Keychain / Linux libsecret), shared with the Seed desktop app and Go daemon. Keys created in the desktop app are immediately available to the CLI, and vice versa.

key generate

Generate a new signing key from a BIP-39 mnemonic.

seed-cli key generate [options]

| Option | Description | | --------------------- | ------------------------------------------------- | | -n, --name <name> | Key name (default: main) | | -w, --words <count> | Mnemonic word count: 12 or 24 (default: 12) | | --passphrase <pass> | Optional BIP-39 passphrase | | --show-mnemonic | Display the mnemonic (save it securely!) |

# Generate with default settings
seed-cli key generate

# Generate a named key with 24 words and show the mnemonic
seed-cli key generate -n secure-key --words 24 --show-mnemonic

# Generate with passphrase
seed-cli key generate -n protected --passphrase "my secret"

Key name rules: Only alphanumeric characters, hyphens, and underscores.


key import

Import a key from an existing BIP-39 mnemonic.

seed-cli key import <mnemonic> [options]

| Option | Description | | --------------------- | ------------------------------ | | -n, --name <name> | Key name (default: imported) | | --passphrase <pass> | Optional BIP-39 passphrase |

seed-cli key import -n restored "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"

seed-cli key import -n restored --passphrase "secret" "word1 word2 ... word12"

key list

List all stored signing keys.

seed-cli key list

| Option | Description | | ------------- | ------------------------------------ | | -q, --quiet | Output name<tab>accountId per line |

seed-cli key list
seed-cli key list -q

key show

Show information for a specific key, or the default key if none specified.

seed-cli key show [nameOrId]

Accepts a key name or account ID.

# Show default key
seed-cli key show

# Show by name
seed-cli key show main

# Show by account ID
seed-cli key show z6Mk...

key default

Set or show the default signing key.

seed-cli key default [nameOrId]
# Show current default
seed-cli key default

# Set a new default
seed-cli key default mykey

Default key resolution order:

  1. Config defaultAccount (set by key default)
  2. Key named main
  3. First key in the keyring

key remove

Remove a stored key.

seed-cli key remove <nameOrId> [options]

| Option | Description | | ------------- | ----------------- | | -f, --force | Skip confirmation |

# Shows warning, requires --force
seed-cli key remove mykey

# Actually remove
seed-cli key remove mykey --force

key rename

Rename a stored key.

seed-cli key rename <currentName> <newName>
seed-cli key rename old-name new-name

key derive

Derive an account ID from a mnemonic without storing the key.

seed-cli key derive <mnemonic> [options]

| Option | Description | | --------------------- | -------------------------- | | --passphrase <pass> | Optional BIP-39 passphrase |

seed-cli key derive "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
# Output: z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp

Useful for verifying a mnemonic maps to the expected account without writing it to the keyring.


Search & Discovery Commands

These are top-level commands (not subcommands).

search

Search for documents across the network.

seed-cli search <query> [options]

| Option | Description | | --------------------- | ---------------------------------- | | -a, --account <uid> | Limit search to a specific account | | -q, --quiet | Output ID<tab>title per line |

seed-cli search "artificial intelligence"
seed-cli search "meeting notes" --account z6Mk...
seed-cli search "project" -q

query

List documents in a space (account).

seed-cli query <space> [options]

| Option | Description | | ------------------- | ------------------------------------------------------------------- | | -p, --path <path> | Path prefix to filter | | -m, --mode <mode> | Children (default) or AllDescendants | | -l, --limit <n> | Maximum results | | --sort <term> | Sort by: Path, Title, CreateTime, UpdateTime, DisplayTime | | --reverse | Reverse sort order | | -q, --quiet | Output ID<tab>name per line |

# List direct children
seed-cli query z6Mk...

# List all descendants recursively
seed-cli query z6Mk... --mode AllDescendants

# List children under a specific path
seed-cli query z6Mk... --path projects

# Sort by update time, newest first
seed-cli query z6Mk... --sort UpdateTime --reverse

# Limit to 5 results
seed-cli query z6Mk... --limit 5

children

Shorthand for query --mode Children.

seed-cli children <space> [options]

| Option | Description | | ------------------- | ----------------------------- | | -p, --path <path> | Path prefix | | -l, --limit <n> | Limit results | | -q, --quiet | Output ID<tab>name per line |

# These are equivalent:
seed-cli children z6Mk...
seed-cli query z6Mk... --mode Children

citations

List documents that cite (link to) a given resource.

seed-cli citations <id> [options]

| Option | Description | | ------------- | ---------------------- | | -q, --quiet | Output source IDs only |

seed-cli citations hm://z6Mk.../my-doc
seed-cli citations hm://z6Mk.../my-doc -q

activity

List recent activity events across the network.

seed-cli activity [options]

| Option | Description | | --------------------- | --------------------------------------- | | -l, --limit <n> | Page size | | -t, --token <token> | Pagination token (from previous output) | | --authors <uids> | Filter by author UIDs (comma-separated) | | --resource <id> | Filter by resource | | -q, --quiet | Output event count + next token only |

# Recent activity
seed-cli activity

# Paginate
seed-cli activity --limit 20
seed-cli activity --limit 20 --token <nextPageToken>

# Filter by author
seed-cli activity --authors z6Mk...

# Filter by resource
seed-cli activity --resource hm://z6Mk.../my-doc

Hypermedia ID Format

Seed uses Hypermedia IDs (HM IDs) as universal resource identifiers:

hm://<uid>[/<path>][?v=<version>][?c=<commentCID>][#<blockRef>]

| Component | Description | Example | | ------------ | ------------------------------------- | -------------------- | | uid | Account's Ed25519 public key ID | z6MkrbYsRzKb1VA... | | path | Forward-slash-separated path segments | /projects/alpha | | version | CID of a specific document version | ?v=bafy2bzace... | | commentCID | CID of a comment | ?c=bafy2bzace... | | blockRef | Specific block ID within the document | #blk-abc123 |

Examples:

hm://z6MkrbYsRzKb1VABdvhsDSAk6JK8fAszKsyHhcaZigYeWCou
hm://z6MkrbYs.../projects/alpha
hm://z6MkrbYs.../my-doc?v=bafy2bzacedfvn...
hm://z6MkrbYs.../my-doc#blk-abc123
hm://z6MkrbYs...?c=bafy2bzace...

The CLI also accepts bare UIDs (without the hm:// prefix) in most places.


Output Formats

JSON (default)

Pretty-printed with 2-space indentation. BigInt values are serialized as strings.

seed-cli account list
{
  "accounts": [
    {
      "id": {"id": "hm://z6Mk...", "uid": "z6Mk..."},
      "metadata": {"name": "Account Name"}
    }
  ]
}

YAML

seed-cli account list --yaml
accounts:
  - id:
      id: hm://z6Mk...
      uid: z6Mk...
    metadata:
      name: Account Name

Pretty

Colorized JSON output:

  • Green: strings
  • Yellow: numbers
  • Blue: booleans
  • Cyan: object keys
  • Dim gray: null
seed-cli account list --pretty

Quiet

Tab-separated values, one record per line. Ideal for piping to awk, cut, grep, etc.

seed-cli account list -q
# hm://z6Mk...	Account Name
# hm://z6Mk...	Another Account

Markdown Conversion

Document to Markdown (--md)

When using document get --md, the CLI converts the internal block tree to GitHub-flavored Markdown:

| Block type | Markdown rendering | | ------------- | ----------------------------------------------------------- | | Heading | #, ##, ###, etc. based on depth | | Paragraph | Plain text with inline formatting | | Code | Fenced code blocks with language tag | | Math | $$...$$ LaTeX blocks | | Image | ![alt](gateway-url) (IPFS CIDs converted to gateway URLs) | | Embed | Blockquote with link (or inlined content with --resolve) | | Query | Resolved to a list of linked documents (with --resolve) | | Button | [text](url) link | | Bold | **text** | | Italic | *text* | | Code (inline) | `text` | | Link | [text](url) |

Frontmatter (--frontmatter):

---
title: Document Title
summary: A brief description
version: bafy2bzace...
authors:
  - z6Mk...
---

Resolve mode (--resolve):

Fetches embedded documents and query results from the server and inlines their content directly in the Markdown output, up to a default recursion depth of 2.

Markdown to Blocks (input)

When creating or updating documents with --body or --body-file, the CLI parses Markdown into the internal block tree:

| Markdown element | Block type | | -------------------- | ----------------------------------------------- | | # Heading | Heading container with children | | Paragraphs | Paragraph blocks | | ```code``` | Code block with language attribute | | **bold** | Bold annotation | | *italic* | Italic annotation | | `code` | Code annotation | | [text](url) | Link annotation | | - item / 1. item | Children with childrenType: Unordered/Ordered |


Key Storage & Cryptography

Where Keys Live

Keys are stored in the OS keyring, not on disk:

| Platform | Backend | CLI tool used | | -------- | -------------------------------- | ------------- | | macOS | Keychain | security | | Linux | D-Bus Secret Service (libsecret) | secret-tool |

The keyring is shared with the Go daemon and desktop app. Keys registered in any Seed application are available in all others.

Keyring Service Names

| Environment | Service Name | Selected by | | ----------- | ------------------ | ------------------- | | Production | seed-daemon-main | Default | | Development | seed-daemon-dev | --dev global flag |

Key Encoding Format

Each key is stored as a 68-byte libp2p protobuf-encoded Ed25519 key pair, base64-encoded:

[08 01 12 40] [32-byte private seed] [32-byte public key]
 ─── header ───  ─── 64 bytes of key data ───

The 4-byte header is:

  • 08 01 — protobuf field 1 (key type) = 1 (Ed25519)
  • 12 40 — protobuf field 2 (key data) length = 64 bytes

Account ID Derivation

32-byte Ed25519 public key
  ↓ prepend multicodec prefix [0xed, 0x01]
34-byte multicodec key
  ↓ base58btc encode (multibase prefix 'z')
Account ID string (starts with "z6Mk")

Key Derivation from Mnemonic

BIP-39 Mnemonic + optional Passphrase
  ↓ bip39.mnemonicToSeedSync()
64-byte seed
  ↓ SLIP-10 derivation at path m/44'/104109'/0'
32-byte Ed25519 private key
  ↓ ed25519.getPublicKey()
32-byte Ed25519 public key
  ↓ computeAccountId()
Account ID (z6Mk...)

The derivation path 104109 is the Unicode codepoint sum for h + m (104 + 109).

Cross-Format Compatibility

The keyring JSON payload uses two formats:

  1. Plain JSON — written by the CLI
  2. go-keyring-base64:<base64> — written by the Go daemon

The CLI reads both formats transparently. When writing, it uses the go-keyring-base64: format for compatibility with the daemon.


Signing & Blob Architecture

All mutable data in Seed is stored as signed CBOR blobs. The CLI creates and signs these blobs client-side before publishing them to the server.

Signing Process

  1. Create the unsigned object with sig: new Uint8Array(64) (zeroed) and ts: 0n.
  2. CBOR-encode the unsigned object.
  3. Sign the CBOR bytes with Ed25519.
  4. Fill in the actual sig and ts values.
  5. CBOR-encode the final signed object.
  6. Compute the SHA-256 CID of the encoded bytes.
  7. Publish with the explicit CID.

Blob Types

Genesis Change: The root of every document's change DAG.

{type: "Change", signer, sig, ts: 0n}

Document Change: Mutations to document content and metadata.

{type: "Change", signer, sig, ts, genesis: CID, deps: CID[], depth, body: {ops, opCount}}

Version Ref: Points clients to the current document head.

{type: "Ref", signer, sig, ts, space, path, genesis, version, generation}

Tombstone Ref: Marks a document as deleted.

Redirect Ref: Points one document to another.

Comment: A signed comment blob attached to a document version.

Contact: A named reference from one account to another.

Capability: A delegation of write or agent access.

Document Operations

Changes contain arrays of operations:

| Operation | Description | | --------------- | ------------------------------ | | SetAttributes | Set metadata key-value pairs | | ReplaceBlock | Insert or replace a block | | MoveBlocks | Move blocks under a new parent | | DeleteBlocks | Remove blocks by ID |


Environment Variables

| Variable | Description | | ------------- | ---------------------------------------------------- | | SEED_SERVER | Default server URL (overrides https://hyper.media) |


Error Handling

Exit codes:

| Code | Meaning | | ---- | ----------------------------------------------------- | | 0 | Success | | 1 | Error (invalid input, network error, not found, etc.) |

Error output: Errors are printed to stderr with a red prefix.

Common errors:

| Error | Cause | | --------------------------------------------------------------- | -------------------------------------------------- | | Invalid Hypermedia ID | Malformed hm:// URL | | API error (500): ... | Server-side error or resource not found | | Key "name" not found | No key with that name or account ID in the keyring | | No signing keys found | Must run key generate or key import first | | Cannot combine --body/--body-file with --blocks/--blocks-file | Mutually exclusive options |


Scripting Examples

Export all documents as Markdown

#!/bin/bash
ACCOUNT="z6MkrbYsRzKb1VABdvhsDSAk6JK8fAszKsyHhcaZigYeWCou"

seed-cli query "$ACCOUNT" --mode AllDescendants -q | while IFS=$'\t' read -r id name; do
  filename=$(echo "$name" | tr ' /' '_' | tr -cd '[:alnum:]_-')
  [ -z "$filename" ] && filename="unnamed_$(echo "$id" | md5sum | head -c 8)"
  seed-cli document get "$id" --md --resolve > "${filename}.md"
  echo "Exported: ${filename}.md"
done

Create a document from a Markdown file

#!/bin/bash
ACCOUNT="z6Mk..."
TITLE="$(head -1 "$1" | sed 's/^# //')"

seed-cli document create "$ACCOUNT" \
  --title "$TITLE" \
  --body-file "$1" \
  --key main

Batch update documents from local files

#!/bin/bash
for file in docs/*.md; do
  DOC_PATH=$(basename "$file" .md)
  ID="hm://z6Mk.../$DOC_PATH"
  echo "Updating $ID from $file"
  seed-cli document update "$ID" -f "$file" --key main
done

Monitor activity feed

#!/bin/bash
TOKEN=""
while true; do
  if [ -n "$TOKEN" ]; then
    OUTPUT=$(seed-cli activity --limit 10 --token "$TOKEN")
  else
    OUTPUT=$(seed-cli activity --limit 10)
  fi
  echo "$OUTPUT" | jq '.events[] | "\(.eventType) by \(.author)"'
  TOKEN=$(echo "$OUTPUT" | jq -r '.nextPageToken // empty')
  sleep 60
done

Find all documents by a specific author

#!/bin/bash
AUTHOR="z6Mk..."
seed-cli activity --authors "$AUTHOR" --limit 100 | jq -r '.events[].resource' | sort -u

Delegate write access

#!/bin/bash
seed-cli capability create \
  --delegate z6MkBob... \
  --role WRITER \
  --key alice

seed-cli contact create \
  --subject z6MkBob... \
  --name "Bob" \
  --key alice

Backup all keys (show mnemonics)

#!/bin/bash
seed-cli key list -q | while IFS=$'\t' read -r name id; do
  echo "=== Key: $name ($id) ==="
  seed-cli key show "$name"
  echo ""
done

Development

cd frontend/apps/cli

# Run directly
bun run src/index.ts [command]

# Build for distribution
npm run build

# Type check
npm run typecheck

# Run fixture-based tests (starts a local daemon)
bun test src/test/cli-fixture.test.ts

# Run daemon integration tests
bun test src/test/cli.test.ts

# Run live server tests
bun test src/test/cli-live.test.ts

Project Structure

frontend/apps/cli/
├── src/
│   ├── index.ts              # Entry point, global options, command registration
│   ├── client.ts             # HTTP API client
│   ├── config.ts             # ~/.seed/config.json management
│   ├── output.ts             # Output formatting (JSON, YAML, pretty, table)
│   ├── markdown.ts           # Document → Markdown conversion
│   ├── commands/
│   │   ├── document.ts       # document get/create/update/delete/fork/move/redirect/changes/stats/cid
│   │   ├── comment.ts        # comment get/list/create/delete/discussions
│   │   ├── capability.ts     # capability create
│   │   ├── contact.ts        # contact create/delete/list
│   │   ├── account.ts        # account get/list/contacts/capabilities
│   │   ├── key.ts            # key generate/import/list/show/default/remove/rename/derive
│   │   ├── search.ts         # search
│   │   └── query.ts          # query/children/citations/activity
│   ├── utils/
│   │   ├── keyring.ts        # Cross-platform OS keyring access
│   │   ├── key-derivation.ts # BIP-39/SLIP-10 key derivation
│   │   ├── signing.ts        # CBOR blob signing (genesis, changes)
│   │   ├── markdown.ts       # Markdown → blocks parser
│   │   ├── blocks-json.ts    # HMBlockNodes JSON parser
│   │   ├── block-diff.ts     # Smart block diffing for document update
│   │   ├── depth.ts          # Change DAG depth resolution
│   │   └── hm-id.ts          # Hypermedia ID pack/unpack
│   └── test/
│       ├── cli-fixture.test.ts  # Fixture-based integration tests
│       ├── cli.test.ts          # Daemon integration tests
│       └── cli-live.test.ts     # Live server tests
├── docs/
│   ├── API.md                # HTTP API reference
│   ├── KEYS.md               # Key management internals
│   ├── SIGNING.md            # Signing and blob creation reference
│   └── TYPES.md              # Type definitions reference
└── package.json

Dependencies

| Package | Purpose | | ------------------------- | --------------------------- | | commander | CLI framework | | multiformats | CID/IPLD handling | | @ipld/dag-cbor | CBOR encoding | | @noble/ed25519 | Ed25519 signatures | | @noble/hashes | Cryptographic hashing | | @exodus/slip10 | SLIP-10 key derivation | | bip39 | BIP-39 mnemonics | | chalk | Terminal colors | | yaml | YAML formatting | | @seed-hypermedia/client | SDK for document operations |


Further Reading