strykelang 0.13.7

A highly parallel Perl 5 interpreter written in Rust
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="color-scheme" content="dark light">
  <meta name="description" content="stryke — the hottest language ever created. Server farms first. 100% TDP load testing, distributed agents, parallel Perl 5 interpreter in Rust. ~368k-line Rust slice (production + tests + tooling), 10,020 builtins (10,632 spellings), 346-opcode VM + Cranelift JIT.">
  <title>stryke — Documentation</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700;900&amp;family=Share+Tech+Mono&amp;display=swap" rel="stylesheet">
  <link rel="stylesheet" href="hud-static.css">
  <link rel="stylesheet" href="tutorial.css">
  <style>
    .tutorial-main { max-width: 68rem; }
    .docs-build-line {
      margin: 0.35rem 0 0;
      font-family: 'Share Tech Mono', ui-monospace, monospace;
      font-size: 11px;
      color: var(--text-dim);
      letter-spacing: 0.03em;
      max-width: 42rem;
      opacity: 0.75;
    }
    .hub-scheme-strip {
      border-bottom: 1px dashed var(--border);
      background: color-mix(in srgb, var(--bg-secondary) 85%, transparent);
      padding: 0.55rem 1.5rem 0.65rem;
      position: relative;
    }
    .hub-scheme-strip-inner {
      max-width: 68rem;
      margin: 0 auto;
      display: flex;
      align-items: center;
      gap: 0.85rem;
    }
    .hub-scheme-strip .hud-scheme-label {
      flex: 0 0 auto;
      font-family: 'Orbitron', sans-serif;
      font-size: 9px;
      font-weight: 700;
      letter-spacing: 2px;
      text-transform: uppercase;
      color: var(--accent);
      text-align: left;
    }
    .hub-scheme-strip .scheme-grid {
      flex: 1 1 auto;
      display: grid;
      grid-template-columns: repeat(5, minmax(0, 1fr));
      gap: 6px;
    }
    @media (max-width: 720px) {
      .hub-scheme-strip-inner { flex-direction: column; align-items: stretch; }
      .hub-scheme-strip .scheme-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }

    /* Reflection / builtin tables */
    .reflection-table {
      width: 100%;
      border-collapse: collapse;
      margin: 0.6rem 0 0.2rem;
      font-size: 12px;
    }
    .reflection-table th {
      background: var(--bg-secondary);
      color: var(--cyan);
      font-family: 'Orbitron', sans-serif;
      font-size: 10px;
      font-weight: 700;
      letter-spacing: 1px;
      text-transform: uppercase;
      text-align: left;
      padding: 6px 10px;
      border: 1px solid var(--border);
    }
    .reflection-table td {
      padding: 6px 10px;
      border: 1px solid var(--border);
      color: var(--text-dim);
      vertical-align: top;
    }
    .reflection-table td code { color: var(--accent-light); background: var(--bg); }

    /* One-liner example blocks — pre with a "copy" affordance via user select */
    .oneliner {
      margin: 0.4rem 0;
      padding: 0.55rem 0.8rem;
      border-left: 2px solid var(--cyan);
      background: var(--bg);
      font-family: 'Share Tech Mono', ui-monospace, monospace;
      font-size: 12px;
      color: var(--text);
      white-space: pre-wrap;
      word-break: break-word;
    }
    .oneliner .comment { color: var(--text-muted); }

    /* Index-card grid for builtin categories */
    .cat-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
      gap: 0.6rem;
      margin: 0.7rem 0;
    }
    .cat-card {
      border: 1px solid var(--border);
      border-left: 2px solid var(--cyan);
      padding: 0.6rem 0.8rem;
      background: color-mix(in srgb, var(--bg-card) 92%, transparent);
      border-radius: 2px;
    }
    .cat-card h4 {
      font-family: 'Orbitron', sans-serif;
      font-size: 11px;
      font-weight: 700;
      letter-spacing: 1.5px;
      text-transform: uppercase;
      color: var(--cyan);
      margin: 0 0 0.35rem;
    }
    .cat-card p {
      margin: 0;
      font-size: 11.5px;
      color: var(--text-dim);
      line-height: 1.5;
    }
    .cat-card code { font-size: 11px; color: var(--accent-light); }
  </style>
</head>
<body>
  <div class="app tutorial-app" id="docsApp">
    <div class="crt-scanline" id="crtH" aria-hidden="true"></div>
    <div class="crt-scanline-v" id="crtV" aria-hidden="true"></div>

    <header class="tutorial-header">
      <div class="tutorial-header-inner">
        <div>
          <h1 class="tutorial-brand">// STRYKE — THE HOTTEST LANGUAGE EVER CREATED 🔥</h1>
          <nav class="tutorial-crumbs" aria-label="Breadcrumb">
            <span class="current">Docs</span>
            <span class="sep">/</span>
            <a href="reference.html">Full reference</a>
            <span class="sep">/</span>
            <a href="https://github.com/MenkeTechnologies/strykelang" target="_blank" rel="noopener noreferrer">GitHub</a>
            <span class="sep">/</span>
            <a href="https://crates.io/crates/strykelang" target="_blank" rel="noopener noreferrer">crates.io</a>
            <span class="sep">/</span>
            <a href="https://docs.rs/strykelang" target="_blank" rel="noopener noreferrer">docs.rs</a>
          </nav>
          <p class="docs-build-line" id="strykeBuildLine">stryke v0.13.6 · Server farms first · 100% TDP load testing · Distributed agents · Cranelift JIT · 10,020 builtins (10,632 spellings)</p>
        </div>
        <div class="tutorial-toolbar">
          <button type="button" class="btn btn-secondary" id="btnTheme" title="Toggle light/dark">Theme</button>
          <button type="button" class="btn btn-secondary active" id="btnCrt" title="CRT scanline overlay">CRT</button>
          <button type="button" class="btn btn-secondary active" id="btnNeon" title="Neon border pulse">Neon</button>
          <a class="btn btn-secondary" href="reference.html">Reference</a>
          <a class="btn btn-secondary" href="https://github.com/MenkeTechnologies/strykelang" target="_blank" rel="noopener noreferrer">GitHub</a>
          <a class="btn btn-secondary" href="https://github.com/MenkeTechnologies/strykelang/issues" target="_blank" rel="noopener noreferrer">Issues</a>
        </div>
      </div>
    </header>

    <div class="hub-scheme-strip">
      <div class="hub-scheme-strip-inner">
        <span class="hud-scheme-label">// Color scheme</span>
        <div class="scheme-grid" id="hudSchemeGrid"></div>
      </div>
    </div>

    <main class="tutorial-main">
      <h2 class="tutorial-title"><span class="step-hash">&gt;_</span>STRYKE — SERVER FARMS FIRST</h2>
      <p class="tutorial-subtitle"><strong>The hottest language ever created. Literally.</strong> Pin millions of servers to 100% TDP from a single REPL. Distributed load testing with <code>stryke agent</code> + <code>stryke controller</code>. Also a blazing-fast Perl 5 interpreter: NaN-boxed values, Rayon work-stealing across every CPU, bytecode VM with Cranelift Block JIT, 10,020 builtins (10,632 callable spellings), and pipe-forward syntax. <strong>100% TDP — beware.</strong></p>

      <section class="tutorial-section">
        <h2>Quickstart</h2>
        <p>Install from crates.io or source, then run scripts or one-liners with <code>s</code> (short for stryke):</p>
<pre># install
cargo install strykelang

# from source
git clone https://github.com/MenkeTechnologies/strykelang
cd strykelang &amp;&amp; cargo build --release

# one-liners
s 'p "hello, world"'
s '1:20 |&gt; fi even |&gt; map { _ * _ } |&gt; sum |&gt; p'
s '~>1:20fi{even}map{_*_}sum p'
s 'qw(a b c) |&gt; map uc |&gt; join "," |&gt; p'
s '~> qw(a,b,c) map{uc} join(",") p'

# parallel primitives
s '1:8 |&gt; pmap expensive |&gt; p'

# read + parse JSON
s 'read_json("data.json") |&gt; to_yaml |&gt; p'
s 'p to_yaml read_json "data.json"'</pre>
        <p>Full install + usage live in the <a href="https://github.com/MenkeTechnologies/strykelang#readme">README</a>.</p>
        <p><strong><code>-e</code> is optional.</strong> If the first argument isn't a file and looks like code, <code>s</code> runs it directly. <code>s 'p 42'</code> and <code>s -e 'p 42'</code> are equivalent.</p>
      </section>

      <section class="tutorial-section">
        <h2>Why stryke — One-Liner Comparison</h2>
        <table class="comparison-table" style="width:100%; border-collapse:collapse; font-size:0.85em;">
          <thead>
            <tr style="border-bottom:2px solid #0ff;">
              <th style="text-align:left; padding:4px;">Feature</th>
              <th style="padding:4px;">stryke</th>
              <th style="padding:4px;">perl5</th>
              <th style="padding:4px;">ruby</th>
              <th style="padding:4px;">python</th>
              <th style="padding:4px;">awk</th>
              <th style="padding:4px;">jq</th>
            </tr>
          </thead>
          <tbody>
            <tr><td>No <code>-e</code> flag needed</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>—</td><td>—</td></tr>
            <tr><td>No semicolons</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10003;</td><td>&#10003;</td><td>&#10003;</td><td>&#10003;</td></tr>
            <tr><td>Built-in HTTP</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Built-in JSON</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10003;</td><td>&#10007;</td><td>&#10003;</td></tr>
            <tr><td>Built-in CSV</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10003;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Built-in SQLite</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10003;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Parallel map/grep</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Pipe-forward <code>|&gt;</code></td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td><code>|</code></td></tr>
            <tr><td>Thread macro</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>In-place edit <code>-i</code></td><td style="color:#0f0;">parallel</td><td>sequential</td><td>sequential</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Data viz (spark/bars/flame)</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Clipboard</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Stress testing / heat</td><td style="color:#f55;"><b>100% TDP</b></td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Distributed agents</td><td style="color:#0f0;">&#10003;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>JIT compiler</td><td style="color:#0f0;">Cranelift</td><td>&#10007;</td><td>YJIT</td><td>&#10007;</td><td>&#10007;</td><td>&#10007;</td></tr>
            <tr><td>Single binary</td><td style="color:#0f0;">33MB</td><td>pkg</td><td>pkg</td><td>pkg</td><td>pkg</td><td>3MB</td></tr>
          </tbody>
        </table>
        <h3 style="margin-top:1em;">Character count — real tasks</h3>
        <table style="width:100%; border-collapse:collapse; font-size:0.85em;">
          <thead>
            <tr style="border-bottom:2px solid #0ff;">
              <th style="text-align:left; padding:4px;">Task</th>
              <th style="padding:4px;">s</th>
              <th style="padding:4px;">perl5</th>
              <th style="padding:4px;">ruby</th>
              <th style="padding:4px;">python</th>
            </tr>
          </thead>
          <tbody>
            <tr><td>Sum 1:100</td><td style="color:#0f0;"><code>s 'p sum 1:100'</code> <b>19c</b></td><td>45c</td><td>28c</td><td>38c</td></tr>
            <tr><td>Word freq</td><td style="color:#0f0;"><code>s -an 'freq(@F) |&gt; dd'</code> <b>25c</b></td><td>61c</td><td>—</td><td>—</td></tr>
            <tr><td>SHA256 file</td><td style="color:#0f0;"><code>s 'p s256"f"'</code> <b>14c</b></td><td>70c+</td><td>—</td><td>80c+</td></tr>
            <tr><td>CSV → JSON</td><td style="color:#0f0;"><code>s 'csv_read("f") |&gt; tj |&gt; p'</code> <b>33c</b></td><td>needs modules</td><td>needs modules</td><td>90c</td></tr>
            <tr><td>Parallel map</td><td style="color:#0f0;"><code>s '1:1e6 |&gt; pmap{_ * 2}'</code> <b>30c</b></td><td>—</td><td>—</td><td>—</td></tr>
          </tbody>
        </table>
      </section>

      <section class="tutorial-section">
        <h2>Overview</h2>
        <ul>
          <li><strong>Parser &amp; compiler</strong> — recursive-descent parser in <code>strykelang/parser.rs</code>, producing an AST consumed by the bytecode <code>Compiler</code> (<code>strykelang/compiler.rs</code>) that feeds the VM (<code>strykelang/vm.rs</code>). 100% lowered to bytecode. Cranelift Block JIT kicks in for hot blocks (<code>strykelang/jit.rs</code>).</li>
          <li><strong>Values</strong> — <code>StrykeValue</code> is a NaN-boxed <code>u64</code>: immediates (<code>undef</code>, <code>i32</code>, raw <code>f64</code> bits) and tagged <code>Arc&lt;HeapObject&gt;</code> pointers for big ints, strings, arrays, hashes, refs, regexes, atomics, channels.</li>
          <li><strong>Regex</strong> — three-tier engine: Rust <code>regex</code> → <code>fancy-regex</code> (backrefs) → <code>pcre2</code> (PCRE-only verbs).</li>
          <li><strong>Parallelism</strong> — every parallel builtin uses rayon work-stealing across all cores. See <code>pmap</code>, <code>pflat_map</code>, <code>pgrep</code>, <code>pfor</code>, <code>psort</code>, <code>preduce</code>, <code>pcache</code>, <code>ppool</code>, <code>fan</code>, <code>pipeline</code>, <code>par_pipeline_stream</code>, <code>pchannel</code>, <code>pselect</code>, <code>par_walk</code>, <code>par_lines</code>, <code>par_sed</code>.</li>
          <li><strong>Stress testing</strong> — <code>heat(60)</code> pins ALL cores to 100% TDP. <code>stryke agent</code> + <code>stryke controller</code> for distributed fleet-wide load testing. The hottest language ever created.</li>
          <li><strong>Binary size</strong> — ~21 MB stripped with LTO + O3.</li>
        </ul>
      </section>

      <section class="tutorial-section">
        <h2>Language reflection</h2>
        <p>Everything the parser and dispatcher know about is exposed as plain Perl hashes, populated from the source of truth at compile time. <code>build.rs</code> parses category-labeled section comments in <code>is_perl5_core</code> / <code>stryke_extension_name</code>, the <code>try_builtin</code> match arms, and LSP hover docs in <code>doc_for_label_text</code>. <strong>Nine hashes — every direct lookup is O(1)</strong>. Plus per-package symbol-table stashes (<code>%main::</code>, <code>%Foo::</code>, …) and the live-binding view (<code>%parameters</code>).</p>

        <h3>Forward maps</h3>
        <table class="reflection-table">
          <thead>
            <tr><th>Long name</th><th>Short</th><th>Key → Value</th></tr>
          </thead>
          <tbody>
            <tr><td><code>%stryke::builtins</code></td><td><code>%b</code></td><td><strong>primary</strong> callable name → category. Callable-only — keywords live in <code>%k</code>, never <code>%b</code>.</td></tr>
            <tr><td><code>%stryke::keywords</code></td><td><code>%k</code></td><td>stryke language keyword → category (<code>"control"</code>, <code>"decl"</code>, <code>"exception"</code>, <code>"phase"</code>, <code>"concurrency"</code>, <code>"oo"</code>, <code>"aop"</code>, <code>"operator"</code>, <code>"quote"</code>, <code>"visibility"</code>, <code>"special"</code>). Disjoint from <code>%b</code>.</td></tr>
            <tr><td><code>%stryke::all</code></td><td><code>%all</code></td><td><strong>every name</strong> stryke recognizes — <code>%a + %b + %k</code>. Use for <code>scalar keys %all</code>.</td></tr>
            <tr><td><code>%stryke::perl_compats</code></td><td><code>%pc</code></td><td>subset of <code>%b</code>: Perl 5 core only, name → category</td></tr>
            <tr><td><code>%stryke::extensions</code></td><td><code>%e</code></td><td>subset of <code>%b</code>: stryke-only, name → category</td></tr>
            <tr><td><code>%stryke::aliases</code></td><td><code>%a</code></td><td>alias → canonical primary</td></tr>
            <tr><td><code>%stryke::descriptions</code></td><td><code>%d</code></td><td>name → LSP one-liner (<em>sparse</em>)</td></tr>
          </tbody>
        </table>

        <h3>Inverted indexes (O(1) reverse-query)</h3>
        <table class="reflection-table">
          <thead>
            <tr><th>Long name</th><th>Short</th><th>Key → Value</th></tr>
          </thead>
          <tbody>
            <tr><td><code>%stryke::categories</code></td><td><code>%c</code></td><td>category → arrayref of names (<code>$c{parallel}</code> → <code>[pmap, pgrep, …]</code>)</td></tr>
            <tr><td><code>%stryke::primaries</code></td><td><code>%p</code></td><td>primary → arrayref of its aliases (<code>$p{to_json}</code> → <code>[tj]</code>)</td></tr>
          </tbody>
        </table>

        <h3>Live-binding view (zsh <code>$parameters</code> analogue)</h3>
        <p><code>%parameters</code> is rebuilt on every read so it always reflects the current scope. Keys are sigil-prefixed names (<code>$x</code>, <code>@a</code>, <code>%h</code>, <code>$Pkg::var</code>); values are kind strings.</p>
        <table class="reflection-table">
          <thead>
            <tr><th>Hash</th><th>Key → Value</th></tr>
          </thead>
          <tbody>
            <tr><td><code>%parameters</code></td><td>sigil-prefixed name → kind (<code>"scalar"</code> / <code>"array"</code> / <code>"hash"</code> / <code>"atomic_array"</code> / <code>"atomic_hash"</code> / <code>"shared_array"</code> / <code>"shared_hash"</code>). Includes lexicals (<code>my $x</code>) and globals (<code>our $X</code>) and the reflection / stash hashes themselves.</td></tr>
          </tbody>
        </table>

        <h3>Package stashes (Perl-spec symbol table)</h3>
        <p>Per-package <code>%Pkg::</code> hashes show what each package <em>declares</em> — populated from <code>our</code> declarations and <code>sub</code> definitions, exactly like Perl 5. Lexical <code>my</code> bindings never enter a stash. Refreshed lazily on every read so newly-defined subs appear immediately.</p>
        <table class="reflection-table">
          <thead>
            <tr><th>Hash</th><th>Key → Value</th></tr>
          </thead>
          <tbody>
            <tr><td><code>%main::</code> / <code>%Foo::</code> / <code>%Foo::Bar::</code></td><td>unqualified symbol name → kind (<code>"scalar"</code> / <code>"sub"</code>). Built from <code>our $X</code> + <code>sub foo { }</code> in that package. Stryke-spec note: <code>our @arr</code> / <code>our %h</code> currently do not enter the stash (only <code>our $scalar</code> and <code>sub</code>).</td></tr>
          </tbody>
        </table>

        <p><strong><code>--compat</code> boundary:</strong> the nine reflection hashes (<code>%b</code> / <code>%k</code> / <code>%all</code> / <code>%pc</code> / <code>%e</code> / <code>%a</code> / <code>%d</code> / <code>%c</code> / <code>%p</code> + their <code>%stryke::*</code> long names) and <code>%parameters</code> are stryke-only — <code>--compat</code> turns them off entirely so they don't collide with user-declared hashes of the same name. Package stashes (<code>%main::</code>) and <code>%ENV</code> / <code>%INC</code> / <code>%SIG</code> stay on in every mode (Perl 5 spec).</p>

        <h3>Examples</h3>
        <div class="oneliner">s 'p $b{pmap}'                              <span class="comment"># "parallel"</span></div>
        <div class="oneliner">s 'p $b{to_json}'                           <span class="comment"># "serialization"</span></div>
        <div class="oneliner">s 'p $k{if}'                                <span class="comment"># "control"</span></div>
        <div class="oneliner">s 'p $k{class}'                             <span class="comment"># "decl"</span></div>
        <div class="oneliner">s 'p $all{tj}'                              <span class="comment"># "serialization"  (alias resolves via %all)</span></div>
        <div class="oneliner">s 'p $all{while}'                           <span class="comment"># "control"        (keyword resolves via %all)</span></div>
        <div class="oneliner">s 'p scalar keys %all'                      <span class="comment"># total names — callables + aliases + keywords</span></div>
        <div class="oneliner">s 'p $pc{map}'                              <span class="comment"># "array / list"   (Perl core only)</span></div>
        <div class="oneliner">s 'p $e{pmap}'                              <span class="comment"># "parallel"       (extensions only)</span></div>
        <div class="oneliner">s 'p $a{tj}'                                <span class="comment"># "to_json"</span></div>
        <div class="oneliner">s 'p $d{pmap}'                              <span class="comment"># LSP one-liner</span></div>
        <div class="oneliner">s '$c{parallel} |&gt; e p'                      <span class="comment"># every parallel op, O(1) reverse-lookup</span></div>
        <div class="oneliner">s '$p{to_json} |&gt; e p'                       <span class="comment"># every alias of to_json</span></div>
        <div class="oneliner">s 'keys %pc |&gt; sort |&gt; p'                    <span class="comment"># every Perl compat, sorted</span></div>
        <div class="oneliner">s 'keys %e  |&gt; sort |&gt; p'                    <span class="comment"># every stryke extension</span></div>
        <div class="oneliner">s 'keys %k  |&gt; sort |&gt; p'                    <span class="comment"># every keyword, sorted</span></div>
        <div class="oneliner">s 'keys %all |&gt; less'                       <span class="comment"># browse every spelling in $PAGER</span></div>
        <div class="oneliner">s 'my %f; $f{$b{_}}++ for keys %b; dd \%f'  <span class="comment"># per-category frequency</span></div>
        <div class="oneliner">s 'for my $h (qw(b k all pc e a d c p)) { printf "%%%-4s %d\n", $h, scalar keys %$h }'  <span class="comment"># catalog</span></div>
        <div class="oneliner">s 'p sort keys %{ merge_hash(\%all, \%parameters) }'  <span class="comment"># every callable + every live binding, sorted</span></div>
        <div class="oneliner">s 'my @scalars = grep { /^\$/ } keys %parameters; p @scalars'  <span class="comment"># live scalars only</span></div>
        <div class="oneliner">s 'package Foo; our $X = 1; sub hello {} ; p sort keys %Foo::'  <span class="comment"># X, hello (our + sub, not my)</span></div>
        <div class="oneliner">s '--compat' -e 'print scalar keys %all'  <span class="comment"># 0 — extensions off in --compat</span></div>

        <h3>Diagnostics &amp; tab-complete dump</h3>
        <div class="oneliner">s 'doctor'                                                  <span class="comment"># runtime health: version, flags, paths, toolchain (returns warning count)</span></div>
        <div class="oneliner">s 'health'                                                  <span class="comment"># alias of doctor</span></div>
        <div class="oneliner">s 'lsp_words |&gt; ep'                                       <span class="comment"># every name LSP tab-complete knows about (~18k entries)</span></div>
        <div class="oneliner">s 'lsp_words |&gt; ep' &gt; strykelang/lsp_completion_words.txt   <span class="comment"># regenerate the static-analyzer / completion snapshot</span></div>
        <div class="oneliner">s 'p len(lsp_words)'                                        <span class="comment"># count: bare names + sigil globals + CORE:: + main:: + keywords</span></div>
        <div class="oneliner">s 'p now'                                                  <span class="comment"># Unix epoch seconds (alias of time)</span></div>
        <div class="oneliner">s 'p now("UTC")'                                           <span class="comment"># ISO-8601 datetime string in any IANA timezone</span></div>
        <div class="oneliner">s 'my @qs = quantiles([1..1000], [0.25, 0.5, 0.75]); p @qs'   <span class="comment"># batch quantile lookup, single sort across all probs</span></div>
        <div class="oneliner">s 'class P { v: Int = 0 }; my $p = P-&gt;new(v=&gt;7); p $p-&gt;to_hash_rec'  <span class="comment"># recursively flatten class/struct trees to plain hashref</span></div>

        <h3>~p&gt; chunk-parallel — string sources</h3>
        <div class="oneliner">s '~p&gt; "the quick brown fox jumps over the lazy dog" letters freq |&gt; ddump'   <span class="comment"># parallel letter histogram of one string</span></div>
        <div class="oneliner">s 'my $n = ~p&gt; "the quick brown fox jumps over the lazy dog" letters freq ||&gt; values |&gt; sum; p $n'  <span class="comment"># 35 — parallel extract, sequential merge</span></div>
        <div class="oneliner">s 'my $n = ~p&gt; "the quick brown fox jumps over the lazy dog" letters freq |then| values |&gt; sum; p $n'  <span class="comment"># 35 — English boundary marker</span></div>
        <div class="oneliner">s 'my $r = ~&gt; "abcdefghij" par_reduce { length(_) }; p $r'                              <span class="comment"># 10 — par_reduce auto-sum, single-block form</span></div>
        <div class="oneliner">s 'my $r = ~&gt; "abcdefghij" par_reduce { length(_) } { _0 + _1 }; p $r'                  <span class="comment"># 10 — explicit pairwise reducer</span></div>
        <div class="oneliner">s 'my $m = ~&gt; "the quick brown fox" words par_reduce { len(_) } { _0 &gt; _1 ? _0 : _1 }; p $m'  <span class="comment"># 5 — max word length via custom reducer</span></div>

        <h3>~p&gt; chunk-parallel — corpus workloads</h3>
        <div class="oneliner">s 'my $h = ~p&gt; c("**.stk") letters freq; p len(keys %$h)'                          <span class="comment"># distinct letters across every .stk file</span></div>
        <div class="oneliner">s 'my $h = ~p&gt; c("**.stk") words freq; p len(keys %$h)'                            <span class="comment"># unique-word count across the corpus</span></div>
        <div class="oneliner">s 'my $h = ~p&gt; c("**.stk") sentences freq; p len(keys %$h)'                        <span class="comment"># unique-sentence count</span></div>
        <div class="oneliner">s 'my $n = ~p&gt; c("**.stk") par_reduce { length(_) }; p $n'                         <span class="comment"># total chars across the corpus (auto-sum)</span></div>
        <div class="oneliner">s 'my $n = ~p&gt; c("**.stk") par_reduce { my @l = split(/\n/,_); len(@l) }; p $n'    <span class="comment"># total lines across the corpus</span></div>
        <div class="oneliner">s 'my $n = ~p&gt; c("**.rs") par_reduce { my @m = (_ =~ /unsafe/g); len(@m) }; p $n'  <span class="comment"># count regex hits across all files</span></div>
        <div class="oneliner">s 'my $n = ~p&gt; c("**.stk") par_reduce { /threading/ ? 1 : 0 }; p $n'               <span class="comment"># files containing a pattern (truthy chunks)</span></div>
        <div class="oneliner">s 'my $h = ~p&gt; c("**.stk") words map { lc } map { substr(_,0,3) } freq; p $h-&gt;{the}'  <span class="comment"># histogram of 3-letter prefixes</span></div>

        <h3>~p&gt; chunk-parallel — top-N highlights</h3>
        <div class="oneliner">s 'my $h = ~p&gt; c("**.stk") letters freq; p (sort { $h-&gt;{$_1} &lt;=&gt; $h-&gt;{$_0} } keys %$h)[0..4]'  <span class="comment"># top 5 letters across .stk</span></div>
        <div class="oneliner">s 'my $h = ~p&gt; c("**.stk") words freq; p (sort { $h-&gt;{$_1} &lt;=&gt; $h-&gt;{$_0} } keys %$h)[0..9]'   <span class="comment"># top 10 words across .stk</span></div>

        <h3>~d&gt; distributed — same surface, chunks ship over ssh</h3>
        <div class="oneliner">s 'my $c = cluster("build1:8","build2:16"); my @h = ~d&gt; on $c c("**.stk") map { sha_256(slurp_raw($_)) }; say scalar @h'  <span class="comment"># hash every .stk in parallel across two hosts</span></div>
        <div class="oneliner">s 'my $c = cluster("h1:4","h2:4"); my @r = ~d&gt; on $c 1:1_000_000 map { $_ * 2 }; say "$r[0] .. $r[-1]"'  <span class="comment"># source-order preserved across slots</span></div>
        <div class="oneliner">s 'my $c = cluster("h1:8"); my @r = ~d&gt; on $c @urls map { fetch($_) } ||&gt; uniq sort'  <span class="comment"># ||&gt; switches back to sequential after the distributed stage</span></div>
        <div class="oneliner">STRYKE_CLUSTER_LOCAL_BIN=$(which stryke) s 'my $c = cluster("localhost:4"); my @r = ~d&gt; on $c 1:100 map { $_ + 100 }; say "@r[0..4]"'  <span class="comment"># loopback bypass — verify ~d&gt; without ssh keys</span></div>

        <h3>par { BLOCK } — generic chunk wrapper</h3>
        <div class="oneliner">s 'my @a = ~&gt; "Hello, World 123" par { letters }; p "@a"'                          <span class="comment"># H e l l o W o r l d — letters per chunk</span></div>
        <div class="oneliner">s 'my @r = ~&gt; "Hello, World" par { uc }; p "@r"'                                  <span class="comment"># per-chunk uppercase</span></div>

        <h3>~s&gt; per-item streaming — basics</h3>
        <div class="oneliner">s 'my $n = ~s&gt; [1, 2, 3, 4, 5] map { _ * 10 } map { _ + 1 }; p "$n items"'        <span class="comment"># basic two-stage stream</span></div>
        <div class="oneliner">s 'my $n = ~s&gt; [1..10] grep { _ % 2 == 0 } map { _ * _ }; p "$n matched"'         <span class="comment"># filter then transform</span></div>
        <div class="oneliner">s 'my $n = ~s&gt; [1..5] map { sleep 0.05; _ * _ }; p "$n items"'                    <span class="comment"># mixed I/O+CPU — workers overlap</span></div>

        <h3>~s&gt; per-item streaming — real workloads</h3>
        <div class="oneliner">s 'my @raw = ({\"v\":10}, {\"v\":20}, {\"v\":30}); my $n = ~s&gt; [@raw] map { _-&gt;{v} * 2 }; p $n'  <span class="comment"># streaming JSON-shape transform</span></div>
        <div class="oneliner">s 'my @log = ("INFO ok","ERROR oops","WARN slow","ERROR bad"); my $n = ~s&gt; [@log] grep { /ERROR/ } map { uc }; p $n'  <span class="comment"># streaming log filter (errors → upper)</span></div>
        <div class="oneliner">s 'mysync $sum = 0; my $n = ~s&gt; [10,20,30,40,50] map { $sum += _; _ }; p "$n items, sum=$sum"'   <span class="comment"># streaming with shared mysync accumulator</span></div>

        <h3>Notes</h3>
        <ul>
          <li>Every <code>$h{name}</code> lookup is O(1). Inverted indexes (<code>%c</code>, <code>%p</code>) let you do reverse-queries in O(1) too; filters like <code>grep { cond } keys %h</code> are still O(n).</li>
          <li>Hash sigil namespace is separate from scalars/functions — the short-alias letters don't collide with <code>$a</code>/<code>$b</code> sort specials, the <code>e</code> extension function, or any other stryke name.</li>
          <li><code>%descriptions</code> is sparse: <code>exists $d{$name}</code> doubles as "is this documented in the LSP?".</li>
          <li>A value of <code>"uncategorized"</code> in <code>%builtins</code> flags a name that's dispatched at runtime but missing a <code>// ── category ──</code> section comment in <code>parser.rs</code>.</li>
        </ul>
      </section>

      <section class="tutorial-section">
        <h2>Pipe-forward</h2>
        <p>The <code>|&gt;</code> operator (F# / Elixir) threads a value into the <strong>first argument</strong> of the next call — parse-time only, zero runtime cost.</p>
<pre>x |&gt; f          # f(x)
x |&gt; f(a, b)    # f(x, a, b)
x |&gt; f |&gt; g(2)  # g(f(x), 2)

# real pipeline — count words per file, top 10 longest:
f("*.txt") |&gt; map { [_, slurp(_) |&gt; split(/\s+/) |&gt; scalar] }
            |&gt; sort { $b-&gt;[1] &lt;=&gt; $a-&gt;[1] }
            |&gt; take(10)
            |&gt; dd</pre>
        <p>Precedence sits between <code>?:</code> and <code>||</code>, so <code>x + 1 |&gt; f || y</code> parses as <code>f(x + 1) || y</code>.</p>

        <h3>Pipe-RHS sugar</h3>
        <ul>
          <li><strong>Thread macro</strong> — <code>t EXPR s1 s2 s3</code> expands to <code>EXPR |&gt; s1 |&gt; s2 |&gt; s3</code>. Stages like <code>pow(_, 2)</code> use bare <code>_</code> (or <code>_</code>) as a placeholder, auto-wrapped in a coderef. Bare <code>_</code> = <code>_</code> in any expression — enables <code>map{_*2}fi{_&gt;5}</code>.</li>
          <li><strong><code>&gt;{ BLOCK }</code></strong> — IIFE anywhere an expression is valid; also works as a pipe stage (<code>lhs |&gt; &gt;{ body }</code>).</li>
          <li><strong><code>@[...]</code></strong> — sugar for <code>@{[...]}</code> (deref anonymous arrayref inline).</li>
          <li><strong><code>%[k =&gt; v]</code></strong> — sugar for <code>%{+{k =&gt; v}}</code> (deref anonymous hashref inline, sidesteps the block-vs-hashref ambiguity).</li>
        </ul>
      </section>

      <section class="tutorial-section">
        <h2>String coordinates — bytes vs codepoints</h2>
        <p>Stryke runs string code in two coordinate systems. <strong>Perl 5 builtins stay byte-indexed</strong> for binary-protocol and <code>.pm</code>-source compat. <strong>Stryke extensions are codepoint-indexed</strong> so search positions and slice bounds line up. They are never auto-converted — pick one coordinate system per expression and keep it consistent.</p>

        <table class="reflection-table">
          <thead>
            <tr><th>Operation</th><th>Stryke (codepoints)</th><th>Perl 5 (bytes)</th></tr>
          </thead>
          <tbody>
            <tr><td>Length</td><td><code>len $s</code></td><td><code>length $s</code></td></tr>
            <tr><td>Index char</td><td><code>$s[$i]</code></td><td><code>substr $s, $i, 1</code></td></tr>
            <tr><td>Slice</td><td><code>$s[$a:$b]</code> (inclusive)</td><td><code>substr $s, $start, $len</code></td></tr>
            <tr><td>Search forward</td><td><code>cindex $s, $needle [, $from]</code></td><td><code>index $s, $needle [, $from]</code></td></tr>
            <tr><td>Search backward</td><td><code>crindex $s, $needle [, $from]</code></td><td><code>rindex $s, $needle [, $from]</code></td></tr>
            <tr><td>Match position</td><td>—</td><td><code>pos $s</code> (regex <code>\G</code>)</td></tr>
          </tbody>
        </table>

<pre><span class="comment"># `─` is 3 bytes in UTF-8 / 1 codepoint</span>
my $s = "hello ─ world"

length $s                    <span class="comment"># 15  (bytes)</span>
len    $s                    <span class="comment"># 13  (codepoints)</span>
index  $s, "world"           <span class="comment"># 9   (byte position — past the 3-byte `─`)</span>
cindex $s, "world"           <span class="comment"># 7   (codepoint position)</span>
$s[7]                        <span class="comment"># "w" — codepoint index</span>
substr $s, 9, 1              <span class="comment"># "w" — byte index</span>
$s[7:11]                     <span class="comment"># "world" — codepoint slice</span>
substr $s, 9, 5              <span class="comment"># "world" — byte substr</span></pre>

        <p><strong>Rule:</strong> never feed an <code>index</code> / <code>pos</code> / <code>length</code> result into a <code>[$a:$b]</code> slice, and never feed a <code>cindex</code> / <code>crindex</code> / <code>len</code> result into <code>substr</code> / <code>index</code>. The coordinate systems silently misalign on any string containing non-ASCII bytes.</p>

        <p><code>--no-interop</code> does <strong>not</strong> force this split — both systems remain available because Perl 5 binary-protocol code legitimately needs byte positions. The split is a coordinate-system choice, not a stylistic one.</p>
      </section>

      <section class="tutorial-section">
        <h2>Builtin categories</h2>
        <p>10,020 primary operations across 10,632 spellings. Query them via <code>keys %stryke::builtins</code> — the table below is a navigational overview, not a full index. Run <code>s 'p scalar keys %b'</code> for the live count.</p>
        <div class="cat-grid">
          <div class="cat-card"><h4>Array / List (134+)</h4><p><code>map maps flat_map grep sort reverse push pop shift unshift splice reduce fold fore e first any all none take take_while drop skip_while partition min_by max_by zip zip_with interleave frequencies count_by chunk windowed enumerate shuffle uniq dedup compact flatten concat pluck grep_v with_index sorted sorted_desc sorted_nums without take_last drop_last pairwise batch rotate swap_pairs sliding_pairs run_length_encode group_consecutive permutations combinations power_set cartesian_product</code> &hellip;</p></div>
          <div class="cat-card"><h4>String (129+)</h4><p><code>chomp chop length substr index rindex split join uc lc ucfirst lcfirst chr ord trim lines words chars snake_case camel_case kebab_case pascal_case constant_case capitalize swap_case title_case squish pad_left pad_right center truncate_at reverse_str rot13 rot47 caesar_shift count_vowels count_consonants first_word last_word left_str right_str wrap_text dedent indent strip_html levenshtein soundex extract_numbers extract_emails extract_urls</code> &hellip;</p></div>
          <div class="cat-card"><h4>Math / Numeric (147+)</h4><p><code>abs int sqrt sin cos tan asin acos atan sinh cosh tanh exp log rand srand inc dec avg stddev clamp normalize range even odd zero positive negative sign negate double triple half round floor ceil gcd lcm factorial fibonacci is_prime divisors sieve_primes cbrt log2 log10 hypot rad_to_deg deg_to_rad pow2 softmax argmax argmin</code> &hellip;</p></div>
          <div class="cat-card"><h4>Conversion / Units (102+)</h4><p><code>c_to_f f_to_c c_to_k k_to_c miles_to_km km_to_miles feet_to_m m_to_feet inches_to_cm kg_to_lbs lbs_to_kg bytes_to_kb bytes_to_mb bytes_to_gb seconds_to_minutes hours_to_seconds liters_to_gallons cups_to_ml joules_to_cal watts_to_hp pascals_to_psi to_bin to_hex to_oct from_bin from_hex from_oct to_base from_base</code> &hellip;</p></div>
          <div class="cat-card"><h4>Validation (91+)</h4><p><code>is_empty is_blank is_numeric is_upper is_lower is_alpha is_digit is_alnum is_space is_palindrome is_prime is_sorted is_subset is_superset is_valid_ipv4 is_valid_ipv6 is_valid_email is_valid_url is_valid_json is_valid_semver is_valid_base64 is_ascii is_printable luhn_check is_undef is_defined is_array is_hash is_code is_ref is_int is_float</code> &hellip;</p></div>
          <div class="cat-card"><h4>Hash / Map (52+)</h4><p><code>keys values each delete exists select_keys top invert merge_hash has_key has_any_key has_all_keys pick omit hash_size hash_from_pairs pairs_from_hash hash_eq keys_sorted values_sorted hash_insert hash_update hash_delete zipmap counter</code></p></div>
          <div class="cat-card"><h4>Encoding / Crypto (64+)</h4><p><code>sha1 sha256 sha384 sha512 md5 hmac_sha256 uuid crc32 base64_encode base64_decode hex_encode hex_decode url_encode url_decode gzip gunzip zstd zstd_decode jwt_encode jwt_decode html_escape_str html_unescape_str shell_escape sql_escape hex_dump random_password random_hex_str</code></p></div>
          <div class="cat-card"><h4>I/O (62+)</h4><p><code>print p say printf open close eof readline read seek tell slurp input capture pager/pg/less binmode flock getc select truncate read_lines append_file to_file read_json write_json tempfile tempdir file_size file_mtime file_atime is_symlink is_readable is_writable is_executable xopen/xo</code></p></div>
          <div class="cat-card"><h4>Filesystem (84+)</h4><p><code>files/f fr dirs/d dr sym_links glob glob_par basename dirname realpath which stat lstat size copy move spurt read_bytes path_ext path_stem path_parent path_join path_split path_is_abs path_is_rel strip_prefix strip_suffix ensure_prefix ensure_suffix</code> &mdash; <strong>full zsh glob qualifier set</strong> (<code>(/)</code>, <code>(.)</code>, <code>(@)</code>, <code>(*)</code>, <code>(L+N)</code>, <code>(om[1])</code>, <code>(N)</code>, <code>(D)</code>, <code>^</code>, <code>,</code>) on every glob entry-point.</p></div>
          <div class="cat-card"><h4>Serialization</h4><p><code>to_json/tj to_csv/tc to_toml/tt to_yaml/ty to_xml/tx to_html/th to_markdown/to_md/tmd ddump/dd stringify/str json_encode/decode yaml_encode/decode toml_encode/decode xml_encode/decode json_pretty json_minify escape_json</code></p></div>
          <div class="cat-card"><h4>Parallel (31)</h4><p><code>pmap pflat_map pgrep pfor psort preduce preduce_init pmap_reduce pmap_chunked pcache ppool pchannel pselect puniq pfirst pany fan fan_cap pipeline par_pipeline_stream glob_par par_walk par_lines par_sed par_find_files par_line_count pwatch watch</code></p></div>
          <div class="cat-card" style="border-color:#f55;"><h4>🔥 Stress Testing</h4><p><code>stress_cpu stress_mem stress_io stress_test heat</code> — Pin ALL cores to 100% TDP. <code>stryke agent</code> + <code>stryke controller</code> for distributed fleet-wide load testing. The hottest language ever created. Literally.</p></div>
          <div class="cat-card"><h4>Functional (56+)</h4><p><code>reduce fold inject collect complement constantly coalesce default_to when_true when_false if_else safe_div safe_mod safe_sqrt safe_log scan accumulate keep_if reject_if group_consecutive normalize_list softmax argmax argmin juxt2 juxt3 tap_val debug_val converge iterate_n unfold</code> &hellip;</p></div>
          <div class="cat-card"><h4>Matrix / Linear Algebra (29+)</h4><p><code>dot_product cross_product matrix_add matrix_scale matrix_multiply identity_matrix zeros_matrix ones_matrix diagonal matrix_trace matrix_shape matrix_row matrix_col magnitude vec_normalize vec_add vec_sub vec_scale linspace arange</code></p></div>
          <div class="cat-card"><h4>Data / Network (50+)</h4><p><code>fetch fetch_json fetch_async par_fetch csv_read csv_write dataframe sqlite json_jq ipv4_to_int int_to_ipv4 email_domain email_local url_host url_path url_query url_scheme</code></p></div>
          <div class="cat-card"><h4>Date / Time (48+)</h4><p><code>time localtime gmtime is_leap_year days_in_month month_name weekday_name quarter_of now_ms now_us now_ns unix_epoch today yesterday tomorrow is_weekend is_weekday datetime_utc datetime_from_epoch datetime_strftime</code></p></div>
          <div class="cat-card"><h4>System / Process (35+)</h4><p><code>system exec exit fork wait waitpid kill alarm sleep os_name os_arch num_cpus pid ppid uid gid username home_dir temp_dir cwd is_root uptime_secs cmd_exists env_get env_has env_set env_keys env_pairs signal_name has_stdin_tty has_stdout_tty</code></p></div>
          <div class="cat-card"><h4>Geometry (45+)</h4><p><code>distance_2d distance_3d midpoint slope area_triangle area_circle circumference perimeter_rect area_rect point_in_circle point_in_rect triangle_area_heron triangle_area_pts polygon_centroid_b28 sphere_volume_b28 sphere_surface_b28 n_ball_volume cylinder_volume_b28 cone_volume_b28 torus_volume_b28 ellipsoid_volume tetrahedron_volume_b28 dist_point_line_2d dist_point_plane_3d closest_pt_segment_2d bbox_from_points haversine_distance_b28 great_circle_law_of_cos initial_bearing midpoint_great_circle shoelace_area polygon_is_convex convex_hull_jarvis euler_characteristic genus_from_euler picks_theorem covariance_matrix_pts</code></p></div>
          <div class="cat-card"><h4>Physics / EM / Optics / Relativity (68+)</h4><p><code>coulomb_force_b23 efield_point epotential_point capacitance_parallel_b23 capacitor_energy_b23 ohm_voltage power_vi power_i2r resistance_series_b23 bfield_wire bfield_solenoid lorentz_force_mag cyclotron_frequency_b23 larmor_radius_b23 faraday_emf inductor_energy_b23 lc_frequency rc_tau rl_tau poynting_magnitude em_intensity radiation_pressure em_wavelength em_frequency snell_theta2 critical_angle_b23 brewster_angle_b23 fresnel_rs fresnel_rp lensmaker thin_lens_v lens_magnification diffraction_grating_angle rayleigh_resolution lorentz_gamma time_dilation_b23 length_contraction_b23 rel_momentum rel_ke rel_total_energy relativistic_doppler rel_velocity_add compton_shift_b23 photon_momentum_b23 wave_string_speed sound_solid sound_gas doppler_classical sound_db plasma_frequency_b23 debye_length_b23 alfven_speed schwarzschild_radius_b23 grav_time_dilation grav_redshift</code></p></div>
          <div class="cat-card"><h4>Chemistry (58+)</h4><p><code>ph_from_h poh_from_oh pka_from_ka henderson_hasselbalch_b21 arrhenius_k eyring_k first_order_concentration first_order_half_life second_order_concentration zero_order_concentration michaelis_menten_b21 lineweaver_burk_b21 ideal_gas_n van_der_waals_p_b21 redlich_kwong_p compressibility_z partial_pressure_b21 mole_fraction_b21 kc_from_rates kp_from_kc reaction_quotient le_chatelier_dir gibbs_free_energy_b21 dg_from_k k_from_dg vant_hoff clausius_clapeyron antoine_p nernst_equation_b21 emf_from_half_cells faraday_mass_deposited beer_lambert_b21 transmittance ksp_from_concs ionic_strength_b21 debye_huckel cp_monatomic_ideal heat_capacity_q calorimeter_dt enthalpy_reaction avogadro_count moles_from_mass molarity_b21 molality_b21 dilution_v2 raoult_law bp_elevation fp_depression osmotic_pressure rydberg_lambda bohr_radius_n bohr_energy_ev photon_energy_freq photon_energy_lambda de_broglie</code></p></div>
          <div class="cat-card"><h4>Biology / Ecology / Epidemiology (51+)</h4><p><code>lotka_volterra_step_b22 logistic_growth_step logistic_growth_analytic gompertz_growth_step allee_growth_step exponential_growth_b22 doubling_time_b22 growth_rate_from_ratio sir_step_b22 seir_step seird_step sis_step r0_basic rt_effective herd_immunity_threshold generation_time shannon_diversity_b22 simpson_diversity_b22 inverse_simpson pielou_evenness margalef_richness menhinick_richness berger_parker jaccard_similarity_b22 sorensen_dice bray_curtis rao_quadratic_entropy hardy_weinberg_b22 selection_step fst_b22 nei_genetic_distance effective_pop_size petersen_estimator chapman_estimator lv_competition_step holling_type1 holling_type2 holling_type3 leslie_step net_reproductive_rate finite_rate_lambda kleibers_law q10 species_area macarthur_wilson_immigration island_equilibrium</code></p></div>
          <div class="cat-card"><h4>Signal Processing (37+)</h4><p><code>hamming_window hann_window blackman_window blackman_harris_window bartlett_window welch_window kaiser_window tukey_window gaussian_window hilbert_envelope goertzel_b25 biquad_step biquad_lowpass_coeffs biquad_highpass_coeffs biquad_bandpass_coeffs biquad_notch_coeffs biquad_allpass_coeffs biquad_peak_coeffs biquad_lowshelf_coeffs biquad_highshelf_coeffs butterworth_prewarp butterworth_order fir_moving_average fir_lowpass_design convolve_b25 xcorr_b25 periodogram_b25 spectrogram_simple zero_pad resample_nearest resample_linear quantize mu_law_encode mu_law_decode a_law_encode a_law_decode chirp_linear</code></p></div>
          <div class="cat-card"><h4>Finance / Pricing (39+)</h4><p><code>bs_call bs_put bs_vega_b20 bs_theta_call bs_rho_call implied_vol_b20 bachelier_call black76_call crr_american_call crr_american_put jr_european_call trinomial_call heston_price_simple sabr_implied_vol merton_jump_call asian_call_mc barrier_up_out_call digital_call lookback_call macaulay_duration bond_convexity forward_rate discount_continuous ytm_newton vasicek_bond cir_bond hull_white_drift cds_upfront black_karasinski_drift quanto_adjustment fx_forward garman_kohlhagen_call margrabe stulz_min_call sharpe_annualized treynor_ratio_b20 information_ratio_b20 jensen_alpha modified_sharpe</code></p></div>
          <div class="cat-card"><h4>Numerical / ODE / Optimization (45+)</h4><p><code>boole_rule gauss_legendre_5 gauss_kronrod_15 romberg_b19 adaptive_simpson_b19 tanh_sinh_quad_b19 midpoint_rule adams_bashforth_4 heun_method rk45_cash_karp milne_pc backward_euler crank_nicolson_ode brent_root ridders_root steffensen_root halley_root muller_root regula_falsi bisection_b19 secant_root anderson_step aberth_step inverse_quad_interp lm_step gradient_descent_step adam_step_b19 rmsprop_step_b19 nesterov_step adagrad_step cg_beta_pr cg_beta_fr bfgs_h_update_1d wolfe_strong_q dogleg_step nelder_mead_reflect nelder_mead_expand nelder_mead_contract sa_accept_prob sa_boltzmann_temp sa_cauchy_temp sa_geometric_temp acceptance_target</code></p></div>
          <div class="cat-card"><h4>Graph Algorithms (32+)</h4><p><code>tarjan_scc kosaraju_scc articulation_points_b24 bridges max_flow_ek min_cut_value hopcroft_karp closeness_centrality_b24 betweenness_centrality_b24 eigenvector_centrality_b24 katz_centrality hits_simple pagerank_damped cc_count cc_labels topological_sort_kahn has_cycle_directed has_cycle_undirected bfs_distances_b24 diameter_bfs eccentricity_b24 radius_bfs num_edges density_b24 k_coreness greedy_coloring chromatic_number_greedy sum_degrees avg_degree max_degree is_tree girth</code></p></div>
          <div class="cat-card"><h4>ML / Activations / Metrics (49+)</h4><p><code>gini_impurity entropy_bits information_gain gain_ratio nb_gaussian_likelihood nb_bernoulli_likelihood nb_multinomial_log_likelihood adaboost_alpha hinge_loss squared_hinge logistic_loss cross_entropy_b27 kl_div js_div wasserstein_1d_b27 sigmoid_b27 sigmoid_grad tanh_grad relu_b27 relu_grad leaky_relu_b27 elu_b27 selu_b27 swish gelu_b27 mish_b27 softsign hardswish prelu threshold_act confusion_counts mcc f_beta specificity npv_b27 balanced_accuracy cohen_kappa brier_score log_loss tversky mahalanobis_1d softmax_b27 log_softmax one_hot argmax_b27 topk_indices minmax_scale zscore_norm robust_scale</code></p></div>
          <div class="cat-card"><h4>Special Functions (50+)</h4><p><code>hyper2f1 hyper1f1 hyper0f1 pochhammer falling_factorial_b29 mathieu_ce0 mathieu_se1 parabolic_d0 parabolic_d1 whittaker_m struve_h0 struve_h1 lambert_w0 wright_omega sinhc cosh_minus1_over_x2 sine_integral_si cosine_integral_ci exp_integral_e1 fresnel_s_b29 fresnel_c_b29 dawson_function owen_t spherical_bessel_j0 spherical_bessel_j1 spherical_bessel_y0 spherical_bessel_y1 mod_sph_bessel_i0 mod_sph_bessel_i1 mod_sph_bessel_k0 coulomb_f0 polylog_li2 polylog_n hurwitz_zeta_b29 dirichlet_eta_b29 dirichlet_beta_b29 catalan_constant_b29 apery_constant_b29 ti2 clausen_cl2 bose_einstein_g fermi_dirac_int theta3 theta2 jacobi_sn_small_q jacobi_cn_small_q jacobi_dn_small_q riemann_xi bessel_jn_general bessel_in_general</code></p></div>
          <div class="cat-card"><h4>Cryptography (41+)</h4><p><code>fnv1a_32 fnv1a_64 djb2_hash_b26 sdbm_hash murmur3_32 xxhash32 siphash24 pbkdf2_hmac_step scrypt_round bcrypt_cost_iters argon2_block_mix hkdf_expand_step lfsr_galois_step mt19937_temper xorshift64 xorshift32 pcg32_step lcg_numrec_step splitmix64_step wyhash_mix crc32_b26 crc16_ccitt_b26 adler32_b26 xor_cipher_byte caesar_b26 rot13_b26 railfence_encrypt beaufort affine_encrypt substitution_encrypt letter_frequency english_chi2 index_of_coincidence kasiski_repeats deterministic_prime pollard_rho dh_shared rsa_encrypt_simple monobit_test runs_test_b26 approximate_entropy</code></p></div>
          <div class="cat-card"><h4>Astronomy / Music / Color / Units (67+)</h4><p><code>distance_modulus_b30 apparent_magnitude_b30 absolute_magnitude pc_to_ly ly_to_pc pc_to_au au_to_m solar_mass_to_kg solar_luminosity_to_w hubble_distance_mpc comoving_distance_approx critical_density et_freq_ratio midi_to_hz hz_to_midi cents_between just_intonation_ratio pythagorean_ratio beat_frequency bpm_to_spb note_name_to_midi rgb_to_hsl_b30 hsl_to_rgb_b30 rgb_to_yiq rgb_to_yuv601 srgb_to_xyz xyz_to_lab delta_e_76_b30 delta_e_94 c_to_f_b30 f_to_c_b30 inches_to_cm_b30 miles_to_km_b30 lb_to_kg kg_to_lb mph_to_kmh kmh_to_mph mps_to_kmh knots_to_kmh psi_to_pa_b30 pa_to_psi_b30 atm_to_pa mmhg_to_pa ev_to_joules joules_to_ev cal_to_joules btu_to_joules kwh_to_joules bpm_to_midi_tick_us iso226_phon_adjustment db_to_amp amp_to_db roman_encode roman_decode number_to_english</code></p></div>
          <div class="cat-card"><h4>Color / ANSI</h4><p><code>rgb_to_hex hex_to_rgb ansi_red ansi_green ansi_blue ansi_yellow ansi_cyan ansi_magenta ansi_bold ansi_dim strip_ansi darken lighten mix_colors is_dark is_light</code></p></div>
          <div class="cat-card"><h4>Random</h4><p><code>rand srand coin_flip dice_roll random_int random_float random_bool random_choice random_between random_string random_alpha random_digit random_password random_hex_str</code></p></div>
          <div class="cat-card"><h4>Data Structures</h4><p><code>set heap deque stack_new queue_new lru_new counter counter_most_common defaultdict ordered_set bitset_new bitset_set bitset_test bitset_clear</code></p></div>
          <div class="cat-card"><h4>Async / Timing</h4><p><code>async spawn await timer bench trace eval_timeout retry rate_limit every gen</code></p></div>
          <div class="cat-card"><h4>Reflection</h4><p>Nine O(1) hashes — <code>%b</code> builtins, <code>%all</code> every spelling, <code>%pc</code> perl_compats, <code>%e</code> extensions, <code>%a</code> aliases, <code>%d</code> descriptions, <code>%c</code> categories, <code>%p</code> primaries, <code>%parameters</code> live bindings. Plus per-package stashes (<code>%main::</code>, <code>%Foo::</code>).</p></div>
        </div>
      </section>

      <section class="tutorial-section" style="border: 2px solid #f55; background: linear-gradient(135deg, rgba(255,85,85,0.1) 0%, transparent 50%);">
        <h2 style="color:#f55;">🔥 KILLER FEATURE: Infrastructure Load Testing</h2>
        <p><strong>stryke is the first language designed for server farms.</strong> Pin millions of servers to 100% TDP from a single REPL. The hottest language ever created. Literally.</p>

        <h3>Stress Testing Builtins</h3>
        <table class="reflection-table">
          <thead>
            <tr><th>Builtin</th><th>What It Does</th><th>Performance</th></tr>
          </thead>
          <tbody>
            <tr><td><code>stress_cpu(secs)</code></td><td>SHA256 hashing on ALL cores</td><td>1117% CPU (18-core M3 Max)</td></tr>
            <tr><td><code>stress_mem(bytes)</code></td><td>Allocate + touch memory across all cores</td><td>1GB in &lt;100ms</td></tr>
            <tr><td><code>stress_io(dir, iter)</code></td><td>Parallel file I/O stress</td><td>Saturates NVMe</td></tr>
            <tr><td><code>stress_test(secs)</code></td><td>Combined CPU + memory + I/O</td><td>Full system stress</td></tr>
            <tr><td><code>heat(secs)</code></td><td>Maximum TDP, Ctrl-C to stop</td><td>100% all cores indefinitely</td></tr>
          </tbody>
        </table>

        <h3>One-Liners That Melt Silicon</h3>
<pre><span class="comment"># Pin all cores for 10 seconds</span>
s 'heat(10)'

<span class="comment"># Stress test with metrics</span>
s 'dd stress_test(60)'

<span class="comment"># Allocate and touch 8GB RAM</span>
s 'stress_mem(8e9)'

<span class="comment"># Maximum parallel computation — billion iterations</span>
s '~>1:1e9 pmaps{sha256 _} collect'</pre>

        <h3>Distributed Agent/Controller Architecture</h3>
        <p>Deploy <code>stryke agent</code> across your fleet. Control from <code>stryke controller</code> REPL.</p>
<pre><span class="comment"># On every server in your fleet</span>
$ stryke agent --controller master.example.com:9999

<span class="comment"># On your control node</span>
$ stryke controller
[controller] Listening on 0.0.0.0:9999
[connected] node1 (18 cores, 64GB)
[connected] node2 (18 cores, 64GB)
[connected] node3 (18 cores, 64GB)

> status
  node1: idle (18 cores, 64GB)
  node2: idle (18 cores, 64GB)
  node3: idle (18 cores, 64GB)

> fire 60
[fire] 3 agents, duration=60s
🔥 All agents pinned to 100% TDP

> terminate
[terminate] All agents stopped</pre>

        <h3>What stryke Validates</h3>
        <ul>
          <li><strong>Cooling capacity</strong> — Can your data center handle 100% TDP across all blades?</li>
          <li><strong>Power infrastructure</strong> — Wire gauge, UPS failover, generator switchover</li>
          <li><strong>Hardware reliability</strong> — Thermal throttling, component failures under stress</li>
          <li><strong>Operations response</strong> — Alert latency, escalation procedures, incident response</li>
          <li><strong>BCP/DR exercises</strong> — Validate failover, switchover, disaster recovery</li>
        </ul>

        <h3>Enterprise Deployment</h3>
<pre><span class="comment"># Zero-install: single static binary</span>
scp stryke server:/usr/local/bin/
ssh server 'stryke agent'

<span class="comment"># Kubernetes DaemonSet: deploy to every node</span>
kubectl apply -f stryke-daemonset.yaml

<span class="comment"># AOT compile your test suite into one binary</span>
stryke build load_test.stk -o load_test
scp load_test node{1:100}:/tmp/</pre>

        <h3>Compliance Use Cases</h3>
        <table class="reflection-table" style="font-size:11px;">
          <thead><tr><th>Framework</th><th>stryke Validates</th></tr></thead>
          <tbody>
            <tr><td>SOC 2</td><td>CC7.2 System operations, CC7.4 Change management</td></tr>
            <tr><td>PCI DSS</td><td>11.3 Penetration testing, 12.10 Incident response</td></tr>
            <tr><td>ISO 27001</td><td>A.17.1 BCP, A.17.2 Redundancies</td></tr>
            <tr><td>FedRAMP</td><td>CP - Contingency Planning</td></tr>
          </tbody>
        </table>

        <p>See <a href="STRESS_TESTING.md">docs/STRESS_TESTING.md</a> and <a href="rfcs/">RFCs</a> for full documentation.</p>
      </section>

      <section class="tutorial-section" style="border: 2px solid #05d9e8; background: linear-gradient(135deg, rgba(5,217,232,0.08) 0%, transparent 50%);">
        <h2 style="color:#05d9e8;">AI Primitives — <code>ai</code> is a builtin like <code>print</code></h2>
        <p>Two letters, ubiquitous, unlimited power. Agent loop, MCP client+server, RAG memory, vector search — all native to the language.</p>

<pre><span class="comment"># Single-shot</span>
my $r = ai "summarize this", $document

<span class="comment"># Auto-routes to agent loop when tool fns are in scope</span>
tool fn weather($city: string) "Get weather" {
    fetch "https://api.weather.com/" . uri_encode($city)
}
ai "what's the weather in Tokyo?"

<span class="comment"># Vision, structured output, PDFs — all via the same `ai` call</span>
my $caption = ai "describe", image =&gt; "/photo.jpg"
my $user    = ai "extract", schema =&gt; +{ name =&gt; "string", age =&gt; "int" }
my $summary = ai "summarize", pdf =&gt; "/contract.pdf"

<span class="comment"># Streaming as a real iterator</span>
for my $chunk in stream_prompt("write a haiku") { print $chunk }

<span class="comment"># Collection ops — single batched LLM call across the list</span>
my @kept = @{ ai_filter(\@docs, "is about cooking") }
my @summaries = @{ ai_map(\@articles, "summarize in one sentence") }

<span class="comment"># RAG memory backed by sqlite</span>
ai_memory_save("doc-1", "Stryke is the fastest Perl-5 interpreter")
my $hits = ai_memory_recall("which language is fast", top_k =&gt; 3)

<span class="comment"># MCP server in one block</span>
mcp_server "filesystem" {
    tool read_file($path: string) "Read file" { slurp $path }
    tool list_dir($path: string) "List dir"   { join("\n", readdir $path) }
}</pre>

        <h3>Surface</h3>
        <table class="reflection-table">
          <thead><tr><th>Builtin</th><th>What it does</th></tr></thead>
          <tbody>
            <tr><td><code>ai $prompt, opts...</code></td><td>Single-shot or auto-routed agent loop / vision / PDF / structured output</td></tr>
            <tr><td><code>tool fn name(...) "doc" { }</code></td><td>Declare an agent-callable tool — auto-schemas signature, auto-attaches to <code>ai()</code></td></tr>
            <tr><td><code>stream_prompt $p, on_chunk =&gt; sub { }</code></td><td>SSE streaming with callback or iterator-context for-loop</td></tr>
            <tr><td><code>ai_filter / ai_map / ai_classify / ai_match / ai_sort / ai_dedupe</code></td><td>Collection ops — one batched call across the list</td></tr>
            <tr><td><code>embed</code> / <code>vec_cosine</code> / <code>vec_search</code></td><td>Embeddings + cosine retrieval</td></tr>
            <tr><td><code>ai_memory_save / recall / forget</code></td><td>Sqlite-backed RAG memory</td></tr>
            <tr><td><code>mcp_connect("stdio:...")</code> / <code>mcp_connect("https://...")</code></td><td>MCP client (stdio + streamable HTTP)</td></tr>
            <tr><td><code>mcp_server "name" { tool ... }</code></td><td>Programmatic MCP server in-process</td></tr>
            <tr><td><code>ai_session_*</code></td><td>Multi-turn chat with auto-history</td></tr>
            <tr><td><code>ai_budget($usd, sub { })</code></td><td>Scoped USD cap; errors if block exceeds</td></tr>
            <tr><td><code>ai_batch(\@prompts)</code></td><td>Anthropic batch API at 50% cost</td></tr>
            <tr><td><code>ai_pmap(\@items, "instruction", cluster =&gt; $c)</code></td><td>Distributed AI across cluster nodes</td></tr>
            <tr><td><code>ai_transcribe "audio.mp3"</code> / <code>ai_speak $text</code></td><td>Whisper transcription / OpenAI TTS</td></tr>
            <tr><td><code>ai_image $prompt, output =&gt; "out.png"</code></td><td>Image generation (DALL-E 3, gpt-image-1)</td></tr>
            <tr><td><code>ai_image_edit $prompt, image =&gt; $src, mask =&gt; $m</code></td><td>Image-to-image edit with optional mask</td></tr>
            <tr><td><code>ai_image_variation image =&gt; $src, n =&gt; 4</code></td><td>Variations of an existing image (DALL-E 2)</td></tr>
            <tr><td><code>ai_dashboard()</code></td><td>ANSI summary: cost, tokens, cache hit-ratio</td></tr>
            <tr><td><code>ai_pricing "claude-opus-4-7"</code></td><td>Pre-flight pricing hashref (input/output per 1k or 1m)</td></tr>
            <tr><td><code>ai_describe "img.png", style =&gt; "alt"</code></td><td>Vision wrapper with concise/detailed/alt presets</td></tr>
            <tr><td><code>ai_grounded $p, documents =&gt; [@paths]</code></td><td>Multi-doc grounding with auto-citations</td></tr>
            <tr><td><code>ai_session_export</code> / <code>ai_session_import</code></td><td>Persist a chat session across runs as JSON</td></tr>
            <tr><td><code>ai_models "openai"</code></td><td>Live model catalog from any provider</td></tr>
            <tr><td><code>ai_pdf $p, pdf =&gt; $f, citations =&gt; 1</code> + <code>ai_citations()</code></td><td>Anthropic grounded responses with char/page offsets</td></tr>
            <tr><td><code>ai_file_upload</code> / <code>list</code> / <code>get</code> / <code>delete</code></td><td>OpenAI Files API</td></tr>
            <tr><td><code>ai_file_anthropic_upload</code> / <code>list</code> / <code>delete</code></td><td>Anthropic Files API (beta)</td></tr>
            <tr><td><code>ai_moderate $text</code></td><td>OpenAI safety classifier (free)</td></tr>
            <tr><td><code>ai_chunk $text, by =&gt; "sentences"</code></td><td>RAG text chunker (pure local)</td></tr>
            <tr><td><code>ai_warm(model =&gt; ...)</code></td><td>Auth + reachability ping at script start</td></tr>
            <tr><td><code>ai_compare $a, $b, criteria =&gt; "..."</code></td><td>Structured semantic comparison</td></tr>
            <tr><td><code>stryke ai "prompt"</code></td><td>UNIX-filter CLI: <code>--model</code>, <code>--system</code>, <code>--stream</code>, <code>--json</code></td></tr>
          </tbody>
        </table>

        <p>Providers: Anthropic (full surface incl. extended thinking, prompt caching, vision, PDF, batch), OpenAI (chat + tool-calls + streaming, Whisper, TTS), Voyage (embeddings, default), Ollama, OpenAI-compatible (<code>openai_compat</code> — LM Studio / vLLM / llama-server, configurable <code>STRYKE_AI_BASE_URL</code>), Google Gemini. Mock with <code>ai_mock_install</code> + <code>STRYKE_AI_MODE=mock-only</code> for deterministic CI.</p>

        <p>Full reference: <a href="AI_PRIMITIVES.md">docs/AI_PRIMITIVES.md</a>.</p>
      </section>

      <section class="tutorial-section" style="border: 2px solid #ff2a6d; background: linear-gradient(135deg, rgba(255,42,109,0.08) 0%, transparent 50%);">
        <h2 style="color:#ff2a6d;">Web Framework — <code>s_web</code></h2>
        <p>Rails-shaped scaffold. Generator emits <code>.stk</code> source files; framework runtime is <code>web_*</code> builtins. The whole framework + your entire app + SQLite ships as a single <code>cargo build --release</code> binary via <code>s_web build</code>.</p>

<pre><span class="comment"># One command — full-stack app, ~70 resources, dark cyberpunk theme,</span>
<span class="comment"># auth + admin + Dockerfile + GitHub Actions + PWA + migrations.</span>
$ s_web new mega --app everything --theme cyberpunk \
    --auth --admin --docker --ci --pwa --migrate
$ cd mega &amp;&amp; bin/server
<span class="comment"># http://localhost:3000 — signup, login, /admin browses every model,</span>
<span class="comment"># /health, /docs (Swagger UI), /openapi.json, ~490 CRUD routes.</span></pre>

        <h3>Highlights</h3>
        <table class="reflection-table">
          <thead><tr><th>Concern</th><th>Builtins</th></tr></thead>
          <tbody>
            <tr><td>Routing</td><td><code>web_route</code>, <code>web_resources</code>, <code>web_root</code>, <code>/openapi.json</code> + <code>/docs</code> auto-served</td></tr>
            <tr><td>ORM</td><td><code>Article::all/find/create/update/destroy</code> static methods generated per model; <code>web_model_paginate/search/soft_destroy/with</code></td></tr>
            <tr><td>Migrations</td><td><code>web_create_table/drop_table/add_column</code> + <code>web_migrate/rollback</code> + <code>schema_migrations</code></td></tr>
            <tr><td>Validations</td><td><code>web_validate(+{title =&gt; "presence,length:1..100"})</code></td></tr>
            <tr><td>Auth</td><td><code>web_password_hash/verify</code>, sessions, signed tokens, <code>web_can</code>, <code>web_jwt_encode/decode</code>, <code>web_otp_*</code> 2FA</td></tr>
            <tr><td>Views</td><td>ERB engine, layouts, partials, helpers (<code>web_link_to/form_with/text_field/button_to</code>, etc.)</td></tr>
            <tr><td>Themes</td><td>9 baked-in: <code>simple</code>, <code>dark</code>, <code>pico</code>, <code>bootstrap</code>, <code>tailwind</code>, <code>cyberpunk</code>, <code>synthwave</code>, <code>terminal</code>, <code>matrix</code></td></tr>
            <tr><td>Presets</td><td><code>blog</code>, <code>ecommerce</code>, <code>saas</code>, <code>social</code>, <code>cms</code>, <code>forum</code>, <code>crm</code>, <code>helpdesk</code>, <code>amazon</code>, <code>facebook</code>, <code>learning</code>, <code>everything</code></td></tr>
            <tr><td>Generators</td><td><code>s_web g {scaffold, model, migration, controller, app, auth, admin, api, mailer, job, channel, docker, ci, pwa}</code></td></tr>
            <tr><td>Fat binary</td><td><code>s_web build --out dist &amp;&amp; cd dist &amp;&amp; cargo build --release</code> — one self-contained executable, no runtime deps</td></tr>
          </tbody>
        </table>

        <p>Full reference: <a href="WEB_FRAMEWORK.md">docs/WEB_FRAMEWORK.md</a> and <a href="https://github.com/MenkeTechnologies/strykelang/tree/main/stryke_web">stryke_web/README.md</a>.</p>
      </section>

      <section class="tutorial-section" style="border: 2px solid #39ff14; background: linear-gradient(135deg, rgba(57,255,20,0.08) 0%, transparent 50%);">
        <h2 style="color:#39ff14;">Expect — Interactive Automation</h2>
        <p>PTY-driven scripting; the modern Tcl/Expect successor with native cluster fanout.</p>

<pre>my $h = pty_spawn("ssh user@host")
pty_expect($h, qr/password:/, 30)
pty_send($h, "$pw\n")
pty_expect($h, qr/\$ /, 30)
pty_send($h, "uptime\n")
my $output = pty_expect($h, qr/\$ /, 30)
pty_close($h)

<span class="comment"># Table form (Tcl `expect { ... }` block)</span>
my $tag = pty_expect_table($h, [
    +{ re =&gt; qr/password:/, do =&gt; fn { pty_send($h, "$pw\n"); "ok" } },
    +{ re =&gt; qr/yes\/no/,   do =&gt; fn { pty_send($h, "yes\n"); "confirmed" } },
    +{ re =&gt; qr/denied/,    do =&gt; fn { die "auth failed" } },
], 30)

<span class="comment"># Method-form sugar</span>
my $h = PtyHandle::spawn("ssh host")
$h-&gt;expect(qr/password:/, 30)
$h-&gt;send("$pw\n")
$h-&gt;interact()   <span class="comment"># raw-mode handoff, Ctrl-] to detach</span>

<span class="comment"># Parallel SSH automation across N hosts</span>
my $cluster = cluster(["host1:8", "host2:8", "host3:8"])
pmap_on $cluster @hosts -&gt; $host {
    my $h = pty_spawn("ssh $host")
    pty_expect($h, qr/\$ /, 30)
    pty_send($h, "apt update && apt upgrade -y\n")
    pty_expect($h, qr/\$ /, 1800)
    pty_close($h)
}</pre>

        <p>Full design: <a href="expect-feature-idea.md">docs/expect-feature-idea.md</a>.</p>
      </section>

      <section class="tutorial-section" style="border: 2px solid #b967ff; background: linear-gradient(135deg, rgba(185,103,255,0.08) 0%, transparent 50%);">
        <h2 style="color:#b967ff;">Package Manager</h2>
        <p>Cargo-shaped manifest + lockfile, hash-pinned reproducible builds, parallel resolver. Single binary surface — no separate <code>cargo</code>-style entry point.</p>

<pre>$ stryke new myapp                  <span class="comment"># scaffold project at ./myapp/</span>
$ cd myapp
$ stryke add http@^1.0 json         <span class="comment"># write deps to stryke.toml</span>
$ stryke install                    <span class="comment"># resolve + write stryke.lock</span>
$ stryke update                     <span class="comment"># re-resolve and rewrite stryke.lock</span>
$ stryke outdated                   <span class="comment"># report deps drifted from their lock pin</span>
$ stryke audit                      <span class="comment"># lockfile vs vulnerability advisory feed</span>
$ stryke tree                       <span class="comment"># resolved dep graph</span>
$ stryke info http                  <span class="comment"># lockfile entry for a dep</span>
$ stryke vendor                     <span class="comment"># snapshot store deps to ./vendor/</span>
$ stryke clean                      <span class="comment"># wipe target/</span>
$ stryke run greet                  <span class="comment"># npm-style task from [scripts]</span>
$ stryke install -g ../mytool       <span class="comment"># link [bin] launchers into ~/.stryke/bin/</span>
$ stryke build --release            <span class="comment"># AOT-compile to single static binary</span></pre>

        <h3>Project layout</h3>
<pre>myapp/
├── stryke.toml         <span class="comment"># manifest (name, deps, [scripts], [bin], [workspace])</span>
├── stryke.lock         <span class="comment"># exact versions + integrity hashes</span>
├── main.stk            <span class="comment"># entry point</span>
├── lib/                <span class="comment"># module sources (require/use)</span>
├── bin/                <span class="comment"># additional executables</span>
├── t/                  <span class="comment"># tests (`stryke test t/`)</span>
├── benches/            <span class="comment"># benchmarks (`stryke bench`)</span>
└── target/             <span class="comment"># build outputs (gitignored)</span>
    └── release/myapp   <span class="comment"># ← native machine code, scp-ready</span></pre>

        <h3>Workspaces</h3>
<pre><span class="comment"># stryke.toml at workspace root</span>
[workspace]
members = ["crates/*"]

[workspace.deps]
shared = { path = "../shared" }     <span class="comment"># one version pinned for the whole monorepo</span>

<span class="comment"># In any member's stryke.toml</span>
[deps]
shared = { workspace = true }       <span class="comment"># inherit version + features</span></pre>

        <p>Deps live globally in <code>~/.stryke/store/name@version/</code>. No <code>node_modules</code>-shaped per-project tree. Every dep hash-pinned in the lockfile (Nix-style reproducibility, Cargo-style ergonomics). Status: path deps + workspaces + full CLI surface (<code>new/init/add/remove/install/update/outdated/audit/tree/info/vendor/clean/run/install&nbsp;-g</code>) are wired and tested today; registry/git deps + PubGrub semver land when the registry endpoint is deployed (<code>search/publish/yank</code> stubs already return clear "registry not deployed yet" diagnostics). Full design: <a href="PACKAGE_REGISTRY.md">docs/PACKAGE_REGISTRY.md</a>.</p>
      </section>

      <section class="tutorial-section">
        <h2>Parallel primitives (highlights)</h2>
        <p>Every <code>p*</code> primitive uses rayon work-stealing, saturates all cores by default, and takes three surface forms:</p>
<pre># block form   ($_ = element, bare _ is shorthand for $_)
pmap { _ * 2 } 1:1_000_000

# expression form
pmap _ * 2, 1:1_000_000

# bare-fn form   (fn double { _ * 2 })
pmap double, 1:1_000_000</pre>

        <h3>fan / pchannel / ppool</h3>
<pre># fan — run a block N times in parallel (_/_0 = index 0:N-1)
fan 16 { heavy_work(_) }

# pchannel — bounded MPMC queue
my ($tx, $rx) = pchannel(100)
async { $tx-&gt;send(_) for 1:1000; undef $tx }
while (defined(my $v = $rx-&gt;recv)) { p $v }

# ppool — persistent worker pool
my $pool = ppool 4, fn {
  while (defined(my $j = $rx-&gt;recv)) { process($j) }
}
$tx-&gt;send(_) for @jobs;  undef $tx
$pool-&gt;join</pre>

        <h3>Pipelines</h3>
<pre># sequential (each stage drains list before next)
pipeline(
  fn { map { _ * 2 } @_ },
  fn { grep { _ &gt; 10 } @_ },
  fn { sum(@_) },
)-&gt;run(1:1000)

# streaming — bounded crossbeam channels, concurrent stages
par_pipeline_stream([\&amp;stage1, \&amp;stage2, \&amp;stage3], \@input)</pre>
      </section>

      <section class="tutorial-section">
        <h2>AOP — before / after / around advice</h2>
        <p>Aspect-oriented advice on user subs. Glob pointcuts, three advice kinds, AspectJ-style around with <code>proceed()</code>. Same surface as zshrs's <code>intercept</code>, adapted as keyword statements instead of a CLI builtin.</p>
<pre># before — sees $INTERCEPT_NAME, @INTERCEPT_ARGS
before "fetch" { warn "calling fetch with @INTERCEPT_ARGS" }

# after  — sees $INTERCEPT_RESULT, $INTERCEPT_MS, $INTERCEPT_US
after "fetch" { warn "fetch returned $INTERCEPT_RESULT in ${INTERCEPT_MS}ms" }

# around — block's value is the call's return; proceed() runs original
around "expensive" {
    my $cached = cache_get($INTERCEPT_ARGS[0])
    return $cached if defined $cached
    my $r = proceed()
    cache_put($INTERCEPT_ARGS[0], $r)
    $r
}

# Glob pointcuts: *, ?
before "log_*" { ... }
before "*"     { trace($INTERCEPT_NAME) }

# Management
intercept_list();   # [[id, kind, pattern], ...]
intercept_remove($id);
intercept_clear();</pre>
        <p>The leading keyword only commits to advice parsing when followed by a string literal, so <code>before(...)</code> as a normal sub call still works. The first matching <code>around</code> wraps; <code>before</code>/<code>after</code> on the same name all fire in registration order. Re-entrancy guard prevents infinite loops when an advice body calls the advised sub. Coverage: user-defined subs only.</p>
      </section>

      <section class="tutorial-section">
        <h2>Reserved Words</h2>
        <p>These cannot be used as function names (they are lexer-level operators or language keywords):</p>
        <div class="oneliner" style="font-size:11px;">y tr s m q qq qw qx qr
if unless while until for foreach given when else elsif
do eval return last next redo goto
my our local state sub fn class struct enum trait
use no require package BEGIN END CHECK INIT UNITCHECK
and or not x eq ne lt gt le ge cmp</div>
        <p>Attempting <code>fn y { }</code> or <code>fn goto { }</code> produces: <code>`y` is a reserved word and cannot be used as a function name</code></p>
        <p style="margin-top: 1em;"><strong>Topic-slot names</strong> are also rejected: <code>fn _</code>, <code>fn _&lt;</code>, <code>fn _0</code>, <code>fn _N</code>, <code>fn _N&lt;+</code>, plus the sigil-prefixed forms <code>fn $_</code>, <code>fn @_</code>, and the package-qualified forms <code>fn Foo::_</code>, <code>fn Pkg::_0</code>. A user-defined sub by any of these names would shadow the topic in expression position and silently break every <code>_</code>-aware builtin. Names like <code>fn _foo</code>, <code>fn _NAME</code>, <code>fn my_helper</code> still work — only EXACT topic-slot spellings reject.</p>
      </section>

      <section class="tutorial-section">
        <h2>Range literals</h2>
        <p>The <code>:</code> range operator (and the <code>!!!</code> separator for IPv6) recognize several built-in literal types as a single token. The runtime expansion dispatches on the surface form so each type gets the right step semantics.</p>
        <div class="oneliner" style="font-size:11px;">1~5~1                         <span class="comment"># numeric (~ works universally)</span>
192.168.1.1:192.168.1.5:1     <span class="comment"># IPv4, octet step</span>
2022-01-01:2022-01-05:1       <span class="comment"># ISO date, day step</span>
2022-01:2022-04:1             <span class="comment"># year-month, month step</span>
0x00:0xFF:1                   <span class="comment"># hex, preserves prefix/width/case</span>
2001::1~2001::5~1             <span class="comment"># IPv6 (must use ~ — : collides)</span>
fe80::ff~fe80::fc~-1          <span class="comment"># IPv6 reverse step</span>
::1~::5~1                     <span class="comment"># IPv6 zero-comp prefix</span></div>
        <p><strong>Hex case preservation</strong> — uppercase iff EITHER endpoint has any uppercase letter. <code>0x00:0xFF:1</code> emits <code>0x00, 0x01, …, 0xFF</code> (uppercase wins from TO). Outside range context, <code>0xFF</code> is still the integer 255 — only range-context lookahead triggers the string-typed literal.</p>
        <p><strong>Why <code>~</code> for IPv6</strong> — IPv6 uses <code>:</code> internally; reusing it as the range separator would be ambiguous. The universal <code>~</code> separator dodges the collision and works for all range types. <code>!</code> can't be used because it's the paired char-index delimiter (<code>$x!N!</code>); inside paired <code>~…~</code> char-index/slice subscripts (<code>$x~5~</code>, <code>$_~1:3~</code>) the range op is suppressed so closing delimiters don't get eaten.</p>
      </section>

      <section class="tutorial-section">
        <h2>Topic chain — <code>_&lt;</code> and the positional matrix</h2>
        <p>Inside a closure (map/grep/sort block, sub body, fan/fan_cap), <code>_&lt;</code> reads the topic of the enclosing scope — the value <code>_</code> held in the frame that called this closure. The chain extends up to <strong>five</strong> frames: <code>_&lt;&lt;</code>, <code>_&lt;&lt;&lt;</code>, <code>_&lt;&lt;&lt;&lt;</code>, <code>_&lt;&lt;&lt;&lt;&lt;</code>. Numeric positional slots get the same matrix: <code>_0&lt;</code>, <code>_1&lt;&lt;</code>, …, <code>_N&lt;&lt;&lt;&lt;&lt;</code>. Bareword and sigil forms (<code>$_&lt;</code>) are equivalent.</p>
        <p><strong>Indexed-ascent <code>_&lt;N</code></strong> — past depth 2, counting chevrons gets error-prone. The lexer accepts <code>_&lt;N</code> (where N is a positive integer) as syntactic sugar for N chevrons: <code>_&lt;3</code> ≡ <code>_&lt;&lt;&lt;</code>, <code>$_2&lt;5</code> ≡ <code>$_2&lt;&lt;&lt;&lt;&lt;</code>. The disambiguator preserves slice syntax: <code>_&lt;3&gt;</code> and <code>_&lt;3:5&gt;</code> remain string slices; <code>_&lt;3</code> (without trailing <code>&gt;</code> or <code>:</code>) is the indexed-ascent form.</p>
<pre><span class="comment"># Nested map — `_&lt;` reaches the outer iter's `_`:</span>
map { my @inner = (1, 2); map { _&lt; + _ } @inner } (10, 20)
<span class="comment"># 11, 12, 21, 22</span>

<span class="comment"># Inside a 3-arg fn, _0&lt;5 (≡ _0&lt;&lt;&lt;&lt;&lt;) reaches arg 0 five frames up:</span>
fn deep($_0, $_1, $_2) {
  ~&gt; 1:1 map { ~&gt; 1:1 map { ~&gt; 1:1 map { ~&gt; 1:1 map { ~&gt; 1:1 map {
    p _0&lt;5, _1&lt;5, _2&lt;5      <span class="comment"># preferred: indexed form</span>
    p _0&lt;&lt;&lt;&lt;&lt;, _1&lt;&lt;&lt;&lt;&lt;     <span class="comment"># equivalent: chevron form</span>
  } } } } }
}</pre>
        <p><strong>Iter re-entry</strong> — the chain shifts on the FIRST <code>set_topic</code> call in a given frame; subsequent iterations of the same loop only refresh <code>_</code>, so <code>_&lt;</code> keeps pointing at the enclosing scope's topic instead of rolling to the previous iter's value. Bound-but-undef chain entries fall back to <code>_</code> so <code>$h-&gt;{_&lt;}</code> at the outermost iter reads the iteration key.</p>
      </section>

      <section class="tutorial-section">
        <h2>Mutation semantics — topic variants align with <code>|param|</code> block params</h2>
        <p>A user writing <code>$_ = ...</code> or <code>$_&lt; = ...</code> inside a block mutates <strong>only the current frame</strong>. Topic variants follow the exact same rule as <code>|$x|</code> block params and inner <code>my $x</code>: writes do not leak outward, and the chain shift on the next frame entry is purely a function of the <em>outer</em> topic value, never the inner mutation.</p>
        <table class="comparison-table" style="width:100%; border-collapse:collapse; font-size:0.85em;">
          <thead>
            <tr>
              <th style="text-align:left; padding:4px 8px; border-bottom:1px solid #444;">form</th>
              <th style="text-align:left; padding:4px 8px; border-bottom:1px solid #444;">mutation propagates to outer scope?</th>
              <th style="text-align:left; padding:4px 8px; border-bottom:1px solid #444;">mechanism</th>
            </tr>
          </thead>
          <tbody>
            <tr><td><code>|$x|</code> block param</td><td style="color:#0f0;">NO — frame-local</td><td>param binding lives in callee frame</td></tr>
            <tr><td><code>my $x</code> inside a block</td><td style="color:#0f0;">NO — frame-local</td><td>new lexical binding in current frame</td></tr>
            <tr><td><code>my $x</code> outer + inner closure writes <code>$x</code></td><td style="color:#f55;">rejected at compile time</td><td>DESIGN-001 (closures capture by value)</td></tr>
            <tr><td><code>mysync $x</code> outer + inner closure writes <code>$x</code></td><td style="color:#ff0;">YES — explicit <code>Arc&lt;Mutex&gt;</code> opt-in</td><td>shared cell, atomic compound ops</td></tr>
            <tr><td><code>our $x</code></td><td style="color:#ff0;">YES — package-global by design</td><td>symbol table, not lexical</td></tr>
            <tr><td><code>$_</code>, <code>$_&lt;</code>, <code>$_&lt;&lt;</code>, <code>$_&lt;&lt;&lt;</code>, <code>$_&lt;&lt;&lt;&lt;</code>, <code>$_&lt;&lt;&lt;&lt;&lt;</code></td><td style="color:#0f0;">NO — frame-local</td><td><code>Frame::set_scalar_raw</code> bypasses CaptureCell write-through</td></tr>
            <tr><td><code>$_0</code>, <code>$_1</code>, … <code>$_N</code> and <code>$_N&lt;+</code> chain forms</td><td style="color:#0f0;">NO — frame-local</td><td>same path as topic-chain writes</td></tr>
          </tbody>
        </table>
        <p style="margin-top:1em;">Implementation: <code>strykelang/scope.rs::Scope::set_scalar</code> recognizes topic-variant names via <code>is_topic_variant_name</code> (regex <code>^_[0-9]*&lt;*$</code>) and routes the write through <code>Frame::set_scalar_raw</code>, which bypasses the CaptureCell write-through that named outer-scope <code>my</code> variables use. Result: <code>$_&lt;</code> always reads the lexical outer-scope topic of the current closure, never an in-flight mutation from a sibling iteration.</p>
      </section>

      <section class="tutorial-section">
        <h2>Coderef-in-block-position</h2>
        <p>Wherever a <code>{ BLOCK }</code> is accepted in a per-element list operator (<code>grep</code>, <code>map</code>, <code>sort</code>, <code>first</code>, <code>any</code>, <code>all</code>, <code>none</code>, <code>take_while</code>, <code>drop_while</code>, <code>reject</code>, <code>partition</code>, <code>min_by</code>, <code>max_by</code>, plus their pipe-forward variants), a coderef-shaped expression also works directly. Runtime check: if the EXPR evaluates to a code ref, it is called with the current element(s) as positional args; otherwise the value's truthiness drives filtering (or its result becomes the mapped value, comparator integer, etc.). Eliminates the <code>{ $f($_) }</code> / <code>{ $f-&gt;($_) }</code> boilerplate.</p>
<pre><span class="comment"># grep / map — single coderef, no block:</span>
my $is_big = fn ($x) { $x &gt; 3 }
my @r = grep $is_big, @l                  <span class="comment"># was: grep { $is_big-&gt;(_) } @l</span>
my @r = @l |&gt; grep $is_big                <span class="comment"># pipe-forward variant</span>
my @doubled = map fn { _ * 2 }, @l        <span class="comment"># inline coderef</span>

<span class="comment"># Sort comparators receive ($a, $b) positionally — no $a/$b global magic:</span>
my $cmp = fn ($a, $b) { $b &lt;=&gt; $a }       <span class="comment"># or fn { _0 &lt;=&gt; _1 } using positional aliases</span>
my @s = sort $cmp @l

<span class="comment"># Tier-2 builtins — no parens, no block:</span>
my $r = first $is_big, @l
my $a = any $is_big, @l
my @t = take_while $is_big, @l
my @r = reject $is_big, @l                <span class="comment"># inverse of grep</span></pre>
        <p><strong>Threading <code>~&gt;</code> excluded</strong> — whitespace-delimited stages can't disambiguate <code>~&gt; @l grep $f</code> from "two stages", so threading still requires <code>{ $f(_) }</code>. Use <code>|&gt;</code> for the bare-coderef form, or stay with <code>{ }</code> blocks under <code>~&gt;</code>.</p>
        <p><strong>Under <code>--compat</code></strong>: dispatch is skipped, restoring Perl's "evaluate EXPR per element, filter by truthiness" semantics. A coderef value is always truthy, so <code>grep $f, @l</code> keeps every element under <code>--compat</code>.</p>
      </section>

      <section class="tutorial-section">
        <h2>Implicit zero-arg coderef from bare positional</h2>
        <p>At <strong>module top level</strong>, a <code>my $f = …</code> declaration whose RHS <em>begins</em> with a bare positional alias (<code>_</code>, <code>_0</code>, <code>_1</code>, …; no <code>$</code> sigil) is auto-wrapped as a zero-arg coderef. Inside any block (<code>fn</code>, <code>map</code>, <code>grep</code>, <code>for</code>, …) bare <code>_</code> is the bound topic, so this sugar only fires where <code>_</code> would otherwise be unbound.</p>
<pre><span class="comment"># at top level — these two forms are equivalent:</span>
my $f = _ * 2
my $f = fn { _ * 2 }
$f-&gt;(5)                <span class="comment"># 10</span>

<span class="comment"># multi-arg coderefs via _1, _2, …:</span>
my $g = _ + _1
$g-&gt;(3, 4)             <span class="comment"># 7</span>

<span class="comment"># inside a block, _ is the topic — NOT auto-wrapped:</span>
fn dbl { my $x = _; $x * 2 }      <span class="comment"># $x captures the first arg</span>
map { my $i = _; $i * 2 } 1:3     <span class="comment"># $i captures each element</span></pre>
        <p><strong>Heuristic</strong>: the wrap fires only when (a) we're at <code>block_depth == 0</code>, (b) the LHS is a single scalar, (c) the first RHS token is a bare positional alias (so <code>match (5) { _ =&gt; … }</code> stays a match expression), and (d) the RHS isn't already a coderef-shaped value. <strong>Disabled under <code>--compat</code></strong>.</p>
      </section>

      <section class="tutorial-section">
        <h2>Hash-key power forms</h2>
        <p>Stryke extends Perl's bareword autoquoting in three ways:</p>
        <ul>
          <li><strong>Topic-slot barewords</strong> — <code>_</code>, <code>_&lt;</code>, <code>_0</code>, <code>_0&lt;</code>, <code>_N&lt;+</code> resolve to the topic value, not the literal name. <code>{ _ =&gt; 1 }</code> ≡ <code>{ $_ =&gt; 1 }</code>; <code>$h-&gt;{_&lt;}</code> reads the outer-scope topic.</li>
          <li><strong>Operator keywords</strong> — <code>eq</code>, <code>ne</code>, <code>lt</code>, <code>gt</code>, <code>le</code>, <code>ge</code>, <code>cmp</code>, <code>and</code>, <code>or</code>, <code>not</code>, <code>x</code> autoquote inside <code>{…}</code> hash subscripts. <code>$h-&gt;{ne}</code>, <code>$h{eq}</code>, etc. read normally.</li>
          <li><strong><code>+{ EXPR }</code> force-hashref</strong> — block-vs-hashref disambiguation falls back to a code block when the body doesn't fit <code>KEY =&gt; VAL</code>. The <code>+</code> prefix forces hashref interpretation; a list-yielding body is paired up to produce a hash. <code>+{ map { ($_, $_ * 2) } (1,2,3) }</code> gives <code>{1 =&gt; 2, 2 =&gt; 4, 3 =&gt; 6}</code>.</li>
        </ul>
      </section>

      <section class="tutorial-section">
        <h2><code>s,/tr,/y,</code> with comma delimiter</h2>
        <p>The <code>s</code>, <code>tr</code>, and <code>y</code> operators accept any non-alphanumeric delimiter, including <code>,</code>. The lookahead heuristic gates the comma form on having three commas before the statement ends, so <code>$obj-&gt;y</code> method calls and <code>struct Pt { x, y, z }</code> field declarations stay barewords.</p>
        <div class="oneliner" style="font-size:11px;">stryke -pe 's,a,b,g' &lt; input
stryke -pe 'tr,A-Z,a-z,'</div>
      </section>

      <section class="tutorial-section">
        <h2>Perl-compat highlights</h2>
        <ul>
          <li><strong>OOP</strong> — <code>@ISA</code>, C3 MRO (live, not cached), <code>$obj-&gt;SUPER::method</code>, <code>tie</code> for scalars/arrays/hashes with <code>TIESCALAR</code>/<code>TIEARRAY</code>/<code>TIEHASH</code>, plus <code>EXISTS</code>/<code>DELETE</code>; <code>use overload</code> with full binary dispatch, <code>nomethod</code>, unary <code>neg</code>/<code>bool</code>/<code>abs</code>. Native <code>class</code> syntax with inheritance, traits, abstract/final, visibility, static fields, operator overloading, and reflection — see <a href="#oop">OOP section</a> below.</li>
          <li><strong>Specials</strong> — <code>$?</code> packed POSIX status, <code>$|</code> autoflush, <code>$.</code> line count (undef until first read), <code>@ARGV</code>, <code>%ENV</code>, <code>%SIG</code> (<code>SIGINT</code>/<code>SIGTERM</code>/<code>SIGALRM</code>/<code>SIGCHLD</code>), <code>format</code>/<code>write</code> (partial).</li>
          <li><strong>Phases</strong> — <code>BEGIN</code> / <code>UNITCHECK</code> / <code>CHECK</code> / <code>INIT</code> / <code>END</code> run in Perl order; <code>${^GLOBAL_PHASE}</code> matches Perl.</li>
          <li><strong>Interpolation</strong> — <code>$var</code>, <code>#{expr}</code>, <code>$h{k}</code>, <code>$a[i]</code>, <code>@a</code>, <code>@a[slice]</code>, <code>$#a</code>, <code>$0</code>, <code>$1</code>..<code>$n</code>; <code>\x{hex}</code> and unbraced <code>\x</code>.</li>
          <li><strong>Strict / modules</strong> — per-mode <code>use strict 'refs'</code> etc., <code>@INC</code> built from <code>-I</code>, <code>vendor/perl</code>, system Perl's <code>@INC</code>, script dir, <code>STRYKE_INC</code>. <code>List::Util</code> is native Rust.</li>
        </ul>
        <p>Full list in the <a href="https://github.com/MenkeTechnologies/strykelang#0x08-supported-perl-features">README §0x08</a>.</p>
      </section>

      <section class="tutorial-section" id="oop">
        <h2>Object-Oriented Programming</h2>
        <p>Stryke supports both Perl 5 OOP (<code>bless</code>, <code>@ISA</code>, <code>tie</code>, <code>use overload</code>) and a native <code>class</code> syntax with inheritance, traits, visibility, static fields, operator overloading, and full reflection.</p>

        <h3>Class basics</h3>
        <p>Declare classes with typed fields, defaults, and instance methods. Fields get auto-generated getters/setters. <code>$self</code> is implicit in methods.</p>
<pre>class Dog {
    name: Str
    breed: Str = "Mixed"
    fn bark { "Woof from " . $self-&gt;name }
}

my $d = Dog(name =&gt; "Rex")           <span class="comment"># named construction</span>
my $d = Dog("Rex", "Lab")             <span class="comment"># positional construction</span>
p $d-&gt;name                            <span class="comment"># getter → "Rex"</span>
$d-&gt;name("Max")                       <span class="comment"># setter</span>
p $d-&gt;bark()                          <span class="comment"># "Woof from Max"</span></pre>

        <h3>Methods with parameters</h3>
<pre>class Calculator {
    value: Int = 0
    fn add($n) { $self-&gt;value + $n }
}
my $c = Calculator(value =&gt; 10)
p $c-&gt;add(5)                          <span class="comment"># 15</span></pre>

        <h3>Static methods</h3>
<pre>class Math {
    fn Self.add($a, $b) { $a + $b }
    fn Self.pi { 3.14159 }
}
p Math::add(3, 4)                      <span class="comment"># 7</span>
p Math::pi()                           <span class="comment"># 3.14159</span></pre>

        <h3>Inheritance (<code>extends</code>)</h3>
        <p>Single and multiple inheritance. Parent fields and methods are inherited. C3 MRO for diamond resolution.</p>
<pre>class Animal {
    name: Str
    fn speak { "Animal: " . $self-&gt;name }
}
class Dog extends Animal {
    fn speak { "Woof from " . $self-&gt;name }  <span class="comment"># override</span>
}
my $d = Dog(name =&gt; "Rex")
p $d-&gt;speak()                         <span class="comment"># "Woof from Rex"</span>

<span class="comment"># multiple inheritance</span>
class A { a: Int = 1 }
class B { b: Int = 2 }
class C extends A, B { c: Int = 3 }
my $c = C()
p $c-&gt;a . "," . $c-&gt;b . "," . $c-&gt;c  <span class="comment"># "1,2,3"</span></pre>

        <h3>Abstract classes</h3>
        <p>Cannot be instantiated directly. Subclasses must implement abstract methods.</p>
<pre>abstract class Shape {
    name: Str
    fn describe { "Shape: " . $self-&gt;name }
}

<span class="comment"># Shape(name =&gt; "x")  → ERROR: cannot instantiate abstract class</span>

class Circle extends Shape { radius: Int }
my $c = Circle(name =&gt; "ring", radius =&gt; 5)
p $c-&gt;describe()                      <span class="comment"># "Shape: ring"</span></pre>

        <h3>Final classes and methods</h3>
        <p><code>final class</code> prevents subclassing. <code>final fn</code> prevents method override in subclasses. Both checked at declaration time.</p>
<pre>final class Config { value: Int = 42 }
<span class="comment"># class Bad extends Config { }  → ERROR: cannot extend final class</span>

class Base {
    final fn id { 42 }
    fn label { "base" }                <span class="comment"># can be overridden</span>
}
class Child extends Base { }
my $c = Child()
p $c-&gt;id()                            <span class="comment"># 42 (inherited, cannot override)</span></pre>

        <h3>Visibility (<code>pub</code> / <code>prot</code> / <code>priv</code>)</h3>
        <p>Applies to both fields and methods. Runtime enforcement on access.</p>
<pre>class Secret {
    pub visible: Int = 1               <span class="comment"># public (default)</span>
    priv hidden: Int = 42              <span class="comment"># own class only</span>
    prot internal: Int = 99            <span class="comment"># class + subclasses</span>

    fn get_hidden { $self-&gt;hidden }    <span class="comment"># internal access ok</span>
}
class Child extends Secret {
    fn get_internal { $self-&gt;internal } <span class="comment"># prot: ok from subclass</span>
}
my $s = Secret()
p $s-&gt;get_hidden()                    <span class="comment"># 42</span>
<span class="comment"># $s-&gt;hidden  → ERROR: private field</span>

my $c = Child()
p $c-&gt;get_internal()                  <span class="comment"># 99</span>
<span class="comment"># $c-&gt;internal  → ERROR: protected field (outside class hierarchy)</span></pre>

        <h3>Static fields</h3>
        <p>Shared across all instances. Access via <code>ClassName::field()</code> (getter) / <code>ClassName::field(value)</code> (setter).</p>
<pre>class Tracker {
    static total: Int = 0
    name: Str
    fn BUILD { Tracker::total(Tracker::total() + 1) }
}
my $a = Tracker(name =&gt; "a")
my $b = Tracker(name =&gt; "b")
p Tracker::total()                     <span class="comment"># 2</span></pre>

        <h3>BUILD / DESTROY hooks (custom constructor / destructor)</h3>
        <p><code>fn BUILD</code> is the custom-constructor hook — runs automatically after field init, parent first then child. Use it for invariant checks, default-injection of computed fields, or post-init wiring. <code>fn DESTROY</code> is the destructor — runs automatically when the object is reaped, child first then parent. Both are method-name conventions the runtime auto-dispatches; no caller-side init step.</p>
<pre>class Connection {
    host: Str
    port: Int = 5432
    socket: Any = undef
    connected_at: Float = 0

    <span class="comment"># Custom constructor — auto-called after fields populate. Open the
    <span class="comment"># socket, stamp the connect time, validate inputs.</span>
    fn BUILD {
        die "host required" unless length $self-&gt;host
        $self-&gt;socket(open_tcp($self-&gt;host, $self-&gt;port))
        $self-&gt;connected_at(time())
    }

    <span class="comment"># Destructor — auto-called on object reap. Close the socket.</span>
    fn DESTROY {
        close_tcp($self-&gt;socket) if defined $self-&gt;socket
    }
}

my $c = Connection(host =&gt; "db.example.com")   <span class="comment"># BUILD fires</span>
<span class="comment"># ... use $c ...</span>
<span class="comment"># DESTROY fires when $c goes out of scope</span></pre>

        <p>Inheritance ordering — parent <code>BUILD</code> first so child code can see parent invariants; child <code>DESTROY</code> first so subclass state unwinds before parent state:</p>
<pre>class Base {
    log: Str = ""
    fn BUILD   { $self-&gt;log("base") }
    fn DESTROY { Base::audit(Base::audit() . "base,") }
    static audit: Str = ""
}
class Child extends Base {
    fn BUILD   { $self-&gt;log($self-&gt;log . "+child") }
    fn DESTROY { Base::audit(Base::audit() . "child,") }
}

my $c = Child()
p $c-&gt;log                             <span class="comment"># "base+child"   (parent BUILD ran first)</span>
$c-&gt;destroy()
p Base::audit()                       <span class="comment"># "child,base,"  (child DESTROY ran first)</span></pre>

        <p>Runnable demo: <a href="https://github.com/MenkeTechnologies/strykelang/blob/main/examples/build_destroy.stk"><code>examples/build_destroy.stk</code></a>.</p>

        <h3>Traits</h3>
        <p>Interface contracts with required and default methods. Enforced at class declaration.</p>
<pre>trait Loggable {
    fn log_prefix { "LOG" }            <span class="comment"># default (optional to implement)</span>
    fn log_msg                         <span class="comment"># required (no body)</span>
}

class Event impl Loggable {
    msg: Str
    fn log_msg { $self-&gt;msg }
}
my $e = Event(msg =&gt; "hello")
p $e-&gt;log_msg()                       <span class="comment"># "hello"</span>
p $e-&gt;does("Loggable")               <span class="comment"># 1</span>

<span class="comment"># Missing required method → compile-time error</span>
<span class="comment"># class Bad impl Loggable { }  → ERROR: missing required method 'log_msg'</span></pre>

        <h3>Late static binding (<code>static::</code>)</h3>
        <p>Resolves to the runtime class of <code>$self</code>, unlike <code>SUPER::</code> which is compile-time.</p>
<pre>class Base {
    fn class_name { static::identify() }
    fn identify { "Base" }
}
class Child extends Base {
    fn identify { "Child" }
}
my $c = Child()
p $c-&gt;class_name()                    <span class="comment"># "Child" (not "Base")</span></pre>

        <h3>Operator overloading</h3>
        <p>Define <code>op_add</code>, <code>op_sub</code>, <code>op_mul</code>, <code>op_div</code>, <code>op_mod</code>, <code>op_pow</code>, <code>op_eq</code>, <code>op_ne</code>, <code>op_lt</code>, <code>op_gt</code>, <code>op_le</code>, <code>op_ge</code>, <code>op_spaceship</code>, <code>op_neg</code>, <code>op_bool</code>, <code>op_abs</code>, <code>op_concat</code>, <code>stringify</code>, and more.</p>
<pre>class Vec2 {
    x: Int
    y: Int
    fn op_add($other) {
        Vec2(x =&gt; $self-&gt;x + $other-&gt;x, y =&gt; $self-&gt;y + $other-&gt;y)
    }
    fn op_neg { Vec2(x =&gt; -$self-&gt;x, y =&gt; -$self-&gt;y) }
    fn stringify { "(" . $self-&gt;x . "," . $self-&gt;y . ")" }
}
my $a = Vec2(x =&gt; 1, y =&gt; 2)
my $b = Vec2(x =&gt; 3, y =&gt; 4)
my $c = $a + $b
p "$c"                                 <span class="comment"># "(4,6)"</span>
my $d = -$a
p "$d"                                 <span class="comment"># "(-1,-2)"</span></pre>

        <h3>Reflection / introspection</h3>
<pre>class Animal { name: Str; fn speak { "..." }; fn eat { "nom" } }
class Dog extends Animal { breed: Str }
my $d = Dog(name =&gt; "Rex", breed =&gt; "Lab")

p join(",", $d-&gt;fields())             <span class="comment"># "name,breed"</span>
p join(",", $d-&gt;methods())            <span class="comment"># "speak,eat"  (inherited)</span>
p join(",", $d-&gt;superclass())         <span class="comment"># "Animal"</span>
p $d-&gt;isa("Dog")                      <span class="comment"># 1</span>
p $d-&gt;isa("Animal")                   <span class="comment"># 1  (inherited)</span>
p $d-&gt;isa("Cat")                      <span class="comment"># ""  (false)</span></pre>

        <h3>Built-in instance methods</h3>
        <table class="reflection-table">
          <thead>
            <tr><th>Method</th><th>Description</th></tr>
          </thead>
          <tbody>
            <tr><td><code>$obj-&gt;fields()</code></td><td>List of all field names (including inherited)</td></tr>
            <tr><td><code>$obj-&gt;methods()</code></td><td>List of all method names (including inherited)</td></tr>
            <tr><td><code>$obj-&gt;superclass()</code></td><td>List of parent class names</td></tr>
            <tr><td><code>$obj-&gt;isa("Class")</code></td><td>Checks inheritance chain</td></tr>
            <tr><td><code>$obj-&gt;does("Trait")</code></td><td>Checks trait implementation</td></tr>
            <tr><td><code>$obj-&gt;clone()</code></td><td>Deep copy (independent instance)</td></tr>
            <tr><td><code>$obj-&gt;with(k =&gt; v)</code></td><td>Functional update — returns new instance with changed fields</td></tr>
            <tr><td><code>$obj-&gt;to_hash()</code></td><td>Convert to hash reference</td></tr>
            <tr><td><code>$obj-&gt;destroy()</code></td><td>Explicit destructor call (triggers DESTROY chain)</td></tr>
            <tr><td><code>"$obj"</code></td><td>Stringify — <code>Class(field =&gt; val, ...)</code> or custom <code>stringify</code></td></tr>
          </tbody>
        </table>

        <h3>Field types</h3>
        <p>Runtime validation on setter. <code>Float</code> accepts both int and float. Custom types (struct/enum names) also work.</p>
<pre>class Typed {
    count: Int               <span class="comment"># integer</span>
    name: Str                <span class="comment"># string</span>
    ratio: Float             <span class="comment"># int or float</span>
    items: Array             <span class="comment"># array reference</span>
    map: Hash                <span class="comment"># hash reference</span>
    any_val                  <span class="comment"># untyped (Any)</span>
}</pre>
      </section>

      <section class="tutorial-section">
        <h2>Extensions beyond stock Perl 5</h2>
        <ul>
          <li><strong>Native data</strong> — CSV (<code>csv_read</code>/<code>csv_write</code>), columnar <code>dataframe</code>, embedded <code>sqlite</code>, TOML/YAML helpers.</li>
          <li><strong>HTTP</strong> — <code>fetch</code> / <code>fetch_json</code> / <code>fetch_async</code> / <code>par_fetch</code>.</li>
          <li><strong>Crypto / compression</strong> — <code>sha256</code>, <code>hmac_sha256</code>, <code>jwt_encode</code>/<code>decode</code>, <code>gzip</code> / <code>gunzip</code> / <code>zstd</code>.</li>
          <li><strong>Standalone binaries</strong> — <code>s build SCRIPT -o OUT</code> bakes a script into a self-contained executable.</li>
          <li><strong>Inline Rust FFI</strong> — <code>rust { pub extern "C" fn ... }</code> blocks compile to a cdylib on first run, dlopen + register as Perl-callable subs.</li>
          <li><strong>Bytecode cache</strong> — single rkyv shard at <code>~/.stryke/scripts.rkyv</code>, <code>mmap</code> + zero-copy <code>ArchivedHashMap</code> lookup, skips lex/parse/compile on warm starts. <strong>11x faster per-process</strong> than the old SQLite cache. <code>stryke test FILE</code> participates in the same cache so test reruns skip compile too. Disable with <code>STRYKE_CACHE=0</code>. <a href="../docs/CACHE_RKYV_MIGRATION.md">Migration story &amp; benchmarks →</a></li>
          <li><strong>Interactive REPL</strong> — reedline-based, line history at <code>~/.stryke/history</code>, columnar tab completion for keywords / lexicals / sub names / arrow methods on blessed objects. Edit mode (emacs/vi) configured via <code>~/.stryke/config.toml</code> <code>[repl] mode = "vi"</code> or per-session via <code>STRYKE_REPL_MODE=vi</code>. The config file is auto-seeded on first launch with all keys commented (documents the schema; default behavior unchanged until you uncomment).</li>
          <li><strong>Distributed compute</strong> — <code>cluster([...])</code> builds an SSH worker pool; <code>pmap_on $cluster { } @list</code> fans an element-wise map across persistent remote workers; <code>~d&gt; on $cluster SRC stages</code> ships chunks of <code>SRC</code> to remote slots and runs the full stage chain per chunk (the <code>~p&gt;</code> surface, distributed). Both share the same dispatcher: ssh-per-slot handshake once, JOB frames per item, per-job retry, order-preserving collect.</li>
          <li><strong>Shared state</strong> — <code>mysync</code> declares atomic variables safe to mutate from parallel workers.</li>
          <li><strong>Language server</strong> — <code>s lsp</code> (or <code>s --lsp</code>) runs an LSP server over stdio with diagnostics, hover, completion. The nine reflection hashes above are part of the completion surface.</li>
        </ul>
      </section>

      <section class="tutorial-section">
        <h2>CLI flags (common)</h2>
<pre>-e CODE                // one-line program (multiple -e's allowed)
-E CODE                // like -e, but enables all optional features
-c                     // syntax check only
--lint / --check       // parse + compile bytecode without running
--disasm               // print bytecode disassembly before VM run
--ast                  // dump parsed AST as JSON and exit
--fmt                  // pretty-print parsed Perl to stdout and exit
--profile              // wall-clock profile stderr (flamegraph-ready)
--flame                // flamegraph: terminal bars (TTY) or SVG
--no-jit               // disable Cranelift JIT (bytecode interpreter only)
--compat               // Perl 5 strict-compat: disable all stryke extensions
-n / -p / -i           // stdin line-mode + in-place edit
-j N                   // parallel threads for multi-file execution
--script               // force script lookup when name conflicts with builtin

// Subcommands
s build SCRIPT -o OUT  // AOT compile to standalone binary
s build --project DIR  // bundle project (main.stk + lib/) into binary
s check FILE...        // parse + compile without executing (CI/editor)
s disasm FILE          // disassemble bytecode
s profile FILE         // run with profiling (--flame for SVG)
s fmt -i FILE...       // format source files in place
s bench                // run benchmarks from bench/ or benches/
s test                 // run tests from t/
s init NAME            // scaffold new project (lib/, bench/, t/)
s repl --load FILE     // REPL with pre-loaded file
s lsp                  // language server over stdio
s completions zsh      // emit shell completions
s ast FILE             // dump AST as JSON
s prun FILE...         // run multiple files in parallel
s convert FILE...      // convert Perl to stryke syntax
s deconvert FILE...    // convert stryke back to Perl
s --remote-worker      // worker process for distributed cluster</pre>

        <h3>Command Resolution Hierarchy</h3>
        <p>When you run <code>stryke ARG</code>, resolution follows this order:</p>
        <ol>
          <li><strong>Subcommand</strong> — <code>build</code>, <code>docs</code>, <code>fmt</code>, <code>test</code>, <code>bench</code>, <code>init</code>, <code>repl</code>, <code>run</code>, <code>serve</code>, <code>check</code>, <code>disasm</code>, <code>profile</code>, <code>lsp</code>, <code>ast</code>, <code>prun</code>, <code>convert</code>, <code>deconvert</code>, <code>completions</code>, <code>agent</code>, <code>controller</code></li>
          <li><strong>Builtin function</strong> — if ARG is a known builtin AND no file named ARG exists, call <code>ARG(@ARGV)</code> and print result</li>
          <li><strong>Script file</strong> — if file exists, run as script</li>
          <li><strong>Inline code</strong> — if ARG looks like code (contains operators, parens, etc.), execute as one-liner</li>
        </ol>
        <p>Use <code>--script</code> to force script lookup when a builtin name conflicts with a script file.</p>
<pre><span class="comment"># Call builtins directly from CLI</span>
s pin                       <span class="comment"># calls pin() — 100% TDP forever</span>
s heat 60                   <span class="comment"># calls heat(60) — 100% TDP for 60s</span>
s basename /foo/bar/baz.txt <span class="comment"># calls basename(@ARGV) → "baz.txt"</span>
s dirname /foo/bar/baz.txt  <span class="comment"># calls dirname(@ARGV) → "/foo/bar"</span>
s gethostname               <span class="comment"># calls gethostname() → hostname</span>
s avg 1 2 3 4 5             <span class="comment"># calls avg(@ARGV) → 3</span>

<span class="comment"># Aliases work too</span>
s bn /foo/bar/baz.txt       <span class="comment"># basename alias</span>
s dn /foo/bar/baz.txt       <span class="comment"># dirname alias</span>
s hn                        <span class="comment"># gethostname alias</span>
s faf                       <span class="comment"># fire_and_forget alias (same as pin)</span>

<span class="comment"># Force script when name conflicts</span>
s --script basename         <span class="comment"># run ./basename script, not builtin</span></pre>
      </section>

      <section class="tutorial-section" id="bytecode-cache">
        <h2>Bytecode Cache (rkyv)</h2>
        <p>stryke caches compiled bytecode in a single rkyv-archived shard at <code>~/.stryke/scripts.rkyv</code>. First run of a script parses + compiles + persists into the shard. Every subsequent run <code>mmap</code>s the shard, validates the archived root once, looks up the entry by canonical path in a zero-copy <code>ArchivedHashMap</code>, and skips lex/parse/compile entirely.</p>
<pre>stryke my_app.stk    <span class="comment"># cold: parse + compile + write to shard</span>
stryke my_app.stk    <span class="comment"># warm: mmap shard + lookup + dispatch</span></pre>

        <h3>Why rkyv (and not SQLite, like before)?</h3>
        <p>The original cache was a SQLite database — port of an early <code>zshrs</code> design. We migrated to rkyv shards in v0.10.3. Apples-to-apples bench (<code>strykelang/cache_bench.rs</code>, 100 scripts, M-series, OS page cache warm):</p>
        <table class="reflection-table">
          <tr><th>Workload</th><th>SQLite (zstd + bincode)</th><th>rkyv (uncompressed)</th><th>Speedup</th></tr>
          <tr><td>Steady-state per hit</td><td>8.60 µs</td><td>2.49 µs</td><td><strong>3.46×</strong></td></tr>
          <tr><td>Per-process p50 (open + 1 lookup + close)</td><td>241 µs</td><td>22 µs</td><td><strong>10.79×</strong></td></tr>
          <tr><td>Per-process total (1000 invocations)</td><td>263.62 ms</td><td>22.95 ms</td><td><strong>11.48×</strong></td></tr>
          <tr><td>File size (100 scripts)</td><td>84 KB</td><td>270 KB</td><td>0.31× (3.2× bigger)</td></tr>
        </table>
        <p>The per-process number is the one that matters for <code>s test t</code> — each test file spawns a fresh process that opens the cache, does one lookup, exits. SQLite pays its full <code>Connection::open</code> + WAL pragmas + statement prepare cost on every process; rkyv pays one <code>mmap</code> + one <code>check_archived_root</code> validation, then <code>ArchivedHashMap::get</code>.</p>
        <p>The 3.2× size growth is the zstd compression we dropped on the inner blobs (kept bincode for now — phase 2 will derive <code>Archive</code> directly on <code>Chunk</code>/<code>Program</code> for true zero-copy load). Disk size is acceptable: 1000+ scripts cached in ~15 MB.</p>

        <h3>Cache invalidation</h3>
        <p>Four conditions evict an entry — no stale bytecode is ever served:</p>
        <ul>
          <li><strong>Source <code>mtime</code> mismatch</strong> — edit a <code>.stk</code> file → cache miss → recompile.</li>
          <li><strong><code>stryke_version</code> mismatch</strong> — Cargo version bump.</li>
          <li><strong>Pointer-width mismatch</strong> — cross-build between 32- and 64-bit targets.</li>
          <li><strong>Binary <code>mtime</code> newer than cached entry</strong> — any <code>cargo build</code> advances the binary's mtime → every cached script invalidates automatically. Catches edits to <code>compiler.rs</code> / <code>parser.rs</code> / <code>vm.rs</code> that don't bump <code>CARGO_PKG_VERSION</code>.</li>
        </ul>

        <h3>Inspection &amp; tuning</h3>
<pre>cacheview()                    <span class="comment"># list all cached scripts</span>
cacheview("pattern")           <span class="comment"># filter by path</span>
cacheview("--count")           <span class="comment"># just the count</span>
cache_stats()                  <span class="comment"># {count, bytes, path, enabled}</span>
cache_exists("script.stk")     <span class="comment"># 1 if cached, 0 if not</span>
cache_clear()                  <span class="comment"># wipe the cache</span>

STRYKE_CACHE=0 stryke app.stk  <span class="comment"># disable caching for this run</span></pre>
        <p>Bypassed for <code>-e</code> / <code>-E</code> one-liners, <code>-n</code> / <code>-p</code>, <code>--lint</code>, <code>--check</code>, <code>--ast</code>, <code>--fmt</code>, <code>--profile</code> modes. Cache is enabled by default for file-based scripts.</p>

        <h3>Aligned with zshrs</h3>
        <p>Same rkyv shard pattern as <code>zshrs/src/daemon/shard.rs</code> — <code>mmap</code> + <code>check_archived_root</code> + zero-copy <code>ArchivedHashMap</code> lookup. zshrs uses per-source-tree shards driven by a daemon; stryke uses a single global shard since scripts are individually invoked. Same crate (<code>rkyv = "0.7"</code> with <code>validation</code>, <code>archive_le</code>, <code>size_32</code> features), same crash-safety story (<code>flock</code> on <code>scripts.rkyv.lock</code>, atomic-rename writes via tmp file + <code>fsync</code>), same versioning fields (<code>magic: u32</code> + <code>format_version: u32</code>).</p>
        <p>Full migration rationale, file-by-file diff, and reproducible bench harness at <a href="../docs/CACHE_RKYV_MIGRATION.md"><code>docs/CACHE_RKYV_MIGRATION.md</code></a>.</p>
      </section>

      <section class="tutorial-section" id="threading-vs-clojure-racket">
        <h2>Threading macros vs Racket / Clojure</h2>
        <p>Every other language with arrow-threading treats the arrow as <em>pure compile-time syntax</em>: a macroexpansion-time AST rewrite into nested calls. Concurrency, when wanted, is a separate primitive (<code>pmap</code>, <code>future</code>, <code>core.async</code>, racket <code>place</code>s). Stryke is the first language to bake execution semantics directly into the threading-arrow family — same surface grammar, distinct runtime models.</p>

        <table class="reflection-table">
          <thead>
            <tr><th>Operator</th><th>Lang</th><th>Desugar / runtime</th><th>Concurrency</th><th>Backpressure</th><th>Per-chunk</th></tr>
          </thead>
          <tbody>
            <tr>
              <td><code>(-&gt; x (f a))</code></td>
              <td>Clojure</td>
              <td>macroexpand &rarr; <code>(f x a)</code> at compile time</td>
              <td>none — sequential</td>
              <td>n/a</td>
              <td>n/a</td>
            </tr>
            <tr>
              <td><code>(-&gt;&gt; x (f a))</code></td>
              <td>Clojure</td>
              <td>macroexpand &rarr; <code>(f a x)</code> (LHS as last arg)</td>
              <td>none — sequential</td>
              <td>n/a</td>
              <td>n/a</td>
            </tr>
            <tr>
              <td><code>(as-&gt; x $ (f $) (g $))</code></td>
              <td>Clojure</td>
              <td>macroexpand with explicit <code>$</code> slot</td>
              <td>none — sequential</td>
              <td>n/a</td>
              <td>n/a</td>
            </tr>
            <tr>
              <td><code>(cond-&gt; x p? (f))</code> / <code>(some-&gt;)</code></td>
              <td>Clojure</td>
              <td>conditional / nil-short-circuit macros</td>
              <td>none — sequential</td>
              <td>n/a</td>
              <td>n/a</td>
            </tr>
            <tr>
              <td><code>(~&gt; x (f a))</code> / <code>(~&gt;&gt; x ...)</code></td>
              <td>Racket (<code>threading</code>)</td>
              <td>macroexpand to nested call (lib macro)</td>
              <td>none — sequential</td>
              <td>n/a</td>
              <td>n/a</td>
            </tr>
            <tr>
              <td><code>x |&gt; f</code></td>
              <td>Elixir / F# / OCaml / R / Hack / JS proposal</td>
              <td>parse-time / inline-fn rewrite to function application</td>
              <td>none — sequential</td>
              <td>n/a</td>
              <td>n/a</td>
            </tr>
            <tr style="border-top:2px solid var(--accent);">
              <td><code>~&gt; SRC stage1 stage2</code></td>
              <td><strong>stryke</strong></td>
              <td>parse-time rewrite (compatible with Racket <code>~&gt;</code> / Clojure <code>-&gt;</code>)</td>
              <td>none — sequential</td>
              <td>n/a</td>
              <td>n/a</td>
            </tr>
            <tr>
              <td><code>~&gt;&gt; SRC stage1 stage2</code></td>
              <td><strong>stryke</strong></td>
              <td>parse-time, thread-last (Clojure <code>-&gt;&gt;</code> compatible)</td>
              <td>none — sequential</td>
              <td>n/a</td>
              <td>n/a</td>
            </tr>
            <tr>
              <td><code>|&gt; rhs</code></td>
              <td><strong>stryke</strong></td>
              <td>parse-time pipe-forward (Elixir-compatible spelling)</td>
              <td>none — sequential</td>
              <td>n/a</td>
              <td>n/a</td>
            </tr>
            <tr style="background: rgba(0, 229, 255, 0.05);">
              <td><code>~s&gt;</code> / <code>~s&gt;&gt;</code></td>
              <td><strong>stryke</strong></td>
              <td>each stage compiled to a worker thread connected by bounded channels (per-item streaming)</td>
              <td><strong>concurrent</strong> across stages</td>
              <td><strong>yes</strong> — bounded channels</td>
              <td>n/a (per-item)</td>
            </tr>
            <tr style="background: rgba(0, 229, 255, 0.05);">
              <td><code>~p&gt;</code> / <code>~p&gt;&gt;</code></td>
              <td><strong>stryke</strong></td>
              <td>input split on type-aware chunk boundaries; whole pipeline runs per-chunk via rayon work-stealing pool with auto-merger</td>
              <td><strong>parallel</strong> (N workers, N=CPU)</td>
              <td>n/a (eager)</td>
              <td><strong>yes</strong> — UTF-8 / element-aligned</td>
            </tr>
            <tr style="background: rgba(0, 229, 255, 0.05);">
              <td><code>par { BLOCK }</code> / <code>par_reduce { … } [{ … }]</code></td>
              <td><strong>stryke</strong></td>
              <td>generic parallel-chunk thread-stage with auto-merge (hash-of-num &rarr; key-wise add, num &rarr; sum, array/string &rarr; concat)</td>
              <td><strong>parallel</strong></td>
              <td>n/a</td>
              <td><strong>yes</strong></td>
            </tr>
            <tr style="background: rgba(0, 229, 255, 0.05);">
              <td><code>||&gt;</code> / <code>|then|</code></td>
              <td><strong>stryke</strong></td>
              <td>boundary marker: switches the rest of a <code>~p&gt;</code> chain back to sequential <code>~&gt;</code> mode (terminal merge stages run on the merged whole)</td>
              <td>boundary &mdash; switches mode</td>
              <td>n/a</td>
              <td>n/a</td>
            </tr>
          </tbody>
        </table>

        <h3>What's structurally novel</h3>
        <ul>
          <li><strong>Pure-syntax tradition:</strong> Clojure / Racket / Elixir / F# / OCaml / R / Hack / JS treat threading as compile-time AST rewrite. To get parallelism you call a separate function (Clojure <code>pmap</code>, Racket <code>future</code>, Elixir <code>Task.async</code>, OCaml <code>Domain.spawn</code>) — never via the arrow.</li>
          <li><strong>Stryke axis-2 — execution model:</strong> <code>~s&gt;</code> and <code>~p&gt;</code> use the <em>same surface grammar</em> as <code>~&gt;</code> but emit different bytecode. One-token swap changes "evaluate sequentially" to "spawn a per-stage worker pool with channels" or "split into chunks and reduce in a tree." No re-plumbing required.</li>
          <li><strong>Boundary markers:</strong> <code>||&gt;</code> / <code>|then|</code> are the world's-first operator that <em>changes the threading mode mid-chain</em>. Lets a single declaration mix parallel chunked extraction with sequential terminal stages without breaking the macro.</li>
          <li><strong>Auto-merger for parallel chunks:</strong> <code>par_reduce { extract }</code> picks a merge strategy by inspecting the first chunk's result type (hash &rarr; key-wise add, scalar &rarr; sum, array &rarr; concat, string &rarr; concat). Canonical histogram merge in one stage; no plumbing.</li>
          <li><strong>Compatibility floor:</strong> <code>~&gt;</code> / <code>~&gt;&gt;</code> / <code>|&gt;</code> behave exactly like Racket <code>~&gt;</code> / Clojure <code>-&gt;&gt;</code> / Elixir <code>|&gt;</code>. Polyglots get the familiar semantics for free; the parallel forms are pure addition.</li>
        </ul>

        <h3>Equivalent rewrite vs. one-token swap</h3>
        <p>To get the equivalent of <code>~p&gt; @data map { _ * 2 } sum</code> in Clojure today, you write:</p>
<pre>(-&gt;&gt; data
     (partition-all (chunk-size))
     (pmap (fn [chunk] (-&gt;&gt; chunk
                            (map #(* 2 %))
                            (reduce +))))
     (reduce +))</pre>
        <p>Five lines, three nested operations, two manual reduces, and an explicit chunk size. Stryke compresses the same shape to:</p>
<pre>~p&gt; @data map { _ * 2 } sum</pre>
        <p>Same input, same output, same parallelism — different operator. The chunk split, worker dispatch, and tree-merge are the operator's job.</p>
      </section>

      <section class="tutorial-section">
        <h2>Inventions</h2>
        <p>Designs that originated in stryke. Other languages are invited to absorb, adapt, or build on any of these under MIT — see <a href="../CREATORS.md">CREATORS.md § Porting stryke ideas</a> for the attribution norm. The list also doubles as the canonical reference porters cite.</p>

        <table class="reflection-table">
          <thead>
            <tr><th>Invention</th><th>Form</th><th>What it does</th></tr>
          </thead>
          <tbody>
            <tr>
              <td><strong>Three-axis threading-operator family</strong></td>
              <td><code>|&gt;</code> &middot; <code>~&gt;</code> &middot; <code>-&gt;&gt;</code></td>
              <td>One operator family with three distinct semantics (pipe-forward, Racket-style, Clojure-style), each accepting bare-fn / arrow-block / placeholder forms per stage. Collapses what Clojure does with three separate macros (<code>-&gt;</code>, <code>-&gt;&gt;</code>, <code>as-&gt;</code>) into one.</td>
            </tr>
            <tr>
              <td><strong>Streaming &amp; chunk-parallel thread macros</strong></td>
              <td><code>~s&gt;</code> &middot; <code>~s&gt;&gt;</code> &middot; <code>~p&gt;</code> &middot; <code>~p&gt;&gt;</code></td>
              <td>Threading macros with execution semantics baked into the operator: <code>~s&gt;</code> / <code>~s&gt;&gt;</code> run each stage as a worker connected by bounded channels (per-item streaming with backpressure), <code>~p&gt;</code> / <code>~p&gt;&gt;</code> chunk the input and run the whole pipeline per-chunk in parallel with an auto-merger (canonical histogram merge for hash-of-numeric, numeric add, array/string concat). <code>||&gt;</code> / <code>|then|</code> mid-pipeline boundary switches a <code>~p&gt;</code> back to sequential <code>~&gt;</code> for terminal stages. No other language overloads its threading macros with concurrent / chunk-parallel semantics — Clojure's <code>-&gt;</code> family is purely syntactic.</td>
            </tr>
            <tr>
              <td><strong>Mid-chain threading-mode-switch operator</strong></td>
              <td><code>||&gt;</code> &middot; <code>|then|</code></td>
              <td>Boundary marker that terminates the chunk-parallel section of a <code>~p&gt;</code> chain and switches the merged result into a sequential <code>~&gt;</code> continuation for terminal stages that operate on the whole. Pure-syntax pipe operators in F# / Hack / Elixir / OCaml / Scala / Julia / R / Clojure / Racket have no equivalent because their threading macros lack execution semantics in the first place — there is no &ldquo;mode&rdquo; to switch out of. The English alias <code>|then|</code> reads as English without changing semantics.</td>
            </tr>
            <tr>
              <td><strong>Generic parallel-chunk wrapper</strong></td>
              <td><code>par { BLOCK }</code> &middot; <code>par_reduce { extract } [{ merge }]</code></td>
              <td>Replaces the explosion of per-fn parallel-prefixed builtins (<code>pletters</code>, <code>pchars</code>, <code>pwords</code>, <code>puc</code>, <code>plc</code>, <code>psplit</code>, <code>pjoin</code>, <code>psum</code>, <code>pmin</code>, <code>pmax</code>, <code>pany</code>, <code>pall</code>, <code>pcount</code>, <code>pfind</code>, ...) with one wrapper that splits input on type-aware chunk boundaries (UTF-8 char-aligned for strings, element-aligned for arrays) and runs any block per chunk in parallel. <code>par_reduce</code> adds an auto-detected merger so frequency-style fused extract+count pipelines (<code>par_reduce { letters |&gt; freq }</code>) achieve 3.5&times;+ wall speedup without materialising 50M-element intermediate vectors. No prior language exposes &ldquo;take any block, parallelize it across chunks of input&rdquo; as a single composable primitive.</td>
            </tr>
            <tr>
              <td><strong>Implicit-positional closure params with depth</strong></td>
              <td><code>_</code> &middot; <code>_&lt;</code> &middot; <code>_&lt;&lt;</code> &middot; <code>_&lt;3</code> &middot; <code>_0</code> &middot; <code>_0&lt;</code> &middot; <code>_0&lt;&lt;</code> &middot; <code>_N&lt;&lt;&lt;&lt;</code></td>
              <td>Two-axis closure-arg notation: <code>N</code> selects positional slot, <code>&lt;</code> count selects closure-nesting depth outward (<code>_&lt;</code> = depth 1, <code>_&lt;&lt;&lt;&lt;&lt;</code> = depth 5, <code>_&lt;N</code> = indexed shortcut). Four-way alias for slot 0 (<code>_</code>, <code>$_</code>, <code>_0</code>, <code>$_0</code>) unifies Scala / Perl / Mathematica / sigil-positional traditions. Bare <code>_&lt;</code> is the sigil-less slot-0 outer-topic shortcut; equivalent to <code>$_&lt;</code>, <code>_0&lt;</code>, <code>$_0&lt;</code>.</td>
            </tr>
            <tr>
              <td><strong>Polymorphic literal-typed range</strong></td>
              <td><code>1:10</code> &middot; <code>'a':'z'</code> &middot; <code>'I':'X'</code> &middot; <code>'2026-01-01':'2026-12-31'</code></td>
              <td>Range syntax where literal type infers range type — integer / character / roman numeral / ISO date / RFC3339 datetime / dotted-quad IP. Step semantics inferred from inferred type.</td>
            </tr>
            <tr>
              <td><strong>Parse-time idiomatic firewall</strong></td>
              <td><code>--no-interop</code></td>
              <td>Parser-enforced rejection of Perl-isms (<code>sub</code>, <code>say</code>, <code>$a</code>/<code>$b</code> globals, <code>scalar</code>, etc.) in favor of stryke idioms (<code>fn</code>, <code>p</code>, <code>$_0</code>/<code>$_1</code>, <code>len</code>). Documented rules become parser errors so LLMs and bots can't ignore them.</td>
            </tr>
            <tr>
              <td><strong>AOP intercepts as language primitive</strong></td>
              <td><code>before</code> &middot; <code>after</code> &middot; <code>around</code> &middot; <code>intercept</code></td>
              <td>Pre / post / around hooks first-class in the language. Not a library — the parser, compiler, and VM all know about the intercept layer.</td>
            </tr>
            <tr>
              <td><strong>AI primitives as syntactic forms</strong></td>
              <td><code>ai</code> &middot; <code>tool fn</code> &middot; <code>mcp_server_start</code></td>
              <td>Calling Anthropic / OpenAI is a builtin verb on par with <code>print</code>. Tool-use, batch fan-out, and MCP server / client are language-level constructs, not third-party crates.</td>
            </tr>
            <tr>
              <td><strong>Encyclopedic-stdlib design axis</strong></td>
              <td>10,020 builtins / 10,632 spellings in 31&nbsp;MB single static binary, zero-import</td>
              <td>Inverts the prevailing scripting-language design philosophy — &ldquo;core minimal, libraries optional&rdquo; becomes &ldquo;core encyclopedic, libraries unnecessary.&rdquo; Shipped builtins span crypto, stats, linear algebra, networking, codecs, terminal viz, git, jq. Density: ~3.6&nbsp;KB amortized per builtin, ~200&times; denser than Wolfram Engine v14 (~5&ndash;6 GB on disk for ~7,000 builtins). The single-binary qualifier is structural, not just a packaging choice — no kernel boot, no paclet manager, no licensing daemon, no <code>library()</code> resolution.</td>
            </tr>
            <tr>
              <td><strong>Live-binding hash with kind strings</strong></td>
              <td><code>%parameters</code></td>
              <td>zsh-<code>$parameters</code> analogue: keys are sigil-prefixed names (<code>$x</code>, <code>@a</code>, <code>%h</code>), values are kind strings (<code>"scalar"</code>, <code>"array"</code>, <code>"hash"</code>, <code>"atomic_array"</code>, ...). Rebuilt on every read so the snapshot is always current.</td>
            </tr>
            <tr>
              <td><strong>Lazy package-stash refresh</strong></td>
              <td><code>%main::</code> &middot; <code>%Foo::</code></td>
              <td>Per-package symbol-table stashes refreshed lazily on every read so newly-defined subs / <code>our</code> vars are visible immediately. Symbol-name → kind string (<code>"scalar"</code> / <code>"sub"</code>).</td>
            </tr>
            <tr>
              <td><strong>Compiled Unix shell substrate</strong></td>
              <td><code>fusevm</code> + zshrs</td>
              <td>First compiled Unix shell. Stryke and zshrs share a bytecode VM and Cranelift JIT path; the shell hosts the scripting language with zero-fork dispatch via <code>@expr</code> syntax.</td>
            </tr>
            <tr>
              <td><strong>Distributed compute as primitive</strong></td>
              <td><code>cluster([...])</code> &middot; <code>pmap_on $c { } @list</code> &middot; <code>~d&gt; on $c SRC stages</code></td>
              <td>Multi-host SSH worker pool as a language-level value. <code>pmap_on</code> fans a parallel map across persistent remote workers with fault tolerance; <code>~d&gt;</code> is the same chunk-block thread-macro surface as <code>~p&gt;</code> but each chunk ships to a remote slot for chunk-aware distributed pipelines. Not a framework, not a library — a builtin triple.</td>
            </tr>
            <tr>
              <td><strong>AOT script binary deployment</strong></td>
              <td><code>s build script.stk</code></td>
              <td>Single static binary output from a script. No runtime install on target, no <code>node_modules</code>, no <code>bundle install</code>, no Docker required — <code>scp ./binary prod:</code> is the deploy.</td>
            </tr>
          </tbody>
        </table>

        <p style="font-size:11px;color:var(--text-muted);margin-top:1rem;">When a port lands in another language, a one-sentence credit in that language's docs (feature reference / release notes / &ldquo;Influences&rdquo; section) referring to stryke as the invention source is the asked attribution form. See <a href="../CREATORS.md#porting-stryke-ideas-to-other-languages">CREATORS.md</a> for the exact wording.</p>
      </section>

      <section class="tutorial-section">
        <h2>Repository &amp; links</h2>
        <ul>
          <li><strong>Source</strong> — <a href="https://github.com/MenkeTechnologies/strykelang">GitHub repo</a></li>
          <li><strong>Crate</strong> — <a href="https://crates.io/crates/strykelang">crates.io</a> (<code>cargo install strykelang</code>)</li>
          <li><strong>Rust API docs</strong> — <a href="https://docs.rs/strykelang">docs.rs</a></li>
          <li><strong>Issues</strong> — <a href="https://github.com/MenkeTechnologies/strykelang/issues">issue tracker</a></li>
          <li><strong>Full README</strong> — <a href="https://github.com/MenkeTechnologies/strykelang#readme">README on GitHub</a> (install, parallel primitives, mysync, CLI flags, architecture, benchmarks, standalone binaries, inline Rust, bytecode cache, distributed <code>pmap_on</code>, LSP).</li>
          <li><strong>Parity</strong> — <code>parity/cases/*.pl</code> holds 20k+ Perl-vs-s test cases run by <code>parity/run_parity.sh</code>.</li>
        </ul>
      </section>
    </main>
  </div>

  <script src="hud-theme.js"></script>
</body>
</html>