]> git.giacomolli.uk - onechat/blob - README.rst
Accept owner photos and image files in Telegram
[onechat] / README.rst
1 #########
2  OneChat
3 #########
4
5 OneChat is one AI agent in a single chat that never ends. A daemon owns
6 the agent and its memory, and you talk to it from a terminal client,
7 Telegram, and through your WhatsApp chats. It is in early development.
8 Linux is supported.
9
10 *******
11  Setup
12 *******
13
14 Data directory
15 ==============
16
17 OneChat keeps all its data in one directory, with mode 0700. It uses
18 ``ONECHAT_DIR`` when it is set, else ``$XDG_DATA_HOME/onechat``, else
19 ``~/.local/share/onechat``. The development shell sets ``ONECHAT_DIR``
20 to ``.devenv/onechat`` in the checkout.
21
22 Optional settings go in ``config.json`` in the data directory:
23
24 .. code:: json
25
26    {
27      "endpoint": "chatgpt",
28      "compactor": {"model": "gpt-6.1-sol", "effort": "high"}
29    }
30
31 ``endpoint`` is ``chatgpt`` (the ChatGPT subscription, the default) or
32 ``api`` (the OpenAI API, with ``OPENAI_API_KEY`` set). ``compactor`` is
33 the model and effort of the memory summaries.
34
35 Login
36 =====
37
38 .. code:: console
39
40    onechat login
41
42 Open the link on any device and enter the code. Device code login must
43 be allowed in the ChatGPT security settings. Do not share the login with
44 the Codex CLI: each program logs the other out.
45
46 Telegram
47 ========
48
49 #. Make a bot with BotFather and keep its token.
50 #. Find your numeric Telegram user ID.
51 #. Write both to ``telegram.json`` in the data directory, with mode
52    0600:
53
54 .. code:: json
55
56    {"token": "123456:ABC-token-from-BotFather", "owner": 123456789}
57
58 Start the daemon and write to the bot in a private chat. It answers only
59 you.
60
61 WhatsApp
62 ========
63
64 Link your WhatsApp account as a linked device from the terminal client
65 or Telegram:
66
67 ``/whatsapp pair PHONE``
68    Gives a pairing code. On the phone, open Linked devices, Link a
69    device, Link with phone number instead, and enter the code.
70
71 ``/whatsapp status``
72    Shows the link and the routes of chats to child agents.
73
74 ``/whatsapp unlink``
75    Ends the link.
76
77 The session file gives full access to the account. If it leaks, remove
78 the device in Linked devices on the phone.
79
80 User service
81 ============
82
83 Run the daemon as a systemd user service. Keep the ``result-service``
84 link, so that Nix keeps the package:
85
86 .. code:: console
87
88    nix build --out-link result-service
89    systemctl --user link --force "$PWD/result-service/share/systemd/user/onechat.service"
90    systemctl --user edit onechat.service
91
92 In the editor, set the data directory, and the tools that the agent may
93 use in its shell:
94
95 .. code:: ini
96
97    [Service]
98    Environment="ONECHAT_DIR=DATA_DIR"
99    Environment="PATH=TOOLS_PATH"
100
101 Then start it, and let it run while you are logged out:
102
103 .. code:: console
104
105    systemctl --user daemon-reload
106    systemctl --user enable --now onechat.service
107    loginctl enable-linger "$USER"
108
109 After a ``git pull``, ``bin/service-update`` builds and restarts it.
110 Never run two daemons on the same data.
111
112 Backups
113 =======
114
115 .. code:: console
116
117    onechat backup BACKUP_DIR/onechat.tar.gz
118    ONECHAT_DIR=EMPTY_DIR onechat restore BACKUP_DIR/onechat.tar.gz
119
120 A backup runs while the daemon runs. Restore needs a stopped daemon and
121 an empty directory. **An archive holds your logins, the bot token, and
122 the WhatsApp link**, so keep it private.
123
124 For a daily backup with the last 14 kept, save this script, with
125 ``BACKUP_DIR`` replaced by a private directory outside the data
126 directory:
127
128 .. code:: sh
129
130    #!/bin/sh
131    set -eu
132    umask 077
133    cd BACKUP_DIR
134    onechat backup "onechat-$(date +%F).tar.gz"
135    ls -1 onechat-????-??-??.tar.gz | sort -r | tail -n +15 | xargs -r rm --
136
137 and run it from a ``Type=oneshot`` user service with the same
138 ``ONECHAT_DIR`` and an ``OnCalendar=daily`` timer.
139
140 *********
141  Talking
142 *********
143
144 .. code:: console
145
146    onechat
147
148 ``onechat`` connects to the running daemon. Each line is a message, and
149 replies show with Markdown styles and tables. These lines are commands:
150
151 ``/stop``
152    Interrupts the running turn.
153
154 ``/stop NAME``
155    Stops the subagent NAME.
156
157 ``/whatsapp ...``
158    The WhatsApp commands above.
159
160 In Telegram, write as in the client, also with photos and image files.
161 ``onechat help`` lists all commands.
162
163 *********************
164  What the agent does
165 *********************
166
167 Memory
168    The agent remembers the whole chat as summaries that it can open
169    again, so it never starts over. ``agent/instructions.md`` holds your
170    lasting preferences. The agent can propose a change to it and makes
171    the change only after you agree.
172
173 Tools
174    The agent runs shell commands as you, in its working directory, with
175    no sandbox.
176
177 Subagents
178    For long tasks it starts subagents in the background, such as
179    ``GreenOtter``, and gets their reports as messages.
180
181 Child agents
182    A child is a permanent agent for one area of your life, such as
183    ``House``, with its own memory. The root creates it, talks to it, and
184    hears from it only what needs you. Children never send WhatsApp
185    messages; they draft replies for you to approve.
186
187 WhatsApp
188    The agent reads your chats in batches and wakes for a private message
189    or a mention of you. It finds chats and sends messages only when you
190    ask. It proposes to route a chat that is only about one area to the
191    child of that area, and sets the route after you agree.
192
193 Images
194    Send a photo, and the agent sees it. Its memory keeps what the image
195    shows, and it can look at an older image again.
196
197 Schedules
198    Ask for reminders and timed tasks, such as "every weekday at 8, tell
199    me what my groups talked about". Each run uses the quota, so runs are
200    at least 5 minutes apart.
201
202 Import
203    Old WhatsApp chats can join the memory in date order. Stop the
204    daemon, export the chat as a ZIP, and run the plan before the import.
205    The import rebuilds the target's memory with model calls:
206
207 .. code:: console
208
209    onechat import -n [--agent NAME] CHAT.zip
210    onechat import [--agent NAME] CHAT.zip
211
212 *****
213  Log
214 *****
215
216 The daemon writes short events with ``key=value`` attributes to the user
217 journal, at three levels: info, warning for a failure that is retried or
218 loses nothing, and error for a failure that loses data or stops work.
219
220 .. code:: console
221
222    journalctl --user -u onechat -f
223    journalctl --user -u onechat -p warning
224
225 *************
226  Development
227 *************
228
229 Nix supplies the Go toolchain and all tools. Enter the development shell
230 with ``direnv allow`` or ``nix develop``. Then:
231
232 .. code:: console
233
234    nix build
235    ./result/bin/onechat version
236    bin/format
237    bin/check
238    nix flake check
239
240 ``onechat version`` prints ``yyyy-mm-dd-gitshort`` for a Nix build and
241 ``dev`` for a direct Go build. ``bin/check`` runs the linters and a
242 short replay of a synthetic log, and ``nix flake check`` also runs the
243 full replay of 100,000 messages. ``onechat probe LOG COUNT`` measures
244 the memory summaries on a log with real model calls.