Claude-skill-registry clojure-babashka-fs

File system operations with babashka.fs. Use when working with file I/O, directory traversal, path manipulation, file copying/moving, temp files, archives (zip/gzip), or file metadata.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/clojure-babashka-fs" ~/.claude/skills/majiayu000-claude-skill-registry-clojure-babashka-fs && rm -rf "$T"
manifest: skills/data/clojure-babashka-fs/SKILL.md
source content

babashka.fs

Cross-platform file system utilities for Clojure. Built on java.nio, works in JVM Clojure and babashka (built-in since v0.2.9).

Setup

deps.edn:

babashka/fs {:mvn/version "0.5.27"}

Leiningen:

[babashka/fs "0.5.27"]

See https://clojars.org/babashka/fs for the latest version.

Note: Built into babashka, no dependency needed if using bb.

Quick Start

(require '[babashka.fs :as fs])

;; Check file types
(fs/directory? ".")          ;; => true
(fs/exists? "project.clj")   ;; => true
(fs/regular-file? "README")  ;; => true

;; Path manipulation
(str (fs/path "src" "app" "core.clj"))
;; => "src/app/core.clj"

(str (fs/absolutize "."))
;; => "/home/user/project"

;; List directory
(map str (fs/list-dir "src"))
;; => ("src/app" "src/test")

;; Find files
(map str (fs/glob "." "**/*.clj"))
;; => ("src/app/core.clj" "test/app/core_test.clj")

Common Operations

Path Creation and Manipulation

;; Build paths
(fs/path "home" "user" "file.txt")     ;; => #object[java.nio.file.Path]
(fs/file "home" "user" "file.txt")     ;; => #object[java.io.File]

;; Expand home directory
(fs/expand-home "~/projects")
;; => #object[java.nio.file.Path "/home/user/projects"]

;; Get components
(fs/file-name "/path/to/file.txt")     ;; => "file.txt"
(fs/parent "/path/to/file.txt")        ;; => #object[Path "/path/to"]
(fs/extension "file.clj")              ;; => "clj"
(split-ext "file.tar.gz")              ;; => ["file.tar" "gz"]
(strip-ext "file.clj")                 ;; => "file"

;; Normalize and resolve
(fs/normalize "path/./to/../file")     ;; => "path/file"
(fs/absolutize "src")                  ;; => "/home/user/project/src"
(fs/canonicalize "src")                ;; => resolves symlinks + normalizes
(fs/real-path "src")                   ;; => like canonicalize, requires existence

Directory Listing and Searching

;; List immediate children
(fs/list-dir "src")
;; => [#object[Path "src/core.clj"] #object[Path "src/util.clj"]]

;; List with glob filter
(fs/list-dir "src" "*.clj")
;; => [#object[Path "src/core.clj"]]

;; Glob search (recursive)
(fs/glob "." "**/*.clj")               ;; all .clj files
(fs/glob "." "**{.clj,.cljc}")        ;; .clj OR .cljc files

;; Match search (more control)
(fs/match "." "regex:.*\\.clj" {:recursive true})

;; Find files in PATH
(fs/which "java")
;; => #object[Path "/usr/bin/java"]

(fs/exec-paths)  ;; all PATH directories as Paths

File Operations

;; Copy
(fs/copy "src.txt" "dest.txt")
(fs/copy "src.txt" "dest.txt" {:replace-existing true})
(fs/copy-tree "src-dir" "dest-dir")    ;; recursive copy

;; Move
(fs/move "old.txt" "new.txt")
(fs/move "old.txt" "new.txt" {:replace-existing true})

;; Delete
(fs/delete "file.txt")                 ;; throws if not exists
(fs/delete-if-exists "file.txt")       ;; safe delete
(fs/delete-tree "dir")                 ;; recursive delete (rm -rf)
(fs/delete-tree "dir" {:force true})   ;; delete read-only files too

Creating Files and Directories

;; Directories
(fs/create-dir "newdir")               ;; single dir, parent must exist
(fs/create-dirs "path/to/newdir")      ;; like mkdir -p

;; Files
(fs/create-file "empty.txt")

;; Temporary
(fs/create-temp-dir)
(fs/create-temp-dir {:prefix "myapp-"})
(fs/create-temp-file)
(fs/create-temp-file {:prefix "log-" :suffix ".txt"})

;; With auto-cleanup
(fs/with-temp-dir [tmp]
  (fs/create-file (fs/path tmp "work.txt"))
  ;; ... do work ...
  ) ;; tmp deleted here

Reading and Writing

;; Read
(fs/read-all-bytes "file.bin")         ;; => byte[]
(fs/read-all-lines "file.txt")         ;; => ["line1" "line2"]

;; Write
(fs/write-bytes "out.bin" byte-array)
(fs/write-lines "out.txt" ["line1" "line2"])
(fs/write-lines "out.txt" ["more"] {:append true})

;; Update in place
(fs/update-file "config.edn"
  #(str/replace % "localhost" "prod.example.com"))

File Metadata

;; Timestamps
(fs/creation-time "file.txt")          ;; => FileTime
(fs/last-modified-time "file.txt")     ;; => FileTime
(fs/file-time->millis (fs/last-modified-time "file.txt"))

;; Set timestamps
(fs/set-last-modified-time "file.txt" (System/currentTimeMillis))

;; Size
(fs/size "file.txt")                   ;; => bytes

;; Permissions (Unix/Linux)
(fs/posix-file-permissions "file.sh")
(fs/posix->str (fs/posix-file-permissions "file.sh"))
;; => "rwxr-xr-x"
(fs/set-posix-file-permissions "file.sh" "rwx------")

;; Owner
(str (fs/owner "file.txt"))            ;; => "username"

Archives

;; Zip
(fs/zip "archive.zip" ["file1.txt" "dir/file2.txt"])
(fs/zip "archive.zip" ["src"] {:root "src"})  ;; elide "src/" in archive

;; Unzip
(fs/unzip "archive.zip")               ;; extract to current dir
(fs/unzip "archive.zip" "dest-dir")
(fs/unzip "archive.zip" "dest-dir" {:replace-existing true})

;; Gzip
(fs/gzip "file.txt")                   ;; creates file.txt.gz
(fs/gzip "file.txt" {:out-file "archive.gz"})

;; Gunzip
(fs/gunzip "file.txt.gz")              ;; extracts to current dir
(fs/gunzip "file.txt.gz" "dest-dir")

Symbolic Links

;; Check
(fs/sym-link? "link")                  ;; => true/false

;; Create
(fs/create-sym-link "link" "target")
(fs/create-link "hardlink" "existing") ;; hard link

;; Read target
(fs/read-link "link")                  ;; => Path to target

Advanced Patterns

Walking File Trees

;; Low-level tree walker
(fs/walk-file-tree "src"
  {:pre-visit-dir (fn [dir attrs]
                    (println "Entering" dir)
                    :continue)
   :visit-file (fn [file attrs]
                 (println "File:" file)
                 :continue)})

;; Find modified files
(fs/modified-since "build/last-build-marker"
                   (fs/glob "src" "**/*.clj"))
;; => seq of files newer than marker

XDG Directories

;; Standard user directories
(fs/xdg-config-home)       ;; => ~/.config
(fs/xdg-config-home "myapp") ;; => ~/.config/myapp
(fs/xdg-data-home)         ;; => ~/.local/share
(fs/xdg-cache-home)        ;; => ~/.cache
(fs/xdg-state-home)        ;; => ~/.local/state

;; Respects XDG_CONFIG_HOME etc. env vars

Cross-Platform Paths

;; Use forward slashes on all platforms
(fs/unixify "C:\\Users\\name\\file.txt")
;; => "C:/Users/name/file.txt"

;; Separators
fs/file-separator  ;; "/" or "\\" depending on OS
fs/path-separator  ;; ":" or ";" for PATH-like strings

;; Platform detection
(fs/windows?)      ;; => true on Windows

Key Gotchas

  1. Empty string means cwd:

    (fs/list-dir "")
    is same as
    (fs/list-dir ".")
    . Most functions treat
    ""
    as current directory.

  2. Symlink following: Many functions accept

    :nofollow-links
    or
    :follow-links
    options. Default behavior varies:

    • Most operations follow symlinks by default
    • Tree walking does NOT follow symlinks unless
      :follow-links true
    • See README for function-specific defaults
  3. creation-time is unreliable: Behavior varies by OS and Java version. On Linux it often returns modified time. See API notes.

  4. glob patterns use java.nio syntax:

    • *
      matches within directory (not across
      /
      )
    • **
      matches across directories
    • {.clj,.cljc}
      for alternation
    • See FileSystem#getPathMatcher
  5. Paths vs Files: Functions return

    java.nio.file.Path
    objects. Use
    str
    to convert to string, or
    fs/file
    to convert to
    java.io.File
    .

  6. Maps are closed by default in newer glob: Recent versions of fs set

    {:hidden false}
    by default unless pattern starts with
    .

References