foxygpu 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.
- foxygpu-0.1.0/LICENSE +21 -0
- foxygpu-0.1.0/PKG-INFO +241 -0
- foxygpu-0.1.0/README.md +211 -0
- foxygpu-0.1.0/foxygpu/__init__.py +3 -0
- foxygpu-0.1.0/foxygpu/agent_source.py +350 -0
- foxygpu-0.1.0/foxygpu/client.py +88 -0
- foxygpu-0.1.0/foxygpu/config.py +51 -0
- foxygpu-0.1.0/foxygpu/github.py +85 -0
- foxygpu-0.1.0/foxygpu/main.py +349 -0
- foxygpu-0.1.0/foxygpu/notebook_builder.py +128 -0
- foxygpu-0.1.0/foxygpu.egg-info/PKG-INFO +241 -0
- foxygpu-0.1.0/foxygpu.egg-info/SOURCES.txt +20 -0
- foxygpu-0.1.0/foxygpu.egg-info/dependency_links.txt +1 -0
- foxygpu-0.1.0/foxygpu.egg-info/entry_points.txt +2 -0
- foxygpu-0.1.0/foxygpu.egg-info/requires.txt +11 -0
- foxygpu-0.1.0/foxygpu.egg-info/top_level.txt +1 -0
- foxygpu-0.1.0/pyproject.toml +55 -0
- foxygpu-0.1.0/setup.cfg +4 -0
- foxygpu-0.1.0/tests/test_agent.py +170 -0
- foxygpu-0.1.0/tests/test_cli.py +126 -0
- foxygpu-0.1.0/tests/test_client.py +65 -0
- foxygpu-0.1.0/tests/test_github.py +99 -0
foxygpu-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shamshad Choudhary
|
|
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.
|
foxygpu-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: foxygpu
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Run local code on Google Colab's free GPU
|
|
5
|
+
Author-email: Shamshad Choudhary <chaudhary.s.shamshad07@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Shamshadz/FoxyGPU
|
|
8
|
+
Project-URL: Repository, https://github.com/Shamshadz/FoxyGPU
|
|
9
|
+
Project-URL: Issues, https://github.com/Shamshadz/FoxyGPU/issues
|
|
10
|
+
Keywords: colab,gpu,ollama,deployment,cli,fastapi
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Topic :: Software Development
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: typer>=0.9
|
|
20
|
+
Requires-Dist: requests>=2.31
|
|
21
|
+
Requires-Dist: websockets>=12.0
|
|
22
|
+
Requires-Dist: rich>=13.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-timeout>=2.2; extra == "dev"
|
|
26
|
+
Requires-Dist: fastapi>=0.100; extra == "dev"
|
|
27
|
+
Requires-Dist: uvicorn>=0.23; extra == "dev"
|
|
28
|
+
Requires-Dist: python-multipart>=0.0.6; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# FoxyGPU
|
|
32
|
+
|
|
33
|
+
[](https://github.com/Shamshadz/FoxyGPU/actions/workflows/tests.yml)
|
|
34
|
+
|
|
35
|
+
Run local code — FastAPI backends, frontend dev servers, or anything else — on
|
|
36
|
+
Google Colab's free-tier GPU, driven entirely from your own machine.
|
|
37
|
+
|
|
38
|
+
## How it works
|
|
39
|
+
|
|
40
|
+
`foxygpu launch` opens FoxyGPU's own runner notebook directly in Colab — no
|
|
41
|
+
manual notebook upload, and **no GitHub account or token needed**. The notebook
|
|
42
|
+
is identical for every user (nothing personalized is baked in), so it's just
|
|
43
|
+
committed straight into this repo and Colab loads it from there; Colab can open
|
|
44
|
+
any public GitHub file with zero authentication. That notebook starts a
|
|
45
|
+
control-plane agent, reached from your machine over a [Cloudflare
|
|
46
|
+
Tunnel](https://github.com/cloudflare/cloudflared) quick tunnel (no account needed).
|
|
47
|
+
The local `foxygpu` CLI talks to that agent to upload your project, start it with a
|
|
48
|
+
shell command, stream its logs, and expose whatever port it's listening on with its
|
|
49
|
+
own public URL.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
local machine Google Colab VM (GPU runtime)
|
|
53
|
+
┌─────────────────┐ HTTPS/WSS via ┌─────────────────────────────┐
|
|
54
|
+
│ foxygpu CLI │◄──cloudflared tunnel──►│ foxygpu_agent (FastAPI) │
|
|
55
|
+
└─────────────────┘ │ spawns your process │
|
|
56
|
+
│ (uvicorn / npm / anything) │
|
|
57
|
+
└─────────────────────────────┘
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Every agent endpoint requires a bearer token generated at startup — the tunnel URL
|
|
61
|
+
alone isn't enough to run anything on your VM.
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
Everything — the CLI and the Colab agent it deploys — ships as one Python package:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install -e .
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Setup
|
|
72
|
+
|
|
73
|
+
### 1. Launch the Colab runtime
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
foxygpu launch
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This just opens Colab straight to FoxyGPU's own committed notebook — nothing to
|
|
80
|
+
sign in to, no token, no account needed.
|
|
81
|
+
|
|
82
|
+
In the browser: select a GPU runtime (`Runtime > Change runtime type > GPU`),
|
|
83
|
+
run all cells. The last cell prints a `foxygpu connect ...` command — copy it.
|
|
84
|
+
|
|
85
|
+
Prefer not to open a link we host at all? `foxygpu notebook ./FoxyGPU_Runner.ipynb`
|
|
86
|
+
writes the same notebook to a local file so you can read it yourself and upload
|
|
87
|
+
it to Colab manually (`File > Upload notebook`) — zero network calls to anything
|
|
88
|
+
but Colab itself.
|
|
89
|
+
|
|
90
|
+
If you've modified `foxygpu/agent_source.py` locally and want the one-click
|
|
91
|
+
experience for your own version without forking/hosting a repo, `foxygpu launch
|
|
92
|
+
--gist` publishes your copy to a GitHub Gist instead — that path does need a
|
|
93
|
+
**classic** GitHub token with the `gist` scope (fine-grained tokens don't support
|
|
94
|
+
the Gists API and fail with a 404); create one at https://github.com/settings/tokens
|
|
95
|
+
-> "Generate new token (classic)".
|
|
96
|
+
|
|
97
|
+
### 2. Connect
|
|
98
|
+
|
|
99
|
+
Paste the command Colab printed, e.g.:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
foxygpu connect https://xxxx.trycloudflare.com --token <token>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Usage
|
|
106
|
+
|
|
107
|
+
Run a project (any language/framework — it's just a shell command). The agent
|
|
108
|
+
picks a free port for you and injects it as `$PORT` — reference that instead of
|
|
109
|
+
a literal number so you never have to think about which ports are free or
|
|
110
|
+
reserved:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
foxygpu run ./my-fastapi-app --cmd 'pip install -r requirements.txt && uvicorn main:app --host 0.0.0.0 --port $PORT' --expose
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> **Shell note**: use **single quotes** around the `--cmd` value, exactly as
|
|
117
|
+
> above, in PowerShell, bash, or zsh — all three treat single quotes as a
|
|
118
|
+
> literal string, so `$PORT` and `&&` reach the remote command unchanged. This
|
|
119
|
+
> does **not** work in `cmd.exe` (no concept of single-quoted literal strings,
|
|
120
|
+
> and it interprets `&&` itself) — use PowerShell or a bash-like shell instead.
|
|
121
|
+
|
|
122
|
+
Logs stream live, and the CLI prints which port got assigned. `--expose`
|
|
123
|
+
immediately opens a public tunnel once the process starts and prints the URL.
|
|
124
|
+
If you skip it, expose later — with no argument it defaults to the most
|
|
125
|
+
recently started process's port:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
foxygpu expose
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Edited your code and want to update what's running? `foxygpu run` always
|
|
132
|
+
starts a fresh, separate deployment — it won't stop whatever's already running
|
|
133
|
+
first. Use `redeploy` instead, which stops the previous deployment of the same
|
|
134
|
+
project (matched by directory name, or `--name` if you gave one) before
|
|
135
|
+
starting the new one:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
foxygpu redeploy ./my-fastapi-app --cmd 'pip install -r requirements.txt && uvicorn main:app --host 0.0.0.0 --port $PORT' --expose
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
If the new run lands back on the same port — likely, since stopping the old
|
|
142
|
+
one just freed it — an existing exposed URL for that port keeps working
|
|
143
|
+
automatically, no need to `expose` again.
|
|
144
|
+
|
|
145
|
+
Check GPU status and running processes (including their assigned ports):
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
foxygpu status
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Stream logs for a process, reconnect after detaching, or stop it (add `--all`
|
|
152
|
+
to stop everything):
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
foxygpu logs <process-id>
|
|
156
|
+
foxygpu stop <process-id>
|
|
157
|
+
foxygpu stop --all
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Pressing Ctrl+C while logs are streaming only detaches your terminal — the
|
|
161
|
+
remote process keeps running on Colab. The CLI reminds you of the `logs`/`stop`
|
|
162
|
+
commands above when you do this.
|
|
163
|
+
|
|
164
|
+
### More examples
|
|
165
|
+
|
|
166
|
+
Node.js app (read `process.env.PORT` in your server code):
|
|
167
|
+
```bash
|
|
168
|
+
foxygpu run ./my-node-app --cmd 'npm install && node server.js' --expose
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Frontend dev server (Vite/React/etc.):
|
|
172
|
+
```bash
|
|
173
|
+
foxygpu run ./my-frontend --cmd 'npm install && npm run dev -- --host 0.0.0.0 --port $PORT' --expose
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
One-off script or training job (no server, so skip `--expose`):
|
|
177
|
+
```bash
|
|
178
|
+
foxygpu run ./train-job --cmd 'pip install -r requirements.txt && python train.py'
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
See `foxygpu run --help` for this same set of examples from the CLI.
|
|
182
|
+
|
|
183
|
+
### Full working example
|
|
184
|
+
|
|
185
|
+
[examples/ollama-chat](examples/ollama-chat/) is a complete ChatGPT-style app
|
|
186
|
+
(FastAPI backend + a small frontend) that runs a real GPU-backed Ollama model
|
|
187
|
+
on Colab — a good first thing to deploy to confirm your setup end-to-end.
|
|
188
|
+
|
|
189
|
+
## Excluding files from upload
|
|
190
|
+
|
|
191
|
+
By default `.git`, `node_modules`, `__pycache__`, `venv`/`.venv`, and a few build
|
|
192
|
+
directories are excluded when zipping your project. Add more patterns by copying
|
|
193
|
+
[.foxygpuignore.default](.foxygpuignore.default) to `.foxygpuignore` in your project
|
|
194
|
+
root.
|
|
195
|
+
|
|
196
|
+
## Development
|
|
197
|
+
|
|
198
|
+
The test suite runs a real instance of the agent locally (no Colab needed) and
|
|
199
|
+
drives it over HTTP/WebSocket, plus in-process CLI tests via Typer's test
|
|
200
|
+
runner. It never touches your real `~/.foxygpu/config.json` — every test gets
|
|
201
|
+
an isolated one automatically.
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
pip install -e ".[dev]"
|
|
205
|
+
pytest
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Known limitations
|
|
209
|
+
|
|
210
|
+
- FastAPI is only used to build the agent itself (the control-plane server running
|
|
211
|
+
inside Colab) — it is not a requirement for what you deploy. `foxygpu run` just
|
|
212
|
+
executes whatever shell command you give it via `--cmd`, so any language or
|
|
213
|
+
framework the Colab VM can run works (Node, Go, Rust, Flask, Streamlit, a plain
|
|
214
|
+
training script, anything), not just Python or FastAPI.
|
|
215
|
+
- Colab free-tier sessions are ephemeral (idle timeout, ~12h cap). If the session
|
|
216
|
+
restarts, run the notebook again (re-run `foxygpu launch` if you closed the tab)
|
|
217
|
+
and `foxygpu connect` again with the new URL/token.
|
|
218
|
+
- The control URL and token grant code execution on the VM — don't share them.
|
|
219
|
+
- `foxygpu launch --gist` (the opt-in path) publishes to a **public** Gist (Gist
|
|
220
|
+
API has no private-but-linkable option) — it contains no secrets (the agent's
|
|
221
|
+
token is generated fresh at runtime in Colab, not baked into the notebook), but
|
|
222
|
+
anyone who finds the Gist URL can see and re-run it against their own Colab.
|
|
223
|
+
- The agent source lives at `foxygpu/agent_source.py`. The committed
|
|
224
|
+
`notebook/FoxyGPU_Runner.ipynb` embeds a copy of it — regenerate that file with
|
|
225
|
+
`foxygpu notebook notebook/FoxyGPU_Runner.ipynb` and commit it after changing
|
|
226
|
+
the agent, since (unlike `--gist`, which always embeds the current source) the
|
|
227
|
+
default `launch` opens the version already committed to this repo.
|
|
228
|
+
- **Port 8765 is reserved** — the agent itself listens there inside Colab. You
|
|
229
|
+
shouldn't need to think about this: reference `$PORT` in your `--cmd` (see
|
|
230
|
+
Usage) and the agent hands you a free port automatically, preferring `9876`
|
|
231
|
+
and falling back to another free one if that's taken (e.g. a second
|
|
232
|
+
concurrent project).
|
|
233
|
+
- **A command with an animated progress bar can hang your whole `--cmd` chain
|
|
234
|
+
forever.** Some CLI tools (Ollama's `pull` is one — see
|
|
235
|
+
[examples/ollama-chat](examples/ollama-chat/README.md)) never exit their
|
|
236
|
+
progress renderer when run through a non-interactive pipe like the one the
|
|
237
|
+
agent uses to capture output, even though the real work finishes. Since
|
|
238
|
+
`foxygpu run` chains commands with `&&`, a hung one blocks everything after
|
|
239
|
+
it. If a step seems stuck, check whether it actually finished (e.g. via a
|
|
240
|
+
second `foxygpu run` with a quick status-checking command) before assuming
|
|
241
|
+
it's slow — the fix is usually prefixing that one command with `TERM=dumb`.
|
foxygpu-0.1.0/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# FoxyGPU
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Shamshadz/FoxyGPU/actions/workflows/tests.yml)
|
|
4
|
+
|
|
5
|
+
Run local code — FastAPI backends, frontend dev servers, or anything else — on
|
|
6
|
+
Google Colab's free-tier GPU, driven entirely from your own machine.
|
|
7
|
+
|
|
8
|
+
## How it works
|
|
9
|
+
|
|
10
|
+
`foxygpu launch` opens FoxyGPU's own runner notebook directly in Colab — no
|
|
11
|
+
manual notebook upload, and **no GitHub account or token needed**. The notebook
|
|
12
|
+
is identical for every user (nothing personalized is baked in), so it's just
|
|
13
|
+
committed straight into this repo and Colab loads it from there; Colab can open
|
|
14
|
+
any public GitHub file with zero authentication. That notebook starts a
|
|
15
|
+
control-plane agent, reached from your machine over a [Cloudflare
|
|
16
|
+
Tunnel](https://github.com/cloudflare/cloudflared) quick tunnel (no account needed).
|
|
17
|
+
The local `foxygpu` CLI talks to that agent to upload your project, start it with a
|
|
18
|
+
shell command, stream its logs, and expose whatever port it's listening on with its
|
|
19
|
+
own public URL.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
local machine Google Colab VM (GPU runtime)
|
|
23
|
+
┌─────────────────┐ HTTPS/WSS via ┌─────────────────────────────┐
|
|
24
|
+
│ foxygpu CLI │◄──cloudflared tunnel──►│ foxygpu_agent (FastAPI) │
|
|
25
|
+
└─────────────────┘ │ spawns your process │
|
|
26
|
+
│ (uvicorn / npm / anything) │
|
|
27
|
+
└─────────────────────────────┘
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Every agent endpoint requires a bearer token generated at startup — the tunnel URL
|
|
31
|
+
alone isn't enough to run anything on your VM.
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
Everything — the CLI and the Colab agent it deploys — ships as one Python package:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install -e .
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Setup
|
|
42
|
+
|
|
43
|
+
### 1. Launch the Colab runtime
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
foxygpu launch
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This just opens Colab straight to FoxyGPU's own committed notebook — nothing to
|
|
50
|
+
sign in to, no token, no account needed.
|
|
51
|
+
|
|
52
|
+
In the browser: select a GPU runtime (`Runtime > Change runtime type > GPU`),
|
|
53
|
+
run all cells. The last cell prints a `foxygpu connect ...` command — copy it.
|
|
54
|
+
|
|
55
|
+
Prefer not to open a link we host at all? `foxygpu notebook ./FoxyGPU_Runner.ipynb`
|
|
56
|
+
writes the same notebook to a local file so you can read it yourself and upload
|
|
57
|
+
it to Colab manually (`File > Upload notebook`) — zero network calls to anything
|
|
58
|
+
but Colab itself.
|
|
59
|
+
|
|
60
|
+
If you've modified `foxygpu/agent_source.py` locally and want the one-click
|
|
61
|
+
experience for your own version without forking/hosting a repo, `foxygpu launch
|
|
62
|
+
--gist` publishes your copy to a GitHub Gist instead — that path does need a
|
|
63
|
+
**classic** GitHub token with the `gist` scope (fine-grained tokens don't support
|
|
64
|
+
the Gists API and fail with a 404); create one at https://github.com/settings/tokens
|
|
65
|
+
-> "Generate new token (classic)".
|
|
66
|
+
|
|
67
|
+
### 2. Connect
|
|
68
|
+
|
|
69
|
+
Paste the command Colab printed, e.g.:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
foxygpu connect https://xxxx.trycloudflare.com --token <token>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
Run a project (any language/framework — it's just a shell command). The agent
|
|
78
|
+
picks a free port for you and injects it as `$PORT` — reference that instead of
|
|
79
|
+
a literal number so you never have to think about which ports are free or
|
|
80
|
+
reserved:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
foxygpu run ./my-fastapi-app --cmd 'pip install -r requirements.txt && uvicorn main:app --host 0.0.0.0 --port $PORT' --expose
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> **Shell note**: use **single quotes** around the `--cmd` value, exactly as
|
|
87
|
+
> above, in PowerShell, bash, or zsh — all three treat single quotes as a
|
|
88
|
+
> literal string, so `$PORT` and `&&` reach the remote command unchanged. This
|
|
89
|
+
> does **not** work in `cmd.exe` (no concept of single-quoted literal strings,
|
|
90
|
+
> and it interprets `&&` itself) — use PowerShell or a bash-like shell instead.
|
|
91
|
+
|
|
92
|
+
Logs stream live, and the CLI prints which port got assigned. `--expose`
|
|
93
|
+
immediately opens a public tunnel once the process starts and prints the URL.
|
|
94
|
+
If you skip it, expose later — with no argument it defaults to the most
|
|
95
|
+
recently started process's port:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
foxygpu expose
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Edited your code and want to update what's running? `foxygpu run` always
|
|
102
|
+
starts a fresh, separate deployment — it won't stop whatever's already running
|
|
103
|
+
first. Use `redeploy` instead, which stops the previous deployment of the same
|
|
104
|
+
project (matched by directory name, or `--name` if you gave one) before
|
|
105
|
+
starting the new one:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
foxygpu redeploy ./my-fastapi-app --cmd 'pip install -r requirements.txt && uvicorn main:app --host 0.0.0.0 --port $PORT' --expose
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
If the new run lands back on the same port — likely, since stopping the old
|
|
112
|
+
one just freed it — an existing exposed URL for that port keeps working
|
|
113
|
+
automatically, no need to `expose` again.
|
|
114
|
+
|
|
115
|
+
Check GPU status and running processes (including their assigned ports):
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
foxygpu status
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Stream logs for a process, reconnect after detaching, or stop it (add `--all`
|
|
122
|
+
to stop everything):
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
foxygpu logs <process-id>
|
|
126
|
+
foxygpu stop <process-id>
|
|
127
|
+
foxygpu stop --all
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Pressing Ctrl+C while logs are streaming only detaches your terminal — the
|
|
131
|
+
remote process keeps running on Colab. The CLI reminds you of the `logs`/`stop`
|
|
132
|
+
commands above when you do this.
|
|
133
|
+
|
|
134
|
+
### More examples
|
|
135
|
+
|
|
136
|
+
Node.js app (read `process.env.PORT` in your server code):
|
|
137
|
+
```bash
|
|
138
|
+
foxygpu run ./my-node-app --cmd 'npm install && node server.js' --expose
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Frontend dev server (Vite/React/etc.):
|
|
142
|
+
```bash
|
|
143
|
+
foxygpu run ./my-frontend --cmd 'npm install && npm run dev -- --host 0.0.0.0 --port $PORT' --expose
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
One-off script or training job (no server, so skip `--expose`):
|
|
147
|
+
```bash
|
|
148
|
+
foxygpu run ./train-job --cmd 'pip install -r requirements.txt && python train.py'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
See `foxygpu run --help` for this same set of examples from the CLI.
|
|
152
|
+
|
|
153
|
+
### Full working example
|
|
154
|
+
|
|
155
|
+
[examples/ollama-chat](examples/ollama-chat/) is a complete ChatGPT-style app
|
|
156
|
+
(FastAPI backend + a small frontend) that runs a real GPU-backed Ollama model
|
|
157
|
+
on Colab — a good first thing to deploy to confirm your setup end-to-end.
|
|
158
|
+
|
|
159
|
+
## Excluding files from upload
|
|
160
|
+
|
|
161
|
+
By default `.git`, `node_modules`, `__pycache__`, `venv`/`.venv`, and a few build
|
|
162
|
+
directories are excluded when zipping your project. Add more patterns by copying
|
|
163
|
+
[.foxygpuignore.default](.foxygpuignore.default) to `.foxygpuignore` in your project
|
|
164
|
+
root.
|
|
165
|
+
|
|
166
|
+
## Development
|
|
167
|
+
|
|
168
|
+
The test suite runs a real instance of the agent locally (no Colab needed) and
|
|
169
|
+
drives it over HTTP/WebSocket, plus in-process CLI tests via Typer's test
|
|
170
|
+
runner. It never touches your real `~/.foxygpu/config.json` — every test gets
|
|
171
|
+
an isolated one automatically.
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
pip install -e ".[dev]"
|
|
175
|
+
pytest
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Known limitations
|
|
179
|
+
|
|
180
|
+
- FastAPI is only used to build the agent itself (the control-plane server running
|
|
181
|
+
inside Colab) — it is not a requirement for what you deploy. `foxygpu run` just
|
|
182
|
+
executes whatever shell command you give it via `--cmd`, so any language or
|
|
183
|
+
framework the Colab VM can run works (Node, Go, Rust, Flask, Streamlit, a plain
|
|
184
|
+
training script, anything), not just Python or FastAPI.
|
|
185
|
+
- Colab free-tier sessions are ephemeral (idle timeout, ~12h cap). If the session
|
|
186
|
+
restarts, run the notebook again (re-run `foxygpu launch` if you closed the tab)
|
|
187
|
+
and `foxygpu connect` again with the new URL/token.
|
|
188
|
+
- The control URL and token grant code execution on the VM — don't share them.
|
|
189
|
+
- `foxygpu launch --gist` (the opt-in path) publishes to a **public** Gist (Gist
|
|
190
|
+
API has no private-but-linkable option) — it contains no secrets (the agent's
|
|
191
|
+
token is generated fresh at runtime in Colab, not baked into the notebook), but
|
|
192
|
+
anyone who finds the Gist URL can see and re-run it against their own Colab.
|
|
193
|
+
- The agent source lives at `foxygpu/agent_source.py`. The committed
|
|
194
|
+
`notebook/FoxyGPU_Runner.ipynb` embeds a copy of it — regenerate that file with
|
|
195
|
+
`foxygpu notebook notebook/FoxyGPU_Runner.ipynb` and commit it after changing
|
|
196
|
+
the agent, since (unlike `--gist`, which always embeds the current source) the
|
|
197
|
+
default `launch` opens the version already committed to this repo.
|
|
198
|
+
- **Port 8765 is reserved** — the agent itself listens there inside Colab. You
|
|
199
|
+
shouldn't need to think about this: reference `$PORT` in your `--cmd` (see
|
|
200
|
+
Usage) and the agent hands you a free port automatically, preferring `9876`
|
|
201
|
+
and falling back to another free one if that's taken (e.g. a second
|
|
202
|
+
concurrent project).
|
|
203
|
+
- **A command with an animated progress bar can hang your whole `--cmd` chain
|
|
204
|
+
forever.** Some CLI tools (Ollama's `pull` is one — see
|
|
205
|
+
[examples/ollama-chat](examples/ollama-chat/README.md)) never exit their
|
|
206
|
+
progress renderer when run through a non-interactive pipe like the one the
|
|
207
|
+
agent uses to capture output, even though the real work finishes. Since
|
|
208
|
+
`foxygpu run` chains commands with `&&`, a hung one blocks everything after
|
|
209
|
+
it. If a step seems stuck, check whether it actually finished (e.g. via a
|
|
210
|
+
second `foxygpu run` with a quick status-checking command) before assuming
|
|
211
|
+
it's slow — the fix is usually prefixing that one command with `TERM=dumb`.
|