Documentation
Everything needed to install it, embed it, or teach it a new language.
Install
The IDE and engine
pip install nishachar-ide
Requires Python 3.10 or newer. This gives you the nishachar command, the HTTP
API, and the Python library.
The embeddable component
npm install @nishachar/ide
Or skip the install entirely and use a CDN:
<script type="module" src="https://cdn.jsdelivr.net/npm/@nishachar/ide"></script>
Container
docker run --rm -p 8777:8777 \ -v /var/run/docker.sock:/var/run/docker.sock \ ghcr.io/ni-sh-a-char/nishachar-ide:2.0.0 --runner docker --host 0.0.0.0
Mounting the Docker socket lets the server start a sandboxed container per language. Without it you still get the API and IDE, limited to the toolchains inside the image.
Quick start
nishachar # the IDE, in your browser nishachar run hello.she # language inferred from the extension nishachar run -l rust -c 'fn main(){println!("hi")}' nishachar languages # what exists, and what you have installed
CLI reference
nishachar
With no arguments, starts the server and opens the IDE in your browser — the Jupyter model. There is no Electron download.
nishachar run
nishachar run FILE # infer language from extension nishachar run FILE -l python # force a language nishachar run -l py -c 'print(1)' # run a snippet echo 'print(1)' | nishachar run -l py - # read stdin
| Flag | Meaning |
|---|---|
-l, --language | Language id, alias or extension. |
-c, --code | Run this snippet instead of a file. |
--runner | auto (default), local or docker. |
--timeout | Seconds before the process tree is killed. Default 10. |
-v, --verbose | Report the language, backend and timing to stderr. |
The exit code is the program's own exit code, so it composes with shell scripts and CI.
nishachar languages
Lists every registered language. A * marks the ones your machine can run right
now. --available shows only those.
nishachar serve
The API without opening a browser.
| Flag | Default | Meaning |
|---|---|---|
--host | 127.0.0.1 | Bind address. |
--port | 8777 | Port. |
--runner | auto | Execution backend. |
--cors | closed | Allow embedding from this origin. Repeatable. |
--allow-shell | off | Enable the terminal endpoint. |
--allowed-host | loopback | Extra acceptable Host value. Repeatable. |
--allow-remote-exec | off | Permit the unsandboxed runner off loopback. |
Component API
<nishachar-ide> is a native custom element. It needs no framework wrapper
because custom elements are part of the platform.
Attributes
| Attribute | Values | Meaning |
|---|---|---|
language | id · alias · extension | Starting language. Default python. |
code | source text | Initial buffer. Inline text content also works. |
theme | dark · light | Follows the OS when unset. |
endpoint | URL | Backend to run against. Omit for in-browser. |
runtime | auto · browser · remote | Default auto. |
readonly | present | Editor is not editable. |
stdin | present | Show the standard-input tab. |
layout | split · stacked | Defaults to width-based. |
timeout | milliseconds | Per-run limit. |
Properties, methods and events
const ide = document.querySelector('nishachar-ide'); ide.value = 'print("hello")'; // read/write the buffer ide.language = 'python'; ide.stdin = 'piped input'; await ide.run(); // resolves with the result object ide.focus(); ide.addEventListener('ready', e => e.detail.languages); ide.addEventListener('change', e => e.detail.code); ide.addEventListener('run', e => e.detail.language); ide.addEventListener('result', e => e.detail.stdout);
Press Ctrl/Cmd + Enter in the editor to run.
Theming
nishachar-ide {
--nsc-accent: #ff4f81;
--nsc-bg: #000;
--nsc-mono: 'JetBrains Mono', monospace;
--nsc-radius: 4px;
height: 600px;
}
nishachar-ide::part(toolbar) { border-bottom: 2px solid var(--nsc-accent); }
Exposed parts: toolbar, editor, output,
run-button.
Python library
import nishachar result = nishachar.run('say "hello"', "she") result.stdout # 'hello\n' result.exit_code # 0 result.duration_ms # 158 result.ok # True result.timed_out # False result.truncated # False nishachar.run_file("script.rs", runner="docker", timeout=30) nishachar.languages() # every Language in the registry nishachar.registry.require("go")
HTTP API
| Endpoint | Returns |
|---|---|
GET /api/health | Version, active runner, language count, whether the shell is on. |
GET /api/languages | Every language, each flagged with localToolchain. |
POST /api/run | Executes and returns the result. |
WS /api/pty | Interactive terminal. Requires --allow-shell. |
curl -X POST http://localhost:8777/api/run \ -H 'content-type: application/json' \ -d '{"language":"she","code":"say \"hi\"","stdin":"","timeout":10}' {"stdout":"hi\n","stderr":"","exitCode":0,"durationMs":158, "timedOut":false,"truncated":false,"runner":"local","language":"she","ok":true}
| Status | Meaning |
|---|---|
400 | Malformed body, or a field of the wrong type. |
404 | Unknown language. |
413 | Source larger than 1 MiB. |
421 | Host header not accepted — see Security. |
422 | No backend could run that language. |
Language registry
Every language is one JSON file. Adding one requires no source changes.
{
"id": "ruby",
"name": "Ruby",
"extensions": [".rb"],
"image": "ruby:3.3-slim",
"run": ["ruby", "{file}"],
"template": "puts \"Hello from Ruby!\"\n"
}
| Placeholder | Becomes |
|---|---|
{file} | Full path to the source file. |
{bin} | Path the compiled binary should be written to. |
{dir} | The working directory. |
{stem} | Filename without its extension. |
Placeholders substitute inside an argument, so "-o{bin}" works.
Commands are argument vectors, never shell strings — nothing reaches a shell, so there is no
quoting to get right and nothing to inject.
Full field reference and contribution guide →
Execution tiers
| Tier | Where | Languages | Isolation |
|---|---|---|---|
browser | the visitor's tab | Python, SHE, JS | the browser sandbox |
local | your machine | whatever is installed | none — runs as you |
docker | a container | all 62 | strong |
auto resolves per language: your local toolchain if you have it, a container if
you don't. That is what lets Rust run on a machine with only Python installed.
Security
--runner docker for input you do not trust.Server defaults are deliberately restrictive:
- The unsandboxed runner is refused off loopback unless explicitly overridden.
- CORS is closed. An open policy on a localhost server would let any page you visit execute code on your machine.
- The
Hostheader is validated on loopback binds, which is what stops DNS rebinding. - The terminal is off until
--allow-shell. - Every tier enforces a timeout and an output cap, and kills the whole process tree.
Full threat model, including what it does not protect against →
Self-hosting
Serving this to people you do not trust:
nishachar serve \
--host 0.0.0.0 \
--runner docker \ # never 'local'
--timeout 10 \
--cors https://your-site.example
Leave the terminal off, put it behind a reverse proxy with rate limiting, and run the whole thing inside a VM. Containers share a kernel; they are a strong boundary, not an absolute one.
Troubleshooting
“X is not installed or not on PATH”
The local toolchain is missing. Install it, or run with --runner docker to use a
container instead.
The nishachar command isn't found after install
pip installed it somewhere off your PATH. python -m nishachar works
identically, or add the reported scripts directory to PATH.
The first in-browser run is slow
Expected. Pyodide is a full CPython build and takes roughly three seconds to download and start. It is cached afterwards, and SHE adds about two more seconds the first time while micropip fetches it from PyPI.
The embedded component won't reach my server
CORS is closed by default. Start the server with
--cors https://your-site.example.
The terminal shows no colours on Windows
ConPTY needs the optional dependency: pip install "nishachar-ide[pty]". Without
it the terminal falls back to pipes, which run commands but have no TTY.