This is a Claude Code skill for the DFOS CLI. To install, copy the skill file and save it to your project:

mkdir -p .claude/skills/dfos
# paste into .claude/skills/dfos/SKILL.md

DFOS CLI

The dfos CLI is a local-first relay node for the DFOS protocol. It manages identities, content chains, beacons, and credentials. Your machine is a relay — all data is stored locally first, then optionally published to remote peers.

Installation

Check if dfos is already installed:

dfos version

If not installed, install via the preferred method for the platform:

macOS (Homebrew):

brew install metalabel/tap/dfos

Linux / macOS (curl):

curl -sSL https://protocol.dfos.com/install.sh | sh

Container:

docker pull ghcr.io/metalabel/dfos:latest

After installation, verify: dfos version. The CLI is a single static binary with no runtime dependencies.

Updating

# Homebrew
brew upgrade metalabel/tap/dfos

# Reinstall via script (fetches latest)
curl -sSL https://protocol.dfos.com/install.sh | sh

The CLI checks for updates automatically on each run (non-blocking, cached 24h). If a newer version exists, it prints a notice to stderr.

Core Concepts

Quick Start (Local-Only)

# 1. Create an identity
dfos identity create --name alice

# 2. Set as active identity (no relay needed)
dfos use alice

# 3. Create some content
dfos content create - <<'EOF'
{"$schema":"https://schemas.dfos.com/post/v1","body":"hello world"}
EOF

# 4. List and verify
dfos content list
dfos content verify <contentId>

No relay needed — the CLI is a local relay. All data lives in ~/.dfos/store/.

Quick Start (With Relay)

# 1. Add a public relay
dfos peer add nyc https://relay.nyc.lark717.xyz

# 2. Create an identity and publish to the relay
dfos identity create --name alice --peer nyc

# 3. Set as default context
dfos use alice@nyc

# 4. Verify setup
dfos status

Passing --peer on identity create auto-publishes the identity genesis operation to the relay after local creation.

Known Public Relays

Name URL Region
nyc https://relay.nyc.lark717.xyz US East
atx https://relay.atx.lark717.xyz US Central
lis https://relay.lis.lark717.xyz EU West

Add any of these with dfos peer add <name> <url>. Use dfos peer info <name> to verify connectivity.

Local-First by Default

The CLI is a local relay. All data lives in ~/.dfos/store/ — no remote peer or HTTP server needed for local operations. Creating identities, content, credentials, and beacons all work offline.

For local-only work, set the active identity with dfos use <name> (no @relay), pass --identity <name> on each command, or set the DFOS_IDENTITY=<name> env var:

dfos identity create --name alice

# Option 1: set as active identity
dfos use alice
dfos content create - <<'EOF'
{"body":"hello"}
EOF
dfos content list

# Option 2: pass --identity on each command
dfos --identity alice content verify <contentId>

# Option 3: use the env var
DFOS_IDENTITY=alice dfos content list

Remote peers (--peer) are only needed when you want to publish to or fetch from another relay. dfos serve exposes your local relay over HTTP so other peers can connect to it — you never need it for local work.

In headless or CI environments, set DFOS_NO_KEYCHAIN=1 to use file-based key storage instead of the OS keychain (which may prompt interactively).

Configuration

Config file: ~/.dfos/config.toml

active_context = "alice@prod"

[relays.prod]
url = "https://relay.nyc.lark717.xyz"
did = "did:dfos:..."

[identities.alice]
did = "did:dfos:..."

[defaults]
auth_token_ttl = "5m"
credential_ttl = "24h"

Context resolution (highest priority first):

  1. --ctx flag (or --identity / --peer individually)
  2. DFOS_CONTEXT environment variable
  3. active_context in config.toml

Environment variables:

Variable Purpose
DFOS_CONTEXT Override active context (identity@relay)
DFOS_IDENTITY Override active identity name
DFOS_RELAY Override active relay name
DFOS_CONFIG Config file path (default ~/.dfos/config.toml)
DFOS_NO_KEYCHAIN Force file-based key storage (useful in CI)
DFOS_DEBUG Enable debug logging
DFOS_NO_UPDATE_CHECK Disable version check

Command Reference

Identity

dfos identity create --name <name> [--peer <relay>]    # generate keys + sign genesis
dfos identity list                                      # list all known identities
dfos identity show <name|did>                           # show identity state
dfos identity keys <name|did>                           # show key state + keychain status
dfos identity update [--rotate-auth] [--rotate-controller]  # rotate keys
dfos identity delete [name|did]                          # sign identity deletion
dfos identity publish <name|did> --peer <relay>         # push to relay
dfos identity fetch <did> --peer <relay> [--name <n>]   # pull from relay

Content

# Create content chain (from file, stdin, or heredoc)
dfos content create <file|-|> [--peer <relay>] [--note <msg>]

# Inspect
dfos content list                           # list all content chains
dfos content show <contentId>               # show chain state
dfos content log <contentId>                # operation history
dfos content download <contentId> [-o file] # download blob

# Mutate
dfos content update <contentId> <file|-|> [--peer <relay>] [--note <msg>]
dfos content delete <contentId> [--peer <relay>]

# Publish / fetch
dfos content publish <contentId> --peer <relay>
dfos content fetch <contentId> --peer <relay>

# Verify integrity locally
dfos content verify <contentId>

Stdin and heredoc creation (common for scripting):

echo '{"body":"hello"}' | dfos content create - --peer prod

dfos content create - --peer prod <<'EOF'
{"$schema":"https://schemas.dfos.com/post/v1","body":"hello world"}
EOF

Content without a $schema field triggers a warning. Pass --no-schema-warn to suppress, or include a $schema URL in the JSON. Schemas are convention-based — any URL works. Common schemas: https://schemas.dfos.com/post/v1 (posts/articles), https://schemas.dfos.com/profile/v1 (identity profiles).

Credentials

dfos cred is an alias for dfos credential.

# Grant read access (default 24h TTL)
dfos credential grant <contentId> <did> --read

# Grant write access
dfos credential grant <contentId> <did> --write

# Custom TTL
dfos credential grant <contentId> <did> --read --ttl 1h

# Wildcard credential covering all content
dfos credential grant <contentId> <did> --read --broad

# Scope to a specific content ID
dfos credential grant <contentId> <did> --read --scope <otherContentId>

# Revoke a credential
dfos credential revoke <credentialCID>

# Revoke and push to a peer immediately
dfos credential revoke <credentialCID> --peer prod

# Delegated write (bob updates alice's content using a write credential)
dfos --ctx bob@prod content update <contentId> new.json --authorization <credential-jws>

# --credential = presenting a READ credential (downloads)
# --authorization = presenting a WRITE credential (mutations)

Beacons

dfos beacon announce <contentId> [--peer <relay>]      # sign manifest pointer, optionally submit to relay
dfos beacon show [name|did]                            # show latest beacon
dfos beacon countersign <name|did> --peer <relay>      # countersign someone's beacon

Witness / Countersignatures

dfos witness <operationCID> --peer <relay>             # countersign an operation
dfos countersigs <cid> --peer <relay>                  # list countersignatures

Auth Tokens

dfos auth token [--ttl <duration>]     # mint JWT (stdout, pipe-friendly)
dfos auth status                        # show current auth state

# Use in scripts
TOKEN=$(dfos auth token)
curl -H "Authorization: Bearer $TOKEN" https://relay.nyc.lark717.xyz/content/abc/blob

Raw API Access

For operations not covered by named commands:

dfos api GET /.well-known/dfos-relay
dfos api GET /identities/<did> --auth
dfos api POST /operations --body '{"operations":["eyJ..."]}' --auth
dfos api POST /operations --body-file ops.json --auth
dfos api PUT /endpoint --auth -H "X-Custom: value" --body-file data.bin
dfos api GET /endpoint -i    # include response headers

Peer / Relay Management

dfos peer add <name> <url>       # register relay (fetches + caches metadata)
dfos peer remove <name>           # unregister
dfos peer list                    # show configured peers
dfos peer info [name]             # inspect + verify peer

dfos relay is an alias for dfos peer.

Config

dfos config list                  # show full config
dfos config get <key>             # get value
dfos config set <key> <value>     # set value

Server & Sync

dfos serve [--port 4444]          # expose local relay over HTTP
dfos sync                          # sync all local data with all configured peers (global, not context-scoped)

Context & Status

dfos use <identity@relay>          # set active context
dfos status                        # overview: context, identity, relay status
dfos version                       # show version

JSON Output

All data commands support --json for machine-readable output. Always use --json when piping or capturing values:

dfos identity show alice --json | jq .did
dfos content create post.json --peer prod --json | jq -r .contentId
dfos credential grant <id> <did> --read --json | jq -r .credential
dfos identity list --json | jq '.[].did'
dfos peer list --json | jq '.[].url'

Common Workflows

Publish content end-to-end

dfos peer add prod https://relay.nyc.lark717.xyz
dfos identity create --name alice --peer prod
dfos use alice@prod

CONTENT=$(dfos content create - --peer prod --json <<'EOF' | jq -r .contentId
{"$schema":"https://schemas.dfos.com/post/v1","body":"hello world"}
EOF
)

echo "Published: $CONTENT"
dfos content show "$CONTENT"

Grant access to another identity

BOB_DID=$(dfos identity show bob --json | jq -r .did)
CRED=$(dfos credential grant "$CONTENT" "$BOB_DID" --read --json | jq -r .credential)

# Bob downloads using the credential
dfos --ctx bob@prod content download "$CONTENT" --credential "$CRED"

Beacon + witness

# Announce beacon over content
dfos beacon announce "$CONTENT" --peer prod

# A witness countersigns
dfos --ctx witness@prod beacon countersign alice --peer prod

Local-first (create offline, publish later)

dfos identity create --name alice           # local only, no relay
dfos --identity alice content create post.json  # local only

# later, when ready:
dfos peer add prod https://relay.nyc.lark717.xyz
dfos identity publish alice --peer prod
dfos content publish <contentId> --peer prod

Error Recovery

Confirmation Behavior

Destructive commands (delete, key rotation) prompt for confirmation. Pass --yes to auto-confirm in scripts:

dfos identity delete alice --yes
dfos content delete <contentId> --yes --peer prod