Smithery Logo
MCPsSkillsDocsPricing
Login
NewFlame, an assistant that learns and improves. Available onTelegramSlack
    hugoduncan

    babashkaprocess

    hugoduncan/babashkaprocess
    Coding
    3

    About

    SKILL.md

    Install

    • Telegram
      Telegram
    • Slack
      Slack
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    • Download skill
    ├─
    ├─
    └─
    Smithery Logo

    Give agents more agency

    Resources

    DocumentationPrivacy PolicySystem Status

    Company

    PricingAboutBlog

    Connect

    © 2026 Smithery. All rights reserved.

    About

    Clojure library for spawning sub-processes and shell operations

    SKILL.md

    babashka.process

    A Clojure library for shelling out and spawning sub-processes. Wraps java.lang.ProcessBuilder with an ergonomic API supporting pipelines, streaming I/O, and process control.

    Overview

    babashka.process provides two main entry points:

    • shell - High-level convenience function with sensible defaults
    • process - Low-level function for fine-grained control

    Included in Babashka since v0.2.3. Also usable as a JVM library.

    Repository: https://github.com/babashka/process

    Installation

    ;; deps.edn
    {:deps {babashka/process {:mvn/version "0.6.25"}}}
    

    Built into Babashka - no installation needed for bb scripts.

    Core Concepts

    shell vs process

    Aspect shell process
    Blocking Yes No (returns immediately)
    Exit check Throws on non-zero No checking
    I/O default :inherit (console) Streams
    Tokenization Auto-tokenizes first arg Manual

    Use shell for simple commands. Use process for pipelines, streaming, or async operations.

    Process Records

    Both functions return a record containing:

    • :proc - java.lang.Process instance
    • :in - Input stream (stdin)
    • :out - Output stream (stdout)
    • :err - Error stream (stderr)
    • :cmd - Command vector
    • :prev - Previous process (pipelines)

    Dereferencing (@ or deref) waits for completion and adds :exit.

    API Reference

    shell

    High-level function for running external programs.

    (require '[babashka.process :refer [shell]])
    
    ;; Basic usage - tokenizes automatically
    (shell "ls -la")
    
    ;; Multiple arguments
    (shell "git" "commit" "-m" "message")
    
    ;; With options
    (shell {:dir "src"} "ls")
    
    ;; Capture output
    (-> (shell {:out :string} "echo hello") :out)
    ;; => "hello\n"
    
    ;; Continue on error (don't throw)
    (shell {:continue true} "ls nonexistent")
    

    Options:

    • :continue - Don't throw on non-zero exit
    • All process options supported

    process

    Low-level function with no opinionated defaults.

    (require '[babashka.process :refer [process]])
    
    ;; Returns immediately
    (def p (process "sleep" "5"))
    
    ;; Deref to wait and get exit code
    (:exit @p)
    
    ;; Capture output
    (->> (process {:out :string} "ls") deref :out)
    

    check

    Wait for process and throw on non-zero exit.

    (require '[babashka.process :refer [process check]])
    
    ;; Throws if ls fails
    (->> (process {:out :string} "ls") check :out)
    
    ;; Chain with process
    (-> (process "make") check)
    

    sh

    Convenience wrapper defaulting :out and :err to :string.

    (require '[babashka.process :refer [sh]])
    
    (sh "ls" "-la")
    ;; => {:exit 0 :out "..." :err ""}
    

    $

    Macro for shell-like syntax with interpolation.

    (require '[babashka.process :refer [$]])
    
    (def file "README.md")
    ($ ls -la ~file)
    
    ;; With options via metadata
    (^{:out :string} $ echo hello)
    

    tokenize

    Split string into argument vector.

    (require '[babashka.process :refer [tokenize]])
    
    (tokenize "ls -la")
    ;; => ["ls" "-la"]
    
    (tokenize "echo 'hello world'")
    ;; => ["echo" "hello world"]
    

    alive?

    Check if process is running.

    (require '[babashka.process :refer [process alive?]])
    
    (def p (process "sleep" "10"))
    (alive? p) ;; => true
    

    destroy / destroy-tree

    Terminate process. destroy-tree also kills descendants (JDK9+).

    (require '[babashka.process :refer [process destroy destroy-tree]])
    
    (def p (process "sleep" "100"))
    (destroy p)
    
    ;; Kill process and all children
    (destroy-tree p)
    

    exec

    Replace current process image (GraalVM/Babashka only).

    (require '[babashka.process :refer [exec]])
    
    ;; Replaces bb process with ls
    (exec "ls" "-la")
    

    pb / pipeline

    Create process builders for pipelines.

    (require '[babashka.process :refer [pb pipeline]])
    
    ;; JDK9+ pipeline
    (-> (pipeline (pb "cat" "file.txt")
                  (pb "grep" "pattern")
                  (pb "wc" "-l"))
        last
        deref
        :out
        slurp)
    

    Options Reference

    I/O Options

    Option Values Description
    :in stream, string, :inherit Stdin source
    :out :string, :bytes, :inherit, :write, :append, file Stdout destination
    :err Same as :out, plus :out to merge Stderr destination
    :in-enc charset Input encoding
    :out-enc charset Output encoding
    :err-enc charset Error encoding

    Process Options

    Option Description
    :dir Working directory
    :env Replace environment (map)
    :extra-env Add to environment (map)
    :inherit If true, inherit all streams
    :cmd Command vector (overrides args)
    :prev Previous process for piping

    Hooks

    Option Description
    :pre-start-fn Called before start with process info
    :shutdown Called when child process ends
    :exit-fn Called on exit (JDK11+)

    Common Patterns

    Capture Output

    ;; As string
    (-> (shell {:out :string} "date") :out str/trim)
    
    ;; As bytes
    (-> (shell {:out :bytes} "cat" "image.png") :out)
    
    ;; Merge stderr into stdout
    (shell {:err :out :out :string} "cmd")
    

    Working Directory

    (shell {:dir "/tmp"} "ls")
    

    Environment Variables

    ;; Add to environment
    (shell {:extra-env {"DEBUG" "1"}} "./script.sh")
    
    ;; Replace environment
    (shell {:env {"PATH" "/usr/bin"}} "ls")
    

    Piping Processes

    ;; Using threading
    (->> (process "cat" "file.txt")
         (process {:out :string} "grep" "pattern")
         deref
         :out)
    
    ;; Using pipeline (JDK9+)
    (-> (pipeline (pb "ls") (pb "grep" "clj"))
        last deref :out slurp)
    

    Input to Process

    ;; String input
    (-> (process {:in "hello\nworld" :out :string} "cat")
        deref :out)
    
    ;; File input
    (-> (process {:in (io/file "data.txt") :out :string} "wc")
        deref :out)
    

    Close Stdin

    For processes that read stdin until EOF, close it immediately:

    ;; Empty string - simplest approach
    (process {:in ""} "cmd")
    
    ;; Null device
    (process {:in null-file} "cmd")
    
    ;; Explicit close after start
    (let [p (process "cmd")]
      (.close (:in p))
      p)
    

    Streaming Output

    (require '[clojure.java.io :as io])
    
    (def p (process {:err :inherit} "bb" "-e" "(doseq [i (range)] (println i) (Thread/sleep 100))"))
    
    (with-open [rdr (io/reader (:out p))]
      (doseq [line (line-seq rdr)]
        (println "Got:" line)))
    

    Interactive Process

    (def p (process "cat"))
    (def w (io/writer (:in p)))
    
    (binding [*out* w]
      (println "hello")
      (println "world"))
    (.close w)
    
    (slurp (:out p))
    ;; => "hello\nworld\n"
    

    Write to File

    ;; Overwrite
    (shell {:out :write :out-file "log.txt"} "ls")
    
    ;; Append
    (shell {:out :append :out-file "log.txt"} "date")
    

    Discard Output

    (require '[babashka.process :refer [shell null-file]])
    
    (shell {:out null-file :err null-file} "noisy-command")
    

    Timeout

    (let [p (process "sleep" "100")]
      (when-not (deref p 1000 nil)
        (destroy-tree p)
        (println "Timed out")))
    

    Pre-start Hook

    (shell {:pre-start-fn (fn [{:keys [cmd]}]
                            (println "Running:" cmd))}
           "ls")
    

    Error Handling

    Check Exit Code

    ;; shell throws by default
    (try
      (shell "ls" "nonexistent")
      (catch Exception e
        (println "Failed:" (ex-message e))))
    
    ;; Suppress with :continue
    (let [{:keys [exit]} (shell {:continue true} "ls" "nonexistent")]
      (when-not (zero? exit)
        (println "Command failed")))
    

    Process Errors

    ;; Manual checking with process
    (let [{:keys [exit out err]} @(process {:out :string :err :string} "cmd")]
      (if (zero? exit)
        (println "Success:" out)
        (println "Error:" err)))
    

    Capture Stderr

    (let [{:keys [err]} (shell {:err :string :continue true} "ls" "nonexistent")]
      (println "Error output:" err))
    

    Performance Tips

    1. Avoid shell for simple operations - Use Clojure/Java directly when possible
    2. Stream large outputs - Don't use :string for large data; stream instead
    3. Reuse process builders - For repeated commands, create pb once
    4. Use destroy-tree - Prevent zombie processes when killing

    Platform Notes

    Windows

    • Environment variable names are case-sensitive for :extra-env
    • Cannot launch .ps1 scripts directly; invoke through PowerShell:
      (shell "powershell" "-File" "script.ps1")
      
    • Globbing doesn't work; expand patterns in Clojure

    macOS/Linux

    • First argument not tokenized if it contains spaces without quotes
    • Use tokenize explicitly when needed

    Comparison with clojure.java.shell

    Feature clojure.java.shell/sh babashka.process
    Blocking Always Explicit via deref
    Piping No Yes
    Streaming No Yes
    Process control Limited Full access
    Exit checking Manual check / shell

    See Also

    • babashka.fs - File system operations
    • babashka-cli - CLI argument parsing
    Recommended Servers
    Netlify
    Netlify
    Context7
    Context7
    ScrapeGraph AI Integration Server
    ScrapeGraph AI Integration Server
    Repository
    hugoduncan/library-skills
    Files