File transfer

May 26, 2026 · View on GitHub

Send files to your repo or pull results back — directly from Telegram on any device. Useful when you need to share a spec, screenshot, or config file with your agent without opening a terminal.

Enable file transfer

=== "untether config"

```sh
untether config set transports.telegram.files.enabled true
untether config set transports.telegram.files.auto_put true
untether config set transports.telegram.files.auto_put_mode "upload"
untether config set transports.telegram.files.uploads_dir "incoming"
untether config set transports.telegram.files.allowed_user_ids "[123456789]"
untether config set transports.telegram.files.deny_globs '[".git/**", ".env", ".envrc", "**/*.pem", "**/.ssh/**"]'
```

=== "toml"

```toml
[transports.telegram.files]
enabled = true
auto_put = true
auto_put_mode = "upload" # upload | prompt
uploads_dir = "incoming"
allowed_user_ids = [123456789]
deny_globs = [".git/**", ".env", ".envrc", "**/*.pem", "**/.ssh/**"]
```

Notes:

  • File transfer is disabled by default.
  • If allowed_user_ids is empty, private chats are allowed and group usage requires admin privileges.

Upload a file (/file put)

Send a document with a caption:

/file put <path>

Examples:

/file put docs/spec.pdf
/file put /happy-gadgets @feat/camera assets/logo.png

If you send a file without a caption, Untether saves it to incoming/<original_filename>.

!!! note "iOS: captions on documents" Telegram on iOS doesn't always show a caption field when sending files via the "File" picker — the file sends immediately. To add a /file put <path> caption on iOS, send photos (which always show the caption field) or use Telegram Desktop / macOS, which shows a caption field for all file types. Alternatively, skip the caption and let files auto-save to incoming/.

If the target file already exists, Untether auto-appends a numeric suffix (_1, _2, etc.) to avoid collisions — so spec.pdf becomes spec_1.pdf. Use --force to overwrite instead:

/file put --force docs/spec.pdf

!!! untether "Untether" 📄 saved docs/spec.pdf (42 KB)

Photos uploaded and auto-saved with confirmation

Fetch a file (/file get)

Send:

/file get <path>

Directories are zipped automatically.

!!! untether "Untether" 📎 src/main.py (1.2 KB)

/file get response showing fetched file as a document

Agent-initiated delivery (outbox)

Agents can send files to you automatically — plan docs, generated images, scripts, data exports — without you having to request them. The agent writes files to a special .untether-outbox/ directory during its run, and Untether delivers them as Telegram documents when the run finishes.

┌─────────────┐    writes     ┌──────────────────┐    run ends    ┌───────────┐    sends     ┌──────────┐
│  Agent CLI   │ ──────────── │ .untether-outbox/ │ ────────────── │  Untether  │ ──────────── │ Telegram │
│ (any engine) │   files      │   plan.md         │   scan + send  │  outbox    │  📎 docs    │  client  │
└─────────────┘              │   diagram.svg     │                │  delivery  │             └──────────┘
                              └──────────────────┘                └───────────┘

Every agent session receives a preamble telling it about the outbox. The agent decides which files to share — you receive them as Telegram document messages with 📎 filename (size) captions, arriving just after the final text response.

Configuration

Outbox delivery is enabled by default when file transfer is enabled:

=== "untether config"

```sh
untether config set transports.telegram.files.outbox_enabled true
untether config set transports.telegram.files.outbox_dir ".untether-outbox"
untether config set transports.telegram.files.outbox_max_files 10
untether config set transports.telegram.files.outbox_cleanup true
```

=== "toml"

```toml
[transports.telegram.files]
enabled = true
outbox_enabled = true            # default: true (when files.enabled)
outbox_dir = ".untether-outbox"  # relative to project root
outbox_max_files = 10            # max files per run (1–50)
outbox_cleanup = true            # delete sent files after delivery
```

How agents use it

Agents receive instructions in their session preamble. They create the directory and write files using their standard tools:

mkdir -p .untether-outbox
cp docs/plan.md .untether-outbox/
cp output/diagram.svg .untether-outbox/

When the run finishes successfully, Untether:

  1. Scans .untether-outbox/ for files (flat scan, no subdirectories)
  2. Validates each file against deny globs, size limits, and path traversal rules
  3. Sends valid files as Telegram documents with 📎 filename (size) captions
  4. Cleans up — deletes sent files and removes the empty directory

Files are sent in alphabetical order, one at a time, immediately after the agent's text response.

Security

Outbox delivery reuses the same security rules as /file get:

  • Deny globs — files matching .git/**, .env, .envrc, **/*.pem, **/.ssh/** (and any custom deny globs) are surfaced to the user as a 📎 Outbox skipped notice rather than silently dropped (#524)
  • Size limit — files larger than 50 MB are skipped (and surfaced via the same notice)
  • Path traversal — symlinks pointing outside the project root are rejected
  • File count — capped at outbox_max_files per run (default 10)
  • Auto-cleanup — sent files are deleted after delivery by default, preventing sensitive data accumulation
  • Failed/auto-continued runs — actual file delivery is still gated on a successful run, but skipped items (directories, deny-globbed files, oversized files) are surfaced even when the run fails or auto-continues, so you always learn what the agent intended to send. Opt out via outbox_notify_skipped = false.

Engine compatibility

All engines support outbox delivery — any agent that can write files to disk can use it.

EngineWorks out of the box?Notes
Claude CodeYesBest file generation capability
Codex CLIYes
OpenCodeYes
PiYes
Gemini CLINeeds configSet approval mode to "Full access" via /config → Approval mode
AMPYes

!!! tip "Gemini CLI permissions" Gemini CLI defaults to read-only approval mode. To enable file creation (and outbox delivery), set the approval mode to "Full access" via /configApproval mode in the Gemini chat.

Limitations

  • Flat scan only — only files directly in .untether-outbox/ are sent; subdirectories are surfaced as 📎 Outbox skipped (#524) but not delivered. Agents can zip nested structures if needed.
  • Failed runs deliver no files — the actual file send is still gated on a successful run, but the skipped-items notice fires either way so the user always learns what the agent intended to ship.
  • No real-time delivery — files are sent after the run completes, not during.