agnview 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.
Files changed (52) hide show
  1. agnview-0.1.0/LICENSE +21 -0
  2. agnview-0.1.0/PKG-INFO +246 -0
  3. agnview-0.1.0/README.md +208 -0
  4. agnview-0.1.0/agent_relay/__init__.py +3 -0
  5. agnview-0.1.0/agent_relay/api/app.py +161 -0
  6. agnview-0.1.0/agent_relay/api/routes.py +1361 -0
  7. agnview-0.1.0/agent_relay/cli/main.py +888 -0
  8. agnview-0.1.0/agent_relay/core/adapters.py +252 -0
  9. agnview-0.1.0/agent_relay/core/certs.py +90 -0
  10. agnview-0.1.0/agent_relay/core/config.py +166 -0
  11. agnview-0.1.0/agent_relay/core/db.py +437 -0
  12. agnview-0.1.0/agent_relay/core/engine.py +665 -0
  13. agnview-0.1.0/agent_relay/core/iroh_transport.py +391 -0
  14. agnview-0.1.0/agent_relay/core/models.py +314 -0
  15. agnview-0.1.0/agent_relay/core/network.py +273 -0
  16. agnview-0.1.0/agent_relay/core/notifications.py +365 -0
  17. agnview-0.1.0/agent_relay/core/pairing.py +275 -0
  18. agnview-0.1.0/agent_relay/core/prompts.py +101 -0
  19. agnview-0.1.0/agent_relay/core/runner.py +538 -0
  20. agnview-0.1.0/agent_relay/core/usage_fetcher.py +526 -0
  21. agnview-0.1.0/agent_relay/mcp/server.py +223 -0
  22. agnview-0.1.0/agnview.egg-info/PKG-INFO +246 -0
  23. agnview-0.1.0/agnview.egg-info/SOURCES.txt +50 -0
  24. agnview-0.1.0/agnview.egg-info/dependency_links.txt +1 -0
  25. agnview-0.1.0/agnview.egg-info/entry_points.txt +3 -0
  26. agnview-0.1.0/agnview.egg-info/requires.txt +13 -0
  27. agnview-0.1.0/agnview.egg-info/top_level.txt +1 -0
  28. agnview-0.1.0/pyproject.toml +62 -0
  29. agnview-0.1.0/setup.cfg +4 -0
  30. agnview-0.1.0/tests/test_adapters.py +106 -0
  31. agnview-0.1.0/tests/test_api.py +198 -0
  32. agnview-0.1.0/tests/test_cli.py +124 -0
  33. agnview-0.1.0/tests/test_config.py +123 -0
  34. agnview-0.1.0/tests/test_console_buffer.py +56 -0
  35. agnview-0.1.0/tests/test_custom_providers.py +190 -0
  36. agnview-0.1.0/tests/test_engine.py +136 -0
  37. agnview-0.1.0/tests/test_events.py +76 -0
  38. agnview-0.1.0/tests/test_failure.py +67 -0
  39. agnview-0.1.0/tests/test_fixlist.py +69 -0
  40. agnview-0.1.0/tests/test_html_syntax.py +31 -0
  41. agnview-0.1.0/tests/test_iroh_invisible.py +59 -0
  42. agnview-0.1.0/tests/test_iroh_transport.py +145 -0
  43. agnview-0.1.0/tests/test_job_validation.py +79 -0
  44. agnview-0.1.0/tests/test_mobile.py +107 -0
  45. agnview-0.1.0/tests/test_no_monetisation.py +69 -0
  46. agnview-0.1.0/tests/test_notifications.py +257 -0
  47. agnview-0.1.0/tests/test_pairing_payload.py +115 -0
  48. agnview-0.1.0/tests/test_runner.py +72 -0
  49. agnview-0.1.0/tests/test_spec_matches_server.py +62 -0
  50. agnview-0.1.0/tests/test_transport_route.py +83 -0
  51. agnview-0.1.0/tests/test_usage.py +170 -0
  52. agnview-0.1.0/tests/test_usage_telemetry.py +142 -0
agnview-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Taher Laskar
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.
agnview-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,246 @@
1
+ Metadata-Version: 2.4
2
+ Name: agnview
3
+ Version: 0.1.0
4
+ Summary: One screen for the coding agents already running on your machine.
5
+ Author: tlaskar-git
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/tlaskar-git/AgnView
8
+ Project-URL: Repository, https://github.com/tlaskar-git/AgnView
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Environment :: Web Environment
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Build Tools
20
+ Classifier: Topic :: Software Development :: User Interfaces
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: fastapi==0.141.1
26
+ Requires-Dist: uvicorn[standard]==0.52.4
27
+ Requires-Dist: pydantic==2.13.5
28
+ Requires-Dist: pyyaml==6.0.3
29
+ Requires-Dist: httpx==0.28.1
30
+ Requires-Dist: rich==15.0.0
31
+ Requires-Dist: sse-starlette==3.4.11
32
+ Requires-Dist: qrcode==8.2
33
+ Requires-Dist: iroh==1.1.0
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest==9.1.1; extra == "dev"
36
+ Requires-Dist: ruff==0.15.4; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ <div align="center">
40
+ <img src="docs/agnview_logo.png" alt="AgnView" width="140" />
41
+ <h1>AgnView</h1>
42
+ <p><strong>One screen for the coding agents already running on your machine.</strong></p>
43
+ </div>
44
+
45
+ ---
46
+
47
+ ## What AgnView is
48
+
49
+ AgnView is a local dashboard and coordination hub for the agent CLIs you have
50
+ installed: Claude Code, Codex, AntiGravity, DeepSeek, and any local model you
51
+ run yourself. There are five known agent roles a task can be assigned to:
52
+ `claude_code`, `codex`, `antigravity`, `deepseek` and `custom`. It does three
53
+ things.
54
+
55
+ **Watch.** Every agent's output streams into one console, colour-coded by
56
+ agent, instead of being scattered across terminal tabs.
57
+
58
+ **Coordinate.** Describe a job as a set of tasks with dependencies. A task
59
+ stays blocked until the tasks it depends on complete, and when it starts, the
60
+ agent picks it up with the upstream summaries and artefacts attached. If one
61
+ agent finds a defect in another's work, it can send the task back for revision,
62
+ or mark it failed, which blocks everything downstream.
63
+
64
+ **Keep an eye on quotas.** Session and weekly limits for your Claude, ChatGPT
65
+ and Gemini subscriptions, in one place.
66
+
67
+ AgnView runs entirely on your own machine. It is free, and there is nothing to
68
+ sign up for.
69
+
70
+ ## Screenshots
71
+
72
+ | | Light | Dark |
73
+ |---|---|---|
74
+ | **Console** | ![Console, light](docs/screenshots/console-light.png) | ![Console, dark](docs/screenshots/console-dark.png) |
75
+ | **Pipelines** | ![Pipelines, light](docs/screenshots/pipelines-light.png) | ![Pipelines, dark](docs/screenshots/pipelines-dark.png) |
76
+ | **Usage** | ![Usage, light](docs/screenshots/usage-light.png) | ![Usage, dark](docs/screenshots/usage-dark.png) |
77
+
78
+ ## Supported platforms
79
+
80
+ | | |
81
+ |---|---|
82
+ | Windows | 10 and 11 |
83
+ | macOS | 12 Monterey and later, Intel and Apple silicon |
84
+ | Linux | any distribution with Python 3.10 or newer |
85
+ | Python | 3.10 or newer |
86
+ | Browser | any current Chrome, Edge, Firefox or Safari |
87
+
88
+ The companion mobile client is iOS and iPadOS.
89
+
90
+ ## Clients
91
+
92
+ The AgnView hub in this repo covers Windows, macOS and Linux.
93
+
94
+ - **iOS and iPadOS**: [github.com/tlaskar-git/AgnView-iOS](https://github.com/tlaskar-git/AgnView-iOS)
95
+ holds the design prototype and mobile spec for the iOS and iPadOS client.
96
+ - **Android**: an Android client will live at
97
+ [github.com/tlaskar-git/AgnView-Android](https://github.com/tlaskar-git/AgnView-Android)
98
+ (reference only, not yet created).
99
+
100
+ AgnView does not install any coding agent for you. It watches and dispatches to
101
+ the CLIs already on your machine: Claude Code, Codex, AntiGravity or any other
102
+ tool you add as an adapter. Install the CLIs you want to use yourself, before
103
+ or after installing AgnView.
104
+
105
+ ## Install
106
+
107
+ The quickest way is not to install at all. [uv](https://docs.astral.sh/uv/)
108
+ fetches and runs AgnView in one command, with no clone and no virtualenv:
109
+
110
+ ```bash
111
+ uvx agnview serve
112
+ ```
113
+
114
+ To keep it around permanently:
115
+
116
+ ```bash
117
+ uv tool install agnview # or: pipx install agnview / pip install agnview
118
+ ```
119
+
120
+ Working on AgnView itself? Install from source:
121
+
122
+ ```bash
123
+ git clone https://github.com/tlaskar-git/AgnView.git
124
+ cd AgnView
125
+ pip install -e .
126
+ ```
127
+
128
+ `agent-relay` is supported as an alias for the `agnview` command.
129
+
130
+ ## Start
131
+
132
+ ```bash
133
+ agnview serve
134
+ ```
135
+
136
+ The dashboard is then at <http://127.0.0.1:8765>.
137
+
138
+ By default AgnView binds `127.0.0.1`, so only your own machine can reach it. To
139
+ let your phone or another computer on the same network connect, opt in
140
+ explicitly:
141
+
142
+ ```bash
143
+ agnview serve --listen-lan
144
+ ```
145
+
146
+ Choose a different port with `--port`, and require a token from connecting
147
+ clients with `--token`.
148
+
149
+ ## Pair a phone
150
+
151
+ 1. Start the hub with `agnview serve --listen-lan`.
152
+ 2. Open the dashboard and choose the mobile option in the header to show the
153
+ pairing QR code.
154
+ 3. Scan it with the AgnView app on a device on the same network.
155
+
156
+ The QR code carries the hub's LAN address, its certificate fingerprint, and a
157
+ pairing key. Regenerating the code invalidates every device already paired.
158
+ `docs/PAIRING.md` is the full contract.
159
+
160
+ **Treat the pairing QR code like a password.** Anyone who can read it can reach
161
+ the hub, and the hub can run commands on this machine. See `SECURITY.md`.
162
+
163
+ ## LAN pairing, plus a remote path if you want it
164
+
165
+ On your own local network, your machine and your phone talk to each other
166
+ directly. Nothing goes through anybody else's infrastructure, and no account
167
+ or setup is needed.
168
+
169
+ If your phone is off your home or office Wi-Fi, LAN pairing alone cannot reach
170
+ it. AgnView also accepts connections over iroh, which can carry the pairing QR
171
+ code and the console beyond the LAN without a VPN. See "Remote access" below
172
+ for what that depends on and how to opt out of it.
173
+
174
+ ## Remote access
175
+
176
+ `docs/REMOTE-ACCESS.md` covers every path in order: LAN, bundled iroh, what
177
+ iroh depends on, running your own relay, and the overlay alternatives
178
+ (Tailscale, NetBird, an SSH local port forward, or an existing WireGuard
179
+ tunnel) via `--listen-overlay`.
180
+
181
+ Remote access uses iroh's free public relays. Most connections are direct and never touch a relay. Relayed connections are rate limited and carry no uptime guarantee. You can point AgnView at your own relay in Settings.
182
+
183
+ ## Docker, and what a container cannot do
184
+
185
+ ```bash
186
+ docker compose up -d
187
+ ```
188
+
189
+ The hub is then at <http://localhost:8765>. The image runs as an unprivileged
190
+ `agnview` user and carries a `HEALTHCHECK` against the dashboard root, and the
191
+ compose file keeps `~/.agnview` (pairing token, adapters, notification config)
192
+ in a named volume so it survives rebuilds and restarts.
193
+
194
+ **A containerised hub cannot dispatch to CLI agents.** AgnView dispatches work
195
+ by executing the agent binaries on the host: `claude`, `codex`, `antigravity`
196
+ and the rest, with their own credentials, config and your working tree. A
197
+ container sees none of that.
198
+
199
+ - Docker suits watching and managing a pipeline: the dashboard, the REST and
200
+ SSE API, job and dependency state, web-LLM prompt generation, quota
201
+ monitoring, and mobile pairing, with remote worker daemons doing the actual
202
+ execution.
203
+ - A native install suits dispatch. If you want AgnView to run Claude Code,
204
+ Codex or AntiGravity for you, install it on the machine where those CLIs
205
+ live.
206
+
207
+ ## Command line
208
+
209
+ `agnview serve` runs the hub. The rest of the commands drive it, so an agent
210
+ can take part in a pipeline from a script:
211
+
212
+ | Command | Purpose |
213
+ |---|---|
214
+ | `create-job` | Create a job from a YAML or JSON pipeline file |
215
+ | `status` | Show job and task status |
216
+ | `wait` | Block until a task's dependencies are satisfied |
217
+ | `claim` | Claim a task and begin work |
218
+ | `complete` | Mark a task complete with a summary |
219
+ | `reject` | Send a task back to its agent for revision |
220
+ | `my-tasks` | List tasks assigned to an agent |
221
+ | `nodes` | List connected agent instances |
222
+ | `worker` | Poll for assigned tasks as a daemon |
223
+ | `export-prompt` | Build a context prompt for a web LLM |
224
+ | `usage` | Show live subscription quotas |
225
+
226
+ Run any of them with `--help` for the full set of options.
227
+
228
+ ## How a pipeline runs
229
+
230
+ 1. Create a job whose tasks name their dependencies. Tasks with no unmet
231
+ dependencies start ready; the rest start pending.
232
+ 2. An agent claims a ready task, which moves it to in progress.
233
+ 3. Completing a task records its summary and artefacts, and unlocks every task
234
+ whose dependencies are now met.
235
+ 4. An agent that finds a defect upstream requests a revision. The upstream task
236
+ reopens and its dependents go back to pending until it is fixed.
237
+ 5. A task that cannot be finished is marked failed, which blocks everything
238
+ downstream of it and fails the job.
239
+
240
+ Every one of these changes is pushed to open dashboards over Server-Sent
241
+ Events, so a second tab or a paired phone follows along without a reload.
242
+
243
+ ## Licence
244
+
245
+ MIT, as declared in `pyproject.toml`. The repository does not yet carry a
246
+ `LICENSE` file; one should be added before public release.
@@ -0,0 +1,208 @@
1
+ <div align="center">
2
+ <img src="docs/agnview_logo.png" alt="AgnView" width="140" />
3
+ <h1>AgnView</h1>
4
+ <p><strong>One screen for the coding agents already running on your machine.</strong></p>
5
+ </div>
6
+
7
+ ---
8
+
9
+ ## What AgnView is
10
+
11
+ AgnView is a local dashboard and coordination hub for the agent CLIs you have
12
+ installed: Claude Code, Codex, AntiGravity, DeepSeek, and any local model you
13
+ run yourself. There are five known agent roles a task can be assigned to:
14
+ `claude_code`, `codex`, `antigravity`, `deepseek` and `custom`. It does three
15
+ things.
16
+
17
+ **Watch.** Every agent's output streams into one console, colour-coded by
18
+ agent, instead of being scattered across terminal tabs.
19
+
20
+ **Coordinate.** Describe a job as a set of tasks with dependencies. A task
21
+ stays blocked until the tasks it depends on complete, and when it starts, the
22
+ agent picks it up with the upstream summaries and artefacts attached. If one
23
+ agent finds a defect in another's work, it can send the task back for revision,
24
+ or mark it failed, which blocks everything downstream.
25
+
26
+ **Keep an eye on quotas.** Session and weekly limits for your Claude, ChatGPT
27
+ and Gemini subscriptions, in one place.
28
+
29
+ AgnView runs entirely on your own machine. It is free, and there is nothing to
30
+ sign up for.
31
+
32
+ ## Screenshots
33
+
34
+ | | Light | Dark |
35
+ |---|---|---|
36
+ | **Console** | ![Console, light](docs/screenshots/console-light.png) | ![Console, dark](docs/screenshots/console-dark.png) |
37
+ | **Pipelines** | ![Pipelines, light](docs/screenshots/pipelines-light.png) | ![Pipelines, dark](docs/screenshots/pipelines-dark.png) |
38
+ | **Usage** | ![Usage, light](docs/screenshots/usage-light.png) | ![Usage, dark](docs/screenshots/usage-dark.png) |
39
+
40
+ ## Supported platforms
41
+
42
+ | | |
43
+ |---|---|
44
+ | Windows | 10 and 11 |
45
+ | macOS | 12 Monterey and later, Intel and Apple silicon |
46
+ | Linux | any distribution with Python 3.10 or newer |
47
+ | Python | 3.10 or newer |
48
+ | Browser | any current Chrome, Edge, Firefox or Safari |
49
+
50
+ The companion mobile client is iOS and iPadOS.
51
+
52
+ ## Clients
53
+
54
+ The AgnView hub in this repo covers Windows, macOS and Linux.
55
+
56
+ - **iOS and iPadOS**: [github.com/tlaskar-git/AgnView-iOS](https://github.com/tlaskar-git/AgnView-iOS)
57
+ holds the design prototype and mobile spec for the iOS and iPadOS client.
58
+ - **Android**: an Android client will live at
59
+ [github.com/tlaskar-git/AgnView-Android](https://github.com/tlaskar-git/AgnView-Android)
60
+ (reference only, not yet created).
61
+
62
+ AgnView does not install any coding agent for you. It watches and dispatches to
63
+ the CLIs already on your machine: Claude Code, Codex, AntiGravity or any other
64
+ tool you add as an adapter. Install the CLIs you want to use yourself, before
65
+ or after installing AgnView.
66
+
67
+ ## Install
68
+
69
+ The quickest way is not to install at all. [uv](https://docs.astral.sh/uv/)
70
+ fetches and runs AgnView in one command, with no clone and no virtualenv:
71
+
72
+ ```bash
73
+ uvx agnview serve
74
+ ```
75
+
76
+ To keep it around permanently:
77
+
78
+ ```bash
79
+ uv tool install agnview # or: pipx install agnview / pip install agnview
80
+ ```
81
+
82
+ Working on AgnView itself? Install from source:
83
+
84
+ ```bash
85
+ git clone https://github.com/tlaskar-git/AgnView.git
86
+ cd AgnView
87
+ pip install -e .
88
+ ```
89
+
90
+ `agent-relay` is supported as an alias for the `agnview` command.
91
+
92
+ ## Start
93
+
94
+ ```bash
95
+ agnview serve
96
+ ```
97
+
98
+ The dashboard is then at <http://127.0.0.1:8765>.
99
+
100
+ By default AgnView binds `127.0.0.1`, so only your own machine can reach it. To
101
+ let your phone or another computer on the same network connect, opt in
102
+ explicitly:
103
+
104
+ ```bash
105
+ agnview serve --listen-lan
106
+ ```
107
+
108
+ Choose a different port with `--port`, and require a token from connecting
109
+ clients with `--token`.
110
+
111
+ ## Pair a phone
112
+
113
+ 1. Start the hub with `agnview serve --listen-lan`.
114
+ 2. Open the dashboard and choose the mobile option in the header to show the
115
+ pairing QR code.
116
+ 3. Scan it with the AgnView app on a device on the same network.
117
+
118
+ The QR code carries the hub's LAN address, its certificate fingerprint, and a
119
+ pairing key. Regenerating the code invalidates every device already paired.
120
+ `docs/PAIRING.md` is the full contract.
121
+
122
+ **Treat the pairing QR code like a password.** Anyone who can read it can reach
123
+ the hub, and the hub can run commands on this machine. See `SECURITY.md`.
124
+
125
+ ## LAN pairing, plus a remote path if you want it
126
+
127
+ On your own local network, your machine and your phone talk to each other
128
+ directly. Nothing goes through anybody else's infrastructure, and no account
129
+ or setup is needed.
130
+
131
+ If your phone is off your home or office Wi-Fi, LAN pairing alone cannot reach
132
+ it. AgnView also accepts connections over iroh, which can carry the pairing QR
133
+ code and the console beyond the LAN without a VPN. See "Remote access" below
134
+ for what that depends on and how to opt out of it.
135
+
136
+ ## Remote access
137
+
138
+ `docs/REMOTE-ACCESS.md` covers every path in order: LAN, bundled iroh, what
139
+ iroh depends on, running your own relay, and the overlay alternatives
140
+ (Tailscale, NetBird, an SSH local port forward, or an existing WireGuard
141
+ tunnel) via `--listen-overlay`.
142
+
143
+ Remote access uses iroh's free public relays. Most connections are direct and never touch a relay. Relayed connections are rate limited and carry no uptime guarantee. You can point AgnView at your own relay in Settings.
144
+
145
+ ## Docker, and what a container cannot do
146
+
147
+ ```bash
148
+ docker compose up -d
149
+ ```
150
+
151
+ The hub is then at <http://localhost:8765>. The image runs as an unprivileged
152
+ `agnview` user and carries a `HEALTHCHECK` against the dashboard root, and the
153
+ compose file keeps `~/.agnview` (pairing token, adapters, notification config)
154
+ in a named volume so it survives rebuilds and restarts.
155
+
156
+ **A containerised hub cannot dispatch to CLI agents.** AgnView dispatches work
157
+ by executing the agent binaries on the host: `claude`, `codex`, `antigravity`
158
+ and the rest, with their own credentials, config and your working tree. A
159
+ container sees none of that.
160
+
161
+ - Docker suits watching and managing a pipeline: the dashboard, the REST and
162
+ SSE API, job and dependency state, web-LLM prompt generation, quota
163
+ monitoring, and mobile pairing, with remote worker daemons doing the actual
164
+ execution.
165
+ - A native install suits dispatch. If you want AgnView to run Claude Code,
166
+ Codex or AntiGravity for you, install it on the machine where those CLIs
167
+ live.
168
+
169
+ ## Command line
170
+
171
+ `agnview serve` runs the hub. The rest of the commands drive it, so an agent
172
+ can take part in a pipeline from a script:
173
+
174
+ | Command | Purpose |
175
+ |---|---|
176
+ | `create-job` | Create a job from a YAML or JSON pipeline file |
177
+ | `status` | Show job and task status |
178
+ | `wait` | Block until a task's dependencies are satisfied |
179
+ | `claim` | Claim a task and begin work |
180
+ | `complete` | Mark a task complete with a summary |
181
+ | `reject` | Send a task back to its agent for revision |
182
+ | `my-tasks` | List tasks assigned to an agent |
183
+ | `nodes` | List connected agent instances |
184
+ | `worker` | Poll for assigned tasks as a daemon |
185
+ | `export-prompt` | Build a context prompt for a web LLM |
186
+ | `usage` | Show live subscription quotas |
187
+
188
+ Run any of them with `--help` for the full set of options.
189
+
190
+ ## How a pipeline runs
191
+
192
+ 1. Create a job whose tasks name their dependencies. Tasks with no unmet
193
+ dependencies start ready; the rest start pending.
194
+ 2. An agent claims a ready task, which moves it to in progress.
195
+ 3. Completing a task records its summary and artefacts, and unlocks every task
196
+ whose dependencies are now met.
197
+ 4. An agent that finds a defect upstream requests a revision. The upstream task
198
+ reopens and its dependents go back to pending until it is fixed.
199
+ 5. A task that cannot be finished is marked failed, which blocks everything
200
+ downstream of it and fails the job.
201
+
202
+ Every one of these changes is pushed to open dashboards over Server-Sent
203
+ Events, so a second tab or a paired phone follows along without a reload.
204
+
205
+ ## Licence
206
+
207
+ MIT, as declared in `pyproject.toml`. The repository does not yet carry a
208
+ `LICENSE` file; one should be added before public release.
@@ -0,0 +1,3 @@
1
+ """AgentRelay: Cross-Agent Orchestration & Status Synchronization Hub."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,161 @@
1
+ import asyncio
2
+ import os
3
+ from pathlib import Path
4
+ from typing import Optional
5
+ from fastapi import FastAPI, Request
6
+ from fastapi.middleware.cors import CORSMiddleware
7
+ from fastapi.staticfiles import StaticFiles
8
+ from fastapi.responses import FileResponse, JSONResponse
9
+
10
+ from .routes import router as api_router
11
+ from ..core.engine import RelayEngine
12
+ from ..core.db import Database
13
+ from ..core.config import load_config
14
+ from ..core.iroh_transport import IrohTransport
15
+
16
+
17
+ # Set AGNVIEW_IROH=0 to keep the hub LAN only. The default is on, because the
18
+ # whole point of the iroh transport is that the user never sets anything up.
19
+ IROH_ENV = "AGNVIEW_IROH"
20
+
21
+
22
+ def _iroh_enabled_from_env() -> bool:
23
+ value = os.environ.get(IROH_ENV)
24
+ if value is None:
25
+ return True
26
+ return value.strip().lower() not in ("0", "false", "no", "off")
27
+
28
+
29
+ def create_app(db_path: Optional[str] = None, auth_token: Optional[str] = None, port: int = 8765) -> FastAPI:
30
+ token = auth_token or os.environ.get("AGENT_RELAY_TOKEN")
31
+
32
+ app = FastAPI(
33
+ title="AgnView API",
34
+ description="Cross-Agent Coordination Hub & Live Console for Claude Code, Codex, AntiGravity, and Web LLMs",
35
+ version="0.1.0"
36
+ )
37
+
38
+ # Enable CORS for external tools, mobile apps, and browser extensions
39
+ app.add_middleware(
40
+ CORSMiddleware,
41
+ allow_origins=["*"],
42
+ allow_credentials=True,
43
+ allow_methods=["*"],
44
+ allow_headers=["*"],
45
+ )
46
+
47
+ # Token Authentication Middleware for distributed multi-computer and mobile setups
48
+ if token:
49
+ @app.middleware("http")
50
+ async def verify_token_middleware(request: Request, call_next):
51
+ # Only authenticate API endpoints; allow static dashboard index and docs
52
+ path = request.url.path
53
+ if path.startswith("/api") and not path.startswith("/api/mobile/pairing"):
54
+ client_ip = request.client.host if request.client else "127.0.0.1"
55
+ # Allow unauthenticated access only for local browser same-origin sessions (not programmatic API clients/tests)
56
+ is_local_browser = (
57
+ client_ip in ("127.0.0.1", "::1", "localhost")
58
+ and (
59
+ request.headers.get("Sec-Fetch-Site") == "same-origin"
60
+ or request.headers.get("Referer", "").startswith(("http://localhost:", "http://127.0.0.1:", "http://[::1]:"))
61
+ )
62
+ )
63
+ if not is_local_browser:
64
+ from ..core.pairing import check_auth_rate_limit, record_failed_auth, reset_auth_rate_limit
65
+
66
+ # Check rate limiting for failed auth attempts
67
+ if not check_auth_rate_limit(client_ip):
68
+ return JSONResponse(
69
+ status_code=429,
70
+ content={"detail": "Too many failed authentication attempts. Please try again later."}
71
+ )
72
+
73
+ auth_header = (
74
+ request.headers.get("X-AgnView-Token") or
75
+ request.headers.get("X-Agent-Relay-Token") or
76
+ request.headers.get("Authorization")
77
+ )
78
+ token_param = request.query_params.get("token")
79
+
80
+ provided = None
81
+ if auth_header:
82
+ if auth_header.startswith("Bearer "):
83
+ provided = auth_header[7:].strip()
84
+ else:
85
+ provided = auth_header.strip()
86
+ elif token_param:
87
+ provided = token_param.strip()
88
+
89
+ expected = request.app.state.auth_token or token
90
+ if not provided or provided != expected:
91
+ record_failed_auth(client_ip)
92
+ return JSONResponse(
93
+ status_code=401,
94
+ content={"detail": "Unauthorized: Invalid or missing AgnView authentication token."}
95
+ )
96
+
97
+ reset_auth_rate_limit(client_ip)
98
+
99
+ return await call_next(request)
100
+
101
+ db = Database(db_path)
102
+ engine = RelayEngine(db, port=port)
103
+ app.state.db = db
104
+ app.state.engine = engine
105
+ app.state.auth_token = token
106
+
107
+ config = load_config()
108
+ app.state.config = config
109
+
110
+ # A configuration the hub cannot act on stops iroh and nothing else. The
111
+ # reason is already in the log and travels to the API in the status.
112
+ if not _iroh_enabled_from_env():
113
+ iroh_enabled, disabled_reason = False, f"{IROH_ENV} is set to off"
114
+ elif not config.iroh_enabled:
115
+ iroh_enabled, disabled_reason = False, f"iroh_enabled is false in {config.path}"
116
+ elif not config.is_valid:
117
+ iroh_enabled, disabled_reason = False, "; ".join(config.errors)
118
+ else:
119
+ iroh_enabled, disabled_reason = True, ""
120
+
121
+ iroh_transport = IrohTransport(
122
+ db=db,
123
+ token_provider=lambda: app.state.auth_token,
124
+ relay_url=config.relay_url,
125
+ enabled=iroh_enabled,
126
+ disabled_reason=disabled_reason,
127
+ )
128
+ app.state.iroh = iroh_transport
129
+
130
+ @app.on_event("startup")
131
+ async def _bind_event_loop():
132
+ # Job and task routes are sync, so they execute on worker threads.
133
+ # Remember the serving loop so their broadcasts still reach SSE clients.
134
+ engine.bind_loop(asyncio.get_running_loop())
135
+
136
+ @app.on_event("startup")
137
+ async def _start_iroh_transport():
138
+ # start() schedules the bind and returns. Startup never waits on the
139
+ # network, so a hub with no route out still comes up and serves the
140
+ # dashboard.
141
+ iroh_transport.start()
142
+
143
+ @app.on_event("shutdown")
144
+ async def _stop_iroh_transport():
145
+ await iroh_transport.stop()
146
+
147
+ app.include_router(api_router)
148
+
149
+ # Web Dashboard Static UI & Assets
150
+ web_dir = Path(__file__).parent.parent / "web"
151
+ static_dir = web_dir / "static"
152
+ if static_dir.exists():
153
+ app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
154
+
155
+ index_file = web_dir / "templates" / "index.html"
156
+ if index_file.exists():
157
+ @app.get("/", include_in_schema=False)
158
+ async def serve_index():
159
+ return FileResponse(str(index_file))
160
+
161
+ return app