Metadata-Version: 2.4
Name: xtralab
Version: 0.10.0
Summary: An opinionated JupyterLab meta-package that bundles a curated set of extensions, ships a path-first file browser, renders jupyterlab-git's text, notebook and image diffs with its own viewers, and applies a quieter default workspace configuration.
Project-URL: Homepage, https://github.com/jtpio/xtralab
Project-URL: Bug Tracker, https://github.com/jtpio/xtralab/issues
Project-URL: Repository, https://github.com/jtpio/xtralab.git
Author: Jeremy Tuloup
License: BSD 3-Clause License
        
        Copyright (c) 2026, Jeremy Tuloup
        
        Redistribution and use in source and binary forms, with or without
        modification, are permitted provided that the following conditions are met:
        
        1. Redistributions of source code must retain the above copyright notice, this
           list of conditions and the following disclaimer.
        
        2. Redistributions in binary form must reproduce the above copyright notice,
           this list of conditions and the following disclaimer in the documentation
           and/or other materials provided with the distribution.
        
        3. Neither the name of the copyright holder nor the names of its contributors
           may be used to endorse or promote products derived from this software
           without specific prior written permission.
        
        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
        AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
        FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
        CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
        OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
License-File: LICENSE
Keywords: jupyter,jupyterlab,meta-package
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: Jupyter
Classifier: Framework :: Jupyter :: JupyterLab
Classifier: Framework :: Jupyter :: JupyterLab :: 4
Classifier: Framework :: Jupyter :: JupyterLab :: Extensions
Classifier: Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.10
Requires-Dist: ajlab>=0.1.8
Requires-Dist: jupyter-server-mcp>=0.3.0a0
Requires-Dist: jupyterlab-cursor-dark>=1.0.2
Requires-Dist: jupyterlab-cursor-light>=1.0.2
Requires-Dist: jupyterlab-day>=0.2.0
Requires-Dist: jupyterlab-git-core>=0.54.0a1
Requires-Dist: jupyterlab-git>=0.54.0a1
Requires-Dist: jupyterlab-lsp>=5.3.0
Requires-Dist: jupyterlab-night>=0.5.2
Requires-Dist: jupyterlab-pierre-dark>=0.1.1
Requires-Dist: jupyterlab-pierre-light>=0.1.1
Requires-Dist: jupyterlab-quickopen>=2.3.0
Requires-Dist: jupyterlab-search-replace>=1.1.3
Requires-Dist: jupyterlab-vim>=4.1.4
Requires-Dist: jupyterlab>=4.6.0b1
Requires-Dist: psutil>=5.9
Requires-Dist: ty>=0.0.40
Description-Content-Type: text/markdown

![xtralab-logo](./logo.png)

An opinionated JupyterLab meta-package for use with coding agents.

It bundles a curated set of JupyterLab extensions, a path-first file browser,
rich git diffs for text, notebooks, and images, an agent launcher, and a
quieter default workspace.

![xtralab screenshot](./screenshot.png)

## Install

```bash
pip install xtralab
```

## Usage

### As a JupyterLab package

Once installed, start JupyterLab the usual way:

```bash
jupyter lab
```

### As a desktop app

A standalone Electron build is also available, packaged as a DMG on macOS and
an AppImage on Linux. Each tagged release ships installers on the
[releases page](https://github.com/jtpio/xtralab/releases/latest), and builds
from `main` are uploaded as workflow artifacts on the
[Actions tab](https://github.com/jtpio/xtralab/actions). See
[CONTRIBUTING.md](./CONTRIBUTING.md) for the desktop app architecture and local
build instructions.

On macOS the build is not notarized yet (it has no Apple Developer ID), so
Gatekeeper blocks it on first launch, and agent notifications fall back to
`osascript`, appearing as "Script Editor". In the meantime you can self-sign it
for free: this lets it launch and gives native notifications instead, branded as
xtralab and clickable to jump to the terminal that fired them. Create a
code-signing certificate once in Keychain Access (Certificate Assistant, Create
a Certificate, with Identity Type "Self Signed Root" and Certificate Type "Code
Signing") named `xtralab-selfsign`, then sign the app you copied out of the DMG:

```bash
codesign --force --deep --sign "xtralab-selfsign" --timestamp=none "/Applications/xtralab.app"
xattr -dr com.apple.quarantine "/Applications/xtralab.app"
```

macOS prompts once to let `codesign` use the key; choose Always Allow. None of
this will be needed once the app ships with a Developer ID signature.

## What's included

xtralab builds on [`ajlab`](https://github.com/jtpio/ajlab), the agent-ready
JupyterLab base. On top of it, xtralab pulls in JupyterLab 4.6+ with
`jupyterlab-git`, `jupyterlab-lsp`, `jupyterlab-quickopen`,
`jupyterlab-search-replace`, `jupyterlab-vim`, and a set of light and dark
themes (`jupyterlab-cursor-light`, `jupyterlab-cursor-dark`,
`jupyterlab-day`, `jupyterlab-night`). See
[`pyproject.toml`](./pyproject.toml) for the full list and pinned versions.

The bundled xtralab labextension then adds:

- A path-first file browser in the left sidebar, with `@pierre/trees`
  file-type icons that also carry over to document tabs and the `jupyterlab-git`
  panel.
- Rich git diffs in the `jupyterlab-git` panel, using `@pierre/diffs` for text
  and notebooks and a 2-up / swipe / onion-skin view for images.
- An agent launcher with a prompt box, buttons for the agents installed on your
  machine (Claude, Codex, Antigravity, Copilot, Goose, OpenCode, Kiro, Mistral
  Vibe), a collapsible list of changed files, and an Open row for a terminal,
  notebook, console, or your terminal editor (Neovim or Vim).
- A Terminals panel listing the running terminal sessions, each badged with the
  agent or editor detected inside it. Open terminal tabs in the main area carry
  the same icon.
- Sidebar toggle buttons in the top bar for the left and right areas.

xtralab also ships a set of opinionated defaults: unused UI is hidden for a
quieter workspace, the activity bar sits at the top, and autocompletion,
continuous LSP hinting, code folding, and gitignore-aware quick open are on by
default. See [the bundled labconfig overrides](./jupyter-config/labconfig) for
the full set.

## Connecting agents to Jupyter (MCP)

xtralab runs a [Model Context Protocol][mcp-spec] server inside JupyterLab,
provided by [`jupyter-server-mcp`][mcp]. To let a coding agent drive JupyterLab
through it, register the bundled `jupyter-server-mcp-proxy` console script with
the agent:

```bash
claude mcp add jupyter -- jupyter-server-mcp-proxy
codex mcp add jupyter -- jupyter-server-mcp-proxy
copilot mcp add jupyter -- jupyter-server-mcp-proxy
```

Run this from a terminal inside xtralab, so the proxy inherits the server
environment and discovers the running server automatically. No port is needed,
and a single registration keeps working across restarts. The launcher also
surfaces these commands with copy buttons, filtered to the agents you have
installed.

See the [`jupyter-server-mcp` README][mcp] for other MCP clients.

[mcp]: https://github.com/jupyter-ai-contrib/jupyter-server-mcp
[mcp-spec]: https://modelcontextprotocol.io

## Agent skill

xtralab ships an [Agent Skills][skills] entry at [`agent-skill/`](./agent-skill)
that teaches any coding agent how to customize JupyterLab from plain-English
requests like "hide the status bar", "change the theme", or "add a language
server". The same SKILL.md file works with Claude Code, Codex CLI, Gemini CLI,
GitHub Copilot, and other tools that read the Agent Skills format.

For Claude Code, this repository doubles as a one-plugin marketplace. Inside a
Claude Code session:

```text
/plugin marketplace add jtpio/xtralab
/plugin install xtralab-skills@xtralab
```

For agents that read from `~/.agents/skills/`, such as Codex CLI or Gemini CLI,
clone and copy the skill directory:

```bash
git clone --depth=1 https://github.com/jtpio/xtralab.git /tmp/xtralab
mkdir -p ~/.agents/skills
cp -r /tmp/xtralab/agent-skill/skills/customize-jupyterlab ~/.agents/skills/
```

See [`agent-skill/README.md`](./agent-skill/README.md) for additional install
paths, the list of supported agents, and what the skill knows.

[skills]: https://agentskills.io

## Language servers

xtralab ships [`jupyterlab-lsp`][lsp] with two language servers pre-registered:

- Python, using [`ty`](https://github.com/astral-sh/ty), which is bundled and
  works out of the box.
- TypeScript and JavaScript, using `typescript-language-server`, which you
  install yourself:

  ```bash
  npm install -g typescript-language-server typescript
  ```

  Restart JupyterLab afterwards to pick it up.

To enable another server (bash, yaml, json, pyright, and more), install its
binary and drop a JSON spec into a `jupyter_server_config.d/` directory. For
`pip install xtralab`, run `jupyter --paths` to find one (typically
`~/.jupyter/jupyter_server_config.d/`). For the desktop app, use
`~/Library/Application Support/xtralab/jupyter/config/jupyter_server_config.d/`
on macOS or `~/.config/xtralab/jupyter/config/jupyter_server_config.d/` on
Linux.

```json
{
  "LanguageServerManager": {
    "language_servers": {
      "bash-language-server": {
        "version": 2,
        "argv": ["bash-language-server", "start"],
        "languages": ["bash", "sh"],
        "mime_types": ["text/x-sh", "application/x-sh"],
        "display_name": "bash-language-server"
      }
    }
  }
}
```

See the [`jupyterlab-lsp` documentation][lsp-config] for the full spec.

[lsp]: https://github.com/jupyter-lsp/jupyterlab-lsp
[lsp-config]: https://jupyterlab-lsp.readthedocs.io/en/latest/Configuring.html

## Customizing the launcher

Open `Settings → Settings Editor → xtralab launcher` to override, hide, or add
launcher entries. Both lists below merge with xtralab's defaults by `id`.

### Agents

Edit the `agents` array:

```jsonc
{
  "agents": [
    // Hide an agent
    { "id": "kiro", "enabled": false },

    // Override an agent's command (e.g. point Claude at a shell alias)
    { "id": "claude", "command": "cl", "requireAvailable": false },

    // Add a new agent; promptArgs: [] appends the prompt as a positional arg
    { "id": "aider", "label": "Aider", "command": "aider", "promptArgs": [] }
  ]
}
```

Fields: `id` (required), `label`, `caption`, `command`, `promptArgs` (how the
prompt is spliced: `[]` for positional, `["--flag"]` for flagged, `null` to opt
out), `iconSvg`, `rank`, `enabled`, `requireAvailable`.

### Editors

The **Open** section's terminal-editor tile (Neovim, falling back to Vim) is
configured the same way through an `editors` array:

```jsonc
{
  "editors": [
    // Hide Neovim so the tile falls back to Vim (or disappears if Vim
    // isn't installed either)
    { "id": "nvim", "enabled": false },

    // Add Helix, preferred over the built-ins
    {
      "id": "helix",
      "label": "Helix",
      "command": "hx",
      "rank": -1,
      "iconSvg": "<svg>…</svg>"
    }
  ]
}
```

The launcher shows a single tile: the first editor, by `rank`, whose `command`
is on `PATH`. Disable both built-ins (`nvim`, `vim`) to remove the tile
entirely. Fields: `id` (required), `label`, `caption`, `command`, `iconSvg`,
`rank`, `enabled`, `requireAvailable`.

## Contributing

See [CONTRIBUTING.md](./CONTRIBUTING.md) for the development setup, the Electron
desktop app architecture, and the build pipeline.

## License

BSD-3-Clause
