myxo-lang 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CONCURRENCY.md +207 -0
  2. package/HOW_IT_WORKS.md +235 -0
  3. package/INDEPENDENCE.md +24 -0
  4. package/MYXO_PROMPT.md +139 -0
  5. package/README.md +494 -0
  6. package/ROADMAP.md +200 -0
  7. package/SPEC.md +181 -0
  8. package/VISION.md +249 -0
  9. package/builtins.js +361 -0
  10. package/command-fence.js +75 -0
  11. package/errors.js +45 -0
  12. package/examples/agent.myx +31 -0
  13. package/examples/fenced-agent.js +78 -0
  14. package/examples/fib.myx +11 -0
  15. package/examples/fibers.myx +57 -0
  16. package/examples/flow-routing.myx +12 -0
  17. package/examples/geo.myx +12 -0
  18. package/examples/hello.myx +2 -0
  19. package/examples/host.js +30 -0
  20. package/examples/james-myxo-demo.js +60 -0
  21. package/examples/living-mesh.myx +22 -0
  22. package/examples/match.myx +18 -0
  23. package/examples/mathlib.js +8 -0
  24. package/examples/mathlib.pl +11 -0
  25. package/examples/mathlib.py +23 -0
  26. package/examples/mcp-host.js +37 -0
  27. package/examples/nexus-mesh.myx +22 -0
  28. package/examples/nexus.myx +29 -0
  29. package/examples/ouroboros.myx +2 -0
  30. package/examples/outward-gate.myx +23 -0
  31. package/examples/physarum.myx +75 -0
  32. package/examples/polyglot-host.js +17 -0
  33. package/examples/polyglot.myx +11 -0
  34. package/examples/resilient.myx +28 -0
  35. package/examples/scheduler.myx +46 -0
  36. package/examples/the-law.myx +27 -0
  37. package/examples/use-geo.myx +9 -0
  38. package/format.js +206 -0
  39. package/interpreter.js +1092 -0
  40. package/lexer.js +173 -0
  41. package/mcp-bridge.js +77 -0
  42. package/mcp-framing.js +34 -0
  43. package/mcp-server.js +57 -0
  44. package/myxo-concurrent.js +110 -0
  45. package/myxo-live-worker.js +30 -0
  46. package/myxo-live.js +83 -0
  47. package/myxo-lsp.js +226 -0
  48. package/myxo-par-worker.js +39 -0
  49. package/myxo-plan.js +207 -0
  50. package/myxo-run.js +63 -0
  51. package/myxo.js +296 -0
  52. package/package.json +27 -0
  53. package/parser.js +662 -0
  54. package/polyglot-host.js +39 -0
  55. package/polyglot.js +191 -0
  56. package/receipt.js +71 -0
  57. package/std.myx +88 -0
  58. package/tools/memo-fuzz.js +224 -0
package/CONCURRENCY.md ADDED
@@ -0,0 +1,207 @@
1
+ # Myxo Concurrency — `dispatch` / `gather`
2
+
3
+ > Real multi-core parallelism, built on Myxo's own bones (the worker+Atomics pattern from `myxo-live`).
4
+ > Honest about its shape: this is **parallelism of pure-ish, isolated tasks** — not cooperative coroutines,
5
+ > not shared-memory threads. The isolation is the feature: it is what makes the parallelism race-free.
6
+
7
+ ## The model
8
+
9
+ ```
10
+ dispatch f(args...) -> an UNSTARTED task (a handle). Nothing runs yet.
11
+ gather [t1, t2, ...] -> runs every task on its own OS thread, in parallel,
12
+ blocks until all finish, returns their results IN ORDER.
13
+ ```
14
+
15
+ ```myx
16
+ agent slow(n) { seed s = 0
17
+ for each i in range(n) { s = s + (i % 7) }
18
+ report s
19
+ }
20
+
21
+ emit gather [dispatch slow(8000000), dispatch slow(8000000), dispatch slow(8000000)]
22
+ ```
23
+
24
+ `gather` is an ordinary expression — its result is a list, so it composes with everything: `gather tasks | sum`,
25
+ `seed [a, b] = gather [...]`, `match gather [...] { ... }`.
26
+
27
+ ## Why this shape (and not threads-with-shared-memory)
28
+
29
+ Myxo's law is *"agents do not merge."* Shared mutable state across threads is exactly merging — and the bug
30
+ factory (data races) that comes with it. So a dispatched task runs in **its own fresh interpreter**: it sees
31
+
32
+ - the **standard library**,
33
+ - **its own arguments**, and
34
+ - **itself** (so recursion works),
35
+
36
+ and **nothing else** — not the parent's pathways, not other user agents, not captured closure state. A task
37
+ that reaches for a parent pathway fails *cleanly* (`unknown pathway 'x'`) rather than silently reading a stale
38
+ copy. Isolation by construction means there is no shared state to race on. That is the whole trick.
39
+
40
+ The cost of isolation is the **data boundary**: arguments and results cross threads *by value*, so they must be
41
+ plain data — `number`, `string`, `bool`, `list`, `mesh`, `void`. Passing or returning an **agent** (code closes
42
+ over an environment that cannot follow it across the boundary) is rejected loudly at the boundary, never shipped
43
+ as a meaningless blob.
44
+
45
+ ## How it works (the mechanism is ours)
46
+
47
+ The interpreter is a synchronous tree-walker, and we keep it that way. `gather` gets parallelism without going
48
+ async by reusing the zero-dependency **worker + `Atomics` + `SharedArrayBuffer`** pattern already proven in
49
+ `myxo-live`:
50
+
51
+ 1. `gather` spawns one `Worker` (`myxo-par-worker.js`) per task, handing each the agent's AST (`params` + `body`)
52
+ and its args as JSON, plus one shared `Int32Array` barrier counter and a private `MessageChannel`.
53
+ 2. Each worker builds a fresh interpreter, defines the agent under its own name (recursion), runs it, then in a
54
+ `finally` — on *every* path, success or error — posts its result (or its error) and `Atomics.add`s the
55
+ barrier counter and notifies. Posting before ticking means a visible tick guarantees the message is queued.
56
+ 3. The calling thread blocks on `Atomics.wait` until the counter reaches N (Node permits `Atomics.wait` on the
57
+ main thread; browsers do not). It then drains each channel with `receiveMessageOnPort` and returns the
58
+ results in input order. Workers and ports are always reclaimed in a `finally`, even on throw or timeout.
59
+
60
+ **Error handling, precisely.** A task that `fail`s, throws, hits a runtime error (e.g. reaches for a parent
61
+ pathway), or fails to even load its interpreter surfaces *promptly* as a single `gather: <message>` error —
62
+ because the worker runs its barrier-tick from a `finally`, so any worker that executes *any* JS reports back.
63
+ The first error wins; the whole `gather` fails (all-or-nothing, like `Promise.all`). The one case the worker
64
+ *can't* self-report is a true hard death (OOM, `SIGKILL`) where the `finally` never runs — that is caught by
65
+ the wall-clock timeout (default 30s), which terminates the stragglers and throws a `timed out` error. (We do
66
+ *not* rely on a parent-side `error`/`exit` callback to release the barrier: the event loop is frozen during
67
+ `Atomics.wait`, so those callbacks can't fire mid-gather — they exist only so a worker failure can't crash the
68
+ parent process.)
69
+
70
+ ## What is honest about the performance
71
+
72
+ Measured on the dev laptop (i7-8750H, 6 physical / 12 logical cores, ~2GB free RAM):
73
+
74
+ - **The interpreter runs at native speed inside a worker.** Pure compute, startup excluded: main 4.70s vs
75
+ worker 4.65s for the same loop. There is *no* per-worker interpreter penalty.
76
+ - **Parallelism is real.** Two CPU-bound tasks complete in ~1.05x the time of one (18.5s vs 17.4s) — two tasks
77
+ for the price of one.
78
+ - **Speedup is bounded by the machine, not the language.** 4 tasks do **not** hit 4x on this box, because of
79
+ (a) only 6 physical cores, (b) ~2GB free RAM (large allocations like `range(8_000_000)` thrash), and
80
+ (c) aggressive thermal throttling under sustained all-core load. On a cooler, higher-core machine the curve
81
+ keeps climbing.
82
+ - **Worker startup is ~0.2s** (a fresh interpreter + stdlib parse) and overlaps across workers. Parallelize
83
+ *expensive* work; for trivial work the startup dominates.
84
+
85
+ ## Limits (v1, on purpose)
86
+
87
+ - **One worker per task per gather** (no pool yet). Fine for coarse-grained work; a pool is a future optimization.
88
+ - **Tasks are isolated** — no shared state, no inter-task channels. Coordination is by *structure* (dispatch →
89
+ gather), not by message-passing between running tasks.
90
+ - **Self-contained agents only.** Calling *other* user agents from inside a dispatched agent fails (they are not
91
+ defined in the worker). Inline what the task needs, or pass it as data.
92
+ - **Not cooperative concurrency.** There is no `yield`/await; this is OS-thread parallelism with a blocking
93
+ barrier. A cooperative scheduler is a separate, later layer (and the road toward the Physarum scheduler).
94
+
95
+ ---
96
+
97
+ # The Physarum scheduler — `schedule` / `flows`
98
+
99
+ > Where `gather` runs a fixed list of tasks, `schedule` runs a **batch through a learning pool**. It is `route`
100
+ > (the slime-mold *selector*) lifted to parallel batches: the same reinforce/decay law that governs memory now
101
+ > governs **execution** — fast workers pull more flux, slow/failed ones decay and get routed around. The
102
+ > language *becomes* the scheduler.
103
+
104
+ ```myx
105
+ agent worker(chunk) { # a worker takes a CHUNK (a list) and returns a results list, same length, in order
106
+ seed out = []
107
+ for each x in chunk { out = out + [x * x] }
108
+ report out
109
+ }
110
+
111
+ emit schedule("squares", [worker, worker], [1, 2, 3, 4, 5, 6, 7, 8]) # -> [1, 4, 9, 16, 25, 36, 49, 64]
112
+ emit flows("squares") # the learned conductance of each tube
113
+ ```
114
+
115
+ ## What it does
116
+
117
+ `schedule(name, workers, items)`:
118
+ 1. Looks up (or creates) a **named, persistent pool** of interchangeable worker-agents — `name` keys the learned
119
+ state, exactly like `route`. Reusing a name with different workers is rejected (no silent stale pool).
120
+ 2. **Distributes** the items across the workers proportional to conductance, via the same credit + explore-floor
121
+ weighted round-robin as `route`. The credit array is **persisted on the pool** across calls, so a trailing or
122
+ recovered worker is sampled at a rate ∝ its conductance over successive batches (not starved by small batches).
123
+ 3. Runs each worker's chunk on its **own worker thread, in parallel** (`gather`'s settled runner underneath),
124
+ blocks, and reassembles every result at its **original item index**.
125
+ 4. Updates each worker's conductance from its **measured per-item speed** (the worker reports its own compute
126
+ time): `quality = 1 + 8/(ms_per_item + 1)`, `cond ← EWMA(cond, quality)`. Fast workers climb; a worker that
127
+ errors decays toward the floor.
128
+
129
+ `flows(name)` returns the pool's learned conductances (it also reports `route` conductances — one viewer for both).
130
+
131
+ ## Failover
132
+
133
+ If a worker errors, its conductance decays hard and **its items reroute to the survivors** in one more parallel
134
+ round — the slime mold routing around a damaged tube. If every worker fails (or a survivor also fails during the
135
+ reroute), `schedule` throws rather than returning partial/silent results. Failover is **single-tier on purpose**:
136
+ one reroute round, then surface the error. (A multi-tier cascade is a future option; one tier covers the common
137
+ "some tubes are dead" case without unbounded retry.)
138
+
139
+ ## What is honest about it
140
+
141
+ - **Adaptation needs more than one call.** The first batch explores (uniform-ish); conductances diverge as speed
142
+ is measured, so *later* batches exploit. Measured: a fast/slow pool over 4 rounds converged to roughly
143
+ `{fast: 7, slow: 1}` — the next batch then routes ~7× the flux to the fast tube. Same explore-then-exploit
144
+ honesty as `route`; the constants are hand-tuned and exploit-leaning.
145
+ - **Timing is nondeterministic**, so exact conductances vary run to run. The guarantees that *don't* vary:
146
+ every item is processed exactly once, results are in item order, and a clearly-faster worker ends higher.
147
+ - **Worker contract:** batch in, batch out (`worker(chunk) -> results`, one result per item, in order). This
148
+ spawns *N* threads (one per worker), not one per item — efficient for real batches. A wrong-length or non-list
149
+ return is a loud contract error. The `dispatch` data boundary applies: items and results must be plain data.
150
+ - **No shared state between workers** (same isolation as `gather`) — which is exactly why distributing work
151
+ across them is race-free.
152
+
153
+ ---
154
+
155
+ # Cooperative concurrency — fibers + channels (`spawn` / `give` / `take` / `yield` / `await`)
156
+
157
+ > Where `gather`/`schedule` give **parallelism** (many OS threads, isolated tasks), fibers give the other half:
158
+ > **concurrency** — many tasks interleaving on *one* thread, talking through **channels**. It's the
159
+ > law-consistent way to do *communicating* tasks: no shared memory, the value passes hand to hand.
160
+
161
+ ```myx
162
+ seed ch = channel() # an unbounded channel; channel(n) is bounded (backpressure)
163
+
164
+ agent producer(c) { seed i = 0
165
+ reinforce i < 3 { give i to c # `give VALUE to CHANNEL` — blocks only if a bounded channel is full
166
+ i = i + 1 } }
167
+
168
+ agent consumer(c) { seed k = 0
169
+ reinforce k < 3 { take x from c # `take NAME from CHANNEL` — parks the fiber until a value arrives
170
+ emit x
171
+ k = k + 1 } }
172
+
173
+ spawn producer(ch) # start a fiber (cooperative, NOT a thread)
174
+ spawn consumer(ch) # both run, interleaved, at program end -> 0 1 2
175
+ ```
176
+
177
+ ## The model
178
+
179
+ - `spawn f(args)` — start a **fiber** and return a handle. Fibers run **cooperatively** on the calling thread:
180
+ one runs until it parks on a channel (or `yield`s), then the scheduler runs the next ready fiber. This is
181
+ *concurrency, not parallelism* — for real multi-core work use `gather`/`schedule`.
182
+ - `give VALUE to CHANNEL` / `take NAME from CHANNEL` — send / receive. A `take` on an empty channel parks the
183
+ fiber until a value is given; a `give` to a *full bounded* channel parks until space frees. Delivery is
184
+ **exactly-once, FIFO**.
185
+ - `yield` — voluntarily give up the turn (cooperative round-robin).
186
+ - `await(fiber)` — run the scheduler and return that fiber's reported value (or re-raise its error). `drain()` —
187
+ run **all** fibers to completion. Spawned-but-unawaited fibers also run at program end; a failed fiber's error
188
+ **never vanishes** — it surfaces at `await`/`drain`/program end.
189
+ - `channel()` unbounded; `channel(n)` bounded to `n` (backpressure). Channels are not data — they can't cross the
190
+ `gather`/`dispatch` thread boundary (rejected loudly).
191
+
192
+ ## Why it's race-free
193
+
194
+ A channel is the *only* thing shared, and a value moves through it hand to hand — there is no shared mutable
195
+ state for two fibers to clobber. The scheduler is single-threaded and **deterministic**, so a fiber program's
196
+ output is reproducible (unlike the timing-dependent parallel side).
197
+
198
+ ## Honest scope (v1)
199
+
200
+ - **Cooperative, not parallel** — fibers interleave on one thread. (Compose with `gather` when you need cores.)
201
+ - **Suspension composes through** the fiber's own body and inside `when` / `match` / `for each` / `reinforce` /
202
+ `attempt`. It does **not** cross into a *called* agent's body (a helper a fiber calls can't `give`/`take`) — that
203
+ would need the whole call stack to be suspendable. Doing so is a **clear, honest error**, not a silent failure.
204
+ - `await`/`drain` can't be called from *inside* a fiber (that would re-enter the scheduler) — coordinate with
205
+ channels or `yield` instead; a clean error says so.
206
+ - A runaway fiber (e.g. `yield` forever) is bounded by a step budget and **errors**, never hangs.
207
+ - No `select`/timeouts/closeable channels yet; deadlocks (everyone parked) are detected and reported.
@@ -0,0 +1,235 @@
1
+ # How Myxo Works
2
+
3
+ Myxo has two jobs:
4
+
5
+ 1. Be an independent language with its own source files, runtime behavior, standard library,
6
+ tooling, and release path.
7
+ 2. Connect useful external runtimes through fenced capabilities: rich bridges for runtimes like
8
+ Python and Node, conditional bridges such as Perl when installed, and weaker executable/CLI
9
+ bridges for compiled tools like C++, Rust, and Go binaries.
10
+
11
+ Those jobs are separate on purpose. Myxo can run by itself. Foreign languages extend it; they do
12
+ not define it.
13
+
14
+ ## 1. The Standalone Language Core
15
+
16
+ A `.myx` program is real Myxo source. It is not translated into Python or C++ first.
17
+
18
+ ```text
19
+ .myx source
20
+ -> lexer.js
21
+ -> parser.js
22
+ -> AST
23
+ -> interpreter.js
24
+ -> output + value + audit ledger
25
+ ```
26
+
27
+ Current implementation:
28
+
29
+ - `lexer.js` tokenizes Myxo source.
30
+ - `parser.js` builds the AST.
31
+ - `interpreter.js` walks the AST and enforces Myxo semantics.
32
+ - `builtins.js` installs the core standard functions.
33
+ - `std.myx` is a self-hosted standard library written in Myxo.
34
+ - `myxo.js` is the CLI, REPL, formatter entrypoint, and Node embed API.
35
+
36
+ That means these are Myxo language behavior, not aliases over another runtime:
37
+
38
+ - `seed` creates a pathway.
39
+ - `agent` defines a callable Myxo function.
40
+ - `report` returns from an agent.
41
+ - `reinforce` loops.
42
+ - `decay` removes a pathway.
43
+ - `attempt` / `rescue` handle failures.
44
+ - `needs` declares external capabilities.
45
+ - pathway strength rises when names are read.
46
+ - routing and mesh behavior live in the interpreter.
47
+
48
+ The reference engine is currently written in Node. That is an implementation fact, not the
49
+ language identity. The independence path is to keep this Node tree-walker as the reference
50
+ while tightening a spec and eventually adding bytecode/native or other host runtimes.
51
+
52
+ ## 2. Values And Execution
53
+
54
+ Myxo values are intentionally small and portable:
55
+
56
+ - numbers
57
+ - strings
58
+ - `live` / `dead`
59
+ - `void`
60
+ - lists
61
+ - meshes
62
+ - agents
63
+
64
+ The interpreter stores named values in environments. A named value is a pathway. Reading a
65
+ pathway reinforces it by increasing its strength. `mesh()`, `strength(name)`, `prune()`, and
66
+ `metabolize()` expose that behavior to Myxo code.
67
+
68
+ Agents are closures over their environment. The runtime can hot-promote pure agents by memoizing
69
+ calls it can prove safe: plain parameters, primitive arguments/results, no capabilities, no
70
+ observable side effects, no mutable outer-data dependency, and no stale global epoch.
71
+
72
+ ## 3. Builtins vs Capabilities
73
+
74
+ Myxo has a hard distinction:
75
+
76
+ - **Builtins** are ordinary language power: math, strings, lists, meshes, output, routing.
77
+ - **Capabilities** are host power: database calls, Telegram, Python, C++ binaries, shell,
78
+ MCP tools, filesystem module loading, or anything outside the interpreter.
79
+
80
+ A capability does not exist inside a script unless the host registers it.
81
+
82
+ Even if the host registers it, production runners can require the script to declare it:
83
+
84
+ ```myx
85
+ needs lookup, spend(max 5, total 15)
86
+
87
+ emit lookup("lead")
88
+ emit spend(4)
89
+ ```
90
+
91
+ The production fence is:
92
+
93
+ ```text
94
+ host allowlist
95
+ -> script `needs` manifest
96
+ -> value budget checks
97
+ -> call execution
98
+ -> audit ledger
99
+ ```
100
+
101
+ If a script calls a capability it did not declare, Myxo refuses before the host is touched. Every
102
+ allowed call and every refusal is recorded in the audit ledger.
103
+
104
+ Production runners also add operational limits:
105
+
106
+ - `requireManifest`: capability calls require `needs`.
107
+ - `maxSteps`: interpreter fuel for runaway loops.
108
+ - `timeoutMs`: live worker wall-clock timeout.
109
+ - `moduleLoader: null`: fences `weave` unless the host grants file loading.
110
+
111
+ ## 4. Polyglot: How Python, C++, And Others Plug In
112
+
113
+ Polyglot support is foreign-function interface, not identity.
114
+
115
+ Myxo sees every foreign language call as a capability:
116
+
117
+ ```myx
118
+ needs pycall(total 3)
119
+
120
+ seed result = pycall("tools.py", "score", "lead-17")
121
+ emit result
122
+ ```
123
+
124
+ The outer Myxo law is the same whether the capability is implemented in Myxo, Python, C++, Node, or
125
+ a remote tool:
126
+
127
+ ```text
128
+ Myxo script -> capability name -> host bridge -> foreign runtime -> Myxo value
129
+ ```
130
+
131
+ ### Rich Runtime Bridge
132
+
133
+ `polyglot.js` currently has rich value-mapped runners for:
134
+
135
+ - Python: `pycall`, `pyeval`
136
+ - Node: `jscall`, `jseval`
137
+ - Perl: `plcall`, `pleval` when Perl is installed
138
+
139
+ These runners use a JSON/framed-result protocol so lists, meshes, numbers, strings, booleans,
140
+ and `void` can cross the boundary cleanly. Non-finite numbers are rejected instead of silently
141
+ becoming null. In the current machine test run, Python and Node passed; Perl support is present
142
+ but skips when `perl` is not on PATH.
143
+
144
+ ### Compiled/CLI Bridge
145
+
146
+ C++, Rust, Go, and many existing tools usually plug in first as compiled executables:
147
+
148
+ ```text
149
+ Myxo -> bridgeExec("my_tool.exe") -> argv/stdout -> Myxo string
150
+ ```
151
+
152
+ That is intentionally weaker than the rich bridge:
153
+
154
+ - stdout is the result
155
+ - structured values need JSON discipline from the executable
156
+ - Myxo can still fence, budget, and audit the call boundary
157
+
158
+ The stronger future version is a stable Myxo FFI/wire protocol so compiled languages can expose
159
+ structured functions instead of only command-line stdout.
160
+
161
+ ## 5. MCP And JAMES Are Hosts, Not The Language
162
+
163
+ MCP tools are another capability catalog. `mcp-bridge.js` turns each MCP tool into a fenced Myxo
164
+ capability. `myxo-run.js` and `myxo-live.js` are production runners for agent-written scripts.
165
+
166
+ JAMES uses this by exposing a narrow `james_nx_run` surface. That is one host integration. Myxo
167
+ must still work without JAMES:
168
+
169
+ ```text
170
+ node myxo.js examples/fib.myx
171
+ node myxo.js
172
+ node myxo.js fmt examples/fib.myx --check
173
+ npm test
174
+ ```
175
+
176
+ ## 6. Security Boundary
177
+
178
+ The fence controls which verb a script may call, how often or how much it may spend, and what
179
+ gets logged at the Myxo boundary.
180
+
181
+ The fence does **not** sandbox the code inside a granted arbitrary runtime.
182
+
183
+ If you grant:
184
+
185
+ - `pyeval`, the script has Python eval power.
186
+ - `jseval`, the script has Node eval power.
187
+ - `sh`, the script has shell power.
188
+ - a C++ executable, the script can run that executable.
189
+
190
+ Budgets are argument and call-count policies. They are not CPU, filesystem, network, or
191
+ subprocess sandboxes for whatever happens inside the granted runtime.
192
+
193
+ For untrusted or model-generated scripts, expose shaped capabilities instead:
194
+
195
+ ```text
196
+ good: score_lead(id)
197
+ bad: pyeval(any_code)
198
+ good: resize_image(input, output)
199
+ bad: sh(any_command)
200
+ ```
201
+
202
+ That is where Myxo is strongest: it gives agents narrow verbs, budgets, time/fuel limits, and an
203
+ audit trail.
204
+
205
+ ## 7. The Short Version
206
+
207
+ Myxo should become "another Python/C++" in independence, not in purpose.
208
+
209
+ It should own:
210
+
211
+ - `.myx` files
212
+ - syntax and semantics
213
+ - runtime behavior
214
+ - standard library
215
+ - CLI and REPL
216
+ - tests and formatter
217
+ - docs and spec
218
+ - release path
219
+
220
+ It should connect:
221
+
222
+ - Python for Python work
223
+ - C++/Rust/Go binaries for compiled work
224
+ - Node for JS work
225
+ - MCP/JAMES/tools for system work
226
+
227
+ The point is one independent language that can coordinate many runtimes under one law:
228
+
229
+ ```text
230
+ declare what you need
231
+ stay inside the budget
232
+ leave an audit trail
233
+ route to the best provider
234
+ run standalone when no foreign runtime is needed
235
+ ```
@@ -0,0 +1,24 @@
1
+ # Myxo Independence Contract
2
+
3
+ Myxo must be a real language, not only a wrapper around other languages.
4
+
5
+ The target is this:
6
+
7
+ - **Standalone first.** A `.myx` program runs as Myxo source through the Myxo CLI/runtime/stdlib without requiring Python, C++, Node scripts, shell glue, or JAMES.
8
+ - **Own semantics.** `seed`, `agent`, `reinforce`, `decay`, `needs`, budgets, audit ledger, pathway strength, and flow routing are Myxo language behavior, not comments over another runtime.
9
+ - **Own toolchain.** Myxo needs a CLI, REPL, formatter, tests, docs, versioning, module rules, errors, and eventually an LSP/debugger and bytecode/native runtime path.
10
+ - **Foreign runtimes are FFI.** Python, Node, Perl, shell, MCP, and compiled binaries such as C++/Rust/Go tools are called through explicit fenced capabilities. They extend Myxo; they do not define Myxo.
11
+ - **One outer law at the boundary.** Whether a capability is written in Myxo, Python, C++, or anything else, the Myxo caller still goes through `needs`, host allowlists, budgets, fuel/timeouts where applicable, and the audit ledger. Myxo does not sandbox arbitrary side effects inside a granted runtime; hosts should expose narrow structured verbs for untrusted callers.
12
+ - **No hidden dependency on Nexus.** Nexus/JAMES can host Myxo, but Myxo must remain usable by itself from the command line and embeddable by other hosts.
13
+
14
+ ## What "another Python/C++" means here
15
+
16
+ Myxo should become a peer in the toolchain: a language someone can install, run, learn, test,
17
+ package, and ship. It does not need to replace Python for data scripting or C++ for systems
18
+ performance. It needs to be independent the way they are independent: it owns a file format,
19
+ runtime, standard library, behavior, documentation, and release path.
20
+
21
+ ## Boundary
22
+
23
+ Polyglot bridging is still core. Myxo connects the useful languages, but as a conductor with its
24
+ own score, not as a thin alias for any one of them.
package/MYXO_PROMPT.md ADDED
@@ -0,0 +1,139 @@
1
+ # Myxo — write this language (prompt card)
2
+
3
+ Myxo is a small scripting language. You will be given a task; return ONLY Myxo code. Myxo is NOT Python, NOT
4
+ JavaScript, NOT C — do not assume their syntax. Learn it from the rules and examples below, then write.
5
+
6
+ ## The 6 rules you must not break
7
+
8
+ 1. **NO SEMICOLONS. EVER.** Statements end at the end of the line — never write `;`. `seed x = 1` then a
9
+ newline. A `;` is a syntax error.
10
+ 2. **Booleans are `live` and `dead`** — never `true`/`false`. `report live`, `when x { ... }`.
11
+ 3. **Functions are `agent`s; return with `report`.** `agent add(a, b) { report a + b }`. No `function`, no
12
+ `def`, no `return`, no `=>` for statements.
13
+ 4. **Declare a variable with `seed`, reassign with plain `=`.** `seed n = 0` then later `n = n + 1`.
14
+ 5. **`==` on two lists or two meshes compares IDENTITY, not contents** — `[1,2] == [1,2]` is `dead`. Compare
15
+ length + elements yourself. (Inside `match`/`expect`, equality IS structural.)
16
+ 6. **Mesh keys are strings.** `{ "a": 1 }`. The number `1` and the string `"1"` are the SAME key.
17
+
18
+ ## Core syntax by example (imitate these)
19
+
20
+ ```myx
21
+ # variables, agents, report
22
+ seed name = "Zero"
23
+ agent greet(who) { report "hi " + who }
24
+
25
+ # conditionals — `when` / `otherwise`, blocks in { }
26
+ agent sign(n) {
27
+ when n > 0 { report "pos" }
28
+ otherwise when n < 0 { report "neg" }
29
+ otherwise { report "zero" }
30
+ }
31
+
32
+ # loop over a list, mesh (keys), or string (chars)
33
+ agent total(xs) {
34
+ seed s = 0
35
+ for each x in xs { s = s + x }
36
+ report s
37
+ }
38
+
39
+ # while-loop is `reinforce COND { }`; repeat is `reinforce N times { }`
40
+ agent countdown(n) {
41
+ reinforce n > 0 { emit n n = n - 1 }
42
+ }
43
+
44
+ # lists and meshes
45
+ seed nums = [1, 2, 3]
46
+ seed person = { "name": "Zero", "age": 30 }
47
+ emit person["name"] # index a mesh by key, a list by integer (negatives from end: xs[0-1] = last)
48
+ seed longer = nums + [4] # + concatenates two lists; + concatenates if EITHER side is a string
49
+ seed n = len(nums) # len works on list/mesh/string
50
+
51
+ # default + rest params, and closures
52
+ agent log(msg, level = "info", ...rest) { report level + ": " + msg }
53
+ agent adder(k) { report agent(x) { report x + k } } # returns a closure
54
+
55
+ # pattern matching — `match` (first arm whose shape fits runs)
56
+ agent describe(v) {
57
+ match v {
58
+ [] { report "empty" }
59
+ [x] { report "one" }
60
+ { "kind": k } { report k } # mesh that HAS key "kind"; binds k
61
+ _ { report "other" } # wildcard
62
+ }
63
+ }
64
+
65
+ # errors — attempt / rescue, and fail
66
+ agent safe_div(a, b) {
67
+ attempt { report a / b } rescue e { report "undefined" } # e is a mesh { message, line, value }
68
+ }
69
+
70
+ # pipeline: x | f == f(x) ; x | f(a) == f(x, a) (piped value is the FIRST arg)
71
+ agent inc(x) { report x + 1 }
72
+ seed y = 5 | inc | inc # 7
73
+ ```
74
+
75
+ ## Truthiness & and/or (these trip up Python/JS habits)
76
+
77
+ - **Dead (falsy):** `void`, `0`, `""`, empty list `[]`, empty mesh `{}`. Everything else is live.
78
+ - **`and`/`or` return a VALUE, not a bool** (and short-circuit): `a or b` → `a` if `a` is live, else `b`.
79
+ So `x or default` gives a fallback. `a and b` → `a` if `a` is dead, else `b`.
80
+
81
+ ```myx
82
+ agent with_default(v, fallback) { report v or fallback } # 0/""/[] all fall back, not just void
83
+ ```
84
+
85
+ ## The capability fence (only when the task mentions natives / a manifest / budgets)
86
+
87
+ A script reaches the host ONLY through granted natives, and must DECLARE them with `needs` at the top.
88
+
89
+ ```myx
90
+ needs lookup, spend(max 5, total 15) # spend is budgeted: max per call, total cumulative
91
+
92
+ seed r = lookup("x")
93
+ emit "got: " + r
94
+ attempt {
95
+ spend(9) # over the max-5 cap -> the fence refuses it
96
+ emit "spent"
97
+ } rescue e {
98
+ emit "blocked" # a fence denial is catchable like any error
99
+ }
100
+ ```
101
+
102
+ Calling a native you did not `needs`-declare is refused even if the host granted it.
103
+
104
+ ## Concurrency (only when the task asks for parallel / fibers / channels)
105
+
106
+ ```myx
107
+ # parallel: dispatch builds a task, gather runs them on real threads, results in order
108
+ agent sq(n) { report n * n }
109
+ agent squares(xs) {
110
+ seed tasks = []
111
+ for each x in xs { tasks = tasks + [dispatch sq(x)] }
112
+ report gather tasks
113
+ }
114
+
115
+ # fibers + channels (one thread, cooperative): spawn / give..to / take..from / await
116
+ agent producer(c, xs) { for each x in xs { give x to c } }
117
+ agent consumer(c, n) { seed s = 0 reinforce n times { take v from c s = s + v } report s }
118
+ agent sum_via_channel(xs) {
119
+ seed ch = channel()
120
+ spawn producer(ch, xs)
121
+ seed job = spawn consumer(ch, len(xs))
122
+ report await(job)
123
+ }
124
+ ```
125
+
126
+ ## The 5 traps (right vs wrong)
127
+
128
+ | Trap | WRONG (a Python/JS habit) | RIGHT (Myxo) |
129
+ |---|---|---|
130
+ | Semicolons | `seed x = 1;` | `seed x = 1` (newline ends it) |
131
+ | Booleans | `report true` | `report live` |
132
+ | List equality | `report a == b` | compare `len` + each element in a loop |
133
+ | Mesh keys collide | assuming `1` ≠ `"1"` as keys | they are the SAME key (keys coerce to strings) |
134
+ | Fallback only on null | `when v == void { ... }` | `v or fallback` (0/""/[] are also dead) |
135
+
136
+ ## How to answer
137
+
138
+ Return ONE ```myx code block. Define exactly the agent(s) the task names — no extra prose, no `main`, no
139
+ semicolons. Prefer the patterns above; when unsure, keep it simple and let `report` return the value.