npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@regibyte/cljam

v0.0.20

Published

[![npm](https://img.shields.io/npm/v/%40regibyte%2Fcljam)](https://www.npmjs.com/package/@regibyte/cljam) [![license](https://img.shields.io/npm/l/%40regibyte%2Fcljam)](LICENSE)

Readme

@regibyte/cljam

npm license

A Clojure interpreter written in TypeScript. Embeds in any JS/TS project as a library, runs as a standalone CLI on Node.js 18+ or Bun, and exposes a full nREPL server compatible with Calva, Cursive, and CIDER.

Try it in the browser →


What it is

cljam is an interpreter. Source code is read, macro-expanded, and evaluated at runtime. An incremental compiler is built in — hot-path forms compile to native closures at definition time — but there is no Clojure → JavaScript file output today.

It is designed to be embedded. The core session API is a plain TypeScript object: create a session, inject host capabilities, evaluate strings. The CLI and nREPL server are thin wrappers around the same session.


Installation

# As a library
npm install @regibyte/cljam
# or
bun add @regibyte/cljam
# As a CLI (Node.js 18+ or Bun)
npm install -g @regibyte/cljam
# or
bun install -g @regibyte/cljam

Embedding

import { createSession, printString, nodePreset } from '@regibyte/cljam'

const session = createSession({
  ...nodePreset(),
})

const result = session.evaluate('(map inc [1 2 3])')
console.log(printString(result)) // => (2 3 4)

nodePreset() wires up Node.js filesystem and standard I/O. Use browserPreset() for the DOM, sandboxPreset() for an isolated evaluation context with no host access.

Injecting host capabilities

hostBindings makes any TypeScript value available as js/<key> in Clojure:

import { createSession, sandboxPreset } from '@regibyte/cljam'

const session = createSession({
  ...sandboxPreset(),
  hostBindings: {
    db: {
      findUser: (id: number) => ({ id, name: 'Alice' }),
    },
  },
})
;; Method call: (. obj method args...)
(. js/db findUser 42)
;; => {:id 42 :name "Alice"}

Using libraries

import { createSession, nodePreset } from '@regibyte/cljam'
import { library as dateLib } from '@regibyte/cljam-date'

const session = createSession({
  ...nodePreset(),
  libraries: [dateLib],
})

session.evaluate(`
  (require '[cljam.date :as d])
  (d/to-iso (d/now))
`)

CLI

# Interactive REPL
cljam repl

# Run a file
cljam run my-script.clj

# Start nREPL server (default port 7888)
cljam nrepl-server
cljam nrepl-server --port 7889 --host 0.0.0.0

nREPL

Full TCP nREPL server with bencode transport. Supports eval, load-file, complete, clone, close, describe, and interrupt. Writes .nrepl-port on startup for auto-connect.

Calva (VS Code)

Add to .vscode/settings.json:

{
  "calva.replConnectSequences": [
    {
      "name": "cljam nREPL",
      "projectType": "generic",
      "nReplPortFile": [".nrepl-port"]
    }
  ]
}

Then: Calva: Connect to Running REPL Server in Project → select cljam nREPL.

CIDER (Emacs)

M-x cider-connect RET
Host: localhost RET
Port: 7888 RET

Cursive (IntelliJ)

Run → Edit Configurations → + → Clojure REPL → Remote → host localhost, port 7888.


Source Root Discovery

When running cljam nrepl-server or cljam run, cljam reads the cljam.sourceRoots field from package.json:

{
  "cljam": {
    "sourceRoots": ["src/clojure"]
  }
}

Source roots control how require resolves namespace files. Falls back to the current working directory if not set.


Language Features

  • Immutable collections: vectors, maps, sets, lists
  • Namespaces with ns, require, refer, alias
  • Multi-arity and variadic functions
  • Sequential and associative destructuring (nested, :keys, :syms, :strs, kwargs)
  • Macros: defmacro, quasiquote/unquote/splicing, macroexpand, macroexpand-all
  • Atoms for controlled mutable state
  • loop/recur with tail-call optimization
  • Transducers: transduce, into with xf
  • Threading macros: ->, ->>
  • Anonymous function shorthand: #(+ % 1)
  • try/catch/finally with predicate-based discriminators (no class hierarchy)
  • Protocols and records: defprotocol, defrecord, extend-protocol, extend-type
  • Multimethods: defmulti, defmethod, keyword hierarchy (derive, isa?)
  • Character literals: \a, \space, \newline, \uXXXX
  • EDN reader: clojure.edn/read-string, reader tags #inst and #uuid
  • JS interop: js/ namespace, . member access, js/new

Standard namespaces bundled at startup: clojure.core clojure.string clojure.edn clojure.math clojure.test — all implemented in Clojure itself and readable in the source tree.


JS Interop

Inject host values with hostBindings, then access them as js/<key> in Clojure:

createSession({
  ...nodePreset(),
  hostBindings: { Math, console, myLib: require('./my-lib') },
})
;; Method call: (. obj method args...)
(. js/Math pow 2 10)            ;; => 1024.0
(. js/console log "hello")

;; Constructors
(def now (js/new js/Date))
(. now toISOString)             ;; => "2026-04-14T..."

;; Injected objects — hostBindings: { myLib: require('./my-lib') }
(. js/myLib greet "world")      ;; => calls myLib.greet("world")

;; Call a bare function with no this binding
(js/call js/myFn 1 2 3)

;; Load a Node/npm module via (:require ["specifier" :as alias])
;; Requires importModule: (s) => import(s) in session options
(ns demo
  (:require ["node:path" :as path]))

(. path join "a" "b" "c")      ;; => "a/b/c"

Building Libraries

A cljam library is a TypeScript package that provides a CljamLibrary manifest containing Clojure namespaces and/or native runtime modules. The cljam gen-lib-source command generates the TypeScript sources map from your .clj files.

Quickstart

# devDependency in your library package
npm install --save-dev @regibyte/cljam
// package.json
{
  "scripts": {
    "gen:sources": "cljam gen-lib-source src/clojure src/generated/sources.ts",
    "prepublishOnly": "npm run gen:sources"
  }
}
// conjure.ts — the library manifest
import type { CljamLibrary } from '@regibyte/cljam'
import { sources } from './src/generated/sources'

export const library: CljamLibrary = {
  id: 'my-lib',
  sources,
}
;; src/clojure/my-lib/core.clj
(ns my-lib.core)

(defn greet [name] (str "Hello, " name "!"))

Run npm run gen:sources to regenerate sources.ts whenever you edit .clj files. The generated file is checked in — it only rewrites when content changes, so diffs stay clean.

For libraries with native TypeScript modules (wrapping JS APIs), see @regibyte/cljam-date as a reference implementation.


Protocols and Records

defprotocol, defrecord, extend-protocol, and extend-type work as in JVM Clojure. Dispatch uses keyword type tags instead of Java class names:

(require '[clojure.math :as math])

(defprotocol IArea
  (area [shape] "Compute the area"))

(defrecord Circle [radius])
(defrecord Rect [w h])

(extend-protocol IArea
  :user/Circle (area [c] (* math/PI (:radius c) (:radius c)))
  :user/Rect   (area [r] (* (:w r) (:h r))))

(area (->Circle 5))   ;; => 78.53981633974483
(area (->Rect 4 6))   ;; => 24

Type tags are keywords of the form :ns/RecordName for records, and :string :int :boolean etc. for built-in types. Use (type x) to get the tag for any value.


Testing with clojure.test

clojure.test is built in. *.test.clj and *.spec.clj files run natively in Vitest via cljTestPlugin():

(ns my-app.core-test
  (:require [clojure.test :refer [deftest is testing run-tests]]))

(deftest arithmetic-works
  (testing "addition"
    (is (= 4 (+ 2 2))))
  (testing "strings"
    (is (= "hello" (str "hel" "lo")))))

(run-tests 'my-app.core-test)
;; {:test 1 :pass 2 :fail 0 :error 0}

To enable *.test.clj → Vitest integration:

// vite.config.ts
import { cljTestPlugin } from '@regibyte/cljam/vite-plugin'

export default { plugins: [cljTestPlugin()] }

Key Differences from JVM Clojure

| JVM Clojure | cljam | |---|---| | Java interop (.method, new Foo, java.lang.*) | Not available — use js/ namespace | | defrecord, defprotocol, extend-protocol | Available — dispatch on keyword type tags, not Java classes | | deftype | Not available | | future, agent, STM (ref, dosync) | Not available — use (async ...) with @deref as await | | Long, BigDecimal, ratio literals (1/3) | Numbers are IEEE-754 floats | | Class-based catch (catch Exception e) | Predicate/keyword discriminators only | | import, Java class hierarchy | Not available | | ##NaN, ##Inf, ##-Inf reader literals | Not yet — use (clojure.math/sqrt -1) for NaN, (clojure.math/log 0) for -∞ |


LLM Integration

@regibyte/cljam-mcp is an MCP server that exposes a persistent cljam REPL to LLM agents. Eval code, load files, introspect with describe, and pair-program with a human developer in Calva — sharing the same live runtime.

See @regibyte/cljam-mcp for setup instructions.

License

MIT