]> git.giacomolli.uk - onechat/blob - README.rst
Log image and message sends
[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 ``/image PATH [caption]``
158 Sends a JPEG, PNG, or WebP image. Quote a path with spaces.
159
160 ``/whatsapp ...``
161 The WhatsApp commands above.
162
163 In Telegram, write as in the client, also with photos and image files.
164 ``onechat help`` lists all commands.
165
166 *********************
167 What the agent does
168 *********************
169
170 Memory
171 The agent remembers the whole chat as summaries that it can open
172 again, so it never starts over. ``agent/instructions.md`` holds your
173 lasting preferences. The agent can propose a change to it and makes
174 the change only after you agree.
175
176 Tools
177 The agent runs shell commands as you, in its working directory, with
178 no sandbox.
179
180 Subagents
181 For long tasks it starts subagents in the background, such as
182 ``GreenOtter``, and gets their reports as messages.
183
184 Child agents
185 A child is a permanent agent for one area of your life, such as
186 ``House``, with its own memory. The root creates it, talks to it, and
187 hears from it only what needs you. Children never send WhatsApp
188 messages; they draft replies for you to approve.
189
190 WhatsApp
191 The agent reads your chats in batches and wakes for a private message
192 or a mention of you. It finds chats and sends messages only when you
193 ask. It proposes to route a chat that is only about one area to the
194 child of that area, and sets the route after you agree.
195
196 Images
197 Send a photo in Telegram, WhatsApp, or with ``/image`` to the agent.
198 Its memory keeps what the image shows, and it can look at an older
199 image again. Ask it to show an image or send one to a WhatsApp chat.
200
201 Schedules
202 Ask for reminders and timed tasks, such as "every weekday at 8, tell
203 me what my groups talked about". Each run uses the quota, so runs are
204 at least 5 minutes apart.
205
206 Import
207 Old WhatsApp chats can join the memory in date order. Stop the
208 daemon, export the chat as a ZIP, and run the plan before the import.
209 The import rebuilds the target's memory with model calls:
210
211 .. code:: console
212
213 onechat import -n [--agent NAME] CHAT.zip
214 onechat import [--agent NAME] CHAT.zip
215
216 *****
217 Log
218 *****
219
220 The daemon writes short events with ``key=value`` attributes to the user
221 journal, at three levels: info, warning for a failure that is retried or
222 loses nothing, and error for a failure that loses data or stops work.
223
224 .. code:: console
225
226 journalctl --user -u onechat -f
227 journalctl --user -u onechat -p warning
228
229 *************
230 Development
231 *************
232
233 Nix supplies the Go toolchain and all tools. Enter the development shell
234 with ``direnv allow`` or ``nix develop``. Then:
235
236 .. code:: console
237
238 nix build
239 ./result/bin/onechat version
240 bin/format
241 bin/check
242 nix flake check
243
244 ``onechat version`` prints ``yyyy-mm-dd-gitshort`` for a Nix build and
245 ``dev`` for a direct Go build. ``bin/check`` runs the linters and a
246 short replay of a synthetic log, and ``nix flake check`` also runs the
247 full replay of 100,000 messages. ``onechat probe LOG COUNT`` measures
248 the memory summaries on a log with real model calls.