@geohar/un-bien 0.8.0 → 0.14.0
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.
- package/README.md +258 -320
- package/dist/actions/handlers.js.map +1 -1
- package/dist/actions/registry.js.map +1 -1
- package/dist/bin/launcher.js +38 -0
- package/dist/bin/launcher.js.map +1 -0
- package/dist/commands/deps.d.ts +156 -0
- package/dist/commands/deps.js +2 -0
- package/dist/commands/deps.js.map +1 -0
- package/dist/commands/fork_link.d.ts +4 -0
- package/dist/commands/fork_link.js +45 -0
- package/dist/commands/fork_link.js.map +1 -0
- package/dist/commands/housekeeping.d.ts +34 -0
- package/dist/commands/housekeeping.js +275 -0
- package/dist/commands/housekeeping.js.map +1 -0
- package/dist/commands/info.d.ts +43 -0
- package/dist/commands/info.js +127 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/lifecycle.d.ts +45 -0
- package/dist/commands/lifecycle.js +708 -0
- package/dist/commands/lifecycle.js.map +1 -0
- package/dist/commands/pairing.d.ts +26 -0
- package/dist/commands/pairing.js +167 -0
- package/dist/commands/pairing.js.map +1 -0
- package/dist/commands/register.d.ts +12 -0
- package/dist/commands/register.js +255 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/relay.d.ts +28 -0
- package/dist/commands/relay.js +81 -0
- package/dist/commands/relay.js.map +1 -0
- package/dist/commands/session_ops.d.ts +52 -0
- package/dist/commands/session_ops.js +75 -0
- package/dist/commands/session_ops.js.map +1 -0
- package/dist/config.d.ts +30 -2
- package/dist/config.js.map +1 -1
- package/dist/daemon/install.d.ts +36 -37
- package/dist/daemon/install.js +49 -73
- package/dist/daemon/install.js.map +1 -1
- package/dist/enrich_tool_args.d.ts +9 -0
- package/dist/enrich_tool_args.js +171 -0
- package/dist/enrich_tool_args.js.map +1 -0
- package/dist/extension_ui_bridge.js.map +1 -1
- package/dist/image_codec.d.ts +22 -0
- package/dist/image_codec.js +149 -0
- package/dist/image_codec.js.map +1 -0
- package/dist/index.d.ts +32 -127
- package/dist/index.js +957 -4042
- package/dist/index.js.map +1 -1
- package/dist/launch.d.ts +42 -0
- package/dist/launch.js +206 -0
- package/dist/launch.js.map +1 -0
- package/dist/launcher/launcher.d.ts +6 -0
- package/dist/launcher/launcher.js +207 -0
- package/dist/launcher/launcher.js.map +1 -0
- package/dist/mcp/mesh_result.js.map +1 -1
- package/dist/mcp/mesh_server.js.map +1 -1
- package/dist/mesh/canonical.js +1 -1
- package/dist/mesh/canonical.js.map +1 -1
- package/dist/mesh/client.js.map +1 -1
- package/dist/mesh/encoding.js.map +1 -1
- package/dist/mesh/self_revoke.js.map +1 -1
- package/dist/mesh/siblings.js.map +1 -1
- package/dist/mesh/verify.js +1 -1
- package/dist/mesh/verify.js.map +1 -1
- package/dist/pairing/crypto.js +0 -1
- package/dist/pairing/crypto.js.map +1 -1
- package/dist/pairing/peer_trust.d.ts +20 -0
- package/dist/pairing/peer_trust.js +82 -0
- package/dist/pairing/peer_trust.js.map +1 -0
- package/dist/pairing/qr.js.map +1 -1
- package/dist/pairing/storage.js +4 -3
- package/dist/pairing/storage.js.map +1 -1
- package/dist/panel_bridge.d.ts +3 -1
- package/dist/panel_bridge.js +11 -10
- package/dist/panel_bridge.js.map +1 -1
- package/dist/paths.d.ts +22 -8
- package/dist/paths.js +37 -10
- package/dist/paths.js.map +1 -1
- package/dist/protocol/codec.js.map +1 -1
- package/dist/rooms.d.ts +16 -0
- package/dist/rooms.js +23 -4
- package/dist/rooms.js.map +1 -1
- package/dist/session/bridge.js.map +1 -1
- package/dist/session/broker.js.map +1 -1
- package/dist/session/broker_remote.js.map +1 -1
- package/dist/session/capabilities.d.ts +11 -0
- package/dist/session/capabilities.js +35 -0
- package/dist/session/capabilities.js.map +1 -0
- package/dist/session/cwd_lock.js +3 -3
- package/dist/session/cwd_lock.js.map +1 -1
- package/dist/session/debug_log.js +15 -5
- package/dist/session/debug_log.js.map +1 -1
- package/dist/session/envelope.js.map +1 -1
- package/dist/session/global_config.d.ts +1 -1
- package/dist/session/global_config.js +1 -1
- package/dist/session/global_config.js.map +1 -1
- package/dist/session/ipc.d.ts +2 -2
- package/dist/session/ipc.js.map +1 -1
- package/dist/session/leader_election.js.map +1 -1
- package/dist/session/local_config.d.ts +37 -0
- package/dist/session/local_config.js +47 -1
- package/dist/session/local_config.js.map +1 -1
- package/dist/session/mesh_node.d.ts +1 -1
- package/dist/session/mesh_node.js +1 -1
- package/dist/session/mesh_node.js.map +1 -1
- package/dist/session/peer.js.map +1 -1
- package/dist/session/peer_inventory.js.map +1 -1
- package/dist/session/peer_limits.js.map +1 -1
- package/dist/session/received_images.d.ts +63 -0
- package/dist/session/received_images.js +273 -0
- package/dist/session/received_images.js.map +1 -0
- package/dist/session/relay_lifecycle.d.ts +219 -0
- package/dist/session/relay_lifecycle.js +764 -0
- package/dist/session/relay_lifecycle.js.map +1 -0
- package/dist/session/rpc_envelope.d.ts +28 -0
- package/dist/session/rpc_envelope.js +10 -1
- package/dist/session/rpc_envelope.js.map +1 -1
- package/dist/session/rpc_handlers.d.ts +53 -0
- package/dist/session/rpc_handlers.js +268 -0
- package/dist/session/rpc_handlers.js.map +1 -0
- package/dist/session/rpc_inbound.d.ts +42 -7
- package/dist/session/rpc_inbound.js +56 -1
- package/dist/session/rpc_inbound.js.map +1 -1
- package/dist/session/setup_wizard.js.map +1 -1
- package/dist/session/tools.js.map +1 -1
- package/dist/session/wizard.js.map +1 -1
- package/dist/state_migration.d.ts +45 -0
- package/dist/state_migration.js +104 -0
- package/dist/state_migration.js.map +1 -0
- package/dist/subagent_rooms.d.ts +68 -0
- package/dist/subagent_rooms.js +919 -0
- package/dist/subagent_rooms.js.map +1 -0
- package/dist/test_hooks.d.ts +180 -0
- package/dist/test_hooks.js +98 -0
- package/dist/test_hooks.js.map +1 -0
- package/dist/transport/peer_channel.d.ts +18 -1
- package/dist/transport/peer_channel.js +42 -12
- package/dist/transport/peer_channel.js.map +1 -1
- package/dist/transport/pi_forward_client.js.map +1 -1
- package/dist/transport/relay_client.d.ts +24 -2
- package/dist/transport/relay_client.js +6 -3
- package/dist/transport/relay_client.js.map +1 -1
- package/dist/ui/footer.js.map +1 -1
- package/docs/daemon.md +170 -179
- package/package.json +13 -11
- package/service-templates/launchd.plist.template +8 -7
- package/service-templates/systemd.service.template +5 -4
- package/service-templates/task-launcher.vbs.template +5 -5
- package/service-templates/task-scheduler.xml.template +1 -1
- package/dist/bin/supervisord.js +0 -86
- package/dist/bin/supervisord.js.map +0 -1
- package/dist/daemon/client.d.ts +0 -20
- package/dist/daemon/client.js +0 -131
- package/dist/daemon/client.js.map +0 -1
- package/dist/daemon/control_protocol.d.ts +0 -176
- package/dist/daemon/control_protocol.js +0 -63
- package/dist/daemon/control_protocol.js.map +0 -1
- package/dist/daemon/cron_log.d.ts +0 -45
- package/dist/daemon/cron_log.js +0 -71
- package/dist/daemon/cron_log.js.map +0 -1
- package/dist/daemon/cron_registry.d.ts +0 -80
- package/dist/daemon/cron_registry.js +0 -198
- package/dist/daemon/cron_registry.js.map +0 -1
- package/dist/daemon/id.d.ts +0 -24
- package/dist/daemon/id.js +0 -36
- package/dist/daemon/id.js.map +0 -1
- package/dist/daemon/registry.d.ts +0 -63
- package/dist/daemon/registry.js +0 -153
- package/dist/daemon/registry.js.map +0 -1
- package/dist/daemon/rpc_child.d.ts +0 -194
- package/dist/daemon/rpc_child.js +0 -419
- package/dist/daemon/rpc_child.js.map +0 -1
- package/dist/daemon/supervisor.d.ts +0 -93
- package/dist/daemon/supervisor.js +0 -666
- package/dist/daemon/supervisor.js.map +0 -1
- /package/dist/bin/{supervisord.d.ts → launcher.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
> **Derived from [remote-pi](https://github.com/jacobaraujo7/remote_pi)** by Jacob
|
|
2
2
|
> Moura, used under the MIT License (preserved in [`LICENSE`](LICENSE)). This tree
|
|
3
|
-
> is part of the [
|
|
4
|
-
> below still carries upstream branding and is being rebranded to un-bien.
|
|
3
|
+
> is part of the [Un Bien](../README.md) monorepo.
|
|
5
4
|
|
|
6
5
|
<p align="center">
|
|
7
|
-
<img src="https://raw.githubusercontent.com/georgeharker/un-bien/main/app/icons/un-bien-macos-1024.png" width="160" alt="
|
|
6
|
+
<img src="https://raw.githubusercontent.com/georgeharker/un-bien/main/app/icons/un-bien-macos-1024.png" width="160" alt="Un Bien logo" />
|
|
8
7
|
</p>
|
|
9
8
|
|
|
10
|
-
<h1 align="center">
|
|
9
|
+
<h1 align="center">Un Bien</h1>
|
|
11
10
|
|
|
12
11
|
> Extend the [Pi coding agent](https://github.com/earendil-works/pi) with two
|
|
13
|
-
> superpowers:
|
|
14
|
-
>
|
|
12
|
+
> superpowers: **remote-control Pi from your phone** (native iOS/macOS app over a
|
|
13
|
+
> relay you host), and a **local agent mesh** where several Pi sessions talk to
|
|
14
|
+
> each other.
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
`/remote-pi` is a single slash command that wires both at once. Run it; the
|
|
19
|
-
first time it asks a couple of questions and you are done.
|
|
16
|
+
`/unbien` is a single slash command that wires both at once. Run it; the first
|
|
17
|
+
time it asks a couple of questions and you are done.
|
|
20
18
|
|
|
21
19
|
## Protocol & Security
|
|
22
20
|
|
|
@@ -32,22 +30,28 @@ document — this README only covers user-facing setup.
|
|
|
32
30
|
Install the extension (one-time):
|
|
33
31
|
|
|
34
32
|
```bash
|
|
35
|
-
pi install npm
|
|
33
|
+
pi install npm:@geohar/un-bien
|
|
36
34
|
```
|
|
37
35
|
|
|
38
36
|
Then in any Pi terminal:
|
|
39
37
|
|
|
40
38
|
```text
|
|
41
|
-
/
|
|
39
|
+
/unbien
|
|
42
40
|
```
|
|
43
41
|
|
|
44
42
|
The first run shows a short interactive wizard (agent name, default session,
|
|
45
|
-
whether to
|
|
46
|
-
the local agent session and starts the relay automatically — no extra
|
|
43
|
+
whether to use the relay on this terminal). On every following run, `/unbien`
|
|
44
|
+
joins the local agent session and starts the relay automatically — no extra
|
|
45
|
+
typing.
|
|
46
|
+
|
|
47
|
+
> **You must configure a relay before the mobile app can connect.** Un Bien ships
|
|
48
|
+
> pointing at **nobody's** infrastructure — there is no built-in default relay.
|
|
49
|
+
> Self-host one (see [The relay](#the-relay)) and point the extension at it with
|
|
50
|
+
> `/unbien set-relay <url>`.
|
|
47
51
|
|
|
48
52
|
### Try the agent network in 30 seconds
|
|
49
53
|
|
|
50
|
-
Open **two** Pi terminals in the same directory and run `/
|
|
54
|
+
Open **two** Pi terminals in the same directory and run `/unbien` in each.
|
|
51
55
|
Both join the same session. Now just talk to the LLM — it has the tools.
|
|
52
56
|
|
|
53
57
|
In terminal A (say it ended up named `agent-A`):
|
|
@@ -78,8 +82,7 @@ normalize it.
|
|
|
78
82
|
|
|
79
83
|
## What it does
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
both:
|
|
85
|
+
Un Bien adds two independent layers on top of Pi. You can use either, or both:
|
|
83
86
|
|
|
84
87
|
### 1) Agent network (local broker, optional cross-PC relay)
|
|
85
88
|
|
|
@@ -97,7 +100,7 @@ current turn, and receive any later reply through the inbox/turn flow with
|
|
|
97
100
|
`re` correlating it to the original message id.
|
|
98
101
|
|
|
99
102
|
Peers on the same machine talk over a Unix domain socket at
|
|
100
|
-
`~/.
|
|
103
|
+
`~/.local/state/un-bien/sessions/<session-name>/broker.sock`. When sibling PCs are paired,
|
|
101
104
|
a leader-capable Extension or MCP participant bridges the opaque cross-PC
|
|
102
105
|
addresses over the relay; local-only use stays on UDS when relay access is off.
|
|
103
106
|
Useful for splitting work across roles (`backend`, `frontend`, `tests`,
|
|
@@ -109,22 +112,19 @@ over — the failover is invisible to the LLMs.
|
|
|
109
112
|
|
|
110
113
|
### 2) Mobile app (over the relay)
|
|
111
114
|
|
|
112
|
-
The companion
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
The companion native iOS/macOS app lets you **attach to a running Pi session — or
|
|
116
|
+
launch a new one** — and drive it from your phone: send prompts, read responses,
|
|
117
|
+
answer Pi's interactive prompts, and switch models. The phone and the Pi process
|
|
118
|
+
find each other through a **relay**: a small WebSocket server that ferries
|
|
119
|
+
messages between them. Pairing is one-time and per device, via QR code.
|
|
116
120
|
|
|
117
121
|
Communication uses WebSocket over TLS to the relay. Fields such as `ct` are
|
|
118
122
|
wire containers, not a systemwide end-to-end confidentiality guarantee: current
|
|
119
123
|
Pi-forward, cross-PC, app, and control envelopes visible to the relay are not
|
|
120
124
|
fully opaque or E2E encrypted. A relay operator can see routed plaintext
|
|
121
125
|
protocol content and metadata; see [`rpc-envelope`](../docs/rpc-envelope.md) for the exact
|
|
122
|
-
trust boundaries.
|
|
123
|
-
|
|
124
|
-
**Get the app** — all current download options (Google Play, App Store, and
|
|
125
|
-
direct builds while public releases roll out):
|
|
126
|
-
|
|
127
|
-
<https://remote-pi.jacobmoura.work/#get-the-app>
|
|
126
|
+
trust boundaries. **Host the relay yourself** to keep that operator role in your
|
|
127
|
+
own hands.
|
|
128
128
|
|
|
129
129
|
---
|
|
130
130
|
|
|
@@ -150,23 +150,25 @@ under "App actions".
|
|
|
150
150
|
It is **not** a generic slash-command picker. The Pi SDK does not expose
|
|
151
151
|
programmatic invocation for most builtins (those live in the TUI's
|
|
152
152
|
interactive loop), so the app exposes only the actions that have a clean
|
|
153
|
-
SDK call.
|
|
154
|
-
follows the same pattern.
|
|
153
|
+
SDK call.
|
|
155
154
|
|
|
156
155
|
### Images
|
|
157
156
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
157
|
+
Un Bien **displays images produced during a session** — when a tool or the agent
|
|
158
|
+
emits an image, the extension surfaces it to the app as a preview (customType
|
|
159
|
+
`un-bien:received-image`), capped at 10 MB.
|
|
160
|
+
|
|
161
|
+
On the inbound side, the wire and extension also support **image ingest**: a
|
|
162
|
+
`user_message` may carry an optional `images` field (`{ data: <base64>, mime }`),
|
|
163
|
+
which the extension turns into the SDK's multimodal content (an `ImageContent`
|
|
164
|
+
followed by the caption `TextContent`) and feeds to `sendUserMessage(content)`.
|
|
165
|
+
The mobile app does **not** yet expose an attach control, so this path is
|
|
166
|
+
available to clients but not surfaced in the app today.
|
|
164
167
|
|
|
165
168
|
Whether a model accepts images is surfaced as a `vision` flag on each
|
|
166
|
-
`WireModel` (derived from the SDK's `Model.input` including `"image"`)
|
|
167
|
-
greys out the attach button when the active model is text-only.
|
|
169
|
+
`WireModel` (derived from the SDK's `Model.input` including `"image"`).
|
|
168
170
|
|
|
169
|
-
The **relay is unchanged** —
|
|
171
|
+
The **relay is unchanged** — an image travels inside the same application
|
|
170
172
|
message container as the text, so there's no binary channel (large files are a
|
|
171
173
|
future track). Base64 or a field named `ct` is not an E2E confidentiality
|
|
172
174
|
boundary; the current Relay visibility follows the trust model above. Text-only
|
|
@@ -179,39 +181,39 @@ messages are unaffected.
|
|
|
179
181
|
Requirements: Node 20+, Pi (the host coding agent).
|
|
180
182
|
|
|
181
183
|
```bash
|
|
182
|
-
pi install npm
|
|
184
|
+
pi install npm:@geohar/un-bien
|
|
183
185
|
```
|
|
184
186
|
|
|
185
|
-
The extension self-registers the `/
|
|
187
|
+
The extension self-registers the `/unbien` slash command and deploys an
|
|
186
188
|
agent skill that teaches the LLM how to use `list_peers`, `agent_send`, and the
|
|
187
189
|
event-driven inbox/reply flow.
|
|
188
190
|
|
|
189
191
|
To verify:
|
|
190
192
|
|
|
191
193
|
```text
|
|
192
|
-
/
|
|
194
|
+
/unbien config
|
|
193
195
|
```
|
|
194
196
|
|
|
195
197
|
It should print the effective relay URL and where it came from
|
|
196
|
-
(`env` / `config` / `
|
|
198
|
+
(`env` / `config` / `unset`).
|
|
197
199
|
|
|
198
200
|
---
|
|
199
201
|
|
|
200
|
-
## Using `/
|
|
202
|
+
## Using `/unbien`
|
|
201
203
|
|
|
202
204
|
The bare command is the everyday entry point:
|
|
203
205
|
|
|
204
206
|
```text
|
|
205
|
-
/
|
|
207
|
+
/unbien
|
|
206
208
|
```
|
|
207
209
|
|
|
208
210
|
Behavior depends on whether there's a local config for this directory:
|
|
209
211
|
|
|
210
|
-
| State
|
|
211
|
-
|
|
|
212
|
-
| First run (no `.pi/
|
|
213
|
-
| Returning user, auto-start enabled
|
|
214
|
-
| Returning user, auto-start disabled
|
|
212
|
+
| State | What happens |
|
|
213
|
+
| ---------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
214
|
+
| First run (no `.pi/un-bien/config.json`) | Interactive wizard → saves config → joins agent session → starts relay (if you opted in) |
|
|
215
|
+
| Returning user, auto-start enabled | Joins agent session + starts relay automatically, then prints status |
|
|
216
|
+
| Returning user, auto-start disabled | Prints status only; join/relay must be run manually |
|
|
215
217
|
|
|
216
218
|
The wizard asks three questions:
|
|
217
219
|
|
|
@@ -220,36 +222,36 @@ The wizard asks three questions:
|
|
|
220
222
|
an address from this name. Defaults to the directory name.
|
|
221
223
|
2. **Default session** — the name of the agent-network room for this
|
|
222
224
|
directory. Multiple terminals in the same directory join the same session.
|
|
223
|
-
3. **
|
|
224
|
-
|
|
225
|
-
|
|
225
|
+
3. **Use the relay on this terminal?** — `Yes` if you want `/unbien` to also
|
|
226
|
+
connect to the relay so the mobile app (and paired PCs) can reach this Pi.
|
|
227
|
+
`No` for local-only use (agent network without mobile access).
|
|
226
228
|
|
|
227
|
-
Re-run the wizard later with `/
|
|
229
|
+
Re-run the wizard later with `/unbien setup`.
|
|
228
230
|
|
|
229
231
|
---
|
|
230
232
|
|
|
231
233
|
## Pairing a mobile device
|
|
232
234
|
|
|
233
|
-
Once the relay is up (`/
|
|
235
|
+
Once the relay is up (`/unbien relay status` shows `started` or `paired`):
|
|
234
236
|
|
|
235
237
|
```text
|
|
236
|
-
/
|
|
238
|
+
/unbien pair
|
|
237
239
|
```
|
|
238
240
|
|
|
239
|
-
A QR code is printed in the terminal. Scan it with the
|
|
241
|
+
A QR code is printed in the terminal. Scan it with the Un Bien mobile app.
|
|
240
242
|
Pairing is **per machine** — once a device is paired, every Pi process on
|
|
241
|
-
this machine accepts it (it lives in `~/.
|
|
243
|
+
this machine accepts it (it lives in `~/.local/state/un-bien/peers.json`).
|
|
242
244
|
|
|
243
245
|
To list paired devices:
|
|
244
246
|
|
|
245
247
|
```text
|
|
246
|
-
/
|
|
248
|
+
/unbien devices
|
|
247
249
|
```
|
|
248
250
|
|
|
249
251
|
To remove one:
|
|
250
252
|
|
|
251
253
|
```text
|
|
252
|
-
/
|
|
254
|
+
/unbien revoke <shortid>
|
|
253
255
|
```
|
|
254
256
|
|
|
255
257
|
The shortid is the first 8 chars shown by `devices`.
|
|
@@ -259,60 +261,36 @@ The shortid is the first 8 chars shown by `devices`.
|
|
|
259
261
|
## The relay
|
|
260
262
|
|
|
261
263
|
The relay is the network boundary. TLS protects transit, but the Relay can see
|
|
262
|
-
routed plaintext protocol content and metadata; use a relay you trust or
|
|
263
|
-
self-host
|
|
264
|
+
routed plaintext protocol content and metadata; **use a relay you trust or
|
|
265
|
+
self-host**. There is no systemwide or PC-mesh E2E guarantee. For Pi-to-Pi
|
|
264
266
|
forwarding, the Relay currently permits a route when any correctly signed Owner
|
|
265
267
|
blob lists both canonical Pi keys. That does not prove the Owner paired with or
|
|
266
268
|
controls either Pi.
|
|
267
269
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
Upgrade the **Relay to 0.3 first**: an old Extension can consume the new
|
|
271
|
-
Relay's UUID errors. Extension 0.6 carries a one-release legacy wire-label
|
|
272
|
-
shim, so mixed new/old Extensions interoperate when both select the same unique
|
|
273
|
-
colon-free signed nickname label, or when neither has one and both use the
|
|
274
|
-
canonical standard-padded key prefix. Delimiter or collision cases, like
|
|
275
|
-
divergent nickname views, are unsupported and may be silently dropped by the
|
|
276
|
-
old receiver. Upgrade all Extension/MCP participants in one maintenance window.
|
|
277
|
-
The shim does not replace the receiver-local aliases returned by `list_peers`;
|
|
278
|
-
addresses remain opaque.
|
|
279
|
-
|
|
280
|
-
Extension 0.6 accepts an old Relay's lowercase 32-hex trusted error ID only as
|
|
281
|
-
a narrow shim for an old Relay or Relay rollback; that shim is not why
|
|
282
|
-
Relay-first is safe.
|
|
283
|
-
|
|
284
|
-
You have two options:
|
|
285
|
-
|
|
286
|
-
### Option A — Use the community relay
|
|
287
|
-
|
|
288
|
-
`https://relay-rp1.jacobmoura.work` (default). Zero setup. Good for trying
|
|
289
|
-
things out or for casual use. (The extension converts to `wss://…`
|
|
290
|
-
internally when opening the connection — both schemes point at the same
|
|
291
|
-
endpoint.)
|
|
270
|
+
**Un Bien ships with no default relay** — `/unbien config` reports `unset` until
|
|
271
|
+
you configure one, and the extension refuses to connect until you do.
|
|
292
272
|
|
|
293
|
-
|
|
273
|
+
### Self-host the relay
|
|
294
274
|
|
|
295
|
-
|
|
296
|
-
- **There is no IP allow-listing or VPN gating**.
|
|
297
|
-
|
|
298
|
-
### Option B — Self-host (recommended for privacy)
|
|
299
|
-
|
|
300
|
-
Run the relay yourself in Docker and put it behind a VPN like
|
|
275
|
+
Run the relay yourself and put it behind a VPN like
|
|
301
276
|
[Tailscale](https://tailscale.com), [WireGuard](https://www.wireguard.com),
|
|
302
277
|
or your own VPC. Because the relay's network-level protection is just TLS +
|
|
303
278
|
keypair authentication, layering a VPN on top means **only your devices** can
|
|
304
279
|
even reach the WebSocket port — defense in depth.
|
|
305
280
|
|
|
306
|
-
|
|
307
|
-
[relay README](
|
|
308
|
-
|
|
281
|
+
Build and run from the `relay/` crate in this monorepo (see the
|
|
282
|
+
[relay README](../relay/README.md) for environment variables and reverse-proxy
|
|
283
|
+
guidance):
|
|
309
284
|
|
|
310
285
|
```bash
|
|
286
|
+
# From the monorepo root:
|
|
287
|
+
docker build -t un-bien-relay ./relay
|
|
311
288
|
docker run -d \
|
|
312
|
-
--name
|
|
289
|
+
--name un-bien-relay \
|
|
313
290
|
-p 3000:3000 \
|
|
291
|
+
-v un-bien-data:/data \
|
|
314
292
|
--restart unless-stopped \
|
|
315
|
-
|
|
293
|
+
un-bien-relay
|
|
316
294
|
```
|
|
317
295
|
|
|
318
296
|
Bind the container to your VPN interface, terminate TLS in a reverse proxy,
|
|
@@ -323,7 +301,7 @@ and point both your Pi and your phone at the resulting `https://…` URL.
|
|
|
323
301
|
Once your relay is reachable, tell the extension:
|
|
324
302
|
|
|
325
303
|
```text
|
|
326
|
-
/
|
|
304
|
+
/unbien relay url https://relay.yourdomain.tld
|
|
327
305
|
```
|
|
328
306
|
|
|
329
307
|
The URL **must** be `http://` or `https://` — `ws://` / `wss://` are
|
|
@@ -331,21 +309,23 @@ rejected at validation. The extension converts to WebSocket internally when
|
|
|
331
309
|
it opens the connection. Same canonical form for the mobile app and any
|
|
332
310
|
self-hosting docs: paste the URL your reverse proxy exposes.
|
|
333
311
|
|
|
334
|
-
This writes
|
|
335
|
-
order (highest precedence first):
|
|
312
|
+
This writes the `relay` field into the global config at
|
|
313
|
+
`~/.pi/extensions/un-bien.json`. Resolution order (highest precedence first):
|
|
314
|
+
|
|
315
|
+
1. `UNBIEN_RELAY` environment variable (CI / one-off overrides)
|
|
316
|
+
2. `relay` field in `~/.pi/extensions/un-bien.json`
|
|
336
317
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
3. The built-in default (`https://relay-rp1.jacobmoura.work`)
|
|
318
|
+
There is **no built-in default** — when neither is set, the extension refuses
|
|
319
|
+
to connect and prompts you to configure a relay.
|
|
340
320
|
|
|
341
321
|
Verify the active URL and its source with:
|
|
342
322
|
|
|
343
323
|
```text
|
|
344
|
-
/
|
|
324
|
+
/unbien config
|
|
345
325
|
```
|
|
346
326
|
|
|
347
|
-
If you change the URL while connected, run `/
|
|
348
|
-
`/
|
|
327
|
+
If you change the URL while connected, run `/unbien relay stop` then
|
|
328
|
+
`/unbien relay start` (or `/unbien relay` to toggle).
|
|
349
329
|
|
|
350
330
|
The mobile app has its own relay-URL setting in its preferences pane — keep
|
|
351
331
|
both pointing at the same relay.
|
|
@@ -394,16 +374,16 @@ original message id.
|
|
|
394
374
|
|
|
395
375
|
The wire format is a 5-field envelope `{ from, to, id, re, body }` serialized
|
|
396
376
|
as one JSON line per message. The leader's broker writes an `audit.jsonl`
|
|
397
|
-
log at `~/.
|
|
377
|
+
log at `~/.local/state/un-bien/sessions/<name>/audit.jsonl` for postmortem inspection.
|
|
398
378
|
|
|
399
379
|
Useful commands:
|
|
400
380
|
|
|
401
|
-
| Command
|
|
402
|
-
|
|
|
403
|
-
| `/
|
|
404
|
-
| `/
|
|
405
|
-
| `/
|
|
406
|
-
| `/
|
|
381
|
+
| Command | What it does |
|
|
382
|
+
| ---------------------- | ----------------------------------------------------- |
|
|
383
|
+
| `/unbien` | Join the local mesh (and start the relay, if enabled) |
|
|
384
|
+
| `/unbien peers` | List local + cross-PC mesh peers, grouped by PC |
|
|
385
|
+
| `/unbien rename <new>` | Rename this agent in the current session |
|
|
386
|
+
| `/unbien stop` | Leave the local mesh and disconnect the relay |
|
|
407
387
|
|
|
408
388
|
Name collisions inside a session get a numeric suffix automatically
|
|
409
389
|
(`backend`, `backend#2`, `backend#3`). The broker assigns it and returns the
|
|
@@ -415,71 +395,30 @@ real name to the peer.
|
|
|
415
395
|
|
|
416
396
|
### Local session (one Pi, one terminal)
|
|
417
397
|
|
|
418
|
-
| Command
|
|
419
|
-
|
|
|
420
|
-
| `/
|
|
421
|
-
| `/
|
|
422
|
-
| `/
|
|
423
|
-
| `/
|
|
424
|
-
| `/
|
|
425
|
-
| `/
|
|
426
|
-
| `/
|
|
427
|
-
| `/
|
|
428
|
-
| `/
|
|
429
|
-
| `/
|
|
430
|
-
| `/
|
|
431
|
-
|
|
432
|
-
###
|
|
433
|
-
|
|
434
|
-
| Command
|
|
435
|
-
|
|
|
436
|
-
| `/
|
|
437
|
-
| `/
|
|
438
|
-
| `/remote-pi daemons` | List registered daemons + state |
|
|
439
|
-
| `/remote-pi daemon start` | Start every registered daemon |
|
|
440
|
-
| `/remote-pi daemon stop` | Stop every running daemon (`/remote-pi stop` stops only the local terminal) |
|
|
441
|
-
| `/remote-pi daemon restart` | Stop + start all daemons |
|
|
442
|
-
| `/remote-pi daemon status` | Detailed runtime status (pid, uptime, restart count) |
|
|
443
|
-
| `/remote-pi daemon send <id> "<text>"` | Send a prompt to a specific daemon |
|
|
444
|
-
| `/remote-pi cron add <id> "<expr>" "<prompt>"` | Schedule a recurring prompt (`--tz`, `--wake`, `--no-skip-busy`, `--catchup`) |
|
|
445
|
-
| `/remote-pi cron list` | List scheduled jobs (schedule, enabled, next run, last status) |
|
|
446
|
-
| `/remote-pi cron run <jobId>` | Fire a job now (ignores its schedule) |
|
|
447
|
-
| `/remote-pi cron enable\|disable <jobId>` | Toggle a job on/off |
|
|
448
|
-
| `/remote-pi cron remove <jobId>` | Delete a job |
|
|
449
|
-
| `/remote-pi cron log [<jobId>] [--tail N]` | Read the fire/skip audit log |
|
|
450
|
-
| `/remote-pi install` | Install `pi-supervisord` as a system service |
|
|
451
|
-
| `/remote-pi uninstall` | Remove the system service (registry preserved) |
|
|
398
|
+
| Command | Description |
|
|
399
|
+
| ------------------------------------- | ------------------------------------------------------------------------------ |
|
|
400
|
+
| `/unbien` | Connect (join local mesh + start relay), or run setup on first use |
|
|
401
|
+
| `/unbien setup` | Run the setup wizard and update local config |
|
|
402
|
+
| `/unbien status` | Show local mesh + relay status |
|
|
403
|
+
| `/unbien stop` | Stop everything for **this** terminal (mesh + relay) |
|
|
404
|
+
| `/unbien pair` | Show QR code + copy-paste pairing URI for a new mobile device |
|
|
405
|
+
| `/unbien devices` | List paired mobile devices (online/offline per device) |
|
|
406
|
+
| `/unbien revoke <shortid>` | Revoke a paired device by its shortid |
|
|
407
|
+
| `/unbien set-relay <url>` | Persist a new relay URL (http:// or https://) |
|
|
408
|
+
| `/unbien relay [start\|stop\|status]` | Relay-only control — leaves local mesh membership untouched (no verb = toggle) |
|
|
409
|
+
| `/unbien relay url <url>` | Same as `set-relay` |
|
|
410
|
+
| `/unbien config` | Show the effective relay URL and its source (env / config / unset) |
|
|
411
|
+
|
|
412
|
+
### Service install & remote launch (see [Remote launch](#remote-launch))
|
|
413
|
+
|
|
414
|
+
| Command | Description |
|
|
415
|
+
| ------------------- | ---------------------------------------------------------------------------------- |
|
|
416
|
+
| `/unbien install` | Install the **unbien-launcher** daemon as a system service + link the `unbien` CLI |
|
|
417
|
+
| `/unbien uninstall` | Remove the launcher service + CLI links (pairing and config preserved) |
|
|
452
418
|
|
|
453
419
|
All commands above work both as Pi slash commands (interactive) and as
|
|
454
|
-
shell-level `
|
|
455
|
-
globally (`npm install -g
|
|
456
|
-
|
|
457
|
-
### Scheduled prompts (`cron`)
|
|
458
|
-
|
|
459
|
-
`remote-pi cron` schedules **recurring prompts** to daemons through the
|
|
460
|
-
supervisor — e.g. a daily "summarise new PRs". Output flows fire-and-forget to
|
|
461
|
-
the mesh/app like any prompt; the cron layer only audits the dispatch.
|
|
462
|
-
|
|
463
|
-
- **Schedule** is a cron expression (croner syntax; an optional 6th _seconds_
|
|
464
|
-
field is supported), with an optional IANA timezone via `--tz`:
|
|
465
|
-
|
|
466
|
-
```sh
|
|
467
|
-
remote-pi cron add a1b2c3d4 "0 9 * * *" "Summarise new PRs" --tz America/Sao_Paulo
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
- **Minimum interval is 60s** — more frequent schedules are rejected (guards
|
|
471
|
-
token cost + pileup). A fire is **skipped when the daemon is mid-turn**
|
|
472
|
-
(`--no-skip-busy` to override); `--wake` starts a stopped daemon first;
|
|
473
|
-
`--catchup` runs once on supervisor start if the previous run was missed.
|
|
474
|
-
- **Prerequisite**: the supervisor must run as a service (`remote-pi install`).
|
|
475
|
-
Without it there is no scheduler, and `cron` commands say so instead of
|
|
476
|
-
silently pretending to schedule.
|
|
477
|
-
- **Audit**: every fire **and** every skip appends one line to
|
|
478
|
-
`~/.pi/remote/cron.jsonl` with a `result` of `delivered`,
|
|
479
|
-
`woke_and_delivered`, `deliver_failed`, `skipped_busy`, `skipped_down`, or
|
|
480
|
-
`skipped_disabled` — read it with `remote-pi cron log`.
|
|
481
|
-
|
|
482
|
-
Step-by-step walkthrough: the [daemon tutorial](https://remote-pi.jacobmoura.work/tutorials/daemon).
|
|
420
|
+
shell-level `unbien <subcommand>` when the package is installed
|
|
421
|
+
globally (`npm install -g @geohar/un-bien`).
|
|
483
422
|
|
|
484
423
|
### Footer + title
|
|
485
424
|
|
|
@@ -494,167 +433,190 @@ tabs.
|
|
|
494
433
|
|
|
495
434
|
---
|
|
496
435
|
|
|
497
|
-
##
|
|
436
|
+
## Remote launch
|
|
498
437
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
438
|
+
The **unbien-launcher** is a lightweight mesh peer — **not** a Pi session — that
|
|
439
|
+
lets a paired app reach your machine even when no Pi is running. It reuses the
|
|
440
|
+
machine's un-bien config (identity + relay), joins the machine-level control
|
|
441
|
+
room, advertises `remote_launch`, and spawns a `pi` window via `tmux` (default)
|
|
442
|
+
or `herdr` when the app asks for one.
|
|
503
443
|
|
|
504
444
|
See [`docs/daemon.md`](./docs/daemon.md) for troubleshooting.
|
|
505
445
|
|
|
506
446
|
### One-time setup
|
|
507
447
|
|
|
508
448
|
```bash
|
|
509
|
-
# Install the package globally so `
|
|
510
|
-
#
|
|
511
|
-
#
|
|
449
|
+
# Install the package globally so the `unbien` CLI is on your PATH
|
|
450
|
+
# (`pi install npm:@geohar/un-bien` alone makes the Pi extension available
|
|
451
|
+
# but does NOT expose the CLI binary — see
|
|
512
452
|
# https://docs.npmjs.com/cli/v10/configuring-npm/package-json#bin).
|
|
513
|
-
npm install -g
|
|
453
|
+
npm install -g @geohar/un-bien
|
|
514
454
|
|
|
515
|
-
# Install the
|
|
455
|
+
# Install the launcher as a user-level system service. Linux uses
|
|
516
456
|
# systemd --user; macOS uses launchd LaunchAgent. Both auto-start at
|
|
517
457
|
# login and survive reboots.
|
|
518
|
-
|
|
458
|
+
unbien install
|
|
519
459
|
```
|
|
520
460
|
|
|
461
|
+
Or from inside Pi: `/unbien install` — same service, plus it links the
|
|
462
|
+
`unbien` CLI into `~/.local/bin` so no global npm install is needed.
|
|
463
|
+
|
|
521
464
|
The `install` command:
|
|
522
465
|
|
|
523
|
-
- Writes `~/.config/systemd/user/
|
|
524
|
-
|
|
466
|
+
- Writes `~/.config/systemd/user/unbien-launcher.service` (Linux) or
|
|
467
|
+
`~/Library/LaunchAgents/dev.unbien.launcher.plist` (macOS); on Windows it
|
|
468
|
+
registers a Task Scheduler task (`RemotePiLauncher`) and prompts for
|
|
469
|
+
elevation once
|
|
525
470
|
- Activates it via `systemctl --user enable --now` or `launchctl bootstrap`
|
|
526
|
-
- The
|
|
471
|
+
- The launcher starts immediately and re-starts on every login
|
|
527
472
|
|
|
528
|
-
|
|
473
|
+
A standalone package exists for running the launcher in the foreground, no
|
|
474
|
+
service: `npm install -g @geohar/un-bien-launcher` → `unbien-launcher`. Same
|
|
475
|
+
daemon, shipped as its own binary (see the
|
|
476
|
+
[launcher README](../launcher/README.md)).
|
|
529
477
|
|
|
530
|
-
|
|
478
|
+
### Enable remote launch
|
|
531
479
|
|
|
532
|
-
|
|
533
|
-
# 1. Configure the agent interactively first (one time).
|
|
534
|
-
cd ~/Movies
|
|
535
|
-
pi # /remote-pi → setup wizard, /remote-pi pair, etc
|
|
536
|
-
|
|
537
|
-
# 2. Promote to a daemon. The id is derived from the cwd
|
|
538
|
-
# (sha256(realpath)[:8]), stable across machines.
|
|
539
|
-
remote-pi create ~/Movies --name "Video Editor"
|
|
540
|
-
# → Daemon registered: id=4e39152d name="Video Editor" cwd=/Users/x/Movies
|
|
480
|
+
The launcher only spawns sessions where remote launch is **opted in**:
|
|
541
481
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
482
|
+
- per directory: `allow_remote_launch: true` in `<cwd>/.pi/un-bien/config.json`
|
|
483
|
+
- or machine-wide: `defaults.allow_remote_launch: true` in the global config
|
|
484
|
+
(`~/.pi/extensions/un-bien.json`)
|
|
545
485
|
|
|
546
|
-
|
|
486
|
+
The spawn backend is machine-wide: `launch.backend` in the global config —
|
|
487
|
+
`tmux` (default; one shared `un-bien` tmux session, a window per launched Pi)
|
|
488
|
+
or `herdr`. The backend binary must be on PATH: `unbien install` snapshots
|
|
489
|
+
your PATH at install time, so re-run it after installing new tools.
|
|
547
490
|
|
|
548
|
-
|
|
549
|
-
remote-pi daemons # list + state
|
|
550
|
-
remote-pi daemon status # uptime, pid, restart count
|
|
551
|
-
remote-pi daemon send 4e39152d "Cut the first 30 seconds of latest clip"
|
|
552
|
-
remote-pi daemon stop # stop all
|
|
553
|
-
remote-pi daemon restart # restart all
|
|
554
|
-
```
|
|
491
|
+
### Launch names
|
|
555
492
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
493
|
+
A `session_launch` request may carry a `name`. On the tmux backend the
|
|
494
|
+
launched Pi gets it as `pi -n <name>` — pi's native session display name —
|
|
495
|
+
which the extension resolves as the session-scoped agent name: the mesh
|
|
496
|
+
join, cwd lock, `room_meta`, and the app's session tile all show it instead
|
|
497
|
+
of the path-derived default. It is per-process (never inherited by
|
|
498
|
+
subagents or child processes) and never persisted — a manual `pi` in the
|
|
499
|
+
same directory keeps its configured `agent_name`. `/unbien rename` still
|
|
500
|
+
wins once it runs. The herdr backend uses the name as the workspace label
|
|
501
|
+
only until it can pass args through to pi.
|
|
560
502
|
|
|
561
503
|
### Removing or uninstalling
|
|
562
504
|
|
|
563
505
|
```bash
|
|
564
|
-
|
|
565
|
-
remote-pi uninstall # remove the supervisor service (registry kept)
|
|
506
|
+
unbien uninstall # remove the launcher service (pairing + config kept)
|
|
566
507
|
```
|
|
567
508
|
|
|
568
|
-
`uninstall` is reversible — re-running `install` later brings
|
|
569
|
-
|
|
570
|
-
~/.pi/remote/daemons.json`.
|
|
509
|
+
`uninstall` is reversible — re-running `install` later brings the launcher
|
|
510
|
+
back. Pairing and identity live in the state root and are never touched.
|
|
571
511
|
|
|
572
512
|
### Where to find logs
|
|
573
513
|
|
|
574
|
-
| Platform | Command
|
|
575
|
-
| -------- |
|
|
576
|
-
| Linux | `journalctl --user -u
|
|
577
|
-
| macOS | `tail -f ~/.
|
|
578
|
-
|
|
579
|
-
Each spawned daemon's stderr is forwarded into the supervisor's log
|
|
580
|
-
with a `[<cwd>]` prefix, so a single log stream shows every agent.
|
|
581
|
-
|
|
582
|
-
### Caveats (plan/26 trade-offs)
|
|
583
|
-
|
|
584
|
-
- **Tool approval is not gated.** Daemons inherit the same Pi config
|
|
585
|
-
the interactive run uses — Bash, Edit, Write etc. all execute without
|
|
586
|
-
prompting. Configure Pi's tool permissions to taste before promoting
|
|
587
|
-
a folder to daemon.
|
|
588
|
-
- **Pairing still happens interactively.** Daemons don't show a QR
|
|
589
|
-
themselves; the keypair + paired devices come from the prior `pi`
|
|
590
|
-
session in the same folder.
|
|
591
|
-
- **Single supervisor.** If `pi-supervisord` crashes all daemons go
|
|
592
|
-
down with it. systemd/launchd restarts it within seconds; daemons
|
|
593
|
-
come back automatically.
|
|
594
|
-
- **One daemon per cwd.** The `roomIdForCwd` derivation makes daemons
|
|
595
|
-
by-path; two daemons in the same folder is rejected at `create` time.
|
|
514
|
+
| Platform | Command |
|
|
515
|
+
| -------- | ------------------------------------------------------- |
|
|
516
|
+
| Linux | `journalctl --user -u unbien-launcher -f` |
|
|
517
|
+
| macOS | `tail -f ~/.local/state/un-bien/launcher.log` |
|
|
518
|
+
| Windows | `Get-Content ~\.local\state\un-bien\launcher.log -Wait` |
|
|
596
519
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
## Configuration files
|
|
600
|
-
|
|
601
|
-
| Path | Scope | What's in it |
|
|
602
|
-
| -------------------------------------------- | ------------- | --------------------------------------------------------------------------------------------------- |
|
|
603
|
-
| `<cwd>/.pi/remote-pi/config.json` | Per-directory | `agent_name`, `session_name`, `auto_start_relay` |
|
|
604
|
-
| `~/.pi/remote/config.json` | Per-user | `relay` URL; optional `defaults.auto_start_relay` (machine-wide fallback for per-directory configs) |
|
|
605
|
-
| `~/.pi/remote/peers.json` | Per-machine | Paired mobile devices |
|
|
606
|
-
| `~/.pi/remote/sessions/<name>/` | Per-session | Broker socket + `audit.jsonl` |
|
|
607
|
-
| `~/.pi/remote/skills/agent-network/SKILL.md` | Per-user | Agent skill the LLM reads |
|
|
520
|
+
### Caveats
|
|
608
521
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
522
|
+
- **Pairing still happens interactively.** The launcher doesn't show a QR; it
|
|
523
|
+
only trusts owners already paired via `/unbien pair` in a Pi session on
|
|
524
|
+
this machine.
|
|
525
|
+
- **Tool execution is not gated.** A launched Pi inherits the same Pi config
|
|
526
|
+
an interactive run uses — Bash, Edit, Write etc. all execute without
|
|
527
|
+
prompting. Configure Pi's tool permissions to taste before enabling
|
|
528
|
+
`allow_remote_launch`.
|
|
529
|
+
- **Same identity, same relay.** The launcher reads the machine's global
|
|
530
|
+
config — `/unbien config` shows exactly what it will use.
|
|
612
531
|
|
|
613
|
-
|
|
614
|
-
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
615
|
-
| `REMOTE_PI_DIR` | Absolute path to the state root. No suffix appended — set this to an XDG-style location like `~/.config/pi/remote-pi`. Takes priority over every other variable. |
|
|
616
|
-
| `REMOTE_PI_HOME` | Stand-in for `$HOME`; state lives at `<REMOTE_PI_HOME>/.pi/remote`. Kept for backward compatibility. |
|
|
617
|
-
|
|
618
|
-
When both are set, `REMOTE_PI_DIR` wins. Use these to put remote-pi **state**
|
|
619
|
-
(sessions, daemon registries, cwd locks, paired identity) on a specific disk,
|
|
620
|
-
inside an XDG directory, or anywhere your system's conventions dictate.
|
|
532
|
+
---
|
|
621
533
|
|
|
622
|
-
|
|
623
|
-
can sit beside the coding agent's own settings rather than the state tree:
|
|
534
|
+
## Configuration & settings
|
|
624
535
|
|
|
625
|
-
|
|
626
|
-
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
627
|
-
| `PI_CODING_AGENT_DIR` | The Pi host's settings root (default `~/.pi`). `config.json` lives at `<PI_CODING_AGENT_DIR>/remote/config.json`, so with the default agent dir the path stays exactly `~/.pi/remote/config.json`. Takes priority for config. |
|
|
536
|
+
### Files
|
|
628
537
|
|
|
629
|
-
|
|
630
|
-
|
|
538
|
+
| Path | Scope | What's in it |
|
|
539
|
+
| ------------------------------------------------------ | ----------------- | ------------------------------------------------------------------------------ |
|
|
540
|
+
| `~/.pi/extensions/un-bien.json` | Per-user (global) | `relay` URL, `defaults`, `identity`, `debug` — the global settings (see below) |
|
|
541
|
+
| `<cwd>/.pi/un-bien/config.json` | Per-directory | `agent_name`, `auto_start_relay`, `allow_remote_launch` |
|
|
542
|
+
| `~/.local/state/un-bien/identity.json` | Per-machine | Paired identity keypair (file identity backend; `0600`) |
|
|
543
|
+
| `~/.local/state/un-bien/peers.json` | Per-machine | Paired mobile devices |
|
|
544
|
+
| `~/.local/state/un-bien/sessions/<name>/` | Per-session | Broker socket + `audit.jsonl` |
|
|
545
|
+
| `~/.local/state/un-bien/skills/agent-network/SKILL.md` | Per-user | Agent skill the LLM reads |
|
|
631
546
|
|
|
632
|
-
### Global
|
|
547
|
+
### Global settings — `~/.pi/extensions/un-bien.json`
|
|
633
548
|
|
|
634
|
-
|
|
635
|
-
|
|
549
|
+
This is a Pi **extension config** (it lives beside the coding agent's own
|
|
550
|
+
settings, under `PI_CODING_AGENT_DIR/extensions/`, not in the state tree). All
|
|
551
|
+
fields are optional:
|
|
636
552
|
|
|
637
553
|
```jsonc
|
|
638
554
|
{
|
|
555
|
+
// Relay URL in canonical http(s):// form. No default — unset means the
|
|
556
|
+
// extension refuses to connect. Set via `/unbien set-relay <url>`.
|
|
639
557
|
"relay": "https://relay.yourdomain.tld",
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
558
|
+
|
|
559
|
+
// Machine-wide fallback for every per-cwd config that doesn't set the field.
|
|
560
|
+
// Pin auto-start once instead of dropping a file into every repo.
|
|
561
|
+
"defaults": { "auto_start_relay": true },
|
|
562
|
+
|
|
563
|
+
// Remote-launch backend a `session_launch` request uses on THIS machine:
|
|
564
|
+
// "tmux" (default; one shared tmux session, a window per launched Pi) or
|
|
565
|
+
// "herdr". Machine-wide choice — whether remote launch is enabled at all
|
|
566
|
+
// stays the per-cwd `allow_remote_launch` flag.
|
|
567
|
+
"launch": { "backend": "tmux" },
|
|
568
|
+
|
|
569
|
+
// Machine-identity storage. `storage` selects the PRIMARY backend for this
|
|
570
|
+
// Pi's long-term Ed25519 seed: "keychain" (OS-secured, default) or "file"
|
|
571
|
+
// (a 0600 seed file — the SSH-private-key model: cat-able, portable,
|
|
572
|
+
// works headless). `path` overrides the file-backend location
|
|
573
|
+
// (default ~/.local/state/un-bien/identity.json). The unselected backend is still
|
|
574
|
+
// READ to recover an existing identity, but never written.
|
|
575
|
+
"identity": { "storage": "keychain", "path": "~/.local/state/un-bien/identity.json" },
|
|
576
|
+
|
|
577
|
+
// File-based diagnostic logs. Off by default. Read from config (not env)
|
|
578
|
+
// because the daemon fork usually runs detached without a shell's env.
|
|
579
|
+
"debug": { "envelope": false, "panels": false },
|
|
643
580
|
}
|
|
644
581
|
```
|
|
645
582
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
583
|
+
### Per-directory settings — `<cwd>/.pi/un-bien/config.json`
|
|
584
|
+
|
|
585
|
+
Written by the `/unbien` setup wizard:
|
|
586
|
+
|
|
587
|
+
| Field | Default | Meaning |
|
|
588
|
+
| --------------------- | -------------- | ------------------------------------------------------------------------------------------ |
|
|
589
|
+
| `agent_name` | directory name | Presentation leaf name for this agent (senders still use the opaque `list_peers` address) |
|
|
590
|
+
| `auto_start_relay` | `true` | On a fresh terminal, `/unbien` auto-joins the mesh and starts the relay |
|
|
591
|
+
| `allow_remote_launch` | `false` | Honor `session_launch` requests from a paired owner (spawn a new Pi session). Opt-in only. |
|
|
592
|
+
|
|
593
|
+
### Environment variables
|
|
594
|
+
|
|
595
|
+
| Variable | Purpose |
|
|
596
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
597
|
+
| `UNBIEN_RELAY` | Relay URL override (highest precedence, ahead of the config file). CI / one-off use. |
|
|
598
|
+
| `UNBIEN_STATE_DIR` | Absolute override of the **state** dir itself. The knob for relocating state. Highest precedence of the state knobs. |
|
|
599
|
+
| `UNBIEN_DIR` | Legacy absolute override of the **state** dir itself (no suffix appended). Lower precedence than `UNBIEN_STATE_DIR`. |
|
|
600
|
+
| `UNBIEN_HOME` | Legacy stand-in `$HOME`; state lives at `<UNBIEN_HOME>/.pi/un-bien`. Lower precedence than `UNBIEN_DIR`. |
|
|
601
|
+
| `PI_CODING_AGENT_DIR` | The Pi host's settings root (default `~/.pi`); the global config lives at `<PI_CODING_AGENT_DIR>/extensions/un-bien.json`. |
|
|
602
|
+
| `UNBIEN_DIRECT_CONFIG` | Inline per-cwd config (JSON) instead of a `.pi/un-bien/config.json` file — CI / one-off use. |
|
|
649
603
|
|
|
650
|
-
The
|
|
651
|
-
|
|
652
|
-
|
|
604
|
+
The state root resolves as `UNBIEN_STATE_DIR` > `UNBIEN_DIR` > `UNBIEN_HOME` >
|
|
605
|
+
`${XDG_STATE_HOME:-~/.local/state}/un-bien` — the XDG-style default. `UNBIEN_DIR`/
|
|
606
|
+
`UNBIEN_HOME` relocate un-bien **state** (sessions, cwd locks, paired identity) and stay honored for older deployments. On first use
|
|
607
|
+
of the new default, a one-time best-effort migration moves any legacy
|
|
608
|
+
`~/.pi/un-bien` state (peers.json included) into the new root.
|
|
609
|
+
`PI_CODING_AGENT_DIR` relocates only the global **config**, so it can sit
|
|
610
|
+
beside the coding agent's own settings.
|
|
611
|
+
|
|
612
|
+
**Deprecated**: the relay no longer defaults its SQLite DB to a CWD-relative
|
|
613
|
+
`data/mesh.db` — see the relay README for its `UNBIEN_MESH_DB_PATH` /
|
|
614
|
+
state-root resolution.
|
|
653
615
|
|
|
654
616
|
Override the relay for a single run without persisting:
|
|
655
617
|
|
|
656
618
|
```bash
|
|
657
|
-
|
|
619
|
+
UNBIEN_RELAY=https://staging.example.tld pi
|
|
658
620
|
```
|
|
659
621
|
|
|
660
622
|
---
|
|
@@ -664,13 +626,16 @@ REMOTE_PI_RELAY=https://staging.example.tld pi
|
|
|
664
626
|
**Footer says `🟡 relay waiting for pairing` even though I paired a device.**
|
|
665
627
|
The icon reflects whether _any_ device has been paired on this machine, not
|
|
666
628
|
whether one is connected right now. If you really have a paired device in
|
|
667
|
-
`/
|
|
629
|
+
`/unbien devices`, restart Pi — the cache may be stale (fixed in current
|
|
668
630
|
release; report a bug if it recurs).
|
|
669
631
|
|
|
670
632
|
**Mobile app times out connecting.** Verify the same relay URL is configured
|
|
671
633
|
on both sides. If you self-host behind a VPN, your phone must also be on the
|
|
672
634
|
VPN (Tailscale on iOS/Android works fine).
|
|
673
635
|
|
|
636
|
+
**`/unbien config` says the relay is `unset`.** Un Bien has no default relay.
|
|
637
|
+
Self-host one and set it with `/unbien set-relay <url>` (or `UNBIEN_RELAY`).
|
|
638
|
+
|
|
674
639
|
**`agent_request` keeps timing out.** It is deprecated because it blocks the
|
|
675
640
|
turn while waiting for another agent's content reply. Migrate to `agent_send`;
|
|
676
641
|
a unicast waits only for the delivery ACK, and the receiver can reply later
|
|
@@ -683,44 +648,17 @@ other terminal first.
|
|
|
683
648
|
|
|
684
649
|
---
|
|
685
650
|
|
|
686
|
-
## Branding
|
|
687
|
-
|
|
688
|
-
Official brand assets live in
|
|
689
|
-
[`/branding`](https://github.com/jacobaraujo7/remote_pi/tree/main/branding) —
|
|
690
|
-
SVG sources for the logo (full, foreground, background, monochrome) plus a
|
|
691
|
-
banner. See the
|
|
692
|
-
[branding README](https://github.com/jacobaraujo7/remote_pi/blob/main/branding/README.md)
|
|
693
|
-
for palette and export sizes.
|
|
694
|
-
|
|
695
|
-
<table>
|
|
696
|
-
<tr>
|
|
697
|
-
<td align="center">
|
|
698
|
-
<img src="https://raw.githubusercontent.com/jacobaraujo7/remote_pi/main/branding/logo-full.svg" width="96" alt="logo-full" /><br/>
|
|
699
|
-
<sub><code>logo-full</code></sub>
|
|
700
|
-
</td>
|
|
701
|
-
<td align="center">
|
|
702
|
-
<img src="https://raw.githubusercontent.com/jacobaraujo7/remote_pi/main/branding/logo-foreground.svg" width="96" alt="logo-foreground" /><br/>
|
|
703
|
-
<sub><code>logo-foreground</code></sub>
|
|
704
|
-
</td>
|
|
705
|
-
<td align="center">
|
|
706
|
-
<img src="https://raw.githubusercontent.com/jacobaraujo7/remote_pi/main/branding/logo-monochrome.svg" width="96" alt="logo-monochrome" /><br/>
|
|
707
|
-
<sub><code>logo-monochrome</code></sub>
|
|
708
|
-
</td>
|
|
709
|
-
</tr>
|
|
710
|
-
</table>
|
|
711
|
-
|
|
712
|
-
---
|
|
713
|
-
|
|
714
651
|
## Links
|
|
715
652
|
|
|
716
|
-
-
|
|
717
|
-
-
|
|
653
|
+
- Repository: <https://github.com/georgeharker/un-bien>
|
|
654
|
+
- Documentation: <https://docs.georgeharker.com/un-bien>
|
|
718
655
|
- Pi coding agent: <https://github.com/earendil-works/pi>
|
|
719
|
-
- Relay (self-hosting guide):
|
|
720
|
-
-
|
|
656
|
+
- Relay (self-hosting guide): [`../relay/README.md`](../relay/README.md)
|
|
657
|
+
- Upstream project (remote-pi, MIT): <https://github.com/jacobaraujo7/remote_pi>
|
|
721
658
|
|
|
722
659
|
---
|
|
723
660
|
|
|
724
661
|
## License
|
|
725
662
|
|
|
726
|
-
MIT
|
|
663
|
+
MIT — derived from [remote-pi](https://github.com/jacobaraujo7/remote_pi) by
|
|
664
|
+
Jacob Moura. See [`LICENSE`](LICENSE).
|