Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
31 changes: 31 additions & 0 deletions .github/workflows/cli-distribution-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,37 @@ jobs:
python3 -m pip install --require-hashes --only-binary=:all: -r cli/ci/requirements-test.txt
cd cli/bun
bun install --frozen-lockfile --ignore-scripts
- name: Check the public surface
# prose-cli is a public user client: no internal service detail or
# developer-only surface in tracked files, release help or binaries.
# Same check as the public-surface gate in cli/ci/run_local.py.
if: matrix.os == 'ubuntu-22.04'
run: |
python3 -m unittest discover -s cli/ci -p test_check_public_surface.py
python3 cli/ci/check_public_surface.py --build-release
- name: Check hosted service parity between the Rust and Bun ports
# One shared corpus drives both ports through the test-seam fixture
# transport; no network. Same checks as the service-* and
# registry-service-* gates in cli/ci/run_local.py.
if: matrix.os == 'ubuntu-22.04'
run: >-
python3 cli/ci/run_local.py
--only shared-contracts
--only service-operations-corpus
--only service-coverage
--only service-help
--only service-operations-rust-build
--only service-operations-rust
--only registry-service-rust
--only service-operations-bun-build
--only service-operations-bun
--only registry-service-bun
- name: Build and test the developer endpoint build
# The dev-endpoint cargo feature is never in a public build; keep it
# compiling and tested. Same checks as the rust-build-dev-endpoint and
# rust-tests-dev-endpoint gates in cli/ci/run_local.py.
if: matrix.os == 'ubuntu-22.04'
run: python3 cli/ci/run_local.py --only rust-build-dev-endpoint --only rust-tests-dev-endpoint
- name: Test distribution plan adapter
run: |
python3 -m unittest discover -s cli/conformance/runner -p test_runner.py
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ Exact admitted versions and platforms are checked at readiness; see the product

Native Claude delegation is available through the opt-in `claude-workspace-tools` native profile. It uses nonbare mode with explicit tools, separate caller-supplied permission rules and directory access, and fresh native configuration for API authentication. The default API profile retains its bare/tool coupling. Native task progress and completion are transported without interpreting their purpose.

## OpenProse service

`prose cli` is also a user client for the hosted OpenProse service: sign in with `prose cli auth login` (or set `OPENPROSE_API_KEY`), then quote, submit, watch and download hosted runs, and manage programs, results, jobs, the wallet and organizations. Public builds talk only to the production service. Start with `prose cli service triage --json`; see [the service client guide](docs/hosted-service-client.md).

## Development and provenance

[Build Rust](cli/rust/README.md) 路 [Build Bun](cli/bun/README.md) 路 [Native output semantics](docs/native-output.md) 路 [Native task events](docs/native-task-events.md)
Expand Down
84 changes: 84 additions & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,90 @@ the tagged release.
authentication boundaries.
- Provider-free package admission and opt-in, cost-acknowledged live transport
evidence for the nonsemantic `echo-v0` image.
- OpenProse hosted service commands in both products:
`cli service status|triage|capabilities|operations|guide`, `cli model list`,
`cli example list|show`, `cli repo list`,
`cli run quote|submit|watch|input|cancel|list|show|download|share`,
`cli program list|show|save|visibility|delete|revisions|draft`,
`cli result list|show|publish|unpublish`, `cli job 鈥,
`cli wallet balance|events|usage|redeem|topup` and `cli org 鈥 (no
organization deletion). One embedded manifest
(`shared/service/operations.v1.json`, printed by `cli service operations`)
drives parsing, help, confirmation and transport limits. Every command emits
versioned JSON or JSONL and never prompts. Commands that spend money, publish
outward, delete or cannot be undone require `--yes`, and `--preview` shows
the planned request without sending it. The service commands talk only to
the production OpenProse service.
- Hosted runs always use a live session that is journaled before submission,
recover from a duplicate submission, and detach on Ctrl-C or the deadline.
Only `cli run cancel --yes` cancels. New taxonomy codes include
`HOSTED_RUN_DETACHED` (exit 21), `HOSTED_RUN_FAILED` and
`RUN_SUBMISSION_AMBIGUOUS` (exit 22), `HOSTED_RUN_CANCELLED` (exit 24),
`CONFIRMATION_REQUIRED`, `SERVICE_RESOURCE_NOT_FOUND` and
`GITHUB_LINK_REQUIRED`.
- `cli service status` reports reachability and the models you can use;
`cli service triage` reports the service, credential, wallet, organization,
recent runs and jobs with next commands.
- Customer-facing results carry prices only; human output shows money in
dollars. Result schemas refuse any property whose name matches `cost`.
- Help and the agent guide: `prose --help` lists the hosted command groups,
every command and group has `--help` with examples and exit codes (including
`cli auth`, `cli org list` and `cli package`), and `cli --help` lists the
everyday groups first. `cli service guide` covers a first program, a daily
job, scripting, pricing, headless keys and sharing.
- `SERVICE_AUTH_REQUIRED` names `credentialSource`, `credentialVariable` and
`credentialProblem` in `details`.
- On Linux, the Rust product stores credentials through `secret-tool` in the
same item the Bun product uses.
- `cli model list` shows each model's status when the service sends a
`catalog`: the models you can run, premium models that unlock with any wallet
top-up (with the service's summary and a top-up preview) and older ids still
accepted with the model to use instead. `--json` adds `result.catalog`
(`id`, `status`, `tier`, `summary`, `successor` only).
- A premium model refused before a top-up (402 `paid_top_up_required`, or 403
`paid_model_required` from older servers) is `SERVICE_PREMIUM_MODEL_LOCKED`
(exit 10) with the model's summary in `details.reason`, a
`cli wallet topup --amount-cents 500 --preview` Action and
`details.suggestedArgv`.

### Breaking

- Service environment selection is removed. Every account, organization,
package and service command reaches the production OpenProse service with
`OPENPROSE_API_KEY` or the stored production credential.
- `cli environment show`, `cli environment use` and `cli environment reset`
are gone and fail with `INVOCATION_INVALID` (exit 2, unknown command).
- The global `--service-environment` option is gone. Placed before `cli`, it
fails with `INVOCATION_INVALID` (exit 2) and says the option was removed.
- `OPENPROSE_STAGING_API_KEY` is no longer read.
- A saved `service_environment` key in the user `cli.toml` is ignored,
whatever its value. A user who had selected the alternate environment now
reaches production; check which credential is in use with
`prose cli auth status`.
- The `openprose.service-environment/1` schema
(`shared/schemas/service-environment.schema.json`) is deleted.
- `cli auth login|status|logout`, `cli org list` and `cli package
publish|fetch|list|withdraw` print the `openprose.service-operation/1`
envelope (`schema`, `operation`, `interaction`, `result`, `problem`, with
keys sorted) like every other service command, instead of the
`openprose.service-account/1`, `openprose.organization-list/1` and
`openprose.package-operation/1` documents. `operation` is the dotted
operation id (`auth.status`, `org.list`, `package.fetch`); the `environment`
member is gone. The schema files of those names now describe the envelope's
`result`: `authenticated` and `credentialSource` (whose stored-key value is
now `store`, not `os-credential-store`), `organizations`, and the package
receipt, page or withdrawal.
- A malformed API key (from `OPENPROSE_API_KEY` or the store) is
`SERVICE_AUTH_REQUIRED` with `details.credentialProblem: "malformed"`, not
`SERVICE_PROTOCOL_INVALID`; the exit code stays 10.
- A registry 404 in `cli package fetch|withdraw|list` is
`SERVICE_RESOURCE_NOT_FOUND` (exit 10, not retryable) naming the missing
package version or organization, not the retryable `SERVICE_UNAVAILABLE`.
- An invalid `cli package` reference, slug, version, `--sha256` or `--cursor`
value is `INVOCATION_INVALID` (exit 2) with the cause in `details.reason`,
not `CONFIG_INVALID`, and every invalid `cli package` invocation is reported
in the `openprose.service-operation/1` envelope.
- No npm package or release binary changes until the next published alpha.

### Compatibility and release boundary

Expand Down
46 changes: 46 additions & 0 deletions cli/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,51 @@ Do not skip a failed gate by loosening a version allowlist, changing evidence
in place, dropping failed trials, retrying without recording the attempt, or
using one product's output as the expected result for the other.

## Keep the client public and user-only

This repository is the public OpenProse user client. It is not developer
tooling for the hosted service. Public builds talk only to the production
OpenProse service, and nothing in this tree may name another service
deployment, a developer credential variable, internal feature flags,
deployment or runtime identities, or real run ids. The `public-surface` gate
enforces this:

```sh
python3 cli/ci/check_public_surface.py # tracked files only
python3 cli/ci/check_public_surface.py --build-release # plus both ports' release --help and the Rust binary strings
python3 cli/ci/run_local.py --only public-surface
```

Use neutral hosts such as `https://example.invalid` in tests and docs, and
short synthetic run ids such as `run_aaaaaaaaaaaaaaaa`.

The denylist (`cli/ci/public_surface_denylist.py`) writes out only generic
patterns. Named internal terms, feature flags and captured identifiers are
matched by salted digest, so the public file does not publish what it guards;
the plaintext list stays with the service maintainers. When the gate reports
an `internal service term`, reword the line rather than the denylist.

### Developer endpoint build

OpenProse developers who need to point the CLI at another service origin use a
separate developer build. The override is compiled out of every default and
release build, which ignore it entirely.

```sh
# Rust
cargo build --release --locked -p prose-cli --features dev-endpoint
# Bun (writes cli/bun/dist/prose-dev)
cd cli/bun && bun run build:dev
```

In a developer build only, `OPENPROSE_API_URL` (an `https` origin with no path,
query or credentials) replaces the production origin. The key is still
`OPENPROSE_API_KEY`, and `prose cli auth login` stores it under a
credential-store entry scoped to that origin, so it never overwrites your
production key. Human output is labeled `OpenProse (custom endpoint <origin>)`
and JSON envelopes report `"environment": "custom"`. Supply the origin at run
time; never commit one.

## Pull request checklist

- The change stays inside the CLI/language boundary.
Expand All @@ -235,6 +280,7 @@ using one product's output as the expected result for the other.
authentication assumptions.
- Evidence and release claims do not exceed the authority actually observed.
- No secret, private path, or raw provider response is present in the diff.
- The `public-surface` gate passes.

For the current implementation status and known blockers, read
`cli/protocol/STATUS.md`. For release construction and local package rehearsal,
Expand Down
75 changes: 55 additions & 20 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,21 @@ Release operators use the
[functional-alpha readiness contract](release/ALPHA_READINESS.md) to distinguish
candidate, promotion, and post-publication authority.

For the candidate service-account connection, see [Connect the CLI to staging](../docs/staging-account.md). The candidate registry commands below reuse that account connection; they do not enable hosted execution. Source implementation and hermetic fixtures do not establish deployment, release availability, or live qualification.
The `prose cli` account, registry and service commands connect to the hosted
OpenProse service. Source implementation and hermetic fixtures do not establish
release availability or live qualification.

## Registry package commands (candidate)

Package commands move bounded, data-only files through the selected OpenProse
account service. Production is the default. Select staging persistently when
working with its separate credentials, then inspect the selection:
Package commands move bounded, data-only files through your OpenProse account.
Sign in once, or set `OPENPROSE_API_KEY`:

```sh
prose cli environment use staging
prose cli environment show
prose cli auth login
prose cli package publish ./hello.md --organization example --name hello --version 1.0.0
prose cli package list example --json
prose cli package fetch example/[email protected] --output-dir ./hello-copy
prose cli package withdraw example/[email protected]
prose cli environment reset
```

A single file uses its basename as the default export and has no dependencies.
Expand Down Expand Up @@ -78,9 +76,9 @@ neither downloaded nor executed. File contents are not scanned for secrets.
See the [package byte format](shared/fixtures/registry/FORMAT.md) for exact path,
encoding, hash, and receipt rules.

Fetch obtains a receipt and canonical artifact from the same selected service,
then verifies artifact and file hashes, manifest, inventory, and canonical bytes
before writing. Supply `--sha256 <64-lowercase-hex-digest>` to require a known
Fetch obtains a receipt and canonical artifact from the service, then verifies
artifact and file hashes, manifest, inventory, and canonical bytes before
writing. Supply `--sha256 <64-lowercase-hex-digest>` to require a known
artifact identity. The output directory must be fresh, its parent must exist,
and its ancestors must not be symlinks. Existing destinations are never replaced.
The receipt is written as `.prose-package-receipt.json`.
Expand All @@ -94,14 +92,50 @@ Cleanup preserves content whose ownership no longer matches the operation.
These checks do not sandbox another process running with the same filesystem
privileges. Native platform qualification remains separate from fixture results.

All four commands accept trailing `--json` or global `--output json`. Reports
include the selected environment; staging human output is labeled. Use global
`--service-environment production|staging` before `cli` for a one-command override.
Only user configuration can persist the selection. Production and staging use
separate OS credentials and `OPENPROSE_API_KEY` / `OPENPROSE_STAGING_API_KEY`
respectively; switching never copies credentials. Public reads can be anonymous
when no credential is available, but malformed selected credentials fail closed.
Publish and withdraw require a credential. No command starts a model or harness.
All four commands accept trailing `--json` or global `--output json`. The key
comes from `OPENPROSE_API_KEY` when it is set, otherwise from the OS credential
store written by `prose cli auth login`. Public reads can be anonymous when no
credential is available, but a malformed credential fails closed. Publish and
withdraw require a credential. No command starts a model or harness.

## OpenProse service commands

The `cli` service commands are a thin, noninteractive client of the hosted
OpenProse service (overview in
[the service client guide](../docs/hosted-service-client.md)). They use the same
account connection as the registry commands above. Unlike every other command
in this README, `cli run submit` starts a hosted model run and spends from your
wallet.

```sh
prose --output json cli service status
prose --output json cli service operations # every command, option, exit code
prose --output json cli wallet balance
prose --output json cli program save hello hello.prose.md
prose --output json cli run quote
prose --output jsonl cli run submit hello.prose.md --yes
prose --output jsonl cli run watch <run-id> --after 0
prose --output json cli run download <run-id> --output-dir ./out
```

`cli service operations` prints the embedded operation manifest. That manifest
drives parsing, help, confirmation, and transport limits in both products, so
it is the complete machine-readable reference. Every command emits
`openprose.service-operation/1` JSON, or `openprose.service-event/1` JSONL lines
ending in exactly one terminal line, and never prompts. Commands that spend
money, publish outward, delete, or cannot be undone stop with
`CONFIRMATION_REQUIRED` (exit 2), which shows the planned request, until you
repeat them with `--yes`. `--preview` shows that plan without sending anything.
Results show prices only.

A submitted run is journaled before it is sent, and `run watch`, `input`, and
`cancel` use that local journal's live session (or `--session UUID`); a run
started elsewhere can still be read with `run show`. `--detach` returns as soon
as the run id is known. Ctrl-C (`HOSTED_RUN_DETACHED`) and the `--wait`
deadline, 30 minutes by default (`SERVICE_WATCH_DEADLINE`), both exit 21 and
leave the run going; their `details.resumeArgv` is the exact command that
resumes watching. Only `cli run cancel <run-id> --yes` cancels. Organization
deletion and browser-only flows are not available.

## First five minutes

Expand Down Expand Up @@ -413,8 +447,9 @@ independent harness and hosted fixtures, Rust and Bun suites, differential
black-box behavior, process settlement, architecture/dependency boundaries,
deterministic dependency inventory and release-note evidence, Windows
resolution plus static/host-neutral checks, isolated archive/npm installation,
exact functional-alpha package admission, and the benchmark and release-
workflow contracts. Passing them is local mechanical admission only; it cannot
exact functional-alpha package admission, the benchmark and release-
workflow contracts, and the `public-surface` leak check that keeps internal
service detail out of this public client. Passing them is local mechanical admission only; it cannot
grant semantic, native-Windows, strict semantic-adapter, or public-release
eligibility.

Expand Down
Loading
Loading