@bondsmith/bondsmithd 0.1.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 +139 -0
- package/dist/index.js +2840 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# bondsmithd
|
|
2
|
+
|
|
3
|
+
Local daemon that manages tmux-backed terminal sessions on your machine and exposes them to the
|
|
4
|
+
Bondsmith web app over a signed WebSocket protocol. Runs entirely on your own machine — no code,
|
|
5
|
+
terminal output, or session data is ever sent anywhere except the Bondsmith account you explicitly
|
|
6
|
+
pair it with.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install -g @bondsmith/bondsmithd
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Requires Node >=24 and `tmux` (`brew install tmux` on macOS). `node-pty`, the one native
|
|
15
|
+
dependency, ships prebuilt binaries for macOS (Intel and Apple Silicon) and installs without
|
|
16
|
+
compiling anything on supported platforms.
|
|
17
|
+
|
|
18
|
+
## Running
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bondsmithd
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
On first run, `bondsmithd` prints a pairing code and URL — confirm it from your Bondsmith account
|
|
25
|
+
to trust this machine. After that, `bondsmithd` just needs to be running for the Bondsmith web app
|
|
26
|
+
to see and control sessions on this machine.
|
|
27
|
+
|
|
28
|
+
Start it from a normal interactive shell, not a stripped-down context (a bare `launchd`/login-item
|
|
29
|
+
invocation, a minimal CI shell, etc.). The daemon passes its own `process.env` through to every
|
|
30
|
+
tmux session it creates, so sessions inherit your real `PATH`, version manager shims
|
|
31
|
+
(`mise`/`nvm`/etc.), and tools like `claude` or `pnpm` — the same environment you'd get opening a
|
|
32
|
+
new terminal tab. A stripped environment at daemon-start time means the same stripped environment
|
|
33
|
+
in every session it launches.
|
|
34
|
+
|
|
35
|
+
Environment variables (all optional):
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
PORT=4577 # defaults to 4577
|
|
39
|
+
ALLOWED_ORIGINS=https://app.bondsmith.dev
|
|
40
|
+
BONDSMITH_RELAY_URL=wss://relay.bondsmith.dev # defaults to a local-only address; set this for a real install
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`BONDSMITH_DEV_TUNNEL_TOKEN` also exists but only applies to the legacy direct-connection path
|
|
44
|
+
(`BONDSMITH_RELAY_ENABLED=false`) — should not be set by hand for a normal install.
|
|
45
|
+
|
|
46
|
+
## What it does
|
|
47
|
+
|
|
48
|
+
- Creates, lists, attaches to, and stops tmux sessions prefixed `bondsmith-*`.
|
|
49
|
+
- Never enumerates or manages tmux sessions it didn't create.
|
|
50
|
+
- Attaches a real PTY (`tmux attach-session`) so whatever is running inside (`claude`, `opencode`,
|
|
51
|
+
`bash`, anything) behaves exactly as it would in a normal terminal.
|
|
52
|
+
- Keeps tmux itself as the only source of truth — no database. Restarting the daemon rediscovers
|
|
53
|
+
running sessions from tmux.
|
|
54
|
+
|
|
55
|
+
## Production connectivity (current status)
|
|
56
|
+
|
|
57
|
+
`bondsmithd` connects outbound to the Bondsmith relay by default (`BONDSMITH_RELAY_ENABLED=true`),
|
|
58
|
+
which is what a production account actually uses — no dev-tunnel token involved. Point
|
|
59
|
+
`BONDSMITH_RELAY_URL` at `wss://relay.bondsmith.dev` for a real install (see "Environment
|
|
60
|
+
variables" above); it defaults to a local-only address for monorepo development.
|
|
61
|
+
|
|
62
|
+
The dev-tunnel-token requirement only applies to the legacy direct-connection path
|
|
63
|
+
(`BONDSMITH_RELAY_ENABLED=false`), which still 404s the token-handoff route in production by
|
|
64
|
+
design — that path is for local debugging only, not a real install.
|
|
65
|
+
|
|
66
|
+
## Security model
|
|
67
|
+
|
|
68
|
+
- Every connection is validated against the daemon's `ALLOWED_ORIGINS` and completes a
|
|
69
|
+
cryptographic handshake — a fresh, single-use, daemon-issued challenge signed by a controller key
|
|
70
|
+
the daemon has explicitly and locally trusted. See "Pairing" above for how a controller key
|
|
71
|
+
becomes trusted in the first place.
|
|
72
|
+
- Every sensitive command AND every sensitive read (session listing, workspace status, diffs, plus
|
|
73
|
+
every state-changing action) must arrive as part of that same authenticated, signed connection —
|
|
74
|
+
read access is not treated as lower-risk than write access, since a read can expose session
|
|
75
|
+
metadata and source code just as much as a write can change it.
|
|
76
|
+
- Replay protection is connection-scoped and lives entirely in the daemon's memory — nothing about
|
|
77
|
+
it is persisted to disk, so a browser reload or reconnect always starts a clean, independent
|
|
78
|
+
session.
|
|
79
|
+
- Revoking trust for a controller (from your Bondsmith account) closes its active connections
|
|
80
|
+
within a bounded time, whether or not it's mid-session.
|
|
81
|
+
- Only ever touches tmux sessions it created itself, named `bondsmith-<uuid>`.
|
|
82
|
+
- All tmux/PTY invocations use argv arrays, never shell string interpolation.
|
|
83
|
+
- PTY/terminal contents are never logged or persisted by the daemon itself.
|
|
84
|
+
- This is not a confidentiality boundary against a compromised network path between your machine
|
|
85
|
+
and Bondsmith Cloud — the design assumes source, protocol behavior, and the daemon binary itself
|
|
86
|
+
are fully observable by an attacker, and derives its guarantees from cryptographic signing and
|
|
87
|
+
local trust decisions, never from secrecy of the code. The dev-tunnel admission token described
|
|
88
|
+
under "Production connectivity" above is the one exception (a genuine shared-secret mechanism),
|
|
89
|
+
but it only applies to the legacy direct-connection path, not the relay path a real install uses.
|
|
90
|
+
|
|
91
|
+
Full design detail: `docs/architecture/local-sessions-auth-decision-log.md` in the
|
|
92
|
+
[bondsmith repository](https://github.com/ellis-river-ventures/bondsmith).
|
|
93
|
+
|
|
94
|
+
## Contributing / developing bondsmithd itself
|
|
95
|
+
|
|
96
|
+
This section is for people working in the `bondsmith` monorepo, not for installed users of the
|
|
97
|
+
published package.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pnpm --filter @bondsmith/bondsmithd dev
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This is deliberately **not** part of `pnpm dev` / `turbo dev` — it needs tmux and a native module
|
|
104
|
+
on the host, and it's opt-in tooling, not a service the rest of the stack depends on.
|
|
105
|
+
|
|
106
|
+
**node-pty is pinned to `1.2.0-beta.15`, not the `1.1.0` stable release.** `1.1.0`'s prebuilt
|
|
107
|
+
`darwin-arm64` binary fails immediately with `posix_spawnp failed` on Node 24 (verified on macOS
|
|
108
|
+
15/Apple Silicon) — any spawn, not just tmux, crashes the whole daemon process. The `1.2.0-beta`
|
|
109
|
+
line has a prebuild that works correctly on Node 24. Don't downgrade to a `node-pty` stable release
|
|
110
|
+
without first confirming `pty.spawn(...)` actually works on your Node version.
|
|
111
|
+
|
|
112
|
+
For local development, create a `.env` file in this directory (or export the vars directly):
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
PORT=4577
|
|
116
|
+
ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,http://localhost:4000,http://127.0.0.1:4000
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Port 4000 is included because that's where `make dev`'s Docker Compose stack serves the web app
|
|
120
|
+
(`docker-compose.dev.yml` maps `4000:4000`); port 3000 covers running `apps/web` directly via
|
|
121
|
+
`pnpm dev:web` instead.
|
|
122
|
+
|
|
123
|
+
The web app needs `NEXT_PUBLIC_LOCAL_AGENT_DAEMON_URL=ws://127.0.0.1:4577` set wherever it reads
|
|
124
|
+
its env from — under `make dev` that's the repo-root `.env.local` (referenced by
|
|
125
|
+
`docker-compose.dev.yml`'s `env_file`), not `apps/web/.env.local`.
|
|
126
|
+
|
|
127
|
+
### Publishing
|
|
128
|
+
|
|
129
|
+
`pnpm --filter @bondsmith/bondsmithd build` bundles `@bondsmith/local-agent-protocol` directly into
|
|
130
|
+
`dist/index.js` (see `tsup.config.ts`'s `noExternal`) — the published package has no `workspace:*`
|
|
131
|
+
dependency and no runtime dependency on that package existing on any registry. Only `dist/index.js`,
|
|
132
|
+
`package.json`, and this README are published (see `package.json`'s `files`); sourcemaps and every
|
|
133
|
+
other repo file are excluded.
|
|
134
|
+
|
|
135
|
+
### Non-goals (current scope)
|
|
136
|
+
|
|
137
|
+
No cloud execution, no multi-machine support, no session sharing, no Claude/OpenCode API
|
|
138
|
+
integration, no agent-output parsing or detection, no terminal history storage or session
|
|
139
|
+
recording.
|