Aktar CLI

aktar CLI documentation

Every command, option and output of aktar, with examples you can paste. New here? The CLI overview is the quicker read.

Overview

aktar is a remote control for the Aktar app on the same computer. You hand it files, it passes them to Aktar on 127.0.0.1, and Aktar uploads them with the destinations, keys, path templates and link settings you already set up. The link comes back to your terminal.

What it is

  • A small Node.js command for scripts, CI jobs on your own Mac or Windows machine, and editors like Typora
  • A way to upload files and the clipboard, show QR codes, and read your destinations and upload history
  • Free and open source (MIT), like the app

What it isn't

  • Not standalone: without Aktar running, it can't upload anything. It never holds your storage keys
  • Not for Linux servers or remote machines: it only talks to Aktar on the same computer. There, use your storage provider's own CLI

Requirements

  • Aktar for Mac 0.4.0 or later, or Aktar for Windows, with at least one destination
  • Node.js 18 or later (Homebrew installs it for you)
  • --name, --qr and aktar qr need aktar 0.2.0 or later
  • Reusing the link of a file that's already uploaded needs aktar 0.2.0 and Aktar for Mac 0.10.0 or Aktar for Windows 0.3.0

Install

Install it once, with npm or Homebrew. Both put the aktar command on your path.

With npm (macOS and Windows)

npm install -g @getaktar/cli

With Homebrew (macOS)

brew install getaktar/tap/aktar-cli

Or run it once without installing anything:

npx @getaktar/cli upload file.png

Check which version you have:

aktar --version
0.2.0

Connect to Aktar

  1. In Aktar for Mac or Windows, open Settings > Integrations and turn on Allow local connections. Aktar then listens on 127.0.0.1 only, port 47913 unless you change it there.
  2. Copy the token shown under it.
  3. Run aktar login and paste the token at the Token: prompt. It stays hidden while you type, and it's checked against Aktar before it's saved, so a typo isn't stored.
aktar login
Copy the token from Aktar: Settings > Integrations (turn on Allow local connections first).
Token:
Connected to Aktar 0.10.0. Saved to /Users/you/.config/aktar/cli.json

Where the token is kept

aktar login saves the token and port in ~/.config/aktar/cli.json on a Mac (or $XDG_CONFIG_HOME/aktar/cli.json if you set it) and in %APPDATA%\aktar\cli.json on Windows. Only your user can read it.

cli.json
{
  "token": "…",
  "port": 47913
}

aktar logout deletes that file. To lock out every client at once, click Regenerate next to the token in Aktar; then run aktar login again with the new one.

Scripts and CI

On a build machine, skip aktar login and set AKTAR_TOKEN (and AKTAR_PORT if you changed the port). They win over the saved file. Aktar has to be running on that machine, signed in to the same user session.

AKTAR_TOKEN="$AKTAR_SECRET" aktar upload dist/app.zip -d Builds
VariableWhat it does
AKTAR_TOKENThe token from Aktar's Settings > Integrations. Used instead of the saved one.
AKTAR_PORTAktar's local API port, if you changed it. --port wins over it.
NO_COLORDraws QR codes with plain characters instead of terminal colors.
XDG_CONFIG_HOMEWhere the config folder is on macOS (default ~/.config). On Windows, %APPDATA% is used.

Commands

All commands talk to Aktar, except aktar qr with plain text or a link. Without -d, uploads go to the destination selected in Aktar's menu bar, and they show up in Aktar's history like any other. aktar --help prints the same list.

aktar upload

Uploads one or more files and prints one link per file, in order, as each one finishes.

Usage

aktar upload <file>... [options]

Options

FlagValueDescription
-d, --destination<name|id>Destination to upload to, by name or ID. Default: the one selected in Aktar.
-f, --format<format>What to print: url (default), markdown, html or custom (your template in Aktar).
--name<name>Upload one file under this name. Its extension is kept if the name has none.
--folder<path>Keep the file name and upload into this folder.
--expires<days>Let the bucket delete the file after 1, 7, 14 or 30 days. 0 keeps it.
--qrAlso print a QR code of each link.
--jsonPrint a JSON array with the full details of each upload, instead of links.
--port<port>Aktar's local API port, for this command only. Wins over AKTAR_PORT and the saved port.

Good to know

  • Every file is checked before anything is uploaded: if one doesn't exist, nothing is uploaded and aktar exits with code 2.
  • If one upload fails, the others still go through. Each failure is reported on stderr, and the exit code is 1.
  • Without --folder, the destination's path template names the file, just like a drop on the menu bar. With --folder, the file keeps its name inside that folder.
  • --name works with one file at a time. Slashes are removed, and the file's extension is added if the name has none: --name cover uploads IMG_4021.jpg as cover.jpg. With --folder, it's the name inside the folder.
  • --expires takes 1, 7, 14 or 30 (days), or 0 to keep the file. Without it, the file is kept, whatever Delete after is set to in Aktar. It needs Aktar's auto-delete rules on that destination, and it can't be combined with --folder.
  • --qr can't be combined with --json, and --png only works with aktar qr.
  • In a terminal, progress is shown on stderr while a file uploads. The file is streamed to Aktar, so its size doesn't matter, and there's no time limit.

Examples

One file, one link.
aktar upload screenshot.png
https://files.example.com/2026/10/7f3c2a91.png
Several files, as Markdown: one line per file, in order.
aktar upload *.png -f markdown
![](https://files.example.com/2026/10/1b9e44d0.png)
![](https://files.example.com/2026/10/c2f71a5e.png)
Upload under another name, into a folder.
aktar upload IMG_4021.jpg --name cover --folder blog/2026
https://files.example.com/blog/2026/cover.jpg
The same file was already in the bucket: the link is printed as usual, and the note goes to stderr.
aktar upload photo.jpg
aktar: photo.jpg: already uploaded, reused the existing link
https://files.example.com/2026/09/4d2a8c61.jpg

aktar upload --clipboard

Uploads the file or image that's on the clipboard, like Aktar's own clipboard shortcut.

Usage

aktar upload --clipboard [options]

Options

FlagValueDescription
--clipboardUpload what's on the clipboard instead of files.
-d, --destination<name|id>Destination to upload to, by name or ID. Default: the one selected in Aktar.
-f, --format<format>What to print: url (default), markdown, html or custom (your template in Aktar).
--expires<days>Let the bucket delete the file after 1, 7, 14 or 30 days. 0 keeps it.
--qrAlso print a QR code of each link.
--jsonPrint a JSON array with the full details of each upload, instead of links.
--port<port>Aktar's local API port, for this command only. Wins over AKTAR_PORT and the saved port.

Good to know

  • Pass files or --clipboard, not both.
  • --name and --folder only work with files. -d, -f, --expires, --qr and --json work as with files.
  • With --json, it still prints an array, with one entry.

Examples

The screenshot you just copied.
aktar upload --clipboard
https://files.example.com/2026/10/9a4c03be.png
As Markdown, to a destination named Blog.
aktar upload --clipboard -f markdown -d Blog
![](https://blog-assets.example.com/2026/10/e5b2c8a4.png)
Deleted by the bucket after a day.
aktar upload --clipboard --expires 1
https://files.example.com/tmp/1d/2026/10/38f0d7c2.png

aktar qr

Shows a QR code of a link or any text in the terminal, so you can open it on a phone. Given an upload ID, it shows that upload's link and its QR code.

Usage

aktar qr <link|text|upload-id> [--png <file>]

Options

FlagValueDescription
--png<file>Save the QR code as a PNG file instead of printing it.
--port<port>Aktar's local API port, for this command only. Wins over AKTAR_PORT and the saved port.

Good to know

  • Pass exactly one argument, and quote text with spaces.
  • An upload ID is the id from aktar history --json or aktar upload --json. aktar looks it up in the last 1,000 uploads in Aktar's history; for plain text or a link, it doesn't need Aktar at all.
  • The code is drawn black on white in a terminal, whatever its theme. When the output isn't a terminal, or NO_COLOR is set, it's drawn without colors.
  • --png saves the QR code as a PNG instead of printing it.

Examples

A QR code for any link. The phone camera opens it.
aktar qr https://files.example.com/2026/10/demo.mp4
An upload from history, saved as a PNG.
aktar qr 0B6C2F8E-3D1A-4C55-9E2B-7A41D0C3E9F1 --png cover-qr.png
Saved to cover-qr.png

aktar login

Checks a token against Aktar and saves it, so the other commands can connect.

Usage

aktar login [--token <token>] [--port <port>]

Options

FlagValueDescription
--token<token>The token, instead of the prompt.
--port<port>Aktar's port, saved along with the token. Default 47913.

Good to know

  • In a terminal, it asks for the token and hides what you type. When the input is piped, it reads the token from there.
  • --token skips the prompt, but the token ends up in your shell history. Piping it in or AKTAR_TOKEN avoids that.
  • A token Aktar rejects isn't saved, and the exit code is 3.

Examples

The token stays hidden while you type it.
aktar login
Copy the token from Aktar: Settings > Integrations (turn on Allow local connections first).
Token:
Connected to Aktar 0.10.0. Saved to /Users/you/.config/aktar/cli.json
On a Mac, with the token copied from Aktar.
pbpaste | aktar login
Connected to Aktar 0.10.0. Saved to /Users/you/.config/aktar/cli.json
Without a prompt, for a changed port.
aktar login --token "$AKTAR_SECRET" --port 47920
Connected to Aktar 0.10.0. Saved to /Users/you/.config/aktar/cli.json

aktar logout

Deletes the saved token and port.

Usage

aktar logout

Options

No options.

Good to know

  • AKTAR_TOKEN, if set, still works after aktar logout.
  • It doesn't disconnect other clients. For that, regenerate the token in Aktar.

Examples

Forget the token.
aktar logout
Logged out.
After that, commands ask you to log in again (exit code 3).
aktar status
aktar: Not connected to Aktar yet. Run aktar login with the token from Aktar's Settings > Integrations.

aktar status

Shows which Aktar you're connected to, on which port, the destination selected in Aktar, and where the config file is.

Usage

aktar status [--json]

Options

FlagValueDescription
--jsonPrint JSON instead of text.
--port<port>Aktar's local API port, for this command only. Wins over AKTAR_PORT and the saved port.

Good to know

  • A quick way to check the connection in a script: it exits with code 3 when Aktar can't be reached or the token is wrong.

Examples

Connected, with the selected destination.
aktar status
Aktar 0.10.0 (build 28) on port 47913
Destination: Screenshots (Cloudflare R2, screenshots)
Config: /Users/you/.config/aktar/cli.json
The same as JSON, for scripts.
aktar status --json
{
  "app": "Aktar",
  "version": "0.10.0",
  "build": "28",
  "apiVersion": 1,
  "defaultDestinationId": "5D1A9C3E-7B2F-4E61-8A0D-3C9B6F2E1A47",
  "outputFormat": "url",
  "port": 47913
}

aktar destinations

Lists your destinations with their provider, bucket and ID. * marks the one selected in Aktar.

Usage

aktar destinations [--json]

Options

FlagValueDescription
--jsonPrint JSON instead of text.
--port<port>Aktar's local API port, for this command only. Wins over AKTAR_PORT and the saved port.

Good to know

  • Use a name or an ID with -d. Names are matched without regard to case; an ID always works, even after a rename.
  • --json gives id, name, provider, providerName, bucket, publicBaseURL and isDefault for each.

Examples

The selected destination is marked with *.
aktar destinations
* Screenshots  Cloudflare R2  screenshots  5D1A9C3E-7B2F-4E61-8A0D-3C9B6F2E1A47
  Builds  Amazon S3  acme-builds  A83F2C10-6D4B-4F7E-9C1A-2B5E8D0F3C66
  Blog  Backblaze B2  blog-assets  E2C7B9A4-1F3D-4A8E-B6C0-9D5F2A7E4B13
The name of the selected destination, with jq.
aktar destinations --json | jq -r '.[] | select(.isDefault) | .name'
Screenshots

aktar history

Lists recent uploads, newest first: date, file name and link. Words after history search the history.

Usage

aktar history [search] [options]

Options

FlagValueDescription
-n, --limit<n>How many uploads to list. Default 20.
-d, --destination<name|id>Only uploads to this destination, by name or ID.
--jsonPrint JSON instead of text.
--port<port>Aktar's local API port, for this command only. Wins over AKTAR_PORT and the saved port.

Good to know

  • It lists 20 uploads unless you pass -n.
  • --json gives the same fields as aktar upload --json, including each upload's id for aktar qr.

Examples

The last three uploads.
aktar history -n 3
2026-10-01  screenshot.png  https://files.example.com/2026/10/7f3c2a91.png
2026-10-01  cover.jpg  https://files.example.com/blog/2026/cover.jpg
2026-09-30  invoice-september.pdf  https://files.example.com/2026/09/0e7d51b3.pdf
Search for invoices in one destination.
aktar history invoice -d Screenshots
2026-09-30  invoice-september.pdf  https://files.example.com/2026/09/0e7d51b3.pdf
2026-08-29  invoice-august.pdf  https://files.example.com/2026/08/a6c94f20.pdf
The link of the latest build, with jq.
aktar history -d Builds -n 1 --json | jq -r '.[0].url'
https://acme-builds.s3.amazonaws.com/2026/10/app-3f9c2e1.zip

Options for every command

FlagValueDescription
-h, --helpShow the list of commands and options.
-v, --versionShow the version of aktar.
--port<port>Aktar's local API port, for this command only. Wins over AKTAR_PORT and the saved port.

Output

Formats

-f picks what's printed for each upload. Without it, aktar prints the plain URL, whatever format Aktar's menu bar copies. Markdown and HTML embed images and link everything else, the same way Aktar does.

FormatPrinted for photo.jpg
-f urlhttps://files.example.com/2026/10/7f3c2a91.jpgThe link (default).
-f markdown![](https://files.example.com/2026/10/7f3c2a91.jpg)A Markdown image, or a Markdown link for other files.
-f html<img src="https://files.example.com/2026/10/7f3c2a91.jpg" alt="">An <img> tag, or an <a> link for other files.
-f custom![photo.jpg](https://files.example.com/2026/10/7f3c2a91.jpg)Your template from Aktar's settings, with {url}, {filename} and the other variables filled in.

stdout and stderr

Standard output gets only the links, one per line, in the order of the files (and the QR codes, with --qr). Everything else goes to standard error: progress, errors, and notes such as aktar: photo.jpg: already uploaded, reused the existing link. So url=$(aktar upload file) and aktar upload *.png > links.txt always get clean links.

aktar upload photo.jpg
aktar: photo.jpg: already uploaded, reused the existing link
https://files.example.com/2026/09/4d2a8c61.jpg

JSON

--json prints an array with one entry per uploaded file, after all of them are done. Failed uploads are left out (they're reported on stderr), so check the exit code too.

aktar upload photo.jpg --json
[
  {
    "id": "0B6C2F8E-3D1A-4C55-9E2B-7A41D0C3E9F1",
    "filename": "photo.jpg",
    "objectKey": "2026/10/7f3c2a91.jpg",
    "url": "https://files.example.com/2026/10/7f3c2a91.jpg",
    "destinationId": "5D1A9C3E-7B2F-4E61-8A0D-3C9B6F2E1A47",
    "destinationName": "Screenshots",
    "mimeType": "image/jpeg",
    "size": 482113,
    "createdAt": "2026-10-01T12:00:00Z",
    "expiresAt": null,
    "formats": {
      "url": "https://files.example.com/2026/10/7f3c2a91.jpg",
      "markdown": "![](https://files.example.com/2026/10/7f3c2a91.jpg)",
      "html": "<img src=\"https://files.example.com/2026/10/7f3c2a91.jpg\" alt=\"\">",
      "custom": "![photo.jpg](https://files.example.com/2026/10/7f3c2a91.jpg)"
    },
    "reused": false
  }
]
FieldMeaning
idThe upload's ID in Aktar's history. aktar qr takes it.
filenameThe file name Aktar knows it by: the file's own, or --name.
objectKeyWhere the file is in the bucket.
urlThe link.
destinationIdThe destination's ID.
destinationNameThe destination's name.
mimeTypeThe file's type, after any conversion by Aktar.
sizeSize in bytes, as stored.
createdAtWhen it was uploaded (ISO 8601, UTC).
expiresAtWhen the bucket deletes it, or null if it's kept.
formatsThe link in all four formats: url, markdown, html and custom.
reusedtrue when nothing was uploaded because the same file was already there. Left out by Aktar versions before Mac 0.10.0 and Windows 0.3.0.

Exit codes

CodeMeaning
0Everything worked.
1At least one upload or request failed; the others still went through. Aktar's own errors, such as auto-delete not being set up, also end here.
2Bad arguments, a file that doesn't exist, or a destination name Aktar doesn't have. Nothing was uploaded.
3Not logged in, Aktar isn't running, its local API is off, or the token is wrong.

Recipes

Copy, adjust the file names, done. Every recipe uses only what's documented above.

Keep the link in a variable

Only the link reaches standard output, so command substitution gets exactly the URL. || exit 1 stops the script if the upload failed.

url=$(aktar upload build/report.pdf) || exit 1
echo "Report: $url"
Report: https://files.example.com/2026/10/0e7d51b3.pdf

Upload a build and post the link

Zip a build, upload it to a destination named Builds under the commit's short hash, and post the link to any webhook that takes JSON (a chat channel, an issue tracker, your own endpoint). set -e stops before posting if the upload fails.

#!/bin/sh
set -e
zip -qr app.zip dist
url=$(aktar upload app.zip -d Builds --name "app-$(git rev-parse --short HEAD)")
curl -fsS -X POST "$WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d "{\"text\": \"New build: $url\"}"

A Makefile target

make share uploads the report under today's date and keeps the link in .last-link. In a Makefile, $$ passes a $ to the shell, and the command line starts with a tab.

Makefile
share: dist/report.pdf
	aktar upload dist/report.pdf --name "report-$$(date +%F)" | tee .last-link

Typora image uploader

In Typora, open Settings > Image, choose Custom Command as the image uploader and enter the full path to aktar (the one which aktar prints) followed by upload. Typora passes the image paths and reads one link per line.

/opt/homebrew/bin/aktar upload

Step by step, with the When Insert… setting: Upload Typora images to S3.

Upload from Finder or Shortcuts

On a Mac, add a Run Shell Script action to a Shortcut, or to an Automator Quick Action that receives files in Finder, and set it to pass input as arguments. Shortcuts and Automator don't load your shell's PATH, hence the first line. Select files, run it, and the links are on the clipboard.

export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
aktar upload "$@" | pbcopy
osascript -e 'display notification "Link copied" with title "aktar"'

It uploads files, not folders. Several files give several links, one per line.

Temporary files

For a log, a screen recording or anything that shouldn't stay around, let the bucket delete it. The destination needs Aktar's auto-delete rules first: set them up once from Delete after in Aktar's menu bar or the destination's settings.

aktar upload crash.log --expires 1
aktar upload screen-recording.mov --expires 7 --qr

Expiring files go under tmp/1d/, tmp/7d/ and so on in the bucket, and the bucket deletes them even when Aktar isn't running.

Open a link on your phone

--qr prints a QR code under the link; point your phone's camera at the terminal. To show it again later, pass an upload's ID to aktar qr, here the latest upload matching "demo".

aktar upload demo.mp4 --qr
aktar qr "$(aktar history demo -n 1 --json | jq -r '.[0].id')"

Windows PowerShell

The same works in PowerShell. $LASTEXITCODE holds the exit code, and ConvertFrom-Json reads --json.

PowerShell
$url = aktar upload .\dist\app.zip -d Builds
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
Set-Clipboard $url

$upload = aktar upload .\report.pdf --json | Out-String | ConvertFrom-Json
$upload.formats.markdown

What Aktar does for you

The CLI only passes files on; Aktar does the rest, with each destination's settings. So everything you set up in the app applies to aktar upload too, without any extra options, and the link you get is the one for the file as stored.

  • Path templates

    The destination's object path names the file, with {year}, {uuid}, {filename} and the rest. {md5} and {sha256} name files by their contents.

  • Image processing

    If the destination converts images to WebP or AVIF, compresses or resizes them, CLI uploads get the same treatment, and the link points to the converted file.

  • Photo metadata

    Image metadata in the destination's upload defaults removes the location from photos, or all metadata, before they leave your computer.

  • Same file, same link

    With Reuse links for duplicate files on, the same contents in the same destination get the existing link instead of a second upload. aktar notes it on stderr.

  • Big files

    Large files go up in parts, with no 5 GB limit, are retried after a dropped connection and resume where they stopped. aktar streams the file to Aktar, so it never loads it into memory.

  • Public or temporary links

    Whether the link is public or a temporary (presigned) one that also works for a private bucket is the destination's choice, as in the app.

Duplicate links, image processing, {md5} and {sha256} and uploads in parts came with Aktar for Mac 0.10.0 and Windows 0.3.0: what's new in 0.10.0.

Troubleshooting

Error messages from aktar start with aktar: and go to stderr. The exit code tells you what kind of problem it is.

Aktar isn't running, or its local API is turned off

Open Aktar and check that Allow local connections is on in Settings > Integrations. If you changed the port there, pass it with --port or AKTAR_PORT, or run aktar login --port again. Exit code 3.

Not connected to Aktar yet

There's no saved token and no AKTAR_TOKEN. Run aktar login with the token from Aktar's Settings > Integrations. Exit code 3.

The token doesn't match Aktar's anymore

The token was regenerated in Aktar, or it's mistyped. Run aktar login again with the current one. If AKTAR_TOKEN is set, it wins over the saved token, so update or unset it too. Exit code 3.

Auto-delete isn't set up for this destination

--expires needs the bucket's auto-delete rules. Set them up once from Delete after in Aktar's menu bar or the destination's settings, or upload without --expires. Exit code 1.

No destination named "…"

The message lists the names Aktar has. Check the spelling, quote names with spaces (-d "Client work"), or use the ID from aktar destinations. Exit code 2.

A big upload takes a long time

That's the storage provider's speed: aktar has no time limit for uploads and shows progress on stderr in a terminal. Keep Aktar running until it's done. If the connection drops or Aktar quits (Aktar closed the connection before the request finished), upload the same file again: Aktar for Mac 0.10.0 and Windows 0.3.0 continue from the last part.

aktar won't start: SyntaxError or parseArgs

Your Node.js is older than 18. Check with node --version and update it, or install aktar with Homebrew, which brings its own Node.js.

PowerShell says running scripts is disabled

PowerShell's execution policy blocks the script npm installs for aktar. Run aktar.cmd instead, or allow local scripts once with Set-ExecutionPolicy -Scope CurrentUser RemoteSigned.