# jsterm: a browser terminal whose filesystem is a JSON document

> jsterm is a terminal simulator that runs in a page and keeps its files in a JSON pseudo-filesystem, so a command like cat is really a lookup in a nested array of objects. The author is blunt that most of it was written a long time ago and that it is due for a rewrite with pipes and writable files.

**clarkduvall/jsterm** — JavaScript terminal using a JSON pseudo-filesystem.

- Repository: https://github.com/clarkduvall/jsterm
- Stars: 549 · Forks: 104
- Language: JavaScript
- License: not declared
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/clarkduvall-jsterm

## The terminal is a front end over a JSON document

jsterm is a terminal simulator that uses a JSON filesystem, and you can see it running at clarkduvall.com. The filesystem is not a real directory tree. It is a recursive grouping of JSON arrays of objects, where each nested array represents the listing of items in a directory and each object in the array defines a file or a directory, with `json/sample.json` given as the example. That design choice is the whole project. A terminal normally implies a shell, a process model, and a kernel underneath; here the terminal is a rendering surface and the filesystem is a document the page loads. The audience is someone who wants a convincing terminal interface in a browser, for a demo or an interactive page, without the risk and the weight of giving a page a shell.

## The command set is a JavaScript file you edit yourself

There is no configuration format to learn, because the configuration is source code. The How To Use section explains that at the bottom of the `js/jsterm.js` file there is a series of `term.enqueue()` calls, and that this is where the commands are set that are run when the page loads. Other changes can be made to personalise your terminal. The repository layout is organised by exactly those concerns. The `commands` directory holds a JavaScript file with all the possible commands that can be run, and that is where you add new commands. The `config` directory holds a JavaScript file with basic configuration information, and things like the prompt are changed there. The `css` directory holds the CSS used on the page, and `images` holds image files used in the filesystem. The `js` directory is the jsterm implementation itself, and `json` is where the filesystem is stored.

## Which filesystem loads is a one-line change in the source

The `json` directory is where the filesystem is stored, and the README explains that to change which filesystem is loaded you change the `term.Init()` call in `js/jsterm.js`. That is the entire extension point for the data side of the terminal, and it is worth pausing on what that implies. Because the filesystem is a static document shipped with the page, the terminal cannot be pointed at a live server filesystem without replacing that call. A deployment that wants a different set of files ships a different JSON file, and a build that wants to generate one from a real directory uses the script described later in the README. For a demo that is a feature, because the entire contents of the terminal can be reviewed in a diff. For anything long-lived, it means the file layout is a data dependency that has to be regenerated rather than browsed.

## Serving it locally needs a web server, and the README's command is dated

Because the browser loads the filesystem over HTTP, you cannot open the file directly from disk. The README says that for the loading of the filesystem to work locally you must serve the files in the directory from a local server, and it says to change into the jsterm directory and run:

```
python -m SimpleHTTPServer 8000
```

That command is worth a note. `SimpleHTTPServer` was the Python 2 module name, and in Python 3 the equivalent is `http.server`, so on a modern Python the documented command needs adjusting. It is a small thing, and it is the sort of detail that tells you the age of the project. The `index.html` at the repository root is the page, and the `js`, `css`, `images`, `config`, `commands`, and `json` directories are all fetched relative to it, so any static server rooted at the project directory will do.

## make_fs.py turns a real directory into the JSON the terminal reads

The `make_fs.py` script creates a jsterm filesystem from a real directory, and the README gives examples of how different file types should be represented. A text file with no execute permissions is simply its contents:

```
This is a text file.
```

An executable or link must be marked executable, and its content is the target:

```
http://google.com
```

An image file can be any image file with a standard extension, for example .png or .jpg. The executable case is the interesting one, because the convention that a file's body holds a URL is what lets the terminal fake a command that opens a link without ever resolving a hostname. The script therefore has to inspect permissions on the source directory, and the author makes the requirement explicit with the capitalised note that it must be marked executable, which suggests the script checks the mode bit rather than guessing from the content.

## The author says plainly that this needs a rewrite

The Disclaimer section is worth quoting in spirit because it sets the expectations a maintainer would have. The author writes that most of this was written a while ago when he knew JavaScript about as well as he knows Spanish, which is a little but not much, and that it is due for a rewrite with some cool new features like pipes, writable files, and other magic. That is an unusually clear statement about the current state of a project. It tells you that the missing features are not oversights in the implementation but a known gap in the design, since a simulator without pipes is not a shell, and without writable files the filesystem is read only. The last push was on 2026-04-14, the repository publishes no GitHub releases, and the licence is reported as unknown, so for anything beyond personal use you would want to check the terms directly.

## Where jsterm is the wrong tool

Three limits are obvious from the README. The first is that this is not a shell. No pipes, no writable files, no exit codes worth the name, and no process model, so anything that expects to run a real program against a real filesystem is out of scope. The second is the deployment model. The filesystem is a JSON document loaded by the page, which means the terminal's contents are whatever shipped with the page, and a user with a browser can change them, so it must not be used to present anything the user is not supposed to edit. The third is the maintenance reality. The project is a single author project with a self-declared need for a rewrite, no releases, and an unknown licence, so the risk is not that a command breaks but that the whole thing is replaced and your page loses its terminal. For a page that needs a terminal-shaped interface with a fixed set of files, that is a perfectly good trade.

## Conclusion

jsterm fits a developer who wants a terminal-looking interface embedded in a page, backed by a filesystem they control as data rather than as real files, which is useful for a demo, a tutorial, or a kiosk interface that should not be able to touch the machine. It is the wrong tool if you need a working shell, since the README states plainly that pipes, writable files, and other magic are still on the to-do list, and the wrong tool for anything beyond a self-contained browser toy. Before you build on it, read the disclaimer at the top of the README, then read `js/jsterm.js` and the `commands` file, because the command set is a plain JavaScript file you edit, and check the `make_fs.py` script, which is how a real directory becomes the JSON filesystem the terminal reads.

## FAQ

### What is jsterm and how does it store its filesystem?

It is a terminal simulator that uses a JSON filesystem. A filesystem is a recursive grouping of JSON arrays of objects, where each nested array represents the listing of items in a directory and each object defines a file or a directory, with `json/sample.json` given as the example.

### How do I add a new command to jsterm?

Commands live in the `commands` directory, which holds a JavaScript file with all the possible commands that can be run, and the README says to add new commands there. The commands that run when the page loads are set by a series of `term.enqueue()` calls at the bottom of the `js/jsterm.js` file.

### How do I run jsterm locally?

You have to serve the files from a local server, because the loading of the filesystem goes over HTTP. The README says to change into the jsterm directory and run `python -m SimpleHTTPServer 8000`, noting that `SimpleHTTPServer` was the Python 2 module name and the Python 3 equivalent is `http.server`.

### How do I create a jsterm filesystem from a real directory?

The `make_fs.py` script does it. The README gives the file conventions it expects: a text file with no execute permissions is just its contents, an executable or link must be marked executable and holds the target such as a URL, and an image file can be any image file with a standard extension like .png or .jpg.

### What is missing from jsterm today?

The README's disclaimer says it was written a long time ago and is due for a rewrite with new features like pipes, writable files, and other magic. It publishes no GitHub releases, the last push was on 2026-04-14, and the licence is reported as unknown.

## Sources

- [clarkduvall/jsterm on GitHub](https://github.com/clarkduvall/jsterm)
- [Issues](https://github.com/clarkduvall/jsterm/issues)
- [README](https://github.com/clarkduvall/jsterm/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/clarkduvall-jsterm
