devist 0.15.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
# 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.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.15.0...HEAD
[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