dirge-agent 0.19.21

Minimalistic coding agent written in Rust, optimized for memory footprint and performance
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
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
# Changelog

All notable changes to dirge are documented here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.19.21] - 2026-07-26

### Fixed
- A pending question to the user now outranks the finalization gates (#717).
  Ask the agent something mid-task, let it reach a point where it needs your
  decision, and the critic would keep reminding it about unfinished work until
  it gave up waiting and guessed. Nothing downstream could tell a turn that
  stopped to ask from a turn that stopped because it was done — every prompt
  tells the model to clarify in prose, and the `question` tool blocks and
  resolves in-turn, so it never reaches finalization. Each gate then re-entered
  on its own budget: critic 1-3x, todo 3x, open-issues 2x.

  A turn that ends by asking now finalizes and hands control back. Detection is
  a trailing question mark on the last meaningful line, after dropping trailing
  option-list lines (so a question followed by a multiple-choice block still
  counts) and markdown decoration; an unterminated code fence is left alone.
  The goal gate is the one exception and still runs, since `--goal` is an
  explicit autonomous stop condition and there may be no user present to
  answer.

  The unfinished-todo and open-issues nudges now also require the turn to have
  edited a file. The todo count comes from a cross-turn process-global mirror,
  so a read-only Q&A turn was being nagged about stale coding todos left over
  from before the interruption.

## [0.19.20] - 2026-07-25

### Fixed
- Pre-write syntax gate (#716), four defects that between them made Lisp files
  hard or impossible to edit:
  - A raw NUL byte anywhere in a file blocked every edit to it, permanently.
    tree-sitter can't distinguish NUL from end-of-input, so the file parsed as
    truncated and the first form was flagged at a line/col unrelated to the
    edit. A NUL inside a string or regex is valid Clojure (there is no `\0`
    escape) and occurs in real code. Such content now skips the grammar and
    falls through to the delimiter scanner, which handles it correctly.
  - The mechanical delimiter repair could silently re-nest code. It appends
    the missing closers at EOF and re-validates with tree-sitter, which proves
    nothing for a Lisp — any balanced arrangement parses. A closer dropped
    mid-form was "repaired" into a file where a following top-level form had
    been swallowed by the one above it. The repair now refuses when closing at
    EOF would pull a column-1 opener inside the form being closed.
  - The delimiter hint named the outermost unclosed opener, which in a Lisp is
    almost always the enclosing top-level `defn` rather than the mistake. It
    now leads with the innermost opener and keeps the outermost as context.
  - The gate had no pre-edit baseline, so a file that already failed the check
    could not be edited at all — including files that legitimately never parse,
    such as templates with `<% %>` markers or linter fixtures. When the file
    was already broken before the edit, the gate now stands down with a warning
    instead of blocking, and does not auto-repair on top of it.

## [0.19.19] - 2026-07-24

### Added
- ACP slash commands (#714): the ACP bridge now advertises a curated set of
  slash commands to editor clients via `available_commands_update` after a
  session is created, and handles them locally instead of forwarding them to
  the model: `/help`, `/clear`, `/cd`, `/model`, and `/mode`. Command names are
  advertised without the leading `/` (the client adds that affordance).
  `/model` and `/mode` switches are session-scoped and persist across turns.
  TUI-only commands (`/panel`, `/tree`, `/fork`, …) aren't advertised because
  they have no meaning without the interactive UI; any unrecognized `/…` input
  still flows through to the model unchanged.
- `no-plugin` build feature (#712, #713): the default feature set minus
  `plugin`, for a source build that needs no C/LLVM toolchain (the `plugin`
  feature compiles Janet from C via bindgen, which needs a C compiler +
  libclang). Install with `cargo install dirge-agent --no-default-features
  --features no-plugin`. `windows-default` now aliases to it.

### Security
- Bumped russh 0.61 → 0.62.4, clearing three advisories (GHSA-5xvq-cp9x-6p6r,
  GHSA-cqjc-rmpq-xprq, GHSA-g9hv-x236-4qp3) against the SSH client used by the
  optional `sandbox-microvm` feature. The API is unchanged across the bump.

## [0.19.18] - 2026-07-23

### Added
- Subagent MCP tools (#701): an agent profile can grant its `task(agent=…)`
  subagent selected MCP tools with `subagent_mcp``all` for every connected
  MCP tool, or a list of names. Resolved against the live MCP-tool set at fork
  time (so background-loaded servers are covered) and validated against it, so
  it can only ever add real MCP tools, never a built-in past the tier cap.
  Honored on the `readonly`/`readwrite` tiers.
- `openai-responses` provider type (#703): a custom OpenAI-compatible provider
  can target the Responses API (`/v1/responses`) instead of chat/completions by
  setting `provider_type: "openai-responses"`. Uses a plain api-key bearer
  against the configured `base_url` — no OAuth/Codex login — so it works against
  any `/v1/responses` server; `allow_insecure` is honored.
- Optional `/plan` approval gate (#622): with `phased_workflow_plan_approval`
  on, the phased workflow pauses after the plan phase to approve / edit / cancel
  before any code is written. Edit takes free-form feedback and re-plans, so you
  can steer the plan before implementation. Default off (implement immediately).
- `code_mode_rubric` config flag (default off): appends a "code mode" rubric to the
  system prompt telling the model to collapse a bulk/fan-out of similar tool calls
  (roughly 10+ items) into ONE `bash` script that returns only the distilled result,
  keeping raw per-item output out of context. A/B measured on deepseek-flash with
  the reproducible harness `scripts/code-mode-ab.sh` (three scenarios). The payoff
  scales with how much naive fan-out the model would do without it: on an
  already-greppable aggregate it is ~flat (nothing to capture); on an obvious
  count task ~19% fewer input tokens; on a task that forces genuine per-file
  fan-out (two markers on different lines, no single-line grep possible) −45%
  input tokens, tool calls 8.0 → 4.5, and correctness up from 5/8 to 8/8 (scripting
  the intersection beats eyeballing 40 files). Methodology in
  `docs/code-mode-rubric.md`.

### Fixed
- Headless `-p` / `--loop` sessions now persist provider token usage. `run_print`
  dropped `AgentEvent::Usage` on the floor, so every headless session saved
  `cumulative_input_tokens = 0`, breaking `/cache` on resumed sessions and any
  token accounting off the session file. It now folds per-turn usage into the
  session like the interactive UI does.

## [0.19.17] - 2026-07-18

### Fixed
- Provider usage-cap 429s (e.g. GLM/Zhipu's 5-hour limit, error code 1308) are no
  longer retried as transient rate-limits. Their quota resets hours out while
  backoff caps at 5 minutes, so retrying only re-hit the cap, burned the retry
  budget, and killed the run mid-task. They're now classified as a non-retryable
  usage cap; headless surfaces it as a distinct, resumable outcome (envelope
  subtype `error_usage_cap`) that prints the reset time and a `--continue` hint,
  with the session already saved (#689).

## [0.19.16] - 2026-07-18

### Added
- macOS microVM sandbox backend via libkrun on Hypervisor.framework: a pure-Rust
  OCI image puller (blob digests verified, tar entries path-checked), ephemeral
  SSH host-key generation with exact host-key verification, PTY-based attach, and
  runtime codesigning of the runner with the hypervisor entitlement. See
  `docs/microvm/SETUP.md` for prerequisites. Opt-in behind the `sandbox-microvm`
  feature (#688).

## [0.19.15] - 2026-07-18

### Added
- Custom per-provider HTTP headers via `providers.<name>.headers` (a
  name → value map). A value that is exactly `${ENV_VAR}` is resolved from the
  environment; header names and values are validated before the client is built
  (#686).
- `--verbose` now logs HTTP request method/URI/status and classifies stream and
  retry errors (abort, timeout, network, auth, rate-limit), making API failures
  easier to diagnose. The logged URI has its query string stripped so a
  credential embedded there (e.g. Gemini's `?key=`) never reaches the logs
  (#685).

## [0.19.14] - 2026-07-18

### Added
- Cerebras as a first-class provider. Set `CEREBRAS_API_KEY` and select it with
  `--provider cerebras` (or a `providers.cerebras` entry); defaults to
  `gemma-4-31b` against `https://api.cerebras.ai/v1`. Reasoning effort is clamped
  to `low`/`medium`/`high`, and image input is model-specific (`gemma-4-31b`
  only). `CEREBRAS_API_KEY` is isolated from other providers (#683).

## [0.19.13] - 2026-07-17

### Fixed
- Blocking code-review mode no longer repeats the same finalization message. The
  review judge is stateless and re-read the run's diff on every finalization, so
  when the model declined a finding and changed nothing on disk the identical
  finding was re-raised and the model repeated its rebuttal. The judge now skips
  an unchanged diff (falling through to the goal/todo gates) and, on a changed
  diff, is given the prior findings so it re-raises one only when it's still
  present and the model neither fixed nor justified it (#681).

## [0.19.12] - 2026-07-17

### Fixed
- A parent turn that dispatched coordinated background subagents no longer runs
  the completion critic — or any lower "are we done?" gate — while that batch is
  still running. It waits for the batch to finish and reconcile instead of being
  judged prematurely; the turn resumes when results are deliverable (#679).
- A blank or whitespace-only `retry_of` on a `task` call is now treated as
  omitted, so a generated tool call carrying an empty retry id no longer enters
  coordinator retry validation for a nonexistent task. Real ids are trimmed and
  still validated strictly (#679).

## [0.19.11] - 2026-07-17

### Added
- `keyboard_enhancement` config (default on). Enables the terminal's enhanced
  keyboard (kitty) protocol on terminals that support it — kitty, Ghostty,
  WezTerm, foot, rio — so distinct chords like Shift+Enter reach the input
  editor instead of collapsing onto plain Enter. A no-op on terminals that
  don't advertise support; set `false` to disable.

### Changed
- Shift+Enter now inserts a newline in the input box instead of submitting, so
  you can write multi-line prompts. The newline gesture is a rebindable
  `insert_newline` command (defaults Shift+Enter, Alt+Enter, Ctrl+J) rather than
  a hardcoded key, so it can be remapped from `keybindings`. Alt+Enter and
  Ctrl+J work in every terminal; Shift+Enter needs `keyboard_enhancement`. Plain
  Enter still submits. Home/End continue to move within the current line.

## [0.19.10] - 2026-07-16

### Added
- Coordinated subagent dispatch. The `task` tool can fan out background
  subagents as a batch and deliver one reconciliation update once the whole
  batch reaches terminal state, routed through configured `readonly` /
  `readwrite` agent profiles. Read-write subagents run isolated in rooted Git
  worktrees when available; `auto` mode warns and serializes writers in the
  parent checkout when no worktree can be created. Reconciliation preserves each
  writer's branch, path, commit, dirty-state, and salvage metadata. See
  `docs/subagent-dispatch-strategy.md` (#670, resolves #660).

### Changed
- The post-turn code reviewer is now folded into the completeness critic as a
  single finalization judge. One judge call both checks the task is done and
  reviews the run's diff for defects, then re-enters the loop with one
  consolidated follow-up the agent acts on. Previously the default `advisory`
  mode ran detached and surfaced findings — even high-severity ones — as a
  display-only notice the model never saw, so a review that flagged a real bug
  right after the agent said "done" changed nothing. Now any finding re-enters
  (high/critical as must-fix, medium/low as optional notes); `advisory`
  re-enters once, `blocking` persists until the diff is clean, `off` reviews
  completeness only.

### Fixed
- `/model <id>` now routes a free-form model id to the right provider. It used
  to switch the live client only on an exact match against another provider's
  pinned `model`; any other id (a version bump, a typo, `glm-4.6`) was renamed
  on the active client and its next turn hit the wrong endpoint. Ids are now
  matched by family (`glm-*`, `deepseek*`, `claude-*`, `gemini-*`, `gpt-*`) and
  routed to a configured provider of that kind; an id whose family has no
  provider is refused with a warning instead of silently mis-routing. The
  session banner also reads the live provider/model instead of re-resolving
  from CLI/config, so a switch or resume is reflected.
- A plugin `prepare-next-run` model swap can now hop providers. The swap builds
  and installs the target provider's client in place, so a follow-up turn
  actually runs there; it no longer clobbers `session.provider` on a
  same-client rename.

## [0.19.9] - 2026-07-16

### Added
- Prompt compression. dirge compresses outgoing request bodies with a
  deterministic, no-model transform (an inlined build of llmtrim-core) before
  they reach the provider: tool-output windowing for logs/diffs/grep plus
  lossless JSON/columnar packing, guarded by a token gate that reverts any
  change that doesn't pay off and cache-zones that keep provider prompt caching
  warm. On by default for every provider; disable with `DIRGE_COMPRESSION=0` or
  `[compression] enabled = false`, or choose a profile with `[compression]
  preset`. Tool-heavy turns typically shrink ~60%.

### Fixed
- The agent no longer breaks or repeats itself on phantom tool calls. When a
  reasoning model left tool-call-shaped JSON in its answer text, the scavenger
  promoted it to a real call; if the args didn't validate, the error result
  could desync the message history into a provider 400 and a duplicated
  response. Scavenged calls are now validated before promotion and dropped when
  invalid; native tool-call errors are unchanged.
- The OpenCode provider (`opencode.ai/zen`, which proxies to DeepSeek models)
  sent the wrong reasoning-control keys — the vLLM/SGLang self-hosted keys
  (`reasoning_level`, `chat_template_kwargs`) that DeepSeek's hosted API ignores
  — so deep-thinking mode and one-shot reasoning-disable didn't take. It now
  uses `reasoning_effort` + `thinking: {type: disabled}`, matching the built-in
  DeepSeek provider (#671).

### Changed
- Work tracking nudges earlier. After the first file edit with no active todo,
  dirge injects a model-visible reminder to `write_todo_list` and mark the item
  in_progress, instead of only a user-facing notice at the end of the turn.

## [0.19.8] - 2026-07-15

### Changed
- Issues and todos are now distinct. Creating an issue files it to a passive
  backlog (unassigned) instead of the active work queue, so filing something
  for later no longer trips the finish-your-work nudge (the loop the model got
  stuck in when you asked it to "add an issue for X"). `issue start` claims a
  backlog item onto your active queue; `write_todo_list` still writes active
  work. The turn-start reminder is split into an "Active work queue" section
  (with a "Currently in progress" callout) and a "Backlog" section, so the
  model has a clear current task each turn (#668).
- Issue ids are now beads-style hashes (`drg-a1b2`) instead of integers.
  Existing issue databases migrate on first open.

### Added
- Issues can be grouped under an epic: `issue create epic=<id>` files under a
  parent, and `issue show <id>` lists an epic's children.
- An advisory nudge when the model edits files without any tracked todo, so
  active work reliably lands on the list.

### Fixed
- Restating a todo as completed with different casing or spacing now closes the
  existing item instead of leaving the finished task stuck on the board behind
  a duplicate.

## [0.19.7] - 2026-07-14

### Fixed
- LSP servers (rust-analyzer and friends), MCP servers, DAP adapters, and
  background shells were orphaned when dirge itself was killed by a signal —
  SIGTERM (`kill`), SIGHUP (terminal or tab closed), or SIGINT. They are
  spawned with `setsid` so terminal-delivered signals never reach them, and
  the `kill(-pgid)` that reaps them only runs from a guard's `Drop`, which a
  signal exit skips. A leaked rust-analyzer kept indexing the workspace and
  held 1 GB+ of RAM. dirge now tracks every detached child process group and,
  on SIGINT/SIGTERM/SIGHUP, kills them all, restores the terminal, and exits
  (dirge-6klk).
- LSP servers were SIGKILLed on shutdown without the `shutdown`/`exit`
  handshake, so they never got to flush or persist state. dirge now sends the
  handshake on the normal teardown path, falling back to the group kill
  (dirge-8m69).

## [0.19.6] - 2026-07-14

### Added
- `animations_enabled` config toggle to turn off UI animations (#664).

### Fixed
- The TODOS panel went empty after a compaction fold or a resume and did not
  come back when the agent picked an existing issue up. It was scoped to the
  live `session.id`, which a fold rotates, so the board query stopped matching
  the rows it had stamped under the old id; and starting an issue created in
  another session never pulled it onto the current board. The board is now
  scoped by the stable lineage origin (so it survives folds/resumes), and
  starting an issue (`issue start` / an update to `in_progress`) claims it for
  the current conversation so a picked-up issue appears (GH #663).
- Redacted secrets stayed searchable in the session transcript index: the v6
  FTS redaction rebuild cleared the external-content index with a plain
  `DELETE`, which left phantom postings, so secrets in folded `tool_calls`
  remained matchable. It now uses the FTS5 `'delete-all'` command
  (dirge-vpma.4).
- Opening the composer in an external editor (Ctrl+G) destroyed text and image
  pastes held in the buffer; they are preserved and re-attached now
  (dirge-vpma.5).
- A corrupt project `config.json` could be rewritten with only the sandbox
  keys, dropping the rest of the configuration (dirge-vpma.6).
- Resizing the terminal could wipe a background subagent's transcript because
  inactive-chat writes skipped their source buffer (dirge-vpma.7).
- Setting one DAP breakpoint replaced the file's whole breakpoint set (DAP
  replace semantics), so adding or removing one dropped the rest; incoming
  breakpoints now merge with the cached set (dirge-vpma.12).
- `--loop-max N` ran N-1 iterations (and zero for `N=1`) (dirge-vpma.15).
- Ctrl+K killed to the end of the whole buffer instead of the end of the line
  (dirge-vpma.16).
- Deleting a session removed only a single file, leaving fold-chain rotations
  resumable; the whole lineage is removed now (dirge-vpma.13).
- Three P1 crash / data-loss bugs: a shell-exit drain race could start a second
  agent run; restoring after removing a chat could overwrite surviving history;
  and the checkpoint-reuse fold spliced snapshots at the wrong index (#665,
  dirge-vpma.1/.2/.3).
- Further Wavescope entropy-audit correctness fixes across the compaction hook
  path, stream-abort racing, plugin session adoption, and rewind bucketing
  (dirge-vpma.8/.9/.10/.11/.14/.19).
- External-editor buffers now open with the markdown filetype (#662).

### Changed
- The TODOS panel now marks the issue the agent is actively on: the
  `in_progress` item is pinned at the top (it already sorted first) with a ``
  marker and a distinct focus color, so the current task stands out from the
  queued work. The panel still mirrors this session's live issue board; use
  `/issues` for the full project board (GH #663).
- Project-scoped `.dirge/plugins/`, `.dirge/config.json`, `.dirge/prompts/`,
  and `.dirge/agents/` are now resolved at the project root — the enclosing
  git repository, or `DIRGE_PROJECT_ROOT` when set — instead of the launch
  directory. Previously these four looked only in `<cwd>/.dirge/`, so starting
  dirge from a subdirectory of a repo silently loaded none of them, even
  though the session database and per-project memory already anchored at the
  repo root. Launching in `<repo>/sub/` now loads `<repo>/.dirge/` config,
  plugins, prompts, and agent profiles, matching where sessions and memory
  live. Skills already walked up the ancestor chain (merging inner-over-outer),
  so their behavior is unchanged (dirge-vpma.17).

## [0.19.5] - 2026-07-13

### Fixed
- AltGr-composed characters (`@ # [ ] { }` on the Italian, German, Spanish, …
  layouts) could not be typed or pasted into the input box on Windows. Windows
  reports AltGr as Ctrl+Alt, so those keystrokes arrived with both modifiers
  set and the editor's text-insertion path — which ignored anything Ctrl- or
  Alt-modified — dropped them. Pasting lost the same characters because the
  Windows console backend delivers a paste as synthesized keystrokes. `@`
  needing AltGr also meant the `@`-file picker could never open. The editor now
  folds an AltGr-composed printable character back to plain text before
  dispatch; real Ctrl/Alt keybindings are unaffected (GH #659).
- The input box was unreadable on a light terminal: the composer text is white
  and relied on the theme's dark background fill, which `plain` (and any
  light/`reset` background) doesn't paint, so it vanished against a light
  terminal. The input box now paints its own dark surface (`input_bg`, default
  `#222222` on both presets) over the background fill, keeping it a dark field
  regardless of the terminal theme. Themeable via `input_bg` in a custom theme;
  set `"input_bg": "reset"` to opt out (GH #628).

## [0.19.4] - 2026-07-09

### Fixed
- A transient transport error ("error decoding response body", network blip,
  rate-limit) arriving after the model had already streamed content killed the
  whole run: the streamed partial was erased from the transcript (the turn
  finalized with empty content), the run tore down to idle, and any steering
  queued mid-run was dropped. The stream layer now preserves the last streamed
  partial (text + thinking, with incomplete tool-call blocks stripped so they
  don't orphan the `tool_use`), and the run loop treats a transient error as
  recoverable — the partial stays in the transcript, a continue nudge drives
  the next turn, a retry banner surfaces, and queued steering is delivered.
  Bounded by three consecutive recoveries; explicit cancel and non-transient
  errors (auth, context-length) still terminate as before (#626).

## [0.19.3] - 2026-07-08

### Added
- Opt-in desktop notifications on macOS, Linux, and Windows, backed by
  `notify-rust`: a notification banner on macOS, a freedesktop D-Bus
  notification on Linux (pure-Rust `zbus`, no libdbus dependency; needs a
  running notification daemon), and a WinRT toast on Windows. Enable with
  `desktop_notifications.enabled`; notifies on run completion and when a
  permission prompt, question, or plugin dialog is waiting for input. Extends
  the macOS-only backend from #611 to all three platforms (GH #594).

### Fixed
- Background review left the avatar showing the idle `(^_^)` face while the
  runner was still busy (the `/plan` reviewer or a plugin hook chain keeps
  `is_running` true after a turn's visible output ends). Since `is_running`
  also routes a typed message to send-vs-queue, messages typed against the
  idle-looking avatar were queued behind the busy runner and could be dropped.
  The idle face is now deferred until the turn actually settles idle, so the
  indicator matches the real run state (dirge-79ue, GH #621).
- Three `cargo audit` advisories in the dependency graph: `anyhow`
  (RUSTSEC-2026-0190), `crossbeam-epoch` (RUSTSEC-2026-0204, via an `ignore`
  pin), and `quinn-proto` (RUSTSEC-2026-0185) bumped to fixed versions (#623).

## [0.19.2] - 2026-07-08

### Fixed
- `cargo install dirge-agent` failed to compile against rig. rig ships
  breaking API changes in patch releases (0.37.1 added a required
  `Text.additional_params` field), and `cargo install` resolves without the
  lockfile, so the caret dependency drifted onto an incompatible rig. rig and
  rig-core are now pinned to an exact version so published installs build
  against the rig dirge was tested with (dirge-omgq, GH #616).
- `dirge auth openai` (or `dirge auth anthropic`) alone wasn't enough to
  launch dirge: provider selection consulted only `--provider`/config and
  API-key env vars before defaulting to OpenRouter, so a user who logged in
  via OAuth but set no env key was still asked for an OpenRouter key. Provider
  resolution now falls back to a stored `dirge auth` login before the
  OpenRouter default (dirge-ppie, GH #617).

## [0.19.1] - 2026-07-07

### Fixed
- Slow startup / laggy rendering on terminals that echo focus events (e.g.
  Ghostty). Such terminals reply with a `FocusGained` whenever focus reporting
  (`?1004h`) is enabled; dirge's `FocusGained` handler re-armed the terminal
  modes — including `?1004h` — unthrottled, so the reply drove an unbounded
  re-arm → echo → re-arm loop that saturated the UI loop and delayed output
  (MCP server logs could take ~a minute to appear). The mode-only re-assert is
  now throttled the same way the full re-assert already was. Terminals that
  don't echo focus (e.g. iTerm2) were unaffected either way (dirge-np9o).

## [0.19.0] - 2026-07-07

### Added
- Paste a clipboard image into the prompt (Ctrl+V) and send it to a
  multimodal provider. User messages are now multipart, so a turn can
  interleave text and images. Images are stored once under the session's
  `assets/` dir and re-read at the provider boundary each turn they stay
  in context, keeping transcripts small. The paste UX is gated by whether
  the active provider/model supports vision (with a `multimodal` override
  on the provider entry for local vision models). Clipboard capture uses
  the platform's built-in scripting host — `osascript` on macOS,
  PowerShell on Windows — or `wl-paste`/`xclip` on Linux; no image on the
  clipboard falls back to a normal text paste.

### Fixed
- A caption-less image paste (image + Enter, no text) no longer aborts the
  turn — the empty text part ahead of the image was serializing to an empty
  text content block that Anthropic rejects with a 400. Empty text parts are
  now dropped at the provider boundary and the seed.
- Pasted images no longer drop out of context on continuation, interject,
  retry, plan-review, and compaction-resume turns; those paths were replaying
  history without the session asset dir, degrading each image to a placeholder.
- DeepSeek vision models (`deepseek-vl*`) are no longer misclassified as
  text-only, so the image-paste UX is offered for them.

## [0.18.13] - 2026-07-07

### Fixed
- Render-loop CPU waste (three fixes from a repaint-loop audit):
  - A no-op or duplicate terminal resize no longer triggers a full scrollback
    re-render. crossterm — and terminals that fire a resize event on focus and
    other non-size changes — emit resizes with unchanged dimensions; each was
    doing a full markdown re-parse + re-wrap of the whole scrollback. Resizes
    now carry the new dimensions and rebuild only when the size actually
    changed (dirge-8p0h).
  - The terminal size is cached instead of re-`open()`ing `/dev/tty` ~8× per
    paint (via panel visibility / width / layout probes). It's refreshed at the
    top of each paint and on resize — the size only changes on resize
    (dirge-jisr).
  - Ambient panel data (session tokens, git, tool activity) is recomputed at
    most every 100ms instead of on every event-loop iteration; during token
    streaming the loop wakes 50–200×/s, so the per-token recompute was pure
    waste. Keystrokes, paints, and the input editor are unchanged (dirge-b14h).

## [0.18.12] - 2026-07-07

### Fixed
- Continuous TUI strobe on gnome-terminal / VTE 0.76 (Linux). The `FocusGained`
  recovery re-entered the alternate screen (`?1049h`), which re-enters *and
  clears* it — and on VTE, processing `?1049h` emits a synthetic `FocusGained`
  as a side effect, so focus-in fed itself into a strobe (and flashed on every
  alt-tab even after the 0.18.11 throttle bounded the loop). dirge never leaves
  the alt screen on a focus change, so re-entry was unnecessary; the focus-in
  recovery is now mode-only — it re-arms mouse capture, bracketed paste, and
  focus reporting without `?1049h` or a screen clear, then repaints. The full
  clear-and-re-enter recovery remains bound to the manual `Ctrl+L` hatch
  (dirge-1f2a). Reported against gnome-terminal 3.52 / VTE 0.76.

## [0.18.11] - 2026-07-07

### Fixed
- Throttle the full terminal re-assert to break a FocusGained feedback loop. On
  terminals that echo a focus event when the re-assert escape sequence is sent,
  the `FocusGained → force_terminal_reassert → …` recovery could re-trigger
  itself in a tight loop — rebuilding the ratatui backend, writing to
  `/dev/tty`, and dirtying a frame every iteration — spinning the event loop and
  causing visible jank. `force_terminal_reassert` now no-ops if it fired within
  the last 500ms, which is imperceptible for a genuine refocus or Ctrl+L but
  stops the loop. Thanks @allen-munsch (#606).

## [0.18.10] - 2026-07-06

### Fixed
- Mouse capture and text selection could stay dead until a manual `Ctrl+L`
  after an external terminal reset (a terminal `reset`, a tmux/screen
  detach+reattach, or a multiplexer that drops private modes). The automatic
  recovery is event-driven (`FocusGained` re-asserts the terminal modes), but
  that event only fires while focus reporting (`?1004`) is armed, and the
  periodic self-heal re-armed mouse + paste but not focus reporting — so once
  `?1004` was dropped the recovery went dark. The periodic reassert now also
  re-arms `?1004`, so focus reporting self-heals within one interval and the
  recovery keeps working (dirge-tc2q follow-up).

## [0.18.9] - 2026-07-06

### Fixed
- Delimiter auto-repair now handles an over-close, not just an under-close. The
  pre-write syntax gate already appended missing closers for a trailing
  truncation; it now also mechanically removes a trailing run of extra closing
  delimiters (an extra `)`/`]`/`}` at EOF) and re-validates. A mid-file stray
  closer is still rejected with its exact line:col, since removing it could
  change what the following forms belong to. This stops the model from dropping
  into hand-counting parentheses to fix an off-by-one imbalance. The DeepSeek
  steering prompt also now directs the model to create/modify source with
  `write`/`edit` (which validate and localize delimiter errors) rather than
  assembling files in a shell here-doc (dirge-1m36).

## [0.18.8] - 2026-07-06

### Added
- Prompt-injection scanning of untrusted tool results (file reads, MCP, web
  search). Detects role-override, summarisation-survival (instructions crafted
  to persist through compaction), link-exfiltration, and invisible-Unicode /
  Unicode-tag-block smuggling. Advisory by default (flagged content is fenced
  as untrusted data); opt-in hard-block via the `injection_scan` config
  (`off`/`advisory`/`block`). Read-scanning matches only the prompt-injection
  patterns, so ordinary source is not fenced (dirge-5ig9).
- Critic `ABSTAIN` verdict: when the spec and evidence don't let the critic
  establish correctness, it now asks the model to add a focused test (or state
  the missing detail) rather than false-passing or wrongly claiming the work is
  unfinished (dirge-ahyh).
- Opt-in open-issues finalization gate: nudges when this session left issues
  open, via the existing issue store (session-scoped, not the global backlog).
  Config `open_issues_gate` (`off`/`advisory`/`blocking`, default off); the
  blocking mode is bounded so it can't trap the loop (dirge-ksjl).
- Recurrence-weighted memory salience graduation: when the same learning has
  been stored as near-duplicate entries, the curator boosts the representative
  entry's salience so it's retained and surfaced. Non-destructive (nothing is
  merged or deleted) and recorded in a ledger so a cluster graduates once.
  Config `memory_graduation` (default on) (dirge-4nix).

### Changed
- Internal: `CodeReviewMode` generalized to a reusable `GateMode` primitive
  shared by the finalization gates (dirge-hsvw).

## [0.18.7] - 2026-07-06

### Fixed
- DeepSeek/GLM reasoning was not being controlled as intended, verified against
  the live hosted APIs. The tool-less one-shots (summarizer, critic, approval
  evaluator) tried to disable reasoning with `chat_template_kwargs` — which the
  hosted DeepSeek and GLM APIs silently ignore, so those calls kept reasoning
  and paid the latency. They now send `thinking:{type:"disabled"}`. And DeepSeek
  reasoning-effort was sent in the nested `reasoning:{effort}` shape it doesn't
  honor; it's now sent top-level as `reasoning_effort` (which it does honor) and
  can reach DeepSeek's `"max"` tier at the highest thinking level (dirge-r9k8,
  dirge-f1su).

### Changed
- Internal: per-provider reasoning wire tuning (enable + disable shapes, effort
  maps) is consolidated into a single `provider::adapter` module, so adding or
  retuning a provider's reasoning is a one-line change instead of edits across
  two files. Behavior-preserving (dirge-md5d).

## [0.18.6] - 2026-07-06

### Fixed
- Question modal: in a multi-select question that allows a custom answer, you
  couldn't submit once you'd typed one — Enter re-opened the text editor
  instead of confirming, and Space did nothing on the `(custom)` row. Enter now
  confirms once custom text exists; Space (re)opens the editor to edit the
  answer in place; the footer shows `Space edit` on the custom row (dirge-72h2).

### Changed
- `review` and `review-security` prompts no longer deny the whole `bash` tool.
  A whole-tool `bash` deny is terminal and pre-empted the default rules that
  already allow read-only git, so the reviewer couldn't even run `git diff` /
  `git log` to inspect the change under review. `bash` now flows through the
  normal permission engine: read-only git and other pre-trusted commands are
  allowed, while effectful/destructive commands (`git push`, `rm`, `curl`, …)
  still prompt. `plan` mode keeps its full read-only lock (dirge-k265).

## [0.18.5] - 2026-07-06

### Added
- External editor for composing messages: `Ctrl+G` or `/edit` opens `$EDITOR`
  with the current input buffer and replaces it on save. Thanks @blob42 (#592).
- Opt-in editor follow-along: set `editor_open_command` (a `{path}`/`{line}`
  template, e.g. `zed {path}:{line}` or `code --goto {path}:{line}`) and dirge
  opens the file it's reading/editing in your GUI editor — detached and
  non-blocking, so the editor follows along like Zed's AI panel. Off by
  default; deduped so repeat reads don't spawn a burst (#572).

## [0.18.4] - 2026-07-05

### Fixed
- The agent no longer silently halts after a failed tool call. When the model's
  last action was a rejected/errored tool call and it then stopped with a
  text-only reply, a deterministic nudge now re-prompts it to complete the step
  (or explain why it can't) instead of waiting for the user to say "continue".
  Bounded and self-limiting — it only fires when a tool-error immediately
  precedes the stopped turn, so it can't loop, and runs before the LLM critic
  so obvious failures are handled without a judge call. Ambiguous "is it
  actually done?" cases remain the critic's job (dirge-rwru).

## [0.18.3] - 2026-07-04

### Changed
- Default working-context budget (`context_target`) raised from 100k to **250k**
  tokens. Context quality degrades gradually past ~100k rather than falling off
  a cliff, and capable newer models (DeepSeek V4, Claude Opus 4.x, Gemini) hold
  up well into the mid-hundreds of thousands — so a flat 100k cap left usable
  range on the table. The effective window is still `min(model_window,
  context_target)`, so smaller models are unaffected; set `context_target`
  lower (e.g. `100000`) for small local models or cost-sensitive routes. Thanks
  @gretel (#585).

## [0.18.2] - 2026-07-04

### Added
- `DIRGE_DUMP_REQUESTS` request-dump lines now carry the `provider` and `model`
  each request went to, plus `messages_bytes` for the conversation history —
  so when debugging multi-provider or mid-turn side-completion behavior you can
  see which backend served each call, not just the byte sizes. `=1` logs the
  summary line, `=full` also logs the prompt body; off by default, emitted at
  INFO on `dirge::wire` (dirge-iis0).

### Fixed
- Tool chambers now re-box to the terminal width on resize, like the rest of
  the scrollback. Previously a chamber laid out at a wide width stayed that
  width (and clipped) after narrowing. The whole chamber — top border, body,
  colorized diffs, LSP-tail rows, and bottom border — reflows together, so the
  box never ends up with a mismatched header (dirge-ghpf).
- Permission prompt no longer hides part of a long or multi-line command. The
  alert box now scrolls: the command detail can be paged with ↑/↓, PgUp/PgDn,
  or Ctrl+O while the `[y]/[a]/[n]/[ESC]` action row stays pinned, and a status
  line shows how much is off-screen. Previously a tall command was cut with a
  bare `` and the modal swallowed scroll keys, so you had to approve a `bash`
  command you couldn't fully read (#587).

## [0.18.1] - 2026-07-04

### Fixed
- Mouse/selection breaking after switching away from and back to the terminal
  window now recovers automatically. Focus reporting is enabled, and on
  focus-in dirge re-asserts the terminal modes (re-enter the alternate screen,
  mouse capture, bracketed paste) wrapped in a synchronized update, so the alt
  screen is restored the instant the window regains focus — no keypress. The
  wheel-scrolls-native-scrollback / dead-selection state that used to require a
  manual Ctrl+L now heals itself. Ctrl+L remains as a manual backstop.

## [0.18.0] - 2026-07-04

Three focused changes on top of 0.17.0: the diff-aware code reviewer is now
configurable and non-blocking by default, a terminal-recovery escape hatch,
and a new provider.

### Added
- `code_review` config (`off` | `advisory` | `blocking`, default `advisory`)
  plus a per-prompt `code_review` front-matter override, controlling how the
  diff-aware reviewer engages. Advisory runs the review in the background after
  a turn and surfaces all findings (high/critical included) as one non-blocking
  `<system>` notice; blocking is the previous synchronous behavior (re-enters
  the loop on high/critical); off disarms it entirely — no diff capture, no
  judge call. Still requires `critic_provider`.
- OpenCode provider — `--provider opencode` (the opencode.ai zen endpoint,
  default model `deepseek-v4-flash`). Thanks @gretel.
- Ctrl+L forces a full terminal redraw: re-enter the alternate screen,
  re-enable mouse capture and bracketed paste, and repaint. Recovers a session
  that was dropped to the main screen — mouse wheel scrolling the native
  scrollback (the whole TUI scrolls off) and selection no longer being
  captured, while the keyboard still works.

### Changed
- The diff-aware code reviewer no longer blocks the turn by default. It now
  runs in the background (advisory mode) and reports findings as a non-blocking
  notice instead of re-entering the loop and spending a react budget, so a
  tight back-and-forth debug loop isn't held up waiting on a review. Set
  `code_review = blocking` to restore the previous synchronous, re-entering
  behavior.

## [0.17.0] - 2026-07-03

A large security- and correctness-hardening release: the findings from a
multi-round internal audit (rounds R1–R8) plus follow-up remediation. Almost
all of it is bug fixes, robustness, and behavior-preserving refactors; a few
user-visible behaviors changed for the better (below). No breaking config or
CLI changes.

### Added
- `timeouts.request_establish_secs` (default 300) bounds the request-establish
  phase — the connection/handshake and wait for the first response event — so a
  stalled connection can't hang a run indefinitely. It sits alongside the other
  named `timeouts.*` keys and retries as a transient network error.

### Changed
- An explicit model choice under a ChatGPT/Codex login is now honored. Previously
  `--model gpt-4o` (or `/model gpt-4o`) was silently rewritten to the Codex
  subscription default; the explicit-vs-default distinction is now resolved once,
  up front, and stored on the session — so it survives resume too.
- `--no-color` now collapses the *entire* TUI (chat, side panels, frames, tool
  output), not just themed text. Color is stripped at the paint chokepoints, so
  the ~100 raw color literals that previously leaked are covered.
- `edit_lines`' staleness hash is now coupled to each line's predecessor. A
  single line drifting perturbs two adjacent hashes, so slipping a stale edit
  past the guard needs two independent collisions (~1/16.7M instead of ~1/4096)
  — with no extra tokens. The first line, and hashes for unchanged regions, are
  unaffected.
- Typing while scrolled up in the chat log no longer jumps you to the bottom —
  you can read back through history while composing. Press Down (when scrolled
  up) to return to the newest content.
- Restored `harness/log` as a working plugin debug sink (drains to the host log
  under `--verbose`/`RUST_LOG`); it had regressed to a no-op.

### Fixed
- **Auth & providers.** OAuth transport, PKCE state, and refresh-race hardening;
  a ChatGPT/Codex token-rotation TOCTOU that could freeze an expired bearer for a
  whole session; the escalation route now runs under the retry policy; retry
  backoff observes cancellation promptly instead of waiting out the full delay.
- **Windows.** Path resolution no longer leaks `\\?\` verbatim prefixes, and a
  brand-new deep file path stays verbatim past MAX_PATH so writes don't fail on
  machines without the long-path opt-in.
- **Compaction & context.** Keep-recent is clamped to half the window on
  small-context models; token totals are recomputed after a fold instead of
  applying a cross-accounting delta; discovery-anchor, overview-eviction, and
  duplicate-reasoning fixes; a fold→persist→resume round-trip is now covered by
  tests.
- **Debugger & language servers.** DAP pause-vs-continue locking, attach status,
  and stale stop events; `continue_` is guarded against session replacement while
  parked. The LSP and DAP clients now share one JSON-RPC correlation core, so the
  drain-on-close fix lives in one place.
- **File mutation.** BOM handling, mixed line endings, non-UTF-8 refusal, and
  correct error propagation from `apply_patch` / result relay.
- **Plugins.** Multi-line steering/followup messages are escaped (no longer
  shredded); a per-process error sentinel prevents a plugin result that looks
  like an internal error marker from being dropped; the renderer registry uses
  the shared escaped format; deny-tools names are escaped before Janet
  interpolation.
- **Skills.** Create/register are transactional; archive failures are logged, not
  swallowed; recovered file skills reactivate on re-register; a force-deleted
  pinned skill no longer leaves a ghost active row.
- **MCP.** The process-group guard is disarmed on the success path (pid-reuse
  race); a delegated child is killed on cancellation instead of orphaned.
- **Sessions, CLI & slash.** Warn on a stale resume for `-c`/`-r`; refuse to start
  on an invalid `permission` config instead of silently dropping all rules;
  `/issues search` treats `%`/`_` as literals; `/loop start` no longer leaks the
  `start` verb into the prompt; `/graph` search stops leaking flags into the FTS
  query; `/wt-merge` / `/wt-exit` handle `:` in paths; `/model` no longer
  mislabels the provider on a same-provider swap; a forbidden `!` command hidden
  behind a `VAR=value` prefix is caught.
- **TUI.** Panic hook that restores the terminal; width-aware (double-width-glyph)
  wrapping; a non-blocking plugin shortcut; the side panels no longer reserve a
  blank right gutter at the show threshold.

### Internal
- Behavior-preserving refactors that removed duplication behind several of the
  above fixes: one shared content-guard module, one judge-gate truncation +
  fail-open wrapper, one agent-rebuild helper, one user-boundary cut-snapping
  helper, a typed `SlashOutcome` replacing the `DEFER_*` error-string protocol,
  and the shared JSON-RPC correlation layer.

## [0.16.0] - 2026-07-01

### Added
- **Diff-aware code reviewer.** A new finalization gate reviews the actual diff a
  run produced (not just the transcript) and surfaces severity-ranked findings.
  It runs two passes — review, then a verify/dedupe pass that drops false
  positives — and splits the results: high/critical findings re-enter the loop
  (fix or justify), medium/low surface as non-blocking advisories. Also runnable
  on demand with `/code-review`. It reuses the `critic_provider` judge, so it's
  the same opt-in as the critic with no cost when off. Prompt craft and the
  finding/verdict model are ported from [roborev]https://go.kenn.io/roborev.

## [0.15.0] - 2026-07-01

### Added
- **Reusable skill learning with salience.** Skills now carry the same salience
  machinery as memory. `/learn` distills a reusable skill from any source — a
  directory, a URL, pasted notes, or the current conversation (bare `/learn`) —
  by running one standards-guided turn with the agent's own tools (`read`,
  `grep`, `find_files`, `webfetch`) and saving through the `skill` tool; there's
  no separate distillation engine. Skill telemetry (use/view/patch counts,
  provenance, success/failure record) moves from the `.usage.json` sidecar into
  the project's SQLite database, and the system-prompt skill list is ordered by
  effective salience so the most useful skills surface first. (#557)
- **Verification gate.** Creating a skill now requires a `## Verification`
  section — a single command that proves the skill works — and a freshly learned
  skill is seeded one grounding success, since it was validated in the session
  that produced it. (#557)

### Changed
- **Skill curation is salience-driven, not age-based.** The old
  active/stale/archived state machine is replaced: the curator decays
  unconsulted agent-created skills and archives those whose effective salience
  (decay folded with a proven success/failure record and confidence) falls to
  the archival threshold. A skill that keeps working survives on its track
  record even when untouched; pinned skills and skills you didn't author are
  never auto-archived. The `.usage.json` sidecar is retired. (#557)

## [0.14.2] - 2026-06-30

### Added
- **[AGENTS] left-panel box.** A fourth box below [GIT] lists the running
  subagents by profile name. When two subagents share a profile the name alone
  is ambiguous, so each row appends its `id_short` (e.g. `architect aaa111`);
  the unnamed-agent fallback shows just the `id_short`. Real subagent data is
  threaded through `LeftPanelInfo`, and the old separate subagent region
  collapses into the vitals card. (#553, #554)

### Changed
- **Slash commands have a single source of truth.** The parallel name-only and
  (name, description) lists are merged into one `slash_commands()`; tab
  completion / `is_known_slash_command` and the `/help` render both derive from
  it, so adding a command is one list entry plus one match arm instead of three
  synchronized edits. name↔description drift is now structurally impossible
  (a no-duplicate-names guard replaces the old drift test); `/help` renders
  "name  description". (#553)
- **Critic scoped or disabled for read-only and design prompts.** The built-in
  critic is tuned for coding mode, where it checks that code, tests, and
  verification all landed. In the read-only/design prompts every mutating tool
  is denied, so it systematically false-positived — blocking turns to demand
  builds or runs the denylist makes impossible. `ask`, `plan`, and
  `write-prompt` keep the critic with a scoped preamble that judges only the
  actual deliverable (answer completeness, plan actionability, prompt-contract
  conformance); `brainstorm`, `review`, and `review-security` set
  `critic: false`. Default coding mode is unchanged. (#549)

### Fixed
- **No duplicate output after a mid-response provider stall.** 0.14.0 (#547)
  made stream-chunk timeouts retryable even after text had committed, but the
  retry reset only clears the message history — not text already rendered — so
  the second attempt re-streamed the whole response and appended a duplicate
  copy. Retry is gated on `!committed` again; the pre-commit mid-assembly-stall
  case (#545) still retries. Also narrows the "stuck in a long reasoning loop"
  nudge so it no longer mis-fires on plain transport stream-chunk timeouts, and
  corrects the now-inaccurate "retried automatically" wording in the timeout
  error message and docs/config.md. (#552)

### Documentation
- **Building with newer libclang.** README notes the Janet build failure with
  newer libclang and a documented workaround for pointing at a compatible
  libclang. (#548)

## [0.14.1] - 2026-06-29

### Fixed
- **Fix the `x86_64-unknown-linux-musl` build** (broken in 0.14.0). The new PTY
  bang-command code cast `TIOCSCTTY` to `c_ulong` for the `ioctl` request arg,
  which only matches glibc/macOS — musl declares that arg as `c_int`, so the
  musl release binary (and `cargo install` on musl) failed to compile. Use
  `as _` so each target infers the right width. (No behavior change on other
  platforms.)

## [0.14.0] - 2026-06-29

### Added
- **`!`/`!!` bang commands run on a real PTY.** They reuse the `/sandbox` attach
  path — suspend the TUI, attach the command to `/dev/tty`, relay I/O, resume —
  so commands that need terminal input (`gh auth login`, editors, interactive
  prompts) work instead of hanging to the 120s timeout. Interactive output
  renders through a vt100 screen parser, so cursor-moving TUIs (arrow-key menus)
  update in place rather than stacking redraws; the avatar stays idle while you
  drive the shell. (#544, #546)
- **`/prompt <name> <text>` switches *and* runs the text.** Previously everything
  after the prompt name was silently dropped; it now switches to the named
  prompt and launches a streamed turn on the trailing text (via a
  `DEFER_PROMPT_RUN` sentinel, gated on the name resolving). (#538)
- **Clipboard "Copied!" tooltip** in the chat area, bridging the lack of native
  terminal copy feedback. (#542)
- **CI clippy gate** — clippy runs with `-D warnings` and the lint backlog was
  cleared across all feature builds. (#540)

### Changed
- **`write_todo_list` is backed by the issue board.** The TODOS panel and the
  end-of-turn nudge were driven by a separate in-memory checklist; they now share
  the durable issue tracker — a todo *is* an issue. Bulk planning gains the full
  lifecycle (open/in_progress/blocked/done/cancelled), items match by title
  across calls (scoped to the session), and omitted items are no longer silently
  dropped (close one by restating it completed/cancelled). (#539)

### Fixed
- **Failed MCP servers are visible in the info panel.** A server that failed its
  initial connect was invisible (rendered as `(none)`); it now shows as broken
  (``), matching how LSP surfaces broken servers. The live connection is still
  dropped, so `/mcp reconnect` keeps working. (#541)
- **Stream retries on a mid-tool-call chunk timeout.** A chunk timeout that fired
  while a tool call was mid-assembly halted the run — prior thinking/text had
  marked the attempt "committed" and the retry layer refused to replay it. Timeout
  errors now retry even after content commits, so a single provider stall no
  longer kills a run on reasoning models that emit thinking before a tool call.
  (#547)
- **Agent construction can't wedge on a stuck DB.** The memory, global-memory,
  and spec-store loads in `build_agent_inner` are now bounded by a 5s timeout
  (graceful degradation on timeout), so a locked/slow SQLite no longer hangs
  agent builds — a contributor to the `/prompt`-rebuild hang.

## [0.13.9] - 2026-06-28

### Changed
- **The `issue` tool is auto-allowed by default.** It's now classified as a
  builtin-allowed meta operation (like `write_todo_list`), so the agent records
  its own work (create/start/block/close/update) without a permission prompt
  each time — the tracker is a local, user-viewable (`/issues`), reversible DB,
  so the prompts were friction without security value. Still overridable via an
  explicit deny rule. (#537)

## [0.13.8] - 2026-06-28

### Added
- **Steerable critic preamble.** The in-loop critic's system preamble was
  hardcoded; it's now exposable at two tiers — a global `critic_preamble` in
  config (`resolve_critic_preamble()`) and a per-prompt frontmatter
  `critic_preamble:` (inline or a YAML block scalar; empty inherits). A
  `critic: false` frontmatter suppresses the critic for that prompt only. See
  [docs/prompts.md]docs/prompts.md. (e0f684a)

### Changed
- **Goal gate decoupled from the critic.** They previously shared one judge
  closure (and preamble), so a critic override or `critic: false` leaked into
  goal judgements. `build_critic_fn` is generalized to a `build_judge_fn` that
  bakes an independent preamble; the critic and the `--goal` gate now share a
  client but judge under separate preambles, and the gate always uses its own
  fixed `GOAL_PREAMBLE`. `CRITIC_FORMAT` and `GOAL_PREAMBLE` remain
  non-overridable by design. (e0f684a)

## [0.13.7] - 2026-06-27

### Fixed
- **`/model <id>` switches providers, not just the model name.** The `/model`
  list shows one row per configured provider's pinned model; selecting a model
  that belongs to a *different* provider now rebuilds the live client for that
  provider instead of sending its model name to the active provider's endpoint
  (which 400'd — e.g. an ollama model sent to GLM). Free-form ids and
  same-provider models keep the current client. (#535)
- **`--provider` now selects that provider's model.** With no `--model`,
  `dirge --provider <p>` took the config default provider's model rather than
  `<p>`'s, so `--provider ollama` switched the endpoint but still loaded the
  default model. It now reads the overridden provider's pinned model. (#535)
- **`XDG_CONFIG_HOME` is honored for the config directory.** Resolution is now
  `DIRGE_CONFIG_DIR``$XDG_CONFIG_HOME/dirge``~/.config/dirge` (relative
  `XDG_CONFIG_HOME` ignored per the XDG spec). (#535)

### Changed
- **Clearer "no API key" error for keyless OpenAI-compatible endpoints.** When
  a `provider_type: "openai"` provider has no key, the error now points local
  ollama/vLLM users at `provider_type: "custom"` (or `"ollama"`), which are
  keyless. (#535)

## [0.13.6] - 2026-06-27

### Added
- **Native issue tracker** — a persistent, agent-facing kanban in the existing
  per-project session DB (`.dirge/sessions/state.db`, `issues` table), framed as
  a stateful extension of the memory model. The new `issue` tool creates /
  starts / blocks / closes / updates / lists / searches durable tasks (status
  `open`/`in_progress`/`blocked`/`done`, priority `high`/`normal`/`low`); unlike
  the ephemeral `write_todo_list`, issues persist across sessions. The harness
  injects the top open issues as a board at the **start of each turn** (bounded,
  with a "+N more" hint) so the model works its backlog without polling — gated
  so forked review/curator runners don't receive it. View it from the TUI with
  `/issues` (`/issues list`, `/issues <id>`, `/issues search <q>`). The store
  owns its schema and opens lock-free, so it adds no migration contention to the
  shared session DB. See [docs/issues.md]docs/issues.md. (#534)

## [0.13.5] - 2026-06-27

### Fixed
- **`auth: "chatgpt"` falls back to legacy `codex login` storage when a Dirge
  OpenAI OAuth credential is present but unusable** (expired with a failed or
  absent refresh, or an unreadable store). It previously hard-errored the
  session in that case even when a valid `~/.codex/auth.json` could have served
  it; now it warns and uses the legacy file. (#533)

## [0.13.4] - 2026-06-26

### Changed
- **`dirge auth openai` now uses a browser-based OAuth (PKCE) flow** instead of a
  device password, matching standard Codex authentication — so you no longer have
  to enable device passwords in the OpenAI console. The browser flow opens a
  loopback redirect, validates a CSRF `state`, and exchanges the code with PKCE
  S256. The previous device-code flow is retained behind
  `dirge auth openai --device-code`. (#532)

### Fixed
- **`auth: "chatgpt"` now honors fresh Dirge OpenAI OAuth credentials before
  falling back to legacy Codex storage.** This prevents a stale
  `~/.codex/auth.json` access token from causing repeated `token_expired` 401s
  after `dirge auth openai` has already produced a fresh, refreshable Dirge
  credential. Stored credentials are refreshed on expiry (and re-persisted)
  rather than served stale. (#532)

## [0.13.3] - 2026-06-26

### Fixed
- **Compaction no longer makes side-LLM summary calls with Anthropic OAuth
  credentials.** A bare summarization request doesn't look like a normal Claude
  Code turn and could trip Anthropic's third-party-use detection, so explicit
  `/compress`, preemptive compaction, reactive overflow recovery, and in-loop
  folding now route their summary call through `summarization_provider` and
  refuse to fall back to Anthropic OAuth. Configure a non-Anthropic-OAuth
  `summarization_provider` to keep high-fidelity LLM summaries. (#529)
- **OAuth sessions without a summarizer degrade gracefully instead of breaking.**
  When no safe summarizer is configured, reactive overflow and explicit
  `/compress` now fall back to a local prune-only emergency compaction (drop the
  oldest turns with a deterministic note) so the session keeps going, rather than
  hard-erroring. The disabled-compaction error is also matched through its full
  source chain so that fallback can't be silently skipped by a wrapped error.
  (#530)

### Added
- **Startup notice when compaction can only prune.** On an Anthropic OAuth
  session with no non-OAuth `summarization_provider`, the interactive UI now warns
  once at launch that context folds will be lossy prune-only, so it isn't a
  surprise at the first fold. The notice self-clears once a summarizer is
  configured. (#531)

## [0.13.2] - 2026-06-26

### Added
- **Cross-session command history.** Up/Down and Ctrl+F recall now seed from the
  most-recent prior sessions in the same project, not just the current one — so a
  fresh session in a project starts with your earlier prompts already in history
  instead of an empty pool. The new top-level `max_sessions` config (default `3`)
  caps how many prior sessions are mined; set `0` to keep recall scoped to the
  current session. Prior prompts are seeded oldest-first ahead of the current
  session's own, so Up still starts from your newest command and walks back.
  Compaction-fold rotations are collapsed so one conversation counts once, and
  synthetic turns (system-reminder wrappers, mid-turn steers, auto-continues)
  never enter history. (#527, #528; thanks @nikolap)

## [0.13.1] - 2026-06-26

### Fixed
- **Headless `--print`/`--loop` no longer hangs forever on a tool that needs
  permission confirmation.** These modes have no UI loop to service the
  permission channel, so a tool routing to a confirmation prompt (e.g. a `bash`
  command `--accept-all` doesn't auto-allow) sent an `AskRequest` and blocked on
  the reply forever — suspending the agent loop with no output and no `result`.
  Headless runs now drain that channel with a deny-all responder (mirroring the
  ACP path), so a not-auto-allowed tool call fails fast instead of hanging; the
  model sees the denial and re-plans. For fully unattended runs that must never
  block, use `--yolo` (which allows every tool and never prompts) or configure
  explicit allow rules. This is the real fix for the deadlock first reported in
  #523 (the earlier 0.12.5 plugin-worker fix addressed a different path).
  (#523, dirge-3oy0)

## [0.13.0] - 2026-06-26

### Added
- **Project-local config overlay.** A project can ship a partial
  `<project>/.dirge/config.json` that deep-merges on top of the global
  `~/.config/dirge/config.json` instead of duplicating the whole file. Scalar
  fields override; map-valued fields (`providers`, `mcp_servers`, `agents`,
  `slash_aliases`, `keybindings`) union key-by-key, so a project can add or
  override a single entry without redeclaring the map. An empty object is a
  no-op, never a wipe. CLI flags and env vars still take precedence over both
  files. (#526; thanks @nikolap)
- **Project-local prompts tier with `/prompt` provenance.** Custom prompts can
  live in `<project>/.dirge/prompts/` and override global or built-in prompts of
  the same name. `/prompt` now shows a `[global]`/`[project]` badge next to
  overridden built-ins, mirroring `/agents`. (#526)

### Changed
- **BREAKING: project-local prompts moved from `./prompts/` to
  `.dirge/prompts/`.** The old cwd-relative `prompts/` directory is no longer
  read. If you relied on a project-level `prompts/` directory, move it to
  `.dirge/prompts/` (matching `.dirge/agents`, `.dirge/plugins`, `.dirge/skills`).
  Global (`~/.config/dirge/prompts/`) and built-in prompts are unaffected.

## [0.12.6] - 2026-06-26

### Fixed
- **Tool chambers and chat now span the full chat band.** On wide terminals
  with the side panels hidden, the chat band reclaims the panel gutters but the
  chamber boxes (and chat text) were still pinned to the gutter-blind, 120-capped
  `content_width`, leaving a dead strip on the right where stale border glyphs
  rendered. Chamber width and chat wrapping now derive from the actual painted
  band (`Layout::chat.width`), so the right border lands on the last painted cell
  and the box matches the left edge. When panels are visible the band is capped
  as before, so that mode is unchanged.
- **`--no-default-features --features mcp` builds again.** The MCP setup
  referenced `cli.loop_mode` and an `ansi` import that only exist with the `loop`
  feature, so that combination failed under `-D warnings`. Both are now gated on
  `loop`. (dirge-oae9)

### Changed
- Bumped `crypto-bigint` 0.7.3 → 0.7.5 (0.7.3 was yanked upstream).

## [0.12.5] - 2026-06-26

### Fixed
- **Headless runs no longer deadlock mid-task on multi-turn agentic work.** In
  `-p` mode a run could freeze permanently after several tool-call turns (alive,
  0% CPU, no `result`). Three compounding issues in the plugin worker path are
  fixed: (1) the before/after tool hooks awaited their `spawn_blocking` dispatch
  via a `tokio::time::timeout` that, on expiry, *detached* a still-running,
  uncancellable blocking task — which kept holding the global plugin-manager
  mutex and the single Janet worker, stalling the next hook; the dispatch is now
  awaited to completion (it's already bounded internally). (2) `harness/confirm`
  / `harness/select` (`send_dialog`) was the one host call with no wall-clock
  bound, so a dialog whose responder never answered pinned the worker forever;
  it now gives up after a generous timeout. (3) the tool hooks round-tripped to
  the worker on *every* tool call even with zero plugins registered;
  `dispatch_tool_hook` now skips the worker entirely when no plugin subscribes.
  (#523, dirge-u5ig)

## [0.12.4] - 2026-06-25

### Added
- **Config-driven aliases for built-in slash commands.** A top-level
  `slash_aliases` map renames a built-in or adds a short alias — `{"exit":
  "quit", "q": "/quit"}` makes `/exit` and `/q` both run `/quit`. A leading `/`
  on either side is optional, arguments after the alias pass through verbatim,
  and an alias inherits its target's safety class (so an alias for `/quit` works
  mid-run). Resolved once at startup; bad targets and keys that shadow a built-in
  warn on the same path as keymap warnings. Aliases register in tab-completion,
  the ghost suffix, and `/help`. (#522; thanks @nikolap)

### Fixed
- **`--print --output-format stream-json` now streams incrementally.** The
  headless run loop received the agent's per-turn and per-tool events but, in
  `stream-json` mode, emitted nothing for them — only a `system` init line, then
  silence for the whole run, then one final `assistant` + `result` at the end.
  Multi-turn agentic runs looked frozen to any consumer parsing the stream. The
  loop now emits a Claude-compatible `assistant` event at each turn boundary
  (text + `tool_use` blocks) and a `user` event carrying that turn's
  `tool_result` blocks, so live-progress UIs get real incremental output. The
  single-turn shape (`system``assistant``result`) is unchanged. (#520,
  dirge-kuqp)

## [0.12.3] - 2026-06-25

### Added
- **SQL semantic support** behind the `semantic-sql` feature (in `default` /
  `windows-default`), backed by the `tree-sitter-sequel` grammar: `list_symbols`
  / `get_symbol_body` / `find_definition` over DDL objects (tables, views,
  materialized views, functions, indexes, types). (#516; thanks @nikolap)

### Fixed
- **SQL writes are no longer blocked by the generic SQL grammar.** `.sql` was
  wired into the pre-write syntax gate, which hard-rejects parse errors — but
  `tree-sitter-sequel` flags valid mainstream SQL (`CREATE PROCEDURE`, the whole
  T-SQL dialect) as errors, so the agent couldn't save it. `.sql` is dropped
  from the write gate; semantic indexing (which tolerates parse errors) is
  unaffected.
- **SQL adapter: anonymous `CREATE INDEX ON t(col)`** no longer emits the table
  as a bogus index symbol — an unnamed index has no symbol to record.
- **SQL adapter: DDL nested in a function body** (e.g. a `CREATE TABLE` inside a
  PL/pgSQL `$$ … $$` body) no longer leaks in as a spurious top-level symbol.

## [0.12.2] - 2026-06-24

### Fixed
- **Proactive compaction now actually runs near the limit.** The pre-send
  trigger fires at 85% of the usable budget, but `prepare_compaction` re-gated
  every non-forced call behind a stricter 100% within-limits check — so in the
  85–100% band the UI announced "preemptive compaction… compressing…" and then
  printed "context within limits, no compression needed" without compacting,
  leaving proactive compaction effectively dead until a hard overflow. The
  trigger now owns the decision (it alone accounts for the incoming prompt) and
  compacts without being re-gated. (dirge-rz4i)

## [0.12.1] - 2026-06-24

### Fixed
- **Mid-task context overflow now resumes the task after compaction instead of
  stranding it.** When a turn overflowed the context mid-work, reactive
  compaction ran but then sat idle because recovery refused to retry once any
  tool had run. With eager post-turn compaction gone (0.12.0), that mid-turn
  path became common, so the agent routinely stopped after compacting. The
  partial assistant turn (streamed text + completed tool calls) is now recorded
  into history before compacting, and recovery resumes as a continuation — the
  already-run tools are not re-executed. (dirge-b899)
- **Queuing a steering message mid-stream no longer duplicates the response.**
  Echoing the queued message sealed the open stream block, and the next token
  re-opened a new block with the whole accumulated response, painting the
  partial `<dirge>` reply twice. The partial is now sealed and the render buffer
  reset so post-queue tokens render as a clean continuation.

## [0.12.0] - 2026-06-24

### Added
- **Experimental entity/relation graph storage** behind the
  `experimental-graph-search` feature gate: entity/relation recording, FTS5 +
  recursive-CTE graph search, a `/graph` command, and Janet harness hooks
  (schema v14). Opt-in; no effect on the default build. (#513, closes #393;
  thanks @allen-munsch)

### Fixed
- **Computer-use hardening** (experimental `experimental-ui-computer-use`):
  closed a single-character shell-injection path in key validation, replaced
  guessable `os/time` temp files with `mktemp`, deduplicated the bash CONTRACT
  hint, and routed desktop actions through the permission PDP (`deny_tools`).
  (#514, follow-up to #415; thanks @allen-munsch)

### Changed
- **The UI no longer freezes during background work.** Long operations used to
  be `.await`ed inline in the single-threaded event loop, freezing rendering,
  input, and Ctrl+C for their whole duration. They now run on spawned tasks
  drained by dedicated `select!` arms, so the loop stays responsive and
  Ctrl+C/Esc abort the work. Converted: compaction (the summarizer — explicit
  `/compress`, preemptive pre-prompt, and reactive overflow recovery), the
  `/plan` reviewer loop (a write-disabled reviewer that runs the code), `/btw`
  side queries, `!cmd` shell commands (up to the 120s cap), and `/wt-merge`
  (the git merge). The post-turn auto-compaction that used to block at every
  turn end was dropped — the now-async preemptive pass covers the next user
  prompt and reactive recovery covers automated follow-ups.
- **`build_agent` no longer re-handshakes MCP servers on every rebuild.** It
  ran a `tools/list` round-trip per connected server, uncached and with no
  timeout, on each of ~9 inline sites (down to a prompt-cycle keystroke) — so a
  rebuild froze the UI for the round-trip, unbounded if a server was wedged.
  Tool definitions are now cached per server (invalidated on `/mcp reconnect`)
  and each fetch is bounded by a 5s timeout.
- **The post-session `git diff --stat` runs off the event loop.** The turn-end
  review digest shelled out on the loop at every turn; the subprocess now runs
  inside the already-spawned post-session task.

## [0.11.3] - 2026-06-22

### Added
- **Read the current session id.** `/sessions current` prints the full session
  id with a `dirge --session <id>` resume hint, and `/sessions list` marks the
  live session. The status footer's session badge now shows a *distinct*
  compact id (keeps a `compacted-`/`forked-` prefix plus the unique uuid head)
  instead of collapsing every compacted session to "compacte".

### Changed
- **One-shot side-LLM calls no longer burn reasoning tokens.** The summarizer,
  critic, and approval-evaluator one-shots now request the model's
  extended-reasoning trace OFF (provider-appropriate param: chat_template_kwargs
  for the openai-compat/DeepSeek family, `think:false` for Ollama, zero thinking
  budget for Gemini). On reasoning-by-default models this roughly halves a
  context-checkpoint summary's latency. Anthropic (off by default) and OpenAI
  (no safe "off") are untouched.

## [0.11.2] - 2026-06-22

### Fixed
- **OpenAI Responses streaming.** Historical reasoning blocks (which the
  Responses API rejects without provider-generated IDs) are dropped and tool
  `call_id`s are synthesized for OpenAI requests, fixing broken streaming /
  tool-use against OpenAI. Applies to all three OpenAI client variants — API
  key, ChatGPT-OAuth, and Codex — regardless of the configured provider alias.
  (#510 + follow-up, issue #480; thanks @ericschmar)
- **Preserve partial answers when escaping a multi-question prompt.** Pressing
  Esc after answering at least one question in a batch now returns the answers
  given (remaining questions marked `[no answer]`) instead of discarding
  everything. Esc on the first question still cancels. (#508; thanks @rgkirch)

## [0.11.1] - 2026-06-22

### Added
- **Hot-load plugins mid-session with `/plugins load`.** `/plugins load <path>`
  loads a single `.janet` file or plugin directory; `/plugins load all` loads
  every `.janet` from `.dirge/plugins/` and `~/.config/dirge/plugins/` (cwd wins
  on same-name). Previously `/plugins` only listed already-loaded plugins. Works
  in release builds. (#505, thanks @allen-munsch)
- **See which prompt goes to which provider, and why.** New opt-in request dump
  behind `DIRGE_DUMP_REQUESTS`: `=1` logs one summary line per outgoing provider
  request (purpose label, provider, tool count/names, reasoning flag, byte
  sizes); `=full` also dumps the system / one-shot prompt body. Emitted at INFO
  on the `dirge::wire` target, so it lands in `dirge.log` (`-v` / `RUST_LOG` /
  `DIRGE_LOG`) or via `RUST_LOG=dirge::wire=info`. Instrumented at both
  request-build choke points — the side-LLM one-shot path (summarizer / critic /
  approval evaluator) and the agent stream factory (turns / escalation /
  subagents / forked review) — so a mystery secondary completion is now
  attributable. Off by default. (#507, dirge-iis0)

## [0.11.0] - 2026-06-22

### Added
- **Scrollback reflows on terminal resize.** The chat buffer became a derived
  cache over a width-independent source log, so prose and markdown — tables
  especially — re-wrap to the new width on resize instead of keeping the
  column widths they were first rendered at. Streamed reasoning/response is
  source-tracked too; tool-chamber borders are preserved verbatim (re-boxing is
  a follow-up). (#504, dirge-qy3y)
- **Memory: a pinned project overview.** A new `overview` memory kind holds a
  single high-level orientation (stack, layout, how to build/test) that is
  exempt from eviction and rendered first in the system prompt, refreshed by the
  background review. (#504, dirge-pkqi)
- **Memory: deterministic session ground-truth.** A model-free digest (goal,
  files touched, commands run, todos, `git diff --stat`) is prepended to the
  background-review transcript so it ranks known facts instead of rediscovering
  them. (#504, dirge-a62g)
- **Memory: open-thread carry-over.** The background review records genuinely
  unfinished work as short `working` entries so a fresh session resumes where
  the last one stopped, and clears them once the work lands. (#504, dirge-hcv8)

### Changed
- **Rebind a key across contexts without unbinding it first.** A user (or
  plugin) keybinding now clears the chord from both the global and input keymaps
  before inserting the resolved command, so e.g. `ctrl-r → reverse_search` takes
  effect without a preceding `unbind`. (#504, dirge-z2p6)

### Fixed
- **Secrets in memory entries are redacted before storage**, not just in the
  full-text index — closing a leak path into the system prompt and global-scope
  memory. (#504, dirge-n3qf)

## [0.10.4] - 2026-06-21

### Added
- **Debug a Python module, not just a file.** The DAP launch path now takes an
  optional `module`, so a debuggee can start as `python -m <module>` (e.g.
  `pytest`) instead of by program path — exposed via the `dap/launch-module`
  Janet binding and the debug slash command. The `debug` tool's launch args also
  gained an `env` map for per-launch environment variables. CI runs the new
  smoke/e2e tests under a `dap` feature-matrix entry. (#497)

## [0.10.3] - 2026-06-21

### Added
- **`/model` lists the models your config pins.** With no argument it now prints
  every model set across your `providers`, marks the active one, and tells you to
  switch with `/model <id>` — previously it only echoed the current model with
  nothing to pick from. (#495, issue #492)

### Changed
- **`Ctrl+D` is forward-delete in the input editor**, not a hard exit. It deletes
  the character under the cursor (rebindable as `delete_char_forward`); `Ctrl+C`
  and `Esc` remain the interrupt/exit gestures. (#493)
- **The context gauge reads 0–100%.** Its denominator is now the full effective
  window instead of the fold-trigger budget (~75% of it), so real usage past 75%
  no longer showed a confusing `>100%` (e.g. `90k/75k (120%)`). A compact
  `fold`/`fold!` marker flags when a fold is near/imminent. (dirge-l4rp, dirge-cx7t)

### Fixed
- **Auto-repair no longer silently mangles files.** Delimiter auto-close now only
  fixes a genuine *trailing* truncation; a mid-file imbalance that would swallow
  the following code is rejected and bounced back to the model instead of being
  "repaired" into valid-but-wrong code. (dirge-a0nl)
- **Auto-repairs are verified by the language server and rolled back when wrong.**
  After an auto-close, `write`/`edit` ask the LSP whether the result actually
  holds up; on error-severity diagnostics the change is reverted to its pre-write
  state and the model gets the diagnostics to fix its original text. A rollback
  that can't snapshot the prior content (e.g. an unreadable existing file) now
  leaves the file in place rather than deleting it. (dirge-p1ws, #501)
- **Nix release job no longer fails on every tag.** The `bin.nix` version bump is
  committed straight to `main` instead of trying to open a PR (which GitHub
  Actions can't do with the default token). (#491)

## [0.10.2] - 2026-06-20

### Added
- **Cycle prompts with Shift+Tab.** A hotkey (rebindable as `cycle_prompt`)
  steps through the configured prompt layers like a mode switcher, and now
  cycles back to the no-prompt base layer past the last one. (#485, #489)

### Fixed
- **Critic / verifier / todo nudge no longer vanishes from the log.** These
  finalization nudges re-enter as user-role messages without a Done/ToolCall to
  reset the stream anchor, so the next turn's render overwrote them — they
  disappeared on screen a moment later even though the model still had them in
  context. The in-flight response is now finalized before the nudge renders, so
  the next turn streams below it. (#488)

## [0.10.1] - 2026-06-20

### Added
- **Undo in the input editor.** `Ctrl+Z` reverts the last edit — a paste, a
  kill, or a run of typing (grouped by word). State resets on submit and
  `/fork`. Rebindable as the `undo` command.
- **Verification-aware finalization.** The in-loop critic now sees whether the
  run actually built/tested its code changes and nudges on an unverified or red
  change — with an explicit "nothing to run / not testable → fine" escape so it
  never forces a test that can't run. The goal gate gets the same signal as a
  soft advisory that can't trap the bounded loop. Active only when a critic
  provider is configured. (#484)
- **Experimental computer-use plugin.** Off by default behind the
  `experimental-ui-computer-use` build feature; intercepts `bash` commands
  prefixed `computer:` to drive a desktop (screenshot, type, click, navigate)
  via ydotool/xdotool plus a local vision backend. Gated by a confirm dialog,
  an explicit host-control opt-in, and a sandboxed-desktop image. (#415)

### Fixed
- **Copy wrapped prose as one line.** Selecting chat text the renderer
  soft-wrapped across rows no longer pastes a newline at every wrap point;
  real line breaks, paragraph breaks, and blank lines are preserved.
- **macOS (Apple Silicon) build.** The computer-use plugin used x86_64-only
  Janet FFI (`janet_wrap_integer`, raw union `.pointer` access), which broke the
  default plugin build on aarch64 — invisible to the Linux-only CI. Now uses
  portable janetrs access. (#483)
- **Shell injection in computer-use `focus`.** The model-controlled app name is
  validated against a safe character set before reaching `pgrep` / the vision
  call. (#482)

## [0.10.0] - 2026-06-20

### Added
- **Configurable key bindings everywhere.** One `keybindings` array now rebinds
  both the global command keys (scroll, chat nav, …) and the input-editor keys
  (cursor/word motion, kill-ring, history, …) — the text-box keys used to be
  hardcoded. Built-in defaults are declarative tables your config merges over;
  see [docs/config.md]docs/config.md#key-bindings for the full command list.
  (#477)
- **Emacs-style chord sequences.** A binding key may be a sequence like
  `ctrl-x ctrl-s`; the footer shows the pending prefix and **Esc**/**Ctrl+G**
  cancels it. Optional `chord_timeout_ms` auto-cancels a pending prefix after a
  set idle time (default: wait indefinitely). (#477, #478, issue #234)
- **Plugins can remap built-in bindings.** `(harness/bind-key keys command)`
  binds a chord (or sequence) to a built-in command, or `"none"` to unbind one,
  merged under your config (defaults < plugin < user). `register-shortcut`
  (bind a key to plugin code) is unchanged. (#477, issue #476)
- **Visual-line cursor motion.** `Ctrl+A`/`Ctrl+E`, `Home`/`End`, and the
  `Ctrl+U` kill now act on the current soft-wrapped line rather than the whole
  buffer. (#474)

### Changed
- **`approval_provider` denials are advisory.** When an LLM approval evaluator
  denies a tool call, it now escalates to the normal permission prompt (showing
  *why* it was flagged) instead of hard-failing — so you can still allow it.
  It's terminal only in non-interactive mode. (#475)
- **Permission denials aren't treated as fixable failures.** The recovery
  checkpoint no longer tells the model to "try a different approach" after a
  permission block (which pushed it to route around the guardrail), and the
  critic treats a permission-denied capability as out of scope rather than
  unfinished work. (#475)

### Fixed
- **`/sessions delete` works when ids collide.** Compacted sessions are named
  `compacted-<uuid>`, so every one rendered as the identical 8-char stub
  "compacte" and "be more specific" was impossible. The list/switch/delete
  views now show ids at the shortest length that keeps them distinct, and never
  cut the leading marker mid-word. (#478)

## [0.9.1] - 2026-06-20

### Changed
- **`/sessions` uses explicit verbs.** `/sessions list | switch <id> | delete <id>`,
  with bare `/sessions <id>` still switching as a shortcut. The first argument no
  longer does double duty as both a `delete` sentinel and a session id, so a
  session can no longer shadow a subcommand. (dirge-aqi3)
- **The footer token budget reflects the compaction point.** The status line now
  measures usage against the budget where auto-compaction kicks in
  (`fold_threshold × min(model_window, context_target)`) instead of the raw
  advertised model window, so the percentage tracks how close the next fold is —
  at 100% a fold is imminent. (dirge-l4rp)

### Fixed
- **Deleting the current session no longer leaves a zombie.** Deleting the session
  you're in removed its file but left the in-memory session pointing at it; you're
  now booted into a fresh session (new id, same model/provider/cwd) with the agent
  rebuilt. (dirge-0cvk)
- **The goal gate no longer acts on a stale compaction summary.** After a resume,
  the merged system prompt carries a `[CONTEXT COMPACTION — REFERENCE ONLY]`
  summary whose `## Active Task` describes already-completed work; the goal judge
  now strips it (matching the critic), so it won't re-demand superseded work. It
  also no longer risks a panic truncating a multi-byte constraints block. (dirge-wp0e)
- **Pasting while answering a question no longer leaks into the main prompt.**
  When typing a free-form custom answer in the `question` modal, a paste went
  to the compose editor instead of the answer field — the modal dispatcher only
  routed key events, so pastes fell through. Pastes now land in the active
  answer (newlines flattened to spaces) and are swallowed for single-key
  modals. (dirge-7543)

## [0.9.0] - 2026-06-19

### Added
- **`show_reasoning` config flag.** Set it to `true` to make the model's
  thinking visible by default instead of pressing `Ctrl+O` each turn. Defaults
  to `false` (unchanged behavior); `Ctrl+O` still toggles per session. (#461)
- **Nix flake.** `nix build` / `nix run` build dirge from source, `nix develop`
  opens a Rust dev shell, and `nix build .#dirge-bin` installs the prebuilt
  release binary. Ships an overlay and `.envrc` for direnv, and supports
  x86_64/aarch64 on both Linux and macOS. A release-tag workflow refreshes
  `nix/bin.nix` hashes and opens a PR. (#462, #466)

### Fixed
- **Compaction no longer 400s under Anthropic OAuth.** dirge injects
  `role:"system"` entries into `messages[]` for compaction summaries and
  mid-session memory re-injection. The OAuth shaper only normalized the
  top-level `system` field, so a stray system turn reached the wire and the
  Claude-Code classifier rejected it as third-party traffic ("extra usage" 400)
  right after every compaction. System-role `messages[]` entries are now folded
  into the top-level `system` block first. (#463)
- **Global-tier skills are advertised in the system prompt.** The skill catalog
  listed only the project-local `.dirge/skills/`, while the `skill` tool could
  load from the global tiers too — so a globally installed skill was loadable
  but never advertised. The catalog now lists from the same source as the tool
  (`discover_skills`). (#464)

## [0.8.1] - 2026-06-18

### Fixed
- **Interactive prompts fail fast instead of hanging to the timeout.** A
  `git clone` that prompted for a username blocked for the full 120s bash
  timeout: git reads credentials from `/dev/tty`, not stdin, and in the Off
  sandbox the child shared dirge's controlling terminal. The bash child now
  runs in its own session (`setsid`) with no controlling terminal, so the
  prompt errors out immediately; `GIT_TERMINAL_PROMPT=0` and friends cover the
  non-tty askpass paths. (#460)

### Changed
- **The loop guard is cost-aware.** The repeat (storm) and failure-streak
  guards were count-based, so a command that burned its whole timeout counted
  the same as a millisecond error and neither escalated. Each result is now
  classified once (ok/error/timeout) and fed to both: a timeout weighs double
  toward the recovery-checkpoint nudge, and an identical retry of a timed-out
  command is suppressed one attempt sooner. (#460)

## [0.8.0] - 2026-06-19

### Fixed
- **Expanded thinking block keeps its box on wrapped lines.** In the Ctrl+O
  thinking panel, a long thought's continuation rows dropped the `` bar and
  started at the left edge, so the text escaped the bounding box. Each line now
  wraps with the bar carried onto every row. (#459)

## [0.7.9] - 2026-06-19

### Added
- **Anthropic Claude Code OAuth.** `dirge auth anthropic` runs a PKCE
  loopback login against a Claude Pro/Max subscription and stores the token at
  `~/.claude/.credentials.json` (Claude Code-compatible), refreshed on expiry.
  Set the Anthropic provider's `auth` to `anthropic` / `claude-code` to use it.
  (#452, #454)
- **OpenAI / ChatGPT OAuth.** `dirge auth openai` (alias `dirge auth chatgpt`)
  runs OpenAI's device-code login for a ChatGPT subscription and stores the
  token in dirge's own credential file; the `auth: chatgpt` mode also still
  reads an existing `~/.codex/auth.json`. Requires enabling device-code auth in
  ChatGPT Codex security settings. (#455)
- **`/memory reload`** refreshes the frozen memory snapshot mid-session without
  restarting. (#435)

### Fixed
- **Long lines in fenced code blocks wrap instead of clipping.** The chat
  painter draws one row per buffer line and clips to width; code rows weren't
  pre-wrapped, so a long line inside a ``` block was cut off at the window
  edge. They now wrap like prose. (#453)
- **Anthropic OAuth credentials are written atomically.** The persist path used
  a non-atomic truncating write with a brief world-readable window before
  permissions were tightened; it now uses the same atomic 0600 write as the
  OpenAI store. (#457)
- **Manifest version restored to match the release tag.** #454 branched from a
  pre-0.7.8 base and regressed `Cargo.toml`/`Cargo.lock` to 0.7.7; bumped back
  so the tree matches the `v0.7.8` tag. (#456)

### Changed
- **Shared OAuth credential I/O across the Anthropic and OpenAI paths** (atomic
  0600 write, expiry check, account-id alias extraction) and unified the
  `dirge auth` dispatch through one config-free path. The two login *flows*
  (loopback vs device-code) stay provider-specific. (#457)

## [0.7.8] - 2026-06-18

### Added
- **Memory improvements.** Procedural playbooks now rank on measured
  effectiveness rather than recency, so a play that keeps working surfaces
  ahead of one that was merely used recently (#436). A confidence axis with
  contradiction-driven supersession lets a newer fact retire a stale one
  instead of both lingering (#437). An opt-in hybrid retrieval provider fuses
  dense embeddings with BM25 via reciprocal-rank fusion (#439). Verbatim
  pre-recall surfaces exact prior snippets as supplemental context without
  disturbing the frozen system-prompt snapshot (#440). Mark/supersede is gated
  to the background review runner so it can't stall the main loop (#441).
  (#442, #445)
- **Retrieval eval harnesses.** A Recall@K harness for the memory retriever
  (#438) and a compaction-recall harness that probes whether load-bearing
  facts survive a fold (#434).
- **Live thinking streams into the Ctrl+O panel.** Expanding an in-progress
  reasoning burst now updates in place as new tokens arrive, instead of
  freezing the snapshot you first opened (#444).

### Fixed
- **Compaction no longer resurrects finished tasks (#443).** After a fold the
  model could re-derive the original request as if still pending when it was
  already done and the live work had moved to a follow-up. The summary's
  `## Active Task` now describes the immediate in-flight work and marks the
  original complete, and the summary preamble warns not to redo finished work.
- **Blockquotes render the `` bar on every line (#446).** The bar code ran
  after the paragraph had already flushed, so it was dead and multi-line
  quotes rendered as bar-less dim prose.
- **Live-thinking expansion hardening (#449, #450).** The in-place re-render
  no longer truncates content that scrolled below the block, the expansion
  state resets across chat switches, and the per-delta re-render is coalesced
  so a long reasoning burst is no longer O(n²). Quoted headings and code
  blocks now carry the quote bar too.

### Docs
- Documented how the context/compaction fold point is computed
  (`compaction_fold_threshold` × `min(model_window, context_target)`) (#447).

## [0.7.7] - 2026-06-17

### Added
- **ChatGPT/Codex authentication.** Run `codex login`, then `dirge` with the
  `openai` provider and `auth: chatgpt` — dirge reads the Codex bearer token
  from `~/.codex/auth.json` (or `$CODEX_HOME/auth.json` / `CODEX_ACCESS_TOKEN`)
  and talks to the Codex backend through a small request shim that adapts the
  `/responses` body shape. The token is sent only to the Codex endpoint over
  https, never logged, and ChatGPT auth is refused for any non-`openai`
  provider so the token can't leak to a third party. (#428, #433)
- **Skills discovered under `.agents/skills/` too**, alongside `.claude`,
  `.opencode`, and `.dirge`, at both home and per-project scope. (#432)

## [0.7.6] - 2026-06-17

### Fixed
- **Destructive git commands no longer run without a prompt (#429).**
  `git checkout`, `git switch`, and `git restore` were on the default
  auto-allow list, so they executed silently anywhere the `bash` tool was
  reachable — and they discard uncommitted work. An agent reverting its own
  edit with `git checkout -- file` could wipe a user's pending changes. They
  now require a permission prompt; `git pull`/`fetch` stay auto-allowed and
  `git reset`/`clean` already prompted.

### Changed
- **Plan mode is locked down comprehensively.** The plan prompt's tool
  denylist previously missed `task`, MCP, plugin, debug, and spec tools, so a
  "read-only" planning session wasn't fully read-only. It now denies every
  tool that can change the filesystem, run a command, reach the network, or
  delegate work. (`edit_lines`/`edit_minified` were already covered via the
  `edit` permission name.)

## [0.7.5] - 2026-06-17

### Changed
- **Edit tools auto-close an unbalanced delimiter instead of bouncing it
  back.** A truncated tool-call JSON argument was already repaired
  mechanically, but an unbalanced `()`/`[]`/`{}` in code the model wrote was
  only detected and the edit rejected — costing a model round-trip for a
  mechanical fix. Now `write`, `edit`, `edit_lines`, `apply_patch`, and
  `edit_minified` mechanically close a purely-unclosed delimiter imbalance and
  report the fix on the result (`[auto-repair] …`), the same way the JSON
  repair does. Safe by construction: only for languages whose comments/strings
  are understood (so a delimiter inside a string or comment is never
  miscounted), never for a stray/mismatched closer, and only when the closed
  result actually re-parses — tree-sitter is the oracle that rejects a nonsense
  close. A genuinely broken edit still gets the precise "the `(` at line N is
  never closed" rejection. All edit tools now share one pre-write gate.

## [0.7.4] - 2026-06-17

### Fixed
- **In-loop critic no longer judges a truncated, stale view of the run.** The
  transcript handed to the F6 critic (and the goal gate) rendered the whole run
  and then kept only the first ~8000 chars — so in a substantial run it saw the
  planning/scaffolding at the start and never the implementation and
  verification at the end, producing confidently wrong critiques ("no code
  created", "no demo run") about work that was actually complete. It now keeps
  the original request plus the most recent activity (head + tail, eliding the
  middle), since completion is decided by the latest work.

## [0.7.3] - 2026-06-17

### Added
- **Storm-breaker graceful failure.** When a run gives up because it's stuck
  repeating the same tool call (the repeat-loop guard's terminal case), it now
  appends a short first-person assistant message explaining that it stopped to
  avoid spinning, instead of ending on an empty/abrupt turn. The message names
  the tool(s) it looped on and is recorded in history, so the user gets a
  coherent reply and the model carries its own failure account into the next
  turn. The internal reflect-then-pivot nudge on the first trip is unchanged.
- **`/rewind` now rolls back files, not just the conversation.** Every
  write/edit/edit_lines/apply_patch (including delete and rename) snapshots the
  touched file's pre-mutation content, keyed by the user prompt that triggered
  it. Rewinding to a prompt restores the working tree to its state before that
  prompt ran, in lockstep with the conversation truncation — so a long
  autonomous run is safe to unwind. Content is deduplicated through a small
  content-addressed pool so a file edited many times across turns doesn't store
  many copies. In-memory and process-scoped (rewind works within a live
  session, not across a restart); a created file is deleted on restore, a
  deleted file is recreated. From the [howard chen
  writeup](https://howardchen.substack.com/p/deepseek-v4-pro-at-5-the-cost-of)'s
  rewind lever.
- **Hash-anchored editing (`edit_lines` + `read(line_hashes=true)`).** A new
  edit path aimed at cheaper models: `read` can prefix each line with a 3-char
  content hash (`42 a3f: ...`), and `edit_lines` replaces a line *range* by
  number — `start_line`, `end_line`, the `expected_hashes` for that range, and
  `new_text` — without retyping the old block. The tool recomputes the hashes
  from disk and rejects the edit (per-line diff) if any line drifted since the
  read, so it never clobbers content that changed underneath it. Reuses the
  existing read-before-edit gate, tree-sitter pre-write validation, and atomic
  write. The win, per the [howard chen
  writeup](https://howardchen.substack.com/p/deepseek-v4-pro-at-5-the-cost-of):
  fewer retries and markedly lower output tokens on models like DeepSeek, since
  the model emits line numbers + tiny hashes instead of reproducing the text it
  wants to replace. The existing exact-string `edit` is unchanged.
- **Prefix-cache hit accounting + `/cache` command.** Providers like DeepSeek
  and Anthropic serve repeated request prefixes from a cache at a steep
  discount (DeepSeek ~1/10 the input price), and dirge already holds the system
  prompt + sorted tool defs at a stable prefix to keep that cache warm — but
  there was no way to tell whether hits were actually landing. Real
  provider-reported usage (`cached_input_tokens`, `cache_creation_input_tokens`)
  now flows from the stream through to a cumulative per-session counter, and
  `/cache` prints the session's cumulative prefix-cache hit ratio. This is the
  instrument for the DeepSeek cost story in the [howard chen
  writeup](https://howardchen.substack.com/p/deepseek-v4-pro-at-5-the-cost-of):
  cache discipline is the headline lever for running cheaper models, and now
  you can measure it.
- **Working memory keeps a slice of the prompt as project facts accumulate.**
  Memory entries are evicted by kind-derived salience, which drops transient
  `working` notes before durable facts — so a project with many high-salience
  invariants could push working memory out of the injected context entirely.
  The hot-tier budget now reserves a small slice for `working` entries:
  long-term still uses the full budget when no working notes are present, but it
  can't evict working below the reserve, and a working note never displaces a
  long-term fact within its share either.
- **The memory curator promotes durable working notes and weighs usage.** A
  `working` note that turns out to be a lasting fact (a build command, a design
  decision) no longer just decays — the background curator now surfaces working
  entries that outlived their session and re-classifies the ones whose use count
  and content prove durable to `procedural`/`semantic`. Its consolidation input
  also annotates every entry with `[kind | uses | id]`, so keep/merge/remove
  decisions weigh how load-bearing an entry actually is, not just its text.

### Changed
- FNV-1a hashing is unified behind one internal module; the `/rewind` snapshot
  store's process-global scope is documented as intentional (subagent edits are
  rewindable by the parent). No behavior change.

## [0.7.2] - 2026-06-15

### Changed
- **Default and coding prompts now lead with a "reach for what exists" ladder.**
  Both prompts gained a short decision procedure run before writing any code:
  skip it (YAGNI) → stdlib → native platform feature → installed dependency →
  one line → minimum that works. The Code Style sections were previously all
  "don'ts"; this adds the positive directive that actually cuts output volume,
  plus an explicit list of what laziness never touches (trust-boundary
  validation, data-loss handling, security, accessibility). Adapted from the
  [ponytail]https://github.com/DietrichGebert/ponytail skill.

## [0.7.1] - 2026-06-15

### Fixed
- **Resumed sessions restore the TODOS and MODIFIED panels past a
  compaction.** 0.7.0 rebuilt these panels by replaying the tool calls in the
  message history, but a destructive compaction drains those messages out of
  the session — so a resumed `compacted-*` session came back with empty TODOS
  and a near-empty MODIFIED list. The panel state is now snapshotted into the
  session file on every save (independent of message history), so resume
  restores it even after a fold. Sessions saved by an older binary have no
  snapshot and can't be recovered; only sessions saved going forward carry it.

### Changed
- **Faster `dirge --session <id>` resume.** Resolving a session id to its fold
  chain tip no longer fully deserializes every session file in the directory —
  it scans with a lightweight partial parse and fully loads only the winning
  tip. Resume startup no longer degrades as old session files accumulate.

## [0.7.0] - 2026-06-15

### Added
- **Spec-driven workflow tracker (SQLite-backed).** A dirge-native take on
  spec-driven development: align on what to build before writing how, tracked
  as rows in the per-project DB rather than a markdown-folder tree. Living
  specs (capability → requirement → scenario) are the current truth; a change
  carries requirement deltas plus a task checklist, and archiving folds the
  deltas into the living specs in one transaction. Real task status as a
  column, queryable specs, no silent parse failures. Exposed via the `spec`
  agent tool and a bundled spec-driven-workflow skill.
- **`/spec` command.** Read-only view of the tracker: list changes, show one
  change (proposal + deltas + tasks), and read living specs
  (`/spec specs [capability]`).
- **Active-change context injection.** The active change (why/what/design +
  recorded deltas + task status) is rendered into the agent preamble at build
  time, so a resumed or fresh session knows what it's implementing and where
  it left off without querying the tool.
- **Archive forms a memory.** Archiving a change folds its rationale and
  design decisions into durable project memory, so the reasoning outlives the
  change record.

### Fixed
- **Session resume restores the TODOS and MODIFIED panels.** The todo list and
  modified-files set live in process-global state that isn't part of the
  session schema, so resuming a session (`--session`) or switching with
  `/sessions` replayed the conversation but left those panels blank until the
  agent ran again. They're now reconstructed by replaying the session's
  recorded tool calls. `/clear` also now clears the todo list, not just the
  modified-files set.

## [0.6.5] - 2026-06-15

### Added
- **Visible compaction progress.** A destructive fold now shows
  `⟳ compacting context…` in the main pane while the summarizer runs,
  instead of the session appearing frozen. The result line follows when
  it finishes.
- **Mid-session memory awareness.** The system-prompt memory block is
  fixed at agent-build time, so memories written by background
  consolidation weren't visible until restart. Consolidation now flags the
  change and the loop re-injects the refreshed memory block at the next
  turn boundary, so the running agent sees newly consolidated memories
  without restarting.

### Changed
- **Faster compaction.** The background incremental checkpoint already
  summarizes a context snapshot off the loop; the destructive fold now
  reuses that precomputed summary (prune + splice, no inline LLM call)
  when it's current and clears the fold target. This is the common path
  under the 100k budget, where folds fire often.

### Fixed
- The inline compaction summarizer is now bounded by a timeout: a provider
  that stalls without erroring falls back to prune-only instead of
  freezing the session indefinitely. The background checkpoint summarizer
  is bounded too so a hung call can't leak the task.

## [0.6.4] - 2026-06-14

### Added
- **Working-context budget (`context_target`, default 100k tokens).** A
  model's effective quality degrades well before its advertised window
  fills — the usable "smart zone" runs out around 100k regardless of size.
  The compaction decision now treats the effective window as
  `min(model_window, context_target)`, so the live context is folded — and
  project memory formed — to stay inside the budget rather than drifting
  into the degradation zone on a 200k/1M model. Configurable in
  `config.json`; floored at 16k; composes with `compaction_fold_threshold`
  (fold point = `fraction × min(window, context_target)`).
- **Memory formation on compaction.** When a summary fold clears
  conversation context, dirge now runs the same background review/curate
  pass it runs at session end, so the session's learnings are captured into
  the durable per-project memory store before the fold discards them.
  Self-throttled and single-runner, so frequent folds don't pile up.

### Fixed
- The agent loop now honors an explicit `context_window` config override
  (it previously read only the built-in model table and ignored it).

## [0.6.3] - 2026-06-13

### Fixed
- **Mouse scroll/select stopped working mid-session.** Mouse capture and
  bracketed paste were enabled once at startup and never re-asserted, so a
  child program run through the bash tool (a pager/TUI like `git log`  `less`, `fzf`, `vim`) that reset terminal modes on exit silently turned
  dirge's off — the wheel then scrolled the whole UI and click-select
  stopped registering. The paint loop now re-asserts these modes on a 1s
  throttle so dirge self-heals; non-SGR escapes are also stripped before a
  chat line reaches a terminal cell so a leaked control sequence can't
  corrupt terminal state in the first place.

### Added
- **`Ctrl+O` toggles expand/collapse of the last truncated block** — a
  thinking burst (live or just completed) or a collapsed tool/command
  result. Thinking is now retained past the turn boundary, so it stays
  expandable once the response is showing; a second press collapses.
- **Bundled workflow skills starter pack** under `skills/`  `systematic-debugging`, `code-review-feedback`, and `writing-skills`,
  adapted from the superpowers collection (MIT). Opt-in: copy a skill dir
  into `.dirge/skills/`. See [skills/README.md]skills/README.md.
- **Short session id in the status bar** for quick reference.

## [0.6.2] - 2026-06-12

Long-horizon session work, porting ideas from MiMo-Code onto dirge's
existing loop and memory rather than bolting on parallel machinery.

### Added
- **Durable session checkpoint (schema v10).** Each conversation gets a
  `session_checkpoints` row holding the regenerated fold summary plus a
  write-once verbatim-intent slot, keyed by a stable `origin_id`. Written
  on every compaction fold; SQLite-backed in the per-project state.db.
- **Incremental checkpointing (default on).** Refreshes the durable
  checkpoint at 20%-interval usage thresholds (20/40/60/80% for windows up
  to 200K; 10% to 500K; 5% above; disabled under 25K) in a background
  task, without folding — so a resume after a quit/crash recovers a fresh
  state instead of falling back to lossy compaction. The destructive fold
  still fires at 0.75. Disabled in headless `-p`/`--loop` (nothing there
  persists it). Disable with `incremental_checkpoint = false`.
- **Goal gate (`--goal`).** Opt-in natural-language stop condition for
  autonomous runs: at each finalization an independent judge (the critic
  provider) rules whether the condition holds; if not, its reason
  re-enters the loop, bounded so a mis-stated goal can't spin forever.
  Requires a configured `critic_provider`.
- **Global memory tier (default on).** A cross-project memory store
  (single db in the user data dir) injected into the prompt under its own
  header; the `memory` tool gains a `scope: "global"` argument for durable
  user preferences that follow you across repos. Isolated from project
  memory.
- **`compaction_fold_threshold` config** (0.3–0.75) to fold — and thus
  checkpoint — earlier, from more coherent context.

### Fixed
- **Resume now picks up where it left off.** A fold rotates the session id
  and leaves the old file behind, so resuming by the id you started with
  loaded a stale pre-fold snapshot. Conversations now carry a stable
  `origin_id` across folds; resume resolves any id to the live chain tip,
  and the session list collapses a folded conversation to one entry
  instead of one per rotation.

## [0.6.1] - 2026-06-11

### Fixed
- **Headless `--session` now persists the full assistant turn.** `dirge -p
  --session <id>` saved only the assistant's final text, dropping every tool
  call and result — so a resumed session (notably an MCP delegation
  follow-up) lost the substance of prior work, and a tool-heavy final turn
  (which often has little trailing text) saved a thin/empty message that read
  as a cut-off end. The turn's tool calls are now saved too, so
  `convert_history` re-emits the `tool_use`/`tool_result` blocks on resume.
- **mermaid_diagram plugin: validation gaps.** The diagram edge check rejected
  valid `er`/`class`/`state` diagrams (and flowchart `-.->`/`==>`); broadened
  the connector match. Added a `{}`-balance check for `{decision}`/`{{hexagon}}`
  nodes, and dropped a stray `[` from an error message.

## [0.6.0] - 2026-06-11

### Added
- **Run dirge as an MCP server** (`dirge mcp`, `mcp-server` feature, default
  on). Another agent (e.g. Claude Code) can delegate implementation tasks to
  dirge and review them — the caller plans/architects, dirge implements.
  Keeps a persistent per-project session: `delegate` extends it, `new_session`
  rotates for a new task/thread, and the current session id is remembered in
  `.dirge/mcp_current_session.json` across restarts. Each `delegate` returns a
  bounded, review-friendly result — `status`, `summary`, `files_changed`,
  `turns` — not the raw transcript. Tools: `delegate`, `new_session`,
  `session_info`, `list_sessions`. Register with
  `claude mcp add dirge -- dirge mcp`. See [docs/mcp-server.md]docs/mcp-server.md.

### Fixed
- **`dirge -p --session <id>` now resumes the conversation.** Headless print
  mode persisted the session but never fed the prior turns back to the model,
  so each `--session` run started cold (a follow-up task had no memory of the
  previous one). The print path now resumes the loaded session's history; the
  `--loop` path is unchanged. Fixes multi-step continuity for the MCP
  delegation loop and any scripted `dirge -p --session` use.

## [0.5.2] - 2026-06-10

### Fixed
- **Tool chambers are restored when a session is reloaded.** The scrollback
  replay (`/sessions` switch, `-c`/`--session` resume, `/fork`) rendered only
  message prose and dropped every persisted tool call, so reloading a session
  lost all its edits/bash/reads from the visible transcript and showed
  pure-tool-call turns as a bare handle. Each call is now reconstructed as a
  chamber, matching the live view. (Data was never lost — the model always
  re-saw the calls; this was a display gap.)
- **Idle scroll no longer stalls.** The render loop's 8ms paint throttle could
  drop the final frame of a fast wheel/trackpad scroll, and with the agent
  idle there was no timer to repaint it — so the scrolled position sat
  unpainted until the next event. A pending dirty frame now repaints just past
  the throttle window even when idle.

### Changed
- Mouse-wheel scrolling over the chat moves 3 lines per tick (was 1), matching
  the side panel.
- On interactive exit, dirge prints a dark-gray hint —
  `Resume this session with: dirge --session <id>` — so it's easy to pick the
  session back up (skipped for `--no-session` / empty sessions).

## [0.5.1] - 2026-06-10

### Fixed
- **`sandbox-microvm` builds on macOS without OpenSSL.** The feature pulled
  `ssh2 → libssh2-sys → openssl-sys`, so `cargo build --features
  sandbox-microvm` (and `--all-features`) failed on machines without a
  system OpenSSL. The microVM SSH client is now `russh` (pure Rust, `ring`
  crypto backend) — no OpenSSL, no libssh2, no cmake. Host-key pinning and
  command execution behave as before.

### Added
- **Homebrew install.** `brew install dirge-code/dirge/dirge` installs a
  prebuilt binary (macOS + Linux); on macOS it avoids the Gatekeeper
  quarantine prompt of a downloaded tarball. The release workflow
  auto-bumps the tap formula on each tag.

## [0.5.0] - 2026-06-10

### Added
- **SQLite-backed project memory.** Memory moved off the flat `MEMORY.md` /
  `PITFALLS.md` files into a `memories` table in the per-project session DB
  (`.dirge/sessions/state.db`). Two-tier storage: hot entries inline in the
  prompt verbatim, and once the inline budget fills the least-salient entries
  demote to a searchable breadcrumb index (id + preview) the agent expands
  with `memory(action='expand')` or queries with `memory(action='search')`
  (FTS5). Removal tombstones rather than deletes (`restore` brings entries
  back). Legacy `MEMORY.md` / `PITFALLS.md` files are imported automatically
  on first load and parked as `*.imported`.
- **Cross-turn failure recovery checkpoint.** The repeat-loop guard only
  catches a model repeating the *same* call; a separate tracker counts
  consecutive errored tool results across turns (reset by any success) and,
  at a streak of three distinct failures, injects one structured recovery
  checkpoint asking the model to name the shared root cause and take a
  different next step. When one tool dominates the streak it's named so the
  model re-reads that tool's contract.
- **"Did you mean?" feedback.** An unknown tool name now gets a nearest-match
  suggestion (`ehco``echo`), an invalid enum argument lists the valid
  values plus the closest one, and `read` on a mistyped path suggests the
  near-miss neighbour in the same directory (`parserr.rs``parser.rs`).
- **Janet compression plugin + `/plugins` command.** Plugins can supply a
  custom compaction summary via an `on-compact` hook, and `/plugins` lists
  the loaded plugins.
- **Interactive DAP REPL** (`/dap-repl`) and a shared JSON-RPC framing layer
  for the debug-adapter client.

### Changed
- **Slash-command tab completion is on by default.** It was gated behind an
  experimental feature that never shipped in the default set; it's now a
  first-class `slash-completion` feature, default-on.
- **Memory guidance explains the frozen snapshot.** The agent is told its
  saved memory is injected as a session-start snapshot, so a fact saved
  mid-session becomes active next session — it no longer re-saves facts it
  doesn't see reappear.
- Oversized `bash` / `webfetch` output now truncates head + tail (was a
  buggier middle-out heuristic).

### Removed
- **Cross-session memory extractor** and the unused memory `confidence`
  field. The post-session orchestrator is now three stages (background
  review → skills curator → memory curator); the extractor re-derived what
  the per-session review already captures.

### Fixed
- A `read` cache hit returns the file content instead of a terse "unchanged"
  message, so a re-read after compaction isn't left empty.
- Compression: git-diff off-by-one and the truncation heuristics.
- Fresh-state panics, an FTS index issue, tool-status lifecycle bugs, and
  duplicate-result handling (DAP review round).
- Fail-closed permissions for the debug-adapter tools.

## [0.4.1] - 2026-06-08

### Fixed
- The `sandbox-microvm` feature now compiles on non-Linux hosts. The reflink
  fast path (`copy_file_range`) and the `dirge-microvm-runner` libkrun calls
  are Linux-only and were ungated, so `--features sandbox-microvm` (and
  `--all-features`) failed to build on macOS. They're now `cfg(target_os =
  "linux")`-gated, with a `std::fs::copy` fallback for file copies and a
  clear "Linux-only" stub for the runner. The sandbox itself still requires
  Linux + KVM at runtime; this only fixes the cross-platform build.

## [0.4.0] - 2026-06-08

### Added
- **Hardware-isolated microVM sandbox** (`--sandbox microvm`, opt-in behind
  the `sandbox-microvm` build feature). A per-session Linux microVM boots
  once via libkrun and runs every `bash` tool call inside it over SSH, with
  the workspace mounted via virtio-fs. Includes a pure-Rust OCI image puller
  (every layer SHA-256-verified against the manifest, no skopeo/buildah
  needed for remote images), ephemeral SSH keys with guest host-key pinning,
  rootfs snapshot/restore, the `/sandbox` slash commands (`attach`/`ssh`,
  `reboot`/`start`, `snapshot save|list|restore|delete`), the
  `dirge sandbox check` / `dirge sandbox setup` subcommands, and a
  `--microvm-image` flag. Requires `/dev/kvm` and `libkrun.so`. See
  [docs/microvm/]docs/microvm/INDEX.md.

  Experimental, and narrower than full isolation: only `bash` runs in the
  VM. The file tools (`read`/`write`/`edit`/`apply_patch`/`list_dir`/
  `find_files`) still operate directly on the host workspace, so the VM is a
  boundary for command execution, not for file access. See
  [docs/microvm/SECURITY.md]docs/microvm/SECURITY.md.
- **Memory entries now carry a UMP kind, identity, and lifecycle metadata.**
  Saved memories are classified by kind (working / semantic / procedural /
  identity / …) at capture time instead of all defaulting to one bucket, and
  record provenance and lifecycle fields used by eviction and recall.

### Changed
- **Memory compaction evicts by salience, not age.** When the store is full
  the least-salient entry is dropped first (ties broken oldest-first, so the
  prior behavior holds under uniform salience). Salience now derives from the
  entry's kind (transient working notes rank well below durable identity /
  semantic facts), so the useful memories survive longer.

### Security
- **Load-time threat scan on memory.** Entries that reach `MEMORY.md` /
  `PITFALLS.md` out-of-band (hand-edit, `git pull`) and so bypassed the
  capture-time check are now scanned on read, closing the rehydration gap for
  prompt-injection content smuggled into the memory files.

## [0.3.1] - 2026-06-05

### Changed
- **The TUI now renders as a single model-driven paint per event.** A
  `UiState` model is the single source of truth, and the screen (status
  line, input area, avatar, panels, scrollback) is painted as one effect
  when the model changes — with dirty-flag coalescing — replacing ~85
  scattered inline paint sites. No change in normal use; this is the
  groundwork for the input fix below.

### Fixed
- **Modal prompts no longer block the UI.** Permission prompts, the
  `question` questionnaire (including custom free-text answers), the
  `/plan` switch confirmation, and plugin confirm/select dialogs each ran
  in their own nested blocking read loop, which could freeze the interface
  while a prompt was up. They now route through a unified input state
  machine driven by the main event loop, so chat scroll, text
  selection/copy, and terminal resize stay live during a prompt, and user
  keystrokes take priority over the agent's output stream. Concurrent
  permission requests from a parallel tool batch queue safely instead of
  clobbering the active prompt.

## [0.3.0] - 2026-06-04

### Security
- **Plugin tools now route through the permission engine.** A Janet
  plugin-registered tool previously ran its handler with **no**
  allow/deny/ask check — arbitrary file/network/shell I/O bypassing
  authorization entirely. Plugin tools now go through the same `enforce`
  chokepoint as built-ins via a new high-risk `Operation::Plugin` (not
  builtin-allowed, not Accept-coerced, like MCP/bash): they prompt by
  default in standard mode, can be denied with `deny_tools`, and are
  allowed under yolo or a `/allow plugin_tool …` grant.

### Added
- **Agent profiles** (opt-in): `/agent <name>` activates a named persona
  that bundles a system prompt, a model, and a tool policy
  (`.dirge/agents/*.md`, `~/.config/dirge/agents/*.md`, or config `agents`,
  layered project > global > config). `/agent off` reverts. The `task` tool
  can spawn a subagent under a profile via `task(agent="<name>")`. See
  [docs/agents.md]docs/agents.md.
- **Shell integration** (the `:` prefix, zsh): an optional plugin to run
  `:<prompt>` from your normal shell — the answer prints and you stay in the
  shell; `:` commands share one session. See
  [shell-plugin/README.md]shell-plugin/README.md.
- **`--session <id>`**: resumes the session with that id if it exists, and
  **creates it under that exact id** otherwise — a stable id for scripts and
  the shell plugin.
- **`--no-color`**: collapses the entire TUI to the terminal's default
  foreground through a single theme chokepoint.
- **`Alt+X`**: drops queued mid-execution interjections without cancelling
  the running agent (`Ctrl+C` still cancels both).
- Role-routing keys `summarization_provider` and `subagent_provider` are now
  actually consumed: the former routes the in-loop compaction summarizer, the
  latter sets the default model for `task`-spawned subagents.

### Changed
- **Automatic compaction now runs LLM summarization.** Proactive
  turn-boundary folds at the high context-ratio threshold now produce a
  structured summary (via `summarization_provider` when configured, else the
  main model) instead of silently degrading to a prune-only pass — the
  in-loop summarizer was declared but never wired. The cheap tool-output
  cap/prune still runs first with no LLM call.
- **`/wt-merge` is now programmatic and conflict-safe.** It performs the
  merge directly (refuses on a dirty tree, `git merge --abort` on conflict,
  never force-deletes the worktree) instead of delegating to an unconstrained
  LLM prompt, and only returns to the main repo on a clean merge.
- **`/prompt` and `/agent` compose as independent layers.** Their
  `deny_tools` now union (an agent can no longer silently re-enable a tool an
  active prompt denied), and `/agent off` restores the prompt layer's prompt +
  denies and the pre-agent model.
- **`allow_tools` now caps MCP and plugin tools too** (via the `mcp_tool` /
  `plugin_tool` umbrellas), not just built-ins.
- **Phased `/plan`**: the plan phase now gets a true context reset
  (findings-only), matching its documented isolation; explore→plan forks run
  off the UI event loop.
- Model-family steering now tracks the active (swapped) model rather than the
  launch-time model, so `/model` and `/agent` swaps steer correctly.

### Fixed
- Compaction could leave an orphaned `tool_use`/`tool_result` pair
  (unbalanced history → provider 400); the fold window now snaps to
  user-message boundaries, and the tool-output prune handles block-array
  content (previously a silent no-op on real tool results).
- `edit_minified` is now classified as a mutating edit, so the
  verify-before-done gate and the repeat-loop/storm breaker treat it like
  `edit`/`apply_patch`.
- `--no-color` no longer leaks hard-coded green/red diff backgrounds.
- `/panel auto` threshold corrected to ≥152 cols (was documented as ≥100,
  where no gutter actually fits).
- The active DAP debug session is now torn down at process exit instead of
  relying on `Drop` of a `static` that never runs.
- Plugin `transform-context` / `on-compact` hooks no longer block a runtime
  worker thread (now `spawn_blocking` + timeout), and `message-end` fires in
  headless (`--print` / `--loop`) mode too.
- Background-shell concurrency cap is enforced atomically; `/mode yolo` warns
  at runtime when configured deny rules are made inert; `/allow add`
  validates against the single tool-name source of truth; a leaked git
  worktree is cleaned up if creation fails after `git worktree add`; an
  ignored plugin-provider re-registration is now surfaced.

## [0.2.4] - 2026-06-03

### Added
- **Debug Adapter Protocol (DAP) integration**: step-through debugging
  alongside the existing LSP client, hardened against the usual adapter
  failure modes (UB, hangs, panics).
- **Configurable terminal background**: themes can set a `background` color,
  and the built-in phosphor theme defaults to a soft charcoal `#222222`. The
  plain theme keeps the terminal's own background (`Reset`).
- **Snap-to-bottom on input**: typing in the prompt or pressing Down on a
  scrolled-up chat jumps straight back to the latest output instead of
  requiring a manual scroll.
- **Phased plan workflow** (`/plan <request>`, opt-in via
  `phased_workflow_enabled`): an explicit per-task command that runs
  explore → plan → implement → reviewer-runs-code loop. The explore and
  plan phases are context-isolated read-only forks; the implement phase
  is a normal streamed turn; a write-disabled reviewer fork then runs the
  code and emits a machine-parsed verdict, with `NEEDS_FIX` feeding a
  punch-list back for a bounded re-implement (`phased_workflow_max_review_cycles`,
  default 2). Ported from [vix]https://github.com/kirby88/vix. See
  [docs/agent-loop.md]docs/agent-loop.md#phased-plan-workflow-plan.
- **Minified tree-sitter read/edit** (`read_minified` / `edit_minified`):
  token-efficient file I/O that collapses a file to its structural
  skeleton — aggressive collapse for Rust/Java/Go, gap-preserving collapse
  for whitespace/ASI-sensitive grammars (Bash, Python, Ruby, Elixir, C/C++,
  TS, Clojure). Each gated on its `semantic-<lang>` feature.
- **Hard read-before-edit gate**: `edit`/`apply_patch` to a file never
  read this session is refused mechanically.
- **Thinking-stall watchdog**: the request-timeout backstop now injects a
  summary-reinjection nudge for graceful recovery from a stalled run.
- **Mandatory reason/intent fields** on the read/grep/glob/find/lsp tools
  (and bash anti-misuse fields), plus a **todo-completion nudge** that
  blocks a premature `end_turn` while todo items remain pending.
- Config keys `phased_workflow_enabled`, `phased_workflow_max_review_cycles`,
  and documentation for the pre-existing `dynamic_tool_search` and
  `context_depth_reminder_threshold` keys.

### Fixed
- **/plan busy indicator**: `/plan` now shows the standard busy state and
  clears the submitted text from the input box while the explore/plan forks
  run (previously it looked idle with the command still lingering), and the
  busy flag can no longer be stranded "running" by a failed repaint.
- **Resize scroll clamp**: enlarging the terminal while scrolled up no longer
  leaves a stale scroll offset that hid the newest output behind blank rows.
- **Idle Ctrl+C** now clears a typed-but-unsent draft instead of quitting
  outright; only an empty input line exits.
- **Home/End** moved to **Ctrl+Home/End** for chat scroll, freeing bare
  Home/End for the input editor's line-start/line-end as documented.
- Ctrl+J inside reverse-i-search no longer desyncs the search buffer.

### Acknowledgements
- Added [vix]https://github.com/kirby88/vix — the battle-tested Go coding
  agent the above agentic-loop features were ported from.

## [0.2.3] - 2026-06-02

### Added
- Unified permission/authorization engine (single Policy Decision Point):
  op-based rules, `/why` decision-trace command, atomic multi-claim bash.
- Input box scrolls to keep the cursor visible past the height cap, and
  Up/Down navigate across soft-wrapped display rows.
- Cohesive low-saturation phosphor palette (hue = action, brightness =
  importance), a dedicated soft "thinking" color, and syntax-highlighted
  `read` boxes. Critic/thinking colors are config-themeable.
- Config-driven plugin toggles (`plugins.<name>.{enabled, auto_start}`)
  and a bundled `backpressured` validation-gated loop plugin.

### Changed
- Lighter terminal UI: the heavy double-line frame is now light
  single-line/rounded, the side panels follow the main frame's theme
  color, and the input prompt is a simple `> `.
- Reasoning/thinking is suppressed by default (spinner + Ctrl+O to
  expand) to keep the conversation focused.

### Fixed
- Secrets in tool output are redacted before reaching the LLM / session
  transcript.
- Transient LLM connection failures ("error sending request") now retry
  with exponential backoff.
- Questionnaire custom answers soft-wrap instead of running off-screen.
- Edit results collapse the appended LSP diagnostics into a one-line
  summary (Ctrl+O to expand); diagnostic floods are summarized and the
  per-file cap tightened, so an unsupported language server no longer
  floods the chat.
- A configured `deny` rule is now terminal above a session allowlist.
- Resumed sessions keep persisting after a save (loaded-mtime refresh).

### Packaging
- Published to crates.io as the **`dirge-agent`** crate (the short
  `dirge` name was taken); the installed binary is still `dirge`:
  `cargo install dirge-agent`.

## [1.0.0]

First tagged release. dirge is a minimalistic, memory-efficient coding
agent in Rust with:

- A terminal UI with markdown rendering, scrollback, and an info panel.
- Configurable permission modes (standard / restrictive / accept / yolo)
  with op-based rules and session allowlists.
- Tree-sitter bash permission parsing and semantic code tools for
  TypeScript, Python, Clojure, Go, Ruby, Rust, Java, C, and C++.
- Claude-compatible skills, persistent project memory, subagents, MCP and
  LSP integration, and a Janet plugin system.
- Session save/load/resume with LLM-summarization compaction.

[Unreleased]: https://github.com/dirge-code/dirge/compare/v0.16.0...HEAD
[0.16.0]: https://github.com/dirge-code/dirge/compare/v0.15.0...v0.16.0
[0.4.1]: https://github.com/dirge-code/dirge/compare/v0.4.0...v0.4.1
[0.4.0]: https://github.com/dirge-code/dirge/compare/v0.3.1...v0.4.0
[0.3.1]: https://github.com/dirge-code/dirge/compare/v0.3.0...v0.3.1
[1.0.0]: https://github.com/dirge-code/dirge/releases/tag/v1.0.0