aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-26 08:24:02 +0200
committerDanilo M. <danix@danix.xyz>2026-09-26 08:24:02 +0200
commit3b6f56f93c829a741df4ded189a4b8c98ce7fdff (patch)
tree1c947731ed3704bdf60d6660f21d10c6ae8b157f
parentb1816ed443d715d0c706a40fd202d595d4a11926 (diff)
downloaddesktop-assistant-3b6f56f93c829a741df4ded189a4b8c98ce7fdff.tar.gz
desktop-assistant-3b6f56f93c829a741df4ded189a4b8c98ce7fdff.zip
Add calc, mail, playing and finance example tools
All read-only: each command is fixed in its tool file, so the model fills parameters but can never reach mailctl tag or firefly tx add. qalc reads "17.5% of 240" as a modulo, so the calc hint shows percent as a factor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--README.md15
-rw-r--r--examples/tools/calc.toml7
-rwxr-xr-xexamples/tools/finance.sh51
-rw-r--r--examples/tools/finance.toml13
-rwxr-xr-xexamples/tools/mail.sh30
-rw-r--r--examples/tools/mail.toml9
-rwxr-xr-xexamples/tools/playing.sh30
-rw-r--r--examples/tools/playing.toml2
8 files changed, 153 insertions, 4 deletions
diff --git a/README.md b/README.md
index 1d7ecef..a9b15e8 100644
--- a/README.md
+++ b/README.md
@@ -75,10 +75,17 @@ type = "string"
description = "What the model should pass"
```
-The example tools only read: `now` (date), `calendar` (`agenda.py` over
-a vdirsyncer folder), `weather` (OpenWeatherMap, key file in the
-conky-theme-udt format), `search` (a SearXNG instance with the JSON
-format enabled).
+The example tools only read:
+
+- `now`: date and time
+- `calendar`: `agenda.py` over a vdirsyncer folder
+- `weather`: OpenWeatherMap, key file in the conky-theme-udt format
+- `search`: a SearXNG instance with the JSON format enabled
+- `calc`: `qalc` (arithmetic, units, currencies, date math)
+- `mail`: unread threads through `mailctl` searches, no tagging or sync
+- `playing`: the current track from `playerctl`, or `mpc`
+- `finance`: balances, budgets and spending from Firefly III's `firefly`
+ list commands
## License
diff --git a/examples/tools/calc.toml b/examples/tools/calc.toml
new file mode 100644
index 0000000..c97ef04
--- /dev/null
+++ b/examples/tools/calc.toml
@@ -0,0 +1,7 @@
+description = "Calculator: arithmetic, percentages, unit and currency conversion, date math (days between dates). Use it instead of computing yourself."
+command = ["qalc", "-t", "{expression}"]
+timeout = 10
+
+[params.expression]
+type = "string"
+description = "A qalc expression. Percent as a factor: 240 * 17.5%, 80 - 15% (not \"17.5% of 240\", qalc reads % there as modulo). Also 70 mph to km/h, 100 EUR to USD, days(today; 2026-12-25)."
diff --git a/examples/tools/finance.sh b/examples/tools/finance.sh
new file mode 100755
index 0000000..3c6f768
--- /dev/null
+++ b/examples/tools/finance.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+# desktop-assistant tool: personal finance from Firefly III (read-only).
+# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# finance.sh WHAT [DAYS]: WHAT is balances (active asset accounts),
+# budgets (this month, spent against the limit) or spending (withdrawals in
+# the last DAYS days, default 30: total and the 10 largest). Only firefly's
+# list commands run here: nothing is recorded or edited.
+
+set -uo pipefail
+
+ff() { firefly "$@" || { echo "firefly $1 $2 failed" >&2; exit 1; }; }
+
+case "${1:-}" in
+balances)
+ ff account list --type asset | jq -r '.[] | select(.active)
+ | "\(.name): \(.current_balance | tonumber * 100 | round / 100) \(.currency_code)"'
+ ;;
+budgets)
+ ff budget list | jq -r '.[] | select(.active)
+ | "\(.name): spent \([.spent[].sum | tonumber] | add // 0 | fabs * 100 | round / 100)"
+ + (if .auto_budget_amount then " of \(.auto_budget_amount | tonumber)" else "" end)
+ + " \(.currency_code // "")"'
+ ;;
+spending)
+ days="${2:-30}"
+ since=$(date -d "$days days ago" +%F) || exit 1
+ ff tx list --since "$since" --all --flat 2>/dev/null | jq -r --arg since "$since" '
+ [.[] | select(.type == "withdrawal") | .amount |= tonumber]
+ | "spent since \($since): \(map(.amount) | add // 0 | . * 100 | round / 100) in \(length) payments",
+ (sort_by(-.amount)[:10][]
+ | "\(.date[:10]) \(.amount * 100 | round / 100) \(.destination_name): \(.description)")'
+ ;;
+*)
+ echo "what must be balances, budgets or spending" >&2
+ exit 1
+ ;;
+esac
diff --git a/examples/tools/finance.toml b/examples/tools/finance.toml
new file mode 100644
index 0000000..b05031c
--- /dev/null
+++ b/examples/tools/finance.toml
@@ -0,0 +1,13 @@
+description = "The user's money, from Firefly III: account balances, this month's budgets, or recent spending. Read-only."
+command = ["finance.sh", "{what}", "{days}"]
+timeout = 20
+announce.it = ["Controllo i conti."]
+announce.en = ["Checking your accounts."]
+
+[params.what]
+type = "string"
+description = "balances, budgets or spending"
+
+[params.days]
+type = "integer"
+description = "For spending: how many days back. Empty for 30."
diff --git a/examples/tools/mail.sh b/examples/tools/mail.sh
new file mode 100755
index 0000000..4e0e9c1
--- /dev/null
+++ b/examples/tools/mail.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# desktop-assistant tool: unread mail summary through mailctl (read-only).
+# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# mail.sh [QUERY]: thread count and the 10 newest threads for a notmuch
+# query, default unread mail in the inbox, across every account. Only
+# mailctl's search runs here: nothing is tagged, moved or synced.
+# MAILCTL overrides the command (default mailctl.py on PATH).
+
+set -uo pipefail
+
+query="${1:-tag:unread and tag:inbox}"
+json=$("${MAILCTL:-mailctl.py}" search "$query" --json) || { echo "mail search failed" >&2; exit 1; }
+jq -r 'length as $n
+ | if $n == 0 then "no threads match"
+ else "\($n) threads", (.[:10][] | "\(.date_relative), \(.authors): \(.subject)")
+ end' <<<"$json"
diff --git a/examples/tools/mail.toml b/examples/tools/mail.toml
new file mode 100644
index 0000000..2f1a9d8
--- /dev/null
+++ b/examples/tools/mail.toml
@@ -0,0 +1,9 @@
+description = "The user's email: how many unread messages and who they are from. Read-only."
+command = ["mail.sh", "{query}"]
+timeout = 15
+announce.it = ["Controllo la posta."]
+announce.en = ["Checking your mail."]
+
+[params.query]
+type = "string"
+description = "notmuch query, e.g. from:amazon or subject:invoice and date:7d.. Empty for unread mail in the inbox."
diff --git a/examples/tools/playing.sh b/examples/tools/playing.sh
new file mode 100755
index 0000000..9605f82
--- /dev/null
+++ b/examples/tools/playing.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# desktop-assistant tool: what is playing now.
+# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# playing.sh: the current track from any MPRIS player (playerctl), or from
+# MPD (mpc) when no MPRIS player is running.
+
+set -uo pipefail
+
+if out=$(playerctl metadata --format '{{status}}: {{artist}} - {{title}} ({{playerName}})' 2>/dev/null); then
+ echo "$out"
+elif out=$(mpc status --format '%artist% - %title%' 2>/dev/null) && [ "$(wc -l <<<"$out")" -gt 1 ]; then
+ head -2 <<<"$out" | tac | tr '\n' ' '
+ echo "(mpd)"
+else
+ echo "nothing is playing"
+fi
diff --git a/examples/tools/playing.toml b/examples/tools/playing.toml
new file mode 100644
index 0000000..6d33743
--- /dev/null
+++ b/examples/tools/playing.toml
@@ -0,0 +1,2 @@
+description = "The song or media playing right now on this computer."
+command = ["playing.sh"]