This is meant for environments where you don’t want to stand up a full supervisor stack (or don’t have one): quick multi-service prototypes, dev environments, constrained userlands, etc.
### What it does
* Spawn/manage shells with:
* **PTY**: interactive terminal sessions (resize, input, stream)
* **Pipes**: stdin/stdout/stderr streams (good for daemons/LSPs)
* **dtach**: persistent sessions you can attach/detach to (survives manager restarts)
* *Runtime isolation* (the big feature): shells are namespaced by
`~/.cache/framework_shells/runtimes/<repo_fingerprint>/<runtime_id>/...`
so two clones of the same repo can run concurrently without cross-adoption or cross-control.
* *Control surfaces*: CLI + optional FastAPI/WS UI for listing, logs, and lifecycle actions.
* Optional *hooks* for host integration (external registries/telemetry).### CLI quickstart
```bash # list shells fws list
# run a one-off shell (no spec) fws run --backend pty --label demo -- bash -l -i
# apply a YAML shellspec (recommended) fws up shells.yaml
# terminate shells fws down
# attach to a dtach-backed shell fws attach <shell_id>
# show managed shells + procfs descendants fws tree --depth 4 ```
### Shellspec example
```yaml version: "1" shells: worker: backend: proc cwd: ${ctx:PROJECT_ROOT} subgroups: ["worker", "project:${ctx:APP_ID}"] command: ["python", "-m", "your_module.worker", "--port", "${free_port}"] ```
### Isolation + security model (simple by default)
* `FRAMEWORK_SHELLS_SECRET` derives the `runtime_id` (namespace) and API tokens. * If the secret is set, mutating API endpoints require:
* `Authorization: Bearer <token>` (or `X-Framework-Key`).
* If the secret is unset, auth is disabled (dev mode).Hard limit: if two runtimes share the same OS user/UID, the OS may still allow signaling each other’s processes. The guarantee is: no cross-count/adopt/control *through the library’s control plane*.
### Real-world usage
I use this as the substrate of a full dev environment where “apps are shells” (terminals, IDE + LSP, agent/MCP, aria2 RPC, file explorer, llama.cpp runner, etc.). Repo:
```text https://github.com/mrsurge/termux-extensions-2 ```
### Feedback I want
* Does the secret/fingerprint/runtime isolation contract feel right? * Any obvious foot-guns in the default API/CLI? * Expectations vs systemd/supervisord/tmux/dtach: where would you use this?
github.com/mrsurge/framework-shells
pip install "framework-shells @ git+https://github.com/mrsurge/framework-shells@main"
```bash fws --help ```