exhale

module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 11, 2026 License: AGPL-3.0

README

Exhale

CI Release

Breathe out. Your subscriptions are handled.

Exhale is an open-source, self-hosted subscription manager where the reminder is the interface. The message that tells you Netflix renews in three days lets you fix it right there: mark it paid, move the date, change the card or the amount, cancel. The message updates in place, and so does the web.

It is one program with one data folder. No cloud, no account with us, no telemetry, no paid tier.

Status: early (0.x). It works and is used daily by its author; expect rough edges, and read the release notes before upgrading.

What it does

  • Reminders you can answer. In Telegram (and Slack), each reminder carries the buttons that fit: already paid, new date (this charge or from now on), another amount, payment method, skip, cancel, undo. Also by email, ntfy and webhook as one-way notifications.
  • The whole app inside a chat message. A pinned message in Telegram is Exhale itself: spend, upcoming charges, every subscription, an add wizard, payment methods, settings and a check-up. It redraws when anything changes.
  • The dates that actually cost money. Free trials (reminds before the first charge), notice periods (reminds before the last day to cancel and asks "keep or cancel?"), things that expire unless renewed (domains, licences), fixed-term contracts, and price changes announced in advance.
  • Billing days as banks charge them. Day 31 falls on the last day of shorter months and comes back on the 31st; "the third Wednesday" or "the last Friday"; charges that fall on a weekend moved to the next or previous business day. Dates are always counted from the first charge, so they never drift.
  • Memory. Every charge is a row with its own state, so Exhale knows what you really paid, when the price went up and by how much, and what each subscription has cost since you track it.
  • A check-up of facts, not tips. The same service paid twice, prices that rose in the last year, trials about to charge, deadlines, big yearly charges coming, a card about to expire and everything that depends on it, subscriptions you said you no longer use.
  • Sharing. Other people get their own account and their own reminders. Split the cost of a subscription and see who owes whom each month. Private subscriptions stay private.
  • Money done properly. Any currency, exact amounts, totals converted with ECB reference rates, how much to put away each month for yearly bills, and what is due before payday.
  • For AI agents. Every operation is a tool over MCP, with a live briefing, previews before any change, confirmation for destructive ones and undo for everything. Claude, ChatGPT or a local model can read and manage your subscriptions safely.
  • Tools for many subscriptions. Search by name, notes, account, category or tag; free tags; duplicate a subscription; change many at once (category, payment method, tags, pause, cancel, delete) with a preview and one undo; and, when you record a plan's other price (say, yearly), what switching saves. See the guide.
  • Your data goes in and out. Import a Wallos database, a CSV or an Exhale export through a review list; import your bank's statement (CSV or PDF, in the web or sent to the bot) to find subscriptions and confirm the charges you expected; export everything as JSON, CSV or a ZIP with your attached documents; subscribe to a private calendar feed.
  • Easy to run. A single binary, installers for macOS and Windows, a container image, .deb/.rpm packages with a hardened systemd service, automatic daily backups, sign-in with a password or your identity provider (OpenID Connect). English and Spanish, in chat and on the web; adding a language is two JSON files.

Install

Get the installer for your computer from the download page: Exhale.dmg for macOS, Exhale-Setup.exe for Windows, .deb or .rpm for Linux. Open it: Exhale starts, opens in your browser and starts again with your computer. Create your account and follow the steps on the home page.

On a server or NAS, with Docker:

docker run -d --name exhale --restart unless-stopped \
  -p 8484:8484 -v exhale-data:/data \
  ghcr.io/akamachinecode/exhale:latest
docker logs exhale   # shows the one-time setup code

Open http://<server>:8484, enter the setup code, create your account and follow the steps on the home page: create your own Telegram bot (guided), link your chat, add your subscriptions or import them, and connect your AI agent if you use one.

Exhale needs no public address: it talks to Telegram and Slack with outgoing connections only, so it works behind a home router.

Every file is also on the releases page, with an install script for any Linux and plain binaries. The install guide covers each one, plus HTTPS and backups.

From source:

git clone https://github.com/akamachinecode/exhale && cd exhale
mise install        # Go, Node, pnpm and the other tools
mise run build      # builds the web UI into the binary: bin/exhale
./bin/exhale serve  # http://127.0.0.1:8484

Documentation

Contributing

Read CONTRIBUTING.md and AGENTS.md (the map of the code, for people and coding agents). Commits follow Conventional Commits and are signed off (DCO). Every technical decision is recorded as an ADR.

mise run test   # Go tests with the race detector
mise run lint   # golangci-lint
mise run gen    # after changing SQL or the API

Security

Report vulnerabilities as described in SECURITY.md.

Licence

AGPL-3.0-or-later.

Directories

Path Synopsis
cmd
exhale command
Command exhale is the Exhale server and CLI.
Command exhale is the Exhale server and CLI.
internal
actions
Package actions (piece ⑥) decides what every reminder says and which buttons it carries, and runs the multi-step flows behind those buttons.
Package actions (piece ⑥) decides what every reminder says and which buttons it carries, and runs the multi-step flows behind those buttons.
agents
Package agents (piece ⑰) makes Exhale agent-ready: an MCP server that exposes every use case as a tool, the household briefing as a resource, and ready-made prompts (ADR 0018).
Package agents (piece ⑰) makes Exhale agent-ready: an MCP server that exposes every use case as a tool, the household briefing as a resource, and ready-made prompts (ADR 0018).
app
Package app (piece ⑦) holds every business operation of Exhale.
Package app (piece ⑦) holds every business operation of Exhale.
assistant
Package assistant is the model Exhale itself uses (ADR 0018, part B): plain language in chat and in the web, and reading statements and screenshots into the import review list.
Package assistant is the model Exhale itself uses (ADR 0018, part B): plain language in chat and in the web, and reading statements and screenshots into the import review list.
auth
Package auth resolves who is calling: API tokens for scripts and AI agents, one-time codes for linking chat accounts, and web accounts and sessions (ADR 0006).
Package auth resolves who is calling: API tokens for scripts and AI agents, one-time codes for linking chat accounts, and web accounts and sessions (ADR 0006).
awake
Package awake keeps the computer Exhale runs on from going to sleep, so that reminders go out on time and chat buttons keep answering (ADR 0028).
Package awake keeps the computer Exhale runs on from going to sleep, so that reminders go out on time and chat buttons keep answering (ADR 0028).
backup
Package backup copies the SQLite database safely: a consistent snapshot with VACUUM INTO (copying the file of a live database can corrupt the copy), a rolling set of automatic snapshots while the server runs, and a restore that never overwrites data (ADR 0009, ADR 0020).
Package backup copies the SQLite database safely: a consistent snapshot with VACUUM INTO (copying the file of a live database can corrupt the copy), a rolling set of automatic snapshots while the server runs, and a restore that never overwrites data (ADR 0009, ADR 0020).
bus
Package bus (piece ⑫) fans out domain events in memory: the web receives them over SSE, chat adapters re-edit messages already sent, and the scheduler re-plans reminders.
Package bus (piece ⑫) fans out domain events in memory: the web receives them over SSE, chat adapters re-edit messages already sent, and the scheduler re-plans reminders.
channels/email
Package email sends reminders by email over SMTP (ADR 0007).
Package email sends reminders by email over SMTP (ADR 0007).
channels/email/smtptest
Package smtptest is an in-process SMTP server for tests.
Package smtptest is an in-process SMTP server for tests.
channels/fake
Package fake is a text channel for tests: it renders messages as plain text so conversation scripts can be compared with golden files.
Package fake is a text channel for tests: it renders messages as plain text so conversation scripts can be compared with golden files.
channels/notifiers
Package notifiers runs the notify-only channels (email, ntfy, webhooks, Web Push): it owns their instance settings and hands the channels to the action layer.
Package notifiers runs the notify-only channels (email, ntfy, webhooks, Web Push): it owns their instance settings and hands the channels to the action layer.
channels/notify
Package notify is what the notify-only channels (email, ntfy, webhooks) share: turning a channel-agnostic actions.Message into plain text and HTML, and the link back to the web.
Package notify is what the notify-only channels (email, ntfy, webhooks) share: turning a channel-agnostic actions.Message into plain text and HTML, and the link back to the web.
channels/ntfy
Package ntfy sends reminders as push notifications through ntfy (https://ntfy.sh or a self-hosted server).
Package ntfy sends reminders as push notifications through ntfy (https://ntfy.sh or a self-hosted server).
channels/slack
Package slack (piece ③) connects Exhale to a Slack workspace over Socket Mode: a WebSocket the app opens outward, so no public URL or open port is needed (ADR 0001, 0007).
Package slack (piece ③) connects Exhale to a Slack workspace over Socket Mode: a WebSocket the app opens outward, so no public URL or open port is needed (ADR 0001, 0007).
channels/telegram
Package telegram (piece ②) connects Exhale to a Telegram bot over long polling: an outbound connection, so no public URL or open port is needed (ADR 0001, 0007).
Package telegram (piece ②) connects Exhale to a Telegram bot over long polling: an outbound connection, so no public URL or open port is needed (ADR 0001, 0007).
channels/webhook
Package webhook sends each reminder as one HTTP POST with a JSON body to an address the member chooses.
Package webhook sends each reminder as one HTTP POST with a JSON body to an address the member chooses.
channels/webpush
Package webpush sends reminders as Web Push notifications to the browsers and installed apps (PWA) where a member turned them on (ADR 0026).
Package webpush sends reminders as Web Push notifications to the browsers and installed apps (PWA) where a member turned them on (ADR 0026).
channels/webpush/pushtest
Package pushtest is a fake Web Push service and a fake browser for tests.
Package pushtest is a fake Web Push service and a fake browser for tests.
desktop
Package desktop is Exhale installed as a desktop app (ADR 0029).
Package desktop is Exhale installed as a desktop app (ADR 0029).
domain
Package domain (piece ⑧) holds the entities and business rules of Exhale.
Package domain (piece ⑧) holds the entities and business rules of Exhale.
engine
Package engine is the billing time engine (piece ⑨): civil dates and billing-style recurrence.
Package engine is the billing time engine (piece ⑨): civil dates and billing-style recurrence.
fx
Package fx (piece ⑤) downloads the European Central Bank's daily reference rates: free, no API key, about 30 currencies (ADR 0008).
Package fx (piece ⑤) downloads the European Central Bank's daily reference rates: free, no API key, about 30 currencies (ADR 0008).
httpapi
Package httpapi (piece ①) serves the REST API (huma, OpenAPI 3.1), live events (SSE), the MCP endpoint, health checks and the embedded web UI.
Package httpapi (piece ①) serves the REST API (huma, OpenAPI 3.1), live events (SSE), the MCP endpoint, health checks and the embedded web UI.
i18n
Package i18n holds the languages Exhale speaks and the translations of what chat and the service say (ADR 0023).
Package i18n holds the languages Exhale speaks and the translations of what chat and the service say (ADR 0023).
importer
Package importer turns files from other tools into Exhale import items: a Wallos database or export, a spreadsheet saved as CSV, or Exhale's own export.
Package importer turns files from other tools into Exhale import items: a Wallos database or export, a spreadsheet saved as CSV, or Exhale's own export.
merchant
Package merchant reduces the description a bank writes for a payment to the words that identify who was paid, so "NETFLIX.COM 866-579-7172 CA", "Netflix.com Amsterdam" and a subscription called "Netflix" compare equal.
Package merchant reduces the description a bank writes for a payment to the words that identify who was paid, so "NETFLIX.COM 866-579-7172 CA", "Netflix.com Amsterdam" and a subscription called "Netflix" compare equal.
money
Package money (piece ⑩) represents exact amounts of money in a currency.
Package money (piece ⑩) represents exact amounts of money in a currency.
netguard
Package netguard keeps HTTP requests to addresses chosen by users (webhook URLs, ntfy servers) away from the server's own machine and network.
Package netguard keeps HTTP requests to addresses chosen by users (webhook URLs, ntfy servers) away from the server's own machine and network.
oauth
Package oauth is Exhale's own OAuth 2.1 authorization server, the part of the MCP authorization spec that lets a cloud assistant (Claude.ai, ChatGPT, Grok) connect to a person's Exhale by its URL (ADR 0018 milestone 3, ADR 0024).
Package oauth is Exhale's own OAuth 2.1 authorization server, the part of the MCP authorization spec that lets a cloud assistant (Claude.ai, ChatGPT, Grok) connect to a person's Exhale by its URL (ADR 0018 milestone 3, ADR 0024).
platform
Package platform (piece ⑮) holds process-level concerns: data directory, logging and supervision of long-running services.
Package platform (piece ⑮) holds process-level concerns: data directory, logging and supervision of long-running services.
scheduler
Package scheduler (piece ⑪) is Exhale's clock.
Package scheduler (piece ⑪) is Exhale's clock.
store
Package store (pieces ⑬ and ⑭) owns the SQLite database: opening it with safe pragmas, running migrations after an automatic backup, and mapping rows to domain types.
Package store (pieces ⑬ and ⑭) owns the SQLite database: opening it with safe pragmas, running migrations after an automatic backup, and mapping rows to domain types.
testutil
Package testutil holds shared test helpers.
Package testutil holds shared test helpers.
toolschema
Package toolschema turns a use case of the op catalog into the JSON Schema of a model tool.
Package toolschema turns a use case of the op catalog into the JSON Schema of a model tool.
Package web embeds the compiled web UI (built with Vite into web/dist).
Package web embeds the compiled web UI (built with Vite into web/dist).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL