algocline 0.44.2

LLM amplification engine — MCP server with Lua scripting
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
# Package author conventions

This document codifies the conventions algocline expects from package
authors. It is the single source of truth for the docstring convention,
the `M.meta` / `M.spec` / `M.docs` shape contract, and the lint rules
enforced by `alc_hub_gendoc`.

---

## 0. SSoT / Projection — Source vs generated artifacts

algocline pkg conventions enforce a strict separation between
**Source** (hand-written) and **Projection** (machine-generated):

- **Source (SSoT)**: `init.lua` — specifically `M.meta`, `M.spec`,
  and the leading `---` docstring block. This is the only file an
  author edits.
- **Projection**: every other artifact about the pkg, regenerated
  by `alc_hub_dist` from the Source.

Recognised projections (current set; the authoritative list lives in
`crates/algocline-app/src/service/lua/gendoc/docs/projections.lua`):

| Projection target            | `alc_hub_dist` projections key | Purpose                                  |
|------------------------------|--------------------------------|------------------------------------------|
| `docs/narrative/{name}.md`   | `narrative`                    | Rendered docstring + Parameters table    |
| `llms.txt` / `llms-full.txt` | `llms`                         | LLM-readable pkg catalog                 |
| `context7.json`              | `context7`                     | Context7 MCP integration                 |
| `.devin/wiki.json`           | `devin`                        | Devin AI wiki ingestion                  |
| `types/alc_pkgs.d.lua`       | `luacats`                      | LuaCATS type stubs for IDE               |

**Hand-writing or hand-editing any projection is forbidden.** A
discrepancy between Source and Projection always means either
(a) a stale projection that needs regeneration, or (b) a Source
write disguised as a projection edit. The lint pipeline assumes
Source is canonical.

The legacy `M.docs.narrative` field and standalone `narrative.md`
files were transitional violations of this principle — projections
that authors edited by hand. They are now fully generated.

---

## 1. Publish patterns and lint scope

Pkg authors fall into one of three publish patterns. Each pattern has
a different lint posture; the same lint codes (§5) are evaluated, but
the severity boundary that fails a build differs.

| Pattern       | Distribution                                                        | Lint mode                | Author expectation                                                                                |
|---------------|---------------------------------------------------------------------|--------------------------|---------------------------------------------------------------------------------------------------|
| **Bundled**   | Shipped via `algocline-bundled-packages` (the official curated set) | `lint_strict=true`       | Required + Recommended fields all populated. Every warning is treated as an error.                |
| **Community** | Personal repos, gists, hand-installed packages                      | `lint_strict=false`      | Required fields populated. Recommended fields strongly encouraged but warnings are non-blocking.  |
| **Private**   | Local-only experiments, never published                             | Lint not expected to run | No baseline. Authors may run lint at their discretion.                                            |

`lint_strict=true` (Bundled / CI gate) is the only mode that fails
the build on warnings. `lint_strict=false` (default) allows warnings
to surface in tooling output without blocking the build.

After lint passes, `alc_hub_dist` (the **DIST** stage) regenerates
every projection listed in §0.

The Required vs Recommended boundary is defined in §2 (`M.meta`
fields) and §3 (docstring shape). All conventions in this document
apply to all three patterns; only the lint posture differs.

---

## 2. Top-level pkg shape

Every algocline pkg is a Lua module that returns a table `M`. The canonical layout (taken from `cot/init.lua` and trimmed):

```lua
local S = require("alc_shapes")
local T = S.T

local M = {}

---@type AlcMeta
M.meta = {
    name        = "cot",
    version     = "0.1.0",
    description = "Iterative chain-of-thought — cumulative reasoning steps, then synthesis",
    category    = "reasoning",
}

---@type AlcSpec
M.spec = {
    entries = {
        run = {
            input = T.shape({
                task  = T.string:describe("The question or task to reason about"),
                depth = T.number:is_optional():describe("Number of reasoning steps (default: 3)"),
            }),
            result = T.shape({
                chain      = T.array_of(T.string):describe("Ordered insights, one per reasoning step"),
                conclusion = T.string:describe("Synthesized final answer"),
            }),
        },
    },
}

-- M.docs is optional; set schema_version for future compat if needed.
-- Do NOT set M.docs.narrative — that field has been removed.
M.docs = {
    schema_version = 1,
}

function M.run(ctx)
    -- ...
end

return M
```

Each field below is tagged with one of three status labels. The same labels are used throughout this document.

| Status          | Meaning                                                                                                                                                       |
|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Required**    | Must be present. Missing it is a lint error in every publish pattern (§1).                                                                                    |
| **Recommended** | Not required, but strongly encouraged. **Bundled** pkgs are expected to populate it; missing it is a warning by default and an error under `lint_strict=true`. |
| **Optional**    | May be omitted. No lint emission.                                                                                                                             |

### 2.1 `M.meta` — identity

| Field                | Status          | Type   | Notes                                                                                                          |
|----------------------|-----------------|--------|----------------------------------------------------------------------------------------------------------------|
| `name`               | **Required**    | string | Must match the pkg directory name (lint: `E_NAME_MISMATCH`).                                                   |
| `version`            | **Required**    | string | SemVer. **Top-level `M.VERSION` is legacy** and triggers `W_META_LEGACY_M_VERSION`; use `M.meta.version` only. |
| `description`        | **Required**    | string | One-line tagline (≤ 80 char). Projected into `llms.txt` entry.                                                 |
| `category`           | **Required**    | string | Grouping key for `llms.txt` and hub search.                                                                    |
| `alc_shapes_compat`  | **Recommended** | string | SemVer range (e.g. `">=0.25.0, <0.26"`) declaring the pkg's compatible `alc_shapes` versions. Validated by `alc_hub_gendoc` against the bundled `alc_shapes` (range mismatch → error; absent → warning). Required for **Bundled** pkgs.    |
| `tags`               | **Recommended** | table (string array) | Free-form classification tags (e.g. `{ "swarm", "primitive" }`). Indexed by `hub_index.json` and searchable via `alc_hub_search`. No enforced taxonomy; authors choose tags that help discovery. |

(Lint codes: `E_META_MISSING_{NAME,VERSION,DESCRIPTION,CATEGORY}`,
`W_META_LEGACY_M_VERSION` — see §5.)

#### Notes on `alc_shapes_compat`

`alc_shapes_compat` is the pkg's declaration of which `alc_shapes`
versions it has been verified against. The gendoc pipeline extracts
the literal `"..."` value from the `M.meta` table and validates it as
a SemVer range; an unparseable range fails the build and a missing
declaration emits a warning naming the current bundled `alc_shapes`
version. Bundled pkgs should track the SemVer caret of the alc_shapes
they ship against (e.g. `"^0.25"` while alc_shapes is on the 0.25.x
line).

### 2.2 `M.spec` — runtime contract

`M.spec.entries.{entry}.{input, result}` declares each entry's
runtime contract using the `alc_shapes` T DSL. This is the
**SSoT for `## Parameters` projections** (§3.4) and for
`alc.run(<pkg>, ctx)` runtime validation.

| Field                                | Status          | Type                            | Notes                                                                                                                              |
|--------------------------------------|-----------------|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------|
| `M.spec.entries.{entry}.input`       | **Recommended** | `T.shape(...)`                  | Each field MUST carry `:describe("...")`. The `:describe` text becomes the `description` column of the `## Parameters` projection. |
| `M.spec.entries.{entry}.result`      | **Recommended** | `T.shape(...)` or `T.ref(name)` | Consumed by `alc_hub_dist projections=["luacats"]` for IDE type stubs.                                                             |

A pkg without `M.spec` is treated as **opaque**: downstream
generators emit "no declared shape" sections. This is acceptable
for **Community** and **Private** patterns but is rejected by
`lint_strict=true` for **Bundled** pkgs.

> **Note on naming**: the Lua-source location is
> `M.spec.entries.{entry}.input`. The name `input_shape` appears
> in `alc_hub_dist`'s JSON projection output (the field key in the
> generated JSON), but is **not** the source location. Do not
> write `M.meta.input_shape`; that phrasing is stale and the
> linter does not recognise it.

(Lint codes for V1: `E_META_MISSING_INPUT_SHAPE` / `E_PARAM_MISSING_DESCRIBE` — see §5.)

### 2.3 `M.docs` — optional container

`M.docs` is preserved as a container for future schema markers.
The only recognised field is `schema_version`. **`M.docs.narrative`
is removed** — do not set it. The linter will warn on unknown
`M.docs` fields in a future release.

---

## 3. Docstring-driven narrative

`init.lua` is the single source of truth for narrative content. The
gendoc pipeline (`extract.lua split_sections` + `projections.lua
narrative_md`) renders the docstring H2 sections into Markdown on
demand. The output is the `narrative` projection (§0).

**Removed conventions** (do not use):

- `M.docs.narrative = "narrative.md"` — field is gone
- Separate `narrative.md` files — not recognised; will be ignored

### 3.1 How the resource is served

When a client requests `alc://packages/{name}/narrative`:

1. The engine locates the pkg's `init.lua` (variant scope first, then global scope).
2. A fresh mlua VM runs `extract.build_pkg_info` + `projections.narrative_md`.
3. The rendered Markdown is returned as `text/markdown`.

No cache — every request re-renders from the current `init.lua`.

### 3.2 Recommended H2 sections

The H2 sections below map onto the four Diátaxis documentation
classes. Write only the sections relevant to the pkg — a simple
wrapper may need only `## Usage`; a paper implementation typically
needs `## Algorithm` + `## Theoretical foundations` + `## References`.

| Section                               | Diátaxis class | When to write                                                                                                                            |
|---------------------------------------|----------------|------------------------------------------------------------------------------------------------------------------------------------------|
| `## Usage`                            | How-to         | Minimum working example. Write for almost every pkg.                                                                                     |
| `## When to use`                      | How-to         | When the pkg overlaps with siblings and the choice is non-obvious.                                                                       |
| `## Algorithm`                        | Explanation    | When the algorithm has 3+ named steps or a non-trivial invariant.                                                                        |
| `## Theoretical foundations`          | Explanation    | When correctness follows from a theorem or paper. State the theorem.                                                                     |
| `## Entry contract`                   | Reference      | When the pkg exposes multiple named entries.                                                                                             |
| `## Caveats`                          | Reference      | Pkg-wide rationale that does not fit a single parameter `:describe()` — known limitations, why certain knobs are hidden, edge cases.     |
| `## Empirical validation`             | Reference      | Bench data, sweep results, coverage observations.                                                                                        |
| `## Comparison with related packages` | Reference      | When a sibling pkg does something similar. One bullet per peer.                                                                          |
| `## References`                       | Reference      | Papers, arXiv IDs, books. Bullet list — see §4.4.                                                                                        |

`## Parameters` is **not** in the list above — it is generated from
`M.spec.entries.{entry}.input` (§2.2 / §4.3) and must not be
hand-written.

### 3.3 Canonical example

The reference docstring below demonstrates the required elements:

```lua
--- conformal_vote — split conformal prediction gate for multi-agent deliberation
---
--- Linear opinion pool + split conformal prediction post-hoc decision layer.
--- Emits a three-way decision (commit / escalate / anomaly) with a finite-sample
--- coverage guarantee `Pr[Y ∈ C(X)] ≥ 1-α` (Theorem 2). Calibration and online
--- rounds share aggregation weights so exchangeability is preserved.
---
--- ## Algorithm
---
--- Given N agents that each emit a verbalized probability distribution
--- π_i(y|x) over a fixed option set, the pkg performs:
---
--- ```math
--- P_social(y|x) = Σ_i w_i · π_i(y|x)        (linear opinion pool)
--- s_nc(x, y)    = 1 - P_social(y|x)          (nonconformity score)
--- q̂            = sorted[⌈(n+1)(1-α)⌉]        (finite-sample quantile, §4.3)
--- C(x)          = { y : P_social(y|x) ≥ 1 - q̂ }   (prediction set)
--- ```
---
--- ## Theoretical foundations
---
--- Theorem 2 guarantees `Pr[Y ∈ C(X)] ≥ 1-α` in finite samples whenever
--- calibration and online rounds share the same aggregation weights and
--- the data is exchangeable.
---
--- ## Entry contract
---
--- - `calibrate`   — pure, direct-args. returns `{ q_hat, tau, alpha, n, weights }`
--- - `aggregate`   — pure, direct-args. returns `{ [label] = p_social }`
--- - `predict_set` — pure, direct-args. returns `{ labels, top1, top1_prob, ... }`
--- - `decide`      — pure, direct-args. returns `{ action, selected }`
--- - `run`         — Strategy, ctx-threading. queries N agents via `alc.llm`
---
--- ## Comparison with related packages
---
--- Category: `validation` (alongside `sprt`, `eval_guard`, `inverse_u`).
---
--- ## References
---
--- Wang, Xie, Wang, Gao, Yang, Li, Qiu, Han, Qiu, Huang, Zhu, Woo (2026).
--- "From Debate to Decision: Conformal Social Choice for Safe Multi-Agent
--- Deliberation". arXiv:2604.07667.
```

---

## 4. Docstring style

### 4.1 1-line summary and abstract

Every docstring opens with a 1-line summary, followed by a 1–3 sentence abstract:

```lua
--- {PkgName} — {verb phrase}
---
--- {abstract: 1-3 sentences explaining the core capability}
---
--- ## {first H2 section}
```

**1-line summary** (line 1):

- One clause, ≤ 80 characters, of the form
  `{PkgName}({StyledName}) — {verb phrase}` when the pkg has a stylized
  name (typically a paper-cited abbreviation such as `CoT`, `UCB`,
  `MCTS`), or `{PkgName} — {verb phrase}` when the pkg directory name
  is already the canonical form
- `PkgName` is always the pkg directory name (lowercase, matches
  `M.meta.name`). `StyledName` is the conventional reading-aid form
  used in the literature; omit it when no such form exists.
- `` is the em dash (UTF-8 `U+2014`)
- Becomes the H1 title in the rendered narrative and the entry in `llms.txt`
- `M.meta.description` (§2.1) carries the same (or slightly expanded) wording for JSON consumers

Good:

```lua
--- conformal_vote — split conformal prediction gate for multi-agent deliberation
--- cot(CoT) — iterative chain-of-thought reasoning
--- ucb(UCB) — upper confidence bound multi-armed bandit
```

Too vague:

```lua
--- conformal_vote — a useful voting package
```

**Abstract** (lines after the blank `---` separator, until the first `## ` heading):

- 1 to 3 sentences
- Plain prose only — no headings, no lists, no code fences
- Explains the core capability at a glance; rationale and algorithm details belong in the H2 sections (§3.2)

If the pkg is trivial enough that no H2 sections follow, the abstract may stand alone — the rendered narrative will then consist of H1 + abstract only.

### 4.2 Markdown syntax

Within the docstring body, follow these Markdown rules. Concrete examples follow each rule.

**Headings**:

- `#` (H1) — **forbidden**. The generator synthesises H1 from the 1-line summary (§4.1).
- `##` is the highest permitted level
- `###` is allowed as a subsection within a `##` block
- `####` and lower — forbidden
- Each heading must be followed by a blank `---` line before body text:

```lua
--- ## Algorithm
---
--- 1. step
```

**Code fences**:

- Use **explicit** triple backticks (`` ``` ``). 4-space-indent fences are forbidden
- Language hint is recommended (`` ```lua `` for Lua, `` ```math `` for GitHub MathJax-rendered equations)
- One snippet per fence. Multiple snippets must use independent fences
- Inline code uses single backticks (`` ` ``)

```lua
--- ## Usage
---
--- ```lua
--- local pkg = require("pkg")
--- return pkg.run(ctx)
--- ```
```

**Lists**:

- Bullet: `-` (hyphen) only. `*` and `+` are forbidden
- Numbered: `1.` / `2.` / `3.` style
- Letter-numbering (`a.` / `b.`) is renderer-dependent and forbidden
- Indentation: 2 spaces for sub-bullets under `-`, 3 spaces for sub-bullets under numbered lists
- Maximum nesting depth: 2 levels. 3+ levels of nesting are forbidden — renderer-dependent

**Links**:

- GitHub-style markdown links only: `[text](url)`
- Bare URLs are forbidden in body text; they are permitted **only** inside `## References` citations (§4.4)

```lua
--- See [the README](../README.md) for derivation.
```

**Encoding**:

- UTF-8 only
- em dash `` (`U+2014`) and en dash `` (`U+2013`) are allowed
- All docstrings are written in English. The rendered narrative and `llms.txt` are public artifacts; non-English docstrings break readability for downstream consumers.

### 4.3 Parameters — generated from `M.spec`

The `## Parameters` section in the rendered narrative is **machine-generated** from `M.spec.entries.{entry}.input` (§2.2). Authors do not write `## Parameters` in the docstring.

The generator emits one row per shape field, using:

- field name as `key`
- shape type as `type`
- `:is_optional()` as `required` (true / false)
- `:describe("...")` text as `description`

**`:describe()` requirements**:

Every shape field MUST carry `:describe("...")`. The describe text is the only source for the `description` column.

```lua
M.spec = {
    entries = {
        run = {
            input = T.shape({
                task  = T.string:describe("The question or task to reason about"),
                depth = T.number:is_optional():describe("Number of reasoning steps (default: 3)"),
            }),
        },
    },
}
```

In **Bundled** mode (`lint_strict=true`), missing `:describe()` is a hard error. In **Community** mode, missing `:describe()` is a warning (lint code `E_PARAM_MISSING_DESCRIBE` — see §5).

**Where to put the rationale** (two-tier rule):

| Scope of rationale                                                                                              | Where to write                                                                                                                              |
|-----------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| Per-parameter semantic rationale (e.g. *why* a numeric default was chosen, when truncation breaks invariants)   | Inside the parameter's `:describe("...")` text. The text may be long; the projection emits it verbatim into the `## Parameters` table.      |
| Pkg-wide rationale (e.g. *why* a token budget knob is hidden, why certain options are intentionally not exposed) | `## Caveats` H2 section (§3.2)                                                                                                              |

This separation ensures (a) parameter-specific rationale survives every projection (`## Parameters` table, `context7.json`, `llms-full.txt`, LuaCATS stubs), and (b) pkg-wide design rationale lives where readers look for caveats.

**Hand-written `## Parameters` is forbidden**:

Writing `## Parameters` in the docstring while `M.spec.entries.{entry}.input` is also declared raises lint error `E_PARAMETERS_CONFLICT`. The two are mutually exclusive: `M.spec` is the SSoT.

For pkgs without `M.spec` (opaque pkgs — Community / Private), the generator emits no `## Parameters` section. Authors do not need to write one.

### 4.4 References

The `## References` H2 section uses a flat bullet list. Do not wrap citations in code fences.

- Each citation is a single bullet starting with `-`
- Continuation lines indent by 2 spaces
- Bare URLs are permitted **only** inside this section (e.g. arXiv links, paper DOIs)

```lua
--- ## References
---
--- - Friedman, M. (1937). "The use of ranks to avoid the assumption of
---   normality ...," J. Am. Stat. Assoc. 32(200): 675–701.
--- - Wang, X. et al. (2026). "From Debate to Decision: Conformal Social
---   Choice for Safe Multi-Agent Deliberation". arXiv:2604.07667.
```

Inline citations in body text reference the bullet by surname or arXiv ID — no inline URL.

### 4.5 LuaCATS annotations

LuaCATS annotations (`---@type`, `---@param`, `---@return`, etc.) appear **after** the narrative docstring body. The generator stops narrative extraction at the first `---@` line.

```lua
--- cot(CoT) — iterative chain-of-thought reasoning
---
--- Builds a reasoning chain step by step, then synthesizes the chain
--- into a single coherent conclusion.
---
--- ## Usage
---
--- ```lua
--- local cot = require("cot")
--- return cot.run({ task = "Why is the sky blue?", depth = 3 })
--- ```

local S = require("alc_shapes")
local T = S.T

local M = {}

---@type AlcMeta
M.meta = {
    name        = "cot",
    version     = "0.1.0",
    description = "Iterative chain-of-thought — cumulative reasoning steps, then synthesis",
    category    = "reasoning",
}

---@type AlcSpec
M.spec = {
    entries = {
        run = {
            input = T.shape({
                task  = T.string:describe("The question or task to reason about"),
                depth = T.number:is_optional():describe("Number of reasoning steps (default: 3)"),
            }),
            result = T.shape({
                chain      = T.array_of(T.string):describe("Ordered insights, one per reasoning step"),
                conclusion = T.string:describe("Synthesized final answer"),
            }),
        },
    },
}

---@param ctx AlcCtx
---@return AlcCtx
function M.run(ctx) ... end

return M
```

Place them last so the narrative reads as a single coherent block when stripped of annotations. LuaCATS is consumed by `alc_hub_dist projections=["luacats"]` to generate IDE type stubs (§0).

### 4.6 Disallowed constructs (collected)

The constructs below are forbidden in any docstring. Each is also covered in the relevant subsection above; this table consolidates them with the corresponding lint code (§5).

| NG                                            | Reason                                                            | Lint code                  |
|-----------------------------------------------|-------------------------------------------------------------------|----------------------------|
| `#` (H1) heading                              | Generator synthesises H1 from the 1-line summary (§4.1)           | `E_H1_IN_DOCSTRING`        |
| `$...$` / `$$...$$` inline LaTeX              | Renders only on GitHub; breaks elsewhere. Use `` ```math `` fence | (no lint, manual review)   |
| 4-space-indent code fence                     | Use explicit `` ``` `` only                                       | (no lint, manual review)   |
| HTML tag (`<br>`, `<sub>`, etc.)              | Markdown only                                                     | (no lint, manual review)   |
| Emoji                                         | Breaks llms.txt and CRAN-style consumers                          | (no lint, manual review)   |
| 3+ levels of list nesting                     | Renderer-dependent                                                | (no lint, manual review)   |
| Hand-written `## Parameters` heading          | `M.spec.entries.{entry}.input` is the SSoT (§4.3)                 | `E_PARAMETERS_CONFLICT`    |

---

## 5. Lint rules

`alc_hub_gendoc` runs the lint pipeline and emits the codes below. `lint_strict=true` (Bundled / CI gate, §1) treats every `error` severity as a build failure; `lint_strict=false` (default) surfaces them as non-blocking diagnostics.

| Code                         | Severity        | Status       | Description                                                                                |
|------------------------------|-----------------|--------------|--------------------------------------------------------------------------------------------|
| `E_META_MISSING_NAME`        | error           | active       | `M.meta.name` missing                                                                      |
| `E_META_MISSING_VERSION`     | error           | active       | `M.meta.version` missing                                                                   |
| `E_META_MISSING_DESCRIPTION` | error           | active       | `M.meta.description` missing                                                               |
| `E_META_MISSING_CATEGORY`    | error           | active       | `M.meta.category` missing                                                                  |
| `E_NAME_MISMATCH`            | error           | active       | `M.meta.name` ≠ pkg directory name                                                         |
| `E_H1_IN_DOCSTRING`          | error           | active       | `#` heading present in docstring                                                           |
| `E_PARAMETERS_CONFLICT`      | error           | active       | `M.spec.entries.{entry}.input` declared and hand-written `## Parameters` both present      |
| `E_RESULT_CONFLICT`          | error           | active       | `M.spec.entries.{entry}.result` declared and hand-written `## Result` both present         |
| `E_META_MISSING_INPUT_SHAPE` | warning / error | planned (V1) | `M.spec.entries.{entry}.input` missing. `warning` in default mode, `error` under `lint_strict=true`. |
| `E_PARAM_MISSING_DESCRIBE`   | warning / error | planned (V1) | Shape field without `:describe(...)`. `warning` in default mode, `error` under `lint_strict=true`.   |
| `W_DESCRIPTION_MULTILINE`    | warning         | active       | `M.meta.description` contains a newline                                                    |
| `W_FAKE_LABEL`               | warning         | active       | `Usage:` / `Args:` style label — promote to `## Usage` etc.                                |
| `W_EMPTY_NARRATIVE`          | warning         | active       | No abstract and no H2 sections                                                             |
| `W_META_LEGACY_M_VERSION`    | warning         | active       | `M.VERSION` top-level field detected. Canonical form uses `M.meta.version` only (§2.1). Safe to remove if no external reference. |

**Severity convention** (per `lint.lua`):

- `error``lint_strict=true` rejects the pkg; `lint_strict=false` reports non-blocking
- `warning` — never blocks the build, surfaces in tooling diagnostics
- Planned rules with split severity emit `warning` in default mode and **promote to `error`** under `lint_strict=true`

Active rules are implemented in `crates/algocline-app/src/service/lua/gendoc/docs/lint.lua`. Planned rules are not yet implemented.

---

## 6. Migration

### 6.1 Migration from `M.docs.narrative` / `narrative.md`

If an existing pkg uses the old (pre-narrative-decommission) convention:

1. Move narrative content into the `---` docstring block as H2 sections.
2. Remove `M.docs.narrative` from the `M.docs` table (or drop `M.docs` entirely if `schema_version` is also absent).
3. Delete the standalone `narrative.md` file.
4. Run `alc_hub_dist` with `projections=["narrative"]` to regenerate `docs/narrative/{name}.md`.
5. Verify `alc://packages/{name}/narrative` returns the expected Markdown.

### 6.2 Migration to V1 conventions

For pkgs predating the V1 conventions in this document:

1. **Move parameters into `M.spec`**: if the pkg declared `M.meta.input_shape` (a stale phrasing) or had a hand-written `## Parameters` H2, move the shape definition into `M.spec.entries.{entry}.input` (§2.2). Delete the `## Parameters` H2.
2. **Add `:describe()` to every shape field**: each field in `input` and `result` must carry a `:describe("...")` clause. Fields without describe text become empty rows in the projected `## Parameters` table.
3. **Move pkg-wide rationale to `## Caveats`**: prose explaining *why* certain knobs are hidden, why a token budget is fixed, etc., goes into the `## Caveats` H2 (§3.2). Per-parameter rationale stays inside `:describe()` (§4.3).
4. **Run lint**: `alc_hub_gendoc lint_strict=false` first to see warnings, then `lint_strict=true` if the pkg targets the Bundled distribution (§1).
5. **Regenerate projections**: `alc_hub_dist` to refresh `docs/narrative/{name}.md` and downstream artifacts (§0).

## 7. 1-pkg authors: publishing a single package to Hub

If your repository contains exactly one algocline package, follow these steps
to make it discoverable via `alc_hub_search`.

### Layout requirement

Place your package at `<repo>/<pkg_name>/init.lua` (nested), **not** at the
repository root. Example:

```
my-cool-pkg/
├── my_cool_pkg/
│   └── init.lua       # M.meta, M.spec, M.run
├── alc.toml
└── hub_index.json     # generated by `alc_hub_dist`
```

### Minimal `alc.toml`

```toml
[hub]
# Default values are sufficient for a single-package repo. Optional sections
# [hub.context7] and [hub.devin] customize projection targets — see
# docs/hub-gendoc-config.md.
```

### Publishing

From a Claude Code / rmcp MCP session in your repo root:

```
alc_hub_dist(
  source_dir = ".",
  output_path = "hub_index.json",
  out_dir = "docs",
  projections = ["hub", "narrative"],
  lint_strict = false
)
```

Then commit and push:

```sh
git add hub_index.json docs/
git commit -m "publish: regenerate hub_index"
git push
```

Consumers can now install via `alc_pkg_install({ url: "github.com/you/my-cool-pkg" })`
and your package will appear in `alc_hub_search` results.

---

## 8. Testing

algocline packages should ship tests under `<pkg>/spec/<file>_spec.lua`. Run
them via `mcp__algocline__alc_pkg_test`.

### Spec file layout

Place spec files at `<pkg_root>/spec/<name>_spec.lua`. Each file is a
self-contained lspec suite. The `lust` global (`describe`, `it`, `expect`,
`spy`, etc.) is pre-loaded automatically — no `require` needed.

```lua
-- <pkg_root>/spec/myfeature_spec.lua

local describe, it, expect = lust.describe, lust.it, lust.expect

describe('myfeature', function()
    it('does X correctly', function()
        local result = require('mypkg').do_x()
        expect(result).to.equal('expected_value')
    end)
end)
```

### Running tests

- `alc_pkg_test pkg="mypkg"` — run all `<pkg_root>/spec/*_spec.lua`
- `alc_pkg_test pkg="mypkg" filter="feature"` — run only specs whose stem
  contains `"feature"` (e.g. `feature_spec.lua`)
- `alc_pkg_test pkg="mypkg" spec_dir="tests"` — use a custom spec directory
- `alc_pkg_test code_file="<abs_path>"` — run a single file (escape hatch;
  use absolute paths in worktree environments)
- `alc_pkg_test code="<inline lua>"` — ad-hoc inline test

### Output shape

```json
{
  "passed": 3,
  "failed": 0,
  "pending": 0,
  "total": 3,
  "duration_ms": 42,
  "spec_files": [
    {
      "path": "/path/to/myfeature_spec.lua",
      "passed": 3,
      "failed": 0,
      "total": 3,
      "duration_ms": 40,
      "tests": [
        { "suite": "myfeature", "name": "does X correctly",
          "passed": true, "pending": false, "error": null }
      ]
    }
  ]
}
```

Per-spec-file Lua crashes increment `failed` and continue (execution is not
aborted). Setup failures (package not found, zero spec files) are returned as
a typed error on the MCP wire.

### Migration from `tests/test_<pkg>.lua`

Existing bundled-packages tests use a flat `tests/test_<pkg>.lua` layout and
continue to work via `mcp__lua-debugger__test_launch`. New packages should
adopt the `<pkg>/spec/<file>_spec.lua` layout and use `alc_pkg_test`.

## 9. Env

Bundled / third-party pkgs MUST NOT read OS env / API keys / dotenv files
directly inside `init.lua`. Host-platform integration (the caller orch
entry / Main AI) pre-resolves env into `ctx.env`, and pkg code declares
the variables it actually consumes via `alc.env:use{...}` at the point of
use.

| Rule                       | What                                                                                                                |
|----------------------------|---------------------------------------------------------------------------------------------------------------------|
| Forbidden inside a pkg     | `os.getenv`, `std.env.get`, hand-rolled dotenv parsing, ad-hoc `API_KEY` / `BASE_URL` lookups                        |
| Recommended inside a pkg   | `local env = alc.env:use{ "KEY1", "KEY2" }` then `env.KEY1` to read                                                 |
| Caller-side responsibility | Pass sources at run time: `alc_run(code, ctx = { env = { dotenv = ".env", allow_os = true } })`                     |
| Reference integration      | `coding_orch` Phase 2 migration (agent-profiles issue `1778976345-92995`) replaces `resolve_*_env` helpers with `alc.env:use` |

### Example (Phase 2 reference)

```lua
-- inside the pkg (post-Phase 2)
local env = alc.env:use{ "QWEN_BASE_URL", "QWEN_API_KEY", "QWEN_MODEL" }
local base_url = env.QWEN_BASE_URL  -- nil if absent
if base_url == nil then
    return error("NEEDS_CONTEXT: QWEN_BASE_URL")
end
```

### Exception: test path resolution

mlua-probe sandbox test path resolution such as `os.getenv("PWD") or "."`
is out of scope for `alc.env` and not subject to this rule — it is a
Lua VM test-runtime constraint, not an application-level env access.

### Why pkg-internal env access is rejected

- Pkgs are portable units; reading env inside an `init.lua` couples the
  pkg to a specific host's secret-loading convention.
- `alc.env:use` makes the required vars **declarative** at the point of
  use, which lets `coding_orch` / future hosts pre-validate and surface
  a single `NEEDS_CONTEXT: <KEY>` error to the caller instead of failing
  deep inside pkg code.
- Audit and caching live in the host (`ctx.env`), not scattered across
  pkgs. A sweep of `algocline-bundled-packages` v0.24.0 (120 pkgs)
  confirms zero pkg-internal env access today; this section codifies the
  existing discipline so future pkgs do not regress.

---

## 10. Cards quick reference (`alc_card_find` DSL)

`alc_card_find` filters Cards using a Prisma-style `where` predicate plus
`order_by`/`limit`/`offset`/`pkg`. Use it to surface eval results, lineage
records, or any other Card type produced by strategies.

### Common patterns

```jsonc
// Top 10 cards by pass_rate for a single pkg
{
  "pkg": "cot",
  "where": { "stats": { "pass_rate": { "gte": 0.8 } } },
  "order_by": "-stats.pass_rate",
  "limit": 10
}

// AND / OR / NOT
{
  "where": {
    "_and": [
      { "model": { "id": "claude-sonnet-4-6" } },
      { "_or": [
          { "tags": { "contains": "bench" } },
          { "category": { "in": ["reasoning", "synthesis"] } }
      ] }
    ]
  }
}

// Existence + dotted path sort
{
  "where": { "stats": { "pass_count": { "exists": true } } },
  "order_by": ["-created_at"]
}
```

### Predicate cheatsheet

| Form | Meaning |
|---|---|
| `{ "field": "value" }` | shorthand for `eq` |
| `{ "field": { "eq": x } }` | equality |
| `{ "field": { "ne": x } }` | inequality |
| `{ "field": { "lt": x } / "lte" / "gt" / "gte" }` | numeric / lexical compare |
| `{ "field": { "in": [a,b] } / "nin": [...] }` | membership |
| `{ "field": { "exists": true } }` | field present (any value) |
| `{ "field": { "contains": "sub" } }` | substring match (strings) |
| `{ "field": { "starts_with": "pre" } }` | prefix match |
| Nested object | section path (e.g. `stats.pass_rate`) |
| `_and` / `_or` / `_not` | logical combinators |

`order_by` accepts a single dotted-path string or an array; `-` prefix is
descending. `pkg` narrows the filesystem scan to one package — pass it
when you know the target. Default sort: `created_at` descending.

### Wiring tips

- Card schemas are pkg-defined. Inspect `mcp__algocline__alc_card_list`
  / `alc_card_samples` first to discover available fields per pkg.
- `where` paths follow Card JSON exactly: nested sections are nested
  objects, not flattened dotted strings.
- `limit` defaults are server-side; pass it explicitly for stable paging
  with `offset`.

## 11. Pre-publish verification workflow

Before pushing a package to Hub, run the local verification chain so
remote consumers receive a known-good artifact. The chain is built from
existing read-only MCP tools — no new tooling is required.

### Pre-push checklist

Run these MCP calls in order against the package source directory.
Each step is read-only except `alc_hub_dist` (writes `hub_index.json`).

1. **`alc_pkg_test`** — run the package's `spec/*_spec.lua` suite.
   ```jsonc
   { "pkg": "<pkg_name>" }
   ```
   Verify `failed == 0` in the returned JSON. See §8 Testing for spec
   layout.

2. **`alc_hub_dist`** — regenerate the local `hub_index.json` and Hub
   docs from the current source tree.
   ```jsonc
   {
     "source_dir": "/abs/path/to/source",
     "output_path": "/abs/path/to/source/hub_index.json"
   }
   ```
   Confirm `reindex.package_count` matches the number of packages you
   expect under `source_dir`. A drop to `0` typically means `M.meta.name`
   is missing in `init.lua` — see `alc_pkg_doctor`'s `missing_meta`
   verdict.

3. **`alc_pkg_doctor`** — inspect every installed package for known
   defect patterns.
   ```jsonc
   {}   // omit `name` to scan all packages
   ```
   For a release-grade run, **all of these arrays must be empty**:
   - `incomplete_pkg` (missing `require()`-ed submodule files)
   - `installed_missing` (registered pkg but install dir gone)
   - `symlink_dangling` (dead `alc_pkg_link` target)
   - `path_missing` (`alc.toml` `path = ...` resolves nowhere)
   - `missing_meta` (`init.lua` without `M.meta.name`)
   - `missing_hub_index` (collection root with 2+ pkgs but no index)
   - `spec_missing` (declared `spec/` but zero `*_spec.lua` files)

   The `stale_cache` array is informational — re-run `alc_hub_search`
   to refresh. `healthy` always contains the rest.

4. **`alc_hub_search` with `local_indices`** — verify the freshly
   regenerated `hub_index.json` is parseable and lists every expected
   package, before any remote push.
   ```jsonc
   {
     "local_indices": ["/abs/path/to/source/hub_index.json"],
     "verbose": "full"
   }
   ```
   The returned `results` array includes both remote-fetched packages
   and the local-only entries. Inspect `name` to confirm every package
   authored in this push is present. Combined with `installed_only:
   false` (default), this surfaces the exact set that remote consumers
   will see after the push lands.

### Local-only verification

For air-gapped or pre-release inspection, drop step 4's remote fetch
entirely by also passing an offline `filter`:

```jsonc
{
  "local_indices": ["/abs/path/to/source/hub_index.json"],
  "filter": { "installed": false },
  "limit": 0
}
```

`limit: 0` means "no limit" (return all entries — empty-means-all
idiom). Useful when CI does not have network access.

### When the chain passes

If steps 1–4 all return clean results, the source tree is consistent
with what remote consumers will fetch after push. Typical push action
is project-defined (release tag, `git push`, registry publish) and is
outside the MCP tool surface.

### When a step fails

| Failure | Most likely cause | Fix |
|---|---|---|
| `alc_pkg_test` `failed > 0` | spec assertion or runtime error | inspect `spec_files[].tests[].error` |
| `alc_hub_dist` `reindex.package_count == 0` | every `init.lua` lacks `M.meta.name` | add `M.meta = { name = "...", version = "..." }` |
| `alc_pkg_doctor` `incomplete_pkg` non-empty | `require("pkg.sub")` references a missing file | add the sub file or remove the `require` |
| `alc_pkg_doctor` `missing_meta` non-empty | `init.lua` parsed but no `M.meta.name` | declare `M.meta` block; see §2.1 |
| `alc_pkg_doctor` `missing_hub_index` non-empty | collection root has 2+ pkg dirs but no index | run step 2 (`alc_hub_dist`) to generate it |
| `alc_pkg_doctor` `spec_missing` non-empty | `spec/` exists but no `*_spec.lua` files | add a `*_spec.lua` file or delete the `spec/` dir |
| `alc_hub_search` does not list a package | the package's `init.lua` was skipped during reindex (no `M.meta.name`) | re-run step 2 after fixing `M.meta` |

The checklist is intentionally tool-only (no shell wrapper). If you need
a single one-shot call site, an `alc_pkg_prepublish_check` combo tool is
tracked as a future convenience; the four-step manual chain remains the
canonical path.

---

## Bundled Hub Sources (Collection-Only Install)

algocline ships with multiple bundled Hub Collection sources, listed in
`src/init.rs::BUNDLED_SOURCES`. These are auto-installed via `alc init` /
`alc update` as a single batch. Each source is a Collection repository
(`<repo>/<pkg-name>/init.lua` layout) and must publish a `hub_index.json`
at the repository root.

**Canonical: collection-unit install.** All bundled sources are designed to
coexist when installed together. Cross-package `require()` chains within a
Collection (e.g., `swarm_frame_algocline` requires `swarm_frame` at the
top level) assume that the entire Collection batch has been installed.
Individual cherry-pick install via `alc_pkg_install` for only a subset of
a Collection may fail at runtime due to unresolved `require()` chains.
algocline does not currently maintain a dependency resolver across packages.

**Discouraged: individual cherry-pick install.** Avoid installing only a
subset of a Collection with `mcp__algocline__alc_pkg_install`. If a
package has cross-package `require()` dependencies within its Collection,
those dependencies will be missing and the package will error at load time.

If you need to remove a specific bundled package (`alc_pkg_remove <name>`),
be aware that other packages in the same Collection may have a runtime
`require()` to it; the registry will not warn you. Re-run `alc update
--force` to restore the full Collection to the pinned bundled version.

The full list of bundled sources and their pinned tags is in
`src/init.rs::BUNDLED_SOURCES`.

**LLM-derived metrics formatting.** Use `alc.fmt` / `alc.log_fmt` instead of raw
`string.format` when interpolating numeric values that may originate from an LLM
(float, NaN/Inf, or string-shaped numbers). The native `string.format("%d", 1.5)`
truncates toward zero and `string.format("%d", 0/0)` raises; `alc.fmt` rounds
half-away-from-zero and substitutes safe string literals.

**Authoring packages that depend on bundled substrate.** When a package
design requires state hand-off, flow control, or frame orchestration, check
whether the bundled substrate already provides the primitive before proposing
a new abstraction. The canonical substrate list is in
`plugins/alc/skills/alc-wake/SKILL.md §Swarm framework` (packages: `flow`,
`swarm_frame`, `swarm_frame_algocline`, `plugin_run_card`, `alc.state`).
During design consultation, `@alc-adviser` cross-references these primitives
and pairs every gap finding with a literal primitive path (e.g.,
`flow.state_save`, `swarm_frame.frame.register`) or the explicit phrase
`no primitive applies`. See `plugins/alc/agents/alc-adviser.md §Substrate Cross-Check`
(step 3b) for the full procedure.