Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.myme.so/llms.txt

Use this file to discover all available pages before exploring further.

The Marfa CLI is a Commander-based terminal client published on npm as @withmarfa/cli. Wraps the TypeScript SDK; every operation the SDK exposes is reachable as a my <resource> <verb> subcommand. Human-readable output by default; auto-switches to JSON when stdout is a pipe or redirected file.

Install

npm install -g @withmarfa/cli
# or: pnpm add -g @withmarfa/cli
# or: yarn global add @withmarfa/cli
Installs the my binary on your PATH. Confirm with my --help.

Authenticate

Two paths, both work; OAuth wins when present. Interactive (recommended for humans)my auth login runs the OAuth Device Authorization Grant. The CLI prints a URL and code; approve in a browser; tokens persist at ~/.marfa/<instance>.json and refresh transparently.
my --url https://marfa.example.com auth login
my auth whoami
my items list           # uses the stored OAuth tokens
my auth logout
API key (recommended for scripts and CI) — set MARFA_API_URL and MARFA_API_KEY, or pass --url / --key per call.
export MARFA_API_URL=https://marfa.example.com
export MARFA_API_KEY=marfa_k1_...
my items list
OAuth tokens take precedence when a stored session matches the resolved URL — an explicit my auth login should beat a stale env var. To force the API-key path: my auth logout, unset MARFA_API_KEY, or pass --key explicitly.

Command surface

my [--url <url>] [--key <key>] [--instance <name>] [--json] [--verbose]
  auth         login, logout, whoami, delete-account
  profile      show, update, avatar {set, clear}
  items        create, get, list, update, delete, restore, transition,
               search, versions, edges, backrefs, bulk, action
  metadata     get, tag, untag, set, merge, list-tags, extensions {get, set}
  edges        create, list, update, delete, types {list, create, delete}, bulk
  blobs        upload, download
  types        list, describe, register, update, delete
  keys         create, update, list, revoke
  apps         register
  webhooks     create, list, get, update, delete, deliveries
  tenant       config {get, set}
  connections  list, get, configure, pause, resume, install, uninstall,
               logs, activity, preview-event, verify, replay-dlq
  platform     tenants {list, show, suspend, unsuspend, quotas, metrics},
               keys {list},
               account-deletion {purge-now}
  export       [--output <file.json>]
  health
my --help and my <subcommand> --help are the canonical reference for flags. The sections below walk the more substantial surfaces.

Examples

Items and edges

# Plain create
my items create --type core.note --prop title="Hello" --prop body="World"

# Atomic item + outbound edges in one transaction
my items create --type core.highlight --prop text="..." \
  --edge references:<doc-id> --edge about:<topic-id>

# Natural-key upsert — re-running with the same --source + --source-id
# updates the existing row in place. Human mode prints "Created." or
# "Updated (natural-key match)." based on the server's 200/201.
my items create --type core.note --prop title="Hello" \
  --source my-script --source-id intro-001

# Filter by edge / backref / state / tier
my items list --type core.note --tier library --edge in-thread=<root-id>
my items list --backref about=<topic-id>

Scoped API keys

my keys create exposes the full permission-map surface. Permission flags use = between key and level (the : separator collides with the edge-create grammar).
my keys create --label app-cred --source acme-app --role member \
  --type-perm core.note=write \
  --type-perm core.task=read \
  --extension-perm app.acme=write \
  --edge-perm about=write

my keys update <key-id> --type-perm core.note=read
--is-platform is silently coerced to false unless the calling credential is itself platform-flagged — the server enforces this.

Metadata extensions

The metadata layer’s extensions map is a JSON sidecar keyed by namespace. Reserved namespaces (e.g. connection.runtime) have constrained write semantics; the CLI is the surface, not the gate.
# Set an app-scoped namespace from inline JSON
my metadata extensions set <item-id> app.acme --data '{"cursor":"abc"}'

# Or from a file / stdin
my metadata extensions set <item-id> connection.runtime --file runtime.json
echo '{"k":1}' | my metadata extensions set <item-id> app.foo

# Read back
my metadata extensions get <item-id>
my metadata extensions get <item-id> --namespace app.acme

# Distinct tag enumeration with usage counts
my metadata list-tags

Connections

my connections is the operator-facing surface for system.connection items of kind integration.
my connections list                              # all connections in the tenant
my connections list --integration acme.gdrive    # filter by integration
my connections get <connection-id>               # hydrates connection.runtime when present
my connections configure <connection-id> --extension connection.runtime --data '{"cursor":"..."}'
my connections pause <connection-id>             # archived
my connections resume <connection-id>            # active
my connections logs <connection-id> --severity error
my connections preview-event --item <id> --event-type item.created [--connection <id>]
my connections uninstall <connection-id>         # orchestrated teardown
install calls the platform’s POST /connections/install orchestration — the admin-only JSON sibling of the browser consent flow. Returns the connection id, seed credential id, and an activity id. uninstall calls the platform’s POST /connections/:id/uninstall orchestration: revokes runtime credentials, deletes upstream OAuth tokens, revokes leased tokens, disables inbound webhook subscriptions, transitions state to revoked, emits system.activity, audits. preview-event is a debug verb. Given an item id and an event type, it renders the queue envelopes the bridge would emit to each subscribed connector — without invoking any handler. Each envelope carries a dispatch_reason (ok, self_event, cross_tenant, hop_budget_exceeded, subscription_inactive) so operators can see why a subscriber would or wouldn’t receive a given event. Pure server-side; safe to run repeatedly while debugging fanout. verify <id> --event <json> synchronously dispatches a sample event through runtime-control into the connector via service binding. Operator-debug; requires a platform credential. Reads the runtime-control endpoint from MARFA_RUNTIME_CONTROL_URL or --runtime-control-url. replay-dlq <id> [--message-ids id1,id2] [--yes] re-enqueues DLQ messages back onto their main queues for a connection. Destructive (handlers re-run upstream); interactive confirmation unless --yes is passed (and --yes is required in non-TTY contexts). my connections logs <id> --dlq reads the same DLQ surface.

Tenant config

my tenant config get
my tenant config set --file ./tenant-config.json
The set body is a full TenantConfig JSON object. Plumbing for the schema-enforcement levers (TSC42 §5: strict_mode, source_allowlist, source_filter) and feed-tier retention. Editing tenant config is rare enough that per-field flags would invent a parallel grammar that drifts from the wire shape; raw JSON is the call.

Webhook deliveries

my webhooks list
my webhooks deliveries <webhook-id>           # recent attempts
my webhooks deliveries <webhook-id> --limit 200

Account deletion

my auth delete-account initiates the hosted-mode account-deletion flow. The CLI verb is initiation-only — the server emails a confirmation link; clicking it transitions the account to pending_deletion. See Account lifecycle for the full state machine.
my auth delete-account            # interactive: prints flow summary, prompts y/N
my auth delete-account --yes      # non-interactive (required outside a TTY)

Profile

my profile reads and updates the calling user’s own profile — name, handle, avatar. The avatar surface is two sub-verbs (set uploads an image, clear reverts to the deterministic placeholder).
my profile show
my profile update --name "Alex"
my profile avatar set ./avatar.png
my profile avatar clear

Platform (operator)

my platform is the cross-tenant operator surface, gated on platform credentials. The two trees:
  • platform tenants — list, inspect, suspend / unsuspend, set quotas, per-tenant metrics.
  • platform account-deletion — force the next pending-delete purger sweep without waiting for the 1-hour cadence.
my platform tenants list
my platform tenants show <tenant-id>
my platform tenants metrics <tenant-id>
my platform tenants suspend <tenant-id> [--yes]
my platform tenants unsuspend <tenant-id> [--yes]
my platform tenants quotas <tenant-id> --items 10000 --webhooks 50 \
  --blobs 5000 --storage-gb 25 --rate-per-minute 600 [--yes]

my platform keys list <tenant-id>

my platform account-deletion purge-now [--yes]
Suspend / unsuspend / quota writes prompt for confirmation unless --yes is passed; the prompt is required in non-TTY contexts. purge-now is the operator escape hatch when an account just crossed its grace window and you want the cascade now rather than at the next 1-hour tick.

Output modes

Human-readable tables in an interactive terminal; JSON when stdout is a pipe, a redirected file, or --json is set explicitly. There’s no --human flag — scripts that consume output get JSON, full stop.
my items list                  # table in a TTY
my items list | jq '.[0]'      # JSON automatically
my items list --json           # force JSON in a TTY
my items list > items.json     # JSON automatically (non-TTY)

Multi-instance config

--instance <name> (or MARFA_INSTANCE) selects the config-file slot under ~/.marfa/<instance>.json. Use it to keep separate sessions per server (e.g. production + staging):
my --instance production --url https://marfa.example.com auth login
my --instance staging    --url https://staging.example.com auth login

my --instance production items list
my --instance staging    items list
The default instance name is default.

Repo

Source at withmarfa/cli. Commander-based; consumes @withmarfa/sdk as a regular npm dep. Build and code rules in the repo’s CLAUDE.md.