# Pi Shell - Enhanced Raspberry Pi Management Tool
A CLI tool for managing multiple Raspberry Pi devices over SSH with automatic Pi detection through symlinks. But why does this exist [BHB.bzz](https://bhb.buzz/pi-shell.html)?
## 📦 Installation
### Recommended: Install from PyPI
```bash
pip install pi-shell
```
### Alternative: Install from Source
```bash
# Clone the repository
git clone https://github.com/mcyork/pi-shell.git
cd pi-shell
# Install using pip
pip install .
# Or install in editable mode for development
pip install -e .
```
This automatically installs all dependencies:
- `paramiko` - SSH library for Python
- `PyYAML` - YAML configuration file parser
- `cryptography` - For SSH key generation
After installation, the `pi-shell` command will be available globally.
## 🚀 Quick Start
### Option 1: SSH Key Authentication (Recommended)
1. **Configure a Pi with automatic key setup:**
```bash
pi-shell add pi1 --host 192.168.1.10 --user pi --password raspberry --push-key
```
This will:
- Generate an SSH key pair at `~/.ssh/pi-shell` (if it doesn't exist)
- Push the public key to the Pi for password-less authentication
- Save the configuration to `~/.config/pi-shell/config.yml` with the key path
**Benefits:** No passwords stored in config, more secure, no password prompts!
### Option 2: Password Authentication
1. **Configure a Pi with password:**
```bash
pi-shell add pi1 --host 192.168.1.10 --user pi --password raspberry
```
This saves the Pi configuration to `~/.config/pi-shell/config.yml`.
**Note:** Password will be stored in plain text in the config file.
2. **Check its status:**
```bash
pi-shell status pi1
```
3. **Run a command:**
```bash
# Using the --pi flag
pi-shell run "uname -a" --pi pi1
# Or if pi1 is set as default
pi-shell run "uname -a"
```
## 🔧 Available Commands
The tool is organized into sub-commands for different actions.
### Core Actions (`run`, `read`, `write`)
These commands perform actions on a target Pi.
- `run <command>`: Execute a shell command.
- `run-stream <command>`: Stream output from a long-running command.
- `read <remote_path>`: Read a file from the Pi.
- `write <remote_path> <content>`: Write content to a file.
**Example:**
```bash
# Reboot pi2
./pi2 run "sudo reboot"
# Read the hostname from the default pi
./pi-shell read "/etc/hostname"
```
### Management Actions (`add`, `remove`, `list`, `status`, `set-default`)
These commands help you manage your list of Pis.
- `add <name> --host <host> --user <user> --password <password> [--push-key]`: Add a new Pi. Creates a symlink.
- Use `--push-key` to automatically set up SSH key authentication (recommended - password used once to push key, then not stored)
- Without `--push-key`, password is stored in config for ongoing authentication (less secure)
- `remove <name>`: Remove a Pi. Deletes the symlink.
- `list`: Show all configured Pis in a table.
- `set-default <name>`: Set the default Pi for commands.
- `status [name]`: Check connectivity and get the hostname for one or all Pis.
**Example:**
```bash
# See all configured Pis
./pi-shell list
# Check if all Pis are online
./pi-shell status
# Add a new Pi named 'pi-hole' with SSH key authentication (recommended)
./pi-shell add pi-hole --host 192.168.1.20 --user admin --password raspberry --push-key
# Or add with password authentication only
./pi-shell add pi-hole --host 192.168.1.20 --user admin --password raspberry
# Set it as the default
./pi-shell set-default pi-hole
```
## ⚙️ Configuration
Device details are stored in `~/.config/pi-shell/config.yml` (per-user). While you can edit it manually, it's recommended to use the `add` and `remove` commands.
**Note:**
- Each user has their own config in their home directory (`~/.config/pi-shell/config.yml`)
- This works with system-wide installations - no conflicts between users!
- You can mix and match authentication methods - some Pis can use SSH keys while others use passwords
### Example:
```yaml
pi1:
host: 192.168.1.10
user: pi
key: ~/.ssh/pi-shell # SSH key authentication (recommended)
pi2:
host: 192.168.1.20
user: pi
password: raspberry # Password authentication
default: pi1
```
## 🔑 SSH Key Authentication
The tool can automatically set up SSH key-based authentication, which is more secure and convenient than passwords.
### How It Works:
1. When you use `--push-key` with the `add` command, the tool:
- Generates an ED25519 SSH key pair at `~/.ssh/pi-shell` (if it doesn't exist)
- Connects to the Pi using the provided password (one time only)
- Copies the public key to the Pi's `~/.ssh/authorized_keys`
- Saves the key path in `config.yml`
2. All future connections use the SSH key automatically - no password needed!
### Benefits:
- ✅ **More Secure:** No passwords stored in plain text
- ✅ **Convenient:** No password prompts during operations
- ✅ **One Key for All:** Same key can be used for all your Pis
- ✅ **LLM-Friendly:** No interactive password prompts when used by AI assistants
### Manual Key Setup:
If you prefer to use your own SSH key:
```bash
./pi-shell add pi1 --host 192.168.1.10 --user pi --key ~/.ssh/id_rsa
```
## 🎯 How It Works
The tool determines which Pi to connect to in the following order of priority:
1. The `--pi <name>` command-line argument.
2. The name of the symlink used to execute the script (e.g., `./pi1`).
3. The `default` entry in `config.yml`.
## 🆘 Troubleshooting
- **Connection Errors:** Use `./pi-shell status` to check connectivity. Ensure the host IP is correct and the device is on the network.
- **Host Key Errors:** If you see a "BadHostKeyException", it means the Pi's SSH key has changed (e.g., after an OS reinstall). The tool will provide you with the correct `ssh-keygen -R <host>` command to run to fix it.
- **Authentication Errors:** If you don't store a password in the config, the tool will prompt you for one. For non-interactive use, consider setting up SSH key-based authentication and providing the key path in `config.yml`.
## 📋 Requirements
- Python 3.6+
- paramiko (SSH library)
- PyYAML
- SSH access to your Raspberry Pis
## ⚠️ Things to Consider
**Password Security:**
- Passwords stored in `config.yml` are **not encrypted**. They are saved in plain text.
- This tool is designed for development environments with Raspberry Pis, typically using default passwords like "raspberry".
- If you plan to use this tool with production Linux machines or systems with sensitive credentials, be aware that there is no encryption on the YAML configuration file.
- For better security in production environments, consider using SSH key-based authentication instead (use the `--key` parameter when adding a Pi).
## 🗑️ Uninstalling
To uninstall pi-shell:
```bash
pip uninstall pi-shell
```
**Note:** This removes the command but preserves your data:
- Config: `~/.config/pi-shell/config.yml`
- SSH keys: `~/.ssh/pi-shell`
- Symlinks: `/usr/local/bin/keybird`, etc.
For complete removal instructions, see [docs/UNINSTALL.md](docs/UNINSTALL.md)
## 🤖 AI Disclosure
AI was used to help write this code, specifically the tool [Cursor](https://cursor.com), which assisted with development, documentation, and code organization.
Raw data
{
"_id": null,
"home_page": null,
"name": "pi-shell",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": null,
"keywords": "raspberry-pi, ssh, remote, management, cli, iot",
"author": null,
"author_email": "Ian McCutcheon <your.email@example.com>",
"download_url": "https://files.pythonhosted.org/packages/c5/87/9705d98362a63b8febb3185878fafd34eccf8a89c78a71beead440bfbf88/pi_shell-1.0.7.tar.gz",
"platform": null,
"description": "# Pi Shell - Enhanced Raspberry Pi Management Tool\n\nA CLI tool for managing multiple Raspberry Pi devices over SSH with automatic Pi detection through symlinks. But why does this exist [BHB.bzz](https://bhb.buzz/pi-shell.html)?\n\n## \ud83d\udce6 Installation\n\n### Recommended: Install from PyPI\n\n```bash\npip install pi-shell\n```\n\n### Alternative: Install from Source\n\n```bash\n# Clone the repository\ngit clone https://github.com/mcyork/pi-shell.git\ncd pi-shell\n\n# Install using pip\npip install .\n\n# Or install in editable mode for development\npip install -e .\n```\n\nThis automatically installs all dependencies:\n- `paramiko` - SSH library for Python\n- `PyYAML` - YAML configuration file parser\n- `cryptography` - For SSH key generation\n\nAfter installation, the `pi-shell` command will be available globally.\n\n## \ud83d\ude80 Quick Start\n\n### Option 1: SSH Key Authentication (Recommended)\n\n1. **Configure a Pi with automatic key setup:**\n ```bash\n pi-shell add pi1 --host 192.168.1.10 --user pi --password raspberry --push-key\n ```\n This will:\n - Generate an SSH key pair at `~/.ssh/pi-shell` (if it doesn't exist)\n - Push the public key to the Pi for password-less authentication\n - Save the configuration to `~/.config/pi-shell/config.yml` with the key path\n \n **Benefits:** No passwords stored in config, more secure, no password prompts!\n\n### Option 2: Password Authentication\n\n1. **Configure a Pi with password:**\n ```bash\n pi-shell add pi1 --host 192.168.1.10 --user pi --password raspberry\n ```\n This saves the Pi configuration to `~/.config/pi-shell/config.yml`.\n \n **Note:** Password will be stored in plain text in the config file.\n\n2. **Check its status:**\n ```bash\n pi-shell status pi1\n ```\n\n3. **Run a command:**\n ```bash\n # Using the --pi flag\n pi-shell run \"uname -a\" --pi pi1\n \n # Or if pi1 is set as default\n pi-shell run \"uname -a\"\n ```\n\n## \ud83d\udd27 Available Commands\n\nThe tool is organized into sub-commands for different actions.\n\n### Core Actions (`run`, `read`, `write`)\n\nThese commands perform actions on a target Pi.\n\n- `run <command>`: Execute a shell command.\n- `run-stream <command>`: Stream output from a long-running command.\n- `read <remote_path>`: Read a file from the Pi.\n- `write <remote_path> <content>`: Write content to a file.\n\n**Example:**\n```bash\n# Reboot pi2\n./pi2 run \"sudo reboot\"\n\n# Read the hostname from the default pi\n./pi-shell read \"/etc/hostname\"\n```\n\n### Management Actions (`add`, `remove`, `list`, `status`, `set-default`)\n\nThese commands help you manage your list of Pis.\n\n- `add <name> --host <host> --user <user> --password <password> [--push-key]`: Add a new Pi. Creates a symlink.\n - Use `--push-key` to automatically set up SSH key authentication (recommended - password used once to push key, then not stored)\n - Without `--push-key`, password is stored in config for ongoing authentication (less secure)\n- `remove <name>`: Remove a Pi. Deletes the symlink.\n- `list`: Show all configured Pis in a table.\n- `set-default <name>`: Set the default Pi for commands.\n- `status [name]`: Check connectivity and get the hostname for one or all Pis.\n\n**Example:**\n```bash\n# See all configured Pis\n./pi-shell list\n\n# Check if all Pis are online\n./pi-shell status\n\n# Add a new Pi named 'pi-hole' with SSH key authentication (recommended)\n./pi-shell add pi-hole --host 192.168.1.20 --user admin --password raspberry --push-key\n\n# Or add with password authentication only\n./pi-shell add pi-hole --host 192.168.1.20 --user admin --password raspberry\n\n# Set it as the default\n./pi-shell set-default pi-hole\n```\n\n## \u2699\ufe0f Configuration\n\nDevice details are stored in `~/.config/pi-shell/config.yml` (per-user). While you can edit it manually, it's recommended to use the `add` and `remove` commands.\n\n**Note:** \n- Each user has their own config in their home directory (`~/.config/pi-shell/config.yml`)\n- This works with system-wide installations - no conflicts between users!\n- You can mix and match authentication methods - some Pis can use SSH keys while others use passwords\n\n### Example:\n```yaml\npi1:\n host: 192.168.1.10\n user: pi\n key: ~/.ssh/pi-shell # SSH key authentication (recommended)\npi2:\n host: 192.168.1.20\n user: pi\n password: raspberry # Password authentication\ndefault: pi1\n```\n\n## \ud83d\udd11 SSH Key Authentication\n\nThe tool can automatically set up SSH key-based authentication, which is more secure and convenient than passwords.\n\n### How It Works:\n1. When you use `--push-key` with the `add` command, the tool:\n - Generates an ED25519 SSH key pair at `~/.ssh/pi-shell` (if it doesn't exist)\n - Connects to the Pi using the provided password (one time only)\n - Copies the public key to the Pi's `~/.ssh/authorized_keys`\n - Saves the key path in `config.yml`\n\n2. All future connections use the SSH key automatically - no password needed!\n\n### Benefits:\n- \u2705 **More Secure:** No passwords stored in plain text\n- \u2705 **Convenient:** No password prompts during operations\n- \u2705 **One Key for All:** Same key can be used for all your Pis\n- \u2705 **LLM-Friendly:** No interactive password prompts when used by AI assistants\n\n### Manual Key Setup:\nIf you prefer to use your own SSH key:\n```bash\n./pi-shell add pi1 --host 192.168.1.10 --user pi --key ~/.ssh/id_rsa\n```\n\n## \ud83c\udfaf How It Works\n\nThe tool determines which Pi to connect to in the following order of priority:\n1. The `--pi <name>` command-line argument.\n2. The name of the symlink used to execute the script (e.g., `./pi1`).\n3. The `default` entry in `config.yml`.\n\n## \ud83c\udd98 Troubleshooting\n\n- **Connection Errors:** Use `./pi-shell status` to check connectivity. Ensure the host IP is correct and the device is on the network.\n- **Host Key Errors:** If you see a \"BadHostKeyException\", it means the Pi's SSH key has changed (e.g., after an OS reinstall). The tool will provide you with the correct `ssh-keygen -R <host>` command to run to fix it.\n- **Authentication Errors:** If you don't store a password in the config, the tool will prompt you for one. For non-interactive use, consider setting up SSH key-based authentication and providing the key path in `config.yml`.\n\n## \ud83d\udccb Requirements\n\n- Python 3.6+\n- paramiko (SSH library)\n- PyYAML\n- SSH access to your Raspberry Pis\n\n## \u26a0\ufe0f Things to Consider\n\n**Password Security:**\n- Passwords stored in `config.yml` are **not encrypted**. They are saved in plain text.\n- This tool is designed for development environments with Raspberry Pis, typically using default passwords like \"raspberry\".\n- If you plan to use this tool with production Linux machines or systems with sensitive credentials, be aware that there is no encryption on the YAML configuration file.\n- For better security in production environments, consider using SSH key-based authentication instead (use the `--key` parameter when adding a Pi).\n\n## \ud83d\uddd1\ufe0f Uninstalling\n\nTo uninstall pi-shell:\n\n```bash\npip uninstall pi-shell\n```\n\n**Note:** This removes the command but preserves your data:\n- Config: `~/.config/pi-shell/config.yml`\n- SSH keys: `~/.ssh/pi-shell`\n- Symlinks: `/usr/local/bin/keybird`, etc.\n\nFor complete removal instructions, see [docs/UNINSTALL.md](docs/UNINSTALL.md)\n\n## \ud83e\udd16 AI Disclosure\n\nAI was used to help write this code, specifically the tool [Cursor](https://cursor.com), which assisted with development, documentation, and code organization.\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A CLI tool for managing multiple Raspberry Pi devices over SSH",
"version": "1.0.7",
"project_urls": {
"Homepage": "https://github.com/mcyork/pi-shell",
"Issues": "https://github.com/mcyork/pi-shell/issues",
"Repository": "https://github.com/mcyork/pi-shell"
},
"split_keywords": [
"raspberry-pi",
" ssh",
" remote",
" management",
" cli",
" iot"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "a1053fac734a1491e87ac1c5d5a98f3685275ce602a7a4cc112f8fae72b3db9e",
"md5": "42e5b4e8a9a0be8586204fc3754a21af",
"sha256": "3286a85b1b9aa912a7cb5dd4e1e3c05537f38bf46c32ca0b08c46c81dc076302"
},
"downloads": -1,
"filename": "pi_shell-1.0.7-py3-none-any.whl",
"has_sig": false,
"md5_digest": "42e5b4e8a9a0be8586204fc3754a21af",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 12820,
"upload_time": "2025-10-26T08:42:26",
"upload_time_iso_8601": "2025-10-26T08:42:26.428700Z",
"url": "https://files.pythonhosted.org/packages/a1/05/3fac734a1491e87ac1c5d5a98f3685275ce602a7a4cc112f8fae72b3db9e/pi_shell-1.0.7-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "c5879705d98362a63b8febb3185878fafd34eccf8a89c78a71beead440bfbf88",
"md5": "217fef1dbb90d1b2853bc9b9cc99cf17",
"sha256": "2767e287f1f17d8fbf73246bc8bccb941f8bf75380da5f7d41a3639ce9846666"
},
"downloads": -1,
"filename": "pi_shell-1.0.7.tar.gz",
"has_sig": false,
"md5_digest": "217fef1dbb90d1b2853bc9b9cc99cf17",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 22751,
"upload_time": "2025-10-26T08:42:27",
"upload_time_iso_8601": "2025-10-26T08:42:27.309223Z",
"url": "https://files.pythonhosted.org/packages/c5/87/9705d98362a63b8febb3185878fafd34eccf8a89c78a71beead440bfbf88/pi_shell-1.0.7.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-26 08:42:27",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "mcyork",
"github_project": "pi-shell",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "paramiko",
"specs": []
},
{
"name": "PyYAML",
"specs": []
},
{
"name": "cryptography",
"specs": []
}
],
"lcname": "pi-shell"
}