jam — A Shell Built for AI

Every tool in the ecosystem runs through a shell. Every shell we have is broken. So we built one.


The Problem

Try to pass an LLM's output through sed. Try to nest quotes three levels deep. Try to write a command with a dollar sign that doesn't expand, a backslash that doesn't escape, a string that doesn't get mangled by the shell before it reaches the tool.

Every developer has lost hours to this. It was tolerable when humans typed every command. It is intolerable when AI generates them.

Traditional shells interpret text before passing it along. Dollar signs become variable expansions. Backslashes become escape sequences. Quotes require their own quoting. The shell sits between you and your tools and rewrites everything on the way through.

When AI generates commands — and it will, increasingly — those commands hit the same escaping minefield. The AI doesn't know the rules. It shouldn't have to.


Words Are Words

Everything is a word separated by whitespace. Quotes group words into strings — but nothing is interpreted inside them. No expansion. No escaping. No magic characters.

A dollar sign is a dollar sign. A backslash is a backslash. A string with quotes in it doesn't need quotes around its quotes. The shell is transparent plumbing. It gets out of the way.

🍞 echo "The price is $100" The price is $100 🍞 echo 'C:\Users\dirk\file.txt' C:\Users\dirk\file.txt

No surprises. Pipes work. Redirection works. Command chaining with && and || works. Semicolons separate commands. Everything a working shell needs, nothing it doesn't.

# pipes, chaining, redirection — all work cat server.log | grep ERROR | toast "summarize" make clean && make && make install ls -la > listing.txt

Numbers are numbers

When jam sees a line that starts with a number and contains only numbers and stack operations, it does RPN math. RPN (Reverse Polish Notation) puts operators after their operands instead of between them. It works with a stack. You push numbers on, and when you hit an operator, it pops the top two numbers, does the math, and pushes the result back. No parentheses needed, no order-of-operations ambiguity. That's why engineers, programmers, scientists, finance folks love RPN calculators. RPN may be a less intuitive input method but it is genuinely more efficient once you internalize it.

🍞 2 3 + 5 🍞 100 2 / 3 * 150 🍞 ? # push last exit status 0

Arithmetic lives in the shell without a subprocess, without bc, without awk. The full RPN vocabulary:

+ - * / mod dup drop swap over negate abs */ . .s cr ?

The ? word pushes the exit status of the last command onto the stack. Query the result of the previous pipeline without parsing $? — because there is no $.


The Fallback Chain

Every line you type goes through a decision chain:

1
Builtin? Run it. cd, pwd, exit, history, source, set, get, send, listen.
2
RPN expression? Evaluate it. Numbers and stack operations.
3
In PATH? Fork and exec. Standard Unix behavior.
4
None of the above? Send it to toastd.

That last step is the interesting one. jam connects directly to toastd over a Unix domain socket. Same protocol. Same authentication. Same connection pool. If toastd isn't running, the shell spawns it. No configuration. No flags.

The result: you type something the shell doesn't recognize, and instead of "command not found" you get an answer. The shell becomes the natural language interface. Not because we added a special mode. Because we made the AI the default fallback.

🍞 eixt Did you mean: exit 🍞 what processes are using port 8080 lsof -i :8080 🍞 how much disk space do I have left df -h

The shell understands intent, not just syntax.


Context Is Everything

jam maintains a .history file. Not just for up-arrow recall — for AI context. When a line falls through to toastd, the last fifty commands go with it as part of the system prompt. The AI knows what you've been doing. It knows your working directory. It knows what you tried and what failed.

The .history file walks up from the current working directory, just like .crumbs does for toast. Put a .history file in a project root and that project gets its own context. Different project, different history, different AI behavior. Per-project context with zero configuration.


Environment Variables

There is no $. A dollar sign is a dollar sign. So jam handles environment variables the way it handles everything else: explicitly, with words.

🍞 set OPENAI_API_KEY sk-abc123 🍞 get OPENAI_API_KEY sk-abc123

set calls setenv(). get calls getenv() and prints the value. No expansion syntax, no interpolation, no quoting around values with spaces — just words.

jam inherits all environment variables from whatever launched it. API keys set in .bashrc or .zshenv carry through. set is the escape hatch for per-session overrides.


Repetition

Two words handle loops. times for bounded repetition. while for unbounded.

🍞 5 times echo hello hello hello hello hello hello
🍞 while make test runs until make test fails 🍞 10 while make test same, but stops after 10 iterations

while runs a command until it returns a nonzero exit status. Prefix with a number for a hard cap. No braces, no do/done, no syntax. Just words.


The Network Bus

A shell runs on one machine. But AI agents run on many. Three linuxtoaster boxes running jam are three islands — unless they can talk to each other.

jam includes a UDP multicast bus. Two words: send and listen.

🍞 send status deploying # one UDP packet, multicast to every jam on the subnet

No broker. No server. No configuration. Fire and forget.

🍞 listen status web3:status deploying

listen joins the multicast group and blocks. With a key, it returns after the first match — pipeable. Without a key, it prints everything it hears. Output is hostname:key value.

This composes with everything else in the shell:

# AI agent that summarizes network events while listen | toast "summarize this event" # wait for 3 nodes to report ready 3 times listen ready

The multicast group defaults to 239.255.66.85:4242. TTL defaults to 1 — local subnet only. Override with set JAM_MCAST_TTL 5 to cross routers. The entire message fits in a single Ethernet frame.

The topology is simple. Same shell — environment variables. Same project — shared history. Same network — multicast. Each scope is a word. Each word composes with pipes.


Scripts

jam runs scripts. Shebang line, file argument, or piped input. Comments with # are ignored. The source builtin runs a script in the current shell context — cd sticks, history accumulates.

#!/usr/local/bin/jam # deploy script echo deploying && make clean && make && make install echo deployed || echo FAILED

No escaping gymnastics. No quoting nightmares. AI-generated scripts execute on the first try.


Technical Summary

Language C — single file, ~1,740 lines Dependencies readline (present on every Unix system) Build make Install make install Tokenizer No-escape string handling. Quotes group, nothing interprets. Pipes Full pipeline execution with file redirection (>, >>) Chaining &&, ||, ; — conditional and unconditional Arithmetic RPN stack interpreter, in-process, no subprocess History Persistent, per-project, readline integration, AI context AI AF_UNIX to toastd, autospawn, SHA-256 auth (embedded, no libsodium) Scripts Shebang, source/., comment stripping Environment set/get builtins, inherits from parent, no expansion Loops N times (bounded), while (until failure), N while (capped) Network UDP multicast bus — send/listen, zero-config agent coordination

The Foundation

jam is a block in the linuxtoaster toolkit. Like toast, like imessage — a C binary for communicating with Apple's iMessage — it's written in C. Single file. Minimal dependencies. Compiles anywhere. It follows the same pattern: do one thing, do it cleanly, compose with everything.

But it occupies a special position. Every other tool runs through the shell. When the shell handles text cleanly, every pipe in the ecosystem works better. When the shell understands natural language as a fallback, the entire toolkit becomes more accessible.

The shell is where text meets the operating system. For fifty years that boundary has been littered with escaping rules, quoting conventions, and special characters that exist only to work around the limitations of a 1970s design.

AI doesn't know those rules. It shouldn't have to.

What you type is what you get. What the AI generates executes on the first try. When you type something that isn't a command, the AI answers. And when you send a message, every jam on the network hears it.

The shell that doesn't escape. Put text in, get text out.