pethost 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.
@@ -0,0 +1,5 @@
1
+ __pycache__/
2
+ *.egg-info/
3
+ .mypy_cache/
4
+ .venv/
5
+ dist/
pethost-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pethost
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.
pethost-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,219 @@
1
+ Metadata-Version: 2.5
2
+ Name: pethost
3
+ Version: 0.1.0
4
+ Summary: The Python SDK for Pethost, hosting for Docker Compose projects: deploy, read logs and requests, run commands and move files through its API.
5
+ Project-URL: Homepage, https://pethost.dev
6
+ Project-URL: Documentation, https://pethost.dev/docs/api/
7
+ Project-URL: Repository, https://github.com/pethost-dev/sdk
8
+ Project-URL: Issues, https://github.com/pethost-dev/sdk/issues
9
+ Author: Pethost
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: api,client,deploy,docker,docker compose,hosting,paas,pethost,sdk
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.10
26
+ Requires-Dist: connectrpc<0.13,>=0.12.1
27
+ Requires-Dist: protobuf-py<0.7,>=0.6.0
28
+ Description-Content-Type: text/markdown
29
+
30
+ # Pethost for Python
31
+
32
+ The Python SDK for [Pethost](https://pethost.dev), hosting for Docker Compose projects on a
33
+ machine of your own. It has the 13 calls of Pethost's API, the ones an agent has through its
34
+ MCP server: read the machine and its projects, deploy, read logs and HTTP requests, run
35
+ commands, move files. Everything is typed, there is a synchronous client and an asyncio one, and
36
+ the whole package is generated from the API's definition, so its methods, its fields and their
37
+ documentation are the API's own.
38
+
39
+ ## Install
40
+
41
+ ```sh
42
+ pip install pethost
43
+ ```
44
+
45
+ Python 3.10 or newer. With uv: `uv add pethost`.
46
+
47
+ ## A token
48
+
49
+ The SDK signs in with an API token. Make one in [the panel](https://console.pethost.dev)'s
50
+ Settings, under "API tokens", and give it to the SDK in the environment variable
51
+ `PETHOST_TOKEN`, or as the client's first argument. A token acts as you: keep it out of your
52
+ code and your repository.
53
+
54
+ ## A first program
55
+
56
+ It reads the machine and its projects, then deploys to the project `notes` by writing one
57
+ file, `/hello.txt`.
58
+
59
+ ```python
60
+ from pethost import FileChange, Pethost
61
+
62
+ with Pethost() as pethost: # The token: PETHOST_TOKEN.
63
+ answer = pethost.get_machine()
64
+ machine = answer.machine
65
+ if machine is None:
66
+ raise SystemExit("the answer has no machine")
67
+
68
+ print(machine.hostname)
69
+ for project in answer.projects:
70
+ print(project.project_id)
71
+
72
+ deployed = pethost.deploy_project(
73
+ "notes",
74
+ files=[FileChange(path="/hello.txt", text="Hello from the Pethost SDK\n")],
75
+ )
76
+ for violation in deployed.violations: # The file was refused: nothing was deployed.
77
+ print(violation.location, violation.violation_message)
78
+
79
+ if deployed.operation is not None:
80
+ print(deployed.operation.status.name)
81
+ if deployed.project is not None: # The project as it is once the deploy ended.
82
+ print(deployed.project.url)
83
+ ```
84
+
85
+ `AsyncPethost` has the same methods for asyncio:
86
+
87
+ ```python
88
+ import asyncio
89
+
90
+ from pethost import AsyncPethost
91
+
92
+
93
+ async def main() -> None:
94
+ async with AsyncPethost() as pethost:
95
+ print(await pethost.get_machine())
96
+
97
+
98
+ asyncio.run(main())
99
+ ```
100
+
101
+ ## Methods
102
+
103
+ | Method | What it does | |
104
+ |---|---|---|
105
+ | `get_machine()` | Get the machine | read-only |
106
+ | `run_machine_action(...)` | Run a machine action | destructive |
107
+ | `get_project(project_id, ...)` | Get a project | read-only |
108
+ | `create_project(project_id, ...)` | Create a project | |
109
+ | `deploy_project(project_id, ...)` | Deploy a project | destructive |
110
+ | `list_commits(project_id, ...)` | List a project's commits | read-only |
111
+ | `run_project_action(project_id, ...)` | Run a project action | destructive |
112
+ | `get_operation(project_id, ...)` | Get an operation | read-only |
113
+ | `query_http_traffic(project_id, ...)` | Query HTTP traffic | read-only |
114
+ | `query_container_logs(project_id, ...)` | Query container logs | read-only |
115
+ | `run_service_command(project_id, ...)` | Run a command in a service | destructive |
116
+ | `read_path(project_id, ...)` | Read a file or directory | read-only |
117
+ | `create_transfer(...)` | Upload or download a file | destructive |
118
+
119
+ A read-only call changes nothing; a destructive one may delete or overwrite something. A
120
+ request's fields are its method's keyword arguments, a message is a frozen dataclass of the same
121
+ name, and each docstring is the API's own description: `help(Pethost)` and your editor show it.
122
+ What the API calls absent is `None` where a type allows `None`, and the zero value anywhere
123
+ else.
124
+
125
+ ## Errors
126
+
127
+ A failed call raises a `PethostError`, and its class is the code:
128
+ `CanceledError`, `UnknownError`, `InvalidArgumentError`, `DeadlineExceededError`, `NotFoundError`, `AlreadyExistsError`, `PermissionDeniedError`, `ResourceExhaustedError`, `FailedPreconditionError`, `AbortedError`, `OutOfRangeError`, `UnimplementedError`, `InternalError`, `UnavailableError`, `DataLossError`, `UnauthenticatedError`.
129
+ `error.message` is prose for people. What a program branches on, beside the class, is
130
+ `error.detail`: `ProjectBusy`, `ProjectChanged`, `MachineUnreachable`, `NoMachine`, or `None`.
131
+
132
+ ```python
133
+ from pethost import NotFoundError, Pethost, PethostError
134
+
135
+ with Pethost() as pethost:
136
+ try:
137
+ project = pethost.get_project("notes").project
138
+ except NotFoundError as error:
139
+ print(error.message) # No such project: the message lists the ones there are.
140
+ except PethostError as error: # Any other code.
141
+ print(type(error).__name__, error.message, error.detail)
142
+ ```
143
+
144
+ A wrong argument the SDK sees itself, such as two members of one oneof, is Python's own
145
+ `TypeError`, `ValueError` or `OverflowError`, raised before anything is sent.
146
+
147
+ ## Links
148
+
149
+ - [The API's reference](https://pethost.dev/docs/api/): every call, message and field.
150
+ - [The panel](https://console.pethost.dev): your machine, your projects and your API tokens.
151
+ - [pethost.dev](https://pethost.dev): what Pethost is and what it costs.
152
+
153
+ ## Docker Compose hosting at one flat price
154
+
155
+ Pethost is managed hosting for Docker Compose projects. A subscription rents one virtual machine
156
+ that only your account uses. Pethost's software on it deploys your projects, gives them HTTPS
157
+ addresses, keeps their request logs and backs them up every night. You run it through your
158
+ agent or from a web panel: both show the same projects, logs and requests.
159
+
160
+ - **A machine of your own:** nobody else's projects on it. No cold starts, nothing sleeps.
161
+ Security updates install themselves.
162
+ - **HTTPS addresses:** anything.yourname.pethost.app at once, or your own domain with one DNS
163
+ record. Certificates renew themselves. A password page in front of the whole site: one
164
+ sentence to your agent.
165
+ - **Deploys from GitHub:** every push deploys itself, and an earlier commit is one step back.
166
+ - **Request logs:** every request with its status and time, the busiest paths and the error
167
+ rate, kept for 30 days.
168
+ - **Nightly backups:** encrypted, stored off the machine, kept for 14 days.
169
+ - **SSH and SFTP** into any container, and a terminal in the panel.
170
+ - **Docker Compose, as written:** a project is a Compose file, and the same file runs anywhere
171
+ else Docker does. A database is one more service in it, at no extra cost.
172
+ - **In the EU:** your data lives on your machine, and requests to your sites go straight to
173
+ it, never through our panel.
174
+
175
+ **Pricing.** Starter is €9.99 a month for 2 vCPU, 3 GB of memory and 30 GB of SSD. Grow is
176
+ €17.99 for 4 vCPU, 6 GB and 60 GB. Prices are without VAT. As many projects, containers and
177
+ databases as fit: nothing is metered, and nothing is billed on top. There is no free tier.
178
+ [See the plans](https://pethost.dev/#pricing).
179
+
180
+ **Who it is for.** Solo developers and early startups who host several projects, bots or small
181
+ apps and want one fixed monthly bill, and people who build with an AI agent and want it to
182
+ deploy and run what it wrote. It is not for large teams whose applications need several regions
183
+ or autoscaling: the machine is the limit.
184
+
185
+ ## How Pethost compares
186
+
187
+ | If you use | The difference |
188
+ |---|---|
189
+ | [Heroku](https://pethost.dev/about/#heroku), [Render](https://pethost.dev/about/#render), [DigitalOcean App Platform](https://pethost.dev/about/#digitalocean) | There each app, worker and database is one more line on the bill. On Pethost one flat price covers the whole machine: as many projects and databases as fit, and nothing sleeps. |
190
+ | [Railway, Fly.io](https://pethost.dev/about/#railway), [Koyeb](https://pethost.dev/about/#koyeb) | There CPU, memory and traffic are metered, so the bill moves with every busy month. On Pethost the machine is the limit: nothing is metered, nothing is billed on top. |
191
+ | [Vercel, Netlify](https://pethost.dev/about/#vercel) | Made for front ends and serverless functions: a bot, a long-running worker or a database is another service with its own price. Pethost runs the front end, the back end and the database on one machine. |
192
+ | [Coolify, Dokploy](https://pethost.dev/about/#coolify), [CapRover, Dokku, Easypanel](https://pethost.dev/about/#caprover) | Self-hosted: the server is yours to rent, update, secure and back up. Pethost is the machine and the panel together, looked after for you, and agents are first-class users, not an add-on. |
193
+ | [Sliplane](https://pethost.dev/about/#sliplane) | The closest: a flat price per server. There a Compose file is converted into its own services; Pethost runs a Compose project as written. |
194
+ | [Replit](https://pethost.dev/about/#replit) | You build and publish inside Replit, with its own agent. Pethost works with the agent you already use, and one flat price covers all your apps. |
195
+ | [PythonAnywhere](https://pethost.dev/about/#pythonanywhere) | Python only, no Docker. Pethost runs anything Docker runs, in any language. |
196
+ | [A VPS you set up yourself](https://pethost.dev/about/#vps) | The server is the cheap part. You still set up the proxy, DNS, certificates, backups and updates yourself, and fix them when they break. Pethost is the server with all of that done. |
197
+
198
+ [About Pethost](https://pethost.dev/about/) has each comparison in full, with prices.
199
+
200
+ ## Questions
201
+
202
+ **Which AI agents does Pethost work with?**
203
+ Almost any agent that supports skills and MCP. The ones we tested ourselves: Claude Code, Codex,
204
+ Cursor, ChatGPT, Gemini CLI, OpenClaw, Hermes and Pi.
205
+
206
+ **What can I deploy?**
207
+ Anything that runs in Docker: web apps, APIs, bots, workers, databases. No Dockerfile? With the
208
+ plugin installed, your agent knows the details and writes it for you.
209
+
210
+ **Do I need an agent?**
211
+ No. The web panel does the same, and shows the same projects, logs and requests.
212
+
213
+ **Can I use my own domain?**
214
+ Yes. One DNS record, and the certificate comes by itself.
215
+
216
+ **Is there a free tier?**
217
+ No: €9.99 rents a real machine, so nothing sleeps. Cancel any time:
218
+ [refunds and cancellation](https://pethost.dev/refunds/) has the rules.
219
+
@@ -0,0 +1,190 @@
1
+ # Pethost for Python
2
+
3
+ The Python SDK for [Pethost](https://pethost.dev), hosting for Docker Compose projects on a
4
+ machine of your own. It has the 13 calls of Pethost's API, the ones an agent has through its
5
+ MCP server: read the machine and its projects, deploy, read logs and HTTP requests, run
6
+ commands, move files. Everything is typed, there is a synchronous client and an asyncio one, and
7
+ the whole package is generated from the API's definition, so its methods, its fields and their
8
+ documentation are the API's own.
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ pip install pethost
14
+ ```
15
+
16
+ Python 3.10 or newer. With uv: `uv add pethost`.
17
+
18
+ ## A token
19
+
20
+ The SDK signs in with an API token. Make one in [the panel](https://console.pethost.dev)'s
21
+ Settings, under "API tokens", and give it to the SDK in the environment variable
22
+ `PETHOST_TOKEN`, or as the client's first argument. A token acts as you: keep it out of your
23
+ code and your repository.
24
+
25
+ ## A first program
26
+
27
+ It reads the machine and its projects, then deploys to the project `notes` by writing one
28
+ file, `/hello.txt`.
29
+
30
+ ```python
31
+ from pethost import FileChange, Pethost
32
+
33
+ with Pethost() as pethost: # The token: PETHOST_TOKEN.
34
+ answer = pethost.get_machine()
35
+ machine = answer.machine
36
+ if machine is None:
37
+ raise SystemExit("the answer has no machine")
38
+
39
+ print(machine.hostname)
40
+ for project in answer.projects:
41
+ print(project.project_id)
42
+
43
+ deployed = pethost.deploy_project(
44
+ "notes",
45
+ files=[FileChange(path="/hello.txt", text="Hello from the Pethost SDK\n")],
46
+ )
47
+ for violation in deployed.violations: # The file was refused: nothing was deployed.
48
+ print(violation.location, violation.violation_message)
49
+
50
+ if deployed.operation is not None:
51
+ print(deployed.operation.status.name)
52
+ if deployed.project is not None: # The project as it is once the deploy ended.
53
+ print(deployed.project.url)
54
+ ```
55
+
56
+ `AsyncPethost` has the same methods for asyncio:
57
+
58
+ ```python
59
+ import asyncio
60
+
61
+ from pethost import AsyncPethost
62
+
63
+
64
+ async def main() -> None:
65
+ async with AsyncPethost() as pethost:
66
+ print(await pethost.get_machine())
67
+
68
+
69
+ asyncio.run(main())
70
+ ```
71
+
72
+ ## Methods
73
+
74
+ | Method | What it does | |
75
+ |---|---|---|
76
+ | `get_machine()` | Get the machine | read-only |
77
+ | `run_machine_action(...)` | Run a machine action | destructive |
78
+ | `get_project(project_id, ...)` | Get a project | read-only |
79
+ | `create_project(project_id, ...)` | Create a project | |
80
+ | `deploy_project(project_id, ...)` | Deploy a project | destructive |
81
+ | `list_commits(project_id, ...)` | List a project's commits | read-only |
82
+ | `run_project_action(project_id, ...)` | Run a project action | destructive |
83
+ | `get_operation(project_id, ...)` | Get an operation | read-only |
84
+ | `query_http_traffic(project_id, ...)` | Query HTTP traffic | read-only |
85
+ | `query_container_logs(project_id, ...)` | Query container logs | read-only |
86
+ | `run_service_command(project_id, ...)` | Run a command in a service | destructive |
87
+ | `read_path(project_id, ...)` | Read a file or directory | read-only |
88
+ | `create_transfer(...)` | Upload or download a file | destructive |
89
+
90
+ A read-only call changes nothing; a destructive one may delete or overwrite something. A
91
+ request's fields are its method's keyword arguments, a message is a frozen dataclass of the same
92
+ name, and each docstring is the API's own description: `help(Pethost)` and your editor show it.
93
+ What the API calls absent is `None` where a type allows `None`, and the zero value anywhere
94
+ else.
95
+
96
+ ## Errors
97
+
98
+ A failed call raises a `PethostError`, and its class is the code:
99
+ `CanceledError`, `UnknownError`, `InvalidArgumentError`, `DeadlineExceededError`, `NotFoundError`, `AlreadyExistsError`, `PermissionDeniedError`, `ResourceExhaustedError`, `FailedPreconditionError`, `AbortedError`, `OutOfRangeError`, `UnimplementedError`, `InternalError`, `UnavailableError`, `DataLossError`, `UnauthenticatedError`.
100
+ `error.message` is prose for people. What a program branches on, beside the class, is
101
+ `error.detail`: `ProjectBusy`, `ProjectChanged`, `MachineUnreachable`, `NoMachine`, or `None`.
102
+
103
+ ```python
104
+ from pethost import NotFoundError, Pethost, PethostError
105
+
106
+ with Pethost() as pethost:
107
+ try:
108
+ project = pethost.get_project("notes").project
109
+ except NotFoundError as error:
110
+ print(error.message) # No such project: the message lists the ones there are.
111
+ except PethostError as error: # Any other code.
112
+ print(type(error).__name__, error.message, error.detail)
113
+ ```
114
+
115
+ A wrong argument the SDK sees itself, such as two members of one oneof, is Python's own
116
+ `TypeError`, `ValueError` or `OverflowError`, raised before anything is sent.
117
+
118
+ ## Links
119
+
120
+ - [The API's reference](https://pethost.dev/docs/api/): every call, message and field.
121
+ - [The panel](https://console.pethost.dev): your machine, your projects and your API tokens.
122
+ - [pethost.dev](https://pethost.dev): what Pethost is and what it costs.
123
+
124
+ ## Docker Compose hosting at one flat price
125
+
126
+ Pethost is managed hosting for Docker Compose projects. A subscription rents one virtual machine
127
+ that only your account uses. Pethost's software on it deploys your projects, gives them HTTPS
128
+ addresses, keeps their request logs and backs them up every night. You run it through your
129
+ agent or from a web panel: both show the same projects, logs and requests.
130
+
131
+ - **A machine of your own:** nobody else's projects on it. No cold starts, nothing sleeps.
132
+ Security updates install themselves.
133
+ - **HTTPS addresses:** anything.yourname.pethost.app at once, or your own domain with one DNS
134
+ record. Certificates renew themselves. A password page in front of the whole site: one
135
+ sentence to your agent.
136
+ - **Deploys from GitHub:** every push deploys itself, and an earlier commit is one step back.
137
+ - **Request logs:** every request with its status and time, the busiest paths and the error
138
+ rate, kept for 30 days.
139
+ - **Nightly backups:** encrypted, stored off the machine, kept for 14 days.
140
+ - **SSH and SFTP** into any container, and a terminal in the panel.
141
+ - **Docker Compose, as written:** a project is a Compose file, and the same file runs anywhere
142
+ else Docker does. A database is one more service in it, at no extra cost.
143
+ - **In the EU:** your data lives on your machine, and requests to your sites go straight to
144
+ it, never through our panel.
145
+
146
+ **Pricing.** Starter is €9.99 a month for 2 vCPU, 3 GB of memory and 30 GB of SSD. Grow is
147
+ €17.99 for 4 vCPU, 6 GB and 60 GB. Prices are without VAT. As many projects, containers and
148
+ databases as fit: nothing is metered, and nothing is billed on top. There is no free tier.
149
+ [See the plans](https://pethost.dev/#pricing).
150
+
151
+ **Who it is for.** Solo developers and early startups who host several projects, bots or small
152
+ apps and want one fixed monthly bill, and people who build with an AI agent and want it to
153
+ deploy and run what it wrote. It is not for large teams whose applications need several regions
154
+ or autoscaling: the machine is the limit.
155
+
156
+ ## How Pethost compares
157
+
158
+ | If you use | The difference |
159
+ |---|---|
160
+ | [Heroku](https://pethost.dev/about/#heroku), [Render](https://pethost.dev/about/#render), [DigitalOcean App Platform](https://pethost.dev/about/#digitalocean) | There each app, worker and database is one more line on the bill. On Pethost one flat price covers the whole machine: as many projects and databases as fit, and nothing sleeps. |
161
+ | [Railway, Fly.io](https://pethost.dev/about/#railway), [Koyeb](https://pethost.dev/about/#koyeb) | There CPU, memory and traffic are metered, so the bill moves with every busy month. On Pethost the machine is the limit: nothing is metered, nothing is billed on top. |
162
+ | [Vercel, Netlify](https://pethost.dev/about/#vercel) | Made for front ends and serverless functions: a bot, a long-running worker or a database is another service with its own price. Pethost runs the front end, the back end and the database on one machine. |
163
+ | [Coolify, Dokploy](https://pethost.dev/about/#coolify), [CapRover, Dokku, Easypanel](https://pethost.dev/about/#caprover) | Self-hosted: the server is yours to rent, update, secure and back up. Pethost is the machine and the panel together, looked after for you, and agents are first-class users, not an add-on. |
164
+ | [Sliplane](https://pethost.dev/about/#sliplane) | The closest: a flat price per server. There a Compose file is converted into its own services; Pethost runs a Compose project as written. |
165
+ | [Replit](https://pethost.dev/about/#replit) | You build and publish inside Replit, with its own agent. Pethost works with the agent you already use, and one flat price covers all your apps. |
166
+ | [PythonAnywhere](https://pethost.dev/about/#pythonanywhere) | Python only, no Docker. Pethost runs anything Docker runs, in any language. |
167
+ | [A VPS you set up yourself](https://pethost.dev/about/#vps) | The server is the cheap part. You still set up the proxy, DNS, certificates, backups and updates yourself, and fix them when they break. Pethost is the server with all of that done. |
168
+
169
+ [About Pethost](https://pethost.dev/about/) has each comparison in full, with prices.
170
+
171
+ ## Questions
172
+
173
+ **Which AI agents does Pethost work with?**
174
+ Almost any agent that supports skills and MCP. The ones we tested ourselves: Claude Code, Codex,
175
+ Cursor, ChatGPT, Gemini CLI, OpenClaw, Hermes and Pi.
176
+
177
+ **What can I deploy?**
178
+ Anything that runs in Docker: web apps, APIs, bots, workers, databases. No Dockerfile? With the
179
+ plugin installed, your agent knows the details and writes it for you.
180
+
181
+ **Do I need an agent?**
182
+ No. The web panel does the same, and shows the same projects, logs and requests.
183
+
184
+ **Can I use my own domain?**
185
+ Yes. One DNS record, and the certificate comes by itself.
186
+
187
+ **Is there a free tier?**
188
+ No: €9.99 rents a real machine, so nothing sleeps. Cancel any time:
189
+ [refunds and cancellation](https://pethost.dev/refunds/) has the rules.
190
+