Skip to main content

Developer Shell for Home Assistant

A slice of cherry pie, drawn like a 1990s Visual Basic icon

A Home Assistant environment designed for custom component developers, tinkerers and native Python speakers. Makes it easy as pie!

It is an opinionated REPL (Read-Eval-Print-Loop) shell that aims are to make it easier without any configuration to:

  • Exploring of the APIs in context of a live working instance
  • Trialling out snippets of code
  • Debugging code (but see note below)
  • Hotfixing issues that don't have built in support to do so from existing components.

If you're not already comfortable using Python tools to manipulate data on the fly, or better REPL shells in other languages, this is a great way to learn, and faster at the keyboard than clicking around Jupyter notebooks.

This is primarily for developers of custom components, and their LLM agents, though may be of interest for other folk tinkering with Home Assistant. It is a potentially sharp tool, so NOT appropriate for general Home Assistant users.

Features

  • Integrated with rich for pretty object printouts and stack traces
  • Access to all entities via dictionary like interface, obj
  • Usual multi-line editing support and history of Python

All of the above works with standard Home Assistant APIs, referred to as api mode.

Dev Shell also has an advanced custom mode that taps directly into a live Home Assistant using an optional server component available via HACS.

Custom Mode

This mode requires a custom component to be installed on the target Home Assistant server via HACS, or use the supplied scripts to install on a local devcontainer. It adds:

  • Full access to the core Home Assistant Python API via hass
  • Read/write access to the actual objects, e.g. entities and their helpers
  • A frisson of danger

Dev Shell Server

A HACS component that taps into the Home Assistant and acts as a session server over web sockets.

Needed for custom mode only, since api mode only uses standard Home Assistant APIs.

Future Developments

See the Roadmap for where this might go, and your feedback welcome.

[!NOTE] It is not intended to ever be a replacement for a Python debugger, although it may complement one. It also does not intend to replicate PyScript, instead focusing on standard python (PyScript uses MicroPython) even at expense of general usability or home assistance access, and not a general automation script execution service. For most non-developer cases, homeassistant-cli is a better choice, with pre-packaged access to devices, entities, services etc.

Using the Shell

The shell is a full Python REPL shell, implemented as a VSCode NotebookController, with multi-line editing, history etc, living inside an asyncio loop that exposes the live Home Assistant instance as

  • obj - the object tree exposed as a dictionary object and common methods

In custom mode it also offers:

  • hass - the HomeAssistant class at the root of the Python API

So I can write code at the command line like:

pir = obj["/rflink/binary_sensor/hall_pir"]
pir.state = "on"  # non-strict mode, sets entity state with repl as context

The return value of the object is returned to the shell, value printed and available to Python code as _. Tracebacks are printed also, as if they were local (in general everything feels like its local)

## The Object Tree

All of the objects (only entities for now) are arranged in a giant tree, like a file system, exposed as the global variable objs and implemented as Python Mapping object (which provides the MappingView views ItemsView and KeysView)

objs offers:

  • Dictionary style access, using []
    • Raises KeyError if entity or sub-path doesn't exist
    • Each level of the tree returns a sub-tree
    • keys(),values(),items() of the sub-tree shows only that level
    • An OrderedView is used rather than plain MappingView so can be accessed like a list and items are alphabetically organized
  • find()
    • Returns a flat iterable of the entire tree
    • Optionally restrict by platform,area,label
  • show()
    • Dump the most useful info on an object to console

All the usual Python tricks can of course also be used, iterators, comprehensions, classes, lambdas or a simple len().

obj[]

This allows dictionary ('Mapping') access to the object tree.

In the example tree below, the objects and subtrees of objects can be accessed like:

obj["/rflink/sensor/shed_temperature"].state. # prints out temperature
obj["/rflink"]        # the 'light','binary_sensor' and 'sensor' subtrees for rflink
obj["/rflink/sensor"] # all the sensors for rflink
len(obj["/rflink/sensor"]) # count of rflink sensors in this example

#### Example Tree

...
- mqtt
- rflink
  - light
    - staircase_ceiling
    - shed
  - switch
    - upstairs_pixie
  - binary_sensor
    - porch_pir
    - shed_door
  - sensor
    - shed_temperature
    - kitchen_humidity
...

[!NOTE] In the roadmap, there will be a visual Object Browser to view and select entities. For now, it is accessible only via Python code. It also may extend beyond entities, to things like areas, users, categories and devices.

obj.find('..')

Where the dictionary access gives a nested directory view of the object tree, find provides a flat iteration with no order guarantees, so its fast and simple and can be sorted the usual Python way if needed.

find also has built in filters, to narrow the big list of objects by one or more platform,domain,area,label - each of these will take a single string or list of strings, and they can be combined to narrow down the list.

{(o.entity_id, o.state) for o in obj.find(domain="binary_sensor")}
Raw Objects

In API Client mode, find() returns a local proxy for the remote class, normalized to look more like the same object you'd get in custom mode. Switching raw=True will bypass this and you'll get the object untouched as it was received from the API.

#### obj.find_paths(..)

Identical to obj.find() except it only returns an iterable of the object paths rather than the objects themselves. Ideal for plugging into some logic that will then call obj[path] on each one.

list(objs.find(area="kitchen"))  # list names of all entities in kitchen
sorted(objs.find(area=["kitchen", "shed"]))

#### obj.find_names(..)

Same as obj.find_paths() except it returns the object bare name, as it would appear in Home Assistant, e.g. sensor.bathroom_humidity

obj.show(..)

The show function will give a pretty version of an object where it knows how. For entities this means it combines the RegistryEntry and Entity information, drops some boring internal stuff, filters out all the None values and turns datetime.datetime structures into local date times.

obj.show('/unifi/sensor/kitchen_wifi_cpu_utilization')

Starting the Shell

Use the HASS_SERVER environment variable or the --url command line argument if the Home Assistant server is not running locally ( i.e. http://127.0.0.1:8123). A long lived access token is needed at --token or in HASS_TOKEN.

Custom Mode for Real Server

On a real instance, install via HACS and add Developer Shell for Home Assistant from Settings → Devices & services → Add integration (or add dev_shell_server: to configuration.yaml, which is imported as a config entry), then on the local terminal set HASS_SERVER and HASS_TOKEN (an admin long-lived token).

The quickest way to run the shell is using uv, which you can do without cloning this repo or making any other downloads.

uv run --with homeassistant-devshell dev_shell         

Get help on the arguments in the usual way,

uv run --with homeassistant-devshell dev_shell --help       

If you do have this repo checked out, you can also use a direct run which means you can also tinker locally with dev_shell code.

uv run dev_shell         

Install Local Home Assistant with the Custom Mode Server

Dev instance (devcontainer, or directly on a host with Python 3.14):

dev/setup.sh                 # installs HA into its own venv + the CLI (devcontainer runs this)
dev/run-ha.sh                # HA on :8123 with custom_components/dev_shell_server symlinked in
uv run python dev/bootstrap.py   # onboard (user dev/dev) and write dev/.env with a token

Using it (host or container):

set -a; . dev/.env; set +a
uv run dev_shell                                         # interactive
uv run dev_shell exec 'hass.states.get("sun.sun")'
uv run dev_shell exec - <<'PY'
await hass.services.async_call("light", "toggle", {"entity_id": "light.kitchen_lights"}, blocking=True)
hass.states.get("light.kitchen_lights").state
PY

Running Tests

Tests: uv run pytest covers the engine without needing HA.

Metadata

Release files for homeassistant-devshell 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for homeassistant-devshell 0.1.0
File Size Uploaded
homeassistant_devshell-0.1.0.tar.gz 18.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for homeassistant-devshell 0.1.0
File Interpreter ABI Platform
homeassistant_devshell-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.1 kB

Release files / homeassistant_devshell-0.1.0.tar.gz

Download URL homeassistant_devshell-0.1.0.tar.gz
Size 18.0 kB
Tags Source
SHA-256 checksum
How to use checksums
900560747cd50a7eadfd4270a29fef9813e30fc2cbc1071c2e0b0f619e55fffb
BLAKE2b-256 checksum
How to use checksums
80e031039a20f1ab4466933ec85c5a2358091996240a5b6f89239a1fe81cf1fd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / homeassistant_devshell-0.1.0-py3-none-any.whl

Download URL homeassistant_devshell-0.1.0-py3-none-any.whl
Size 21.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
77c9eaf2274fc892972416750fcc3a1dbdf95184d8531be91cde4d2648912aad
BLAKE2b-256 checksum
How to use checksums
19bfb543d372902c2661387626d88203bfa2dc1f8d2423c0bdbeba59cb96fbfa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page