*muschel 0.1* — a Clojure(Script) library for parsing bash, gating it with an allow/deny permit, and running it through a pluggable host.
Built as the bash front-end for LLM agent shells: agents emit bash naturally, muschel walks the AST, classifies every call against your rules, and executes via a host you control. Same .cljc layer runs on JVM, babashka, and ClojureScript (Node + browser-with-virtual-fs).
A few things that might be interesting:
• Hand-written parser, no instaparse — sci-safe so it runs in bb without surgery
• Parse-time + runtime-hook permit check (catches $cmd args dynamic dispatch and lazy command substitution)
• Forkable sessions for multi-turn shells (atom default, optional spindel for time-travel)
• muschel.emit translates bash → idiomatic Clojure forms (`if` / reduce / loop / as->) — useful for "show me the Clojure equivalent" inspection in agent UIs
• npm + TypeScript types — usable from JS / TS, with a browser host that runs bash against a virtual fs and a virtual tool registry (no real spawn)
Try it:
• Browser playground: https://replikativ.github.io/muschel/playground/ (not yet working)
• GitHub: https://github.com/replikativ/muschel
• Clojars: org.replikativ/muschel {:mvn/version "0.1.1"}
• npm: npm install muschel
• babashka: bb exec "echo hi | tr a-z A-Z"
Built as part of the dvergr agentic-harness work. Early days, feedback welcome.
Playground is now working, and a wide range of shell tools are implemented in Clojure, including awk, sed etc.
cool, but how do i actually run the script.sh ?
This is a bug. sh -c 'echo nested' works, but not invoking it with a file.
Fixed.
hmm the first https://github.com/replikativ/muschel/tree/main#quickstart--clojure is just hanging my repl indefinitely (on jvm)
seems related to waiting on stdin somewhere. this works for me:
clojure -M -e "(require '[muschel.core :as m])
(let [host (m/builtin-host
{:fs (m/virtual-fs {\"/work/a.txt\" \"alpha\nbeta\n\"} {:cwd \"/work\"})
:fallback-host (m/jvm-host)})]
(println (m/run-and-capture (m/new-env) \"grep beta a.txt\" {:host host})))" < /dev/null
but without the /dev/null redirect it hangsShould be fixed with https://github.com/replikativ/muschel/pull/5
Oh yeah it works now with version 0.2.13 thanks!