aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: 8f622b98c60a27d12696f2ad40a659f3135eb653 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# desktop-assistant

A local text assistant daemon. Questions arrive on a Unix socket, the
model already loaded in a local llama-server answers, calling read-only
tools when a question needs them, and the reply streams back token by
token. Every conversation is kept in a local SQLite history with
full-text search. The model and the history stay on the machine; only
tools you enable (weather, web search) reach the network.

The front end is the assistant canvas of the quickshell desktop
(`desktop/assistant/` in the quickshell repo, on SUPER+Home). Anything
that speaks JSON lines on a Unix socket can drive it.

The voice version (push-to-talk, whisper, Kokoro) is the tag `voice-v1`.

## Requirements

- a running `llama-server` with an OpenAI-compatible API, router mode
- Python 3 (stdlib only; SQLite with FTS5)
- poppler (`pdftotext`, `pdftoppm`) for PDF attachments
- `curl` and `jq` for the weather and search example tools,
  `python3-dateutil` for the calendar one

## Usage

```sh
python3 assistant.py          # run
python3 assistant.py --test   # self-check
./assistant.sh start          # detached
./assistant.sh stop
./assistant.sh restart
./assistant.sh status
```

The daemon uses whichever model the router has loaded, so it never swaps
a model out under another client.

Only one daemon serves the socket: a second one refuses to start while the
first answers.

## Protocol

JSON lines both ways on `$XDG_RUNTIME_DIR/desktop-assistant.sock` (mode
0600). Every connected client sees every event.

In: `ask {text, files}`, `write {files, prompt, dir, name}`, `stop`, `new`, `list`, `open {id}`, `search {q}`,
`delete {id}`.

Out: `hello` on connect (state, model, context use, the current
conversation and any reply in flight), then `user`, `think`, `token`,
`tool`, `done`, `state`, `ctx`, `error`, and the answers `conversations`,
`conversation` and `results`. The full table is in
`docs/superpowers/specs/2026-10-16-text-daemon-design.md`.

Ids are integers; a malformed command or argument answers `error` and the
connection stays open.

`write` is a one-off request whose reply goes to a file instead of the
conversation (the canvas's To .md): no history, no thinking, no tools; it
streams `progress {chars}` and ends with `written {path}`, the first free
name of `name` in `dir`. A stop leaves no file.

`files` is a list of absolute paths, at most 8. Text and code files and
PDFs are read and inlined, sharing half the free context (a PDF page with
no text goes as an image, at most 4, rendered at 150 dpi, at most 1600 px);
images go as image parts to a model that reports seeing them. History
keeps the text and, for images, the path and hash: a file that changed or
moved is reported as no longer available when the conversation is
reopened, and a model that cannot see images gets a note instead.

Try it by hand:

```sh
socat - UNIX-CONNECT:$XDG_RUNTIME_DIR/desktop-assistant.sock
{"type":"ask","text":"What time is it?"}
```

## History

`~/.local/share/desktop-assistant/history.db` (`$XDG_DATA_HOME`
honoured), directory 0700, file 0600. The model is sent the last 10 turns
of the open conversation. Tool results are stored as a placeholder, not
their output. Reasoning is shown live and not stored.

## Configuration and tools

Everything is optional. Settings and tools live in
`~/.config/desktop-assistant/` (or `$XDG_CONFIG_HOME/desktop-assistant/`):

```sh
mkdir -p ~/.config/desktop-assistant
cp examples/config.toml ~/.config/desktop-assistant/
cp -r examples/tools ~/.config/desktop-assistant/
```

- `config.toml`: every key is optional, the example lists the defaults.
  `[env]` is added to every tool's environment; put instance URLs and
  key file paths there.
- `tools/<name>.toml`: one tool each, enabled by being there. A tool is a
  command run without a shell, its stdout goes back to the model:

```toml
description = "What the tool does, for the model"
command = ["script.sh", "{param}"]   # looked up in tools/ first, then PATH
timeout = 10

[params.param]
type = "string"
description = "What the model should pass"
```

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
- `bluetooth`: power, connected devices (battery when reported) and paired
  ones, through `bluetoothctl show/devices/info`
- `vms`: libvirt VMs and their state, or one VM's details, through `virsh`
  read commands
- `updates`: Slackware -current ChangeLog entries newer than the installed
  packages: counts, security fixes, kernel bump, one package's notes, or a
  full markdown recap opened in `MD_EDITOR` (default `xdg-open`); `CHANGELOG`
  and `PKGDIR` in `[env]` override the mirror path and package database

## License

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. See [LICENSE](LICENSE).

## Development Approach

This project is developed using AI-assisted tools. Code is generated with the help of AI based on human-provided specifications, design decisions, and iterative feedback.

All contributions are reviewed, tested, and curated by the maintainer before being included in the codebase. AI is used as a productivity and exploration tool, while human oversight remains central to all decisions.

The goal is to combine the flexibility of AI-assisted development with standard open-source practices such as transparency, review, and accountability.