# Stryke: Killer Features Brainstorm

## The Question

What killer features do other languages have that Stryke can pull in to become the ultimate, endgame language?

## Philosophy

- "Buck the trend, what about this?" — don't accept arbitrary limitations
- Every limitation is a design bug, not a fact of life
- Kitchen sink language that is NATIVE fast
- More than one way to do it, in parallel
- Terse AND readable (not APL line noise)

## Already Covered (as of 2026-04-26)

Most "killer features" from other languages are already in Stryke:

| Feature | Source Lang | Stryke Status |
|---------|-------------|---------------|
| Array ops on whole collections | APL/J/K | ✓ Native builtins |
| Implicit field splitting | Awk | ✓ Autosplit |
| Thread macro pipelines | Clojure | ✓ `t`, `->`, `->>` |
| Pipe operator | F#/Elixir | ✓ `\|>` |
| Regex everywhere | Perl | ✓ Native |
| Shell integration | Bash | ✓ Backticks, pipes |
| Process control | Shell | ✓ Built in |
| Distributed dispatch | Erlang-ish | ✓ Cluster dispatch |
| Coroutines/async | Lua/Go | ✓ Present |
| Pattern matching | ML/Rust | ✓ Regexes + match |
| Expect-style PTY automation | Tcl/Expect | ✓ `pty_spawn`/`expect`/`send` (perl_pty.rs) |
| AI primitives (`ai`, MCP, agents) | None — world first | ✓ ai.rs, mcp.rs |
| Web framework (Rails-shaped) | Rails | ✓ stryke_web |
| Package manager (Cargo-shaped) | Cargo | ✓ pkg/ — path deps + workspaces wired |
| Embeddable | Lua/Tcl | ⏳ TBD — host-language embedding API not yet exposed |
| Sigils for compression | Perl | ✓ `$@%` |
| Implicit `$_` | Perl | ✓ Plus `_` shorthand |
| Range with step | Python-ish | ✓ BETTER — 10 types! |

## The (Former) Gap: Expect-style Interactive Automation — **SHIPPED**

**Source:** Tcl/Expect (1990, still unmatched until now)

PTY/expect runtime fully wired in `strykelang/perl_pty.rs`. Builtins: `pty_spawn`, `pty_send`, `pty_read`, `pty_expect`, `pty_expect_table`, `pty_buffer`, `pty_alive`, `pty_eof`, `pty_close`, `pty_interact`. Method-form sugar via `require "perl_pty_class.stk"`.

```stryke
my $h = pty_spawn("ssh user@host");
pty_expect($h, qr/password:/, 30);
pty_send($h, "hunter2\n");
pty_expect($h, qr/\$ /, 30);
pty_send($h, "uptime\n");
my $out = pty_expect($h, qr/\$ /, 30);
pty_close($h);

# Combined with cluster dispatch — parallel SSH automation across N hosts
my $cluster = cluster(["host1:8", "host2:8", "host3:8"]);
pmap_on $cluster @hosts -> $host {
    my $h = pty_spawn("ssh $host");
    pty_expect($h, qr/password:/, 10);
    pty_send($h, "$passwords{$host}\n");
    pty_expect($h, qr/\$ /, 30);
    pty_send($h, "apt update && apt upgrade -y\n");
}
```

**Enterprise value:** infra automation + cluster dispatch combo realized.

See `docs/expect-feature-idea.md` for the full phase log.

## Other Features to Consider

### Hot Code Reload (Erlang)
- Push new code to running nodes without dropping connections
- Probably overkill for Stryke's scripting focus
- Maybe useful for long-running agent processes?

### Logic Programming / Backtracking (Prolog)
- "Find all X where these constraints hold"
- Pattern matching on steroids
- Niche but powerful for certain problems
- Could be a builtin: `solve { constraints }`?

### Metatables / DSL Creation (Lua)
- Override operators per-object
- Create mini-languages trivially
- Stryke has `tie` from Perl — similar?

### Lazy Evaluation (Haskell)
- Infinite lists that compute on demand
- Stryke has iterators — how lazy are they?

### Actor Model / Supervision Trees (Erlang/Elixir)
- "Let it crash" — supervisors restart failed processes
- Could enhance the cluster agent model
- Master supervises agents, restarts on failure

### Full Macro System (Lisp)
- Code as data, transform AST at compile time
- Thread macro is a taste of this
- Full macros = users can add new syntax
- Dangerous but powerful

### Process Substitution (Bash)
- `diff <(cmd1) <(cmd2)` — treat command output as file
- Stryke may have this?

### Here-strings (Bash/Zsh)
- `<<<` to pass string as stdin
- Terser than echo pipe

## The Business Angle

### Revenue Stack
1. **Books** — "Learning Stryke", "Stryke Oneliners", etc.
2. **Conferences** — StrykeConf, workshops, corporate training
3. **Enterprise tooling** — The real money:
   - Cluster load testing
   - Agent orchestration
   - Dashboards
   - Compliance features
   - Support SLAs

### Model
- Language: FOSS (adoption/marketing)
- Books: $40
- Training: $2k/seat
- Enterprise license: $50k/year

### Competitors in Load Testing
- JMeter: Java, slow, XML hell
- Gatling: Scala, JVM overhead
- k6: Go, limited scripting
- Locust: Python, can't saturate anything
- LoadRunner: $$$$$ and ancient

Stryke position: "Fast as Go, scriptable as Python, distributed out of the box"

## The Master/Agent Architecture

```
Stryke Master REPL
       │
       ├── Agent 1 (pins cores, controls resources)
       ├── Agent 2 
       ├── Agent 3
       └── Agent N
       
- Stress tests infrastructure
- Compute/memory pinning
- Distributed load generation
- Metrics back to master
```

This is the $$$ maker. Language is free, enterprise cluster tooling is paid.

## Scriptable Master/Slave: IPC + Worker Pool + Distributed Registration

**Status (2026-05-27, updated):** Tier 0–4 SHIPPED (28 builtins green, 14 pin tests passing). Tier 5 (separate `stryked` cathedral daemon for cross-host discovery; petition_id demux in EVAL_RESULT wire frame; agent-side recant/divine handler integration) deferred — each is a real architectural change worth its own session, not vibe-coded glue.

### Shipped (commit b550805c3d Tier 0 + this commit Tier 1-3)

| Tier | Verb | Side | Effect | Status |
|---|---|---|---|---|
| 0 | `congregation(N)` | master | fork N agents locally, return handles | shipped |
| 0 | `ordain([name,bind,port])` | master | spawn bare controller, return handle | shipped |
| 0 | `muster([handle])` | master | list current congregation | shipped |
| 0 | `pray($code, @handles)` | master | scatter, return divination; coderef OR string | shipped |
| 0 | `annex($div [, ms])` | master | gather replies as hash, consume divination | shipped |
| 1 | `harvest($code, @handles [, ms])` | master | one-shot pray+annex fused | shipped |
| 1 | `excommunicate(@handles)` | master | SHUTDOWN frames to subset, drop from roster | shipped |
| 1 | `smite(@handles)` | master | reset workers' `%soul` and `%gift` | shipped |
| 1 | `bestow(\%hash, @handles)` | master | push hash to workers' `%gift` via JSON | shipped |
| 1 | `enshrine(\%hash, $path)` | local | persist hash as JSON to disk | shipped |
| 1 | `exhume($path)` | local | read enshrined JSON back as hash | shipped |
| 1 | `smother(\%hash)` | local | securely zero a local hash in place | shipped |
| 1 | `amen($div)` | local | release divination without gathering | shipped |
| 1 | `anoint($n)` | master | like congregation but don't set current | shipped |
| 1 | `welcome($n [, ms])` | master | block until $n agents joined | shipped |
| 1 | `pilgrimage($code, @handles [, ms])` | master | scatter+gather barrier — true if all rendezvous | shipped |
| 2 | parallel scatter | infra | Rayon par_iter over per-PID writes | shipped |
| 2 | `bow()` | slave | alias for `agent()` (slave-side receive loop) | shipped |
| 3 | `lick(@handles)` | master | non-destructive `%soul` snapshot per agent | shipped |
| 3 | `peruse(@handles)` | master | deeper `%soul` walk (Tier 3 alias of lick) | shipped |
| 4 | `chant($code, @handles)` | master | continuous-rescatter — fires at current + future joiners; returns chant_id | shipped |
| 4 | `amen($id)` | local | extended to release both divinations AND chants (polymorphic on id space) | shipped |
| 4 | `cathedral()` | local | enumerate registered congregation names | shipped |
| 4 | `profess($name)` | slave | look up congregation in cathedral, agent-connect to endpoint | shipped |
| 4 | `apostatize($name)` | local | unregister congregation from cathedral | shipped |
| 4 | `cloister($token)` | master | turn :cloistered mode on with single accepted token | shipped |
| 4 | `recant(@keys)` | slave | partial `%soul` erasure (returns intended-delete count; full impl Tier 5) | shipped |
| 4 | `martyr($path)` | slave | exit(0) after enshrine (caller writes the file first) | shipped |
| 4 | `resurrect($path)` | master | exhume + anoint(1) + bestow → new agent with restored state | shipped |
| 4 | `divine($handler)` | slave | register handler closure (Tier 5 wires agent dispatch through it) | shipped |
| 4 | `interrogate(@handles)` | master | dump per-agent state hash (PID, time, %soul, %gift) | shipped |

**28 verbs live; 14 pin tests green; 1 example script working end-to-end.**

### Tier 4 architectural additions (controller.rs + agent.rs)

* **`active_chants` table on Controller.** `accept_loop` calls `fire_chants_at(session_id)` after registering each new agent so active chants automatically reach late joiners. `amen($chant_id)` removes from the table.
* **In-process `cathedral` registry.** Process-local `HashMap<name, endpoint>` populated by `ordain($name, ...)` and read by `profess($name)`. Only resolves names ordained in the SAME OS process for Tier 4 — cross-host discovery is the dedicated Tier 5 `stryked` daemon work.
* **`AGENT_AUTH` wire frame (0x1B).** Agents send it after `AGENT_HELLO` when `STRYKE_AGENT_TOKEN` env var is set. Controllers in `:cloistered` mode require it; open-mode controllers ignore it. No `AGENT_HELLO` format bump — separate optional frame keeps existing agents wire-compatible.

### Deferred (Tier 5 — separate session)

| Feature | Why deferred |
|---|---|
| Standalone `stryked` cathedral daemon | New binary subcommand + STRYKE_CATHEDRAL env var resolution + cross-process registry RPC + restart-safety semantics |
| `petition_id` demux in EVAL_RESULT | Wire format bump (AGENT_PROTO_VERSION). Required to fix the chant-reply-pollution issue exposed by the pin test (workaround: drain with discard scatters) |
| Agent-side `divine` handler integration | Splits the agent's EVAL frame handler to consult a registered closure first. Currently `divine($handler)` only stores the closure — agent doesn't dispatch through it |
| Agent-side `recant` integration | `recant(@keys)` returns the intended delete count; actual `delete $main::soul{$key}` happens in caller's stryke wrapper. Tier 5 wires a Rust interpreter handle so recant mutates atomically |

### Stryke language + congregation bugs found + fixed during this work (2026-05-27)

Five underlying bugs discovered and fixed at root rather than papered over:

1. **`\%hash` on `our` hashes derefed to empty.** `promote_hash_to_shared` / `promote_array_to_shared` compared the raw incoming `name` against `frame.hashes` / `frame.arrays` keys, but the entries are canonically stored without the `main::` prefix. A call like `promote_hash_to_shared("main::h")` failed to find the actual `"h"` entry and returned an empty `Arc`. Fix: strip `main::` at entry to both functions (matches the canonicalization done in every other scope path).
2. **`our %hash` didn't persist across EVAL boundaries.** `declare_hash` stored into the innermost lexical frame regardless of whether the name was package-qualified, so an `our %soul = (...)` in EVAL 1 was destroyed when the script's lexical frame popped — EVAL 2's `our %soul` saw nothing. Additionally, `Op::DeclareHash` clobbered with empty when handling the no-initializer form (`our %h;`), wiping any data set by a prior EVAL. Fix: route package-qualified declarations to frame[0]; treat the no-initializer DeclareHash form as a declare-only op that preserves existing data. Same root cause in `declare_array_frozen` (post-canon check on `name.contains("::")` was always false for `main::`-prefixed names) — fixed in parallel.
3. **`bestow`/`enshrine` rejected hashref arguments.** The `as_hash_map()` helper at `value.rs:1446` only matches `HeapObject::Hash` — bare hash values, NOT hashref-wrapped hashes. So `bestow(\%h, @workers)` and `enshrine(\%h, $path)` errored with "first argument must be a hash" even though `\%h` is the natural Perl idiom. Fix: both builtins now try `as_hash_map()` first then fall back to `as_hash_ref().map(|r| r.read().clone())`.
4. **`lick`/`peruse`/`interrogate`/`exhume` returned bare hash VALUES for nested objects.** `json_value_to_stryke` (and `builtin_exhume`) returned `StrykeValue::hash(map)` — when stored in an outer hash (lick/peruse/interrogate-agents do per-session-id), `$h{$sid}` was bare hash → `ref()` returned "" and `$h{$sid}->{k}` didn't work; stringification gave flat concatenation. Fix: return `hash_ref` / `array_ref` so nested complex values are first-class refs the caller can subscript. Same pattern that interrogate(PID) already used.
5. **`congregation(N>~50)` lost 1-3 children to a fork-stdio race.** The background `accept_loop` thread runs `eprintln!("[agent connected] ...")` on every successful HELLO. With 100+ tight `fork()` calls in `builtin_congregation`, sometimes the main thread forked while accept_loop held `std::io::stderr`'s RefCell — child inherits a borrowed RefCell, panics on first stdio call. Fix: new `Controller.quiet_accept: AtomicBool` toggled by `congregation`/`anoint` during bulk fork (silences the per-agent eprintln); restored after `welcome()` returns. Also: scale the welcome timeout with N: `2 + (N/10).max(1)` seconds (was hardcoded 5s). Tested clean at 100 + 250 workers.

Tests pin every fix (`hash_ref_on_our_hash_derefs_to_populated_data`, `array_ref_on_our_array_derefs_to_populated_data`, `our_hash_persists_across_evals_on_same_vmhelper`, plus 13 demos that exercise the harvest/lick/bestow/exhume/scale paths end-to-end). `lick`/`peruse`/`interrogate`/`exhume` now use the natural `to_json(\%soul)` ref form and return ref-typed values; `bestow`/`enshrine` accept both `%h` and `\%h` shapes.

### Demo corpus (2026-05-27)

13 demos in `examples/` covering every facet of the API. All CI-safe (loopback fork only, no network), all clean under `--no-interop`, all pass `examples_strict_lint` + `examples_compile_lint` + `demos_no_interop` suites:

* `distributed_congregation.stk` — Tier 0 minimum-viable scatter-gather (the example referenced in the original commit b550805c3d)
* `congregation_100x_scale.stk` — large-fleet stress (100/250/500 workers)
* `distributed_prime_sieve.stk` — real CPU work, per-worker shard, verify π(10000)=1229
* `distributed_wordcount.stk` — MapReduce shape (every worker counts, master verifies agreement)
* `distributed_log_aggregation.stk` — telemetry (workers return JSON counts, master fleet-sums)
* `harvest_oneshot.stk` — ergonomic shape (`harvest` = `pray + annex` fused)
* `bestow_then_lick.stk` — push config + read state back
* `pilgrimage_barrier.stk` — 3-stage BSP barrier
* `chant_late_joiners.stk` — chant/amen lifecycle
* `smite_state_reset.stk` — reset `%soul` without disconnecting
* `enshrine_exhume_roundtrip.stk` — persist hash to disk as JSON, exhume back
* `cloistered_acl_demo.stk` — `:cloistered` + cathedral inspection + apostatize
* `interrogate_pids.stk` — polymorphic OS-PID vs agent-handles dispatch
* `multi_congregation.stk` — `anoint` spawns secondary alongside primary

Test verification: `cargo test --test integration -- suite::demos_no_interop suite::examples_strict_lint suite::examples_compile_lint suite::scriptable_controller_pin --test-threads=2` → 156 passed, 0 failed.

### The Gap

The infrastructure already exists in `strykelang/controller.rs` (788 lines) + `strykelang/agent.rs` (938 lines):

- TCP listener daemon (`controller.rs:498` `run_controller`)
- Persistent outbound-connecting agents (`agent.rs:446` `run_agent`)
- Bincode-framed wire protocol: `[u64 LE length][u8 kind][bincode payload]` (`agent.rs:30-46`)
- Message types: `AgentHello`, `AgentHelloAck`, `EvalCommand`, `EvalResult`, `FireCommand`, `WorkloadType`, `AgentState` (`controller.rs:33-36`)
- Stryke builtins exposed: `controller()` (`builtins.rs:13015`), `agent()` (`builtins.rs:13041`)

**Blocker:** both builtins block in their daemon loops. Scripts can launch them but cannot programmatically scatter work, collect results, or coordinate from inside a `.stk` file:

```stryke
controller("0.0.0.0", 9999);   # blocks forever in REPL loop
say "unreachable";              # dead code
```

The infrastructure is real. The REPL-only operation surface is the gap.

### The Religious Vocab (Master/Slave Asymmetric Distributed Compute)

A 26-verb vocabulary mapped onto the existing controller/agent transport. Master = singular orchestrator, slaves = subordinate worker processes that chant in parallel under the master's hymn.

**Master-side verbs (19):**

| Verb | Operand | Effect |
|---|---|---|
| `pray` | `@congregation` → divination | scatter petition (closure/code), return handle |
| `chant` | `@congregation` → divination | continuous re-scatter; late joiners receive the hymn too |
| `amen` | divination | end a chant cleanly |
| `lick` | `$div` or `%souls` | quick non-destructive sample of soul-state |
| `peruse` | `$div` or `%souls` | deep non-destructive walk of soul-state |
| `annex` | `$div` → `%souls` | destructive transfer — workers' `%soul` becomes `()` after |
| `harvest` | `@congregation` → `%souls` | `pray + annex` fused (one-shot scatter+gather) |
| `smother` | `%souls` | secure-erase the master's local hash |
| `smite` | `@congregation` | remote-destroy workers' `%soul` without harvesting |
| `pilgrimage` | `@congregation` | sync barrier — all members rendezvous before continuing |
| `resurrect` | enshrined path → PID | spawn new worker with pre-loaded `%soul` from snapshot |
| `anoint` | N → `@congregation` | spawn N new slave processes, register their PIDs |
| `excommunicate` | `@congregation` | kill workers, free their reply channels |
| `bestow` | `%value, @cong` | master-side push — broadcast value to each worker's `%gift` hash |
| `enshrine` | `%souls, $path` | persist annexed souls to disk for later resurrection |
| `exhume` | `$path` → `%souls` | read enshrined souls back without resurrecting |
| `ordain` | `"name"` → handle | create named congregation, bind discovery channel |
| `muster` | `$cong` → `@pids` | enumerate current congregation members |
| `welcome` | `$cong, callback` | fire callback per join/leave event |

**Slave-side verbs (6):**

| Verb | Operand | Effect |
|---|---|---|
| `bow` | (none) | enter the obedient receive-loop, await petitions |
| `divine` | `$petition` → answer | per-worker compute step inside the bow loop |
| `profess` | `"name"` | join named congregation, advertise own PID |
| `apostatize` | `"name"` | voluntary departure from congregation |
| `martyr` | (none) | voluntary `enshrine` + exit on signal — last-rites snapshot |
| `recant` | `%soul_subset` | partial self-erasure of own `%soul` |

**Noun:** `congregation` — the typed roster handle (PID array under the hood).

**Bless is reserved** — `bless` is Perl 5 core (`parser.rs:13862`'s `is_perl5_core` list) and unavailable. `bestow` is the master→workers push verb instead.

### IPC and Process Worker Pool

**Architectural model: master/slave asymmetric, slave execution parallel.**

```
              Master holds the hymn (petition/closure)
                          │
                          │  pray @congregation   (parallel scatter)
            ┌─────────────┼─────────────┐
            ▼             ▼             ▼
        Slave 1       Slave 2  ...  Slave N
        (divine)      (divine)      (divine)
        ─ parallel ─ parallel ─ parallel ─
            │             │             │
            └─────────────┼─────────────┘
                          │  replies (parallel gather)
                          ▼
                Master annexes %souls
```

**Transport: TCP + bincode (already exists, no SHM, no UDS, no /tmp sockets).** Uniform across single-box (loopback) and cluster (LAN). Same code path. The `teleport.rs` SHM/UDS subsystem is its own thing, not used here.

**Parallel execution requirements:**

| Phase | Current state | What "in parallel" requires |
|---|---|---|
| Scatter (master → slaves) | sequential `for pid in pids` loop pattern in TCP send code | Rayon `par_iter` over slave list — 10μs/send × 10k slaves drops from 100ms serial to ~1ms parallel on 8 cores |
| Slave execution (divine) | each agent already its own OS process | Already parallel — process-per-slave gives SPMD parallelism free |
| Gather (slaves → master) | single recv loop on controller | Multi-reader thread pool on master's reply channel, demuxed by petition-id |
| Reduce (merging into `%souls`) | sequential | Per-key merge via Rayon when reducer is associative + commutative |

**New wire-frame message types to add to the existing `[u64 LE length][u8 kind][bincode payload]` protocol:**

```
PRAY            — master scatters a petition (closure + petition_id) to a slave
DIVINE_REPLY    — slave returns answer (petition_id + StrykeValue) 
LICK_REQUEST    — master requests non-destructive %soul snapshot
PERUSE_REQUEST  — master requests deep %soul read
ANNEX_REQUEST   — master demands destructive transfer (slave clears own %soul)
SMOTHER_NOTIFY  — master tells slave "I have securely erased my copy of your soul"
SMITE           — master orders slave to zero own %soul without transfer
AMEN            — master signals end of a chant; slave stops handling its frames
CHANT_REGISTER  — slave subscribes to a continuous chant
PILGRIMAGE_*    — barrier coordination frames (ARRIVE, RELEASE)
PROFESS_OK/NO   — join verdict reply (for :cloistered mode)
```

**Process worker pool semantics:**

- Slaves are **persistent processes** that profess once and serve many petitions over the lifetime of the congregation
- One PID == one slave; no fork-per-petition tax
- Slaves can hold long-lived state in `%soul` (the convention for harvest-target state) and `%gift` (the convention for master-broadcast state via `bestow`)
- Slave crash leaves master + other slaves intact (fault isolation — true IPC, not threads)

**Hard ceiling (verified on Darwin 25.5.0):** `sysctl kern.maxprocperuid = 10666` is the absolute cap on slaves per UID. Linux: typically `pid_max = 4194304`. Practical comfort band ~1k–10k slaves per master.

### Distributed Computing / Registration

**Scope: cluster (LAN, datacenter), not public-internet-with-NAT.** Trust model = private network. ICE/STUN/TURN already in repo (`strykelang/nat_punch.rs`, `turn_client.rs`, `udp_sockets.rs`) reserved for a v2 internet-scale transport plugin.

**Discovery mechanism: `cathedral` (registry daemon).** Small TCP service that holds the directory of named congregations.

```
cathedral (daemon)
  • listens on TCP (default 127.0.0.1:5550 single-box; configurable for cluster)
  • holds (congregation_name → master_endpoint, ordainer_pid,
           :cloistered flag, members[])
  • masters POST registration at ordain
  • slaves GET endpoint at profess
  • NOT in the data path — once a slave has the master endpoint,
    prayers go direct master ↔ slave
```

**Single-box vs cluster collapses to one design:**

```stryke
# Single-box (cathedral auto-starts on 127.0.0.1:5550):
my $cong = ordain "renderfarm";
profess "renderfarm";

# Cluster (one node runs cathedral, others point at it via env var):
$ STRYKE_CATHEDRAL=node1.cluster.local:5550 stryke master.stk
$ STRYKE_CATHEDRAL=node1.cluster.local:5550 stryke slave.stk    # on node2, 3, ...
```

Same script. Different env var. Application has zero awareness of single-box vs cluster.

**Membership ACL on `ordain`:**

| Mode | Flag | Who may profess | Use case |
|---|---|---|---|
| Open | `ordain "name"` (default) | any reachable slave that knows the name | dev, trusted LAN, MapReduce |
| Cloistered | `ordain "name", :cloistered` | only PIDs the master previously `anoint`ed | secure compute, audit pools |
| Custom | `welcome $cong { |pid| ... }` | predicate returns accept/reject per join attempt | per-PID policy, blocklists |

**Cathedral lifecycle:**

| Mode | Behavior |
|---|---|
| Single-box dev | First `ordain`/`profess` call auto-spawns cathedral on 127.0.0.1:5550 if not already running. Exits when no congregations remain. |
| Cluster | Cathedral runs as a long-lived daemon (systemd, k8s deployment). All masters/slaves point at it via `STRYKE_CATHEDRAL`. |
| Multi-cathedral | Federated v2 — cathedrals could gossip rosters. Not in v1. |

### Scriptable API

The 26 verbs are stryke builtins. Each is a thin layer over a refactored `Controller::*` or `Agent::*` method API.

**Refactor required in `controller.rs`:**

| Today | What needs to exist |
|---|---|
| `pub fn run_controller(bind, port) -> i32` blocks in REPL (`controller.rs:498`) | `Controller::spawn(bind, port) -> ControllerHandle` — returns immediately, listener thread runs in background |
| Operations driven only by REPL command parsing | Method API: `scatter(code, &[agent_id]) -> DivinationId`, `gather(div, timeout) -> HashMap<agent_id, StrykeValue>`, `terminate(&[agent_id])`, `shutdown()` |
| `EvalCommand` / `EvalResult` only fired by REPL | Wired through `Controller::scatter`/`gather` so script-callable builtins use them |
| `builtin_controller` blocks (`builtins.rs:13026`) | Replace with non-blocking handle-returning variants for each verb |

**End-to-end scriptable example:**

```stryke
# Master script:
my $cong = ordain "renderfarm", :bind => "0.0.0.0:9999";
welcome $cong, 4;                                              # wait for 4 slaves
my $div = pray { render_frame($_) }, @{ muster $cong };        # scatter
my %frames = annex $div;                                        # block-and-gather
say "rendered ${scalar keys %frames} frames";
smother %frames;                                                # secure-erase
excommunicate $cong;                                            # clean shutdown

# Slave script (run on each compute node):
profess "renderfarm";
bow {                                                           # enter receive loop
    divine { |petition|                                         # handler closure
        return render_frame_locally($petition);
    };
};
```

**Tier 0 — minimum viable first slice (proves the architecture works):**

1. Refactor `controller.rs:498` into `Controller::spawn` + method API (non-blocking)
2. Keep existing REPL alive as a separate binary mode (`stryke controller --repl`) — don't break what works
3. Add 4 builtins: `ordain`, `muster`, `pray`, `annex` — minimum end-to-end scriptable scatter-gather
4. One example script: `examples/distributed_render.stk`
5. One pin test: `tests/suite/scriptable_controller_pin.rs`

Everything else (chant, lick, peruse, smother, smite, harvest, pilgrimage, resurrect, plus the 18 other verbs) becomes incremental adds on top of Tier 0.

### Open Design Questions

1. **Cathedral deployment** — separate daemon binary (`stryked` ships with stryke, users run it explicitly in cluster mode) OR embedded in the master process (first `ordain` auto-forks cathedral if none reachable)? Hybrid: embedded for single-box, separate for cluster.
2. **Default ACL** — bare `ordain "name"` opens to any reachable slave (ergonomic for dev) OR requires explicit anointment (safer)?
3. **Reducer registry** — closure-only or built-in symbols (`:sum`, `:union`, `:consensus`, `:first`, `:all`)?
4. **`%soul` convention** — hardcoded variable name slaves must use, OR configurable per-congregation?
5. **Annex ownership semantics** — destructive (move, slave's `%soul = ()` after) OR copy (both sides keep)? Destructive matches the territorial-conquest meaning of "annex" and earns `lick`/`peruse` slots as the non-destructive alternatives.

### Project-Bar Check

**World's first leg:** A scriptable, in-language, single-keyword scatter-gather + distributed state harvest + secure-erase API for cooperating cluster processes does not exist as a language primitive anywhere. MPI is a C library requiring `mpirun`; Erlang has process groups but no destructive-harvest or peek/commit pair; Spark/Hadoop require cluster bootstrap and JVM; nothing in shell-language space comes close. The full vocab (especially the `lick`/`annex`/`smother` triple and the `chant`/`amen` continuous-rescatter pair) is genuinely empty territory.

**World's fastest leg:** TCP + bincode is fast enough for cluster scope. Parallel fanout (Rayon par_iter on the scatter) gets 100x over the existing serial controller `for pid in pids` pattern. SHM fast-path for same-host slaves can be added as v2 optimization.

**Both legs clear.** Each verb earns its slot on either world-first novelty (most of them) or paired ergonomic with a world-first verb (`amen` pairs with `chant`, `exhume` pairs with `enshrine`).

## What's Left to Examine?

Languages not yet fully mined for ideas:
- **Nim** — Compiles to C, macros, syntax
- **Zig** — Comptime, no hidden allocations
- **Crystal** — Ruby syntax, compiled
- **Raku** — Perl 6, grammars, hyperoperators
- **Red/Rebol** — Dialects, parse DSL
- **Factor** — Stack-based, quotations
- **Io** — Prototype-based, message passing
- **Smalltalk** — Everything is message send
- **OCaml** — Module system, functors
- **Racket** — Language-oriented programming

## Session Notes

This brainstorm came from the question: "What killer features do other languages have that Stryke can't touch?"

Original answer (2026-04-26): Not many. The main gap was Expect-style interactive automation — now closed.

Subsequent work (2026-04 → 2026-05) shipped the AI primitives surface (`ai`, MCP client/server, agents, vision/audio/image, multi-provider, citations, files API), the Rails-shaped web framework (`stryke_web` with full scaffold generator), the Cargo-shaped package manager (`s install/add/remove/update/outdated/audit/vendor/run/install -g/...` plus `[workspace]` member globbing), and **the full zsh glob qualifier set imported from zshrs** — every qualifier from `man zshexpn` (`(/)`, `(.)`, `(@)`, `(*)`, `(L±N)`, `(om[N])`, `(N)`, `(D)`, `(F)`, `(f<bits>)`, `(d<N>)`, `(e'CMD')`, `(P…)`, `(Q…)`, `(:s/…/…/)`, `^`, `-`, `,`) wired into every glob entry-point (`glob`, `glob_par`, `slurp`/`c`/`cat`, `pwatch`, `<…>`, `par_find_files`). World-first: no other scripting language has this. Each one was its own "world's first AND world's fastest in category" lever.

The polymorphic range system (10 types, forward/reverse, custom step) remains a world-first that no other language has.

## Guiding Principle

> "My secret is say buck the trend, what about this. Why stop at ints/chars. We can range on every imaginable item. It's rebellion."

Keep asking "why does this have limits?" instead of "how do I work within the limits?"
