A collection of shared Babashka libraries for common functionality across development toolkits.
This repository provides reusable Babashka scripts that implement core functionality shared across multiple development tools. Rather than duplicating code, tools like ADR, Requirements Management, and RunNotes load these shared libraries at runtime.
This library is a dependency of:
- ~/.adr - Architecture Decision Records toolkit ✅ Required
- ~/.runnote - Development Knowledge Capture system ✅ Required
- ~/.req - Requirements Management toolkit ❌ No dependency
See DEPENDENCIES.md for version compatibility matrix.
# Install latest release
curl -sL https://github.com/rriehle/.lib/releases/latest/download/install.sh | bash
# Or install specific version
curl -sL https://github.com/rriehle/.lib/releases/download/v1.0.0/install.sh | bashThis installs to ~/.lib/ by default. Dependent toolkits (.adr, .runnote) will automatically detect and use it.
# Clone this repository to ~/.lib
git clone https://github.com/rriehle/.lib.git ~/.lib# Check files installed
ls ~/.lib/*.bb
# Check version
cat ~/.lib/VERSIONNote: .lib must be installed before installing dependent toolkits (.adr, .runnote).
config-core.bb - Shared configuration loading and merging
- Purpose: Unified config hierarchy (global → project overrides)
- Used by: ADR tools, Requirements tools
- Features:
- EDN config file parsing
- Multi-level config merging
- Path resolution and expansion
- Project root discovery
Example usage:
(load-file (str (fs/expand-home "~/.lib/config-core.bb")))
;; Load merged config
(def config (load-merged-config
"~/.adr/config.edn" ; Global defaults
".adr.edn")) ; Project overridesmetadata-parser.bb - EDN metadata extraction from markdown
- Purpose: Parse embedded EDN metadata blocks from markdown files
- Used by: All tools (ADR, Requirements, RunNotes)
- Features:
- Extracts
```edn :metadatablocks - Validates EDN syntax
- Returns parsed Clojure data structures
- Handles malformed metadata gracefully
- Extracts
Example usage:
(load-file (str (fs/expand-home "~/.lib/metadata-parser.bb")))
;; Extract metadata from file
(def metadata (extract-metadata "path/to/file.md"))
;; => {:date "2025-10-01" :status :accepted :tag #{:architecture}}test/test-framework.bb - Comprehensive testing utilities for Babashka scripts
- Purpose: Reusable test framework for all CLI tools (ADR, Requirements, RunNotes)
- Used by: Test suites across all projects
- Features:
- Assertion functions (
assert-true,assert-equal,assert-string-contains, etc.) - Property-based testing utilities
- Test fixtures (temporary directories, file creation)
- Command execution helpers
- Test reporting and summaries
- Assertion functions (
Assertion Functions:
assert-true,assert-false- Boolean assertionsassert-equal,assert-not-equal- Value equalityassert-string-contains- Substring matchingassert-contains- Collection membershipassert-nil,assert-not-nil- Null checksassert-count- Collection sizeassert-throws- Exception expectationsassert-file-exists,assert-file-not-exists- File system checks
Test Utilities:
test-case- Run single test with pass/fail reportingrun-tests- Execute test suite and return resultswith-temp-dir- Temporary directory fixture with auto-cleanupcreate-test-file- Create test files in temp directories
Property-Based Testing:
gen-string,gen-int,gen-seq- Random data generatorscheck-property- Run property tests N times
Example usage:
(load-file (str (fs/expand-home "~/.lib/test/test-framework.bb")))
;; Import what you need
(def test-case (:test-case test-framework/exports))
(def assert-equal (:assert-equal test-framework/exports))
(def assert-string-contains (:assert-string-contains test-framework/exports))
(def with-temp-dir (:with-temp-dir test-framework/exports))
;; Write tests
(defn test-example []
(with-temp-dir
(fn [temp-dir]
(let [result (my-function temp-dir)]
(assert-equal "expected" result "Should return expected value")))))
(defn test-error-messages []
(let [error (get-error-message)]
(assert-string-contains error "field-name"
"Error should mention the field")))
;; Run tests
(def tests
[(test-case "Example test" test-example)
(test-case "Error message test" test-error-messages)])
;; Execute and get results
(let [results ((:run-tests test-framework/exports) tests)]
(println (str (:passed results) " passed, " (:failed results) " failed")))~/.lib/
├── config-core.bb # Shared config management (truly shared)
├── metadata-parser.bb # EDN metadata parsing (truly shared)
├── test/
│ └── test-framework.bb # Test utilities (truly shared)
└── README.md # This file
Note: Project-specific libraries have been moved to their respective projects:
- ADR libraries: ~/.adr/adr-core.bb, ~/.adr/adr-metadata-extractor.bb
- Requirements libraries: ~/.req/req-core.bb, ~/.req/req-metadata-extractor.bb
What belongs in ~/.lib:
- Code used by 2+ projects (config-core.bb, metadata-parser.bb)
- Test infrastructure (test-framework.bb)
- Universal utilities with no domain-specific logic
What belongs in project directories:
- Domain-specific logic (ADR utilities in ~/.adr, Requirements utilities in ~/.req)
- Project-specific validation and extraction
- Tools that only make sense in one domain context
This separation emerged from DRY refactoring work (October 2025) that identified and eliminated duplicate functions while clarifying architectural boundaries.
Libraries are loaded at runtime using load-file, allowing:
- Zero build process
- Immediate updates across all dependent tools
- Easy debugging and development
Each library is self-contained with clear dependencies. Libraries can load other libraries but avoid circular dependencies.
All code is Babashka-compatible:
- Fast startup time (no JVM)
- Minimal dependencies
- Standard Clojure syntax
- Create new
.bbfile in~/.lib/ - Follow naming convention:
<domain>-<purpose>.bb - Add clear docstrings and examples
- Update this README
Since libraries are loaded at runtime, test changes immediately:
# Test with ADR tools
cd ~/path/to/project
adr-validate
# Test with Requirements tools
req-search list
# Test with RunNotes
runnote-launch research Testcd ~/.lib
clj-kondo --lint *.bb
# Expected: 0 errors, 0 warnings;; Load shared libraries from ~/.lib
(load-file (str (fs/expand-home "~/.lib/config-core.bb")))
(load-file (str (fs/expand-home "~/.lib/metadata-parser.bb")))
;; Load project-specific libraries from their home directories
;; (if building ADR tools)
(load-file (str (fs/expand-home "~/.adr/adr-core.bb")))
(load-file (str (fs/expand-home "~/.adr/adr-metadata-extractor.bb")))
;; (if building Requirements tools)
(load-file (str (fs/expand-home "~/.req/req-core.bb")))
(load-file (str (fs/expand-home "~/.req/req-metadata-extractor.bb")));; Global config with project overrides
(def global-config "~/.adr/config.edn")
(def project-config ".adr.edn")
(def config (load-merged-config global-config project-config))
(def adr-dir (get-in config [:adr :path] "doc/adr"));; Extract and validate metadata
(def file-content (slurp "00042-decision.md"))
(def metadata (extract-metadata file-content))
;; Validate required fields
(when-not (and (:date metadata) (:status metadata))
(throw (ex-info "Missing required metadata" {:file file})))This repository follows semantic versioning:
- Major (X.0.0): Breaking API changes - requires toolkit updates
- Minor (1.X.0): New features, backward compatible - safe to upgrade
- Patch (1.0.X): Bug fixes - recommended for all
Current Version: v1.0.0
See DEPENDENCIES.md for:
- Version compatibility matrix
- Toolkit version requirements
- Upgrade and rollback procedures
- Breaking change policy
;; ~/.adr/bin/adr-validate
#!/usr/bin/env bb
(require '[babashka.fs :as fs])
;; Load shared libraries from ~/.lib
(load-file (str (fs/expand-home "~/.lib/config-core.bb")))
(load-file (str (fs/expand-home "~/.lib/metadata-parser.bb")))
;; Load ADR-specific libraries from ~/.adr
(load-file (str (fs/expand-home "~/.adr/adr-core.bb")))
(load-file (str (fs/expand-home "~/.adr/adr-metadata-extractor.bb")))
;; Use functionality
(def config ((:load-config adr-core/exports)))
(def adr-dir ((:resolve-adr-path adr-core/exports) config));; ~/.req/bin/req-search
#!/usr/bin/env bb
(require '[babashka.fs :as fs])
;; Load shared libraries from ~/.lib
(load-file (str (fs/expand-home "~/.lib/config-core.bb")))
(load-file (str (fs/expand-home "~/.lib/metadata-parser.bb")))
;; Load Requirements-specific libraries from ~/.req
(load-file (str (fs/expand-home "~/.req/req-core.bb")))
(load-file (str (fs/expand-home "~/.req/req-metadata-extractor.bb")))
;; Use functionality
(def config ((:load-config req-core/exports)))
(def req-dir ((:resolve-req-path req-core/exports) config))Problem: FileNotFoundException: ~/.lib/config-core.bb
Solution:
# Verify installation
ls ~/.lib/*.bb
# Re-clone if missing
git clone <repo-url> ~/.libProblem: Unable to resolve symbol
Solution: Load libraries in dependency order:
- Shared libraries first:
config-core.bb,metadata-parser.bb(from ~/.lib) - Domain-specific cores:
adr-core.bb(from ~/.adr) orreq-core.bb(from ~/.req) - Domain-specific extractors:
adr-metadata-extractor.bborreq-metadata-extractor.bb
Note: Project-specific libraries are now in their respective project directories, not in ~/.lib.
Problem: Updated library but tools still use old code
Solution: Babashka scripts load libraries at runtime - no caching. Check:
# Verify file was actually saved
cat ~/.lib/config-core.bb | head -20
# Check git status
cd ~/.lib
git statusThis is shared infrastructure - changes impact multiple projects:
- Test thoroughly across all dependent tools
- Document changes in this README
- Maintain backward compatibility when possible
- Version appropriately following semver
- Babashka - Fast native Clojure scripting
- ADR Tools - Architecture Decision Records
- Requirements Tools - Requirements Management
- RunNotes - Development Knowledge Capture
- ADR-00035 - Naming conventions
MIT