devist 0.23.0

Project bootstrap CLI for AI-assisted development. Spin up new projects from templates, manage backends, and keep your codebase comprehensible.
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
# Changelog

All notable changes to devist are documented here.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/).

## [0.23.0] - 2026-05-04

### Added — Inbox audit thread
- 6th daemon thread `audit` — companion to `verify`, but answers a
  different question. Where verify asks "did the user fix this?",
  audit asks "should this advice have been raised in the first place?"
- **Triggers** (whichever fires first): 30-minute tick OR 5+ pending
  actionable items older than 5 minutes accumulated.
- **Process**: fetches un-acked `suggest|warn|block` advice older than
  5min (so fresh items have a chance to be acted on first), sends to
  Claude with current strong/constraint memories injected so the
  auditor can detect "this advice contradicts a user-declared
  invariant", then auto-acks rejects with `acked_by='audit'` and a
  reason logged.
- Cost: 1 Claude call per cycle, max 30 advice items per call.

### Why
Memory consolidation (v0.22.0) handles the Reso store. The advice
inbox needed the same treatment — even with MUST/MUST NOT in the
generation prompt, Claude can still produce noise. The audit pass
closes that loop by re-evaluating un-acked advice against the same
bar, and against the user's strong/constraint memories. Inbox
quality is now continuously evaluated, not just gated at generation.

## [0.22.0] - 2026-05-04

### Added — Reso memory consolidation thread
- New 5th daemon thread `consolidate` runs Reso's "sleep cycle":
  reads all active memories, asks Claude to evaluate each against the
  fact-extraction MUST/MUST NOT bar, then applies verdicts (keep,
  update, merge, delete) via Supabase soft-delete + PATCH.
- **Triggers** (whichever fires first): hourly tick OR 10+ new
  memories accumulated since last run.
- **Safety rails**: `source='user'` rows never auto-deleted/demoted;
  `priority='constraint'` rows never auto-demoted; all mutations are
  soft-delete (restorable via SQL); 60-memory cap per cycle.
- Heartbeats as thread name `consolidate` so the dashboard reflects
  the new thread.

### Added — Watcher noise filter (editor artifacts)
- `is_editor_artifact()` filter blocks `*.tmp.<pid>.<ts>` atomic-write
  residue, Vim swap (`.swp/.swo/.swn`), backup (`*~`), the `4913`
  probe, Vite `*.timestamp-*.mjs`, smoke-test scratch (`SMOKE_*.md`),
  and `tsbuildinfo`. Inbox audit on prior 28 advice items showed 9 of
  them (32%) were repeated observations of these patterns.
- Unit tests cover atomic-write, Vim, Vite, SMOKE, and real-source
  cases.

### Added — Project name aliases
- `WorkerConfig.project_aliases: HashMap<String, String>` lets users
  pick a brand-correct casing for a watch-folder without renaming the
  on-disk directory.
- Default ships `{"devist": "Devist"}` so Devist's Supabase rows
  (memories, worker_events) carry the canonical brand label.

### Changed — Advice prompt mirrors facts MUST/MUST NOT
- 4 must-raise categories (concrete bugs with location, code-doc
  drift with both sides cited, cross-cutting invariants, concrete
  refactor wins) and 6 must-not categories (build artifacts,
  gitignore nags, "consider tests", stale doc warnings, restating
  diff, repeats of prior memory).
- Severity guidance: `block` reserved for prod-breaking; most output
  should be `info` or `suggest`.
- Empty advice array is the expected outcome for most bursts.

## [0.21.0] - 2026-05-04

### Changed — branding + install UX
- Dashboard / landing copy capitalizes the brand to "Devist" in
  user-facing prose (header, login subtitle, "What is Devist?",
  overview subtitle, "Devist core" rules layer). CLI commands, paths,
  and package names stay lowercase since those reflect actual shell
  input.
- README Install section reorganized: Homebrew + `cargo install` are
  now the documented default paths (both work today). Removed the
  outdated "planned for v1.0" note.
- New README subsection explains the macOS "unidentified developer"
  warning and two workarounds (`xattr -d com.apple.quarantine` or
  Finder right-click → Open).
- Homebrew formula now ships a `caveats` block so the warning + fix
  appear automatically after `brew install WebchemistCorp/devist/devist`.

### Why
Apple Developer ID signing ($99/year) is on the roadmap, not in scope
yet. Until then, clear documentation + a tap-side caveats block keeps
the install flow usable without surprising new users.

## [0.20.0] - 2026-05-04

### Changed — Reso fact extraction is now strict
- Rewrote the fact-extraction prompt with explicit MUST / MUST NOT
  rules. Four valid categories: decision rationale (WHY), hard
  constraints, cross-file invariants, and past-incident scars.
  Six forbidden categories with concrete examples (dependency lists,
  file structure, CI config, doc restatements, version snapshots,
  observation phrasing).
- Default to empty `facts: []` when in doubt — most bursts now
  produce zero memories, which is the expected outcome.
- Confidence threshold raised 0.7 → 0.85.

### Why
Earlier extractions surfaced mostly code-surface restatements
(rusqlite version, release profile flags, file paths) — information
already visible in `Cargo.toml` / `ci.yml` / module doc comments. After
13 such entries the user reported low value + heavy duplication. New
prompt makes the bar explicit: a fact is something a future maintainer
or AI cannot learn by reading the code.

## [0.19.0] - 2026-05-03

### Added — macOS launchd integration
- `devist worker enable` registers a LaunchAgent
  (`~/Library/LaunchAgents/dev.webchemist.devist.worker.plist`) with
  `RunAtLoad=true` + `KeepAlive=true`. Daemon now auto-starts on every
  login and respawns on crash.
- `devist worker disable` removes the LaunchAgent.
- **Self-restart on update** — daemon polls its own binary mtime every
  30s (after a 60s grace window). When the binary changes
  (`cargo install --force`, `brew upgrade devist`) AND launchd is
  managing the daemon, it exits cleanly so KeepAlive respawns the new
  binary. No manual `worker stop && worker start` needed after updates.
- `worker status` shows whether launchd registration is active.
- `worker start` detects the LaunchAgent and uses `launchctl kickstart`
  instead of forking, keeping the daemon under launchd's lifecycle.

macOS only — Linux/Windows fall back to the existing detached-fork flow.

### Changed
- Daemon's `run_loop` now writes its own PID file, so `worker status`
  works regardless of how the daemon was launched.
- `ci.yml` triggers only on PRs (was: PRs + main pushes). Solo
  workflow runs tests locally before pushing; Dependabot PRs still
  validated.
- `ci.yml` dropped `publish-dry-run` job — release.yml's actual
  publish covers the same checks.

### Dependencies
- rusqlite 0.31 → 0.39 (Dependabot).

## [0.18.0] - 2026-05-03

### Added — Reso unified memory system
- New `memories` table on Supabase as the canonical store, with mem0
  Cloud as semantic index (dual-write). Replaces the old `worker_rules`
  table + standalone mem0 design.
- Daemon writes `info` advice + high-confidence facts to Reso with
  scope (`project`/`tech`/`user`) + priority
  (`constraint`/`strong`/`preference`/`info`).
- `constraint` and `strong` memories are always injected into the
  advice prompt; `preference` surfaces via semantic search.
- Dashboard **Memory** page replaces the old Rules page — list, scope
  tabs, search, promote/demote priority, soft-delete.

### Changed
- Daemon dropped the `rules-sync` thread + entire `worker_rules` code
  path. Built-in safety rules now live compiled-in
  (`prompt_constants.rs`).
- Inbox redesigned: card layout with project/path in header, full-width
  body, locale-aware relative time, Copy + Ack actions only.
- Page headers across Inbox/Overview/ProjectTimeline drop redundant
  subtitles. Memory page title becomes "Reso 시스템".

### Fixed
- ProjectTimeline History tab crash caused by Supabase realtime channel
  name collision when both Activity and History subscribed to the same
  channel — channel names now include a per-instance random suffix.

### Migrations
- `0013_memories.sql` — create `memories` table.
- `0014_backfill_rules_to_memories.sql` — migrate existing
  `worker_rules` rows.
- `0015_drop_worker_rules.sql` — drop legacy table.

## [0.17.2] - 2026-05-03

### Fixed
- Release workflow now passes `--allow-dirty` to `cargo publish`.
  CI sometimes regenerates `Cargo.lock` after checkout, which made
  v0.17.0 and v0.17.1 publishes fail to push to crates.io even though
  the binaries built fine. This patch unblocks the pipeline so
  `cargo install devist` picks up the latest version.

## [0.17.1] - 2026-05-03

### Tuned
- verify thread is more responsive:
  - tick: 60s → **20s**
  - per-project cooldown: 5min → **90s**
  - per-project budget: 4/h → **8/h**
- Net effect: typical "user fixes issue → auto-ack" latency drops
  from 60s–6min to ~30s–1m30s. Cost ceiling stays bounded by the
  hourly budget + change-gate.

## [0.17.0] - 2026-05-03

### Changed
- `listProjects` now reads from a server-side aggregating view
  (`public.project_summary`) instead of fetching 2000 raw rows and
  reducing in JS. Removes the silent long-tail-project drop that
  would have appeared once event volume grew.

### Migration
- `migrations/0012_project_summary_view.sql``CREATE OR REPLACE
  VIEW … WITH (security_invoker = true)` so the existing `worker_events`
  RLS policy is honored. `GRANT SELECT` to authenticated + service_role.
  Idempotent.

## [0.16.0] - 2026-05-03

### Added — Advice row interactions
- 📋 **Copy** button on each advice row → `navigator.clipboard.writeText`
  with brief check-mark feedback.
- ✏️ **Inline edit** — pencil icon opens a textarea, Save PATCHes
  `payload.text`. Migration `0011_grant_payload_update.sql` adds the
  required column-level UPDATE grant.
-**Apply with AI** — clicking the Sparkles icon shows a confirmation
  modal, then INSERTs an `apply_advice` worker_job. Daemon spawns
  `claude` in the project directory with `--permission-mode bypassPermissions`
  so the agent can edit files surgically. On success the advice
  auto-acks (`acked_by='apply'`) with a 10-second Undo strip
  (Gmail-style reversibility).
- Acked badge now shows the source: `acked (verify)`, `acked (apply)`,
  or `acked (user)`.

### Internal
- `ClaudeCli::ask_json_in_dir(prompt, workdir, timeout)` — wraps
  `claude -p` with a working directory + bypass permissions, parses
  JSON response. Used by the new `handle_apply_advice` job handler.
- `WorkerEvent.acked_by` surfaced in TS types; `ackEvent(id, source)`
  signature accepts an explicit attribution.

### Migration
- `migrations/0011_grant_payload_update.sql``GRANT UPDATE (payload)
  ON worker_events TO authenticated`. Idempotent.

## [0.15.0] - 2026-05-03

### Added — periodic, change-gated auto-verify of advice
- New 5th daemon thread `verify` runs every 60s. Per project:
  1. Skip if cooldown < 5min since last check.
  2. Skip if no `file_changed` in local SQLite since last verify
     (change-gate — no tokens spent on quiet projects).
  3. Fetch un-acked, **verifiable** advice from Supabase.
  4. Read current content of the referenced files (locally, no
     extra Supabase round-trips).
  5. One Claude call per project: which items are resolved?
     Conservative prompt — only resolved=true if the issue is
     clearly absent from current file content.
  6. PATCH each resolved row with `acked_at=now()`,
     `acked_by='verify'`.
- Per-project rate limit: 4 verify calls per hour
  (sliding-window `HourlyLimiter`).
- Advice generation now emits `verifiable: true|false` per item +
  `paths: [...]`. Subjective advice (`verifiable=false`) is ignored
  by the verify thread.

### Added
- Migration `0010_acked_by.sql` adds `worker_events.acked_by` text
  column (`'user'` | `'verify'` | `'apply'`). Authenticated users
  retain UPDATE permission on it alongside `acked_at`.
- `Db::distinct_projects()` and `Db::project_has_changes_since()`
  helpers backing the verify thread's local-SQLite gate.
- `SupabaseClient::list_pending_verifiable_advice(project)` and
  `ack_event(id, source)` for the verify ↔ Supabase round-trip.
- `urlencoding` dependency for safe project-name URL encoding.

### Why
File events themselves are too noisy to drive auto-ack. Periodic
batched verification with a change-gate keeps cost bounded
(typical day: ~10-30 Claude calls instead of hundreds), preserves
local SQLite as the source of truth for activity, and reads
Supabase only when there's actually pending work.

## [0.14.0] - 2026-05-03

### Changed — daemon advice locale follows the user automatically
- `auto` advice (file-change burst) used to use the static
  `advice_locale` from worker config (default `"ko"`). It now resolves
  the user's current language preference at write time:
  1. `public.user_locale_pref` view (latest user's
     `auth.users.raw_user_meta_data.lang`)
  2. fallback to `cfg.advice_locale`
- Same resolution for AI rule-generation jobs when the dashboard
  doesn't pass an explicit `input.locale`.
- `SupabaseClient::get_user_locale()` caches the value for 5 minutes
  ~one extra REST hit per cache window, otherwise zero overhead.
- Failures (HTTP, missing view, no preference) silently fall back to
  config — advice generation never blocks on locale resolution.

### Added
- Migration `0009_user_locale_pref_view.sql` — public view exposing
  the most-recently-active user's `lang`. Restricted to `service_role`.

### Removed
- Japanese (`ja`) from the dashboard. Two languages only: `en`, `ko`.
  Translation of dynamic content turned out to be too much surface
  area for too little benefit; `advice_locale` write-at-source is the
  canonical answer.

### Notes
- Single-user assumption: the view returns one row (latest user). For
  multi-user, replace with a per-(client_id) mapping table.
- Existing English advice rows from earlier daemon runs were
  one-shot translated to Korean in the conversation log; not part of
  any migration.

## [0.13.0] - 2026-05-03

### Added — locale-aware AI output
- `WorkerConfig.advice_locale` (default `"ko"`). Daemon's advice prompt
  appends an explicit instruction to write all natural-language strings
  (every `text`, every `explain` field) in this BCP-47 language code.
  JSON keys/structure stay English regardless.
- `worker_jobs.input.locale` is honored per-request — the dashboard
  passes the user's current UI language so AI-generated rule drafts come
  back in that language. Falls back to `advice_locale` from config.
- Dashboard now translates `severity` (info/suggest/warn/block) and
  `event_type` (advice/advice_error/file_changed/scan/...) per language.
  Filter buttons, EventRow badges, and the "acked" pill all localized
  for en/ko/ja.

### Added — Japanese
- Full `ja` dictionary covering Landing / Login / Dashboard / pages.
- `LANGUAGES` array exposes `English / 한국어 / 日本語`.

### Changed
- `LanguageSwitch` uses shadcn/ui `Select` (not native `<select>`).
- I18nProvider now syncs language preference to
  `auth.users.user_metadata.lang` so it follows the user across devices.
- Sidebar title is the typographic logo `DEVIST` + small `DASHBOARD`
  caption + email.

## [0.12.0] - 2026-05-03

### Changed (breaking)
- Rules are now two layers: **devist core** (built-in, immutable,
  ships with the binary) + **user global** (single editable file at
  `~/.devist/worker/rules.md`). Per-project rules removed.
- `devist worker rules path|show|init` no longer accept `--project`.
- `Rules::load(monitor, project)``Rules::load_global()`.
- Templates no longer ship `.devist/rules.md.tmpl`.

### Added
- `BUILTIN_RULES` constant in `src/worker/rules.rs` with output
  discipline, safety, scope, and tone sections that always inject
  into the Claude advice prompt regardless of user config.
- Dashboard Rules page redesigned: collapsible read-only "devist core"
  panel at top, single editable user textarea below. The AI generation
  flow now operates on the user layer only.

### Migrations
- `migrations/0008_drop_project_rules.sql` deletes any
  `scope LIKE 'project:%'` rows from `worker_rules`. Idempotent.

### Why
Per-project rules added cognitive load (which scope am I editing?)
without commensurate value. A few well-written global rules + the
project's own `CLAUDE.md` cover the same ground more cleanly.

## [0.11.0] - 2026-05-03

### Changed
- Daemon no longer pushes `file_changed` / `file_changed_continuous`
  events to Supabase. They remain in local SQLite (so `worker watch`
  CLI and the burst-based advice trigger keep working) but stop
  flooding the dashboard. Sync log now reads e.g.
  `[sync] pushed 0 events to Supabase (1 local-only)`.

### Migration
- `migrations/0007_drop_file_changed_events.sql` — one-shot DELETE
  of historical `file_changed*` rows from the cloud table. Idempotent.

### Why
A typical workday produced thousands of file-change rows that drowned
out the few advice items that mattered. The dashboard's "Recent
events" was essentially noise. Local SQLite is unaffected — full
fidelity stays where forensic detail is useful (the CLI).

## [0.10.0] - 2026-05-03

### Added — Per-thread daemon heartbeat
- Migration `0006_worker_heartbeat.sql` adds the table
  `(client_id, thread, last_beat_at)` with composite PK, RLS
  authenticated read, joined to supabase_realtime. Daemon writes via
  service-role.
- Each daemon thread emits a heartbeat every ~10s during its loop:
  `main` (in the watcher poll), `advice` (now uses recv_timeout so it
  beats while idle), `rules-sync`, `jobs`. Failure to write a heartbeat
  is non-fatal — best-effort.
- Thread spawns are wrapped in `panic::catch_unwind` so a panic
  surfaces as `[<thread>] thread panicked` in the log instead of
  silently leaving the PID alive while the thread is dead.
- Dashboard sidebar shows a small `DaemonStatus` widget under the
  user email: ● green if all threads beat within 30s, yellow within
  2 min, red beyond. Click expands a per-thread breakdown with the
  age in seconds. Polls every 10s.

### Why
Previously `devist worker status` only checked the PID, so a thread
crashing silently (e.g. `jobs` panic) showed as `running` while no
jobs were processed. The dashboard now surfaces the truth.

## [0.9.0] - 2026-05-03

### Added — Rules editor Phase 2 (AI assistance)
- Migration `0005_worker_jobs.sql` adds the queue table:
  `worker_jobs (id, kind, scope, input jsonb, output jsonb, status,
  error, client_id, created_at, updated_at)` with auto-touched
  `updated_at`, RLS (authenticated read + insert), and realtime.
- Daemon spawns a `jobs` worker thread that polls every 5s for
  `status='pending'` rows, atomically claims via
  `UPDATE WHERE id=X AND status='pending'`, dispatches by `kind`,
  spawns `claude -p` for `generate_rules`, writes back `output` +
  `status='done'` (or `'error'` with `error` text).
- Dashboard Rules page gains an AI assistant section:
  natural-language intent textarea → "Generate" button → INSERT
  `worker_jobs` row → realtime subscription on that row → preview
  pane with Claude's draft + explanation → "Use this draft" loads
  it into the editor (still editable before save).

### Notes
- `generate_rules` prompt asks Claude to MERGE with current content
  rather than replace, so iterating rules with successive prompts is
  additive by default.
- Realtime is the primary update path; a 4s polling fallback handles
  the case where the user reloads after submitting.

## [0.8.0] - 2026-05-03

### Added
- **Rules editor** (Phase 1: editor + sync, no AI yet).
  - Migration `0004_worker_rules.sql` adds the table + auto-touched
    `updated_at` trigger + RLS policies (authenticated read+write) +
    realtime publication.
  - Daemon spawns a `rules_sync` thread that bootstraps any local
    `rules.md` content into the table on first run, then polls the
    table every 10s and mirrors changed rows to the appropriate local
    file (global → `~/.devist/worker/rules.md`, project scope →
    `<monitor>/<name>/.devist/rules.md`).
  - Dashboard ships a `/dashboard/rules` page with scope picker
    (global + per project), textarea, save button, and a
    "last updated" relative time.
  - Daemon log tags: `[rules-sync] thread up`,
    `[rules-sync] bootstrapped <scope> from <path>`,
    `[rules-sync] wrote <path> (updated_at=...)`.

### Notes
- Table is canonical: edits made directly to local files after
  bootstrap are not pushed back. Use the dashboard or restart the
  daemon (with the table row deleted) to re-bootstrap.
- AI-assisted rule generation (Phase 2) lands later: dashboard
  describes intent in natural language → daemon spawns claude CLI
  via a `worker_jobs` queue → result returned to dashboard.

## [0.7.0] - 2026-05-03

### Added
- `devist project sync <name>` — add-only sync from the project's
  template. Walks the latest template files and copies any that don't
  already exist in the project. Existing files are never overwritten,
  so user edits are safe. Useful for catching old projects up to new
  template scaffolds (e.g. the `.claude/`, `_workspace/`, `.devist/`
  files added in the recent templates release).
- `--dry-run` flag prints what would change without writing.
- `--var key=value` overrides for rendering newly added templated files
  (mirrors `devist init`).

### Notes
- Idempotent: a second sync with no template changes is a no-op.
- This is intentionally a one-way "fast forward" for missing files
  only. A full 3-way merge (with lockfile + diff) is a separate
  feature that will land later if needed.

## [0.6.0] - 2026-05-03

### Added
- `render.rs` now supports conditional blocks:
  - `{{#if VAR}}...{{/if}}` — render when `VAR` is set and non-empty
  - `{{#unless VAR}}...{{/unless}}` — render when `VAR` is unset/empty
  - Nesting works. Inside a *skipped* branch, unknown variable references
    are tolerated (they wouldn't be reachable anyway). Active regions
    still error on unknown vars.
- `agent_mode` is a recognized template variable. `devist init` derives
  `is_devist` and `is_vibe` boolean-style vars from it (default
  `agent_mode = "devist"`). Templates can now ship a single
  `CLAUDE.md.tmpl` that conditionally renders devist-flavored or
  vibe-flavored content.
- Companion `devist-templates` release pairs every template with
  `CLAUDE.md.tmpl` + `AGENT.md.tmpl`, and adds a new `react-vite`
  template (no Supabase, pure React + Vite + TS + Tailwind v4 +
  shadcn/ui).

### Tests
- 12 render unit tests covering conditional truthy/falsy/nested cases,
  skipped-branch tolerance, unmatched/unclosed errors.

## [0.5.0] - 2026-05-03

### Security
- New `src/worker/secrets.rs` module with a 4-layer blocklist
  (filenames, prefixes, extensions, path segments). Matched paths are
  dropped at the daemon — never recorded in SQLite, never pushed to
  Supabase, never read by the advice pipeline. Defense-in-depth check
  also runs in `advice.rs::collect_snippets`.
- 7 unit tests cover dotenv family, credential files, key extensions,
  `~/.ssh` / `~/.aws` / `secrets/` segments, case-insensitivity, and
  Windows separators.

### Changed
- mem0 search query now summarizes the burst's parent dirs, filenames,
  and extensions (e.g. `"Project foo: edits in src/auth affecting
  login.tsx (tsx, ts)..."`) instead of the prior keyword-style
  `"project: foo"` which never matched stored facts.

### Added (web dashboard)
- Realtime subscription via Supabase channel (`useRealtimeWorkerEvents`).
  Inbox, Project timeline, and Overview update live on INSERT/UPDATE.
  Project timeline subscribes with a server-side `project=eq.X` filter.
- Acknowledge flow: per-row Ack button on advice rows. Acked rows
  render muted with a strikethrough title and "ACKED" badge. Inbox and
  Project timeline have a "Show acked" toggle.

### Migrations
- `migrations/0003_worker_events_realtime_and_ack.sql` — adds the table
  to `supabase_realtime` publication and creates a column-restricted
  UPDATE policy (`GRANT UPDATE (acked_at)` + RLS) so authenticated
  dashboard users can only mutate `acked_at`, not other columns.
- Fixed `migrations/0002` — replaced unsupported
  `CREATE POLICY IF NOT EXISTS` with a `DROP POLICY IF EXISTS` + create
  pattern so the file is idempotent.

## [0.4.0] - 2026-05-02

### Added
- Real Supabase L2 push (replaces the prior stub):
  - `migrations/0001_worker_events.sql` defines the table, idempotency
    index `(client_id, client_event_id)`, and RLS enable.
  - `WorkerConfig.client_id` (defaults to hostname) is the per-host
    idempotency key.
  - Daemon batch-flushes up to 500 unsynced rows every
    `sync_interval_secs`, marks them synced on success, retries on the
    next interval otherwise.
- Rules system that shapes Claude advice deterministically:
  - Global `~/.devist/worker/rules.md` and per-project
    `<monitor>/<project>/.devist/rules.md`. Both plain markdown,
    concatenated and prepended to the advice prompt.
  - `devist worker rules path|show|init [--project N]` to manage them.
  - `rules init` writes a starter template (Korean tone, focus areas,
    mem0 persistence policy).

### Changed
- Advice prompt now starts with a "User-defined rules (follow these
  strictly)" section when rules are present.

## [0.3.0] - 2026-05-02

### Changed (breaking)
- Removed `devist brief`, `devist scan`, `devist explain`, `devist watch`
  CLI commands. The underlying scanner/git helpers remain as internal
  libraries for the worker.

### Added
- `devist worker` background daemon that observes a parent folder of
  projects and records every file event into a local SQLite store
  (`~/.devist/worker/worker.db`).
  - `worker start` (with first-run setup), `worker stop`, `worker status`,
    `worker watch` (live tail), `worker config show|get|set|path`.
- AI advice generation (Phase 2):
  - Idle-burst trigger: after `advice_idle_seconds` of quiet on a
    project, the daemon spawns the `claude` CLI with the changed
    snippets and recent mem0 memories to extract facts + advice.
  - mem0 Cloud integration (`api.mem0.ai`) for long-term semantic
    memory of facts above `mem0_confidence_threshold`.
  - 4-tier guard against runaway calls: `advice_enabled` kill switch,
    `advice_min_batch`, per-project `advice_max_per_hour`, global
    `mem0_max_writes_per_hour` sliding-window limiters.
  - `worker advice [--project N] [--limit N]` lists generated advice.
  - `worker memory search <query>` for ad-hoc mem0 lookup.
- `devist doctor` now also checks the `claude` CLI.

### Notes
- The daemon writes its log to `~/.devist/worker/worker.log` and PID to
  `worker.pid`. Restart after changing config (`worker stop && start`).
- mem0 + Claude integration is opt-in: without `mem0_api_key` the worker
  silently skips advice generation; the SQLite event log still works.

## [0.2.0] - 2026-05-02

### Changed (breaking)
- Renamed CLI command `devist projects``devist project`
  (e.g. `devist project list`, `devist project forget <name>`).

### Added
- `devist start <name> --dev` now runs the template's `install` command
  (e.g. `pnpm install`) automatically when `package.json` exists but
  `node_modules` is missing, before launching the dev server.
- Release workflow publishes GitHub Releases directly (no draft step).

## [0.1.1] - 2026-05-02

### Fixed
- Release workflow now downloads SHA files via GitHub API,
  supporting draft releases.
- `cargo publish` step is idempotent — re-running on an existing
  version is treated as a non-fatal no-op.

## [0.1.0] - 2026-05-02

Initial beta release. Phase 1 through Phase 4 complete.

### Added
- Core CLI with 12 commands: `setup`, `doctor`, `about`, `template` (list/add/sync/remove),
  `projects` (list/forget), `init`, `start`, `stop`, `brief`, `scan`, `explain`, `watch`.
- Template system with `devist.toml` manifest, variable substitution via
  `*.tmpl` files, automatic discovery of single- and multi-template repos.
- Lazy backend management: only one project's `supabase`/`docker-compose`
  stack runs at a time. `start` automatically stops any other active
  project's backend.
- Code comprehension commands (`brief`, `scan`, `explain`, `watch`) for
  understanding AI-assisted codebases.
- Workspace at `~/.devist/` with `config.toml`, `registry.toml`, `state.toml`,
  and template cache.
- 7 official templates: `react-supabase`, `react-native-supabase`,
  `flutter-supabase`, `fastapi-postgres`, `nestjs-postgres`, `rust-axum`,
  `wordpress`.

### Notes
- Beta — APIs and template manifest schema may change before v1.0.
- Public Homebrew tap and crates.io publish targeted for v1.0.

[Unreleased]: https://github.com/WebchemistCorp/devist/compare/v0.17.2...HEAD
[0.17.2]: https://github.com/WebchemistCorp/devist/releases/tag/v0.17.2
[0.17.1]: https://github.com/WebchemistCorp/devist/releases/tag/v0.17.1
[0.17.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.17.0
[0.16.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.16.0
[0.15.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.15.0
[0.14.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.14.0
[0.13.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.13.0
[0.12.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.12.0
[0.11.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.11.0
[0.10.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.10.0
[0.9.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.9.0
[0.8.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.8.0
[0.7.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.7.0
[0.6.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.6.0
[0.5.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.5.0
[0.4.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.4.0
[0.3.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.3.0
[0.2.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.2.0
[0.1.1]: https://github.com/WebchemistCorp/devist/releases/tag/v0.1.1
[0.1.0]: https://github.com/WebchemistCorp/devist/releases/tag/v0.1.0