nazar-bridge 0.1.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.
- nazar_bridge-0.1.0/LICENSE +21 -0
- nazar_bridge-0.1.0/PKG-INFO +240 -0
- nazar_bridge-0.1.0/README.md +207 -0
- nazar_bridge-0.1.0/nazar_bridge/__init__.py +21 -0
- nazar_bridge-0.1.0/nazar_bridge/__main__.py +13 -0
- nazar_bridge-0.1.0/nazar_bridge/claude_runner.py +534 -0
- nazar_bridge-0.1.0/nazar_bridge/cli.py +595 -0
- nazar_bridge-0.1.0/nazar_bridge/client.py +213 -0
- nazar_bridge-0.1.0/nazar_bridge/config.py +286 -0
- nazar_bridge-0.1.0/nazar_bridge/desk.py +328 -0
- nazar_bridge-0.1.0/nazar_bridge/exceptions.py +68 -0
- nazar_bridge-0.1.0/nazar_bridge/py.typed +0 -0
- nazar_bridge-0.1.0/nazar_bridge/runner.py +609 -0
- nazar_bridge-0.1.0/nazar_bridge/service.py +356 -0
- nazar_bridge-0.1.0/nazar_bridge/wire.py +170 -0
- nazar_bridge-0.1.0/nazar_bridge.egg-info/PKG-INFO +240 -0
- nazar_bridge-0.1.0/nazar_bridge.egg-info/SOURCES.txt +29 -0
- nazar_bridge-0.1.0/nazar_bridge.egg-info/dependency_links.txt +1 -0
- nazar_bridge-0.1.0/nazar_bridge.egg-info/entry_points.txt +2 -0
- nazar_bridge-0.1.0/nazar_bridge.egg-info/requires.txt +8 -0
- nazar_bridge-0.1.0/nazar_bridge.egg-info/top_level.txt +1 -0
- nazar_bridge-0.1.0/pyproject.toml +103 -0
- nazar_bridge-0.1.0/setup.cfg +4 -0
- nazar_bridge-0.1.0/tests/test_claude_runner.py +417 -0
- nazar_bridge-0.1.0/tests/test_cli.py +643 -0
- nazar_bridge-0.1.0/tests/test_client_handshake.py +147 -0
- nazar_bridge-0.1.0/tests/test_config.py +135 -0
- nazar_bridge-0.1.0/tests/test_desk.py +200 -0
- nazar_bridge-0.1.0/tests/test_runner_loop.py +832 -0
- nazar_bridge-0.1.0/tests/test_service.py +78 -0
- nazar_bridge-0.1.0/tests/test_wire.py +53 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nazar-bridge
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Nazar bridge daemon — relays phone prompts to local `claude -p` over a long-lived WebSocket.
|
|
5
|
+
Author: Arman
|
|
6
|
+
Maintainer: Arman
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/arm-yan/nazar
|
|
9
|
+
Project-URL: Repository, https://github.com/arm-yan/nazar
|
|
10
|
+
Project-URL: Issues, https://github.com/arm-yan/nazar/issues
|
|
11
|
+
Keywords: nazar,claude,claude-code,daemon,websocket,bridge,ai-assistant,remote-control
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
20
|
+
Classifier: Topic :: Utilities
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.12
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: websockets<17,>=15
|
|
26
|
+
Requires-Dist: pydantic<3,>=2
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest==9.0.3; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-asyncio==1.3.0; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff==0.15.12; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy==2.1.0; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# nazar-bridge
|
|
35
|
+
|
|
36
|
+
`nazar-bridge` is a small, open-source daemon that lets you drive
|
|
37
|
+
[Claude Code](https://claude.com/claude-code) on your own machine from the
|
|
38
|
+
[Nazar](https://github.com/arm-yan/nazar) phone dashboard.
|
|
39
|
+
|
|
40
|
+
It holds a single long-lived **outbound** WebSocket connection to the Nazar
|
|
41
|
+
API, registers your local Claude-Code project directories, and — when you send
|
|
42
|
+
a prompt from your phone — spawns `claude -p` in the matching project and
|
|
43
|
+
streams the output back. Nothing listens for inbound connections on your
|
|
44
|
+
machine; the daemon dials out, so there are no ports to open.
|
|
45
|
+
|
|
46
|
+
The source is intentionally small and auditable — read it before you install
|
|
47
|
+
it. That's the whole trust model (see [Trust & supply chain](#trust--supply-chain)).
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Prerequisites
|
|
52
|
+
|
|
53
|
+
- **Python 3.12+** on your machine.
|
|
54
|
+
- **[Claude Code](https://claude.com/claude-code) installed and authenticated.**
|
|
55
|
+
The daemon shells out to the `claude` CLI using *your* logged-in session, so
|
|
56
|
+
`claude` must be on your `PATH` and already signed in.
|
|
57
|
+
- **A Nazar account on a Pro or Unlimited plan.** The bridge is a paid-tier
|
|
58
|
+
feature — **the Free plan has no bridge** and cannot mint daemon tokens.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
Recommended (isolated tool install via [uv](https://docs.astral.sh/uv/)):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
uv tool install nazar-bridge
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Alternative (via [pipx](https://pipx.pypa.io/)):
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pipx install nazar-bridge
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Upgrade later:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
uv tool upgrade nazar-bridge # or: pipx upgrade nazar-bridge
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Both put a `nazar-bridge` command on your `PATH`.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Connect
|
|
87
|
+
|
|
88
|
+
1. **Get a daemon token.** In the Nazar dashboard, open **/code → Bridge
|
|
89
|
+
tokens** and create one. It looks like `nazar_bridge_xxxxxxxxxxxxxxxx`.
|
|
90
|
+
Copy it now — it's shown only once.
|
|
91
|
+
|
|
92
|
+
2. **Configure the daemon** with the token (and, if your API host differs from
|
|
93
|
+
the default, the WebSocket URL):
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
nazar-bridge configure --token nazar_bridge_xxxxxxxxxxxxxxxx
|
|
97
|
+
# to point at a self-hosted / dev API instead of the default:
|
|
98
|
+
nazar-bridge configure --token nazar_bridge_xxxx --api-url wss://your-host/api/bridge/ws
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
3. **Register the project directories** you want reachable from your phone:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
nazar-bridge add /path/to/your/project
|
|
105
|
+
nazar-bridge add /path/to/another/project
|
|
106
|
+
nazar-bridge list
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
4. **Run it.** Either start it once in a terminal:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
nazar-bridge run # add --debug for verbose logs
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
…or install it as a login autostart service (recommended — see below) so it
|
|
116
|
+
reconnects automatically after a reboot.
|
|
117
|
+
|
|
118
|
+
`run --once` exits right after the first successful register — handy for
|
|
119
|
+
smoke-testing a freshly-configured daemon.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Autostart at login (recommended)
|
|
124
|
+
|
|
125
|
+
Instead of leaving a terminal open, register the daemon to start at login and
|
|
126
|
+
restart on failure. One cross-platform command detects your OS and writes the
|
|
127
|
+
right unit:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
nazar-bridge service install # Windows / macOS / Linux
|
|
131
|
+
nazar-bridge service status # is it installed / running?
|
|
132
|
+
nazar-bridge service uninstall # remove it
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
| OS | What `service install` creates |
|
|
136
|
+
| ------- | ------------------------------------------------------------------------- |
|
|
137
|
+
| Windows | A Task Scheduler task **"Nazar Bridge"** that runs at logon (windowless). |
|
|
138
|
+
| macOS | A launchd LaunchAgent `app.nazar.bridge` in `~/Library/LaunchAgents`. |
|
|
139
|
+
| Linux | A systemd `--user` unit `nazar-bridge.service` (enabled + started). |
|
|
140
|
+
|
|
141
|
+
The service always runs **as your own user** (never root/SYSTEM) because the
|
|
142
|
+
daemon spawns `claude` with your personal Claude Code login — `service install`
|
|
143
|
+
refuses to run as root. On Linux, run `loginctl enable-linger $USER` if you
|
|
144
|
+
want the daemon up even when you're not logged in interactively.
|
|
145
|
+
|
|
146
|
+
Logs go to the daemon's rotating log file (see below) regardless of how it's
|
|
147
|
+
started. For live debugging, run `nazar-bridge run` in a terminal to watch
|
|
148
|
+
output directly.
|
|
149
|
+
|
|
150
|
+
> **Windows note:** earlier releases shipped
|
|
151
|
+
> `scripts/install-windows-startup.ps1`. That script still works and adds a
|
|
152
|
+
> richer restart policy, but `nazar-bridge service install` is now the
|
|
153
|
+
> recommended, cross-platform path.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Where config & logs live
|
|
158
|
+
|
|
159
|
+
| OS | Config file | Daemon log |
|
|
160
|
+
| ------- | ---------------------------------------------------- | --------------------------- |
|
|
161
|
+
| Windows | `%APPDATA%\nazar-bridge\config.toml` | `%APPDATA%\nazar-bridge\daemon.log` |
|
|
162
|
+
| macOS | `~/.config/nazar-bridge/config.toml` | `~/.config/nazar-bridge/daemon.log` |
|
|
163
|
+
| Linux | `$XDG_CONFIG_HOME/nazar-bridge/config.toml` or | `…/nazar-bridge/daemon.log` |
|
|
164
|
+
| | `~/.config/nazar-bridge/config.toml` | |
|
|
165
|
+
|
|
166
|
+
The token is stored **plaintext** in `config.toml` — it's the daemon's only
|
|
167
|
+
credential. Protect it with filesystem permissions:
|
|
168
|
+
|
|
169
|
+
- **Windows:** `icacls "%APPDATA%\nazar-bridge\config.toml" /inheritance:r /grant:r "%USERNAME%:F"`
|
|
170
|
+
- **macOS / Linux:** `chmod 600 ~/.config/nazar-bridge/config.toml`
|
|
171
|
+
|
|
172
|
+
Rotating the token is two commands: `nazar-bridge configure --force --token <new>`
|
|
173
|
+
(your project list is preserved).
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Trust & supply chain
|
|
178
|
+
|
|
179
|
+
The bridge runs on your machine and runs Claude Code with full permissions, so
|
|
180
|
+
its trustworthiness matters. The design keeps that auditable:
|
|
181
|
+
|
|
182
|
+
- **Open source.** Every line is on GitHub:
|
|
183
|
+
[arm-yan/nazar](https://github.com/arm-yan/nazar) under `apps/bridge`. Read it
|
|
184
|
+
before installing.
|
|
185
|
+
- **Published from PyPI, not a private host.** `uv tool install nazar-bridge`
|
|
186
|
+
pulls the package and its only two runtime dependencies (`websockets`,
|
|
187
|
+
`pydantic`) from PyPI. Nothing is downloaded from a private or vendor server.
|
|
188
|
+
- **Signed provenance.** Releases are published to PyPI via GitHub Actions
|
|
189
|
+
**Trusted Publishing (OIDC)** with attestations — no long-lived upload token
|
|
190
|
+
exists, and each artifact carries signed build provenance you can verify back
|
|
191
|
+
to the tagged commit.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Security model
|
|
196
|
+
|
|
197
|
+
Be deliberate about what this daemon does:
|
|
198
|
+
|
|
199
|
+
- When a prompt arrives from your authenticated Nazar dashboard, the daemon
|
|
200
|
+
spawns Claude Code **with `--dangerously-skip-permissions`** — Claude can read,
|
|
201
|
+
write, and run commands in the registered project directory without per-action
|
|
202
|
+
prompts. This is intentional: it's *your* machine, *your* Claude login, and
|
|
203
|
+
*your* token, and the point of the bridge is hands-off remote execution.
|
|
204
|
+
- The **trust boundary is your daemon token plus your single-user host.** Anyone
|
|
205
|
+
who holds the token can drive Claude on your machine through the Nazar API.
|
|
206
|
+
Treat the token like an SSH key: keep `config.toml` locked down, and
|
|
207
|
+
rotate/revoke the token (from the dashboard) if it leaks.
|
|
208
|
+
- The daemon only ever makes an **outbound** WebSocket connection — it opens no
|
|
209
|
+
listening port on your machine.
|
|
210
|
+
|
|
211
|
+
If that posture isn't acceptable for a given machine, don't install the bridge
|
|
212
|
+
there.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Wire protocol
|
|
217
|
+
|
|
218
|
+
The daemon and API speak JSON text frames over the WebSocket. The source of
|
|
219
|
+
truth for the schemas is `apps/api/nazar_api/schemas/bridge.py`; the daemon's
|
|
220
|
+
`nazar_bridge/wire.py` mirrors the relevant subset so the daemon stays
|
|
221
|
+
installable independently of the API package.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Develop / test
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
cd apps/bridge
|
|
229
|
+
python -m pip install -e ".[dev]"
|
|
230
|
+
pytest
|
|
231
|
+
ruff check nazar_bridge tests
|
|
232
|
+
mypy nazar_bridge
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Build the distributables locally:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
python -m build # produces dist/*.whl and dist/*.tar.gz
|
|
239
|
+
twine check dist/*
|
|
240
|
+
```
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# nazar-bridge
|
|
2
|
+
|
|
3
|
+
`nazar-bridge` is a small, open-source daemon that lets you drive
|
|
4
|
+
[Claude Code](https://claude.com/claude-code) on your own machine from the
|
|
5
|
+
[Nazar](https://github.com/arm-yan/nazar) phone dashboard.
|
|
6
|
+
|
|
7
|
+
It holds a single long-lived **outbound** WebSocket connection to the Nazar
|
|
8
|
+
API, registers your local Claude-Code project directories, and — when you send
|
|
9
|
+
a prompt from your phone — spawns `claude -p` in the matching project and
|
|
10
|
+
streams the output back. Nothing listens for inbound connections on your
|
|
11
|
+
machine; the daemon dials out, so there are no ports to open.
|
|
12
|
+
|
|
13
|
+
The source is intentionally small and auditable — read it before you install
|
|
14
|
+
it. That's the whole trust model (see [Trust & supply chain](#trust--supply-chain)).
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
- **Python 3.12+** on your machine.
|
|
21
|
+
- **[Claude Code](https://claude.com/claude-code) installed and authenticated.**
|
|
22
|
+
The daemon shells out to the `claude` CLI using *your* logged-in session, so
|
|
23
|
+
`claude` must be on your `PATH` and already signed in.
|
|
24
|
+
- **A Nazar account on a Pro or Unlimited plan.** The bridge is a paid-tier
|
|
25
|
+
feature — **the Free plan has no bridge** and cannot mint daemon tokens.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
Recommended (isolated tool install via [uv](https://docs.astral.sh/uv/)):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
uv tool install nazar-bridge
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Alternative (via [pipx](https://pipx.pypa.io/)):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pipx install nazar-bridge
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Upgrade later:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv tool upgrade nazar-bridge # or: pipx upgrade nazar-bridge
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Both put a `nazar-bridge` command on your `PATH`.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Connect
|
|
54
|
+
|
|
55
|
+
1. **Get a daemon token.** In the Nazar dashboard, open **/code → Bridge
|
|
56
|
+
tokens** and create one. It looks like `nazar_bridge_xxxxxxxxxxxxxxxx`.
|
|
57
|
+
Copy it now — it's shown only once.
|
|
58
|
+
|
|
59
|
+
2. **Configure the daemon** with the token (and, if your API host differs from
|
|
60
|
+
the default, the WebSocket URL):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
nazar-bridge configure --token nazar_bridge_xxxxxxxxxxxxxxxx
|
|
64
|
+
# to point at a self-hosted / dev API instead of the default:
|
|
65
|
+
nazar-bridge configure --token nazar_bridge_xxxx --api-url wss://your-host/api/bridge/ws
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
3. **Register the project directories** you want reachable from your phone:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
nazar-bridge add /path/to/your/project
|
|
72
|
+
nazar-bridge add /path/to/another/project
|
|
73
|
+
nazar-bridge list
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
4. **Run it.** Either start it once in a terminal:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
nazar-bridge run # add --debug for verbose logs
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
…or install it as a login autostart service (recommended — see below) so it
|
|
83
|
+
reconnects automatically after a reboot.
|
|
84
|
+
|
|
85
|
+
`run --once` exits right after the first successful register — handy for
|
|
86
|
+
smoke-testing a freshly-configured daemon.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Autostart at login (recommended)
|
|
91
|
+
|
|
92
|
+
Instead of leaving a terminal open, register the daemon to start at login and
|
|
93
|
+
restart on failure. One cross-platform command detects your OS and writes the
|
|
94
|
+
right unit:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
nazar-bridge service install # Windows / macOS / Linux
|
|
98
|
+
nazar-bridge service status # is it installed / running?
|
|
99
|
+
nazar-bridge service uninstall # remove it
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
| OS | What `service install` creates |
|
|
103
|
+
| ------- | ------------------------------------------------------------------------- |
|
|
104
|
+
| Windows | A Task Scheduler task **"Nazar Bridge"** that runs at logon (windowless). |
|
|
105
|
+
| macOS | A launchd LaunchAgent `app.nazar.bridge` in `~/Library/LaunchAgents`. |
|
|
106
|
+
| Linux | A systemd `--user` unit `nazar-bridge.service` (enabled + started). |
|
|
107
|
+
|
|
108
|
+
The service always runs **as your own user** (never root/SYSTEM) because the
|
|
109
|
+
daemon spawns `claude` with your personal Claude Code login — `service install`
|
|
110
|
+
refuses to run as root. On Linux, run `loginctl enable-linger $USER` if you
|
|
111
|
+
want the daemon up even when you're not logged in interactively.
|
|
112
|
+
|
|
113
|
+
Logs go to the daemon's rotating log file (see below) regardless of how it's
|
|
114
|
+
started. For live debugging, run `nazar-bridge run` in a terminal to watch
|
|
115
|
+
output directly.
|
|
116
|
+
|
|
117
|
+
> **Windows note:** earlier releases shipped
|
|
118
|
+
> `scripts/install-windows-startup.ps1`. That script still works and adds a
|
|
119
|
+
> richer restart policy, but `nazar-bridge service install` is now the
|
|
120
|
+
> recommended, cross-platform path.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Where config & logs live
|
|
125
|
+
|
|
126
|
+
| OS | Config file | Daemon log |
|
|
127
|
+
| ------- | ---------------------------------------------------- | --------------------------- |
|
|
128
|
+
| Windows | `%APPDATA%\nazar-bridge\config.toml` | `%APPDATA%\nazar-bridge\daemon.log` |
|
|
129
|
+
| macOS | `~/.config/nazar-bridge/config.toml` | `~/.config/nazar-bridge/daemon.log` |
|
|
130
|
+
| Linux | `$XDG_CONFIG_HOME/nazar-bridge/config.toml` or | `…/nazar-bridge/daemon.log` |
|
|
131
|
+
| | `~/.config/nazar-bridge/config.toml` | |
|
|
132
|
+
|
|
133
|
+
The token is stored **plaintext** in `config.toml` — it's the daemon's only
|
|
134
|
+
credential. Protect it with filesystem permissions:
|
|
135
|
+
|
|
136
|
+
- **Windows:** `icacls "%APPDATA%\nazar-bridge\config.toml" /inheritance:r /grant:r "%USERNAME%:F"`
|
|
137
|
+
- **macOS / Linux:** `chmod 600 ~/.config/nazar-bridge/config.toml`
|
|
138
|
+
|
|
139
|
+
Rotating the token is two commands: `nazar-bridge configure --force --token <new>`
|
|
140
|
+
(your project list is preserved).
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Trust & supply chain
|
|
145
|
+
|
|
146
|
+
The bridge runs on your machine and runs Claude Code with full permissions, so
|
|
147
|
+
its trustworthiness matters. The design keeps that auditable:
|
|
148
|
+
|
|
149
|
+
- **Open source.** Every line is on GitHub:
|
|
150
|
+
[arm-yan/nazar](https://github.com/arm-yan/nazar) under `apps/bridge`. Read it
|
|
151
|
+
before installing.
|
|
152
|
+
- **Published from PyPI, not a private host.** `uv tool install nazar-bridge`
|
|
153
|
+
pulls the package and its only two runtime dependencies (`websockets`,
|
|
154
|
+
`pydantic`) from PyPI. Nothing is downloaded from a private or vendor server.
|
|
155
|
+
- **Signed provenance.** Releases are published to PyPI via GitHub Actions
|
|
156
|
+
**Trusted Publishing (OIDC)** with attestations — no long-lived upload token
|
|
157
|
+
exists, and each artifact carries signed build provenance you can verify back
|
|
158
|
+
to the tagged commit.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Security model
|
|
163
|
+
|
|
164
|
+
Be deliberate about what this daemon does:
|
|
165
|
+
|
|
166
|
+
- When a prompt arrives from your authenticated Nazar dashboard, the daemon
|
|
167
|
+
spawns Claude Code **with `--dangerously-skip-permissions`** — Claude can read,
|
|
168
|
+
write, and run commands in the registered project directory without per-action
|
|
169
|
+
prompts. This is intentional: it's *your* machine, *your* Claude login, and
|
|
170
|
+
*your* token, and the point of the bridge is hands-off remote execution.
|
|
171
|
+
- The **trust boundary is your daemon token plus your single-user host.** Anyone
|
|
172
|
+
who holds the token can drive Claude on your machine through the Nazar API.
|
|
173
|
+
Treat the token like an SSH key: keep `config.toml` locked down, and
|
|
174
|
+
rotate/revoke the token (from the dashboard) if it leaks.
|
|
175
|
+
- The daemon only ever makes an **outbound** WebSocket connection — it opens no
|
|
176
|
+
listening port on your machine.
|
|
177
|
+
|
|
178
|
+
If that posture isn't acceptable for a given machine, don't install the bridge
|
|
179
|
+
there.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Wire protocol
|
|
184
|
+
|
|
185
|
+
The daemon and API speak JSON text frames over the WebSocket. The source of
|
|
186
|
+
truth for the schemas is `apps/api/nazar_api/schemas/bridge.py`; the daemon's
|
|
187
|
+
`nazar_bridge/wire.py` mirrors the relevant subset so the daemon stays
|
|
188
|
+
installable independently of the API package.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Develop / test
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
cd apps/bridge
|
|
196
|
+
python -m pip install -e ".[dev]"
|
|
197
|
+
pytest
|
|
198
|
+
ruff check nazar_bridge tests
|
|
199
|
+
mypy nazar_bridge
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Build the distributables locally:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
python -m build # produces dist/*.whl and dist/*.tar.gz
|
|
206
|
+
twine check dist/*
|
|
207
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""nazar-bridge — daemon that relays phone-prompts to local ``claude -p``.
|
|
2
|
+
|
|
3
|
+
The daemon maintains a persistent outbound WebSocket connection to the
|
|
4
|
+
Nazar API, registers the founder's local Claude Code project
|
|
5
|
+
directories, and (in a follow-up ticket #26) shells out to
|
|
6
|
+
``claude -p`` to execute prompts pushed from the dashboard.
|
|
7
|
+
|
|
8
|
+
This module is intentionally tiny — every concern is split into a
|
|
9
|
+
dedicated submodule:
|
|
10
|
+
|
|
11
|
+
* :mod:`nazar_bridge.config` — TOML config file load/save.
|
|
12
|
+
* :mod:`nazar_bridge.client` — async WebSocket client + reconnect.
|
|
13
|
+
* :mod:`nazar_bridge.runner` — long-running ``run()`` entrypoint.
|
|
14
|
+
* :mod:`nazar_bridge.cli` — argparse-based console script.
|
|
15
|
+
* :mod:`nazar_bridge.wire` — Pydantic wire-protocol schemas.
|
|
16
|
+
* :mod:`nazar_bridge.exceptions` — typed errors surfaced to the CLI.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Allow ``python -m nazar_bridge`` as an equivalent to the console script.
|
|
2
|
+
|
|
3
|
+
Useful when the package is installed but the ``nazar-bridge`` script
|
|
4
|
+
isn't on the ``PATH`` (e.g. a venv that's been activated by absolute
|
|
5
|
+
``python`` path).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from nazar_bridge.cli import main
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
raise SystemExit(main())
|