# Editor setup: VSCode

You can use any editor with qc-rs, but **Visual Studio Code** (VSCode) is a good default: it is free, works
the same on every OS, has excellent Python and Jupyter support, and — importantly for quantum chemistry —
can edit and run code on a **remote machine** (a cluster) as if it were local. This chapter gets you a
comfortable qc-rs workspace. It is optional; if you prefer another editor, skip to the
[Quickstart](quickstart.md).

## Install VSCode and the essentials

Install VSCode from [code.visualstudio.com](https://code.visualstudio.com/), then add a few extensions
(the Extensions panel is the square icon in the sidebar, or `Ctrl/Cmd+Shift+X`):

- **Python** and **Pylance** (Microsoft) — language support, completion, and interpreter management;
- **Jupyter** (Microsoft) — run notebooks and interactive cells;
- **Remote - SSH** (Microsoft) — edit and run on a remote machine (see below);
- optional: **Live Preview** (to preview this manual's HTML), and **rust-analyzer** if you will touch the
  Rust core.

## Recommended: an AI coding assistant

Before going further, **install an AI coding assistant — [Claude Code](https://claude.ai) or
[Codex](https://chatgpt.com/codex)** — and keep it open in VSCode's integrated terminal
(**Terminal → New Terminal**, or `` Ctrl+` ``). This is not an optional nicety for qc-rs: it is the
**AI-first ("vibe coding") way qc-rs is meant to be used**, and the same workflow the project is built with.
A few concrete reasons it pays off immediately:

- **It builds qc-rs for you.** On a new machine, ask it to run `make setup` / `make install` and save a
  build profile — it detects your BLAS/MPI/Python and fixes the flags itself. This is the recommended build
  path in [Installation §3.1](installation-and-make-setup.md).
- **It answers "how do I…" from inside the repo.** It reads the source and this manual, so you can ask it
  how to run a calculation, what an option does, or why a build failed — without leaving the editor.
- **It writes and edits code with you.** Because the assistant lives in the terminal, it edits the very
  files open in VSCode; you review its diffs in the editor's source-control view.

The [next chapter](ai-coding-clis.md) is dedicated to installing and driving these tools (the one-line
`curl … | sh` installers, no Node.js required). Claude Code also ships an official **VSCode extension**
(search "Claude Code" in the Extensions panel) that adds a side panel on top of the terminal CLI, if you
prefer a GUI.

## Working on a remote machine (cluster)

Quantum-chemistry jobs often run on a shared server, not your laptop. With **Remote - SSH** you open the
remote machine *inside* VSCode:

1. `Ctrl/Cmd+Shift+P` → **"Remote-SSH: Connect to Host…"** → pick (or add) your server, e.g. `you@cluster`.
2. A new VSCode window opens, running *on the server*. **File → Open Folder…** and choose your qc-rs
   checkout.
3. From here everything — the terminal, Python, the manual build — runs on the server; your laptop is just
   the screen and keyboard.

:::{tip}
Remote-SSH also **forwards ports** automatically. That is how you view a locally-served web page (like the
built manual) in your laptop's browser — see "Preview the manual" below.
:::

## Point VSCode at the qc-rs environment

VSCode needs to know which Python to use — the `uv` venv that has qc-rs installed. **`make setup` already
did this for you**: it generated a git-ignored `.vscode/` folder with four files. It is worth reading them,
because they explain *how* VSCode knows to use your venv, rebuild the Rust core, and run with the right
environment. (All of this comes from your profile — see
[Installation → what a profile looks like](#install-profile).)

### `settings.json` — the workspace settings

```json
{
  "python.defaultInterpreterPath": "/home/you/local/myproj/.venv/bin/python",
  "python.envFile": "${workspaceFolder}/.vscode/my.env",
  "python.testing.pytestEnabled": true,
  "python.testing.pytestArgs": ["tests"],
  "python.terminal.activateEnvironment": true,
  "terminal.integrated.env.linux": { "UV_PROJECT": "/home/you/local/myproj" },
  "rust-analyzer.cargo.noDefaultFeatures": true,
  "rust-analyzer.cargo.features": ["intel-mkl-system", "xc-bundled", "pcm"],
  "rust-analyzer.cargo.extraEnv": { "MKLROOT": ".../mkl/2025.2", "MKL_THREADING_LAYER": "GNU" }
}
```

- **`python.defaultInterpreterPath`** — points VSCode at your venv's Python (the one with qc-rs), so *Run*
  and the terminal use it automatically.
- **`python.envFile`** — loads environment variables from `.vscode/my.env` (below) whenever you run code.
- **`python.testing.pytestEnabled` / `pytestArgs`** — turns on the **Testing** panel, running `pytest tests`
  — you can run and debug individual tests with a click.
- **`python.terminal.activateEnvironment` / `terminal.integrated.env.linux.UV_PROJECT`** — auto-activate the
  venv in new integrated terminals and set `UV_PROJECT`, so `uv` commands act on the right project.
- **`rust-analyzer.cargo.*`** — only relevant if you edit the **Rust** core: they make the Rust language
  server compile with the same features/env as your build, so its inline errors match reality.

### `my.env` — runtime environment variables

```text
# GENERATED by mytools/setup/bootstrap.py — do not edit by hand.
MKL_THREADING_LAYER=GNU
MKL_INTERFACE_LAYER=LP64
LD_LIBRARY_PATH=.../mpi/2021.16/lib
```

These are the variables the extension needs *at run time* (the MKL threading/interface layers; the MPI
library path). `settings.json` and the debug configs load this file, so pressing *Run* or `F5` "just works"
without you exporting anything.

### `tasks.json` — the build task

One shell task, labelled like *"maturin develop (MKL, myproj)"*. Its command sources your build environment
(`~/.cargo/env`, the venv, the oneAPI `vars.sh`), sets `RUSTFLAGS`, and runs `maturin develop` with your
feature list — i.e. exactly the `build.pre` / `rustflags` / `maturin_args` from your profile. You run it
with **`Ctrl/Cmd+Shift+P` → "Tasks: Run Build Task"** instead of typing `make install`.

### `launch.json` — run/debug configurations

Two `debugpy` configurations, *"Python: Current File (qc-rs)"* and *"Python: helloworld.py"*. Each one:
runs in the integrated terminal with your interpreter, loads `.vscode/my.env`, sets `justMyCode: false` (so
you can step into library code too), and — crucially — has **`preLaunchTask`** set to the build task above,
so **VSCode rebuilds qc-rs before every debug run**. Press `F5` and your edited Rust core is recompiled,
then your script runs.

So after `make setup`, VSCode should already select the right interpreter. If it does not,
`Ctrl/Cmd+Shift+P` → **"Python: Select Interpreter"** and pick the one under your `uv` venv (its path is in
`settings.json`). The chosen interpreter is shown in the status bar at the bottom.

:::{note}
`.vscode/` is **git-ignored machine config** generated by `make setup` — it is yours and is not committed.
Re-run `make setup` if you ever need to regenerate it (e.g. after changing venv or backend).
:::

## Run and debug code

- **Run a script.** Open a `.py` file and press the ▷ **Run** button (top right), or `F5` to run with the
  debugger.
- **Rebuild qc-rs from the editor.** After changing the Rust core, `Ctrl/Cmd+Shift+P` → **"Tasks: Run Build
  Task"** runs the maturin build task instead of typing `make install`.
- **Interactive / notebooks.** Create a `.ipynb` notebook (or add `# %%` cell markers to a `.py` file) and
  run cells one at a time — ideal for exploring a calculation, plotting convergence, or viewing molecules.
  In a notebook, `%matplotlib inline` shows plots in the cell.
- **Debug.** Click in the gutter to set a breakpoint, then `F5`. Execution pauses there so you can inspect
  variables — very useful when a script does not do what you expect.

:::{tip} A Python note
An `.ipynb` **notebook** interleaves code cells and their output (numbers, tables, figures) in one
document. It is the most beginner-friendly way to try qc-rs: run a cell, see the result, edit, run again.
:::

## Jupyter notebooks & `helloworld.ipynb`

A notebook is the most enjoyable way to explore qc-rs: run one cell, see the result, tweak, run again. The
repo ships one to play with — **`myworkspace/helloworld.ipynb`** — which runs a couple of real SCF
calculations and streams the live, quantum-chemistry-style log.

### Set up the notebook environment

1. Make sure **`ipykernel`** is in your venv (it lets VSCode start a kernel there):
   `uv add --dev ipykernel --project "$UV_PROJECT"`, then rebuild qc-rs with `make install` (recall that
   `uv add` prunes the extension).
2. Install the **Jupyter** extension (in the extensions list near the top of this chapter).

### Pick the right kernel — so `import qc` works

This is the one step people trip on. A notebook runs against a **kernel** (a Python), and it *must* be the
**uv venv Python that has qc-rs installed** — otherwise the first cell fails with
`ModuleNotFoundError: No module named 'qc'`. `make setup` already recorded that interpreter in
`.vscode/settings.json` (`python.defaultInterpreterPath`), so VSCode usually offers it. To be sure: open
`myworkspace/helloworld.ipynb`, click **"Select Kernel"** (top-right of the notebook) → **"Python
Environments…"** → choose the interpreter under your `uv` project (e.g. `…/myproj/.venv/bin/python`, the
*same* path shown in `settings.json`).

:::{tip} Kernel = VSCode interpreter = your uv Python
The notebook **kernel**, the VSCode **interpreter** (`python.defaultInterpreterPath`), and the `python` in
your **uv project** must all be the *same* venv. If they drift apart, `import qc` breaks. When in doubt, run
`import sys; print(sys.executable)` in a cell — it should print your `…/.venv/bin/python`.
:::

### Play with it, and watch the log

Open `myworkspace/helloworld.ipynb` and run the cells (▷ on a cell, or **Run All**). It builds a water
checkpoint and runs an SCF, then a heavier example (a silver complex with ECP + RI + DFT + dispersion). The
best part is the **live log** from `run(log=...)`:

```python
mychk = qc.chk.new(atom="O 0 0 0; H 0.757 0.586 0; H -0.757 0.586 0",
                   ao="def2-svp", unit="angstrom")
mychk = mychk.scf(ref="r").run(log="stdout")     # stream a quantum-chemistry-style transcript
```

```text
── System ───────────────────────────────────────────────
  formula H2O
  charge 0   spin 1 (2S+1)   electrons 10 (5α / 5β)
  basis sets (spherical AOs):  AO def2-svp   24 functions
  nuclear repulsion: 9.1939131606 Eh
── plan ──────────────────────────────────────────────────
  2 steps (topological order)
    1  guess:sad        [auto]         ⇒ guess, density, mo
    2  scf:rhf          [user]  ← 1    ⇒ scf-ref, mo, density
── SCF rhf ────────────────────────────────────────────────
 cycle        E / Eh             dE       RMS[grad]  accel
     1       -75.465273843             -      2.56e-1      —
     …
     9       -75.961008958     -9.42e-11      2.37e-7  cdiis
✓ converged in 9 cycles
```

That transcript — the system summary, the auto-inserted `sad` guess (from [Core concepts](concepts.md)),
the SCF cycle table with the DIIS accelerator, and the convergence check — is what real quantum-chemistry
output looks like.

### A few `run(...)` options

`.run()` takes options for output and parallelism. The handful you will reach for first (the full set is in
the [Logging & output chapter](../20-guide/logging-output.md)):

| option | what it does |
|---|---|
| `log="stdout"` | stream the live transcript to the cell (a file path or object also works) |
| `log_style="modern"` / `"orca"` | pick the visual style of the transcript |
| `plot=True` | draw the SCF convergence plot inline (needs matplotlib + `%matplotlib inline`) |
| `nthread=8` | use 8 CPU threads for this run |

After a run you can replay or inspect the transcript without recomputing: `mychk.log()` prints it as text
(also `format="markdown"`/`"jsonl"`), `mychk.show()` renders a snapshot of the current state and results,
and `mychk.run_events()` returns the raw events as JSON.

## Preview the manual

To read this manual as you edit it, build the HTML and preview it:

```bash
make docs-html          # build docs/user/{en,ja}/_build/html  (needs jupyter-book)
```

Then either right-click `docs/user/en/_build/html/index.html` → **"Open with Live Preview"**, or serve it
and let VSCode forward the port:

```bash
python -m http.server 8000 --directory docs/user/en/_build/html
```

and open `http://localhost:8000` in your browser (Remote-SSH forwards port 8000 automatically).

With your editor and notebook ready, run your first calculation in the
[Quickstart](quickstart.md).
