@oxy-hq/cli 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +256 -10
- package/dist/main.mjs +3246 -365
- package/dist/main.mjs.map +1 -1
- package/dist/mcp-D5FFpqAw.mjs +902 -0
- package/dist/mcp-D5FFpqAw.mjs.map +1 -0
- package/json-schemas/agentic.json +1 -1
- package/json-schemas/flow-test.json +3 -3
- package/package.json +4 -4
- package/skills/oxy-cli/SKILL.md +23 -0
- package/skills/oxy-custom-apps/SKILL.md +98 -0
- package/dist/mcp-CIsyezzU.mjs +0 -316
- package/dist/mcp-CIsyezzU.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -5,8 +5,10 @@ manages customer workspace repos.
|
|
|
5
5
|
|
|
6
6
|
- **API client** — `api`, `routes`, `schema`, `openapi`, `login`, `whoami`, `assume`, `oltp`
|
|
7
7
|
- **Customer workspaces** — `list`, `new`, `import`, `doctor`, `update`, `adopt`, `launch`
|
|
8
|
-
- **Custom apps** — `publish`, `init-ci`, `proxy`
|
|
8
|
+
- **Custom apps** — `publish`, `init-ci`, `proxy`, `apps`
|
|
9
9
|
- **Checks** — `checks run`
|
|
10
|
+
- **Sandboxes** — `env`, `fn call`, `invocations`, `logs`
|
|
11
|
+
- **Workspace previews** — `preview`
|
|
10
12
|
- **Development** — `validate`, `mcp`, `guide`, `skills`
|
|
11
13
|
|
|
12
14
|
## Install
|
|
@@ -77,7 +79,10 @@ Credentials are stored **per deployment**, and the default is production. A
|
|
|
77
79
|
oxyc api <path> [flags]
|
|
78
80
|
```
|
|
79
81
|
|
|
80
|
-
`<path>` is relative to `/api`; a leading `/` or `api/` is accepted.
|
|
82
|
+
`<path>` is relative to `/api`; a leading `/` or `api/` is accepted. One
|
|
83
|
+
exception: `customer-apps/…` is sent as written, because `/customer-apps/<org>/<app>/…`
|
|
84
|
+
is where an app's bundle is served. The app registry API is `api/customer-apps/…`
|
|
85
|
+
— spell the `api/` out for it (a 404 on the bare form says so).
|
|
81
86
|
|
|
82
87
|
| Flag | Meaning |
|
|
83
88
|
| --- | --- |
|
|
@@ -111,9 +116,10 @@ the server.
|
|
|
111
116
|
`oxyc login`; `/external/api/**` sends `X-API-Key` from `$OXY_API_KEY`.
|
|
112
117
|
|
|
113
118
|
**`--paginate` is a heuristic.** Oxy sends `Link: rel="next"` on some endpoints
|
|
114
|
-
and nothing on others; where there is no header, `oxyc` reads
|
|
115
|
-
`pagination.has_next`, then `has_more`,
|
|
116
|
-
|
|
119
|
+
and nothing on others; where there is no header, `oxyc` reads `next_offset`
|
|
120
|
+
(and asks again with `?offset=`), then `pagination.has_next`, then `has_more`,
|
|
121
|
+
then `page < total_pages` (asking again with `?page=`). Nothing recognised
|
|
122
|
+
means one page, and it warns when the server said nothing at all.
|
|
117
123
|
|
|
118
124
|
```bash
|
|
119
125
|
oxyc api {org}/workspaces --md
|
|
@@ -181,6 +187,8 @@ Staff can see and request an org's transactional Postgres — the store behind
|
|
|
181
187
|
```bash
|
|
182
188
|
oxyc oltp status [--org <slug|uuid|url>] [--json]
|
|
183
189
|
oxyc oltp provision --org <slug|uuid|url> --writer app:<slug> [--writer pipeline:<source> …] [--yes] [--json]
|
|
190
|
+
oxyc oltp provision --org <slug|uuid|url> --branch staging [--yes] [--json]
|
|
191
|
+
oxyc oltp reset --org <slug|uuid|url> --branch staging [--yes] [--json]
|
|
184
192
|
```
|
|
185
193
|
|
|
186
194
|
`status` lists every org, with a database or without; with `--org` it shows
|
|
@@ -194,6 +202,15 @@ derived the way the platform derives `ctx.oltp`'s schema (`app:store-ops` →
|
|
|
194
202
|
`raw_<source>`. A 404 can be an org outside your staff grant's scope, and an
|
|
195
203
|
active `assume` session closes `/admin`.
|
|
196
204
|
|
|
205
|
+
`--branch staging` also cuts the org's **staging branch**: one copy of the whole
|
|
206
|
+
database per org, which every app's staging environment writes to. It is made
|
|
207
|
+
only by this flag — never by a publish — and re-running it mints whatever a
|
|
208
|
+
writer added since the cut needs, without resetting anyone's data. `status`
|
|
209
|
+
shows its age and calls it stale past 30 days; nothing resets it on a timer.
|
|
210
|
+
`reset --branch staging` re-copies it from production, discarding every app's
|
|
211
|
+
staging data in the org, so it lists those apps and asks first (`--yes`
|
|
212
|
+
without a terminal).
|
|
213
|
+
|
|
197
214
|
## Customer workspaces
|
|
198
215
|
|
|
199
216
|
A customer **is** a GitHub repo carrying the `oxy-customer` topic. Tagging the
|
|
@@ -225,7 +242,7 @@ the current directory while granting access to the customer's repo.
|
|
|
225
242
|
## Custom apps
|
|
226
243
|
|
|
227
244
|
```bash
|
|
228
|
-
oxyc publish [--env <e>] [--dir <path>] [--promote] [--build-only | --prebuilt] [--json] [--allow-function-lint]
|
|
245
|
+
oxyc publish [--env <e>] [--dir <path>] [--promote] [--build-only | --prebuilt] [--json] [--allow-function-lint] [--app-env <dev-handle>]
|
|
229
246
|
oxyc init-ci [--app <org>/<app>] [--environment <name>] [--force]
|
|
230
247
|
oxyc proxy [--port <n>] [--allow-writes] [--allow-events] [--yes]
|
|
231
248
|
```
|
|
@@ -277,6 +294,104 @@ OIDC. `--promote` makes that publish go live and adds a `checks run` step after
|
|
|
277
294
|
it, when the manifest declares a check. It prints the `oxyc api …/publishers`
|
|
278
295
|
call that registers the workflow.
|
|
279
296
|
|
|
297
|
+
**`--app-env <dev-handle>`** moves one sandbox's build pointer instead of the
|
|
298
|
+
draft/live channel — see [Sandboxes](#sandboxes). It needs a staff credential
|
|
299
|
+
(never a publish token or OIDC) and is refused together with `--promote`: a
|
|
300
|
+
sandbox build is never promoted, so the loop is publish to the sandbox,
|
|
301
|
+
iterate, then publish the same tree to staging and promote that.
|
|
302
|
+
|
|
303
|
+
## Apps
|
|
304
|
+
|
|
305
|
+
Read-only: every request these make is a GET, against `/api/customer-apps/**`
|
|
306
|
+
(the app-admin role). `<app>` is `<org-slug>/<app-slug>` or an app UUID.
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
oxyc apps list [--org <slug>] [--published | --draft] [--builds] [--json]
|
|
310
|
+
oxyc apps show <app> [--json]
|
|
311
|
+
oxyc apps builds <app> [--json]
|
|
312
|
+
oxyc apps health [<app>] [--needs-attention] [--json]
|
|
313
|
+
oxyc apps usage <app> [--json]
|
|
314
|
+
oxyc apps drift [<app>] [--org <slug>] [--dir <path>] [--refresh] [--json]
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
- **`list`** — every app you can see, across organizations, walking the paged
|
|
318
|
+
registry to its end. `STATE` is `live` when the app has a published build and
|
|
319
|
+
`draft` when it has none. `SOURCE` is the repository the app is *registered*
|
|
320
|
+
against. `--builds` adds the live build's id, the repository and commit it was
|
|
321
|
+
built from, who published it and when — one extra request per app, six at a
|
|
322
|
+
time.
|
|
323
|
+
- **`show`** — one app on one screen: the registry row, the live build, the
|
|
324
|
+
draft build when it is newer than the live one, deployment integrity,
|
|
325
|
+
availability, and the 7-day usage summary. `last promote` is when the promote
|
|
326
|
+
or rollback action was last used; `oxyc publish --promote` does not update it,
|
|
327
|
+
so it can be older than the live build.
|
|
328
|
+
- **`builds`** — the build history, newest first. `CHANNEL` marks the build each
|
|
329
|
+
channel points at: `live`, `draft`, or both for one build.
|
|
330
|
+
- **`health`** — with no argument, the fleet table (published apps only):
|
|
331
|
+
`down`, `degraded`, `not_measured`, `quiet` or `operational` per app, with the
|
|
332
|
+
totals on stderr. `--needs-attention` keeps the first three. With `<app>`: the
|
|
333
|
+
deployment-integrity checks, the availability windows, and the browser errors
|
|
334
|
+
of the last 24 hours.
|
|
335
|
+
- **`usage`** — the 7-day summary, the visitors, and the tracked events by name.
|
|
336
|
+
- **`drift`** — see below.
|
|
337
|
+
|
|
338
|
+
Times are UTC. `--json` prints one document on stdout; a table goes to stdout and
|
|
339
|
+
the count line to stderr.
|
|
340
|
+
|
|
341
|
+
**An empty result and a failed request are different answers.** No apps, no
|
|
342
|
+
builds, no errors recorded: the command says so and exits `0`. A request that
|
|
343
|
+
failed exits with the code its status maps to (`4`, `5`, `7`, …). Where a
|
|
344
|
+
command makes several independent requests (`show`, `health <app>`,
|
|
345
|
+
`list --builds`, `drift`), it prints what it did read, marks what it did not as
|
|
346
|
+
`NOT READ` (`"failed": […]` / `live_build_error` in `--json`), and then exits
|
|
347
|
+
non-zero. These commands report state: a failing health check, a `down` app or
|
|
348
|
+
a drifted app is an answer and exits `0` — read it from the output.
|
|
349
|
+
|
|
350
|
+
The health route answers **503 with its report** when a check fails; `oxyc`
|
|
351
|
+
prints that as a failing report, not as an outage.
|
|
352
|
+
|
|
353
|
+
### `apps drift`
|
|
354
|
+
|
|
355
|
+
Compares what is live against source on **this machine**. For each app it takes
|
|
356
|
+
the live build's recorded repository and commit, finds a local checkout of that
|
|
357
|
+
repository (the ones `oxyc repos` and `oxyc path` report, or `--dir`), finds the
|
|
358
|
+
app's directory by the `oxy-app.json` whose `slug` and `orgSlug` match — at
|
|
359
|
+
`<app>/oxy-app.json` or `<app>/public/oxy-app.json`, never by folder name — and
|
|
360
|
+
counts the commits on the checkout's **current branch** that touch that
|
|
361
|
+
directory after the published commit.
|
|
362
|
+
|
|
363
|
+
| Result | Meaning |
|
|
364
|
+
| --- | --- |
|
|
365
|
+
| `in sync` | no commit on the current branch touches the app directory after the published commit |
|
|
366
|
+
| `N commits ahead` | that many do; they are listed |
|
|
367
|
+
| `unknown — <reason>` | the comparison could not be made |
|
|
368
|
+
|
|
369
|
+
`unknown` is never reported as `in sync`. Its reasons (`reason` in `--json`):
|
|
370
|
+
|
|
371
|
+
| `reason` | |
|
|
372
|
+
| --- | --- |
|
|
373
|
+
| `not_published` | nothing is live |
|
|
374
|
+
| `source_unrecorded` | the live build records no repository or no commit |
|
|
375
|
+
| `repo_not_checked_out` | the repository is not on this machine — clone it, or pass `--dir` |
|
|
376
|
+
| `commit_not_in_checkout` | the checkout does not have the published commit — `git fetch` there |
|
|
377
|
+
| `app_dir_not_found` | no tracked `oxy-app.json` declares this `slug` and `orgSlug` |
|
|
378
|
+
| `app_dir_ambiguous` | more than one does |
|
|
379
|
+
| `commit_not_on_branch` | the published commit is not an ancestor of the checked-out branch |
|
|
380
|
+
| `working_tree_dirty` | the app directory has uncommitted or untracked files |
|
|
381
|
+
| `git_failed` | `git log` or `git status` failed in the checkout, so the comparison could not be read |
|
|
382
|
+
| `request_failed` | the builds request failed (the command then exits non-zero) |
|
|
383
|
+
|
|
384
|
+
It runs read-only git commands and nothing else: it does not fetch, check out,
|
|
385
|
+
or refresh the index. The answer is therefore about the checkout as it is on
|
|
386
|
+
disk — a branch that is behind its remote reports fewer commits than the remote
|
|
387
|
+
has. With no `<app>`, every published app is compared, and `--dir` applies to
|
|
388
|
+
the apps whose source repository is that checkout's `origin`; with `<app>`,
|
|
389
|
+
`--dir` is used whatever its remote is.
|
|
390
|
+
|
|
391
|
+
An app published to two organizations from one directory (a staging org and a
|
|
392
|
+
production org) matches the manifest for only one of them; the other reports
|
|
393
|
+
`app_dir_not_found` and names the manifest it found with the other `orgSlug`.
|
|
394
|
+
|
|
280
395
|
## Checks
|
|
281
396
|
|
|
282
397
|
```bash
|
|
@@ -331,7 +446,12 @@ it admitted any function.
|
|
|
331
446
|
the execution alike. So `checks run` after a plain `oxyc publish` verifies the
|
|
332
447
|
*previously promoted* code, not the draft just uploaded. `oxyc init-ci` writes
|
|
333
448
|
the step only with `--promote`, where the build just published is the one the
|
|
334
|
-
check runs, and only when the manifest declares a check.
|
|
449
|
+
check runs, and only when the manifest declares a check. **With `--app-env`**
|
|
450
|
+
it runs against that environment's own build instead — a sandbox's own
|
|
451
|
+
publish, or staging's — and the report gains `environment` and each check's
|
|
452
|
+
`invocationId`; the publish-token and OIDC paths are unchanged and work only
|
|
453
|
+
against production, since every non-production operation needs a staff
|
|
454
|
+
credential (see [Sandboxes](#sandboxes)).
|
|
335
455
|
|
|
336
456
|
With a publish token, `<app>` must be the **UUID** — resolving a slug means
|
|
337
457
|
listing every app, which such a token may not do. The OIDC path needs no id at
|
|
@@ -346,6 +466,119 @@ expired 90-day API key reads this way, not as a missing one); `2` a bad
|
|
|
346
466
|
the deployment answered the OIDC exchange without an `app_id`, meaning it
|
|
347
467
|
predates trusted checks.
|
|
348
468
|
|
|
469
|
+
## Sandboxes
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
oxyc env create <app> <name> # name is dev-<handle>, 1-12 chars a-z0-9-
|
|
473
|
+
oxyc env list <app>
|
|
474
|
+
oxyc env show <app> <name>
|
|
475
|
+
oxyc env delete <app> <name> [--yes] [--wait [seconds]]
|
|
476
|
+
|
|
477
|
+
oxyc publish --app-env <name> [--env <e>] # see "Custom apps" above
|
|
478
|
+
oxyc fn call <app> <function> [--app-env <name>] [--data <json|@file|->]
|
|
479
|
+
oxyc checks run <app> --app-env <name> # see "Checks" above
|
|
480
|
+
|
|
481
|
+
oxyc invocations list <app> [--app-env] [--build] [--function] [--limit]
|
|
482
|
+
oxyc invocations held <app> <invocation-id>
|
|
483
|
+
oxyc logs <app> [--app-env] [--invocation] [--request] [--hours] [--limit]
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
A **sandbox** is a named, short-lived `dev-<handle>` environment of one custom
|
|
487
|
+
app: its own build pointer, storage silo, secrets, Airhouse sibling and — in
|
|
488
|
+
an org with an OLTP staging branch — its own copy of the app's database, with
|
|
489
|
+
reads hitting production and most writes either isolated or *held* (recorded,
|
|
490
|
+
not performed — see `invocations held`). It starts with no build, is deleted
|
|
491
|
+
explicitly or after 7 idle days, and an app has at most 20. Full contract,
|
|
492
|
+
including what is **not** isolated (`ctx.warehouse`) and the other gaps:
|
|
493
|
+
`internal-docs/custom-app-sandboxes.md`.
|
|
494
|
+
|
|
495
|
+
`ctx.oltp` in a sandbox runs in a schema of its own (`app_<app>__dev_<handle>`)
|
|
496
|
+
inside the org's staging branch. `publish --app-env` queues it: a copy of
|
|
497
|
+
staging's tables (rows up to a size cap), then the build's OLTP migrations.
|
|
498
|
+
`env show` reports it as `oltp_schema` — `status` is `seeding`, `ready`,
|
|
499
|
+
`failed` (with `error`) or `stale` (the branch was reset; publish again), and
|
|
500
|
+
`structure_only` lists the tables copied empty. Until it is `ready` a
|
|
501
|
+
`ctx.oltp` call in the sandbox is refused with a message that says which.
|
|
502
|
+
|
|
503
|
+
The loop: `env create` → `publish --app-env` → `fn call` / `checks run
|
|
504
|
+
--app-env` → `invocations list` / `held` to read back what ran → iterate from
|
|
505
|
+
`publish` → `env delete --yes --wait` when done. `oxyc guide` has the same six
|
|
506
|
+
lines, meant to sit in an agent's context.
|
|
507
|
+
|
|
508
|
+
**`--app-env <environment>`** (`production`, `staging` or `dev-<handle>`,
|
|
509
|
+
validated client-side — exit `2` on a malformed name) is a *different axis*
|
|
510
|
+
from `--env`, which is the deployment: both can appear on the same command
|
|
511
|
+
(`oxyc fn call acme/store f --env dev --app-env dev-a1`). It is not a global
|
|
512
|
+
flag — only `publish`, `fn call`, `checks run`, `invocations list` and `logs`
|
|
513
|
+
take it. A publish-token credential is refused before any request for
|
|
514
|
+
`--app-env` other than `production` (exit `2`); `env`, `invocations` and
|
|
515
|
+
`logs` refuse one outright, for any environment, because sandbox management
|
|
516
|
+
is a staff console surface.
|
|
517
|
+
|
|
518
|
+
**`env delete`** without `--yes` asks on a terminal and exits `8` (refused)
|
|
519
|
+
off one, same as `oltp reset`. `--wait [seconds]` (default 120) polls until
|
|
520
|
+
the teardown finishes and prints `{"name","status":"deleted"}`; past the
|
|
521
|
+
deadline it exits `7` (retryable) rather than hanging.
|
|
522
|
+
|
|
523
|
+
**`fn call`** POSTs directly to `{target}/customer-apps/{org}/{app}/fn/{name}`
|
|
524
|
+
(no `/api`) — the response is Server-Sent Events, not JSON, so `oxyc` parses
|
|
525
|
+
the `log` / `data` / `done` / `error` frames itself. It exits `0` only when
|
|
526
|
+
the stream ends `done` with a 2xx status; a function that threw, or answered a
|
|
527
|
+
non-2xx, is a function-level failure (exit `1`, `ok: false` in the JSON), kept
|
|
528
|
+
distinct from a non-2xx on the POST itself (exit per the usual status mapping
|
|
529
|
+
— e.g. `EnvironmentHasNoBuild` before the stream starts). The
|
|
530
|
+
`x-oxy-invocation-id` response header becomes `invocationId` in the result.
|
|
531
|
+
|
|
532
|
+
**`invocations held`** is what the non-production write policy did *not* do —
|
|
533
|
+
production's would-be effect, recorded rather than performed. It is `[]` for a
|
|
534
|
+
production invocation, since nothing is held there.
|
|
535
|
+
|
|
536
|
+
## Workspace previews
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
oxyc preview create <branch> [--wait [seconds]] [--json]
|
|
540
|
+
oxyc preview list [--json]
|
|
541
|
+
oxyc preview show <branch> [--json]
|
|
542
|
+
oxyc preview delete <branch> [--yes] [--json]
|
|
543
|
+
oxyc preview checks <branch> [--json]
|
|
544
|
+
|
|
545
|
+
oxyc preview run <branch> <kind> <ref> [--variables <json|@file|->] [--read-live-only]
|
|
546
|
+
[--window-from <iso>] [--window-to <iso>] [--resource <name>...]
|
|
547
|
+
[--wait [seconds]] [--json]
|
|
548
|
+
oxyc preview runs list <branch> [--json]
|
|
549
|
+
oxyc preview runs show <run-id> [--wait [seconds]] [--json]
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
A **preview** opens a workspace branch on the real product, against real data,
|
|
553
|
+
without the branch being live — staff only. `create` compiles the branch's
|
|
554
|
+
head into a staging revision (or reuses a ready one for that commit) and is
|
|
555
|
+
idempotent; `--wait [seconds]` (default 120) blocks until the compile is
|
|
556
|
+
`ready` or `failed` instead of returning the `compiling` item the request
|
|
557
|
+
itself answers with, and exits `7` (retryable) past the deadline. There is no
|
|
558
|
+
single-preview route: `show` fetches `list` and filters it client-side, so its
|
|
559
|
+
`5` (not found) is synthesized here, not a literal 404.
|
|
560
|
+
|
|
561
|
+
The loop: `preview create --wait` → `preview checks` → `preview run` →
|
|
562
|
+
`preview runs show --wait` → iterate → `preview delete --yes` when done.
|
|
563
|
+
|
|
564
|
+
**`<kind>`** is `procedure` or `airway_sample` — the only two `POST
|
|
565
|
+
/previews/runs` accepts (exit `2` client-side on anything else, naming the
|
|
566
|
+
read-back verb). `transform_build` and `compare` runs are queued by the
|
|
567
|
+
server's own Airway change check, never started here; `preview runs list`
|
|
568
|
+
surfaces them alongside the kinds you *can* start, and `preview runs show
|
|
569
|
+
<run-id> --wait` reads any of the four back — a procedure's held steps, a
|
|
570
|
+
transform build's or compare's outcome, or a sample's ask and result.
|
|
571
|
+
`--variables` / `--read-live-only` are `procedure`-only; `--window-from` /
|
|
572
|
+
`--window-to` / `--resource` (repeatable) are `airway_sample`-only.
|
|
573
|
+
|
|
574
|
+
Every verb needs `{workspace}` resolved — `--workspace <id>`, exactly the way
|
|
575
|
+
`oxyc api {workspace}/...` resolves it; there is no second workspace
|
|
576
|
+
resolver. A deployment with `OXY_PREVIEW_RUNS` off answers every runs route
|
|
577
|
+
`404 preview_runs_disabled`, surfaced the same way any other server refusal
|
|
578
|
+
is: the server's own `code` rides along on the thrown error, and the exit
|
|
579
|
+
class follows the usual HTTP-status mapping (`400`/`409` → `6`, `404` → `5`).
|
|
580
|
+
Full contract: `internal-docs/workspace-previews.md`.
|
|
581
|
+
|
|
349
582
|
## Development commands
|
|
350
583
|
|
|
351
584
|
```bash
|
|
@@ -424,9 +657,22 @@ production target (any host under `oxygen-hq.com`) is refused without `--yes`.
|
|
|
424
657
|
Each Oxy Function call carries a W3C trace — the SDK's, or one minted here — and
|
|
425
658
|
prints `↳ <status> fn <name> request_id=… trace_id=…`.
|
|
426
659
|
|
|
427
|
-
**`mcp`** serves the API over stdio as four tools — `oxy_routes`,
|
|
428
|
-
`oxy_request`, `oxy_whoami` — rather than one per endpoint, so
|
|
429
|
-
cost ~2 KB per turn and reach endpoints added after this
|
|
660
|
+
**`mcp`** serves the API over stdio as four generic tools — `oxy_routes`,
|
|
661
|
+
`oxy_schema`, `oxy_request`, `oxy_whoami` — rather than one per endpoint, so
|
|
662
|
+
those schemas cost ~2 KB per turn and reach endpoints added after this
|
|
663
|
+
package shipped. Two named exceptions trade that minimalism for validation an
|
|
664
|
+
agent needs to drive a loop unsupervised: the **sandbox loop**
|
|
665
|
+
(`oxy_env_create`/`list`/`show`/`delete`, `oxy_publish_sandbox`,
|
|
666
|
+
`oxy_fn_call`, `oxy_checks_run`, `oxy_invocations_list`/`held`, `oxy_logs`)
|
|
667
|
+
and **workspace previews** (`oxy_preview_create`/`list`/`show`/`delete`/
|
|
668
|
+
`checks`/`run`/`runs_list`/`run_show`). Each tool calls its CLI verb's own
|
|
669
|
+
request-building function, so a tool's result is the same JSON document that
|
|
670
|
+
verb's `--json` prints, and a failure carries the server's own error code
|
|
671
|
+
plus the exit-code class (`[exit 5 NOT_FOUND]`) the way `oxyc`'s exit code
|
|
672
|
+
would. `oxy_env_delete` / `oxy_preview_delete` need `confirm: true` (there is
|
|
673
|
+
no terminal to ask on inside an MCP server), and `oxy_publish_sandbox`
|
|
674
|
+
requires a `dev-<handle>` `appEnv` and refuses production, staging or a
|
|
675
|
+
promote client-side — it can never reach the live channel.
|
|
430
676
|
|
|
431
677
|
```bash
|
|
432
678
|
claude mcp add oxyc -- npx -y @oxy-hq/cli mcp --env production
|