Metadata-Version: 2.4
Name: sandcastle-sim
Version: 0.1.1
Summary: Smart-home sandbox for AI agents. Bundles Home Assistant + MQTT + a fully simulated home + MCP server + a built-in CLI agent. Runs on a laptop or a Raspberry Pi.
Author: Marco G.
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/itsMarco-G/sandcastle-sim
Project-URL: Documentation, https://github.com/itsMarco-G/sandcastle-sim/tree/main/docs
Project-URL: Repository, https://github.com/itsMarco-G/sandcastle-sim
Project-URL: Issues, https://github.com/itsMarco-G/sandcastle-sim/issues
Keywords: smart-home,home-assistant,mqtt,ai-agent,mcp,model-context-protocol,ollama,raspberry-pi,iot,simulator,dev-kit
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Home Automation
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp[cli]>=1.2
Requires-Dist: aiomqtt>=2.3
Requires-Dist: aiohttp>=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: websockets>=12.0
Requires-Dist: python-dotenv>=1.0
Requires-Dist: rich>=13.7
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Dynamic: license-file

# sandcastle-sim

![build](https://img.shields.io/github/actions/workflow/status/itsMarco-G/sandcastle-sim/pr-check.yml?branch=main)
![pypi](https://img.shields.io/pypi/v/sandcastle-sim)
![license](https://img.shields.io/pypi/l/sandcastle-sim)
![python](https://img.shields.io/pypi/pyversions/sandcastle-sim)

Sandcastle Sim is a sandbox for smart-home AI agents. Real Home Assistant (HA) and Mosquitto run in Docker; the devices are simulated and publish via standard MQTT discovery. From HA's perspective there's no difference between a simulated bulb and a real one, so an agent that works here works against a real home unchanged.

For developers building smart-home agents. One command brings up the full stack. A built-in CLI agent gets you to a working demo in minutes, then drop in your own when you're ready to iterate on prompts, UX, and edge cases.


![architecture](docs/architecture.svg)

## Contents

- [Install](#install)
- [Quickstart](#quickstart)
- [Eval suite](#eval-suite)
- [Connect your agent](#connect-your-agent)
- [Customize](#customize)
- [Read more](#read-more)

## Install

### Prerequisites

- [Docker](https://docs.docker.com/compose/) with Compose v2
- Python >= 3.10
- [Ollama](https://ollama.com) for the built-in CLI agent. Optional if you're connecting your own MCP agent.
- Tested on Mac (Apple Silicon), Linux, and Raspberry Pi 4/5. Windows not yet tested.

### Setup

Create and activate a virtual environment so the install stays isolated from your system Python:

```sh
python -m venv .venv
source .venv/bin/activate
```

Then install:

```sh
pip install sandcastle-sim
```

Planning to make code changes? Install editable from a checkout instead (`pip install -e .`). See [CONTRIBUTING.md](CONTRIBUTING.md) for the full dev setup.

## Quickstart

### Start the stack

```sh
sandcastle-sim start
```

When the castle banner prints in the terminal, the stack is up. Open `http://localhost:8766` and you should see the floor plan with every device laid out across six rooms. Click any device to flip it on or off, dim a light, or open a blind. That's the simulated home.

### Drive it with natural language

In a separate terminal, pull the model and start Ollama:

```sh
ollama pull gemma4:e4b
```

```sh
ollama serve
```

Then back in your first terminal:

```sh
sandcastle-sim chat
```

A chat panel shows up listing the model and the available tools. For your first prompt, try:

```
set up welcome guest
```

The hallway, kitchen, living-room, and both bedroom lights all turn on across the floor plan in real time, with the tool calls the agent fired printed inline. From there, riff off the tool list the chat panel shows.

Run `sandcastle-sim --help` for the full command list.

Using an AI coding agent (Claude Code, Codex, Copilot)? Read [AGENTS.md](AGENTS.md) first.

## Eval suite

AI agents aren't deterministic. The same prompt can produce different outputs as you change the model, the system prompt, or the tool config. Small changes break things in non-obvious ways. The eval suite is how you catch that, and a quick way to see how performance looks on your hardware.

### Baseline (per host)

End-to-end latency on the bundled `quick.yaml` suite against the live stack (HA + MQTT + simulator + MCP) with `gemma4:e4b` (~4 B params, q4_K_M). 

**Avg/case** is the full round trip for one prompt — the model reads it, decides which tool to call, the MCP server dispatches the call, Home Assistant executes it and updates state, and the model writes its reply back. The eval pre-warms the model with a single token so per-case timings reflect steady-state cost only — the cold model-load you see once at the start of `sandcastle-sim chat` is excluded.

| Host | Pass | Avg/case | Slowest |
|---|---|---|---|
| **DGX Spark** (NVIDIA GB10, 128 GB unified) | 5/5 | 3.7 s | `state_query` 9.0 s |
| **MacBook Pro M3 Max** (36 GB unified) | 5/5 | 3.7 s | `state_query` 6.9 s |
| **MacBook Pro M3 Pro** (18 GB unified) | 5/5 | 6.3 s | `state_query` 15.7 s |

Numbers are **median of 3 repeats per case** (`--repeat 3`, the default) so single-shot noise on bandwidth-bound laptops doesn't show up as performance changes.

The five cases in `quick.yaml`:
- `light_off` — "turn off the kitchen counter light"
- `scene_named` — "set up movie night"
- `lock_door` — "lock the front door"
- `climate_setpoint` — "set the temperature to 22"
- `state_query` — "what lights are on right now?" (the heaviest case — the agent has to list devices, then answer)

### Try it

**1. Save a baseline snapshot** of how the agent behaves right now:

```sh
sandcastle-sim eval --save-baseline
```

**2. First go — see the diff workflow without writing any code.** Toggle off the agent's tool-routing optimisation for one run:

```sh
sandcastle-sim eval --no-routing --diff
```

Every case lands a bit slower (no failures), and the diff surfaces clean latency regressions against the baseline you just saved. The flag scopes to that one command; the next eval reverts to defaults automatically.

**3. Normal use — after you change your agent.** Make any change, then:

```sh
sandcastle-sim eval --diff
```

The report leads with cases that used to pass and now fail. Cases that got noticeably slower show up too. Exit code is non-zero if anything regressed, so a coding agent running this in a loop can tell when its own changes broke something.

[evals/quick.yaml](evals/quick.yaml) is the starter suite. Write your own to match your agent's acceptance bar.

## Connect your agent

Point any MCP client at `http://localhost:8765/mcp/`:

```python
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async with streamablehttp_client("http://localhost:8765/mcp/") as (r, w, _):
    async with ClientSession(r, w) as session:
        await session.initialize()
        tools = await session.list_tools()
```

[docs/integrating-your-agent.md](docs/integrating-your-agent.md) covers the Anthropic SDK, OpenAI SDK, and raw streamable-HTTP samples.

## Customize

The kit is set up to be forkable. Topology defines what's in the home, the simulator brings devices to life, the MCP server exposes the contract your agent calls. Here's where each one lives.

- `src/sandcastle_sim/simulator/topology.py` : the home's device list, areas, friendly names
- `src/sandcastle_sim/simulator/` : one module per device type (lights, locks, climate, sensors, vacuum, covers)
- `src/sandcastle_sim/mcp_server/server.py` : MCP tool surface and HA integration
- `src/sandcastle_sim/agent/` : built-in Ollama + MCP agent (one-shot and chat REPL)
- `src/sandcastle_sim/data/gui/index.html` : floor-plan GUI
- `evals/quick.yaml` : starter eval suite for the regression net
- `pyproject.toml` : runtime and dev deps; optional extras `.[dev]`

[docs/extending-the-simulator.md](docs/extending-the-simulator.md) for the deep dive.

## Read more

- [AGENTS.md](AGENTS.md) : orientation for AI coding agents
- [docs/architecture.md](docs/architecture.md) : what runs where and why
- [docs/tool-contract.md](docs/tool-contract.md) : full MCP tool surface
- [docs/integrating-your-agent.md](docs/integrating-your-agent.md) : connect any MCP-speaking agent
- [docs/extending-the-simulator.md](docs/extending-the-simulator.md) : add devices, tools, scenes
- [docs/hardware.md](docs/hardware.md) : Mac, Linux, Pi 4/5 sizing notes
- [docs/adding-matter.md](docs/adding-matter.md) : swap in real Matter hardware
- [CONTRIBUTING.md](CONTRIBUTING.md) : how to contribute

---

Apache-2.0
