kache-ssh 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/PKG-INFO +63 -7
  2. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/README.md +205 -150
  3. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/pyproject.toml +43 -42
  4. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/AGENTS.md +63 -13
  5. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/__init__.py +17 -17
  6. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/agent.py +99 -15
  7. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/cli.py +389 -23
  8. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/client.py +118 -0
  9. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/evidence.py +118 -112
  10. kache_ssh-0.2.0/src/kache/files.py +63 -0
  11. kache_ssh-0.2.0/src/kache/jobs.py +274 -0
  12. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/mcp.py +388 -277
  13. kache_ssh-0.2.0/src/kache/notify.py +173 -0
  14. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/service.py +104 -3
  15. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/tui.py +196 -14
  16. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/tests/test_service.py +12 -0
  17. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/tests/test_tui.py +26 -0
  18. kache_ssh-0.2.0/tests/test_v02.py +292 -0
  19. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/.gitignore +0 -0
  20. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/AGENTS.md +0 -0
  21. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/LICENSE +0 -0
  22. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/__main__.py +0 -0
  23. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/config.py +0 -0
  24. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/keys.py +0 -0
  25. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/network.py +0 -0
  26. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/probe.py +0 -0
  27. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/src/kache/telemetry.py +0 -0
  28. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/tests/test_agent_api.py +0 -0
  29. {kache_ssh-0.1.2 → kache_ssh-0.2.0}/tests/test_e2e.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: kache-ssh
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Kache: one terminal to command all your devices over SSH, with a gatekeeper agent on every device.
5
5
  Author: Simon Malm
6
6
  License-Expression: MIT
@@ -16,6 +16,7 @@ Requires-Python: >=3.10
16
16
  Requires-Dist: asyncssh>=2.14
17
17
  Requires-Dist: platformdirs>=4.0
18
18
  Requires-Dist: psutil>=5.9
19
+ Requires-Dist: segno>=1.5
19
20
  Requires-Dist: textual>=8.0
20
21
  Provides-Extra: dev
21
22
  Requires-Dist: build>=1.0; extra == 'dev'
@@ -49,6 +50,14 @@ kache
49
50
  `cd` sticks between commands, output streams live, Ctrl+C stops an order.
50
51
  - **One device or all of them.** Pick a device, or press F6 and send the same
51
52
  order to every device in parallel; output is labelled per device.
53
+ - **Jobs that keep running.** Press F7 instead of Enter (or `kache run
54
+ --detach`) and the order keeps going after you close Kache or lose the
55
+ connection: training runs, builds, downloads. F8 shows every job, its
56
+ live output, and stops it.
57
+ - **Files both ways.** `kache push` and `kache pull` copy files and whole
58
+ folders over the same paired connection.
59
+ - **Phone notifications.** Get a push message when a job finishes, an
60
+ agent's order fails, a device goes offline or someone asks to pair.
52
61
  - **Device health at a glance.** Online/offline, CPU and RAM use, GPU load,
53
62
  temperature and memory (NVIDIA), and CPU temperature where the OS exposes it.
54
63
  - **Pairing with a yes/no question.** Ask another device to pair; its Kache
@@ -64,7 +73,8 @@ kache
64
73
  - **Evidence when things break.** A failing order comes back with a report:
65
74
  exit code, last lines of output, labelled hints (command not found,
66
75
  permission, disk full, missing Python module, network, out of memory...)
67
- and the machine's state at that moment.
76
+ and the machine's state at that moment. An order that "succeeded" while
77
+ PowerShell printed errors says so: *ok, but 3 errors were reported*.
68
78
  - **A live feed of every order.** Who sent what to which device, when, and
69
79
  how it ended, including orders from scripts and AI agents, which are
70
80
  labelled with the agent's name.
@@ -101,6 +111,8 @@ Python may accept connections. Allow it, or other devices cannot reach this one.
101
111
  | ↑ / ↓ | previous / next command |
102
112
  | Ctrl+↑ / ↓ | select the previous / next device |
103
113
  | F6 | switch between one device and all devices |
114
+ | F7 | send what you typed as a background job |
115
+ | F8 | jobs: watch their output live, stop them |
104
116
  | Ctrl+C | stop the running order(s) |
105
117
  | F2 | pair a new device |
106
118
  | F3 | rename the selected device |
@@ -108,6 +120,48 @@ Python may accept connections. Allow it, or other devices cannot reach this one.
108
120
  | F5 | show the last failure's evidence |
109
121
  | Ctrl+Q | quit |
110
122
 
123
+ ### Start at boot
124
+
125
+ By default the gatekeeper starts when you log in. For a computer that must
126
+ stay reachable after a restart even when nobody logs in (a Windows Update
127
+ reboot while you are away), run once in an administrator terminal:
128
+
129
+ ```
130
+ kache service install --at-boot
131
+ ```
132
+
133
+ When the computer shuts down, Kache simply stops; nothing needs saving.
134
+ Background jobs that were running are reported as *lost* afterwards, so
135
+ you know to start them again.
136
+
137
+ ## Jobs and files
138
+
139
+ ```
140
+ kache run desktop --detach -- python train.py # starts a job, prints its id
141
+ kache jobs # every job on every device
142
+ kache logs J-3f2a9c -f # follow its output live
143
+ kache cancel J-3f2a9c # stop it
144
+ kache push model.pt data/ desktop:C:/proj # copy to a device
145
+ kache pull desktop:C:/proj/results . # copy back
146
+ kache run desktop -f setup.ps1 # send a whole script
147
+ ```
148
+
149
+ ## Phone notifications
150
+
151
+ Kache uses [ntfy](https://ntfy.sh), a free open-source push service:
152
+
153
+ 1. Install the **ntfy** app on your phone (App Store or Google Play).
154
+ 2. On one of your devices run `kache notify setup`. It shows a QR code;
155
+ scan it (or subscribe in the app to the topic it prints). All your paired
156
+ devices get the same setting.
157
+ 3. Run `kache notify test`.
158
+
159
+ You get a message when a background job ends, an order from a script or AI
160
+ agent fails, a device goes offline or comes back, or a device asks to pair.
161
+ Messages contain a short summary, never command output. The topic name is
162
+ a long random secret; anyone who knows it can read the messages, so keep it
163
+ private, or use your own ntfy server with `--server`.
164
+
111
165
  ## Away from home: Tailscale
112
166
 
113
167
  Kache connects devices directly, so a device must be reachable from the one
@@ -142,9 +196,10 @@ For MCP clients (Claude Code, Claude Desktop, Cursor and others):
142
196
  claude mcp add kache -- kache mcp
143
197
  ```
144
198
 
145
- Agents get the tools `kache_devices`, `kache_run`, `kache_feed`,
146
- `kache_evidence`, `kache_doctor`, `kache_discover`, `kache_pending` and
147
- `kache_pair`. Accepting pair requests and revoking devices stays with
199
+ Agents get the tools `kache_devices`, `kache_run` (optionally as a job),
200
+ `kache_jobs`, `kache_job_log`, `kache_cancel_job`, `kache_push`,
201
+ `kache_pull`, `kache_feed`, `kache_evidence`, `kache_doctor`,
202
+ `kache_discover`, `kache_pending` and `kache_pair`. Accepting pair requests and revoking devices stays with
148
203
  people. `kache guide` prints the full guide: JSON shapes, feed event kinds,
149
204
  exit codes and rules for agents.
150
205
 
@@ -165,12 +220,13 @@ Tailscale, each address, the device's key, the pairing) and says what to fix.
165
220
 
166
221
  ## Status
167
222
 
168
- Version 0.1.2: pairing, orders, sessions, evidence, live feed, health,
223
+ Version 0.2: pairing, orders, sessions, evidence, live feed, health,
224
+ background jobs, file transfer, phone notifications, start at boot,
169
225
  Tailscale, JSON output and MCP work on Windows, Linux and macOS.
170
226
 
171
227
  Planned:
172
228
  - full interactive sessions (`kache attach` for programs like vim or htop);
173
- - confirmation popups for dangerous orders;
229
+ - permissions per sender: read-only scripts and agents, your approval for dangerous orders;
174
230
  - pairing both directions in one step;
175
231
  - a relay for devices that cannot reach each other directly.
176
232
 
@@ -1,150 +1,205 @@
1
- # Kache
2
-
3
- One terminal to command all your devices.
4
-
5
- Kache is a hub that runs in your terminal. Pair your computers once, then
6
- type a command and it runs on the device you picked, or on all of them at
7
- once, exactly as if you were sitting at that machine. Every device runs a
8
- small **gatekeeper** that only obeys devices you paired, refuses orders that
9
- cannot work there, and sends back an evidence report when something fails.
10
- Every order anyone sends (you, a script, or an AI agent working for you)
11
- shows up in the live feed with the exact command.
12
-
13
- ```
14
- pip install kache-ssh
15
- kache
16
- ```
17
-
18
- ## What you get
19
-
20
- - **A real remote terminal.** What you type is what runs on the other device,
21
- in its own shell (PowerShell on Windows, your shell on Linux and macOS).
22
- `cd` sticks between commands, output streams live, Ctrl+C stops an order.
23
- - **One device or all of them.** Pick a device, or press F6 and send the same
24
- order to every device in parallel; output is labelled per device.
25
- - **Device health at a glance.** Online/offline, CPU and RAM use, GPU load,
26
- temperature and memory (NVIDIA), and CPU temperature where the OS exposes it.
27
- - **Pairing with a yes/no question.** Ask another device to pair; its Kache
28
- terminal asks *"laptop wants to send orders to this device. Code 482 913.
29
- Accept?"* Both screens show the same code, so nobody can sit in between.
30
- - **Works at home and away.** Kache remembers every address of a device (LAN,
31
- Tailscale IP, Tailscale name) and uses whichever answers. Pair once at
32
- home; it keeps working over [Tailscale](https://tailscale.com) anywhere.
33
- - **A gatekeeper on every device.** Unknown devices can only say hello or ask
34
- to pair. Paired devices are pinned by key. Orders for commands that do not
35
- exist on that device are refused up front (Linux/macOS) or explained
36
- afterwards (Windows).
37
- - **Evidence when things break.** A failing order comes back with a report:
38
- exit code, last lines of output, labelled hints (command not found,
39
- permission, disk full, missing Python module, network, out of memory...)
40
- and the machine's state at that moment.
41
- - **A live feed of every order.** Who sent what to which device, when, and
42
- how it ended, including orders from scripts and AI agents, which are
43
- labelled with the agent's name.
44
- - **Built for AI agents too.** Every command has `--json`, there is an MCP
45
- server (`kache mcp`), and `kache guide` explains everything an agent needs.
46
-
47
- ## Quick start
48
-
49
- On every device, one command:
50
-
51
- ```
52
- pip install kache-ssh
53
- ```
54
-
55
- Then open Kache by typing `kache`. The first time, it also starts its
56
- gatekeeper in the background and from then on at every login, so the device
57
- stays reachable when the window is closed (`kache service uninstall` turns
58
- that off, `kache service status` shows it). No administrator rights needed.
59
-
60
- In the Kache terminal on the device you want to command *from*, press **F2**
61
- and enter the other device's address: its LAN IP, Tailscale IP or Tailscale
62
- machine name (devices on your tailnet are listed for you). Accept on the
63
- other device when the codes match. It appears in your device list, and
64
- anything you type now runs there.
65
-
66
- On Windows, the first time the gatekeeper starts, Windows may ask whether
67
- Python may accept connections. Allow it, or other devices cannot reach this one.
68
-
69
- ### Keys
70
-
71
- | Key | Action |
72
- |------------|-----------------------------------------------|
73
- | Enter | send what you typed to the selected device(s) |
74
- | ↑ / ↓ | previous / next command |
75
- | Ctrl+↑ / ↓ | select the previous / next device |
76
- | F6 | switch between one device and all devices |
77
- | Ctrl+C | stop the running order(s) |
78
- | F2 | pair a new device |
79
- | F3 | rename the selected device |
80
- | F4 | remove the selected device |
81
- | F5 | show the last failure's evidence |
82
- | Ctrl+Q | quit |
83
-
84
- ## Away from home: Tailscale
85
-
86
- Kache connects devices directly, so a device must be reachable from the one
87
- commanding it. At home that is your LAN. Away from home, install
88
- [Tailscale](https://tailscale.com) (free for personal use) on both devices
89
- and sign in with the same account. Then:
90
-
91
- - `kache discover` lists the devices on your tailnet and which run Kache;
92
- - pairing by Tailscale name works: `kache pair my-desktop`;
93
- - devices paired over LAN switch to Tailscale automatically when the LAN
94
- address stops answering;
95
- - `kache listen tailscale` makes a gatekeeper answer on your tailnet only,
96
- ignoring the local network.
97
-
98
- ## For scripts and AI agents
99
-
100
- Everything the terminal does is also a command with `--json` output, and
101
- every order still appears in the feed:
102
-
103
- ```
104
- kache devices --json # status and health of every device
105
- kache run desktop --json --timeout 60 -- nvidia-smi
106
- kache run all --as nightly-job -- git pull # labelled in every feed
107
- kache feed -d all -f --json # live JSON-lines feed from all devices
108
- kache evidence E-3f2a9c -d desktop # a failure report
109
- kache doctor desktop --json # why a device cannot be reached
110
- ```
111
-
112
- For MCP clients (Claude Code, Claude Desktop, Cursor and others):
113
-
114
- ```
115
- claude mcp add kache -- kache mcp
116
- ```
117
-
118
- Agents get the tools `kache_devices`, `kache_run`, `kache_feed`,
119
- `kache_evidence`, `kache_doctor`, `kache_discover`, `kache_pending` and
120
- `kache_pair`. Accepting pair requests and revoking devices stays with
121
- people. `kache guide` prints the full guide: JSON shapes, feed event kinds,
122
- exit codes and rules for agents.
123
-
124
- ## How it works
125
-
126
- Each device has one ed25519 key, created on first run. The gatekeeper is an
127
- SSH server (built on asyncssh, port 7722) that accepts any key but only lets
128
- unknown keys say hello or ask to pair; paired keys may send orders. The
129
- Kache terminal is an SSH client that pins each paired device's key. Nothing
130
- goes through a server in between.
131
-
132
- State lives in one folder per device (`kache whoami` shows where; override
133
- with `KACHE_HOME`): the device key, its name, the devices it commands, the
134
- devices trusted to command it, the feed and the evidence reports.
135
-
136
- If something does not connect, `kache doctor` checks every step (gatekeeper,
137
- Tailscale, each address, the device's key, the pairing) and says what to fix.
138
-
139
- ## Status
140
-
141
- Version 0.1.2: pairing, orders, sessions, evidence, live feed, health,
142
- Tailscale, JSON output and MCP work on Windows, Linux and macOS.
143
-
144
- Planned:
145
- - full interactive sessions (`kache attach` for programs like vim or htop);
146
- - confirmation popups for dangerous orders;
147
- - pairing both directions in one step;
148
- - a relay for devices that cannot reach each other directly.
149
-
150
- MIT licensed.
1
+ # Kache
2
+
3
+ One terminal to command all your devices.
4
+
5
+ Kache is a hub that runs in your terminal. Pair your computers once, then
6
+ type a command and it runs on the device you picked, or on all of them at
7
+ once, exactly as if you were sitting at that machine. Every device runs a
8
+ small **gatekeeper** that only obeys devices you paired, refuses orders that
9
+ cannot work there, and sends back an evidence report when something fails.
10
+ Every order anyone sends (you, a script, or an AI agent working for you)
11
+ shows up in the live feed with the exact command.
12
+
13
+ ```
14
+ pip install kache-ssh
15
+ kache
16
+ ```
17
+
18
+ ## What you get
19
+
20
+ - **A real remote terminal.** What you type is what runs on the other device,
21
+ in its own shell (PowerShell on Windows, your shell on Linux and macOS).
22
+ `cd` sticks between commands, output streams live, Ctrl+C stops an order.
23
+ - **One device or all of them.** Pick a device, or press F6 and send the same
24
+ order to every device in parallel; output is labelled per device.
25
+ - **Jobs that keep running.** Press F7 instead of Enter (or `kache run
26
+ --detach`) and the order keeps going after you close Kache or lose the
27
+ connection: training runs, builds, downloads. F8 shows every job, its
28
+ live output, and stops it.
29
+ - **Files both ways.** `kache push` and `kache pull` copy files and whole
30
+ folders over the same paired connection.
31
+ - **Phone notifications.** Get a push message when a job finishes, an
32
+ agent's order fails, a device goes offline or someone asks to pair.
33
+ - **Device health at a glance.** Online/offline, CPU and RAM use, GPU load,
34
+ temperature and memory (NVIDIA), and CPU temperature where the OS exposes it.
35
+ - **Pairing with a yes/no question.** Ask another device to pair; its Kache
36
+ terminal asks *"laptop wants to send orders to this device. Code 482 913.
37
+ Accept?"* Both screens show the same code, so nobody can sit in between.
38
+ - **Works at home and away.** Kache remembers every address of a device (LAN,
39
+ Tailscale IP, Tailscale name) and uses whichever answers. Pair once at
40
+ home; it keeps working over [Tailscale](https://tailscale.com) anywhere.
41
+ - **A gatekeeper on every device.** Unknown devices can only say hello or ask
42
+ to pair. Paired devices are pinned by key. Orders for commands that do not
43
+ exist on that device are refused up front (Linux/macOS) or explained
44
+ afterwards (Windows).
45
+ - **Evidence when things break.** A failing order comes back with a report:
46
+ exit code, last lines of output, labelled hints (command not found,
47
+ permission, disk full, missing Python module, network, out of memory...)
48
+ and the machine's state at that moment. An order that "succeeded" while
49
+ PowerShell printed errors says so: *ok, but 3 errors were reported*.
50
+ - **A live feed of every order.** Who sent what to which device, when, and
51
+ how it ended, including orders from scripts and AI agents, which are
52
+ labelled with the agent's name.
53
+ - **Built for AI agents too.** Every command has `--json`, there is an MCP
54
+ server (`kache mcp`), and `kache guide` explains everything an agent needs.
55
+
56
+ ## Quick start
57
+
58
+ On every device, one command:
59
+
60
+ ```
61
+ pip install kache-ssh
62
+ ```
63
+
64
+ Then open Kache by typing `kache`. The first time, it also starts its
65
+ gatekeeper in the background and from then on at every login, so the device
66
+ stays reachable when the window is closed (`kache service uninstall` turns
67
+ that off, `kache service status` shows it). No administrator rights needed.
68
+
69
+ In the Kache terminal on the device you want to command *from*, press **F2**
70
+ and enter the other device's address: its LAN IP, Tailscale IP or Tailscale
71
+ machine name (devices on your tailnet are listed for you). Accept on the
72
+ other device when the codes match. It appears in your device list, and
73
+ anything you type now runs there.
74
+
75
+ On Windows, the first time the gatekeeper starts, Windows may ask whether
76
+ Python may accept connections. Allow it, or other devices cannot reach this one.
77
+
78
+ ### Keys
79
+
80
+ | Key | Action |
81
+ |------------|-----------------------------------------------|
82
+ | Enter | send what you typed to the selected device(s) |
83
+ | ↑ / ↓ | previous / next command |
84
+ | Ctrl+↑ / ↓ | select the previous / next device |
85
+ | F6 | switch between one device and all devices |
86
+ | F7 | send what you typed as a background job |
87
+ | F8 | jobs: watch their output live, stop them |
88
+ | Ctrl+C | stop the running order(s) |
89
+ | F2 | pair a new device |
90
+ | F3 | rename the selected device |
91
+ | F4 | remove the selected device |
92
+ | F5 | show the last failure's evidence |
93
+ | Ctrl+Q | quit |
94
+
95
+ ### Start at boot
96
+
97
+ By default the gatekeeper starts when you log in. For a computer that must
98
+ stay reachable after a restart even when nobody logs in (a Windows Update
99
+ reboot while you are away), run once in an administrator terminal:
100
+
101
+ ```
102
+ kache service install --at-boot
103
+ ```
104
+
105
+ When the computer shuts down, Kache simply stops; nothing needs saving.
106
+ Background jobs that were running are reported as *lost* afterwards, so
107
+ you know to start them again.
108
+
109
+ ## Jobs and files
110
+
111
+ ```
112
+ kache run desktop --detach -- python train.py # starts a job, prints its id
113
+ kache jobs # every job on every device
114
+ kache logs J-3f2a9c -f # follow its output live
115
+ kache cancel J-3f2a9c # stop it
116
+ kache push model.pt data/ desktop:C:/proj # copy to a device
117
+ kache pull desktop:C:/proj/results . # copy back
118
+ kache run desktop -f setup.ps1 # send a whole script
119
+ ```
120
+
121
+ ## Phone notifications
122
+
123
+ Kache uses [ntfy](https://ntfy.sh), a free open-source push service:
124
+
125
+ 1. Install the **ntfy** app on your phone (App Store or Google Play).
126
+ 2. On one of your devices run `kache notify setup`. It shows a QR code;
127
+ scan it (or subscribe in the app to the topic it prints). All your paired
128
+ devices get the same setting.
129
+ 3. Run `kache notify test`.
130
+
131
+ You get a message when a background job ends, an order from a script or AI
132
+ agent fails, a device goes offline or comes back, or a device asks to pair.
133
+ Messages contain a short summary, never command output. The topic name is
134
+ a long random secret; anyone who knows it can read the messages, so keep it
135
+ private, or use your own ntfy server with `--server`.
136
+
137
+ ## Away from home: Tailscale
138
+
139
+ Kache connects devices directly, so a device must be reachable from the one
140
+ commanding it. At home that is your LAN. Away from home, install
141
+ [Tailscale](https://tailscale.com) (free for personal use) on both devices
142
+ and sign in with the same account. Then:
143
+
144
+ - `kache discover` lists the devices on your tailnet and which run Kache;
145
+ - pairing by Tailscale name works: `kache pair my-desktop`;
146
+ - devices paired over LAN switch to Tailscale automatically when the LAN
147
+ address stops answering;
148
+ - `kache listen tailscale` makes a gatekeeper answer on your tailnet only,
149
+ ignoring the local network.
150
+
151
+ ## For scripts and AI agents
152
+
153
+ Everything the terminal does is also a command with `--json` output, and
154
+ every order still appears in the feed:
155
+
156
+ ```
157
+ kache devices --json # status and health of every device
158
+ kache run desktop --json --timeout 60 -- nvidia-smi
159
+ kache run all --as nightly-job -- git pull # labelled in every feed
160
+ kache feed -d all -f --json # live JSON-lines feed from all devices
161
+ kache evidence E-3f2a9c -d desktop # a failure report
162
+ kache doctor desktop --json # why a device cannot be reached
163
+ ```
164
+
165
+ For MCP clients (Claude Code, Claude Desktop, Cursor and others):
166
+
167
+ ```
168
+ claude mcp add kache -- kache mcp
169
+ ```
170
+
171
+ Agents get the tools `kache_devices`, `kache_run` (optionally as a job),
172
+ `kache_jobs`, `kache_job_log`, `kache_cancel_job`, `kache_push`,
173
+ `kache_pull`, `kache_feed`, `kache_evidence`, `kache_doctor`,
174
+ `kache_discover`, `kache_pending` and `kache_pair`. Accepting pair requests and revoking devices stays with
175
+ people. `kache guide` prints the full guide: JSON shapes, feed event kinds,
176
+ exit codes and rules for agents.
177
+
178
+ ## How it works
179
+
180
+ Each device has one ed25519 key, created on first run. The gatekeeper is an
181
+ SSH server (built on asyncssh, port 7722) that accepts any key but only lets
182
+ unknown keys say hello or ask to pair; paired keys may send orders. The
183
+ Kache terminal is an SSH client that pins each paired device's key. Nothing
184
+ goes through a server in between.
185
+
186
+ State lives in one folder per device (`kache whoami` shows where; override
187
+ with `KACHE_HOME`): the device key, its name, the devices it commands, the
188
+ devices trusted to command it, the feed and the evidence reports.
189
+
190
+ If something does not connect, `kache doctor` checks every step (gatekeeper,
191
+ Tailscale, each address, the device's key, the pairing) and says what to fix.
192
+
193
+ ## Status
194
+
195
+ Version 0.2: pairing, orders, sessions, evidence, live feed, health,
196
+ background jobs, file transfer, phone notifications, start at boot,
197
+ Tailscale, JSON output and MCP work on Windows, Linux and macOS.
198
+
199
+ Planned:
200
+ - full interactive sessions (`kache attach` for programs like vim or htop);
201
+ - permissions per sender: read-only scripts and agents, your approval for dangerous orders;
202
+ - pairing both directions in one step;
203
+ - a relay for devices that cannot reach each other directly.
204
+
205
+ MIT licensed.
@@ -1,42 +1,43 @@
1
- [build-system]
2
- requires = ["hatchling>=1.24"]
3
- build-backend = "hatchling.build"
4
-
5
- [project]
6
- name = "kache-ssh"
7
- version = "0.1.2"
8
- description = "Kache: one terminal to command all your devices over SSH, with a gatekeeper agent on every device."
9
- readme = "README.md"
10
- requires-python = ">=3.10"
11
- license = "MIT"
12
- license-files = ["LICENSE"]
13
- authors = [{ name = "Simon Malm" }]
14
- keywords = ["ssh", "remote", "orchestration", "terminal", "tui", "fleet", "tailscale", "mcp", "ai-agents"]
15
- classifiers = [
16
- "Environment :: Console",
17
- "Operating System :: Microsoft :: Windows",
18
- "Operating System :: POSIX :: Linux",
19
- "Operating System :: MacOS",
20
- "Programming Language :: Python :: 3",
21
- "Topic :: System :: Systems Administration",
22
- ]
23
- dependencies = [
24
- "asyncssh>=2.14",
25
- "textual>=8.0",
26
- "psutil>=5.9",
27
- "platformdirs>=4.0",
28
- ]
29
-
30
- [project.optional-dependencies]
31
- gpu = ["nvidia-ml-py>=12"]
32
- dev = ["pytest>=8", "pytest-asyncio>=0.23", "build>=1.0"]
33
-
34
- [project.scripts]
35
- kache = "kache.cli:main"
36
-
37
- [tool.hatch.build.targets.wheel]
38
- packages = ["src/kache"]
39
-
40
- [tool.pytest.ini_options]
41
- asyncio_mode = "auto"
42
- testpaths = ["tests"]
1
+ [build-system]
2
+ requires = ["hatchling>=1.24"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "kache-ssh"
7
+ version = "0.2.0"
8
+ description = "Kache: one terminal to command all your devices over SSH, with a gatekeeper agent on every device."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Simon Malm" }]
14
+ keywords = ["ssh", "remote", "orchestration", "terminal", "tui", "fleet", "tailscale", "mcp", "ai-agents"]
15
+ classifiers = [
16
+ "Environment :: Console",
17
+ "Operating System :: Microsoft :: Windows",
18
+ "Operating System :: POSIX :: Linux",
19
+ "Operating System :: MacOS",
20
+ "Programming Language :: Python :: 3",
21
+ "Topic :: System :: Systems Administration",
22
+ ]
23
+ dependencies = [
24
+ "asyncssh>=2.14",
25
+ "textual>=8.0",
26
+ "psutil>=5.9",
27
+ "platformdirs>=4.0",
28
+ "segno>=1.5",
29
+ ]
30
+
31
+ [project.optional-dependencies]
32
+ gpu = ["nvidia-ml-py>=12"]
33
+ dev = ["pytest>=8", "pytest-asyncio>=0.23", "build>=1.0"]
34
+
35
+ [project.scripts]
36
+ kache = "kache.cli:main"
37
+
38
+ [tool.hatch.build.targets.wheel]
39
+ packages = ["src/kache"]
40
+
41
+ [tool.pytest.ini_options]
42
+ asyncio_mode = "auto"
43
+ testpaths = ["tests"]