Documentation · macOS 15+

Filecrow CLI

filecrow is a macOS 15+ command-line sender using the same delivery API, ZIP64 STORED archive, multipart transport, CRC32/SHA-256 entry metadata, and server size/ready checks as the Mac app. It ships inside the Filecrow Mac app. It uploads one archive; it never uploads originals separately. Its credential and recovery directories belong to the CLI.

Installation

The CLI is included in the Filecrow Mac app, version 0.3.7 and later. There is nothing separate to download, and it updates with the app. It requires macOS 15 or later and lives at:

Command syntax
/Applications/filecrow.app/Contents/Helpers/filecrow

If the app was moved, the path is the app's location followed by Contents/Helpers/filecrow. Contents/MacOS/filecrow is the app itself, not the CLI. There is no separate CLI download or Homebrew formula; do not use a guessed brew command or download URL.

No app yet? Filecrow is invitation-only: open the link in your invitation, or https://filecrow.com/install if you already have an account. Is the app older than 0.3.7, with no Contents/Helpers/filecrow? Choose filecrow › Check for Updates… in the menu bar and click Install Update.

Typing filecrow in Terminal

Optional. Link the bundled CLI into a folder on your PATH. A link rather than a copy, so it keeps pointing at the current version after every app update:

Shell
mkdir -p "$HOME/.local/bin"
ln -sf /Applications/filecrow.app/Contents/Helpers/filecrow "$HOME/.local/bin/filecrow"
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
filecrow --version

The last line prints the CLI version. If it prints command not found, check that /Applications/filecrow.app/Contents/Helpers/filecrow exists; if it does not, update the app as described above.

First transfer

Shell
filecrow login --email you@example.com
# Open the Filecrow email and confirm sign-in in any browser.
filecrow send ./folder

A successful send prints the server-issued recipient URL. It reports success only after archive completion and the production ready checks pass.

Shell
filecrow send ./folder --json --no-interactive
filecrow send ./folder --quiet
filecrow send ./folder --title 'Client finals' --from 'Studio' --expires 7
filecrow send ./folder --password
filecrow send ./folder --password-file /path/to/private-password.txt --json

--password requires a terminal and hides input. A password file must be a regular file with no group/other permissions (chmod 600). --password-file - reads stdin. One trailing newline is removed. Passwords are never saved in transfer metadata, passed as command-line values, or printed.

Commands

Command syntax
filecrow login [--email ADDRESS]
filecrow logout
filecrow whoami
filecrow send <path...> [--title TEXT] [--from TEXT] [--expires DAYS]
                      [--password | --password-file PATH] [--new]
filecrow send --resume ID
filecrow deliveries [--limit 1..100] [--cursor CURSOR]
filecrow delivery ID
filecrow delete ID [--yes]
Command Purpose
login Sign in through emailed browser confirmation
logout Revoke this CLI session and remove its credential
whoami Show the current account and allowance
send Send one ZIP64 STORED delivery or resume a draft
deliveries List deliveries with cursor pagination
delivery Inspect a delivery and its file manifest
delete Delete a delivery and disable its recipient link

All commands accept --json, --quiet, and --no-interactive. --json implies noninteractive operation. Use --help on any command for its options.

Authentication and confirmation

filecrow login --email ADDRESS requests a magic-link email and waits for approval until the server challenge deadline. Open the email's link and confirm sign-in in a browser; approval can happen on another computer. --no-interactive disables terminal prompts, but it does not bypass email approval. A login with --email --json --no-interactive can still wait for that human action.

Credentials use the CLI's own macOS Keychain item, separate from the Mac app's, so signing in to the app does not sign in the CLI. Each Mac needs one CLI sign-in; after that it stays signed in until logout or the session expires.

An agent does not need to check the sign-in before sending: send itself reports authentication_required (exit 3) when the CLI is not signed in. whoami --json --no-interactive shows the account when that is what you want to know. When a command reports authentication_required:

  1. Ask the person which email address their Filecrow account uses, and tell them: "A Filecrow email is on its way. Open it and click Confirm."
  2. Run filecrow login --email ADDRESS --json --no-interactive. It waits until they confirm, for up to 15 minutes; run it in the background if your tool has a shorter time limit.
  3. Run the original command again. If macOS showed a Keychain dialog, the person should click Always Allow.

If you cannot run a waiting command at all, ask the person to run filecrow login --email ADDRESS in Terminal instead. Never request an account token, reuse the Mac app's credential, or repeatedly retry an unauthenticated send. A refused sign-in may also require account access; report the returned error to the person.

delete prompts for y in an interactive terminal. In JSON or noninteractive mode it requires --yes; without confirmation it returns confirmation_required and exit 9. Inspect the intended delivery and obtain the human's authorization before an agent runs delete ID --yes. No active upload is deleted on interruption. logout revokes the CLI session server-side before removing it locally. If the network cannot acknowledge revocation, the credential is retained and the command fails so logout can be retried.

File selection

Directories contribute their contents without their top directory. Individual files contribute their basename; multiple roots merge into the same archive. Paths are NFC normalized and sorted deterministically. Duplicate archive paths, symlinks, special files, unreadable files, and invalid paths are refused. Dotfiles and dot directories inside a traversed directory are omitted; an explicitly selected hidden regular file is included. Empty directories are omitted. Use -- before filenames beginning with a dash.

Output for scripts and agents

Stdout carries one final result. Progress and human diagnostics use stderr. Animation appears only on a terminal, never in JSON or quiet mode. Progress counts bytes acknowledged by the server and uses the shared network speed tracker; source reads do not become confirmed upload progress.

With --json --no-interactive, stdout contains exactly one newline-terminated JSON object on success or failure. Parse stdout and check the process exit status and ok; do not parse human text or progress. send --quiet prints only the URL on success. Other human commands print a readable result. Help and version are plain text even with --json.

If a process is killed or stdout breaks, a complete envelope may be absent. Treat missing/truncated JSON as a failed command and inspect or resume the transfer; never infer successful delivery from partial output.

Success envelope (formatted here for readability):

JSON
{
  "schema_version": 1,
  "command": "send",
  "ok": true,
  "data": {
    "delivery_id": "11111111-1111-4111-8111-111111111111",
    "status": "ready",
    "public_url": "https://files.filecrow.com/d/<recipient-token>",
    "file_count": 147,
    "source_bytes": 18400000000,
    "archive_bytes": 18400025000,
    "expires_at": "2026-10-09T00:00:00Z",
    "resumed": false
  }
}

Error envelope (missing authentication example):

JSON
{
  "schema_version": 1,
  "command": "send",
  "ok": false,
  "error": {
    "code": "authentication_required",
    "message": "Run filecrow login first.",
    "retryable": false,
    "resumable": false
  }
}

Failures use the same envelope with ok:false and error instead of data. An error contains code, message, retryable, and resumable. Where available, it adds delivery_id, resume_deadline, backend_code, request_id, and details. No raw session token or password is returned. IDs are UUIDs. Byte counts are integers; send expiry/deadline strings are UTC ISO 8601. Account and history/detail timestamps preserve the API's Unix seconds. Unknown additive fields must be ignored by consumers. schema_version changes for breaking output changes. The example recipient token above is a placeholder, not a live link.

Stable exit codes

Exit Meaning
0 Success
1 Internal/unclassified API failure
2 Arguments or selection
3 Authentication or credential storage
4 Entitlement, quota, expiry ceiling, or sending disabled
5 Network failure or uncertain creation
6 Changed source, ambiguous/conflicting resume, expired draft
7 Recovery state or competing process
8 Archive verification failure
9 Destructive confirmation missing
130 / 143 SIGINT / SIGTERM

Recovery

Rerun the same send ./folder after a crash or a network failure. A single matching unfinished CLI transfer resumes automatically. The complete file plan must still match: path, size, and modification time. A partially sent entry is re-appended whole through the existing archive checkpoint machinery. No partial-file hash state or alternate journal format is introduced.

Use send --resume ID when several transfers match. Resume uses saved paths and delivery options; it accepts no new selection/options. Omit password options when resuming; the original password is already set on the delivery. --new deliberately starts a new delivery and preserves prior drafts. Use delete ID --yes to delete a draft and its local recovery state after server acknowledgement. Keep the resume deadline in error output: the multipart upload cannot be continued after it lapses. A missing/truncated spool or changed source fails closed.

Creation is not automatically retried. A lost creation response leaves a marker and returns creation_outcome_unknown; inspect deliveries before using --new. This avoids silently creating more charged deliveries. It does not add server creation idempotency.

After sealing, CLI metadata preserves the manifest, expected size, and recipient URL until commit/complete/ready and output succeed. Recovery reuses those existing idempotent endpoints. If the server is already ready it returns the original URL. An output failure retains the result for a later retry. The existing Mac app's checkpoint cleanup remains unchanged.

Configuration and security

The default API/account/auth origin is https://filecrow.com. Recipient links come from the server, normally https://files.filecrow.com; the CLI never creates one from the API origin. FILECROW_API_ORIGIN can select another HTTPS origin (loopback HTTP is allowed for development). Credentials and state are namespaced by that origin.

FILECROW_STATE_DIR overrides the default ~/Library/Application Support/FilecrowCLI. Recovery directories are private (0700); CLI metadata and locks are 0600. Do not share or commit them: they contain source paths and recipient capabilities. Passwords and sessions are not stored there. The Keychain service is com.filecrow.cli; it never borrows the app's session. Only an intentional interactive login allows credential UI. Unattended credential access fails promptly if permission/unlocking is required.

From and expiry default to the account's settings. No configuration file or production environment-token fallback is provided. An agent uses an already signed-in CLI without receiving an account secret.

Scope

The V1 integrity gate is the current production delivery contract. CRC64/NVME full-object verification, server creation idempotency, and broader checkpoint or publication hardening belong to separate Filecrow reliability work. Watched folders, MCP, Linux, teams, and a new recovery journal are outside V1.

FilecrowCore exposes login, account/history/detail/delete, send, and output acknowledgement without terminal dependencies. A future MCP adapter can call this boundary with its own credential/progress adapters and confirmation policy. It would reuse the same transfer implementation.