@lovenyberg/ove 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: create-issue
3
+ description: Create a well-structured GitHub issue with labels and acceptance criteria
4
+ disable-model-invocation: true
5
+ argument-hint: "[repo] [title]"
6
+ allowed-tools: Bash(gh *)
7
+ ---
8
+
9
+ Create a GitHub issue on the specified repo.
10
+
11
+ Usage: `/create-issue owner/repo Title of the issue`
12
+
13
+ If only a title is given without a repo, use the current repository.
14
+
15
+ ## Steps
16
+
17
+ 1. Parse $ARGUMENTS into repo and title
18
+ 2. Ask clarifying questions if the request is vague
19
+ 3. Draft the issue body with:
20
+ - **Description**: What and why
21
+ - **Acceptance criteria**: Checkboxes for done conditions
22
+ - **Technical notes**: Relevant files, patterns, constraints
23
+ 4. Create with: `gh issue create --repo <repo> --title "<title>" --body "<body>"`
24
+ 5. Return the issue URL
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: review-pr
3
+ description: Review a pull request with critical analysis and refactoring suggestions
4
+ disable-model-invocation: true
5
+ argument-hint: "[PR number or URL]"
6
+ allowed-tools: Bash(gh *), Read, Grep, Glob
7
+ ---
8
+
9
+ Review the pull request specified by $ARGUMENTS.
10
+
11
+ ## Steps
12
+
13
+ 1. Fetch PR details: `gh pr view $ARGUMENTS --json title,body,additions,deletions,changedFiles,baseRefName,headRefName`
14
+ 2. Fetch the diff: `gh pr diff $ARGUMENTS`
15
+ 3. Read changed files in full for context
16
+ 4. Analyze the changes for:
17
+ - Correctness: bugs, edge cases, off-by-one errors
18
+ - Security: injection, auth issues, secrets in code
19
+ - Performance: N+1 queries, unnecessary allocations, missing indexes
20
+ - Style: matches project conventions (see CLAUDE.md)
21
+ - Tests: adequate coverage for new/changed behavior
22
+
23
+ ## Output format
24
+
25
+ Provide a structured review:
26
+
27
+ ### Summary
28
+ One paragraph on what the PR does.
29
+
30
+ ### Issues
31
+ List any problems found, with file:line references.
32
+
33
+ ### Suggestions
34
+ Optional improvements that aren't blocking.
35
+
36
+ ### Verdict
37
+ APPROVE, REQUEST_CHANGES, or COMMENT with reasoning.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: ship
3
+ description: Create branch, commit changes, push, and open a PR
4
+ disable-model-invocation: true
5
+ argument-hint: "[description of changes]"
6
+ allowed-tools: Bash(git *), Bash(gh *)
7
+ ---
8
+
9
+ Ship the current changes as a pull request.
10
+
11
+ ## Steps
12
+
13
+ 1. Run `git status` and `git diff --stat` to understand what changed
14
+ 2. Create a descriptive branch name from the changes (e.g. `fix/sse-timeout`, `feat/sidebar-history`)
15
+ 3. Stage relevant files (avoid secrets, lock files, local config)
16
+ 4. Commit with a conventional commit message (feat/fix/refactor/docs/chore)
17
+ 5. Push the branch with `git push -u origin <branch>`
18
+ 6. Create a PR with `gh pr create` including:
19
+ - Short title (under 70 chars)
20
+ - Summary section with bullet points
21
+ - Test plan section
22
+ 7. Return the PR URL
package/.env.example CHANGED
@@ -4,6 +4,8 @@ SLACK_APP_TOKEN=xapp-...
4
4
 
5
5
  # WhatsApp
6
6
  WHATSAPP_ENABLED=false
7
+ # WHATSAPP_PHONE=46701234567
8
+ # WHATSAPP_ALLOWED_CHATS=46701234567,120363xxx@g.us
7
9
 
8
10
  # Telegram
9
11
  # TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
@@ -23,6 +25,9 @@ WHATSAPP_ENABLED=false
23
25
  # CLI mode (auto-enabled when no other adapters configured)
24
26
  # CLI_MODE=true
25
27
 
28
+ # Task tracing (stores per-task event timeline in SQLite)
29
+ # OVE_TRACE=true
30
+
26
31
  # Repos directory
27
32
  REPOS_DIR=./repos
28
33
 
package/CLAUDE.md CHANGED
@@ -27,3 +27,23 @@ Your grumpy but meticulous dev companion — routes chat messages to AI coding a
27
27
  - Use bun:sqlite directly, no ORMs
28
28
  - Use bun:test for testing
29
29
  - Structured JSON logging via src/logger.ts
30
+
31
+ ## Skills
32
+
33
+ Ove spawns Claude Code CLI (`claude -p`) in isolated worktrees. The spawned instances automatically pick up:
34
+
35
+ - **Project skills** from `.claude/skills/` in the target repo's worktree
36
+ - **Personal skills** from `~/.claude/skills/` on the host machine
37
+ - **Plugin skills** from installed plugins (configured via `~/.claude/settings.json` `enabledPlugins`)
38
+
39
+ Skills follow the [Agent Skills](https://agentskills.io) open standard. See [Claude Code skills docs](https://code.claude.com/docs/en/skills) for full reference.
40
+
41
+ ### Setting up skills for Ove
42
+
43
+ Skills are configured **manually** in the Claude Code installation that Ove runs on:
44
+
45
+ 1. **Personal skills** — place in `~/.claude/skills/<name>/SKILL.md` on the host running Ove
46
+ 2. **Per-repo skills** — commit `.claude/skills/<name>/SKILL.md` to each repo Ove manages
47
+ 3. **Plugins** — install via `claude plugins add` and enable in `~/.claude/settings.json`
48
+
49
+ The Ove project itself ships skills in `.claude/skills/` (review-pr, create-issue, ship) that are available when working on the Ove codebase.
package/README.md CHANGED
@@ -41,7 +41,7 @@ Talk to Ove the way you'd talk to a teammate. These all work:
41
41
  "refactor the user service, it's getting messy"
42
42
  ```
43
43
 
44
- Ove figures out the intent, picks the right repo, and gets to work. For common tasks, there are also shorthand commands:
44
+ Ove figures out the intent, picks the right repo, and gets to work. See [more examples](docs/examples.md). For common tasks, there are also shorthand commands:
45
45
 
46
46
  ```
47
47
  review PR #N on <repo> Code review with inline comments
@@ -130,8 +130,9 @@ sudo systemctl enable --now ove
130
130
  ### HTTP API + Web UI
131
131
 
132
132
  1. Set `HTTP_API_PORT=3000` and `HTTP_API_KEY=<your-secret>` in `.env`
133
- 2. Open `http://localhost:3000` for the Web UI
134
- 3. Or call the API directly: `curl -X POST http://localhost:3000/api/message -H "X-API-Key: <key>" -H "Content-Type: application/json" -d '{"text": "validate my-app"}'`
133
+ 2. Open `http://localhost:3000` for the chat UI
134
+ 3. Open `http://localhost:3000/trace` for the trace viewer (see [Web Pages](#web-pages) below)
135
+ 4. Or call the API directly: `curl -X POST http://localhost:3000/api/message -H "X-API-Key: <key>" -H "Content-Type: application/json" -d '{"text": "validate my-app"}'`
135
136
 
136
137
  ### GitHub (issue/PR comments)
137
138
 
@@ -142,8 +143,9 @@ sudo systemctl enable --now ove
142
143
 
143
144
  ### WhatsApp
144
145
 
145
- 1. Set `WHATSAPP_ENABLED=true` in `.env`
146
- 2. Scan the QR code printed in the terminal on first start
146
+ 1. Set `WHATSAPP_ENABLED=true` and `WHATSAPP_PHONE=<your-number>` in `.env`
147
+ 2. Start Ove and enter the pairing code on your phone (WhatsApp Linked Devices → Link a Device)
148
+ 3. Set `WHATSAPP_ALLOWED_CHATS=<phone1>,<phone2>` to limit which chats Ove listens to. Without this, Ove responds to **all** your outgoing messages in every chat. Use phone numbers (e.g. `46701234567`) for individual chats or full JIDs (e.g. `120363xxx@g.us`) for groups.
147
149
 
148
150
  ## Config
149
151
 
@@ -195,25 +197,99 @@ Per-repo `runner` overrides the global default. Supported runners: `"claude"` (d
195
197
 
196
198
  Static cron jobs go in `config.json`. Users can also create schedules via chat — these are stored in SQLite and managed with `list schedules` / `remove schedule #N`.
197
199
 
200
+ ## Web Pages
201
+
202
+ The HTTP adapter serves two pages (no auth required to load — API key is entered in-browser and stored in `localStorage`):
203
+
204
+ | Route | Page | Description |
205
+ |-------|------|-------------|
206
+ | `/` | Chat UI | Send messages to Ove, see streaming status updates and results |
207
+ | `/trace` | Trace Viewer | Browse tasks and inspect per-task trace timelines |
208
+ | `/status` | Status | Adapter health, connection state, queue stats, WhatsApp pairing code |
209
+
210
+ ### Trace Viewer (`/trace`)
211
+
212
+ A debugging dashboard for inspecting what happened during task execution.
213
+
214
+ - **Left panel** — Task list with status badges, repo name, prompt preview, and relative timestamps. Filterable by repo, user, and status.
215
+ - **Right panel** — When a task is selected, shows:
216
+ - **Context card** — Full prompt, user, repo, status, created/done timestamps, and total duration.
217
+ - **Trace timeline** — Chronological events with color-coded kinds: lifecycle (green), tool (blue), status (gray), output (white), error (red). Each event with detail data can be expanded individually.
218
+ - **Toolbar** — "show all details" expands every trace event at once, "copy json" copies the full task + trace data as JSON for troubleshooting.
219
+ - **Auto-refresh** — Toggle to poll every 3 seconds, useful for watching running tasks.
220
+
221
+ ### Tracing
222
+
223
+ Tracing records per-task event timelines in SQLite. Enable it with:
224
+
225
+ ```bash
226
+ OVE_TRACE=true
227
+ ```
228
+
229
+ Trace events are also accessible via chat (`trace <task-id>`) and the API:
230
+
231
+ ```bash
232
+ # List recent tasks
233
+ curl http://localhost:3000/api/tasks?key=<key>&limit=20&status=completed
234
+
235
+ # Get trace for a specific task
236
+ curl http://localhost:3000/api/trace/<task-id>?key=<key>
237
+ ```
238
+
239
+ ## Skills
240
+
241
+ Ove spawns Claude Code CLI (`claude -p`) in isolated worktrees. The spawned instances automatically pick up [skills](https://code.claude.com/docs/en/skills) — reusable instruction sets that follow the [Agent Skills](https://agentskills.io) open standard.
242
+
243
+ Skills are configured **manually** on the host machine running Ove:
244
+
245
+ | Level | Path | Scope |
246
+ |-------|------|-------|
247
+ | Personal | `~/.claude/skills/<name>/SKILL.md` | All repos on this machine |
248
+ | Per-repo | `.claude/skills/<name>/SKILL.md` (committed to repo) | That repo only |
249
+ | Plugins | Installed via `claude plugins add` | Where enabled |
250
+
251
+ When Ove runs a task in a worktree, Claude Code picks up personal skills from `~/.claude/skills/`, project skills from the repo's `.claude/skills/`, and any enabled plugins. This means you can give the Claude instances domain-specific knowledge, coding conventions, deployment workflows, or review checklists — just by dropping a `SKILL.md` in the right place.
252
+
253
+ Example: adding a review skill to a repo so Ove knows your team's review standards:
254
+
255
+ ```
256
+ my-repo/.claude/skills/review/SKILL.md
257
+ ```
258
+
259
+ ```yaml
260
+ ---
261
+ name: review
262
+ description: Review code using our team standards
263
+ ---
264
+
265
+ When reviewing code, check for:
266
+ 1. Error handling covers all failure modes
267
+ 2. Tests cover the happy path and at least one edge case
268
+ 3. No secrets or credentials in code
269
+ ```
270
+
271
+ See the [Claude Code skills docs](https://code.claude.com/docs/en/skills) for the full reference on frontmatter options, argument passing, subagent execution, and more.
272
+
198
273
  ## Testing
199
274
 
200
275
  ```bash
201
- bun test # 150 tests
276
+ bun test # 224 tests
202
277
  ```
203
278
 
204
- ## How It Works
279
+ ## Security
280
+
281
+ Ove executes arbitrary code on your machine via Claude Code CLI. Treat it accordingly.
282
+
283
+ **Never expose Ove to the public internet.** The HTTP API and Web UI are designed for local or private network use only. There is no rate limiting, no session management, and the API key is a single shared secret. Putting this behind a public URL is asking for trouble.
205
284
 
206
- 1. Message arrives via any transport (Slack, WhatsApp, Telegram, Discord, CLI, HTTP API, or GitHub comment)
207
- 2. Chat adapters use `handleMessage`, event adapters use `handleEvent`
208
- 3. Router parses intent and extracts repo/args
209
- 4. Task gets queued in SQLite (one per repo at a time, different repos run in parallel)
210
- 5. Worker loop picks up tasks concurrently (up to 5 parallel tasks across different repos)
211
- 6. Each task gets an isolated git worktree
212
- 7. Runs the configured agent runner (`claude -p` or `codex exec`) with streaming JSON output
213
- 8. Status updates stream back (chat: edits a message, HTTP: SSE, GitHub: single comment)
214
- 9. Result sent back, worktree cleaned up
285
+ - **Run on localhost or a private network.** If you need remote access, put it behind a VPN or SSH tunnel — not a reverse proxy with a public domain.
286
+ - **Keep your API key secret.** It grants full access to submit tasks, read chat history, and view adapter status (including WhatsApp pairing codes). Rotate it if compromised.
287
+ - **Ove runs code as your user.** Whatever permissions your shell user has, Ove's spawned agents have too — SSH keys, git credentials, cloud CLI sessions, everything. Run it under a dedicated user with minimal permissions where possible.
288
+ - **Audit your config.** The `users` map controls who can submit tasks. Don't add wildcard entries. Lock repos to specific users.
289
+ - **WhatsApp pairing codes are sensitive.** They appear on the `/status` page (behind API key auth) and in server logs. Anyone with the code can link a device to your WhatsApp account.
290
+ - **Docker helps.** Running in Docker limits blast radius. The container only mounts what you give it.
215
291
 
216
- See [example conversations](docs/examples.md) for all flows.
292
+ This is a power tool for developers, not a hosted service. You are responsible for securing your deployment.
217
293
 
218
294
  ## License
219
295
 
package/docs/examples.md CHANGED
@@ -9,10 +9,7 @@ You don't need commands. Just describe what you need, like you'd tell a colleagu
9
9
  **Slack DM:**
10
10
  ```
11
11
  alice: the login page is broken, users get a 500 after submitting the form
12
- ove: Task queued (aaa11111). Working on it...
13
- > Grep: "login" in src/
14
- > Read: src/routes/auth.ts
15
- > Read: src/middleware/session.ts
12
+ ove: Working on it...
16
13
  ove: Found the issue — the session middleware wasn't awaiting the
17
14
  database call on line 34 of src/middleware/session.ts. Created
18
15
  PR #47 with the fix and added a test:
@@ -22,11 +19,7 @@ ove: Found the issue — the session middleware wasn't awaiting the
22
19
  **Telegram:**
23
20
  ```
24
21
  alice: can you add input validation to the user registration endpoint in my-app?
25
- ove: Task queued (bbb22222). Working on it...
26
- > Read: src/routes/users.ts
27
- > Edit: src/routes/users.ts
28
- > Write: src/routes/users.test.ts
29
- > Bash: bun test
22
+ ove: Working on it...
30
23
  ove: Done. Added zod validation for email, password length, and
31
24
  username format. All 48 tests pass. PR #48:
32
25
  https://github.com/org/my-app/pull/48
@@ -37,10 +30,6 @@ ove: Done. Added zod validation for email, password length, and
37
30
  alice: how does the caching layer work in my-app? I need to understand
38
31
  it before I make changes
39
32
  ove: Looking into it...
40
- > Glob: **/*cache*
41
- > Read: src/cache/redis.ts
42
- > Read: src/cache/keys.ts
43
- > Read: src/middleware/cache.ts
44
33
  ove: The caching layer has 3 parts:
45
34
  1. src/cache/redis.ts — Redis client wrapper with connection pooling
46
35
  2. src/cache/keys.ts — key generation with TTL per resource type
@@ -55,10 +44,7 @@ ove: The caching layer has 3 parts:
55
44
  **Slack DM:**
56
45
  ```
57
46
  alice: review PR #42 on my-app
58
- ove: Task queued (abc12345). Working on it...
59
- > Bash: gh pr diff 42
60
- > Read: src/auth.ts
61
- > Read: src/middleware.ts
47
+ ove: Working on it...
62
48
  ove: PR #42 review done. Left 3 inline comments:
63
49
  - src/auth.ts:15 — potential SQL injection in query param
64
50
  - src/middleware.ts:42 — missing error handler for async route
@@ -76,14 +62,7 @@ Ove replies with a comment containing the review summary.
76
62
  **Telegram:**
77
63
  ```
78
64
  alice: fix issue #15 on my-app
79
- ove: Task queued (bbb22222). Working on it...
80
- > Bash: gh issue view 15
81
- > Grep: "handleAuth"
82
- > Read: src/auth.ts
83
- > Edit: src/auth.ts
84
- > Bash: bun test
85
- > Bash: git add -A && git commit -m "Fix auth token expiry check"
86
- > Bash: gh pr create --title "Fix #15: auth token expiry"
65
+ ove: Working on it...
87
66
  ove: Fixed! Created PR #43:
88
67
  https://github.com/org/my-app/pull/43
89
68
  Changed src/auth.ts to properly check token expiry timestamps.
@@ -94,10 +73,7 @@ ove: Fixed! Created PR #43:
94
73
  **Discord:**
95
74
  ```
96
75
  alice: validate my-app
97
- ove: Task queued (ccc33333). Working on it...
98
- > Bash: bun test
99
- > Read: package.json
100
- > Bash: bunx eslint src/
76
+ ove: Working on it...
101
77
  ove: All 42 tests pass. ESLint found 3 warnings:
102
78
  • src/utils.ts:12 — unused variable 'tmp'
103
79
  • src/api.ts:45 — prefer const
@@ -108,11 +84,7 @@ ove: All 42 tests pass. ESLint found 3 warnings:
108
84
 
109
85
  ```
110
86
  alice: simplify src/router.ts in my-app
111
- ove: Task queued (ddd44444). Working on it...
112
- > Read: src/router.ts
113
- > Edit: src/router.ts
114
- > Bash: bun test
115
- > Bash: gh pr create --title "Simplify src/router.ts"
87
+ ove: Working on it...
116
88
  ove: Created PR #44. Reduced cyclomatic complexity from 18 to 9.
117
89
  Extracted 3 helper functions, removed duplicated regex logic.
118
90
  ```
@@ -142,12 +114,7 @@ ove: Let's think about this. Key questions:
142
114
 
143
115
  ```
144
116
  alice: create project my-api with template express
145
- ove: Task queued (eee55555). Working on it...
146
- > Bash: mkdir -p my-api && cd my-api && npm init -y
147
- > Write: src/index.ts
148
- > Bash: npm install express
149
- > Bash: git init && git add -A && git commit -m "Initial commit"
150
- > Bash: gh repo create my-api --public --push
117
+ ove: Working on it...
151
118
  ove: Project "my-api" created and pushed to GitHub:
152
119
  https://github.com/org/my-api
153
120
  Structure: Express + TypeScript, src/index.ts entry point
@@ -182,9 +149,6 @@ Anything you type works. Ove parses intent from natural language.
182
149
 
183
150
  ```
184
151
  alice: what does the auth middleware do in my-app
185
- ove: Task queued (fff66666). Working on it...
186
- > Glob: **/*middleware*
187
- > Read: src/middleware/auth.ts
188
152
  ove: The auth middleware in my-app:
189
153
  1. Extracts JWT from Authorization header
190
154
  2. Verifies signature against JWKS endpoint
@@ -195,10 +159,7 @@ ove: The auth middleware in my-app:
195
159
 
196
160
  ```
197
161
  alice: the CI is red on main, can you check what's going on?
198
- ove: Task queued (ggg77777). Working on it...
199
- > Bash: gh run list --limit 5
200
- > Bash: gh run view 12345 --log-failed
201
- > Read: src/api.test.ts
162
+ ove: Looking into it...
202
163
  ove: The test "should return 404 for unknown routes" is failing
203
164
  because the new /health endpoint was added without updating
204
165
  the route count assertion. Line 89 in src/api.test.ts expects
@@ -217,12 +178,10 @@ curl -X POST http://localhost:3000/api/message \
217
178
 
218
179
  **Stream results via SSE:**
219
180
  ```bash
220
- curl -N http://localhost:3000/api/tasks/abc12345/stream \
221
- -H "X-API-Key: your-secret"
181
+ curl -N "http://localhost:3000/api/message/<eventId>/stream?key=your-secret"
222
182
 
223
- data: {"type":"status","message":"Running tests..."}
224
- data: {"type":"status","message":"All 42 tests pass."}
225
- data: {"type":"done","result":"Validation complete. No issues."}
183
+ data: {"status":"pending","statusText":"Running tests..."}
184
+ data: {"status":"completed","result":"Validation complete. No issues."}
226
185
  ```
227
186
 
228
187
  **Web UI:** Open `http://localhost:3000` in a browser for a chat-style interface.
package/docs/index.html CHANGED
@@ -807,6 +807,43 @@ sudo systemctl enable --now ove</pre>
807
807
  </ol>
808
808
  </section>
809
809
 
810
+ <section class="section" id="skills">
811
+ <h2>Skills</h2>
812
+ <p class="section-note">Teach Ove's Claude instances your conventions. Manually.</p>
813
+
814
+ <p>Ove spawns <a href="https://code.claude.com/docs/en/skills">Claude Code CLI</a> in isolated worktrees. The spawned instances automatically pick up <strong>skills</strong> &mdash; reusable instruction sets that follow the <a href="https://agentskills.io">Agent Skills</a> open standard.</p>
815
+
816
+ <p>Skills are configured <strong>manually</strong> on the host machine running Ove:</p>
817
+
818
+ <dl class="cmd-grid">
819
+ <dt>~/.claude/skills/</dt>
820
+ <dd>Personal skills &mdash; available across all repos on this machine</dd>
821
+ <dt>.claude/skills/</dt>
822
+ <dd>Per-repo skills &mdash; committed to each repo Ove manages</dd>
823
+ <dt>Plugins</dt>
824
+ <dd>Installed via <code>claude plugins add</code> &mdash; available where enabled</dd>
825
+ </dl>
826
+
827
+ <p>When Ove runs a task, Claude Code picks up all three levels. Drop a <code>SKILL.md</code> with domain knowledge, coding conventions, review checklists, or deployment workflows &mdash; and every task on that repo benefits.</p>
828
+
829
+ <pre data-label="example: .claude/skills/review/SKILL.md">---
830
+ name: review
831
+ description: Review code using our team standards
832
+ ---
833
+
834
+ When reviewing code, check for:
835
+ 1. Error handling covers all failure modes
836
+ 2. Tests cover the happy path and at least one edge case
837
+ 3. No secrets or credentials in code</pre>
838
+
839
+ <p>See the <a href="https://code.claude.com/docs/en/skills">Claude Code skills docs</a> for frontmatter options, argument passing, subagent execution, and more.</p>
840
+
841
+ <div class="ove-says">
842
+ "Skills are just instructions in a file. Not magic. But they work."
843
+ <span class="attr">&mdash; Ove</span>
844
+ </div>
845
+ </section>
846
+
810
847
  <section class="section" id="transports">
811
848
  <h2>Transport Setup</h2>
812
849
  <p class="section-note">Enable what you need. Ove doesn't judge. Much.</p>
@@ -855,8 +892,9 @@ sudo systemctl enable --now ove</pre>
855
892
 
856
893
  <h3>WhatsApp</h3>
857
894
  <ol class="steps">
858
- <li>Set <code>WHATSAPP_ENABLED=true</code> in <code>.env</code></li>
859
- <li>Scan the QR code printed in the terminal on first start</li>
895
+ <li>Set <code>WHATSAPP_ENABLED=true</code> and <code>WHATSAPP_PHONE=&lt;your-number&gt;</code> in <code>.env</code></li>
896
+ <li>Start Ove and enter the pairing code on your phone (WhatsApp &rarr; Linked Devices &rarr; Link a Device)</li>
897
+ <li>Set <code>WHATSAPP_ALLOWED_CHATS=&lt;phone1&gt;,&lt;phone2&gt;</code> to limit which chats Ove listens to. Without this, Ove responds to <strong>all</strong> your outgoing messages in every chat. Use phone numbers (e.g. <code>46701234567</code>) for individual chats or full JIDs (e.g. <code>120363xxx@g.us</code>) for groups.</li>
860
898
  </ol>
861
899
  </section>
862
900