algocline-engine 0.41.1

algocline Lua execution engine — VM, session, bridge
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
# algocline

[![CI](https://github.com/ynishi/algocline/actions/workflows/ci.yml/badge.svg)](https://github.com/ynishi/algocline/actions/workflows/ci.yml)

**Research-grade reasoning for your LLM — as Pure Lua you can read, edit, and ship.**

UCB1 exploration, self-reflection, multi-agent debate, chain-of-verification — each strategy is a single Lua file. Install with `cargo install`, customize anything, no framework lock-in.

## What it does

LLMs are single-shot by default. Ask a question, get one answer, hope it's right. Research papers describe techniques that do better — iterating, scoring, selecting — but using them today means Python, framework lock-in, and API key management.

algocline makes these techniques **immediately usable**. Each algorithm is a Pure Lua file (100-350 lines) that runs inside your existing MCP host. No infrastructure. No setup beyond `alc init`.

```
Human ──→ LLM (MCP host) ──→ algocline ──→ Algorithm (Lua) ──→ alc.llm() ──→ back to LLM
                                                                    ↑              │
                                                                    └──────────────┘
                                                                   (loop until done)
```

**Use** existing algorithms with one call. **Build** your own by writing Lua. **Share** them via Git.

## When to use

| What you want to do | What happens | Strategy |
|---|---|---|
| Catch what your code review missed | Draft → self-critique → revise. Found that `std::fs::write` is non-atomic (crash = data loss) after the first draft said "no issues" | `reflect` |
| Make design decisions structurally, not by gut | Advocate, critic, and pragmatist debate. Resolved "do we need log rotation?" → "no, but add a display limit" in 4 rounds | `panel` |
| Fact-check LLM claims before trusting them | Auto-generates verification questions → checks each one. Escalated a path traversal from medium to high severity after confirming `PathBuf::join()` does zero validation | `cove` |
| Break down a complex problem step by step | Builds reasoning chain incrementally. Structured Vec vs HashMap trade-offs into cache locality → memory overhead → API ergonomics | `cot` |
| Pick the best option from multiple candidates | Scores each candidate on your criteria, pairwise comparison | `rank` |
| Get a reliable answer, not a lucky one | Generates N answers → majority vote picks the most consistent one | `sc` |

## Why algocline

| Approach | Limitation |
|---|---|
| Prompt engineering | Single-shot. No iteration, no scoring, no selection |
| DSPy / LangGraph | Python infra. Pip install. API keys. Framework lock-in |
| **algocline** | Zero infra. Pure Lua. Runs inside your existing MCP host. Use research-grade algorithms today, or write your own |

## Quick start

### 1. Install

```bash
cargo install algocline
```

### 2. Initialize packages

```bash
alc init
```

This downloads the bundled package collection (UCB1, chain-of-thought, self-consistency, etc.) into `~/.algocline/packages/`. Run `alc init --force` to overwrite existing packages.

It also distributes `alc.d.lua` — LuaCats type definitions for all `alc.*` StdLib functions — to `~/.algocline/types/alc.d.lua`. This enables editor completion in any editor backed by [lua-language-server](https://github.com/LuaLS/lua-language-server). If `.luarc.json` is not present in the current directory, a setup tip is printed.

> **Note**: If you skip this step, packages are auto-installed on first `alc_advice` call via MCP. But running `alc init` upfront is recommended for faster first use and offline availability.

### 3. Add to your MCP config

By default, `alc` runs as an MCP stdio server — it is designed to be launched by an MCP client
such as Claude Code, not invoked directly from a shell. For one-shot maintenance tasks, use the
`alc init` and `alc update` subcommands. For ad-hoc shell access to algocline MCP tools, set up
an agent-block harness that starts `alc` as a child process and calls the MCP server directly;
running plain `alc` from a terminal will start the server in the foreground waiting for an MCP
client connection. Run `alc --help` for a summary of available subcommands.

Add algocline as an MCP server in your host's configuration (e.g. Claude Code's `~/.claude.json`, Cursor's MCP settings, etc.):

```json
{
  "mcpServers": {
    "algocline": {
      "command": "alc"
    }
  }
}
```

Add an `env` object only when you need to set one of the environment
variables documented below.

After adding the config, restart your MCP host session so it picks up the new server.

#### Environment variables

| Variable | Description | Default |
|---|---|---|
| `ALC_LOG_DIR` | Directory for session transcript logs | `~/.algocline/logs` |
| `ALC_LOG_LEVEL` | `full` (enable logging) or `off` (disable) | `full` |
| `ALC_PACKAGES_PATH` | Additional package search paths (colon-separated). Takes priority over `~/.algocline/packages/` | (none) |
| `ALC_PROJECT_ROOT` | Project root directory for project-local package resolution. When omitted, auto-detected by walking up from cwd to find `alc.toml` | (auto-detect) |
| `ALC_POOL_STATE_DIR` | Directory for pool registry state (`registry.json`). Overrides the default `~/.algocline/state/pool/` | `~/.algocline/state/pool` |
| `ALC_POOL_IDLE_TIMEOUT` | Idle timeout in seconds for pool worker subprocesses. Set to `0` to disable. Only relevant when using `host_mode: true` | `1800` |
| `ALC_CARD_SINKS` | Card subscriber backends (mirror destinations) as a `\|`-separated URI list. v1 only accepts `file:///absolute/path`. Duplicate URIs are first-wins; malformed entries are logged and skipped. | (none) |

Example: writing logs to a custom directory:

```json
{
  "mcpServers": {
    "algocline": {
      "command": "alc",
      "env": {
        "ALC_LOG_DIR": "/path/to/custom/logs"
      }
    }
  }
}
```

### Optional: Install as a Claude Code plugin

If you use [Claude Code](https://claude.ai/code), you can install algocline together with a curated set of development tools as a single plugin instead of editing `~/.claude.json` by hand:

```
/plugin marketplace add ynishi/algocline
/plugin install alc@algocline
```

The plugin bundles:

- `algocline` and `git-reader` MCP server entries (no manual `mcp.json` edit needed),
- the `/alc-wake` and `/alc-build` skills,
- the `@alc-adviser` / `@alc-coder` / `@alc-refiner` agents for algocline package development.

See [`plugins/alc/README.md`](plugins/alc/README.md) for details.

### 4. Use

Call algocline tools from your MCP host. The host LLM calls these tools on your behalf:

One-liner with an installed package:

```
alc_advice({ strategy: "ucb", task: "Design a rate limiter for a REST API" })
```

Or write your own Lua:

```lua
-- alc_run({ code: "..." })
local draft = alc.llm("Draft a solution for: " .. ctx.task)
local critique = alc.llm("Find flaws in:\n" .. draft)
local final = alc.llm("Revise based on critique:\n" .. draft .. "\n\nCritique:\n" .. critique)
return { result = final }
```

To pass environment variables to the Lua VM, use `ctx.env`:

```
alc_run({
  code: "return { api_url = alc.env.API_URL }",
  ctx: {
    env: {
      inject: { "API_URL": "https://example.com" }
    }
  }
})
```

`ctx.env` supports three sources merged in priority order (`inject > dotenv > os.env`):
- `inject` — key/value map supplied inline (highest priority)
- `dotenv` — path to a `.env` file relative to the project root
- `allow_os: true` — expose the server's OS environment (opt-in, lowest priority)

An optional `alc.toml [env.allow]` allowlist filters which keys reach the Lua VM. Writes to `alc.env` always raise a runtime error — the snapshot is immutable for the lifetime of the run.

## Ecosystem

algocline is a single binary, but the strategies and tools around it form a distributed ecosystem of Git-hosted package collections.

### Repository structure

```
algocline                         — Engine (Rust binary, MCP server)
├── algocline-bundled-packages    — 15 core strategies (cot, reflect, ucb, panel, …)
├── algocline-swarm-frame         — Multi-agent orchestration (swarm_frame + plugins)
├── evalframe                     — Evaluation framework (graders, scenarios, Cards)
└── alc plugin                    — Claude Code skills + agents for pkg development
```

Each collection is an independent Git repo with a `hub_index.json` catalog. `alc init` installs the bundled collections; third-party collections install the same way via `alc_pkg_install`.

### Hub: decentralized package discovery

There is no central registry. Each collection repo ships a `hub_index.json` that describes its packages. `alc_hub_search` queries across all cached indices.

```
alc_hub_search({ query: "reasoning" })   → matches from all registered sources
alc_hub_info({ name: "reflect" })         → metadata, Cards, aliases, stats
```

### Author workflow

Write a strategy, test it locally, publish it for anyone to install:

```
Develop:    alc_pkg_scaffold → write init.lua → alc_pkg_link → alc_pkg_test → iterate
Distribute: alc_hub_reindex → alc_hub_dist → git push
Consume:    alc_hub_search → alc_pkg_install({ url: "github.com/you/repo" }) → alc_advice
```

During development, `alc_pkg_link` symlinks a local directory as a package — no publishing needed to iterate. When ready, push to Git and anyone can install with one command.

`alc_hub_dist` generates documentation in multiple projections from a single source:

| Projection | Output |
|---|---|
| `hub` | Package catalog page |
| `context7` | Context7-compatible doc |
| `devin` | Devin-compatible doc |
| `luacats` | LuaCats type definitions |
| `narrative` | Human-readable narrative |
| `llms` | LLM-optimized reference |
| `lint` | Lint rule definitions |

The `/alc-build` skill and `@alc-coder` agent can scaffold, implement, and test packages end-to-end — strategy authoring works from natural language to a published collection.

## Configuration

algocline reads configuration from layered TOML files plus environment overrides.

### Files

| Layer | Path | Notes |
|-------|------|-------|
| User-global | `~/.algocline/config.toml` (override with `ALC_HOME`) | Created on first `alc init` with a commented template. |
| Project | `<project>/alc.toml` | Shared (git-tracked). |
| Project (local) | `<project>/alc.local.toml` | Worktree-scoped, git-ignored. Overrides `alc.toml`. |

### `[setting.<target>]` tables

A generic per-target configuration table. Each `<target>` is a snake_case name
(for example `journal`, `advisor`). Field names and types are caller-defined;
algocline core does not impose a schema.

```toml
[setting.journal]
path = "/Users/me/journal.md"
pkg  = false
```

### Resolution order

For each field, the highest-priority layer that defines it wins. Lower layers
are not discarded — fields they uniquely define are still surfaced.

1. Environment variable `ALC_SETTING_<TARGET>_<FIELD>` (uppercase snake)
2. Project (`alc.local.toml` → `alc.toml`)
3. User-global (`~/.algocline/config.toml`)
4. Missing — field is absent from the response; the caller decides.

### `alc_setting_resolve` MCP tool

```jsonc
// Tool call
{ "name": "alc_setting_resolve", "arguments": { "target": "journal" } }

// Response (JSON string)
{
  "resolved": { "journal": { "path": "/Users/me/journal.md", "pkg": true } },
  "sources":  { "journal": { "path": "env", "pkg": "project" } }
}
```

Omit `target` to receive all configured targets in a single call.

## Architecture

### Three-Layer StdLib

```
Layer 0: Runtime Primitives (Rust → alc.*)
│  alc.llm(prompt, opts?)        — Host LLM call via MCP Sampling
│  alc.llm_batch(items)          — parallel LLM calls (single round-trip)
│  alc.fork(strategies, ctx, o?) — parallel multi-VM strategy execution
│  alc.json_encode/json_decode   — serde_json bridge
│  alc.log(level, msg)           — tracing bridge
│  alc.state.get/set/keys/delete — persistent key-value store (legacy single-namespace API)
│  alc.state.list(ns)           — list keys under dispatched layout {state_root}/{ns}/*.json
│  alc.state.show(ns, key)      — read full JSON content; typed error when key is absent
│  alc.state.reset(ns, key, o?) — atomically mutate state file (.bak + tempfile + rename)
│  alc.match_enum(text, cs, o?)  — fuzzy enum match from LLM output
│  alc.match_bool(text)          — yes/no normalizer for LLM output
│  alc.budget_remaining()        — remaining budget (calls/time)
│  alc.progress(step, total, m?) — structured progress reporting
│  alc.env                       — host-owned readonly env snapshot (inject/dotenv/os); alc.env:use{...} declare-at-use proxy
│
Layer 1: Prelude Combinators (Lua → alc.*)
│  alc.cache(prompt, opts?)      — memoized LLM call (session-scoped)
│  alc.parallel(items, fn, o?)   — batch-parallel LLM over array
│  alc.map(items, fn)            — transform each element
│  alc.reduce(items, fn, init)   — fold to single value
│  alc.vote(answers)             — majority aggregation
│  alc.filter(items, fn)         — conditional selection
│  alc.json_extract(raw)         — extract JSON from LLM output
│  alc.parse_number(text, pat?)  — extract number from LLM output
│  alc.state.update(key, fn)     — read-modify-write for state
│  alc.llm_safe(prompt, opts, d) — non-throwing LLM wrapper
│  alc.llm_json(prompt, opts?)   — LLM call with JSON parse + retry
│  alc.fingerprint(str)          — normalize + DJB2 hash (dedup)
│  alc.tuning(defaults, ctx)     — config merge with deep merge
│  alc.budget_check()            — boolean budget guard
│  alc.pipe(strategies, ctx)     — sequential strategy pipeline
│  alc.eval(scenario, strategy)  — evalframe facade (eval + Card)
│
Layer 2: Bundled Packages (require() from ~/.algocline/packages/)
   cot        — chain-of-thought                    [reasoning]
   maieutic   — maieutic prompting                  [reasoning]
   reflect    — self-reflection                     [reasoning]
   calibrate  — confidence calibration              [reasoning]
   sc         — self-consistency (majority vote)     [selection]
   rank       — pairwise ranking                    [selection]
   triad      — triad comparison                    [selection]
   ucb        — UCB1 hypothesis exploration          [selection]
   sot        — skeleton-of-thought                 [generation]
   decompose  — task decomposition                  [generation]
   distill    — knowledge distillation              [extraction]
   cod        — chain-of-density                    [extraction]
   cove       — chain-of-verification               [validation]
   factscore  — factual precision scoring           [validation]
   panel      — multi-perspective deliberation      [synthesis]
```

Layer 0/1 are always available. Layer 2 packages are installed via `alc init` or `alc_pkg_install` from [algocline-bundled-packages](https://github.com/ynishi/algocline-bundled-packages) and loaded via `require()`.

Package kind (runnable/library) is auto-detected at runtime from whether `M.run` is defined (`type(pkg.run) == "function"` via Lua VM eval). `alc_advice` and `alc_eval` reject library packages with a typed error.

### Crate structure

```
algocline (bin: alc)
├── algocline-core      — Domain types, EngineApi trait (transport-independent API surface)
├── algocline-engine    — Lua VM executor, session registry, bridge
└── algocline-mcp       — MCP tool handlers (alc_run, alc_advice, etc.)
```

### Execution model

Each `alc_run` / `alc_advice` call spawns a **dedicated Lua VM** (OS thread + mlua instance). Concurrent sessions are fully isolated — each session's `alc`, `ctx`, and `package.loaded` live in their own VM, so parallel executions cannot interfere with each other.

`alc.llm()` is a **cooperative yield**. When Lua calls it, the VM pauses and returns the prompt to the MCP host. The host processes the prompt with its own LLM, then calls `alc_continue` with the response to resume execution.

```
alc_run(code)
  → Spawn dedicated VM → Lua executes → alc.llm("prompt") → VM pauses
  → returns { status: "needs_response", prompt: "...", session_id: "..." }

alc_continue({ session_id, response })
  → Lua resumes → ... → alc.llm("next prompt") → VM pauses again
  → ...repeat until Lua returns a final value → VM cleaned up
```

## MCP Tools

| Tool | Description |
|---|---|
| `alc_run` | Execute Lua code with optional JSON context. Pass `host_mode: true` to run the session in a long-lived pool worker subprocess that survives MCP server restarts |
| `alc_continue` | Resume a paused execution with the host LLM's response. Automatically routes to a pool worker when the session was started with `host_mode: true` |
| `alc_v2_run` | (v2) Spawn an execution session via the `ExecutionService` API. Streams progress notifications when `_meta.progressToken` is present; supports MCP-level cancellation via `notifications/cancelled`. Returns `{ session_id, status, result?, error? }` |
| `alc_v2_state` | (v2) Return the current `ExecutionStateV2` snapshot for a session (read-only) |
| `alc_v2_resume` | (v2) Resume a paused session with a `Single` or `Batch` `ResumePayload` |
| `alc_v2_cancel` | (v2) Cancel a session with `CancelCode::User`; idempotent on already-terminal sessions |
| `alc_advice` | Apply an installed package by name. Returns a typed error for auto-detected library packages (no `M.run`); use `alc_run` with `require()` to call library APIs directly |
| `alc_card_analyze` | Run a Card analyzer pkg over a single Card. Loads the Card body and its `samples.jsonl` sidecar host-side and dispatches them to `require(pkg).run(ctx)` (default `pkg = "card_analysis"`). Returns a typed result `{ pattern, suggested_change, confidence }` validated by the host before the MCP response is constructed — freeform pkg output is rejected with a typed error |
| `alc_pkg_link` | Link a local directory as a project-local package via symlink. Records path in `alc.lock` |
| `alc_pkg_unlink` | Remove a symlink created by `alc_pkg_link` (rejects real directories) |
| `alc_pkg_list` | List installed packages with metadata. Pass `project_root` to include project-local packages. |
| `alc_pkg_install` | Install a package or collection from Git URL or local path. Pass `force: true` to overwrite an already-installed package. Response includes `types_path` (absolute path to `alc.d.lua`) |
| `alc_pkg_remove` | Remove an installed package from `alc.toml` + `alc.lock`. Pass `project_root` to target project scope |
| `alc_pkg_doctor` | Diagnose package state (read-only). Returns JSON with ten buckets: `healthy` / `incomplete_pkg` / `installed_missing` / `symlink_dangling` / `path_missing` / `missing_meta` (installed pkg whose `init.lua` lacks `M.meta.name`) / `missing_hub_index` (Collection-mode project root with 2+ pkg dirs but no `hub_index.json`) / `spec_missing` (installed pkg with `spec/` but zero `*_spec.lua` files; opt-in spec discipline check) / `stale_cache` (hub cache file older than 3600s; refresh via `alc_hub_search`) / `unregistered_pkg` (physical dir under `~/.algocline/packages/` with `init.lua` but not registered in `installed.json`, `alc.toml`, or `alc.local.toml`; `suggestion` is an `array<string>` with install / link / remove / source-note options). Safe to invoke freely — no filesystem writes |
| `alc_pkg_test` | Run mlua-lspec tests against a package's spec directory (`<pkg>/spec/*_spec.lua`), a single `code_file`, or inline `code`. Returns JSON `{passed, failed, pending, total, duration_ms, spec_files[], resolved_search_paths[], search_path_warnings?}`. Exactly one of `pkg` / `code_file` / `code` must be provided. `auto_search_paths` (optional bool, default `true`) controls automatic prepending of directories from all three registry sources (installed `~/.algocline/packages/`, `alc.toml` linked-global entries, `alc.local.toml` linked-variant entries) to the Lua VM's `package.path`, before any caller-supplied `search_paths`. Set to `false` to suppress all auto-resolution. `resolved_search_paths` is always present in the response (empty array when `auto_search_paths: false`) |
| `alc_init` | Initialize a project — creates `alc.toml` in the project root if absent |
| `alc_update` | Update packages declared in `alc.toml` by re-installing from their recorded sources |
| `alc_migrate` | Migrate a legacy `alc.lock` to the new `alc.toml` + `alc.lock` schema |
| `alc_eval` | Evaluate a strategy against a scenario (cases + graders). Returns a typed error for library packages |
| `alc_eval_history` | List past eval results, filter by strategy |
| `alc_eval_detail` | View a specific eval result in full detail |
| `alc_eval_compare` | Compare two eval results with Welch's t-test |
| `alc_note` | Add a note to a completed session's log |
| `alc_log_view` | View session logs (list or detail) |
| `alc_stats` | Aggregate usage stats across sessions (per-strategy) |
| `alc_status` | Query active session status, progress, and metrics |
| `alc_info` | Show server configuration and diagnostics |
| `alc_hub_search` | Search packages across remote Hub indices + local state |
| `alc_hub_info` | Show detailed info for a single package (metadata, Cards, aliases, stats) |
| `alc_hub_reindex` | Rebuild Hub index from locally installed packages |
| `alc_hub_dist` | Generate and distribute documentation for a package hub (`hub`, `context7`, `devin`, `lint`, `lint_only`, `luacats`, `narrative`, `llms` projections) |
| `alc_hub_gendoc` | Generate documentation for a single package (`hub`, `context7`, `devin`, `lint`, `lint_only`, `luacats`, `narrative`, `llms` projections) |
| `alc_pkg_scaffold` | Generate a minimal package skeleton with `M.meta` / `M.run` template and pre-filled `alc_shapes_compat` range |
| `alc_scenario_list` | List installed eval scenarios |
| `alc_scenario_show` | Show an installed scenario's content |
| `alc_scenario_install` | Install scenarios from Git URL or local path |
| `alc_pool_ensure` | Ensure a pool worker subprocess is running for a session; spawns one if absent. Returns `{sid, sock, pid, status}` |
| `alc_pool_status` | List active pool sessions with PID, socket path, and version. Also runs GC to evict stale entries and persists the updated registry |
| `alc_pool_stop` | Send SIGTERM to a named session's pool worker and remove its registry entry |

## MCP Resources

algocline exposes structured data via [MCP Resources](https://spec.modelcontextprotocol.io/specification/server/resources/) — a standard capability that lets MCP clients read named files and catalog data without calling tools.

### Resource URIs

| URI | Type | Description |
|---|---|---|
| `alc://types/alc.d.lua` | Fixed | LuaCats type definitions for `alc.*` StdLib (editor completion) |
| `alc://types/alc_shapes.d.lua` | Fixed | LuaCats definitions for `alc_shapes` shape library |
| `alc://hub/index` | Fixed | Aggregated hub package catalog (`application/json`) — merges all cached `hub_index.json` files across registered sources |
| `alc://packages/{name}/init.lua` | Template | Package `init.lua` source |
| `alc://packages/{name}/meta` | Template | Package metadata JSON |
| `alc://cards/{card_id}` | Template | Eval card JSON |
| `alc://scenarios/{name}` | Template | Scenario Lua source |
| `alc://eval/{result_id}` | Template | Eval result JSON |
| `alc://logs/{session_id}` | Template | Session transcript log |

### Claude Code `@`-mention

When algocline is configured as an MCP server, Claude Code exposes all resources via `@alc:` mention syntax. Type `@alc:` in the input field to browse or tab-complete resource URIs:

```
@alc:alc://hub/index                         # read the full package catalog
@alc:alc://packages/reflect/init.lua         # read the reflect package source
@alc:alc://types/alc.d.lua                   # read StdLib type definitions
```

Tab-completion for template arguments is supported (`completion/complete`). Typing `@alc:alc://packages/` and pressing `<TAB>` returns installed package names filtered by prefix.

> **Caveat**: Claude Code subagents launched with `subagent_type` may not inherit the parent session's MCP resource access. Read resources from the main agent context, not from within a delegated subagent.

### `alc://hub/index` — aggregated package catalog

Reading `alc://hub/index` returns a JSON object with the union of all registered hub sources:

```json
{
  "schema_version": "hub_index/v0",
  "packages": [ ... ],
  "warnings": []
}
```

Individual source read failures are surfaced in `"warnings"` rather than failing the whole request (best-effort aggregate). On a clean install with no cached sources the response is `{"schema_version":"hub_index/v0","packages":[]}`.

## MCP Prompts

algocline exposes each installed package as an [MCP Prompt](https://spec.modelcontextprotocol.io/specification/server/prompts/) — a pre-built, parameterized instruction template that MCP clients can invoke directly.

### How prompts are generated

`prompts/list` enumerates packages by reading `alc.toml` and `~/.algocline/packages/` on every request. Each installed package produces one prompt:

| Prompt field | Value |
|---|---|
| `name` | Package name (e.g. `cot`) |
| `title` | Name with first letter capitalised (e.g. `Cot`) |
| `description` | Package `description` from its metadata, if present |
| `arguments` | `[{ name: "task", description: "Task to apply this strategy to", required: false }]` |

`prompts/get` returns a single user-role text message. If the `task` argument is supplied, its value is substituted into the message at runtime before the response is returned.

### Using prompts in Claude Code

When algocline is configured as an MCP server, prompts appear as slash commands in Claude Code. Type `/` followed by `mcp__algocline__` to browse them:

```
/mcp__algocline__cot       → apply chain-of-thought to a task
/mcp__algocline__reflect   → apply self-reflection to a task
/mcp__algocline__panel     → apply multi-perspective deliberation to a task
```

Each slash command optionally accepts a `task` argument. If omitted, the prompt message includes guidance for a general use.

### Capability

algocline declares `prompts: { listChanged: true }` and fires
`notifications/prompts/list_changed` whenever a pkg-mutating operation
succeeds (`alc_pkg_install`, `alc_pkg_remove`, `alc_pkg_link`,
`alc_pkg_unlink`, `alc_pkg_repair`, `alc_pkg_scaffold`). MCP clients
that subscribe to this notification (e.g. Claude Code) will
automatically refresh their prompt list after each install or removal.

## Host integration patterns

algocline's `alc.llm()` is a cooperative yield — it pauses the Lua VM and returns a prompt to the host. How the host handles this determines performance and quality.

### Pattern 1: Manual loop (baseline)

The host LLM reads each prompt, generates a response, and calls `alc_continue`. Simple but requires one round-trip per `alc.llm()` call.

```
Host LLM → alc_advice → needs_response → Host reads prompt → Host generates response → alc_continue → repeat
```

**Best for**: Interactive exploration where you want to inspect each step.

### Pattern 2: Autonomous agent delegation (recommended)

Delegate the entire strategy execution to a single agent that has MCP tool access. The agent calls `alc_advice`, handles every `needs_response` internally, and returns only the final result.

```
Host LLM → Agent(MCP-capable) → [alc_advice → needs_response → self-respond → alc_continue → ...] → final result
```

**Best for**: Production use. Zero host intervention. Fastest execution.

Example (Claude Code):

```
Agent(general-purpose) with prompt:
  1. Call alc_advice(strategy="explore", task="...")
  2. For each needs_response: generate a response following the system/prompt instructions
  3. Call alc_continue with your response
  4. Repeat until status="completed"
  5. Return the final result
```

> **Known limitation: MCP tool permissions in subagents**
>
> Claude Code subagents may not inherit MCP tool permissions from the parent session's `settings.json`. If `alc_run`/`alc_continue` calls fail with permission errors inside a subagent, add the following to your `~/.claude/settings.json` under `permissions.allow`:
>
> ```json
> "mcp__alc__*"
> ```
>
> If the issue persists, run the `alc_run`/`alc_continue` loop directly from the main agent instead of delegating to a subagent.

### Pattern 3: MCP Sampling (future)

When the MCP host supports server-initiated sampling, `alc.llm()` will resolve automatically without pausing. No agent delegation needed — the host responds inline.

### Performance comparison

Benchmarked on the same task (UCB1 explore, 11 LLM calls):

| Pattern | Time | Host interventions | Notes |
|---|---|---|---|
| Manual (Opus) | 152s | 9 | High quality, manual effort |
| SubAgent relay (Haiku) | 224s | 9 | Agent startup overhead per call |
| SubAgent relay (Opus) | 442s | 9 | Same overhead, better quality |
| **Autonomous agent** | **69s** | **0** | Single agent, full MCP access, no relay overhead |

The autonomous agent pattern eliminates relay overhead entirely. The agent handles the full `alc_advice → alc_continue` loop in-process, resulting in ~2x faster execution than even manual operation.

### Strategy selection guide

| Strategy | Structure | Best for |
|---|---|---|
| `explore` / `ucb` | Generate hypotheses → UCB1 score → refine best | Open-ended questions, design decisions |
| `triad` | 3-role debate (proponent/opponent/judge) | Comparative analysis, pro/con evaluation |
| `panel` | Multi-perspective deliberation + moderator | Complex problems needing diverse viewpoints |
| `verify` / `cove` | Draft → verify → revise | Factual accuracy, reducing hallucination |
| `reflect` | Generate → critique → revise loop | Iterative improvement |
| `ensemble` / `sc` | Multiple answers → majority vote | When consistency matters more than novelty |
| `rank` | Pairwise tournament ranking | Selecting best among candidates |
| `factscore` | Atomic claim decomposition + verification | Fact-checking, claim validation |
| `cod` | Iterative information densification | Summarization, compression |

## Evaluating strategies

algocline includes a built-in evaluation framework powered by [evalframe](https://github.com/ynishi/evalframe). Define scenarios with test cases and graders, then run them against any strategy to measure quality.

### Define a scenario

A scenario is a Lua table with bindings (graders) and cases (input/expected pairs):

```lua
-- scenario.lua
local ef = require("evalframe")
return {
  ef.bind { ef.graders.contains },
  cases = {
    ef.case { input = "What is 2+2?", expected = "4" },
    ef.case { input = "Capital of France?", expected = "Paris" },
  },
}
```

### Run an eval

```
alc_eval({ scenario: "...", strategy: "cove" })
```

Or point to a file:

```
alc_eval({ scenario_file: "/path/to/scenario.lua", strategy: "cove" })
```

The strategy is automatically wired as the provider — no boilerplate needed. Results include per-case scores, pass/fail status, and aggregate metrics.

### Track and compare results

Eval results are persisted to `~/.algocline/evals/` automatically.

```
alc_eval_history({ strategy: "cove", limit: 10 })   # List past results
alc_eval_detail({ eval_id: "cove_1710672000" })      # Full result detail
alc_eval_compare({ eval_id_a: "...", eval_id_b: "..." })  # Welch's t-test
```

`alc_eval_compare` performs a Welch's t-test on the score distributions, reporting whether the difference between two runs is statistically significant.

## Writing strategies

A strategy is a Lua file with an `init.lua` entry point:

```lua
-- my-strategy/init.lua
local M = {}

M.meta = {
    name = "my-strategy",
    version = "0.1.0",
    description = "What it does",
}

function M.run(ctx)
    local task = ctx.task or error("ctx.task is required")

    -- Your reasoning algorithm here
    local step1 = alc.llm("Analyze: " .. task)
    local step2 = alc.llm("Given analysis:\n" .. step1 .. "\n\nSynthesize a solution.")

    ctx.result = { answer = step2 }
    return ctx
end

return M
```

Install it:

```
alc_pkg_install({ url: "github.com/you/my-strategy" })
```

Use it:

```
alc_advice({ strategy: "my-strategy", task: "..." })
```

## Package management

### Bundled packages

Bundled packages ship in two Hub Collection repositories (see [Ecosystem](#ecosystem) for the full picture):

| Collection | Packages | Repo |
|---|---|---|
| [algocline-bundled-packages](https://github.com/ynishi/algocline-bundled-packages) | 15 core strategies (cot, reflect, ucb, panel, …) | Core reasoning/selection/validation |
| [algocline-swarm-frame](https://github.com/ynishi/algocline-swarm-frame) | swarm_frame, swarm_frame_algocline, swarm_aggregate_plugin | Multi-agent orchestration |

Install via CLI:

```bash
alc init            # Download and install all bundled packages
alc init --force    # Overwrite existing packages
```

If you call `alc_advice` with a package that isn't installed, algocline **automatically downloads the bundled collection** from GitHub. But `alc init` upfront is recommended.

Install or update via MCP:

```
alc_pkg_install({ url: "github.com/ynishi/algocline-bundled-packages" })
alc_pkg_install({ url: "github.com/ynishi/algocline-bundled-packages", force: true })  # overwrite
```

### Installing third-party packages

```
alc_pkg_install({ url: "github.com/user/my-strategy" })
```

`alc_pkg_install` expects the repository to use **collection layout** and ship a
`hub_index.json` at its root. Each subdirectory with an `init.lua` is installed
as a separate package. A single-package repo is fully supported — place
`init.lua` at `<repo>/<pkg_name>/init.lua` and generate `hub_index.json` with
`alc_hub_dist` (see `docs/pkg-author-conventions.md §7`).

Supported URL formats:

| Format | Example |
|---|---|
| GitHub shorthand | `github.com/user/my-strategy` |
| HTTPS | `https://github.com/user/my-strategy.git` |
| SSH | `git@github.com:user/my-strategy.git` |
| Local path (file://) | `file:///path/to/my-strategy` |
| Local path (absolute) | `/path/to/my-strategy` |

Optional parameters:

```
alc_pkg_install({ url: "/path/to/repo", force: true })  # overwrite if already installed
```

### Managing packages

```
alc_pkg_list()                          # List installed packages with metadata
alc_pkg_remove({ name: "my-strategy" }) # Remove a package
```

Packages live in `~/.algocline/packages/`. Each package is a directory with an `init.lua`.

### Project-local packages

Project-local packages are managed via two files at the project root:

- **`alc.toml`** — Package declarations (source of truth). Created by `alc_init` or automatically on first `alc_pkg_install`.
- **`alc.lock`** — Resolved lockfile written by install/link operations.

Initialize a project:

```
alc_init({ project_root: "/path/to/project" })
```

Link a local directory as a project-scoped package via symlink (no copy):

```
alc_pkg_link({ path: "/path/to/my-strategy" })
```

This creates a symlink in `~/.algocline/packages/` and records the entry in `alc.toml` + `alc.lock`:

```toml
# alc.toml
[packages.my-strategy]
source = "path"
path = "/path/to/my-strategy"
```

Remove the symlink:

```
alc_pkg_unlink({ name: "my-strategy" })
```

Project root is auto-detected by walking up the directory tree to find `alc.toml`. You can also pass `project_root` explicitly.

Resolution order (highest priority first):

1. `alc.lock` `path` entries — symlinked local directories
2. `ALC_PACKAGES_PATH` (environment)
3. `~/.algocline/packages/` (global default)

Migrate an existing project using the old `alc.lock` schema:

```
alc_migrate({ project_root: "/path/to/project" })
```

Use `project_root` to activate project scope in other tools:

```
alc_pkg_list({ project_root: "/path/to/project" })    # Lists both project and global packages
alc_pkg_remove({ name: "my-strategy", project_root: "/path/to/project" })  # Removes from alc.toml + alc.lock
alc_update({ project_root: "/path/to/project" })       # Re-installs all alc.toml packages
```

## Strategy development

Strategies are Pure Lua files. The host LLM can read, write, and execute them via `alc_run` — that's enough to iterate.

For debugging and testing, there are dedicated tools that run on the same mlua VM:

- [mlua-probe](https://github.com/ynishi/mlua-probe) — Lua debugger (MCP server). Breakpoints, stepping, variable inspection, expression evaluation
- [mlua-lspec](https://github.com/ynishi/mlua-lspec) — BDD test framework (`describe`/`it`/`expect`). Structured test results for CI/LLM consumption

## Contributing

Bug reports and feature requests are welcome — please [open an issue](https://github.com/ynishi/algocline/issues).

Pull requests are also appreciated. For larger changes, consider opening an issue first to discuss the approach.

### Share your strategies

Writing a strategy package is straightforward: create `init.lua`, define `M.meta` and `M.run(ctx)`, and you're done. If you build something useful, publish it as a Git repo and others can install it with:

```
alc_pkg_install({ url: "github.com/you/your-strategy" })
```

See [Writing strategies](#writing-strategies) and [Package management](#package-management) for details.

## License

MIT OR Apache-2.0