Metadata-Version: 2.4
Name: ai-marketplace-cli
Version: 2.1.0
Summary: AI Marketplace Platform CLI
Requires-Python: >=3.13
Requires-Dist: ai-marketplace-framework==0.3.0
Requires-Dist: ai-marketplace-sdk==0.3.0
Requires-Dist: click==8.1.8
Requires-Dist: httpx==0.28.1
Requires-Dist: prompt-toolkit==3.0.52
Requires-Dist: pydantic==2.10.6
Requires-Dist: pyyaml==6.0.2
Requires-Dist: rich==13.9.4
Requires-Dist: typer==0.15.1
Provides-Extra: dev
Requires-Dist: mypy==1.18.2; extra == 'dev'
Requires-Dist: pytest==8.4.2; extra == 'dev'
Requires-Dist: ruff==0.13.0; extra == 'dev'
Description-Content-Type: text/markdown

# AI Marketplace CLI

Python CLI for publishing and managing marketplace models.

## Install

Requirements:

- Python 3.13+
- Docker

Install with `uv`:

```bash
uv tool install ./cli
```

Or with `pipx`:

```bash
pipx install ./cli
```

For local development:

```bash
cd cli
uv sync --extra dev
uv run ai --help
```

## Commands

### `ai`

With no arguments on an interactive terminal, opens the branded launcher.
When the current directory already contains `contract.toml`, the launcher switches to
project-aware actions such as editing the contract and configuring publish settings. Remote
marketplace model tools are grouped under a `Marketplace Models` submenu instead of appearing
as top-level home actions.

Without interactive stdin/stdout, prints help.

Launcher controls:

- Up / Down arrows to move
- `Enter` to select
- `Esc` to cancel or go back from prompt screens
- `Ctrl-C` to exit

### `ai init`

Create one unified framework and platform project:

- `model/`
- `agent.py`
- `contract.toml`
- `.aimp/project.toml`
- `.aimp/publish.toml`
- `studio/article.mdx`
- `studio/cover.jpg`
- `pyproject.toml`
- `Dockerfile`

`contract.toml` is the publish source of truth for the model release version.
`pyproject.toml` remains the dependency/package manifest; `ai push` derives the
build-time package version from `contract.toml` during bundling.

The hidden `.aimp/project.toml` also carries one CLI-managed `[publish]` section used only
for source-bundle packaging metadata:

```toml
[publish]
artifact_path = "model"
artifact_format = "tar.zst"
```

This is platform-internal packaging config, not author-facing model logic.

Build-time assets are prepared through:

```bash
python -m aimp_sdk.build_runner --module /app/agent.py
```

The actual project-owned build hook remains inside `model/engine.py`.

`agent.py` stays registry-only:

```python
from aimp_framework.base import Agent
from model.model import Example

class MyModelAgent(Agent):
    models = [Example]
```

Model declarations stay inside `model/model.py` by default:

```python
class Example(Model):
    modes = [GenerateMode]
    train = [ExampleTrainer]
    engine = ExampleEngine()
```

The starter model package is flat:

```text
model/
  model.py
  engine.py
  schemas.py
  modes.py
  trainer.py
  vector.py
```

Examples:

```bash
ai init my-model
ai init my-model --yes
ai init my-model --json
```

`ai init` now scaffolds the default unified project immediately. The official next steps are:

```bash
cd my-model
uv sync
ai publish --configure
ai push
```

### `ai login`

Authenticate and persist credentials in `~/.aimp/config.json`.

Examples:

```bash
ai login
ai login --gateway http://localhost:8080 --api-key pk_live_xxx
printf '%s' "$AIMP_API_KEY" | ai login --gateway http://localhost:8080 --stdin
```

### `ai auth`

Show current authentication status.

### `ai logout`

Remove stored credentials.

### `ai publish`

Package, upload, remotely build, and publish the current model.

Requirements:

- `agent.py`
- `contract.toml`
- `.aimp/publish.toml` or a TTY session for guided configuration
- `Dockerfile`

Publish does not require local registry credentials or local Docker daemon access. The CLI
packages a source bundle and the platform performs the build.

For local stack development, the platform-side Build Service still needs its own registry
Docker config secret. Use `make repair-local-registry-auth` to provision or repair that
platform secret contract before retrying a failed remote publish push.

`ai publish` now owns publish setup. If `.aimp/publish.toml` is missing or invalid and the
session is interactive, the CLI fetches the platform hardware catalog from Gateway, lets you
choose tiers and developer margin, then writes the hidden config before publishing.

Publish flow:

- CLI creates a source bundle from the local build context
- CLI derives the build-time package version from `contract.toml` before bundling
- CLI uploads that bundle through Gateway
- the platform creates a `publish-build` execution
- Build Service builds the image inside the platform and publishes immutable outputs
- final model publish resolves artifacts from the succeeded build job only

`ai publish --configure` runs that guided flow without building or publishing.

Published Python runtime packages:

- scaffolded projects depend on `ai-marketplace-framework` and `ai-marketplace-sdk` from PyPI by default
- publish preflight now waits briefly for package-index propagation when those runtime packages were just released, then re-runs the normal resolver check
- scaffolded projects do not add local `[tool.uv.sources]` runtime path overrides, even inside this monorepo
- older generated projects that still contain runtime path sources must remove `[tool.uv.sources]`, run `uv sync`, and then retry `ai push`
- `TestPyPI` and custom indexes remain advanced overrides only; the default publish path is real `PyPI`
- if you intentionally test unpublished releases from `TestPyPI` or mirror those packages in another index, configure the CLI preflight with:
  - `AIMP_PYTHON_PACKAGE_EXTRA_INDEX_URL`
  - `AIMP_PYTHON_PACKAGE_INDEX_USERNAME`
  - `AIMP_PYTHON_PACKAGE_INDEX_PASSWORD`
- for `TestPyPI`, set only:
  - `AIMP_PYTHON_PACKAGE_EXTRA_INDEX_URL=https://test.pypi.org/simple/`
- configure the Build Service with the matching platform-side settings when remote builds must use that same extra index:
  - `PYTHON_PACKAGE_EXTRA_INDEX_URL`
  - `PYTHON_PACKAGE_INDEX_USERNAME`
  - `PYTHON_PACKAGE_INDEX_PASSWORD`
- for `TestPyPI`, set only:
  - `PYTHON_PACKAGE_EXTRA_INDEX_URL=https://test.pypi.org/simple/`
- scaffolded Dockerfiles mount this index configuration as an optional BuildKit secret during
  `pip install`, so extra-index settings are available at build time without being baked into the
  final image

Platform-owned values are never edited locally:

- infra base cost comes from the platform hardware catalog
- platform fee comes from billing config
- local publish config stores only user intent such as hardware choices, article path, and margin
- registry resolution and target image naming are platform-owned

Examples:

```bash
ai publish
ai publish --configure
ai publish --parallel 4 --verbose
ai publish --python .venv/bin/python
ai push
```

### `ai fine-tune`

Fine-tune is CLI-first in V1.

- model authors enable it locally with `ai fine-tune init`
- consumers generate a schema-matched workspace with `ai fine-tune scaffold --model <slug>`
- the workspace produces `bundle.json`, and the CLI uploads that bundle through Gateway
- the dashboard remains read-only for history/detail
- successful jobs materialize a derived output model that is executed via its model slug

Commands:

- `ai fine-tune init`
- `ai fine-tune remove --yes`
- `ai fine-tune scaffold --model <slug>`
- `ai fine-tune create --model <slug> --workspace ./<slug>-fine-tune`
- `ai fine-tune list`
- `ai fine-tune get --job <job_id>`

Examples:

```bash
ai fine-tune init
ai fine-tune scaffold --model vision-pro
python vision-pro-fine-tune/prepare_bundle.py
ai fine-tune create --model vision-pro --workspace ./vision-pro-fine-tune
ai fine-tune list --json
ai fine-tune get --job 7d2a4b2c-....
```

### `ai jobs`

Jobs are read from the CLI only.

- `ai push` still performs publish/build orchestration end-to-end
- `ai jobs list` reads build and fine-tune jobs from one surface
- `ai jobs get` reads a single job by explicit type
- `ai jobs cancel` cancels a job
- `ai jobs delete` removes a terminal job from history
- `ai push` now finalizes publish from the trusted remote build job; internal artifact URIs are not shown to the user

Examples:

```bash
ai jobs list
ai jobs list --type build
ai jobs list --type fine-tune --status running
ai jobs list --model vision-pro --page 1 --page-size 20
ai jobs get --type build --job 7d2a4b2c-....
ai jobs get --type fine-tune --job 7d2a4b2c-....
ai jobs cancel --type build --job 7d2a4b2c-....
ai jobs delete --type fine-tune --job 7d2a4b2c-....
```

Interpreter precedence for contract extraction:

1. `--python`
2. active `VIRTUAL_ENV/bin/python`
3. active `VIRTUAL_ENV/Scripts/python.exe`
4. active `VIRTUAL_ENV/Scripts/python`
5. the running CLI interpreter
6. `python`
7. `python3`

Remote build troubleshooting:

- `ai publish` does not require local Docker daemon access.
- If a publish build fails, inspect it with `ai jobs get --type build --job <job_id>`.
- If the local stack is used for development, run `make dev-up` before retrying a failed publish.

### `ai model inspect`

Fetch model metadata, analytics, and rates.

Examples:

```bash
ai model inspect --slug my-model
ai model inspect --id 7d2a4b2c-....
ai model inspect --slug my-model --json
```

By default this command prints a human-readable summary.
Use `--json` for machine-readable output.

### `ai model pull`

Pull remote studio metadata into local files.

Writes:

- `.aimp/publish.toml`
- the configured article path from the current local publish config when present
- otherwise `studio/article.mdx`
- local projects also use `studio/cover.jpg` as the default cover path

Examples:

```bash
ai model pull --slug my-model
ai model pull --id 7d2a4b2c-....
```

## Auth Resolution

Authentication uses this precedence:

1. Command flags
2. Environment variables
3. Stored config

Supported environment variables:

- `AIMP_GATEWAY_URL`
- `AIMP_API_KEY`

Only `ai login` persists credentials.

## Contract Editing

`ai contract edit` and `ai project configure` manage public modes independently.

- `--modes` accepts any non-empty comma-separated mode list
- `--mode-inputs <mode>=<csv>` and `--mode-outputs <mode>=<csv>` customize per-mode modalities
- `search` and `index` are ordinary mode names; they do not imply vector access
- vector access is declared explicitly by the Python model contract and synced into TOML resources
- `--vector-db` only controls the project resource flag; it is not inferred from mode names

## Default Starter

`ai init` now scaffolds a model-centric starter with:

- `GenerateMode`
- `SearchMode`
- `IndexMode`
- `DocsVector`
- `model/playground.py` for mode Playground specs consumed from `model/modes.py`

The framework-facing vector API is:

```python
docs = owner.vectors.get(DocsVector)
docs.objects.index(embedding, text=data.text, source=data.source)
hits = docs.objects.search(embedding, limit=params.top_k)
```

## Agent Usage

For local coding agents, this CLI is the primary execution surface. MCP is not required for the
local-repo workflow in this phase.

- Prefer explicit non-interactive commands over the interactive launcher
- Prefer `--json` whenever the command supports it
- Use local project skills under `.agents/skills/` as the first guidance layer
- Read `contract.toml`, `.aimp/publish.toml`, and `agent.py` before mutating the project

Recommended patterns:

```bash
ai contract validate --json
ai contract show --json
ai model inspect --slug my-model --json
ai publish --configure --json
```

## JSON Output

These commands support `--json`:

- `ai init`
- `ai login`
- `ai auth`
- `ai logout`
- `ai publish`
- `ai push`
- `ai model inspect`
- `ai model pull`
- `ai jobs list`
- `ai jobs get`
- `ai fine-tune create`
- `ai fine-tune list`
- `ai fine-tune get`

JSON success payloads use:

```json
{
  "ok": true,
  "request_id": "cli-...",
  "data": {}
}
```

JSON error payloads use:

```json
{
  "ok": false,
  "request_id": "cli-...",
  "error": {
    "code": "gateway_unreachable",
    "category": "network",
    "message": "Authentication failed: gateway unreachable",
    "retryable": true,
    "exit_code": 5
  }
}
```

Debug logs from `--debug` are written to `stderr`.

## Exit Codes

- `0`: success or expected status result
- `2`: usage or local config validation error
- `3`: authentication or permission failure
- `4`: local environment or dependency failure
- `5`: network or downstream service failure
- `6`: remote conflict, quota, or not-found state
- `130`: interrupted

## Development

```bash
cd cli
uv run ruff check .
uv run --extra dev mypy aimp_cli tests
uv run pytest
```
