-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathMakefile
More file actions
1016 lines (806 loc) · 101 KB
/
Copy pathMakefile
File metadata and controls
1016 lines (806 loc) · 101 KB
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
# Makefile — agentic IDE harness (omp-based, Option A)
#
# Conventions:
# make test -> all tests (Bun harness + sidecar smoke)
# make demo-00 -> increment 0 demo (proves fail-closed on day one)
# make demo-<id> -> per-increment runnable proof
#
# The harness is TypeScript on Bun. The only Python is scanner-sidecar/,
# managed by uv. See CLAUDE.md and DECISIONS.md.
SHELL := /bin/bash
.DEFAULT_GOAL := help
BUN := bun
UV := uv
SIDECAR_DIR := scanner-sidecar
PY := $(UV) run --project $(SIDECAR_DIR) python
# ---------------------------------------------------------------------------
# Setup
# ---------------------------------------------------------------------------
.PHONY: install
install: install-harness install-sidecar install-hooks ## Install harness + sidecar deps + git hooks
.PHONY: install-hooks
install-hooks: ## Point git at .githooks/ so the pre-commit license-header hook runs
git config core.hooksPath .githooks
@echo "✓ core.hooksPath -> .githooks (pre-commit applies BUSL-1.1 headers to staged source)"
.PHONY: install-harness
install-harness: ## Install Bun/TypeScript harness deps
$(BUN) install
.PHONY: install-sidecar
install-sidecar: ## Create/sync the pinned Python sidecar venv
cd $(SIDECAR_DIR) && $(UV) sync
# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------
.PHONY: test
test: test-harness test-sidecar ## Run all tests
# The gate's scope is defined by EXCLUSION, never by positional patterns. `bun test desktop harness`
# reads like a directory scope and is not one: bun treats positional args as SUBSTRING matches against
# the whole path, so adding `tools` also selects every vendor/oh-my-pi/**/tools/** file. Measured on this
# repo: exclusion-only 357 files / 11 fail, versus `bun test desktop harness tools` 486 files / 125 fail.
# Each exclusion is a tree whose tests are not this gate's to run:
# desktop/release/** GENERATED. A packaged copy of this repo, so it double-counts every test in it.
# vendor/** NOT OURS: oh-my-pi's own suite. Gitignored (.gitignore:13), but bun walks it
# regardless. Including it reports 1659 files / 942 fail, which is why the
# documented gate had never once reproduced the numbers PROGRESS.md quotes.
# lucidaddon_audit/** OURS, but 11 independently-installed packages with their own package.json that
# `make install` does not prepare, so its 51 files fail on missing deps (ajv and
# friends) rather than on anything real. Use `make test-audit` after installing
# them. Excluded LOUDLY here rather than silently omitted by a hand-typed scope.
# See ADR-0303.
TEST_IGNORES := --path-ignore-patterns='desktop/release/**' --path-ignore-patterns='vendor/**' --path-ignore-patterns='lucidaddon_audit/**'
.PHONY: test-harness
test-harness: ## Bun test suite over first-party code (357 files). TEST_IGNORES above is load-bearing.
$(BUN) test $(TEST_IGNORES)
.PHONY: test-audit
test-audit: ## lucidaddon_audit/ (51 files, 11 packages). NOT part of `make test`: needs its own installs first.
cd lucidaddon_audit && $(BUN) test
.PHONY: test-sidecar
test-sidecar: ## Sidecar smoke test: one request in, well-formed response out
$(PY) -m pytest -q $(SIDECAR_DIR)/tests || \
(echo "sidecar tests failed" && exit 1)
# ---------------------------------------------------------------------------
# Increment 0 demo
# 1. headless omp round-trip via the echo provider (no network/keys)
# 2. scanner sidecar: clean string + zero-width-injected string
# 3. FAIL-CLOSED PROOF: kill the sidecar mid-call, assert the gate blocks
# ---------------------------------------------------------------------------
.PHONY: demo-00
demo-00: ## Increment 0: omp echo round-trip + scanner + fail-closed proof
@echo "== [1/3] omp echo-provider round-trip =="
$(BUN) run harness/scripts/demo00_omp_echo.ts
@echo "== [2/3] scanner clean vs poisoned =="
$(BUN) run harness/scripts/demo00_scanner.ts
@echo "== [3/3] FAIL-CLOSED: kill sidecar mid-call, expect BLOCK =="
$(BUN) run harness/scripts/demo00_failclosed.ts
@echo "== demo-00 OK =="
# The fail-closed proof is ALSO a permanent test, not just a demo.
# It lives in the harness suite so it can never silently regress.
.PHONY: test-failclosed
test-failclosed: ## Standalone run of the fail-closed regression test
$(BUN) test harness/security/gate.failclosed.test.ts
# ---------------------------------------------------------------------------
# Placeholders for later increments (fill in as you build)
# ---------------------------------------------------------------------------
.PHONY: demo-01
demo-01: ## Boundary contracts: emit events + ToolResult round-trip
$(BUN) run harness/scripts/demo01_contracts.ts
.PHONY: demo-02
demo-02: ## Cache-optimized prompt assembly: prefix bytes identical across tasks
$(BUN) run harness/scripts/demo02_prefix_hash.ts
.PHONY: demo-P2.1
demo-P2.1: ## P2.1: scan adversarial fixtures; each finding fires, clean corpus is FP-free
$(PY) $(SIDECAR_DIR)/demo_p2_1.py
.PHONY: demo-P2.3
demo-P2.3: ## P2.3: ingest a poisoned artifact -> artifact/scan/findings/sanitized rows
$(BUN) run harness/scripts/demo03_ingest.ts
.PHONY: demo-P2.4
demo-P2.4: ## P2.4: poisoned tool call blocked by the omp pre-hook + approval workflow
$(BUN) run harness/scripts/demo04_quarantine_hook.ts
.PHONY: demo-P3.1
demo-P3.1: ## P3.1: verification engine; security scan is a fail-closed completion precondition
$(BUN) run harness/scripts/demo05_verification.ts
.PHONY: demo-P3.2
demo-P3.2: ## P3.2: ingest telemetry JSONL into DuckDB (idempotent) + sample security queries
$(BUN) run harness/scripts/demo06_telemetry_ingest.ts
.PHONY: demo-P4.1
demo-P4.1: ## P4.1: memory layers (working/archive/semantic) + state artifacts
$(BUN) run harness/scripts/demo07_memory.ts
.PHONY: demo-P4.2
demo-P4.2: ## P4.2: security-aware compaction (summaries from sanitized; raw preserved)
$(BUN) run harness/scripts/demo08_compaction.ts
.PHONY: demo-P4.3
demo-P4.3: ## P4.3: semantic-promotion gate blocks suspicious-source promotions (keystone #2)
$(BUN) run harness/scripts/demo09_promotion_gate.ts
.PHONY: demo-P5.1
demo-P5.1: ## P5.1: parent/child run lineage + subagent dispatch with per-run scan lineage
$(BUN) run harness/scripts/demo10_lineage.ts
.PHONY: demo-P5.2
demo-P5.2: ## P5.2: sandbox profiles auto-downgrade + read-only security-review subagent
$(BUN) run harness/scripts/demo11_sandbox.ts
.PHONY: demo-P6.1
demo-P6.1: ## P6.1: remote-runner gate scans payload before dispatch; routes suspicious to review
$(BUN) run harness/scripts/demo12_remote_gate.ts
.PHONY: demo-P6.2
demo-P6.2: ## P6.2: safe export (MD/CSV/JSON); raw never rendered by default; export audited
$(BUN) run harness/scripts/demo13_safe_export.ts
.PHONY: demo-P7.1
demo-P7.1: ## P7.1: materialize the six security dashboard views to safe CSVs
$(BUN) run harness/scripts/demo14_dashboards.ts
.PHONY: demo-P7.2
demo-P7.2: ## P7.2: replay run tree/timeline + benchmark cache-hit per prompt-prefix version
$(BUN) run harness/scripts/demo15_replay_bench.ts
.PHONY: demo-P-LOC.1
demo-P-LOC.1: ## P-LOC.1: AI-LOC attribution — count AI-authored lines per model/repo/identity
$(BUN) run harness/scripts/demo16_ai_loc.ts
.PHONY: demo-ADR9A
demo-ADR9A: ## ADR-0009 Phase A: recall prior-session facts into a new session (suspicious never recalled)
$(BUN) run harness/scripts/demo17_recall.ts
.PHONY: demo-P-CODE.1
demo-P-CODE.1: ## P-CODE.1 (ADR-0030): git workspace diffstat this month + fail-closed omit of non-git dirs
$(BUN) run harness/scripts/demo_pcode1.ts
.PHONY: demo-P-TPS.1
demo-P-TPS.1: ## P-TPS.1 (ADR-0044): streaming output-token readout — output-only, prompt-excluded, provider-reconciled
$(BUN) run harness/scripts/demo_ptps1.ts
.PHONY: demo-P-SKILL.1
demo-P-SKILL.1: ## P-SKILL.1 (ADR-0045): gated skill import — clean .md writes to .omp/skills/, poisoned blocks at the gate
$(BUN) run harness/scripts/demo_pskill1.ts
.PHONY: demo-P-SKILL.4
demo-P-SKILL.4: ## P-SKILL.4 (ADR-0097): the Agent Skill directory - classify roots/trust, fail-closed re-scan locks a flagged skill, remove confined to project/user (immutable .agents refused)
$(BUN) run harness/scripts/demo_pskill4.ts
.PHONY: demo-P-SKILLREG.1
demo-P-SKILLREG.1: ## P-SKILLREG.1 (ADR-0098): the enterprise skills registry READER - Ed25519 verify + fail-closed scan-gate on install; unsigned/untrusted-key/poisoned blocked, clean installs as an untrusted registry row
$(BUN) run harness/scripts/demo_pskillreg1.ts
.PHONY: demo-P-SKILL.5
demo-P-SKILL.5: ## P-SKILL.5 (ADR-0101): Skill Studio - analyze recent work into candidate skills, codify each through the fail-closed gate (clean writes, poisoned blocks); analyze writes nothing
$(BUN) run harness/scripts/demo_pskill5.ts
.PHONY: demo-P-SKILLREG.2
demo-P-SKILLREG.2: ## P-SKILLREG.2 (ADR-0102): the skill publish seam - sign + publish a codified skill to the Local Skills Registry (remote target no-ops fail-safe), then round-trip it back through the reader into a registry row
$(BUN) run harness/scripts/demo_pskillreg2.ts
.PHONY: demo-P-KB.1
demo-P-KB.1: ## P-KB.1 (ADR-0099): the compiled KB - a clean doc compiles into a page graph, a poisoned source is quarantined (never compiled), a poisoned derived page is re-scanned + quarantined (never stored)
$(BUN) run harness/scripts/demo_pkb1.ts
.PHONY: demo-P-KB.2
demo-P-KB.2: ## P-KB.2 (ADR-0100): the hybrid retrieval router (vector | compiled | both, delimited + cited) + the kept-in-sync generator (idempotent re-ingest, contradiction-flagged, prior page retained)
$(BUN) run harness/scripts/demo_pkb2.ts
.PHONY: demo-P-KB.2b
demo-P-KB.2b: ## P-KB.2b (ADR-0099/0100 desktop): the desktop compiled-KB surface - ingest compiles into the process store, retrieve returns cited delimited hits, graph exposes pages+links, poisoned source quarantined
$(BUN) run desktop/scripts/demo_p_kb_1.ts
.PHONY: demo-P-GOAL.9
demo-P-GOAL.9: ## P-GOAL.9 (ADR-0054): /goal After-Action Report — tool calls/LOC/errors/websites graphs + stall guard
$(BUN) run harness/scripts/demo_pgoal9.ts
.PHONY: demo-P-GOAL.10
demo-P-GOAL.10: ## P-GOAL.10 (ADR-0055): /goal cross-run evaluation ledger — success rate, avg iters, failure breakdown
$(BUN) run harness/scripts/demo_pgoal10.ts
.PHONY: demo-P-GOAL.11
demo-P-GOAL.11: ## P-GOAL.11 (ADR-0056): /goal live spend meter + budget kill switch — halts an unattended run at a $ cap
$(BUN) run harness/scripts/demo_pgoal11.ts
.PHONY: demo-P-GOAL.12
demo-P-GOAL.12: ## P-GOAL.12 (ADR-0057): Pre-Flight Audit — readiness L0→L3, history awareness, interview, Loop Design report
$(BUN) run harness/scripts/demo_pgoal12.ts
.PHONY: demo-P-RAG.1
demo-P-RAG.1: ## P-RAG.1 (ADR-0058): local knowledge spine — scan-gated ingest, fail-closed block, offline cosine retrieval, delimited injection
$(BUN) run harness/scripts/demo_prag1.ts
.PHONY: demo-P-RAG.1b
demo-P-RAG.1b: ## P-RAG.1b (ADR-0063): real bge-small embedder — SEMANTIC retrieval (zero shared words), still scan-gated + delimited
$(BUN) run harness/scripts/demo_prag1b.ts
.PHONY: demo-P-RAG.1c
demo-P-RAG.1c: ## P-RAG.1c (ADR-0064): PDF -> text through the SAME scan gate — semantic retrieval from a PDF, corrupt PDF fails closed
$(BUN) run harness/scripts/demo_prag1c.ts
.PHONY: demo-P-BRIEF.1
demo-P-BRIEF.1: ## P-BRIEF.1 (ADR-0070): Executive Engineering Update from the repo's DECISIONS/PROGRESS — written brief + two-host podcast script, air-gap clean
$(BUN) run harness/scripts/demo_pbrief1.ts
.PHONY: demo-P-BRIEF.2
demo-P-BRIEF.2: ## P-BRIEF.2 (ADR-0071): the exec-update script → one WAV via the OpenAI-compatible (Kokoro) TTS backend; mock transport offline, LUCID_TTS_BASE_URL for live
$(BUN) run harness/scripts/demo_pbrief2.ts
.PHONY: demo-P-STT.1
demo-P-STT.1: ## P-STT.1 (ADR-0073): mic audio → text via the OpenAI-compatible (local Whisper) STT backend; mock transport offline, LUCID_STT_BASE_URL for live
$(BUN) run harness/scripts/demo_pstt1.ts
.PHONY: demo-P-ASKSAGE.1
demo-P-ASKSAGE.1: ## P-ASKSAGE.1 (ADR-0059): AskSage tool-loop diagnostics + tolerant extraction — wrapped replies recovered, empty turns flagged
$(BUN) run harness/scripts/demo_paskage1.ts
.PHONY: demo-B-KG.1
demo-B-KG.1: ## B-KG.1 (#112/#113/#114): KG interaction polish — large graph fits on open, idle CPU halts, forget is instant + snapshot-safe
$(BUN) run desktop/scripts/demo_b_kg_1.ts
.PHONY: demo-P-KG-REL.1
demo-P-KG-REL.1: ## P-KG-REL.1 (#109/ADR-0075): manual relate — authored edge lands in the store + persists; drag/multi-select interaction logic
$(BUN) run desktop/scripts/demo_p_kg_rel_1.ts
.PHONY: demo-B-KG.2
demo-B-KG.2: ## B-KG.2 (#115): export location is recoverable — persistent toast + Open folder / Copy path
$(BUN) run desktop/scripts/demo_b_kg_2.ts
.PHONY: demo-P-ENT.1
demo-P-ENT.1: ## P-ENT.1 (ADR-0068): enterprise managed-policy override — set + lock exec/egress/model knobs via GPO/MDM, only ever tightening, fail-safe to unmanaged
$(BUN) run harness/scripts/demo_pent1.ts
.PHONY: demo-P-KG-INGEST.1
demo-P-KG-INGEST.1: ## P-KG-INGEST.1 (#110/ADR-0076): non-blocking background ingest — progress countdown, fail-safe cancel, single-flight job
$(BUN) run desktop/scripts/demo_p_kg_ingest_1.ts
.PHONY: demo-P-KG-INGEST.1b
demo-P-KG-INGEST.1b: ## P-KG-INGEST.1b (#110/ADR-0076): group the throwaway "Extract DURABLE facts…" ingest sessions out of the chat list
$(BUN) run desktop/scripts/demo_p_kg_ingest_1b.ts
.PHONY: demo-P-VAULT-HINT.1
demo-P-VAULT-HINT.1: ## P-VAULT-HINT.1 (#111/ADR-0077): locked vault → content-free existence hint (agent offers to unlock; never decrypts)
$(BUN) run desktop/scripts/demo_p_vault_hint_1.ts
.PHONY: demo-P-KG-REL.2
demo-P-KG-REL.2: ## P-KG-REL.2 (#122/ADR-0078): custom relation labels — typed label round-trips through the store; blank defaults to "related"
$(BUN) run desktop/scripts/demo_p_kg_rel_2.ts
.PHONY: demo-P-KG-INGEST.2
demo-P-KG-INGEST.2: ## P-KG-INGEST.2 (#123/ADR-0079): bulk-clear ingest sessions — workspace-scoped, real chats survive, idempotent
$(BUN) run desktop/scripts/demo_p_kg_ingest_2.ts
.PHONY: demo-P-VAULT-HINT.2
demo-P-VAULT-HINT.2: ## P-VAULT-HINT.2 (#124/ADR-0080): fact count in the locked-vault hint — in-memory at lock, never on disk, never content
$(BUN) run desktop/scripts/demo_p_vault_hint_2.ts
.PHONY: demo-P-KG-INGEST.3
demo-P-KG-INGEST.3: ## P-KG-INGEST.3 (#125/ADR-0081): chat preempts a back-to-back ingest loop via the ChatGate (yields, then resumes)
$(BUN) run desktop/scripts/demo_p_kg_ingest_3.ts
.PHONY: demo-P-KG-REL.3
demo-P-KG-REL.3: ## P-KG-REL.3 (#130/ADR-0082): remove a relationship — optimistic edge removal + store.removeLink persists (only the targeted edge)
$(BUN) run desktop/scripts/demo_p_kg_rel_3.ts
.PHONY: demo-P-KG-SEARCH.1
demo-P-KG-SEARCH.1: ## P-KG-SEARCH.1 (#132/ADR-0083): find a node — case-insensitive substring matcher feeding highlight + center
$(BUN) run desktop/scripts/demo_p_kg_search_1.ts
.PHONY: demo-P-PERF.1
demo-P-PERF.1: ## P-PERF.1 (#134/ADR-0084): instant cached session list + transcripts (SWR) — paint cache, refresh, re-render only if changed; LRU-capped
$(BUN) run desktop/scripts/demo_p_perf_1.ts
.PHONY: demo-P-KG-INGEST.4
demo-P-KG-INGEST.4: ## P-KG-INGEST.4 (#136/ADR-0085): true ingest concurrency — dedicated util omp connection; fail-safe fallback; routing contract
$(BUN) run desktop/scripts/demo_p_kg_ingest_4.ts
.PHONY: demo-P-ABOUT.1
demo-P-ABOUT.1: ## P-ABOUT.1 (ADR-0087): About panel — single-sourced app version (v1.8.7), LUCID + TechLead 187 + BUSL-1.1 licensing, animated rail glyph
$(BUN) run desktop/scripts/demo_p_about_1.ts
.PHONY: demo-P-EXEC.1
demo-P-EXEC.1: ## P-EXEC.1 (ADR-0066): per-action exec approval — classifier (safe/risky/catastrophic), prompt interactive + block unattended, standing allows, managed denylist
$(BUN) run desktop/scripts/demo_p_exec_1.ts
.PHONY: demo-P-GOAL.13
demo-P-GOAL.13: ## P-GOAL.13 (ADR-0067): unattended loop Speed↔Risk dial — graded tiers T0-T4, loopVerdict (T4 always blocks, unset=safest), managed ceiling, AAR Blocks section
$(BUN) run desktop/scripts/demo_p_goal_13.ts
.PHONY: demo-P-ENT.2
demo-P-ENT.2: ## P-ENT.2 (ADR-0069): OCSF security audit export — each source → valid OCSF Detection Finding, fail-safe dispatcher (dead sink never blocks a turn)
$(BUN) run desktop/scripts/demo_p_ent_2.ts
.PHONY: demo-P-ROLE.1
demo-P-ROLE.1: ## P-ROLE.1 (ADR-0088): role-based onboarding — closed role set, fail-safe normalize (unknown->developer), calm per-role default landing surface, cosmetic-only (gate untouched)
$(BUN) run desktop/scripts/demo_p_role_1.ts
.PHONY: demo-P-ROLE.1b
demo-P-ROLE.1b: ## P-ROLE.1b (ADR-0089): first-run guided walkthrough — tailored per-role coachmark tour (opens on composer, closes on closer, no dangling targets), Back/Next/Skip card, replay-guard
$(BUN) run desktop/scripts/demo_p_role_1b.ts
.PHONY: demo-P-AVATAR.1
demo-P-AVATAR.1: ## P-AVATAR.1 (ADR-0251): the LUCID Agent role + immersive stage - closed role set grows by one behavioral role, bespoke no-rail tour, animated glyph, and the stylesheet hides both rails + inspector under .immersive
$(BUN) run desktop/scripts/demo_p_avatar_1.ts
.PHONY: demo-P-MASCOT.1
demo-P-MASCOT.1: ## P-MASCOT.1 (ADR-0251 pivot): LUCID the ninja mascot - frame-grid integrity (dims + palette), state machine priorities (victory on landed work), working-activity rotation, and beat-timeline frame picks
$(BUN) run desktop/scripts/demo_p_mascot_1.ts
.PHONY: demo-P-MASCOT.2
demo-P-MASCOT.2: ## P-MASCOT.2: the prompt-bar parkour mini ninja - route order (run/climb/sneak/pause/drop/rest), lane geometry, the silent-drop clip contract, gravity easing, direction alternation
$(BUN) run desktop/scripts/demo_p_mascot_2.ts
.PHONY: demo-P-AVATAR.4
demo-P-AVATAR.4: ## P-AVATAR.4 (ADR-0251): the LUCID Agent enter flow - fast-model preference order (Terra > Sonnet 5 > Flash, no pointless switch), one-gap-at-a-time readiness (provider > tts > stt), the one-time KG offer, exit model restoration
$(BUN) run desktop/scripts/demo_p_avatar_4.ts
.PHONY: demo-P-AVATAR.5
demo-P-AVATAR.5: ## P-AVATAR.5 (ADR-0251): voice tool approval - keyword-strict grammar (sentences never match), danger class demands the literal word after a spoken repeat-back, widening grants unreachable by voice, deny always easy
$(BUN) run desktop/scripts/demo_p_avatar_5.ts
.PHONY: demo-P-AVATAR.6
demo-P-AVATAR.6: ## P-AVATAR.6 (ADR-0251): the boot cinematic - real-signal stage lines, min-beat + hard-cap done gate (config-gated; voice/models never hold boot), ninja sprint choreography
$(BUN) run desktop/scripts/demo_p_avatar_6.ts
.PHONY: demo-P-REMOTE.12
demo-P-REMOTE.12: ## P-REMOTE.12 (ADR-0251): PWA push-to-talk - fail-closed PromptAudio validator (shape/mime/size/base64, both ends), audio-only guest prompts, additive frame compatibility
$(BUN) run desktop/scripts/demo_p_remote_12.ts
.PHONY: demo-P-REMOTE.13
demo-P-REMOTE.13: ## P-REMOTE.13 (ADR-0251): the invisible hourly reconnect - grace-window presentation (young flap = Live, real outage surfaces, terminal never masked); the 60-min cap + hourly re-verify stay
$(BUN) run desktop/scripts/demo_p_remote_13.ts
.PHONY: demo-P-GOVCUI.1
demo-P-GOVCUI.1: ## P-GOVCUI.1: first-run Government/CUI step - asks once if the user is a Government/GovCon user handling CUI; a "yes" walks a novice into the CUI-safe posture (AskSage gov gateway in LOCKDOWN) with the CIV routing endpoint PREFILLED + step-by-step token instructions. Pure core: decideGovOnboarding (ask/skip/auto-enable, exactly once; org-forced routing auto-enables) + planGovSetup (with a key -> CIV persisted + lockdown ON; no key -> endpoint prefilled but lockdown NEVER flipped, since a keyless lockdown leaves no gov model and the backend fail-closes)
$(BUN) run harness/scripts/demo_pgovcui1.ts
demo-P-NETDIAG.1: ## P-NETDIAG.1 (ADR-0090): in-app OAuth localhost-callback watcher - netstat/lsof parse, keeps loopback + all-interface listeners, flags a new callback-port listener as the bind-or-not evidence, read-only diagnostics (no gate verdict)
$(BUN) run desktop/scripts/demo_p_netdiag_1.ts
demo-P-TOOLFAIL.1: ## P-TOOLFAIL.1 (ADR-0093): honest failed/rejected tool-call chip - distinguishes ran-and-errored (failed) from did-not-run (rejected/unavailable), surfaces omp's own message, never implies a security denial
$(BUN) run desktop/scripts/demo_p_toolfail_1.ts
demo-P-EGRESS.2: ## P-EGRESS.2 (ADR-0094): a local-file browser open is labeled a local-file open (open-once/block, no host pin) not a website visit, http(s) egress unchanged, and the no-listener block is audited (folds in P-ENT.3)
$(BUN) run desktop/scripts/demo_p_egress_2.ts
demo-P-LOC.3: ## P-LOC.3 (ADR-0095): the AI-authored code ledger is discoverable (command-palette entry) and never silently vanishes (always rendered when a session is active, with an explicit empty state)
$(BUN) run desktop/scripts/demo_p_loc_3.ts
.PHONY: demo-P-LOC.4
demo-P-LOC.4: ## P-LOC.4 (ADR-0211): AI-authored lines reach the UI again - the gate holds agent_obs.duckdb read-write for the whole session, so the desktop's READ_ONLY aiLocSummary() lock-failed -> null -> "none yet" despite rows in the DB. Fix (mirrors turns/security/latency logs): the desktop appends every edit to a GUI-owned JSONL it can read live (same linediff count as the chat chip); the dashboard aggregates that lock-free. Proves count (write/edit/patch) + record (no-op on 0 lines) + read/aggregate roll-up + empty-null
$(BUN) run desktop/scripts/demo_p_loc_4.ts
demo-P-PREVIEW.1: ## P-PREVIEW.1 (ADR-0096): in-app browser preview - resolver renders local files the agent builds, gates remote (egress, P-PREVIEW.3), blocks the ambiguous; panel + screenshot-to-chat seam
$(BUN) run desktop/scripts/demo_p_preview_1.ts
demo-P-PREVIEW.2: ## P-PREVIEW.2 (ADR-0096): auto-surface the agent's freshly-written app - a write/edit of a previewable file (.html/.svg) lights up the Preview panel; reads + non-page writes never do
$(BUN) run desktop/scripts/demo_p_preview_2.ts
demo-P-PREVIEW.3: ## P-PREVIEW.3 (ADR-0096): hardened preview sandbox - opaque-origin <iframe> (scripts on, same-origin off), no escape tokens, all powerful features denied
$(BUN) run desktop/scripts/demo_p_preview_3.ts
demo-P-PREVIEW.3b: ## P-PREVIEW.3b (ADR-0096): a remote URL previews only through the egress gate - loads iff egress-approved AND https, opaque-origin; else stays gated (agent requests via egress flow)
$(BUN) run desktop/scripts/demo_p_preview_3b.ts
demo-P-PREVIEW.3a: ## P-PREVIEW.3a (ADR-0096): agent-invoked preview_open tool (read-tier, real TSchema) - registration never breaks omp, execute gates local .html/.svg, acp_backend drives the panel off the call title (live omp+Electron verifies invocation)
$(BUN) run desktop/scripts/demo_p_preview_3a.ts
demo-P-ENT.4: ## P-ENT.4 (ADR-0069): every per-action gate denial is auditable + attributed - explicit "denied by you" vs "fail-closed (turn ended / no response)"; closes the silent fail-closed-timeout gap
$(BUN) run desktop/scripts/demo_p_ent_4.ts
demo-P-GATE-DIAG.1: ## P-GATE-DIAG.1 (ADR-0066/0062): dev-mode diagnostics recording the interactive-check inputs + decision for every exec/egress permission request (Logs → Exec / egress gate decisions) — reveals WHY a tool was auto-denied with no prompt
$(BUN) run desktop/scripts/demo_p_gate_diag_1.ts
demo-P-PREVIEW.4: ## P-PREVIEW.4 (ADR-0096): RENDER local files in Preview via served-content + iframe srcdoc (Chromium blocks file:// from an http origin, so iframe.src=file:// never rendered)
$(BUN) run desktop/scripts/demo_p_preview_4.ts
demo-P-PREVIEW.4b: ## P-PREVIEW.4b (ADR-0096): serve the preview with its OWN per-frame CSP (iframe.src, not srcdoc) so the app's inline scripts RUN - a srcdoc frame inherits script-src 'self' and blocked them; connect-src 'none' still blocks egress
$(BUN) run desktop/scripts/demo_p_preview_4b.ts
demo-P-PREVIEW.3a-shot: ## P-PREVIEW.3a-shot (ADR-0096): the agent SEES its own UI - renderer caches a preview PNG, the preview_screenshot tool fetches it as ImageContent (read-tier); every failure path degrades to text
$(BUN) run desktop/scripts/demo_p_preview_3a_shot.ts
demo-P-PREVIEW.4c: ## P-PREVIEW.4c (ADR-0096): MULTI-FILE apps render by inlining their own relative css/js/img/fonts (link→style, script src→inline, img/url→data:) under the SAME frame CSP; remote/traversal refs refused
$(BUN) run desktop/scripts/demo_p_preview_4c.ts
.PHONY: demo-P-CHAT.1
demo-P-CHAT.1: ## P-CHAT.1 (ADR-0104): inline expandable code preview for tool steps - writes syntax-highlighted (Monaco), edits as green/red line diffs; proves the pure diff logic
$(BUN) run desktop/scripts/demo_p_chat_1.ts
.PHONY: demo-P-FS.1
demo-P-FS.1: ## P-FS.1 (ADR-0103): full-tree workspace folder browser - browse above home to the FS root / drives, with an optional managed workspaceRoots confinement
$(BUN) run desktop/scripts/demo_p_fs_1.ts
.PHONY: demo-P-FS.2
demo-P-FS.2: ## P-FS.2 (ADR-0253/0254): the browser build opens the REAL OS folder dialog through the local backend (modern Explorer picker, marker-anchored parse, escaped/argv-passed titles, cancel never re-prompts) + the frozen data-integration steer (prefix v10) routes prompt-stuffed datasets to MCP / RAG / secure vendor connections
$(BUN) test desktop/native_dialog.test.ts harness/prompt/assembler.test.ts
.PHONY: demo-P-NETWL.1
demo-P-NETWL.1: ## P-NETWL.1 (ADR-0106): curated network whitelist (domain wildcards + IP CIDR, internal/external, trust scopes) auto-allows egress under the managed ceiling; OS-encrypted credential vault fail-closes with no plaintext
$(BUN) run desktop/scripts/demo_p_netwl_1.ts
.PHONY: demo-P-NETWL.3
demo-P-NETWL.3: ## P-NETWL.3 (ADR-0106): enforce project/loop trust scopes + per-loop call budget (first N auto-allow, then block), all under the managed ceiling
$(BUN) run desktop/scripts/demo_p_netwl_3.ts
.PHONY: demo-P-KEYS.2
demo-P-KEYS.2: ## P-KEYS.2 (ADR-0107): credential rotation visibility (age/due/expiry, non-secret) + manual rotate-in-place (same ref, fail-closed)
$(BUN) run desktop/scripts/demo_p_keys_2.ts
.PHONY: demo-P-PERF.2
demo-P-PERF.2: ## P-PERF.2 (ADR-0129): power/spec-aware perf tiers — battery→calm capped graph, low battery→viz paused (agent access untouched), poll backoff, user override
$(BUN) run desktop/scripts/demo_p_perf_2.ts
.PHONY: demo-P-PERF.3
demo-P-PERF.3: ## P-PERF.3 (ADR-0130): KG layout continuity — re-open is a static paint (0 sim frames), refresh nestles newcomers, cold open exits on energy, positions never touch disk
$(BUN) run desktop/scripts/demo_p_perf_3.ts
.PHONY: demo-P-PERF.4
demo-P-PERF.4: ## P-PERF.4 (ADR-0131): incremental session index (warm polls parse nothing) + tail-first transcript pages + AC-only prefetch gate
$(BUN) run desktop/scripts/demo_p_perf_4.ts
.PHONY: demo-P-PERF.5
demo-P-PERF.5: ## P-PERF.5 (ADR-0132): switch hygiene - optimistic model switch, debounced lastModel write-behind (read-your-writes), memoized settings load, memoized picker
$(BUN) run desktop/scripts/demo_p_perf_5.ts
.PHONY: demo-P-NETWL.5
demo-P-NETWL.5: ## P-NETWL.5 (ADR-0108): egress posture — allow-all + web-search toggles; whitelist enforces only when allow-all is off; still prompts for public IPs / foreign TLDs; managed clamp
$(BUN) run desktop/scripts/demo_p_netwl_5.ts
.PHONY: demo-P-AGENT.1
demo-P-AGENT.1: ## P-AGENT.1 (ADR-0133): Agent Spec — a valid v1 DAG round-trips through DuckDB (migration 0010); a cyclic/invalid spec is refused fail-closed and never persisted
$(BUN) run harness/scripts/demo_p_agent_1.ts
.PHONY: demo-P-AGENT.3
demo-P-AGENT.3: ## P-AGENT.3 (ADR-0133): the compiler buildAgent(spec) -> AgentBundle (system prompt + generated omp allow-list extension + manifest); the emitted extension enforces the allow-list; invalid spec refused
$(BUN) run harness/scripts/demo_p_agent_3.ts
.PHONY: demo-P-AGENT.5
demo-P-AGENT.5: ## P-AGENT.5 (ADR-0133): untrusted-spec quarantine gate vs the real scanner — imported/poisoned specs are quarantined + blocked from auto-running; only a clean local spec is trusted + runnable
$(BUN) run harness/scripts/demo_p_agent_5.ts
.PHONY: demo-P-AGENT.6
demo-P-AGENT.6: ## P-AGENT.6 (ADR-0133): enterprise export — package a compiled agent portably for electron/web/cloud with a tamper-evident content digest; verifyExport catches modification
$(BUN) run harness/scripts/demo_p_agent_6.ts
.PHONY: demo-P-AGENT.4-live
demo-P-AGENT.4-live: ## P-AGENT.4-live (ADR-0133): run a BUILT agent on a REAL Claude model (Haiku). NEEDS a model + network — NOT part of `make test`. Proves the agent runs + follows its compiled spec, AND its allow-list extension hard-blocks disallowed tools.
$(BUN) run harness/scripts/demo_p_agent_4_live.ts
$(BUN) run harness/scripts/demo_p_agent_4_live_enforce.ts
.PHONY: demo-P-AGENT.8.1
demo-P-AGENT.8.1: ## P-AGENT.8.1 (ADR-0134): secret guardrail — agents DECLARE credential names (SecretRef); a secret VALUE embedded in a spec is refused at compile + save (secrets belong in the vault)
$(BUN) run harness/scripts/demo_p_agent_8_1.ts
.PHONY: demo-P-AGENTFW.1
demo-P-AGENTFW.1: ## P-AGENTFW.1 (ADR-0147): agent-firewall MCP \u2014 scans both directions vs a remote ACP agent (hermes/openclaw); quarantines poisoned replies, neutralizes delimiter breakout, blocks outbound hidden vectors, fails closed when the scanner dies
$(BUN) run harness/scripts/demo_pagentfw1.ts
.PHONY: demo-P-FLEET.1
demo-P-FLEET.1: ## P-FLEET.1 (ADR-0268): async job handles through the agent-firewall - dispatch/job_status/cancel + bounded-wait prompt over ONE gated path; fan-out across connections, serialization within one, fail-closed per job, deadline cleanup, idempotent retries
$(BUN) run harness/scripts/demo_pfleet1.ts
.PHONY: demo-P-FLEET.L1
demo-P-FLEET.L1: ## P-FLEET.L1 (guard evolved by P-FLEET.L2): local lanes - concurrent gated headless LUCID agents under the sustained-pressure guard (a burst is free, a held line is not), fail-closed approvals (needs-approval glow), cancel/stop hygiene, metadata-only fleet status for the master agent
$(BUN) run harness/scripts/demo_pfleetl1.ts
.PHONY: creator-backend-plan
creator-backend-plan: ## Print the exact commands the Creator-backend setup would run against a remote GPU host, executing NOTHING (pass your host: make creator-backend-plan HOST=gpu-box USER=me). Then drop --dry-run to do it for real.
$(BUN) run tools/creator-backend/setup-backend.ts --host $(or $(HOST),gpu-box) $(if $(USER_AT),--user $(USER_AT),) --dry-run
.PHONY: verify-creator-comfy
verify-creator-comfy: ## CREATOR-1/IMG verification: drives the REAL product code (probe -> capability attestation -> upload -> substitute -> submit -> poll -> read back -> store) against a ComfyUI-shaped fixture, so the whole path is provable with no ComfyUI, no GPU and no network. Point it at your own server with: bun run harness/scripts/verify_creator_comfy.ts --url http://host:8188 --workflow ./graph.json
$(BUN) run harness/scripts/verify_creator_comfy.ts
.PHONY: demo-CREATOR-5
demo-CREATOR-5: ## CREATOR-5 (ADR-0289): the mixer - N takes played AT ONCE and summed to one file, where two layers are the EXACT arithmetic sum at every frame, the same graph renders byte-identical audio twice, and a track silenced by mute, by another track's solo, or by a muted bus contributes exactly nothing (byte-identical to the same graph with that track REMOVED, with the reason named). Clip x track x bus x master levels multiply to a predicted sample, fades and envelopes are half their level at their midpoints, equal-power pan holds total power at 1, and a hot mix REPORTS its true peak and every clipped sample instead of quietly normalizing: headroom is applied only when the caller asks and the exact gain comes back. A missing source and a rate mismatch are refused by name, an edited CREATOR-2 timeline lifts onto a mix track, and a saved mix is a NEW remix naming every input while its inputs keep every byte. A library holding nothing decodable claims NO format at all, which the pane's shape gate accepts as honest while refusing half a format, and the render answer is pinned key for key: every measurement present (clipped 0 included), the headroom factor only when it was asked for, and a refusal carrying its reason and nothing it never measured
$(BUN) run harness/scripts/demo_creator5.ts
.PHONY: demo-CREATOR-3
demo-CREATOR-3: ## CREATOR-3 (ADR-0287): the video and 3D pipelines, end to end. A capability no LIVE probe attested is refused before one byte leaves the machine (and an expired probe attests nothing, so staleness refuses through the same gate); a governor refusal is a written-down `refused` job quoting the percent and the duration it held; a workflow with an unfilled placeholder is never submitted. An artifact's type comes from its own MAGIC BYTES, so a server claiming video/mp4 while sending PNG has its output refused by name and stores nothing. THE SCAN GATE IS FAIL-CLOSED: a dead scanner, a quarantining finding, or a malformed verdict each BLOCK the artifact before it touches the disk, and the job says which. Video and 3D outputs are read by output key and extension (an animated webp is a video, not a still), the /ws stream is telemetry that cannot hang, revive, or corrupt a render (a foreign prompt id, a truncated binary frame and a silent socket are all proven harmless), frame capture is reproducible or reports which of the two ways it lied, Blender runs as a fixed argv with no shell and quotes its own failing line, and a model manifest stays a claim until the probe agrees. Four sections run the REAL product code against a REAL server process over real HTTP and a real websocket
$(BUN) run harness/scripts/demo_creator3.ts
.PHONY: demo-CREATOR-2
demo-CREATOR-2: ## CREATOR-2 (ADR-0286): the follow-along audio editor - alignment DERIVED from the take's own energy is labeled derived and capped below vendor confidence with the reason shown verbatim, a deleted word closes the timeline by exactly its span (and the render's byte length follows), a dragged span re-orders audio without creating or destroying a sample, and a re-rendered span changes ONLY the bytes inside it (the audio before and after comes back byte for byte), with undo re-rendering to the original file, a deterministic render, and a missing source refused BY NAME instead of substituted with silence
$(BUN) run harness/scripts/demo_creator2.ts
.PHONY: demo-CREATOR-1
demo-CREATOR-1: ## CREATOR-1 (ADR-0292): capability PROBES (ComfyUI from its installed nodes, ElevenLabs from its documented model flags, a user-run service proves reachability and admits nothing more, a desktop app proves it is on disk) that turn registry `configured` into a truthful `ready` and EXPIRE, plus the durable job ledger - legal transitions only, the governor's measurement recorded per job, a refusal written down with its reason, and a cancel that is a request until the runner confirms
$(BUN) run harness/scripts/demo_creator1.ts
.PHONY: demo-CREATOR-IMG
demo-CREATOR-IMG: ## CREATOR-IMG (ADR-0291): sprite sheets, animated GIFs, and memes encoded INSIDE LUCID (valid PNG chunks, an LZW stream that decodes back to its own indices, text that always fits), a model dropdown that is a live probe of the user's own ComfyUI install, a workflow with an unfilled placeholder REFUSED rather than guessed, and artifacts that carry the prompt/model/sha256 that produced them
$(BUN) run harness/scripts/demo_creator_img.ts
.PHONY: demo-CREATOR-0
demo-CREATOR-0: ## CREATOR-0 (ADR-0279..0284, ADR-0304): the Creator flavor - a second LUCID on its own identity/port/data root, Creator Mode gated to that build with AGENT security semantics, an honest integration registry (Suno generation is bring-your-own-endpoint, ElevenLabs Studio editing is vendor-app-only), evidence-based CPU/GPU admission where unknown is never idle, a local track library (listen/review/remix/re-prompt) that needs no provider API, and a release channel that cannot be crossed with Agent's in either direction (Creator updates from its own fixed-URL feed, and no Creator release can move the repo pointer Agent's installed base resolves through)
$(BUN) run harness/scripts/demo_creator0.ts
.PHONY: demo-P-FLEET.L2
demo-P-FLEET.L2: ## P-FLEET.L2 (ADR-0273): UNLIMITED lanes gated only by SUSTAINED pressure (90% held 30s - a burst never refuses, a blind sample never counts as load, no evidence fails open), lanes spawned from real GitHub/GitLab/Azure DevOps remotes via the OS folder dialog, per-HOST credentials in the OS-encrypted vault (scoped ref -> env round-trip, never offered cross-host, rides an Authorization header not the URL, redacted from errors), and the minimized status-bar snapshot (one colored dot + count per lane state, needs-approval first)
$(BUN) run harness/scripts/demo_pfleetl2.ts
.PHONY: demo-P-FLEET.L3
demo-P-FLEET.L3: ## P-FLEET.L3 (ADR-0274): lane FIDELITY - a write/edit tool call's authored code crosses the lane wire as a structured payload (P-CHAT.1 rawInput contract, path resolved against the LANE's cwd) so cards render real diff chips; pasted images ride as ACP image blocks exactly like the master chat (replay memory keeps the COUNT, never the base64); and staged prompts wait in a capped manager-owned FIFO per lane (reorder/remove, drained in order when idle, refused loudly at 8, never crossed into a busy lane)
$(BUN) run harness/scripts/demo_pfleetl3.ts
.PHONY: demo-P-FLEET.L4
demo-P-FLEET.L4: ## P-FLEET.L4 (ADR-0274): lanes that SURVIVE - no lane turn clock (a mid-turn child crash lands error in milliseconds, event-driven, never a 600s deadline), error is a recoverable state (Retry re-sends the last prompt, Respawn revives IN PLACE on the same lane id with the transcript carried - capability-gated session/load when the agent offers it, delimited-transcript preamble otherwise), fail-closed survives recovery (an ask open at death dies as a DENY and the revived lane RE-ASKS a human), and a user-stopped lane is refused by prompt but revived by explicit respawn with memory intact
$(BUN) run harness/scripts/demo_pfleetl4.ts
.PHONY: demo-P-FLEET.L5
demo-P-FLEET.L5: ## P-FLEET.L5 (ADR-0274): histories + the reviewable TIMELINE - every lane spawn/recovery NAMES its omp session in a durable JSONL ledger (~/.omp/lucid-fleet-lanes.jsonl), so the .jsonl histories omp already persists become attributable; one timeline surface merges master chats + lane sessions + kg-ingest throwaways across EVERY workspace, newest first, lanes labeled with their names (latest ledger record wins); a stopped lane's transcript still opens (review is an index over existing files, never a second recording); torn ledger lines skip and a missing ledger degrades labels, never the surface
$(BUN) run harness/scripts/demo_pfleetl5.ts
.PHONY: demo-P-FLEET.L7
demo-P-FLEET.L7: ## P-FLEET.L7: lane tool-call FIDELITY + a transcript that survives its own stream - a code-less call (bash/read/search) now carries the bounded, code-stripped rawInput so "the command used" is drillable (before L7 the chevron had literally nothing to open), an edit still carries `code` and never a duplicate `input`, hasBody and laneChipBody agree BY CONSTRUCTION so a dead chevron is impossible, a lane chip DELEGATES kind/detail/diffstat to the same answer_chips.toolChip the master composer uses (the two surfaces cannot disagree), ids are monotone and never reused (the precondition for patching DOM instead of the innerHTML-per-token rebuild that destroyed mid-stream text selection and slammed every open tool call shut), an oversized command or diff is clipped AND SAYS SO, and the lane forwards omp's MEASURED context/window/cost while inventing no output figure
$(BUN) run harness/scripts/demo_pfleetl7.ts
.PHONY: demo-P-FLEET.L8
demo-P-FLEET.L8: ## P-FLEET.L8: promote a fleet lane into the MAIN composer and pull it back - promotion is an ATTACH, not a handoff (the lane's omp child, ACP session id, cwd, and model are byte-identical before and after), which is the only design that works MID-TURN and makes demote instant; a `working` lane promotes with NO refusal because switching on the fly is the ask, while stopped/error refuse naming respawn and an UNKNOWN status refuses fail-closed; exactly one lane may hold the composer (a second promote releases the first); promote and demote each write a durable ledger line naming the lane, folder, MODEL AT THAT MOMENT, and turns carried, so a stretch driven from the main chat is never indistinguishable from lane work; and the composer is seeded from the lane's transcript with tool bookkeeping folded to one note and the prose byte-preserved
$(BUN) run harness/scripts/demo_pfleetl8.ts
.PHONY: demo-P-FLEET.L10
demo-P-FLEET.L10: demo-P-FLEET.L8 ## P-FLEET.L10 (runs with P-FLEET.L8): DISMISS a lane so its card leaves the grid. `stop` only PARKED a lane (transcript readable, respawnable in place) and nothing removed it from the map, so a finished lane held a grid column until the whole app restarted. The close button is now a two-step gesture: stop, then dismiss, because one click must never be able to destroy work in flight - a mid-turn dismissal is REFUSED with the fix named. Dismissing a PROMOTED lane releases the composer first, or the main composer strands on a lane id that no longer resolves and every later prompt fails with "unknown lane". Dismissal is idempotent, drops the in-memory transcript, and the lane's durable ledger line SURVIVES, so a dismissed lane is still labeled and openable on the timeline (P-FLEET.L5: review is an index over files omp already persists, never a second recording)
.PHONY: demo-P-HEALTH.1
demo-P-HEALTH.1: ## P-HEALTH.1: the harness watches its OWN sessions so a stalled long run never needs the whole app restarted - the ok/quiet/probe/recover ladder with inclusive thresholds, an idle session always ok, and the LOAD-BEARING refusal: an OPEN TOOL CALL caps the verdict at `quiet` at 3min, 7min, 30min, and 10 HOURS (ADR-0263 deleted the wall-clock cutoff because it killed exactly the turns worth running, and nothing here reintroduces one), with only a DEAD child overriding because that is evidence rather than a guess; bounded attempts mean no nag loop and no respawn loop (past the budget it SAYS it stopped trying), any real activity restores the budget, an unreadable clock authorizes nothing (NaN/Infinity/negative all yield ok even with a dead child), the probe is an operator note that asks for status AND says to continue so it can never read as a stop order, and LIVE a real lane keeps its id/turns/transcript while a lane the USER stopped is never auto-revived
$(BUN) run harness/scripts/demo_phealth1.ts
.PHONY: demo-P-HEALTH.2
demo-P-HEALTH.2: demo-P-HEALTH.1 ## P-HEALTH.2 (runs with P-HEALTH.1): a recovered session now RESUMES THE RUN the recovery interrupted. P-HEALTH.1's `recover` reloads the same session id so the conversation survives, but dropping the omp child rejects the in-flight session/prompt, so the turn printed "[agent unavailable]" and settled: the session was healthy again and the WORK was gone, with nothing telling the user which, so they still had to notice the stall and re-ask. The run is now re-sent on the recovered session with a short operator note (do NOT start over, re-read and verify any file you were part-way through writing) and the user is told plainly that the stalled session is restarting and picking up where it left off. The refusals are the design: a user STOP is never resumed (Stop means stop), one mark authorizes exactly ONE resume so a repeat failure cannot reuse it, a session that failed to reload is never resumed rather than talking to a phantom, and the budget is per RUN and NOT refilled by activity - so wedge/resume/wedge/resume/wedge STOPS and says the work so far is saved, even though that same activity deliberately refills the health episode's own probe/recover budget.
$(BUN) run harness/scripts/demo_phealth2.ts
.PHONY: demo-P-TOKENS.1
demo-P-TOKENS.1: ## P-TOKENS.1 / P-FLEET.L9: the token-spend accounting behind the fleet card's context-fill chip (the composer popover it was first built for was removed at the user's request, ADR-0315; the module stays because each lane card folds its own usage and reads meterBadge for the value and the escalation thresholds) - the central assertion is NEGATIVE: omp reports only context fill, window, and cost, so a metric that never arrived reads "not reported", never a plausible $0.00 or 0 tokens a user would budget against. A REPORTED zero renders $0.00 and stays measured because a reported zero is a fact while an unreported one is an invention; every output row is unmeasured with a hint containing "estimate"; per-call context delta is ATTRIBUTION that says so when unbracketed rather than showing 0; 70 calls keep the newest 60 and no reducer mutates its input. Plus the geometry: dragging a card's BOTTOM edge DOWN grows it (the grip follows the cursor, cards top-anchored so the row holds still), the dock's north edge keeps its BOTTOM edge pinned even once height pins at the minimum, 7 corrupt saved layouts degrade to empty without throwing, and resizeShape composes with share_dock's viewport clamp
$(BUN) run harness/scripts/demo_ptokens1.ts
.PHONY: demo-P-MCP-GATE.1
demo-P-MCP-GATE.1: ## P-MCP-GATE.1 (ADR-0148): in-process MCP tool_result gate — poisoned MCP result withheld, clean result delimited+labeled untrusted, LOCAL tool results untouched (source-scoped), fail-closed
$(BUN) run harness/scripts/demo_pmcpgate1.ts
.PHONY: demo-P-LOCAL.1
demo-P-LOCAL.1: ## P-LOCAL.1 (ADR-0135): Local Providers — declare a self-hosted / custom OpenAI-compatible LLM (Ollama, llama.cpp, vLLM, DGX-over-VPN); validate fail-closed, emit the omp --config overlay (secret from the vault, skipped if absent), persist WITHOUT the secret
$(BUN) run desktop/scripts/demo_p_local_1.ts
.PHONY: demo-P-VISION.1
demo-P-VISION.1: ## P-VISION.1 (ADR-0136): paste/drop a screenshot into the prompt bar — validate fail-closed (image-only, size/count caps), emit an omp image content block (base64, prefix stripped), and render a thumbnail strip that never interpolates the data URL (XSS-safe)
$(BUN) run desktop/scripts/demo_p_vision_1.ts
.PHONY: demo-P-PROV.1
demo-P-PROV.1: ## P-PROV.1 (ADR-0210): first-party enterprise providers - exposes omp-native Azure OpenAI (key + AZURE_OPENAI_* config), GitHub Copilot OAuth (device-flow broker; the Business/Enterprise "easy button" + a GHE-domain prompt), and Google Vertex AI = Gemini Enterprise (GOOGLE_CLOUD_API_KEY or ADC: project+location+credentials), and adds GOOGLE_CLOUD_PROJECT to the Gemini card - the missing env without which omp aborts Workspace/Enterprise Gemini OAuth. Extra fields ride the same setKey->env->omp seam as the primary key (no new storage); proves the descriptors + secret-masked/non-secret-echoed field reporting
$(BUN) run desktop/scripts/demo_p_prov_1.ts
.PHONY: demo-P-IMG.1
demo-P-IMG.1: ## P-IMG.1 (ADR-0208): generated/tool images inside the chat reply - lifts image content blocks OUT of an (UNTRUSTED) tool result through the strict image-data-URL gate (ACP-wrapped AND bare omp blocks; SVG/non-base64/oversized dropped fail-closed, count capped), renders them inline via the safe img.src-property idiom with a Download (safe filename, no traversal) and a "Send to preview" that builds a self-contained, CSP-safe wrapper (data: URI, no <script>) so the markup canvas + Screenshot->chat let the user iterate. Pure core verified here; the app.ts render + preview route are typechecked
$(BUN) run desktop/scripts/demo_p_img_1.ts
.PHONY: demo-P-NVIM.1
demo-P-NVIM.1: ## P-NVIM.1 (ADR-0150): Neovim + terminal integration — `lucid tui` is the gated command minus `acp` (gate first, policy, passthru last), fail-closes (dead scanner ⇒ no spawn), and the Neovim plugin's pure helpers pass headless nvim
$(BUN) run harness/scripts/demo_pnvim1.ts
.PHONY: demo-P-NVIM.6
demo-P-NVIM.6: ## P-NVIM.6: the `lucid kb` knowledge-graph viewer behind :LucidKb — seeds a temp KG, then proves kbList/kbPages/kbShow/kbSearch + runKb (list|pages|show|search, --json vs text, exit codes) read the shared ~/.omp registry; the neovim pure helpers ride the headless spec (demo-P-NVIM.1)
$(BUN) run harness/scripts/demo_pnvim6.ts
.PHONY: demo-P-THEME.1
demo-P-THEME.1: ## P-THEME.1 (ADR-0160): the LUCID skin for gated terminals — themes/lucid.json resolves, session_start provisions (idempotent) + setTheme("lucid"), fail-OPEN cosmetics never weaken fail-CLOSED, and the theme -e rides behind the gate -e
$(BUN) run harness/scripts/demo_ptheme1.ts
.PHONY: pwa-build
pwa-build: ## P-REMOTE.3 (ADR-0226/0227): bundle the phone guest PWA (tools/remote-pwa) into a static site under dist/
$(BUN) run tools/remote-pwa/build.ts
.PHONY: demo-P-BRAND.1
demo-P-BRAND.1: ## P-BRAND.1 (issue #314): the LUCID TUI welcome — lucid_tui.config.yml suppresses omp's welcome (startup.quiet), renderWelcomeLines names LUCID never omp, LUCID_WELCOME=off restores omp's box, fail-OPEN cosmetics never weaken fail-CLOSED, and the welcome -e rides behind the gate + theme -e with the --config overlay
$(BUN) run harness/scripts/demo_pbrand1.ts
.PHONY: nvim-plugin-split
nvim-plugin-split: ## Split extensions/neovim -> the standalone `lucid.nvim` branch (add PUSH=1 to force-push to origin)
@sha=$$(git subtree split --prefix=extensions/neovim HEAD); \
echo "lucid.nvim split -> $$sha"; \
if [ "$(PUSH)" = "1" ]; then git push -f origin "$$sha:refs/heads/lucid.nvim"; else echo "(dry run — add PUSH=1 to publish; CI does this on every master push)"; fi
.PHONY: demo-P-PREVIEW.6a
demo-P-PREVIEW.6a: ## P-PREVIEW.6a (ADR-0153): the agent reviews its work live in the preview — a preview tool-call (screenshot/open/inspect/action) maps to a user-facing label that glows the panel + shows a "reviewing/testing" pill; non-preview tools never trigger it
$(BUN) run desktop/scripts/demo_p_preview_6a.ts
.PHONY: demo-P-PREVIEW.6b
demo-P-PREVIEW.6b: ## P-PREVIEW.6b (ADR-0153): the agent READS the live preview DOM — a held tool→server→renderer→iframe relay + a READ-ONLY postMessage bridge injected into the sandboxed preview (no eval/mutation), fail-closed on timeout
$(BUN) run desktop/scripts/demo_p_preview_6b.ts
.PHONY: demo-P-PREVIEW.6c
demo-P-PREVIEW.6c: ## P-PREVIEW.6c (ADR-0153): the agent CLICKS/TYPES in the live preview by CSS selector — structured actions through the same relay + bridge (fixed allowlist click/type/focus/scroll; still no eval/innerHTML)
$(BUN) run desktop/scripts/demo_p_preview_6c.ts
.PHONY: demo-P-DESIGN.1
demo-P-DESIGN.1: ## P-DESIGN.1 (ADR-0154): the agent honors a workspace DESIGN.md — read + wrapped as a <design-invariants> block and re-delivered in the user-turn preamble EVERY turn (never the frozen prefix); no DESIGN.md → no block
$(BUN) run desktop/scripts/demo_p_design_1.ts
.PHONY: demo-P-MARKET.1
demo-P-MARKET.1: ## P-MARKET.1 (ADR-0158): the Plugin Marketplace popup - Excalidraw pinned first, then Obsidian's top-ranked integrations by community downloads; searchable scrim-modal on the About//goal conventions; rows only open their GitHub repo (installs are P-MARKET.2)
$(BUN) run desktop/scripts/demo_p_market_1.ts
.PHONY: demo-P-FIGMA.1
demo-P-FIGMA.1: ## P-FIGMA.1 (ADR-0154): /figma — parse a Figma file URL → key, walk the doc → top frames (capped), build a design-board HTML with frames inlined as PNG data URLs (names escaped, only data:image src) for the sandboxed preview
$(BUN) run desktop/scripts/demo_p_figma_1.ts
.PHONY: demo-P-FIGMA.2
demo-P-FIGMA.2: ## P-FIGMA.2 (ADR-0154): after /figma import, a guided step — review the design / open-or-build DESIGN.md; an agent write to DESIGN.md is detected (no false positives) → `design-available` pops it out in the IDE, then it's honored as standing guidance
$(BUN) run desktop/scripts/demo_p_figma_2.ts
.PHONY: demo-P-SANDBOX.1
demo-P-SANDBOX.1: ## P-SANDBOX.1 (ADR-0157): the runtime execution boundary — sandbox seam (bwrap/noop), canNetwork/canExec caps ENFORCED at the omp spawn (suspicious-chain downgrade = real --unshare-net), managed require-isolation fail-closes, disclosed passthrough elsewhere
$(BUN) run harness/scripts/demo_p_sandbox_1.ts
.PHONY: demo-P-SANDBOX.2
demo-P-SANDBOX.2: ## P-SANDBOX.2 (ADR-0166): mediated subprocess egress — a loopback DNS + CONNECT proxy decided by the agent's own egressDecisionDetailed brain (only allow passes; prompt/foreign-ccTLD/IP-literal/unparseable/thrown all DENY). Live: denied gethostbyname → REFUSED, upstream never contacted; allowed → forwarded. Proxy dead ⇒ egress denied but local exec still runs; wired at the omp spawn (HTTP(S)_PROXY + resolv.conf steer)
$(BUN) run harness/scripts/demo_p_sandbox_2.ts
.PHONY: demo-P-SANDBOX.3
demo-P-SANDBOX.3: ## P-SANDBOX.3 (ADR-0167): the mediated-egress audit trail — a BLOCKED subprocess reach-out becomes one canonical `egress` SecurityEvent (block/high) on the audit/OCSF pipeline (P-REPORT.10 precedent; no new EventName, no approvable live-block); deduped by host so a looping exfil can't flood the SIEM; allowed reach-outs emit nothing; auditing never weakens the fail-closed guarantee (throwing sink swallowed, dead proxy still denies)
$(BUN) run harness/scripts/demo_p_sandbox_3.ts
.PHONY: demo-P-SANDBOX.4
demo-P-SANDBOX.4: ## P-SANDBOX.4 (ADR-0168): the macOS Seatbelt backend — real runtime containment on macOS via `sandbox-exec`. Declared caps enforced (network-off denies ALL network + cuts DNS via mDNSResponder); mediated egress CONFINED TO LOOPBACK so a raw-IP socket ignoring HTTP_PROXY is kernel-denied (bwrap only drops it); require-isolation fail-closed on macOS-without-sandbox-exec + Windows. Windows AppContainer (native) + Linux slirp raw-socket forwarding are named follow-ups
$(BUN) run harness/scripts/demo_p_sandbox_4.ts
.PHONY: demo-P-SANDBOX.5
demo-P-SANDBOX.5: ## P-SANDBOX.5 (ADR-0169): the runtime-execution boundary made VISIBLE in the Security panel — a GUI-owned store of the live posture (bwrap/Seatbelt/disclosed/fail-closed-blocked) + a bounded newest-first ring of refused subprocess reach-outs; a PURE panel builder rendering green/amber/red posture (auto-opens when NOT isolated), escaping hostile host/reason text; the egress audit sink feeds one deduped panel row per refused host
$(BUN) run desktop/scripts/demo_p_sandbox_5.ts
.PHONY: demo-P-SANDBOX.6
demo-P-SANDBOX.6: ## P-SANDBOX.6 (ADR-0172): the Windows AppContainer backend SEAM — a first-party `lucid-appcontainer <flags> -- <argv>` helper that fits the wrap→{cmd,args,env} contract (no OS argv-wrapper exists for AppContainer). Flag contract mirrors bwrap/Seatbelt's 3 network states (network-off → --deny-network; mediated → --loopback-only + HTTP(S)_PROXY, raw-IP sockets WFP-denied; no-proxy → fail-closed --deny-network); resolveBackend selects it when the helper is on PATH, else discloses; require-isolation fail-closed without it. The native helper itself ships in P-SANDBOX.7
$(BUN) run harness/scripts/demo_p_sandbox_6.ts
.PHONY: demo-P-SANDBOX.7
demo-P-SANDBOX.7: ## P-SANDBOX.7 (ADR-0173): the native Windows AppContainer helper (bun-compiled TS+FFI). Parser fail-closes on malformed flags; main() refuses (non-zero) wherever it cannot contain (never a passthrough); LIVE on Windows a benign child runs but a networked child is BLOCKED (a no-capability AppContainer has no network); off-Windows it correctly refuses
$(BUN) run harness/scripts/demo_p_sandbox_7.ts
.PHONY: demo-P-SANDBOX.7b
demo-P-SANDBOX.7b: ## P-SANDBOX.7b (ADR-0174): mediated --loopback-only for the AppContainer helper - the empty-caps container has NO direct internet (verified live: curl → http_code=000) and a one-time ADMIN loopback exemption (--register-loopback via CheckNetIsolation) lets it reach ONLY the loopback proxy; the no-internet guarantee holds with or without the exemption; off-Windows every mode fail-closes
$(BUN) run harness/scripts/demo_p_sandbox_7b.ts
.PHONY: build-appcontainer
build-appcontainer: ## P-SANDBOX.7: cross-compile the native lucid-appcontainer.exe helper (bun build --compile, Windows x64) into dist/
$(BUN) build tools/appcontainer/lucid_appcontainer.ts --compile --target=bun-windows-x64 --outfile dist/lucid-appcontainer.exe
.PHONY: demo-P-REPORT.9
demo-P-REPORT.9: ## P-REPORT.9 (ADR-0162): multi-repo remote fetch + PR aggregation for the Engineering Report — remote-URL parse (GitHub vs not), commits aggregated across branches (deduped) + line totals, the Cross-repo activity annex, fail-soft on a failed fetch (local refs still shown), PRs skipped with a reason on non-GitHub/unauthed remotes, and untrusted commit/PR text neutralized (no HTML/fence breakout)
$(BUN) run desktop/scripts/demo_p_report_9.ts
.PHONY: demo-P-TOOLFAIL.2
demo-P-TOOLFAIL.2: ## P-TOOLFAIL.2 (ADR-0163): failed tool calls collapse into a red toolbox badge, click expands the Tool Call Actions list (command attempted + full error); never a security surface
$(BUN) run desktop/scripts/demo_p_toolfail_2.ts
.PHONY: demo-P-REPORT.10
demo-P-REPORT.10: ## P-REPORT.10 (ADR-0164): a formal SecurityEvent per fetch/PR reach-out — the report collector's first-party git fetch / gh PR list (which bypass the agent gate) each emit a canonical egress/allow SecurityEvent (OCSF/SIEM), metadata-only (host, no credential), skipped PR lists emit nothing, proven live+offline via a local bare-origin fetch through the real dispatcher
$(BUN) run desktop/scripts/demo_p_report_10.ts
.PHONY: demo-P-FAV.1
demo-P-FAV.1: ## P-FAV.1 (ADR-0165): model-picker favorite stars - star a model to pin it into a Favorites section at the top of the picker; catalog order preserved, corrupted storage degrades safely, stale stars survive provider reconnects
$(BUN) run desktop/scripts/demo_p_fav_1.ts
.PHONY: demo-P-PROV.2
demo-P-PROV.2: ## P-PROV.2: the Provider Hub - a dedicated popup listing every provider omp offers (names only); new open-weight providers (Qwen OAuth+key, GLM/MiniMax key) join Kimi behind the typed ACKNOWLEDGE gate, which emits NO non-U.S. provider until acknowledged
$(BUN) run desktop/scripts/demo_p_prov_2.ts
.PHONY: demo-P-LOCAL.4
demo-P-LOCAL.4: ## P-LOCAL.4: one-click local-model presets (Laguna 2.1 Poolside, Gemma 4, Qwen 3.8, +) that build ONE Local Provider fronting many models behind a single secured NGINX endpoint, through the existing P-LOCAL.3 add/validate/vault path
$(BUN) run desktop/scripts/demo_p_local_4.ts
.PHONY: demo-P-STT.2
demo-P-STT.2: ## P-STT.2: guided on-device Whisper - hardware-capability gate (run only where it fits), model catalog + install/serve plan, whisper.cpp binary resolution, and the download-with-integrity flow (all pure/injected; no network, no binary)
$(BUN) run desktop/scripts/demo_p_stt_2.ts
.PHONY: demo-P-STT.6
demo-P-STT.6: ## P-STT.6 (ADR-0255): Whisper model housekeeping - the picker offers tiny/base/small only (medium/large proved slow + buggy through the local server), grays out tiers the hardware can't run (reason shown, never hidden), lists every downloaded model with its real on-disk size + a Remove button (legacy medium/large installs reclaim disk; the running tier is refused until stopped), and the recommendation/summary clamp to the offered set
$(BUN) test desktop/whisper_install.test.ts desktop/whisper_runtime.test.ts
.PHONY: demo-P-SECACK.1
demo-P-SECACK.1: ## P-SECACK.1 (ADR-0170): reviewed security rows leave the active view - GUI-owned ack ledger (releases NOTHING, audit kept), findings-seen watermark counts only new findings, and the right-click Cut/Copy/Paste menu for the prompt bar (no Cut/Copy on password fields)
$(BUN) run desktop/scripts/demo_p_secack_1.ts
.PHONY: demo-P-RESUME.1
demo-P-RESUME.1: ## P-RESUME.1 (ADR-0171): a resumed session keeps its thinking + tool-call + tool-failure history - per-session lucid-steps sidecar (omp's transcript untouched), turn anchors only move forward, quarantines not duplicated, hostile text escaped, corrupt sidecar degrades safely
$(BUN) run desktop/scripts/demo_p_resume_1.ts
.PHONY: dashboards
dashboards: ## Materialize dashboard CSVs from a DuckDB into observable/docs/data (DB=path)
$(BUN) run harness/scripts/materialize_dashboards.ts $(DB) observable/docs/data
# ---------------------------------------------------------------------------
# KG Packs (ADR-0207): headless pack builder
# ---------------------------------------------------------------------------
.PHONY: kg-pack
kg-pack: ## Build one KG pack headlessly, e.g. `make kg-pack ROLE=bd` (see `bun tools/build_kg_pack.ts --help` for keys/flags). Extra flags via FLAGS=, e.g. FLAGS="--limit 5"
$(BUN) run tools/build_kg_pack.ts $(ROLE) $(FLAGS)
.PHONY: kg-pack-all
kg-pack-all: ## Build every KG pack in the catalog, sequentially (long — one model call per conversation)
$(BUN) run tools/build_kg_pack.ts --all $(FLAGS)
# ---------------------------------------------------------------------------
# Hygiene
# ---------------------------------------------------------------------------
.PHONY: typecheck
typecheck: ## TS typecheck (no emit)
$(BUN) x tsc --noEmit
.PHONY: license-headers
license-headers: ## Apply the BUSL-1.1 SPDX header to first-party source (idempotent)
$(BUN) run tools/license_headers.ts
.PHONY: license-check
license-check: ## Fail if any first-party source file is missing the BUSL-1.1 header (CI guard)
$(BUN) run tools/license_headers.ts --check
.PHONY: clean
clean: ## Remove build/test artifacts (keeps committed source + DBs)
rm -rf node_modules/.cache .bun 2>/dev/null || true
find . -name "__pycache__" -type d -prune -exec rm -rf {} + 2>/dev/null || true
.PHONY: help
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
.PHONY: demo-P-TRIV.1
demo-P-TRIV.1: ## P-TRIV.1 (ADR-0174): the Trivia Wire - a word-game ticker in the status bar's idle gap; seed bank valid + varied, no repeats until the bank empties, streak scoring capped at x3, corrupt/throwing storage degrades safely, streaming-only visibility, hostile question text renders as text (never markup)
$(BUN) run harness/scripts/demo_ptriv1.ts
.PHONY: demo-P-TRIV.2
demo-P-TRIV.2: ## P-TRIV.2 (ADR-0175): role-aware Trivia Wire - executive→GovCon (M&A/opportunities/federal priorities), manager→CMMI-DEV L3 + PM, security→CMMC + RMF, developer/none→general; banks valid + domain-confined + duplicate-free; idle engagement wakes the ticker on an empty composer only when past sessions or an unlocked KG exist
$(BUN) run harness/scripts/demo_ptriv2.ts
.PHONY: demo-P-TRIV.3
demo-P-TRIV.3: ## P-TRIV.3 (ADR-0176): 100-question dev/security/manager banks + 50 executive - and the executive INTEL WIRE: curated defense/intel RSS fetched first-party (host-only egress audit), scan-gated FAIL-CLOSED (findings or a dead scanner drop the batch), fail-quiet offline, rendered as escaped text between questions
$(BUN) run harness/scripts/demo_ptriv3.ts
.PHONY: demo-P-PREVIEW.7
demo-P-PREVIEW.7: ## P-PREVIEW.7 (ADR-0179): the silent-white preview explained + runnable - the injected bridge posts a one-shot health report (empty body + bounded errors); Electron apps detect evidence-based (fail-false for plain pages); launch plan prefers the app's own electron, falls back to PATH, null otherwise; non-Electron paths never plan a launch
$(BUN) run harness/scripts/demo_ppreview7.ts
.PHONY: demo-P-TASK.5
demo-P-TASK.5: ## P-TASK.5 (ADR-0180): live subagent activity - the delegation card opens each subtask (generated name, live now-line, thinking/tool/text steps tailed from omp's per-subtask transcripts); read-only + path-confined + corrupt-tolerant + bounded; never-delegated sessions fail-quiet
$(BUN) run harness/scripts/demo_ptask5.ts
.PHONY: demo-P-SYSRES.1
demo-P-SYSRES.1: ## P-SYSRES.1 (ADR-0182): the system resource guard - a weak CPU under heavy load / RAM pressure pauses the KG + Code Graph builds behind a notice (why + machine line + top-processes panel + re-check, no escape hatch); FAIL-OPEN (no evidence never blocks); read-only fixed-argv process listing
$(BUN) run desktop/scripts/demo_p_sysres_1.ts
.PHONY: demo-P-KGVIZ.1
demo-P-KGVIZ.1: ## P-KGVIZ.1 (ADR-0183): form in place - the KG/code-graph settle runs OFF-SCREEN (time-boxed presettle) so hundreds of nodes open already formed at the final center, parked; live merges settle silently; resizes re-fit without reheating; drag is the only visible sim
$(BUN) run desktop/scripts/demo_p_kgviz_1.ts
.PHONY: demo-P-KGPACK.1
demo-P-KGPACK.1: ## P-KGPACK.1 (ADR-0205): named, swappable KGs (file-per-KG + JSON registry) - the pre-existing combined kb_graph.duckdb is ADOPTED as the default "My Knowledge" KG (zero data loss), new role KGs are ISOLATED files (a page in one is invisible from another), rename touches only the label, and switching the active KG re-points a no-arg store lookup
$(BUN) run desktop/scripts/demo_p_kgpack_1.ts
.PHONY: demo-P-KGMARKET.1
demo-P-KGMARKET.1: ## P-KGMARKET.1 (ADR-0206): the fail-closed entitlement gate - the pure decision core (not signed in → signin; only an active, unexpired entitlement → pull; a lapsed/missing one → checkout) + the provider seam that defaults to a fail-closed null provider so an unconfigured public build can never pull a pack without entitlement
$(BUN) run desktop/scripts/demo_p_kgmarket_1.ts
.PHONY: demo-P-KGMARKET.4
demo-P-KGMARKET.4: ## P-KGMARKET.4 (ADR-0206): the download → unzip → gated-install path - a KG exports to a single .lkgpack.zip (first-party zip writer); installPackFromUrl fetches a signed URL, unzips, and runs the SAME P-KGPACK.4 gate (verify + re-scan fail-closed, read-only). A clean pack installs; a Trojan-Source pack is blocked at re-scan (a purchase grants access, not trust)
$(BUN) run desktop/scripts/demo_p_kgmarket_4.ts
.PHONY: demo-P-KGMARKET.4b
demo-P-KGMARKET.4b: ## P-KGMARKET.4 part 2 (ADR-0206): the marketplace SIGN-IN flow, against stubs - the boot orchestration picks the provider (firebase / dev stub / off); STUB mode drives signin → checkout(instant grant) → pull → the SAME gated install offline; FIREBASE mode opens the hosted page then the lucid://auth deep link signs in; OFF leaves the fail-closed nullProvider. No token ⇒ signed out ⇒ never a pull
$(BUN) run desktop/scripts/demo_p_kgmarket_4b.ts
.PHONY: demo-P-KGPACK.6
demo-P-KGPACK.6: ## P-KGPACK.6 (ADR-0205): the background KG-seed job - lift the 50-doc cap so a full dataset (here 120 conversations, past the old cap) compiles as a tracked background job with live counts + cancel; all 120 compile, 0 skipped
$(BUN) run desktop/scripts/demo_p_kgpack_6.ts
.PHONY: demo-P-KGPACK.8
demo-P-KGPACK.8: ## P-KGPACK.8 (ADR-0341): real gated pack import preserves full knowledge while the metadata-only graph snapshot bounds nodes and links
$(BUN) run desktop/scripts/demo_p_kgpack_8.ts
.PHONY: demo-P-KGPACK.7
demo-P-KGPACK.7: ## P-KGPACK.7 (ADR-0340): a BOUGHT pack imports in the SHIPPED app - every DuckDB store computed its migrations dir as join(import.meta.dir,"migrations"), a real path from source and a VIRTUAL bunfs path inside the compiled engine, so opening a pack db threw ENOENT on 'B:\~BUN\root\migrations' and the import was refused at the scan stage; the resolver now PROBES (own dir, then LUCID_RESOURCES, then execPath) and this demo COMPILES a probe with the same --compile flag the engine uses to prove a real store opens where the bug lived; plus the picker accepts the downloaded .lkgpack.zip (it was folder-only, so the delivered artifact was unselectable) or the manifest.json inside an unzipped pack
$(BUN) run desktop/scripts/demo_p_kgpack_7.ts
.PHONY: demo-P-KGPACK.5
demo-P-KGPACK.5: ## P-KGPACK.5 (ADR-0205): the Role KG Packs storefront - a curated, filter-as-you-type catalog of role-specific KG Packs (public SKU surface; rows link to the product page, packs live in the private add-on repo) with a gated "Import a pack you own" action routing through the P-KGPACK.4 verify + re-scan
$(BUN) run desktop/scripts/demo_p_kgpack_5.ts
.PHONY: demo-P-KGPACK.4
demo-P-KGPACK.4: ## P-KGPACK.4 (ADR-0205): the .lkgpack KG Pack - author (export a KG as db + signed/unsigned manifest) + gated import (integrity + Ed25519 origin verified, EVERY page re-scanned fail-closed, installed READ-ONLY + untrusted); a tampered db is refused at integrity, a Trojan-Source page blocks the whole import, an untrusted-key signature is refused
$(BUN) run desktop/scripts/demo_p_kgpack_4.ts
.PHONY: demo-P-KGPACK.3
demo-P-KGPACK.3: ## P-KGPACK.3 (ADR-0205): seed a named KG from a folder - an Obsidian markdown vault or a ChatGPT/Claude/Gemini export becomes one document per note/conversation, batch-compiled into a NAMED KG through the SAME fail-closed gate (a Trojan-Source note is quarantined, never compiled); KGs stay isolated files and the default is untouched
$(BUN) run desktop/scripts/demo_p_kgpack_3.ts
.PHONY: demo-P-KGPACK.2
demo-P-KGPACK.2: ## P-KGPACK.2 (ADR-0205): the named-KG picker - the combined "Compiled KB" becomes a filter-as-you-type dropdown of named KGs (active one checked, rename inline, "New KG"); the views button reads the active KG's name; user KG names are escaped
$(BUN) run desktop/scripts/demo_p_kgpack_2.ts
.PHONY: demo-P-KGUI.1
demo-P-KGUI.1: ## P-KGUI.1 (ADR-0184): the KG header decluttered - title "KG" (hover: Knowledge Graph, icon dropped) and the Relate/Code-graph/Compiled-KB stack consolidated into ONE labeled dropdown (hover tip lists the options; the menu explains each inline; active view checked)
$(BUN) run desktop/scripts/demo_p_kgui_1.ts
.PHONY: demo-P-KGUI.2
demo-P-KGUI.2: ## P-KGUI.2 (ADR-0185): the Data dropdown - Import history / AI-extraction toggle / Export vault / CUI archive folded from three buttons + a checkbox into one self-describing menu; the AI toggle is remembered state (never closes the menu); CUI keeps its danger look + confirm toast
$(BUN) run desktop/scripts/demo_p_kgui_2.ts
.PHONY: demo-P-TRIV.4
demo-P-TRIV.4: ## P-TRIV.4 (ADR-0191): the Settings toggle + an AI re-seed ("recycle") for the Trivia Wire - regenerate a per-role pack on the user's SELECTED model from opt-in context (sessions/KG/code graph); context is scanned FAIL-CLOSED (a finding or a dead scanner drops the whole re-seed, model never called), delimited + late, generated questions clear the SAME isTriviaQuestion gate as the seed floor, fail-quiet to the seed bank
$(BUN) run harness/scripts/demo_ptriv4.ts
.PHONY: demo-P-EVAL.1
demo-P-EVAL.1: ## P-EVAL.1 (ADR-0187): the PURE Model-Evaluation metrics + per-model API-latency rollup core - metric formulas with direct/proxy/needs_signal honesty tiers (a missing signal is null, never zero), DST-correct business-hours (08:00-17:00 ET) bucketing + nearest-rank p50/p95, per-model-by-hour weekly/monthly rollup with WoW/MoM deltas, and ASCII-only mermaid xychart markdown the existing report viewer bar-ifies
$(BUN) run harness/scripts/demo_peval1.ts
.PHONY: demo-P-CHAT.A
demo-P-CHAT.A: ## P-CHAT.A (ADR-0188): sectioned agent turn - PURE fence-aware heading/rule splitter (sectionizeAnswer) that turns a settled answer into collapsible sections (streaming unchanged; a trivial answer is never accordioned) + subagent card collapsed by default. Pure keystone verified here; the app.ts settle-transform + collapse are typechecked and QA-gated in-app
$(BUN) run harness/scripts/demo_pchata.ts
.PHONY: demo-P-CHAT.B
demo-P-CHAT.B: ## P-CHAT.B (ADR-0189): inline tool-event chips - PURE fence-aware / block-boundary interleave (interleaveChips) that threads each tool call back into the settled answer as an expandable chip anchored where it fired (prose parts still sectionize via P-CHAT.A; a no-tool answer is unchanged) + a +/- diffstat per edit/write + a lazy drilldown. Pure keystone verified here; the app.ts settle interleave + chip drilldowns + thoughts-window drop are typechecked and QA-gated in-app
$(BUN) run harness/scripts/demo_pchatb.ts
.PHONY: demo-P-CHAT.C
demo-P-CHAT.C: ## P-CHAT.C (ADR-0190): settled-turn "Generate engineering report" - PURE observed-turn->RunRecord adapter (buildRunRecord/renderTurnEvalReport) that maps a turn's tool calls + diffstats + tokens into evals.ts's RunRecord (reads/searches/bash are not files, repeated edits merge, the surplus is a re-edit, no AC/test signal stays needs_signal not faked) and renders the reused Model-Evaluation markdown. Pure keystone verified here; the run-footer CTA + /api/eval/report route are typechecked and QA-gated in-app
$(BUN) run harness/scripts/demo_pchatc.ts
.PHONY: demo-P-STALL.1
demo-P-STALL.1: ## P-STALL.1 (ADR-0186, evolved by ADR-0263): visible provider silence - a slow event at each quiet 2-min mark keeps the wait legible (HUD phase counts the silence honestly); the 10-min cap itself was removed by P-STALL.2
$(BUN) run desktop/scripts/demo_p_stall_1.ts
.PHONY: demo-P-STALL.2
demo-P-STALL.2: ## P-STALL.2 (ADR-0263): no turn cutoff, visible pending work - the 10-min silence kill is GONE (long subagent fan-outs outlive any fixed clock; a turn runs until the work ends or Stop), a dead omp child now rejects in-flight requests EVENT-DRIVEN (proven with a real child process), and every slow notice names the open tool calls / spawned subagent tasks with their elapsed time (turn_pending.ts -> { type:'slow', pending } -> HUD phase + toast)
$(BUN) run desktop/scripts/demo_p_stall_2.ts
.PHONY: demo-P-WINBOOT.1
demo-P-WINBOOT.1: ## P-WINBOOT.1 (ADR-0259): Windows installed-app startup hardening - a Program Files install (Bun EPERMs loading dev.ts from the protected tree) is diagnosed FAST + ACTIONABLY (reinstall per-user / run portable) instead of a 30s blank box; waitForServer bails on the engine's early exit; a failed write probe / EPERM signal / protected path all classify, while a dev run never blames the install location; and the installer posture (ADR-0262): assisted installer, per-user DEFAULT, per-machine (Program Files) allowed again - pinned as legal ONLY while build-desktop.yml carries the strict ADR-0261 boot gate (removing the gate turns this demo red)
$(BUN) run desktop/scripts/demo_p_winboot_1.ts
.PHONY: demo-P-WINBOOT.2
demo-P-WINBOOT.2: ## P-WINBOOT.2 (ADR-0260): the permanent fix - the engine ships as a `bun build --compile` binary (bin/lucid-engine) that EMBEDS dev.ts (Bun never module-loads a .ts from a protected install dir) with native addons the only --external (loaded via the OS loader, fine from Program Files) and the renderer PREBUILT (no runtime Bun.build of .ts); dev.ts derives its base dir from execPath when compiled, main.ts spawns the binary in packaged mode (fallback to `bun run dev.ts`), and the demo BUILDS + BOOTS the real binary proving /api/health + prebuilt /app.js serve with nothing .ts loaded off disk
$(BUN) run desktop/scripts/demo_p_winboot_2.ts
.PHONY: demo-P-WINBOOT.2C
demo-P-WINBOOT.2C: ## P-WINBOOT.2C (ADR-0261): the Program Files boot GATE - stages the packaged repo (or a source-built skeleton) into a Program Files-ACL location, denies the current user the specific write/delete rights (never generic W - that denies SYNCHRONIZE and EPERMs CreateProcess itself), PROVES the denial took, then requires the compiled bin/lucid-engine to answer /api/health and serve the prebuilt renderer bundle from the protected tree; wired STRICT into build-desktop.yml's Windows runner so the v1.12.0 brick class fails the build, never a user
$(BUN) run desktop/scripts/demo_p_winboot_2c.ts
.PHONY: demo-portguard
demo-portguard: ## P-PORTGUARD.1 (ADR-0305): the engine port handshake - main only renders a health answer carrying its per-launch nonce, so a foreign process squatting the engine port fails LOUDLY with a copy/paste incident report (process name, pid, start date/time, command line), never a silent roll onto a stranger's UI
$(BUN) run desktop/scripts/demo_portguard.ts
.PHONY: demo-preview-open
demo-preview-open: ## P-PREVIEW.11 (ADR-0308): the agent's `preview_open` opens the panel again - omp's intent tracing rewrites a custom tool's ACP call title to the model's intent prose (and the update carries no tool-name field at all), so the old title match silently swallowed every preview; the tool now REPORTS ITSELF over its own token'd channel like preview_screenshot/inspect/act, best-effort so an unreachable or older desktop degrades instead of failing, and fail-closed so a refused target is never reported
$(BUN) run desktop/scripts/demo_preview_open.ts
.PHONY: demo-release-identity
demo-release-identity: ## P-RELEASE.4 (ADR-0307): the release-identity gate - CI reads each artifact's EMBEDDED identity before upload (pkg bundle id + payload .app path + version out of the xar Distribution/PackageInfo, deb package name out of the gunzipped ar control member, rpm name out of the 96-byte lead, the updater feed's declared path because both flavors emit a file named latest.yml, filename stem for the rest) and FAILS the build on a mismatch; the demo proves the swap case - correct Agent filenames wrapping Creator bytes, invisible to every name check - plus fail-closed on an empty/missing dir and an unaccounted-for file
$(BUN) run desktop/scripts/demo_release_identity.ts
.PHONY: demo-office
demo-office: ## P-OFFICE.1 (ADR-0306): Word/Excel/PowerPoint through the pinned OfficeCLI binary as a GATED skill - the skill is version-pinned and forbids the piped `curl | bash` installer (which exec_policy independently classifies T4 always-prompt), exec_policy grades officecli by subcommand (view/get safe T0, create/add/set/remove/close T1, install/watch T2, an unknown verb fail-closed T3), and the live create -> add -> view outline -> view html -> close round-trip runs wherever the pinned binary is installed and prints a VISIBLE skip where it is not
$(BUN) run desktop/scripts/demo_office.ts
.PHONY: demo-P-KG-INGEST.5
demo-P-KG-INGEST.5: ## P-KG-INGEST.5 (ADR-0264): the chat-history ingest can no longer hang and Stop always stops - ACP requests are bounded (timeout + signal) and drained when the omp child exits (an unanswered `initialize` used to freeze the import at 0/500 forever), cancel is checked per MESSAGE and reaches the extractor so an in-flight model call is interrupted rather than awaited, a wedged job is force-cancelled after a grace period so single-flight releases and the user can retry without restarting, and the pill reports a silent run as STALLED instead of rendering a healthy-looking bar
$(BUN) run desktop/scripts/demo_p_kg_ingest_5.ts
.PHONY: demo-P-EVAL.2
demo-P-EVAL.2: ## P-EVAL.2 (ADR-0187): the API-latency CAPTURE + PERSISTENCE pipeline - the GUI-side sink turns t_sent/t_first_token/t_end into a LatencySample appended to an append-only JSONL (the GUI opens the observer DB read-only), the frozen migration 0011 creates api_latency + eval_metrics + the latency_rollup view, the single-writer ingest loads the JSONL idempotently, and readLatencyCalls round-trips the rows back into evals.ts's ApiLatencyCall (ok-only) so rollupLatency + render stay the P-EVAL.1 source of truth
$(BUN) run harness/scripts/demo_peval2.ts
.PHONY: demo-P-EVAL.3
demo-P-EVAL.3: ## P-EVAL.3 Part A (ADR-0187): the per-run eval-metrics PERSISTENCE pipeline - evalMetricsForTurn maps an observed turn to EvalMetrics (reuses P-CHAT.C + P-EVAL.1), the GUI-side sink flattens it to a sample + appends to an append-only JSONL keeping the honesty rule (a no-signal metric is null not 0, tier preserved), the single-writer ingest loads eval_metrics idempotently on run_id, and readEvalMetricsRows round-trips the rows back (NULLs + tiers intact) for the cross-run rollup
$(BUN) run harness/scripts/demo_peval3.ts
.PHONY: demo-P-EVAL.3b
demo-P-EVAL.3b: ## P-EVAL.3 Part B (ADR-0187): the cross-run Model-Evaluation ROLLUP report (the /api/eval/rollup path) - the eval-metrics + latency JSONL ledgers ingest into a throwaway GUI-owned DuckDB, aggregateEvalMetrics rolls per model (means over runs-with-signal; a no-signal metric stays "no signal", never a fake 0), rollupLatency adds the per-model p50/p95, and the combined ASCII markdown (xychart-beta the viewer bar-ifies) saves as an `evals` brief; an empty ledger yields a friendly report, never an error
$(BUN) run harness/scripts/demo_peval3b.ts
.PHONY: demo-P-REMOTE.1
demo-P-REMOTE.1: ## P-REMOTE.1 (ADR-0226/0227): the relay identity gate, offline - first-frame Firebase auth (never a URL param) against a local JWKS: premium/allowlisted admitted + E2E bytes stay opaque, expired/forged -> 4401, verified-but-unentitled -> 4403, silent socket reaped, anonymous self-host mode byte-identical
$(BUN) run harness/scripts/demo_premote1.ts
.PHONY: demo-P-REMOTE.2
demo-P-REMOTE.2: ## P-REMOTE.2 (ADR-0226/0227): hosted-rendezvous transport - a real CollabSocket host presents a fresh token per connect (first frame) + opens on auth-ok, a host drop is HELD in grace so the guest stays up, the same account re-claims within grace (roster resent, delivery resumes, guest never reconnects), and a null token is terminal (no unauthenticated retry loop)
$(BUN) run harness/scripts/demo_premote2.ts
.PHONY: demo-P-REMOTE.2b
demo-P-REMOTE.2b: ## P-REMOTE.2b (ADR-0226/0227): desktop wiring for the hosted rendezvous - MarketAuth renews a near-expiry Firebase ID token via the securetoken refresh exchange (fail-closed when signed out), and a CollabManager with a pwaBase relay mints PHONE-openable browser invites (PWA URL, secret in the fragment, write token when editing); no pwaBase keeps the legacy relay-host link
$(BUN) run harness/scripts/demo_premote2b.ts
.PHONY: demo-P-REMOTE.2c
demo-P-REMOTE.2c: ## P-REMOTE.2c (ADR-0226/0227): backend token delivery - the renderer-pushed Firebase token lands in a RelayTokenCache the host CollabSocket reads via authToken; a live token authenticates + opens the room over a REAL gated relay, an empty cache / refused token FAILS CLOSED (never a silent unauthenticated connect), and a plain socket (un-gated default) still connects anonymously (unchanged)
$(BUN) run harness/scripts/demo_premote2c.ts
.PHONY: demo-P-REMOTE.3
demo-P-REMOTE.3: ## P-REMOTE.3 (ADR-0226/0227): the phone guest PWA data path - a real CollabSocket+CollabGuest 'phone' (the exact modules the PWA bundles) authenticates to a REAL gated relay, goes live against a real CollabHost, and the pure pwa_view reducer/renderer folds the host's thinking + tool chips + streamed answer (hostile content escaped); host stop -> ended
$(BUN) run harness/scripts/demo_premote3.ts
.PHONY: demo-P-REMOTE.4a
demo-P-REMOTE.4a: ## P-REMOTE.4a (ADR-0226/0227): the invite-link QR - a dependency-free byte-mode encoder renders a real invite link as a scannable QR (printed to the terminal + a self-contained SVG); asserts finder/timing/dark structure + a safe-to-inline SVG. The room key rides IN the link fragment, so scanning carries the E2E secret exactly like copying it
$(BUN) run harness/scripts/demo_premote4a.ts
.PHONY: demo-P-REMOTE.6
demo-P-REMOTE.6: ## P-REMOTE.6 (ADR-0227): the paid Remote Access tier - over a REAL gated relay, a premium phone goes live (never shown Subscribe) while a verified-but-unentitled token is refused 4403 and the pure detector routes it to Subscribe; createRemoteCheckout opens a Stripe session fail-closed (null on error / no token); and a post-webhook refreshed token gains the `premium` claim so the phone recognises entitlement + reconnects
$(BUN) run harness/scripts/demo_premote6.ts
.PHONY: demo-P-REMOTE.8
demo-P-REMOTE.8: ## P-REMOTE.8 (ADR-0229): PWA composer image attachments + reconnect-status recovery - over a REAL relay an EDIT guest attaches validated image data URLs to a prompt; they arrive E2E-sealed at the host's onGuestPrompt (staged into the host composer -> model vision input, host-gated), image-only messages work, and a VIEW guest's image prompt is refused. Then a transient drop shows a reconnect note and the next live host frame CLEARS it - no more stale "connection lost" banner while streaming
$(BUN) run harness/scripts/demo_premote8.ts
.PHONY: demo-P-REMOTE.9
demo-P-REMOTE.9: ## P-REMOTE.9 (ADR-0230): phone transcript - own-message echo + per-edit +/- diffstats + end-of-run engineering report, over a REAL relay. The host broadcasts a `tool` event carrying the edit's authored code; it arrives E2E and the guest folds it into a tool item with a +/- diffstat (same convention as the desktop chips); on `done` it builds a per-turn report (files + line counts + tool counts + model + context) rendered as mobile cards + copyable Markdown; the guest's own sent message is echoed locally
$(BUN) run harness/scripts/demo_premote9.ts
.PHONY: demo-P-REMOTE.10
demo-P-REMOTE.10: ## P-REMOTE.10 (ADR-0233): out-of-band reconnect via a Google Drive relay-codes file - REAL WebCrypto over a mock Drive. A host writes the current EDIT reconnect link, PIN-encrypted, to the single `lucid_relay_codes` file (drive.file scope); at rest the file is CIPHERTEXT (the link is absent); a disconnected reader reads + decrypts with the PIN to recover the freshest link; a wrong PIN fails closed; a later reconnect appends a fresh code (newest wins); and the single file is shared with a teammate via a per-file writer permission (never the rest of the Drive). The drive.file OAuth consent is the only live-only step
$(BUN) run harness/scripts/demo_premote10.ts
.PHONY: demo-P-REMOTE.10c
demo-P-REMOTE.10c: ## P-REMOTE.10c (ADR-0235): the phone PWA "get a reconnect code" READER - REAL WebCrypto over a mock Drive. A disconnected phone (drive.file token) reads the host's shared `lucid_relay_codes` file and resolves it via the `resolveReconnect` state machine: the right PIN recovers the freshest EDIT link, which normalizes LOSSLESSLY to a room fragment the PWA re-parses (room + key + write token) before reloading; locked (no PIN), wrong-PIN, expired, and empty all fail closed (never a link)
$(BUN) run harness/scripts/demo_premote10c.ts
.PHONY: demo-P-PREVIEW-PWA.1
demo-P-PREVIEW-PWA.1: ## P-PREVIEW-PWA.1 (ADR-0237): send the desktop Preview panel to a phone guest (item C, slice 1). Proves the PURE path headlessly: the bandwidth-light downscale sizing (longest edge capped, aspect kept, never upscaled), and that a host `preview-snapshot` event folds into a tappable phone thumbnail whose image data URL is NEVER inlined into the transcript HTML (hydrated as an <img> property) and whose label is HTML-escaped; distinct snapshots keep stable ids across re-renders. Live capture (Electron capturePage) + broadcast + on-device display are Electron/deploy-gated
$(BUN) run harness/scripts/demo_preview_pwa1.ts
.PHONY: demo-P-PREVIEW-PWA.2
demo-P-PREVIEW-PWA.2: ## P-PREVIEW-PWA.2 (ADR-0239): phone MARKUP on a preview snapshot + send-back (item C, slice 2). Proves the pure path: strokes are NORMALIZED to image space (clamped at the edges, resize/rotation-proof) and scale losslessly onto the natural-size composite; the on-screen pen and the composite pen share ONE width formula (ink parity); and the sent-back composite rides the SAME fail-closed P-REMOTE.8 attachment validation as a pasted image (PNG accepted, script-capable SVG refused). The finger ink + canvas composite are on-device
$(BUN) run harness/scripts/demo_preview_pwa2.ts
.PHONY: demo-P-PREVIEW-PWA.3
demo-P-PREVIEW-PWA.3: ## P-PREVIEW-PWA.3 (ADR-0240): agent PWA-awareness / autodetect (item C, slice 3). While guests watch a Session Share the agent's prompt carries a TRUSTED preamble (counts only) so it can suggest broadcasting the Preview; proven: autodetect (no guests -> no block, rebuilt per turn), counts-only construction (a hostile guest NAME can never ride into the prompt - invariant #5), the composition rule (the MODEL sees preamble+prompt while the P-COLLAB.15 mirror + transcript keep the CLEAN prompt), and clamping of garbage counts
$(BUN) run harness/scripts/demo_preview_pwa3.ts
.PHONY: demo-P-PWA-FOCUS.1
demo-P-PWA-FOCUS.1: ## P-PWA-FOCUS.1: tap a Process/lane on the phone and THAT lane becomes the live transcript. Real CollabHost + real CollabGuest over an in-memory wire (no relay, no sockets, no phone), with the lane traffic flowing through the real `laneEventToChatEvent`. Proves the bandwidth guarantee first: a guest that never sent `watch` receives ZERO lane frames on the wire, so N idle lanes never stream tokens at a phone on cellular. Then a lane `watch` is answered with that lane's replay (unicast `lane-sync`, so a lane that has worked for ten minutes does not open empty); lane events arrive through onLaneEvent tagged with their lane id and never touch the master transcript / context gauge / onEvent (not even a lane `done` carrying text); watch("master") unsubscribes so the lane goes silent again; two guests on two lanes get no crosstalk (the subscription is per peer); permission / auto-approved / status are dropped so a lane's approval ask never double-reports as conversation; and a `watch` from a peer that never sent `hello` is ignored fail-closed (no `lane-sync` replay, no subscription)
$(BUN) run harness/scripts/demo_pwa_focus1.ts
.PHONY: demo-P-SHARE.2
demo-P-SHARE.2: ## P-SHARE.2 (ADR-0234): Session Share dock UI polish - the "Reachable at" bind list now defaults to a GUEST-ROUTABLE address (LAN IPv4, then IPv6) and sinks loopback (unreachable by a guest) to the bottom; IPv4 precedes IPv6 within each group; ordering is pure + non-mutating. And the cold-boot dock paints a SECRET-FREE cached snapshot INSTANTLY (never a blank Loading) then revalidates - the cache carries only the non-secret relay descriptor + serve status + a redacted P2P config, NEVER an invite link / room id / TURN credential and never a stale Live state
$(BUN) run harness/scripts/demo_pshare2.ts
.PHONY: demo-P-SHARE.3
demo-P-SHARE.3: ## P-SHARE.3: mobile-safe invite links - the Share dock FEATURES the https phone/browser link (accent "Copy phone link" + QR), keeps the wss LUCID-to-LUCID link in a demoted "desktop only" row (muted field + "Copy desktop link"), and NEVER offers or QR-codes a wss (LAN) link to a phone - texting that both fails to join AND leaks roomId.secret into whatever HTTP server answers the host. classifyInviteLink (pure) is the single source of truth: pick the https link, discard a non-http(s) value, and flag an https link on a private/LAN/loopback host as same-network-only
$(BUN) run harness/scripts/demo_pshare3.ts
.PHONY: demo-P-COLLAB.1
demo-P-COLLAB.1: ## P-COLLAB.1 (ADR-0192): the live-collaboration transport KEYSTONE - a host mints a room (id + 32B key + 16B write token) + a full/view invite link (roomId.base64url(secret), reusing omp's @oh-my-pi/pi-wire constants), SEALS a LUCID ChatEvent frame (AES-256-GCM, [12B IV][ct+tag]) + envelopes it with its peer id, and a guest holding the link unpacks + opens it end-to-end; the relay only ever sees opaque bytes (a wrong key can't open, a tampered byte fails the tag), and a view link is read-only. The relay client, host/guest, and Share UI are P-COLLAB.2-.4
$(BUN) run harness/scripts/demo_pcollab1.ts
.PHONY: demo-P-COLLAB.2
demo-P-COLLAB.2: ## P-COLLAB.2 (ADR-0192): the relay CLIENT + the view-only broadcast HOST, proven end-to-end offline - an in-memory relay routes opaque envelopes between a REAL host CollabSocket (driven by a REAL CollabHost) and REAL guest sockets: a guest joins with a view link + hello, the host answers with a unicast E2E welcome (header + replayed transcript + roster), broadcasts live ChatEvents the guests open, a 2nd guest joins mid-stream and its state shows the folded context fill, and view-only is enforced host-side even for a full-token guest (Phase 1); the relay never sees plaintext. Fail-closed: a bad-key frame terminates the socket (no reconnect). The Share panel UI + guest join/render + guest-write are P-COLLAB.3
$(BUN) run harness/scripts/demo_pcollab2.ts
.PHONY: demo-P-COLLAB.3
demo-P-COLLAB.3: ## P-COLLAB.3 (ADR-0192): the backend host LIFECYCLE (CollabManager) dev.ts wires to /api/collab/* + the /api/chat ChatEvent tap - a REAL CollabManager mints a room over an in-memory relay (self-hosted-default resolveRelay), a REAL guest socket joins with the view link + gets an E2E welcome, the manager taps live ChatEvents through to the guest (the passthrough), status reflects the roster, stop tears it down + sends bye, and start REFUSES when no relay is authorized (fail-closed - no self-hosted URL + public opt-in off). The Share panel UI + guest join/render + guest-write are the next slice
$(BUN) run harness/scripts/demo_pcollab3.ts
.PHONY: demo-P-COLLAB.4
demo-P-COLLAB.4: ## P-COLLAB.4/.5 (ADR-0192): the read-only GUEST + the OPTIONAL embedded relay, end-to-end over REAL localhost WebSockets - LUCID starts its OWN relay (127.0.0.1, no third party), a real host (CollabSocket+CollabHost) + real guest (CollabSocket+CollabGuest) connect through it: the guest pastes the view link + gets an E2E welcome, the host's live ChatEvents stream host->relay->guest read-only, the roster tracks a 2nd guest join/leave, a guest to a nonexistent room is refused (fail-closed, relay saw only ciphertext), and stop tells the guest. The Join panel UI + the 'be the relay' toggle are the UI slice
$(BUN) run harness/scripts/demo_pcollab4.ts
.PHONY: demo-P-COLLAB.12
demo-P-COLLAB.12: ## P-COLLAB.12 (ADR-0198): guest-WRITE over a real relay - a guest with EDIT access (full link + valid write token) drives the host: its prompt reaches onGuestPrompt (which in the app runs it in the host's omp session, where the fail-closed scan gate + exec/egress approvals still apply - the guest bypasses nothing) + onGuestAbort. A VIEW-only guest is refused BOTH client-side (sendPrompt returns false, never hits the wire) AND host-side (a hand-crafted raw prompt frame is refused with a read-only error, never runs). Token-gated + fail-closed
$(BUN) run harness/scripts/demo_pcollab12.ts
.PHONY: demo-P-COLLAB.14
demo-P-COLLAB.14: ## P-COLLAB.14 (ADR-0228): edit-guest MODEL + already-used-FOLDER selection over a real relay - the host OFFERS its model + recent-folder allowlists to an EDIT guest only (a view guest is offered nothing); the guest picks either and it reaches onGuestSetModel / onGuestSetWorkspace (the app applies it through the host's OWN picker path - its UI + omp reconcile, and a folder switch restarts the agent in the new cwd). Fail-closed: a value/id NOT in the offered allowlist is guarded client-side AND refused host-side (never applied), and a folder is picked by an OPAQUE id the host resolves to a path locally - no arbitrary model id or filesystem path ever crosses the wire. host.setOptions rebroadcasts the live selection to edit guests
$(BUN) run harness/scripts/demo_pcollab14.ts
.PHONY: demo-P-COLLAB.15
demo-P-COLLAB.15: ## P-COLLAB.15 (ADR-0231): LIVE user-turn mirroring over a real relay - the host broadcasts every user turn (its own + each guest's, attributed by `from`) so ALL participants see who typed what, in order. Two guests: the host's turn + a guest-attributed turn both reach BOTH guests live (view-only guests included), and a late joiner sees prior turns in the welcome replay
$(BUN) run harness/scripts/demo_pcollab15.ts
.PHONY: demo-P-COLLAB.20
demo-P-COLLAB.20: ## P-COLLAB.20 (ADR-0242): the Join panel becomes a floating, NON-BLOCKING dock - watch (or drive, with an edit link) another LUCID while fully using your own. Proven headless on the pure chassis: the join dock persists geometry under its OWN key (independent of the Share dock), first-open lands beside the rails (never stacked on the share dock), stored shapes re-clamp to the live viewport, minimize round-trips, and it snaps with the exact P-SHARE.1 rules (one chassis). Multi-join orchestration = P-COLLAB.21
$(BUN) run harness/scripts/demo_pcollab20.ts
.PHONY: demo-P-COLLAB.19
demo-P-COLLAB.19: ## P-COLLAB.19 (ADR-0241): dual invite links - ONE room, TWO capabilities. An edit share mints the EDIT link (+ phone twin, write token: can drive) AND the VIEW-ONLY link (+ phone twin, key only: watch, never write) so different guests get different access to the same live session; all four forms open the same room + E2E key; a view-only share and the legacy (no-PWA) browser form never mint an edit-capable link. Host-side refusal of a view guest's write: demo-P-COLLAB.12
$(BUN) run harness/scripts/demo_pcollab19.ts
.PHONY: demo-P-COLLAB.11
demo-P-COLLAB.11: ## P-COLLAB.11 (ADR-0197): WebRTC signaling over the relay - the SDP offer/answer + trickled ICE route host<->guest as `signal` frames through the relay's peer routing (signal to peer 0 -> host; to the guest's peer id -> guest), a `signal` frame is recognized by the demux (session handlers ignore it), and close is terminal. This SignalingChannel is what WebRtcTransport consumes before the peers go DIRECT P2P (RTCPeerConnection is renderer-only, so the DataChannel itself is preview-verified)
$(BUN) run harness/scripts/demo_pcollab11.ts
.PHONY: demo-P-COLLAB.9
demo-P-COLLAB.9: ## P-COLLAB.9 (ADR-0195): the STANDALONE relay broker (tools/relay) - spawns `bun run tools/relay/serve.ts` as a separate process exactly like a jumpbox/systemd would, waits for /healthz, then connects a REAL host + REAL guest THROUGH the deployed process (hello->welcome->live event->bye), and confirms /healthz reflects the live room + peer counts (never content). Validates the deployable, not just the in-process library. Self-contained (no npm deps); deploy on an office server / Ubuntu 24 jumpbox / DGX Spark
$(BUN) run harness/scripts/demo_pcollab9.ts
.PHONY: demo-P-GPUFIX.1
demo-P-GPUFIX.1: ## P-GPUFIX.1 (ADR-0246): zombie-SID GPU-sandbox self-heal (electron/electron#51761) - on the 2nd fatal GPU child death BEFORE the first window renders, main.ts relaunches with --disable-gpu-sandbox (renderer sandbox intact) and persists a userData flag (survives the NSIS reinstall that re-inherits the zombie SID); a sandbox-off instance NEVER relaunches again (loop guard), post-render GPU crashes and normal lifecycle exits are ignored, the engine.log line self-diagnoses (0xC0000022 + the issue + the switch), and dev.on("error") tees a spawn failure into engine.log instead of swallowing it
$(BUN) run desktop/scripts/demo_p_gpufix_1.ts
.PHONY: demo-P-COLLAB.6
demo-P-COLLAB.6: ## P-COLLAB.6 (ADR-0193): enterprise/MDM governance for the embedded relay - fail-closed + absolute allowlisting. Unmanaged = the user's call; a managed allowServe:false FORBIDS hosting (startRelayServer THROWS, no listener); under management a LAN/0.0.0.0 bind is REFUSED unless it's on the absolute host:port allowlist (localhost always ok); allowedRelays whitelists which relay endpoints a user may connect to (malformed fails closed). The 'be the relay' toggle UI reads this + managedLocks.collab
$(BUN) run harness/scripts/demo_pcollab6.ts
.PHONY: demo-P-TRAINER.1
demo-P-TRAINER.1: ## P-TRAINER.1 (ADR-0252/0255): the pure interview engine over the WMO coverage map - a scripted extraction session opens with a SCENARIO probe, asks ONE question at a time (a second nextQuestion re-issues the pending one), chases deviation cues with capped five-whys followups before returning to the map, never re-asks L3-confirmed ground, and past the session cap it closes with a visible-progress recap instead of asking on
$(BUN) run harness/scripts/demo_p_trainer_1.ts
.PHONY: demo-P-TRAINER.2