Open-source project
BetterThanTomorrow/joyride avatar
BetterThanTomorrow/joyride

Joyride gives VS Code a scriptable editor with Clojure

Making VS Code Hackable like Emacs since 2022

596 stars22 forksClojureNOASSERTION

At a glance

What is it?
Joyride is a VS Code extension that embeds the SCI small Clojure interpreter so you can drive the editor API and the APIs of its extensions from a live REPL, in the spirit of Emacs and ELisp. The reward is an editor you can reshape while it runs, and the cost is that you are running arbitrary code in your own workspace.
Who is it for?
Joyride fits a developer who wants to extend VS Code without shipping a compiled extension, who is comfortable with Clojure or willing to learn it, and who wants to shape the editor around a particular workflow rather than around what the extension marketplace happens to offer.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Clojure, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A REPL inside the editor, not an extension to install

The pitch in one line is that Joyride lets you modify your VS Code while it is running, with the Visual Studio Code API and the APIs of its extensions at your command. The description is that Joyride makes VS Code scriptable in a very similar way to how Emacs users can hack their editor.

The mechanism is the SCI interpreter. The package metadata gives it away in the description field: Making VS Code hackable, a bit like Emacs with ELisp, powered by SCI, the Small Clojure Interpreter.

That choice is the interesting engineering decision. SCI is an interpreter for a subset of Clojure that runs in the host process without a JVM, which means the extension can host a live Clojure REPL inside VS Code, evaluate forms against the editor API, and reload files as they change on disk. The project description says Making VS Code Hackable like Emacs since 2022, and the topics list clojure, clojurescript, interpreter and vscode.

The practical payoff is the REPL itself. A script can be run, evaluated again, and inspected, with the editor's own state available in the same session. That is a different development loop from writing an extension, packaging it and reloading the extension host, and it is why the examples include a workspace activation script and a Joyride Sidecar extension created on the fly.

The repository is a Clojure and ClojureScript codebase with a shadow-cljs.edn build file, a deps.edn, a bb.edn for babashka tasks, a cljfmt.edn, a .clj-kondo directory for linting, and both a script and a src directory.

Scripts live in two directories and share one classpath

Joyride supports User and Workspace scripts, in two fixed locations: the user home directory at .config/joyride/scripts, and the workspace root at .joyride/scripts.

The two are invoked with commands from the command palette, searched for Joyride. Joyride Run User Script has the default keybinding ctrl+alt+j u, and Joyride Run Workspace Script has ctrl+alt+j w, and there are matching Open commands for each.

The classpath detail is the part to understand before you write anything substantial. Used with ClojureScript, Joyride effectively has a classpath of user/scripts:user/src:workspace/scripts:workspace/src. A file at the user scripts directory named foo_bar.cljs establishes or uses a namespace foo-bar, and the same is true for a workspace file of the same name.

Then the documentation says any symbols in these files will be shared or overwritten, as the files are loaded and reloaded. The writer of that warning is explicit about how to treat it, calling it a super power and warning that you might also hurt yourself with it. Concretely, a workspace script and a user script that define the same name will collide, and a reload replaces the previous definition globally rather than in a fresh scope. For scripts you write deliberately, that is a feature. For a project with several people adding scripts in a shared workspace, it is a source of collisions that only appear when someone happens to use a common name.

The Joyride Run Workspace Script menu also includes a command for downloading and installing default or example workspace scripts, which is a quick way to see working code in a folder.

The first script you write talks to the file system

The quick start has you create two scripts, one in ClojureScript and one in JavaScript, that show an information message and write a file in the root of the workspace. The ClojureScript version lives at .joyride/scripts/example/write_a_file.cljs:

``` clojure (ns example.write-a-file (:require ["fs" :as fs] ["path" :as path] ["vscode" :as vscode] [clojure.string :as str]))

(defn info [& xs] (vscode/window.showInformationMessage (str/join " " xs)))

(def root-path (-> (first vscode/workspace.workspaceFolders) .-uri .-fsPath)) (info "The root path of this workspace:" root-path) (fs/writeFileSync (path/resolve root-path "test-from-cljs-script.txt") "Written from a Workspace ClojureScript Script!") ```

Three things are visible in that script. The vscode namespace is required the same way you would require any other library, so the editor API is just a namespace. Node's fs and path modules are available, which means a script can read and write files without going through an extension host API. And the workspace root is obtained as an interop chain, taking the first workspace folder, its uri, and its fsPath.

The JavaScript equivalent at .joyride/scripts/example/write-a-file.js uses require for fs, path and vscode, and the documentation is candid that the JavaScript support in Joyride is experimental and not at par with the ClojureScript support. It adds that you will only get to enjoy Interactive Programming using ClojureScript, which is the clearest statement of where the project wants you to spend your time.

One naming quirk to note: the ClojureScript file uses a low dash in write_a_file.cljs, while the JavaScript file uses a hyphen in write-a-file.js, and the namespaces follow from the file names.

Keybindings are how the scripts become muscle memory

Scripts can be run from the Joyride Run Workspace Script menu, but the quick start also walks through binding them to keyboard shortcuts in the VS Code keybindings JSON file:

``` json { "key": "shift+ctrl+alt+j 1", "command": "joyride.runWorkspaceScript", "args": "example/write-a-file.js" } { "key": "shift+ctrl+alt+j 2", "command": "joyride.runWorkspaceScript", "args": "example/write_a_file.cljs" } ```

The args value is the path to the script relative to the scripts directory, which is what makes the command generic enough to run anything you have written.

There is one ordering caveat, and it is the kind of detail that produces a bug report. Because of how VS Code renders the command palette, the documentation says it is good to add the default joyride.runWorkspaceScript keybinding as the last bindings in the JSON file. Put your own bindings first, let the default come last.

The pattern here is the same one Joyride applies to everything else. The extension does not need a new keybinding per script. You register one command with a path argument, and the editor runs the file. Adding a new script means adding a file and, if you want a shortcut, one more entry in your keybindings.

Copilot gets the same REPL, and the documentation says so

Joyride includes a Language Model Tool that gives Copilot access to the scripting environment so that it can hack your editor while you are working with it. The README links a video with that title, and points to a separate project so you can try it yourself.

The security note attached to that feature is the most direct statement in the whole document: Joyride gives you and Copilot full access to the VS Code API and execution environment, and you are responsible for the code that is executed in Joyride. If you do not want Copilot to have any access to the Joyride REPL tool, then disable it in settings with joyride.lm.enableReplTool.

That is a sensible default to ship and an important one to know about. The extension deliberately does not sandbox what a script can do, because a script that could not reach the file system or the editor API would not be worth much. The consequence is that the trust boundary is your own judgement about what code you run and what an assistant proposes.

The package metadata shows a second integration point in the same area, with configuration keys for an nREPL server host address, defaulting to 127.0.0.1, and an MCP socket server that can be started automatically on activation, with a related auto register setting. The MCP server is off by default.

There is also a prompt pack for asking Copilot to write Joyride scripts, with custom instructions in the prompts/general directory, and the documentation admits that the project is still discovering how best to instruct an AI model for Joyride scripting.

What the examples directory says about the intended scope

The list of examples is the best available description of what Joyride is actually used for, and it is broader than a config script runner.

There is a workspace activation script, a fuzzy git commit search and lookup menu, an interactive Webview, WebView panels and sidebar views with Flares inspired by Calva Flares, use of npm dependencies, a demonstration of contributing a File Explorer tree view and commands by creating a Joyride Sidecar extension on the fly, terminal creation and control, Calva structural editing enhancements, opening and showing project files, font size manipulation, the Joyride extension API, the joyride.core namespace, clojure.zip, babashka.fs path helpers and Hickory.

Read as a whole, that list describes a project that treats the editor as a programmable environment rather than as an application with a settings screen. A script can add a tree view, open a webview, run a terminal, hook into structural editing, and drive npm packages, all from a file in a folder.

The two entries that show how far this goes are the Sidecar example and the WebView examples. A Sidecar is a Joyride extension created on the fly at runtime, which means a script can contribute a File Explorer view and commands without anything being installed ahead of time. The WebView examples put a rendering surface inside the editor, and Flares is the borrowed idea for interactive panels in the sidebar.

The repository structure supports all of this with a playground directory, a dev directory, a doc directory with api.md, a seatbelt-e2e directory for end to end tests, a test directory, and an examples directory that is itself a full project with its own package.json, deps.edn, .joyride, .clj-kondo, .eca, .github and .lsp configuration.

Where Joyride is the wrong answer

Four situations argue against it.

The first is any machine where the code in your workspace is not yours to trust. Joyride scripts run with full access to the VS Code API and the execution environment, and a script that opens a repository can run whatever that repository tells it to run. That is a deliberate design choice, and it means the extension should not be installed in an environment that clones untrusted code, or on a machine where the editor is shared with code you did not write. The Copilot REPL tool is separately disableable, but the underlying property remains.

The second is a team that wants shared, reviewable editor configuration. A Joyride setup is scripts in a directory, and workspace scripts do live in the repository, so they can be reviewed. But the user scripts do not, and the classpath behaviour means a user script and a workspace script can silently overwrite each other's symbols. VS Code's own settings and keybindings give you a declarative, diffable configuration model, and Joyride sits above that layer rather than replacing it.

The third is a JavaScript shop that will not learn Clojure. The documentation is explicit that the JavaScript support is experimental and not at par, and that interactive programming is a ClojureScript experience. If your team is not going to write Clojure, the parts of Joyride that justify the extension are the parts you will not use.

The fourth is a well served editor. Joyride is most valuable where the extension ecosystem does not cover your need. If what you want is a different look, a different keybinding scheme or a specific language integration, there is a maintained extension for that, and the maintenance burden of a custom script is yours.

The alternative is the one Joyride itself is modelled on. Emacs configuration in ELisp gives the same programmability, and for a Clojure developer the ClojureScript REPL and the tooling around it, including Calva, which Joyride's own examples build on, are the closest thing in the VS Code ecosystem.

Editorial conclusion

Joyride fits a developer who wants to extend VS Code without shipping a compiled extension, who is comfortable with Clojure or willing to learn it, and who wants to shape the editor around a particular workflow rather than around what the extension marketplace happens to offer. It is the wrong choice for a machine where the editor runs code you do not control, and it is the wrong choice for a team that needs a shared, reviewable, versioned configuration of the editor, because a Joyride setup is scripts in a directory rather than a settings file in a repository. Before adopting it, check three things: that the Copilot REPL tool is acceptable on your machine, since the documentation states you are responsible for the code that runs in Joyride and that the tool can be disabled with joyride.lm.enableReplTool, whether the shared classpath behaviour of the script namespaces suits you, since the documentation warns that symbols are shared and overwritten as files load and reload, and that the licence in LICENSE.txt is what you expect, because the package metadata says MIT while the project records a custom licence. The last push was on 2026-10-19, with v0.0.86 released the same day.

Frequently asked questions

What is Joyride and how does it make VS Code hackable?

Joyride is a VS Code extension that embeds SCI, the small Clojure interpreter, so scripts can drive the Visual Studio Code API and the APIs of its extensions while the editor is running. The package description compares it to Emacs with ELisp, and the project has been doing this since 2022.

Where do Joyride scripts live?

User scripts go in the user home directory at .config/joyride/scripts, and workspace scripts go in the workspace root at .joyride/scripts. You run them with the Joyride Run User Script and Joyride Run Workspace Script commands from the command palette, with default keybindings ctrl+alt+j u and ctrl+alt+j w.

Can I use JavaScript with Joyride instead of ClojureScript?

Yes, but the documentation states that the JavaScript support in Joyride is experimental and not at par with the ClojureScript support, and that interactive programming is only available with ClojureScript. Workspace scripts can be written as .cljs or .js files side by side.

Does Copilot get access to the Joyride REPL?

Yes. Joyride includes a Language Model Tool that gives Copilot access to the scripting environment. The documentation notes that you and Copilot have full access to the VS Code API and execution environment and that you are responsible for the code executed, and you can disable the tool with the joyride.lm.enableReplTool setting.

What is the Joyride licence and version?

The package.json records the license as MIT for the extension and the version as 0.0.86, while the project itself records a custom licence that GitHub cannot classify, with the terms in LICENSE.txt. The last push was on 2026-10-19 and the release v0.0.86 shipped the same day.

Official sources

  1. BetterThanTomorrow/joyride on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/betterthantomorrow-joyride.svg)](https://hysenlabs.com/projects/betterthantomorrow-joyride)

Was this useful?