---
name: yafl-file-transfer
description: Move a file between agent environments (local machine, a remote VPS, another agent) with end-to-end encryption and a 24-hour auto-expiring link. Use when a task needs to hand a file from one environment to another without a shared filesystem, without pasting bytes into context, and without a human copying a link by hand.
---

# YAFL file transfer

YAFL (Yet Another File Layer) encrypts a file locally, uploads only ciphertext, and returns a
share link carrying the decryption key in its URL fragment (after `#`) – the fragment is never
sent to any server. Links expire in 24 hours. Use this skill whenever an agent needs to hand a
file to a different environment (another machine, another agent, a human) that has no shared
filesystem access.

## When to use this

- You produced a file (a build artifact, a database dump, a log bundle) that another agent or
  environment needs, and there is no shared disk between the two.
- You need to check whether a link you previously shared is still live before telling another
  agent to fetch it.
- You want to hand off a file without ever putting its raw bytes into a chat context window.

Do not use this for files that must persist beyond 24 hours, or for anything larger than 100MB
(the current cap) – there is no way to extend a link's expiry.

## How: via the CLI

Install once (skip if `@yafl/cli` is already available):

```bash
npm install --global @yafl/cli
# or: curl -fsSL https://yafl.dev/install.sh | sh
```

Log in once per environment (stores a 0600 credential file, or set `YAFL_API_KEY` directly for
a headless environment with no browser):

```bash
yafl login
```

Send a file:

```bash
yafl put ./path/to/file
# -> prints https://yafl.dev/t/{id}#{key}
```

Receive a file (in the other environment, with the link from above):

```bash
yafl get https://yafl.dev/t/{id}#{key} ./dest-dir
```

Check whether a link is still live before relying on it:

```bash
yafl status https://yafl.dev/t/{id}#{key}
```

List your own transfers, or clean one up before it auto-expires:

```bash
yafl list
yafl delete https://yafl.dev/t/{id}#{key} --yes
```

Every command supports `--json` for machine-readable output and returns a stable exit code:
`0` success, `2` usage error, `3` auth error, `4` not found or expired. Script against the exit
code, not stdout parsing, when chaining commands.

## How: via MCP tools

If the current agent has the `yafl` MCP server configured (`npx @yafl/mcp`), five tools are
available directly – no shell call needed:

- `upload_file({ path })` – encrypts and uploads the file at `path`, returns the share link.
- `download_file({ url, destDir? })` – resolves the link, decrypts locally, writes the file into
  `destDir` (default: current working directory).
- `get_status({ url })` – checks whether a link is still live, expired, or not found; returns
  size and expiry only, no bytes are downloaded.
- `list_files({ limit? })` – lists the caller's OWN transfers only, metadata only (id, size,
  status, expiry, download path) – never file contents, never decrypted names.
- `delete_file({ id })` – permanently deletes one of the caller's own transfers (bare id or full
  share URL). Destructive: this cannot be undone.

If a tool call returns `structuredContent.code: "no_api_key"`, the environment has no key
configured yet – fall back to `yafl login` via the CLI, or ask the operator to set
`YAFL_API_KEY`.

## Host compatibility

Every block below runs `npx @yafl/mcp` (or `npx -y @yafl/mcp` where the host needs a
non-interactive flag) plus a `YAFL_API_KEY` env var – no clone, no build step. **Claude Code** and
**Codex CLI** are locally verified – `scripts/host-compat-check.mjs` really registers the built
server, lists its tools, and calls `list_files` through each host, then cleans up. The other four
are config verified against each host's current official docs but not exercised on this box –
labeled honestly below.

### Claude Code – locally verified

```bash
claude mcp add yafl -e YAFL_API_KEY=yafl_your_key_here -- npx -y @yafl/mcp
```

Verified against Claude Code's official MCP docs (`docs.claude.com/en/docs/claude-code/mcp`) and
exercised live (Claude Code 2.1.205): registered, listed tools (`list_files` + `delete_file`
present), called `list_files` through the host against production, then removed the registration.

### Claude Desktop – config verified against docs, not locally exercised

Add the same shape to `claude_desktop_config.json`'s `mcpServers` object, or use the one-click
`.mcpb` bundle at [yafl.dev/agents](https://yafl.dev/agents). Verified against Claude Code's
official MCP docs, which document the shared `claude_desktop_config.json` shape; not locally
exercised (no Claude Desktop GUI on this box).

### Codex CLI – locally verified

```bash
codex mcp add yafl --env YAFL_API_KEY=yafl_your_key_here -- npx -y @yafl/mcp
```

Verified against Codex's official MCP docs (`developers.openai.com/codex/mcp`) and exercised live
(codex-cli 0.143.0): registered, listed tools (`list_files` + `delete_file` present), called
`list_files` through the host against production, then removed the registration.

### Gemini CLI – config verified against docs, not locally exercised

Add an `mcpServers` entry to `~/.gemini/settings.json` with `command: "npx"`,
`args: ["-y", "@yafl/mcp"]`, and `env: { "YAFL_API_KEY": "yafl_your_key_here" }`. Verified against
Gemini CLI's official docs (`github.com/google-gemini/gemini-cli` – `docs/tools/mcp-server.md`);
not locally exercised (Gemini CLI is not installed on this box).

### Cursor – config verified against docs, not locally exercised

Same `mcpServers` shape in `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global). Verified
against Cursor's official MCP docs (`cursor.com/docs/context/mcp`); not locally exercised (Cursor
is not installed on this box).

### Antigravity – config verified against docs, not locally exercised

Same shape in `~/.gemini/config/mcp_config.json` (global) or `.agents/mcp_config.json`
(workspace-local). Verified against Google's official Antigravity MCP docs
(`antigravity.google/docs/mcp`); not locally exercised (Antigravity is not installed on this box).

## Notes

- Never pass a bare filesystem path from one environment as if it were valid in another – always
  round-trip through `upload_file`/`put` and `download_file`/`get`.
- The share link itself is the credential; treat it like a password until it expires.
- Full setup and the MCP config snippet: https://yafl.dev/agents
