README.md

# Mastomation

`mastomation` is a small Elixir CLI for Mastodon account workflows.

It can:

- inspect and export thread content
- delete your posts with safety defaults
- download and search your private profile notes

For delete workflows, it **keeps pinned, bookmarked, and favourited (by you) statuses** and only deletes the rest.

## Warning

This tool performs destructive actions against your account.

- Deletions are permanent.
- Start with `--dry-run` to verify which statuses would be removed.
- Use a dedicated access token with only the permissions you need.

## Requirements

- Elixir `~> 1.18`
- Network access to your Mastodon instance
- A Mastodon access token able to delete statuses

## Create a Mastodon access token

1. Open your instance app page:
   - `https://<your-instance>/settings/applications/new`
2. Create a new application (name can be anything, e.g. `mastomation`).
3. Enable these permissions/scopes:
   - `read`
   - `write`
   - `profile`
4. Save the application and copy the generated access token.
5. Configure these environment variables:
   - `MASTODON_INSTANCE_URL`
   - `MASTODON_ACCESS_TOKEN`

Examples:

Bash:

```bash
export MASTODON_INSTANCE_URL="https://mastodon.social"
export MASTODON_ACCESS_TOKEN="YOUR_TOKEN"
```

Fish:

```fish
set -x MASTODON_INSTANCE_URL "https://mastodon.social"
set -x MASTODON_ACCESS_TOKEN "YOUR_TOKEN"
```

You can also pass them as CLI options (`--instance-url` and `--access-token`).

## Installation

Install from Hex (recommended):

```bash
mix escript.install hex mastomation
```

This installs:

- `mastomation` into `~/.mix/escripts`
- the CLI executable only (shell completions are not installed automatically)

Install from source:

```bash
git clone https://codeberg.org/maikelthedev/mastomation.git
cd mastomation
mix deps.get
```

Build the escript:

```bash
mix escript.build
```

Install it:

```bash
mix escript.install
```

After installation, the executable is available under:

```bash
~/.mix/escripts/mastomation
```

Add `~/.mix/escripts` to your `PATH` so you can run `mastomation` directly.

If you prefer running from source in the project folder:

```bash
iex -S mix
```

Then call modules directly:

```elixir
Mastomation.run(["delete", "--dry-run"])
Mastomation.run(["thread", "see", "https://mastodon.social/@me/123456789012345678"])
```

## Usage

Run without arguments to see help:

```bash
mastomation
```

Deletion is explicit, and credentials can be passed as flags or environment variables:

```bash
mastomation delete all
```

Or, without env vars:

```bash
mastomation delete all --instance-url https://mastodon.social --access-token YOUR_TOKEN
```

### Options

`delete all` subcommand options:

- `-i`, `--instance-url INSTANCE_URL`: Mastodon instance URL
- `-t`, `--access-token ACCESS_TOKEN`: access token
- `-d`, `--delay-ms MILLISECONDS`: delay between deletions (default: `60000`)
- `--keyword KEYWORD` (repeatable): delete only statuses containing keyword(s)
- `--override-instance-url INSTANCE_URL`: override target instance for this run
- `--override-access-token ACCESS_TOKEN`: override token for this run
- `--dry-run`: print what would be deleted, but do not delete
- `--no-backup`: skip backup export before delete
- `--frontmatter`: include YAML frontmatter in backup markdown files

By default, delete operations backup statuses before deleting. Backups are written under `./export/backups` (relative to where you run `mastomation`).

`delete thread` command:

```bash
mastomation delete thread https://mastodon.social/@me/123456789012345678
```

`delete thread` uses the same auth/backup/keyword flags as `delete all`, includes the source toot if authored by you, and caps delay at 2 seconds between deletions because thread batches are typically shorter and less likely to hit Mastodon's default delete rate limit (30 deletions per 30 minutes).

### Thread subcommands

Inspect a joined thread from a source toot (same author only), including replies/subtoots in order.

```bash
mastomation thread see https://mastodon.social/@me/123456789012345678
```

Export the thread to markdown and media files under `./export`:

```bash
mastomation thread export https://mastodon.social/@me/123456789012345678
```

Thread auth options:

- `-i`, `--instance-url INSTANCE_URL`
- `-t`, `--access-token ACCESS_TOKEN`
- `--frontmatter`: include YAML frontmatter in exported markdown
- `--override-instance-url INSTANCE_URL`
- `--override-access-token ACCESS_TOKEN`

### Notes subcommands

Download private profile notes for accounts you follow and that follow you:

```bash
mastomation notes download
```

Search downloaded notes:

```bash
mastomation notes search "project"
mastomation notes search --term ops --term infra
```

Optional notes flags:

- `--path FILE_PATH`: custom notes JSON location

Default notes file location:

- `$XDG_DATA_HOME/mastomation/notes.json` (or `~/.local/share/mastomation/notes.json` when `XDG_DATA_HOME` is unset)

`notes download` also supports auth override flags:

- `-i`, `--instance-url INSTANCE_URL`
- `-t`, `--access-token ACCESS_TOKEN`
- `--override-instance-url INSTANCE_URL`
- `--override-access-token ACCESS_TOKEN`

Notes search profile links use `MASTODON_INSTANCE_URL`. If `MASTODON_UI=DECK`, links are rendered as `/deck/@handle` (for example `https://vmst.io/deck/@nik@toot.teckids.org`).

Compatibility aliases still supported:

- `mastomation thread <URL_OR_ID>` behaves like `mastomation thread see <URL_OR_ID>`
- `mastomation delete` behaves like `mastomation delete all`
- `mastomation delete --thread-source <URL_OR_ID>` behaves like `mastomation delete thread <URL_OR_ID>`

## Examples

Delete all with default backup:

```bash
mastomation delete all
```

Delete by keyword only:

```bash
mastomation delete all --keyword projectx --keyword launch
```

Delete your replies in a thread:

```bash
mastomation delete thread https://mastodon.social/@me/123456789012345678
```

## Behavior

The tool:

1. Resolves your account ID via `/api/v1/accounts/verify_credentials`
2. Fetches statuses in pages (`limit=40`) from `/api/v1/accounts/:id/statuses`
3. Filters out pinned/bookmarked/favourited statuses
4. Deletes each remaining status via `/api/v1/statuses/:id`
5. Waits `delay_ms` between deletions to reduce rate-limit pressure

## Development

Run tests:

```bash
mix test
```

Format and lint:

```bash
mix format
mix credo
```

## Shell completions

Fish completion file:

- `completions/mastomation.fish`

### Install Fish completions

Copy-based install:

```bash
mkdir -p ~/.config/fish/completions
cp completions/mastomation.fish ~/.config/fish/completions/mastomation.fish
```

If you installed from Hex and do not have the repository checked out, download and install the completion file directly:

```bash
mkdir -p ~/.config/fish/completions
curl -fsSL https://codeberg.org/maikelthedev/mastomation/raw/branch/main/completions/mastomation.fish \
  -o ~/.config/fish/completions/mastomation.fish
```

Symlink-based install (recommended during development):

```bash
mkdir -p ~/.config/fish/completions
ln -sf "$PWD/completions/mastomation.fish" ~/.config/fish/completions/mastomation.fish
```

Reload fish (or open a new shell):

```bash
exec fish
```

## Versioning and changelog

- Semantic versioning policy: `SEMVER.md`
- Change history: `CHANGELOG.md`

## Telemetry events

Mastomation emits telemetry events you can attach to:

- `[:mastomation, :http, :get, :start]` / `:stop` (metadata includes `url`)
- `[:mastomation, :http, :delete, :start]` / `:stop` (metadata includes `url`, `attempt`)
- `[:mastomation, :delete, :all, :start]` / `:stop`
- `[:mastomation, :delete, :thread, :start]` / `:stop` (metadata includes `thread_source`)
- `[:mastomation, :thread, :export, :start]` / `:stop` (metadata includes `dry_run`)