Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Remote State
# RemoteState

[![CI](https://github.com/forman/remotestate/actions/workflows/ci.yml/badge.svg)](https://github.com/forman/remotestate/actions/workflows/ci.yml)
[![CI](https://github.com/bcdev/remotestate/actions/workflows/ci.yml/badge.svg)](https://github.com/bcdev/remotestate/actions/workflows/ci.yml)
[![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
[![Vite](https://img.shields.io/badge/Vite-646CFF?logo=vite&logoColor=white)](https://vite.dev/)
[![Ruff](https://img.shields.io/badge/Ruff-2C2F3A?logo=ruff&logoColor=white)](https://docs.astral.sh/ruff/)
Expand All @@ -9,10 +9,14 @@

> **Python state, React UI.** One runtime for notebook apps and addon backends.

Remote State is a Python-first framework for building stateful React frontends.
_RemoteState_ is a Python-first framework for building stateful React frontends.
It lets you define application state, actions, and queries in Python, then
render the UI in React/TypeScript over a WebSocket bridge.

Package-specific docs:
- [Python package README](./remotestate-py/README.md)
- [TypeScript package README](./remotestate-ts/README.md)

The library is designed around two primary use cases:

1. **React frontends for Python code** - especially notebook-driven UIs, where a Jupyter cell or Python script owns the state and the browser only renders the interface.
Expand All @@ -23,7 +27,7 @@ React handles presentation, interaction, and reactivity on the browser side.

---

## What Remote State Provides
## What RemoteState Provides

- **Python-owned application state** - store nested state in a `Store` and mutate it through actions.
- **Read and write separation** - use `@action` for mutations and `@query` for read-only calls.
Expand Down Expand Up @@ -237,15 +241,15 @@ Re-running the same Jupyter cell restarts the server automatically.

### `createRemoteState<TService>(url)`

Creates a typed Remote State bridge.
Creates a typed RemoteState bridge.

```typescript
const remoteState = createRemoteState<MyService>("ws://localhost:9753/ws");
```

### `RemoteStateProvider` and `useRemoteStateClient<TService>()`

React context wrapper for a Remote State bridge bound to a WebSocket URL, plus
React context wrapper for a RemoteState bridge bound to a WebSocket URL, plus
a hook to access it.

```tsx
Expand Down Expand Up @@ -310,7 +314,7 @@ re-renders on invalidation.
### Setup

```bash
git clone https://github.com/your-username/remotestate
git clone https://github.com/bcdev/remotestate
cd remotestate

# Python
Expand Down Expand Up @@ -348,12 +352,12 @@ remotestate generate my_service.py --out ui/src/MyService.ts
## Architecture

```text
Python (source of truth) TypeScript / React (renderer)
────────────────────────────── ──────────────────────────────
Store StoreImpl (cache)
state lazy fetch per path
actions + queries ──► invalidate -> re-render
progress events ──► task updates
Python (source of truth) TypeScript / React (renderer)
────────────────────────────── ──────────────────────────────
Store StoreImpl (cache)
state lazy fetch per path
actions + queries ──► invalidate -> re-render
progress events ──► task updates

Service
@action -> mutate state ──► remoteState.action()
Expand Down Expand Up @@ -399,4 +403,4 @@ and TypeScript strict mode on the JavaScript side.

## License

MIT © Norman Fomferra
MIT © [@forman](https://github.com/forman)
1 change: 1 addition & 0 deletions remotestate-py/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ __pycache__/
.ipynb_checkpoints/
.venv/
uv.lock
dist/
21 changes: 21 additions & 0 deletions remotestate-py/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Norman Fomferra

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
36 changes: 36 additions & 0 deletions remotestate-py/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# RemoteState - Python

`remotestate` is the Python runtime for the _RemoteState_ library.

It gives you:

- `Store` for application state
- `Service` for defining actions and queries
- `action` and `query` decorators
- `serve()` for exposing the backend to the React frontend

## Install

```bash
pip install remotestate
```

## Quick Start

```python
import remotestate as rs

store = rs.Store({"count": 0})


class MyService(rs.Service):
@rs.action
async def increment(self):
self.store.set("count", self.store.get("count") + 1)


rs.serve(MyService(store), dist_dir="my-ui/dist")
```

For the full project overview, see the repository root README:
[Remote State](https://github.com/bcdev/remotestate)
2 changes: 1 addition & 1 deletion remotestate-py/notebooks/demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"id": "b5855fdc-6ffc-486e-8172-8202e56f7778",
"metadata": {},
"source": [
"Assumes you have checked out https://github.com/forman/remotestate-demo next to this project \n",
"Assumes you have checked out https://github.com/bcdev/remotestate-demo next to this project\n",
"and called `npm run build`. "
]
},
Expand Down
47 changes: 47 additions & 0 deletions remotestate-py/pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 22 additions & 5 deletions remotestate-py/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
[project]
authors = [{name = "Norman Fomferra", email = "norman.fomferra@brockmann-consult.de"}]
name = "remotestate"
version = "0.1.0"
authors = [{name = "forman"}]
description = "Python state, React UI."
readme = "README.md"
keywords = ["python", "state", "react", "ui", "jupyter"]
license = {text = "MIT"}
license-files = ["LICENSE"]
requires-python = ">= 3.12"
dependencies = [
"fastapi>=0.136,<0.137",
"pydantic>=2,<3",
"uvicorn>=0.46,<0.47"
]
name = "remotestate"
requires-python = ">= 3.12"
version = "0.1.0"
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries :: Python Modules",
]
urls = { Homepage = "https://github.com/bcdev/remotestate", Issues = "https://github.com/bcdev/remotestate/issues", Repository = "https://github.com/bcdev/remotestate"}

[tool.hatch.build.targets.wheel]
packages = ["src/remotestate"]

[build-system]
build-backend = "hatchling.build"
requires = ["hatchling"]
requires = ["hatchling>=1,<2"]

[tool.ruff]
src = ["src/remotestate"]
Expand Down Expand Up @@ -44,9 +58,12 @@ pytest-cov = ">=7.1.0,<8"
ruff = ">=0.15.11,<0.16"

[tool.pixi.pypi-dependencies]
build = ">=1,<2"
hatchling = ">=1,<2"
remotestate = { path = ".", editable = true }

[tool.pixi.tasks]
build = "python -m build"
format = "ruff format src"
checks = "ruff check src"
tests = "pytest tests"
Expand Down
21 changes: 21 additions & 0 deletions remotestate-ts/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Norman Fomferra

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
21 changes: 21 additions & 0 deletions remotestate-ts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# RemoteState - TypeScript/React

`remotestate` is the TypeScript and React bridge of the _RemoteState_ library.

This package provides the frontend client, provider, and hooks that pair with
the Python backend from the main repository.

## Install

```bash
npm install remotestate
```

## Use

```ts
import { RemoteStateProvider, useRemoteStateClient } from "remotestate";
```

For full project documentation, see the repository root README:
[Remote State](https://github.com/bcdev/remotestate)
27 changes: 27 additions & 0 deletions remotestate-ts/package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,42 @@
{
"name": "remotestate",
"version": "0.1.0",
"description": "Python state, React UI.",
"type": "module",
"main": "./dist/remotestate.js",
"types": "./dist/remotestate.d.ts",
"license": "MIT",
"author": "forman",
"homepage": "https://github.com/bcdev/remotestate#readme",
"bugs": {
"url": "https://github.com/bcdev/remotestate/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/bcdev/remotestate.git",
"directory": "remotestate-ts"
},
"keywords": [
"react",
"typescript",
"state",
"websocket",
"hooks"
],
"files": [
"dist",
"README.md",
"LICENSE"
],
"exports": {
".": {
"import": "./dist/remotestate.js",
"types": "./dist/remotestate.d.ts"
}
},
"engines": {
"node": ">=20"
},
"scripts": {
"build": "tsc && vite build",
"tests": "vitest run",
Expand Down