> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ns.rocks/llms.txt
> Use this file to discover all available pages before exploring further.

# First Machine

> Create a hosted Nullspace machine with Python in under five minutes.

Run your first hosted Nullspace machine from any laptop with Python 3.11+ and
a private-beta API key.

<Steps>
  <Step title="Install the CLI">
    <CodeGroup>
      ```bash macOS / Linux theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
      python3 -m venv .venv
      source .venv/bin/activate
      python -m pip install --upgrade pip
      python -m pip install "nullspace-sdk[cli]==1.0.0"
      ```

      ```bash uv theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
      uv venv
      source .venv/bin/activate
      uv pip install "nullspace-sdk[cli]==1.0.0"
      ```

      ```fish fish theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
      python3 -m venv .venv
      source .venv/bin/activate.fish
      python -m pip install --upgrade pip
      python -m pip install "nullspace-sdk[cli]==1.0.0"
      ```

      ```powershell PowerShell theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
      py -3.11 -m venv .venv
      .\.venv\Scripts\Activate.ps1
      python -m pip install --upgrade pip
      python -m pip install "nullspace-sdk[cli]==1.0.0"
      ```

      ```batch Windows cmd theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
      py -3.11 -m venv .venv
      .venv\Scripts\activate.bat
      python -m pip install --upgrade pip
      python -m pip install "nullspace-sdk[cli]==1.0.0"
      ```
    </CodeGroup>

    <Accordion title="PowerShell blocks activation?">
      Run this first, then activate again:

      ```powershell theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
      Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
      ```
    </Accordion>
  </Step>

  <Step title="Save your API key">
    Ask the Nullspace team for a beta key, then save it with the hosted API URL:

    ```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    nullspace auth login --api-url https://api.13-215-85-171.sslip.io
    ```

    The command prompts for the key and stores it in your local Nullspace config —
    no environment variables needed for local use.
  </Step>

  <Step title="Check access">
    ```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    nullspace doctor
    ```

    When the checks pass, `doctor` prints `Run: nullspace quickstart`.
  </Step>

  <Step title="Run the first machine">
    ```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    nullspace quickstart
    ```

    Expected output:

    ```text theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    Creating machine from template 'base'...
    Machine ready: mch_...
    hello from nullspace
    hello from a machine
    Preview URL: https://preview.your-nullspace-domain/.../?edge_token=...
    ```

    Open the preview URL while the command waits for Enter — it serves a live HTTP
    server running inside your machine. Pressing Enter stops the server and
    destroys the machine.
  </Step>
</Steps>

## The same flow in Python

The CLI quickstart runs the exact SDK flow you would write yourself. Save it
locally with `nullspace quickstart --write quickstart.py`, or create it by
hand:

```python quickstart.py theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
from nullspace import Machine

with Machine.create(template="base", timeout=300) as machine:
    print(f"Machine ready: {machine.id}")

    result = machine.commands.run("echo 'hello from nullspace'", shell=True)
    print(result.stdout.strip())

    machine.files.write("/workspace/hello.txt", "hello from a machine\n")
    print(machine.files.read("/workspace/hello.txt").strip())

    server = machine.commands.run(
        "cd /workspace && python3 -m http.server 8080 --bind 0.0.0.0",
        shell=True,
        background=True,
    )
    try:
        url = machine.get_url(8080)
        print(f"Preview URL: {url}")
        input("Open the URL, then press Enter to stop the server and destroy the machine...")
    finally:
        server.kill()
```

Run it from the activated environment with `python quickstart.py`.

A few things worth noticing:

* General filesystem APIs also accept valid machine-scoped absolute paths like
  `/tmp/result.txt`; `/workspace` remains the default mutable work tree.
* The `with` block destroys the machine on exit. Without a context manager,
  call `machine.kill()` when you are done.
* The preview URL is a signed link to a port inside the microVM — see
  [Preview URLs](../networking/preview-urls).
* For the command line reference and more CLI workflows, see the
  [Python CLI Guide](../guides/python-sdk/cli).

## Configuration for scripts and CI

Environment variables work everywhere the CLI config does:

```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
export NULLSPACE_API_KEY=ns_live_...
export NULLSPACE_API_URL=https://api.13-215-85-171.sslip.io
```

The SDK and CLI also read project `.env`, `~/.config/nullspace/config.json`,
and `~/.nullspace/config.json`. Explicit `api_key=` and `base_url=` arguments
override local config when you need per-process values.

<Accordion title="Optional: set up Claude Code or Codex locally">
  If you want Claude Code or Codex on your laptop to build with Nullspace,
  install the MCP extra and then the project-local agent pack:

  ```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  python -m pip install "nullspace-sdk[cli,mcp]==1.0.0"
  cd /path/to/your/project
  nullspace docs install --agent all
  ```

  This writes local agent docs (`.nullspace/agent-docs/`), Claude Code and Codex
  skills, managed `CLAUDE.md`/`AGENTS.md` blocks, and MCP config. Use
  `--agent claude-code` or `--agent codex` for a narrower install. The installer
  needs no API key, stores no secrets, and never edits user-level files.
</Accordion>

## Troubleshooting

| Symptom                         | Check                                                                                                                                        |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `NULLSPACE_API_KEY is required` | Run `nullspace auth login --api-url https://api.13-215-85-171.sslip.io`, export `NULLSPACE_API_KEY`, or pass `api_key=` to `Machine.create`. |
| `401` or `403`                  | Confirm the key is active and sent as `Authorization: Bearer ...`.                                                                           |
| Machine create times out        | Increase `--timeout` or `timeout=` during private beta, or retry when capacity is available.                                                 |
| Preview URL does not respond    | Bind the server to `0.0.0.0`, keep the background process running, then retry `machine.get_url(port)`.                                       |

## Next steps

<CardGroup cols={2}>
  <Card title="Browse recipes" icon="list" href="./recipes">
    Common next tasks: files, ports, fork, templates, volumes, and raw HTTP.
  </Card>

  <Card title="Run notebook-style code" icon="square-terminal" href="../code-interpreter/overview">
    Stateful Python cells, packages, charts, and artifacts.
  </Card>

  <Card title="Run an agent in a machine" icon="bot" href="../agents/overview">
    Codex, Claude Code, Amp, OpenCode — or deploy your own.
  </Card>

  <Card title="Build a template" icon="layers" href="../templates/overview">
    Bake dependencies once and launch repeatable machines.
  </Card>
</CardGroup>
