Metadata-Version: 2.4
Name: forktex-cloud
Version: 0.2.3
Summary: Typed Python SDK for the ForkTex Cloud platform — provision, deploy, and manage VPS-backed apps via a declarative manifest.
License-Expression: AGPL-3.0-only
License-File: LICENSE
License-File: NOTICE
Keywords: forktex,cloud,deployment,vps,hetzner,ansible,blue-green,iac,infrastructure-as-code,sdk
Author: FORKTEX
Author-email: info@forktex.com
Requires-Python: >=3.12
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Distributed Computing
Classifier: Topic :: System :: Installation/Setup
Classifier: Topic :: System :: Systems Administration
Classifier: Typing :: Typed
Requires-Dist: cryptography (>=42.0)
Requires-Dist: httpx (>=0.27.0,<1.0.0)
Requires-Dist: pydantic[email] (>=2.11.10,<3.0.0)
Requires-Dist: pyyaml (>=6.0)
Project-URL: Changelog, https://github.com/forktex/cloud/blob/master/sdk-py/CHANGELOG.md
Project-URL: Documentation, https://github.com/forktex/cloud/tree/master/docs
Project-URL: Homepage, https://forktex.com
Project-URL: Issues, https://github.com/forktex/cloud/issues
Project-URL: Repository, https://github.com/forktex/cloud
Description-Content-Type: text/markdown

# forktex-cloud

[![PyPI](https://img.shields.io/pypi/v/forktex-cloud.svg)](https://pypi.org/project/forktex-cloud/)
[![Python](https://img.shields.io/pypi/pyversions/forktex-cloud.svg)](https://pypi.org/project/forktex-cloud/)
[![License](https://img.shields.io/pypi/l/forktex-cloud.svg)](https://github.com/forktex/cloud/blob/master/sdk-py/LICENSE)

Standalone Python SDK for the [ForkTex Cloud](https://cloud.forktex.com) platform.

`forktex-cloud` is the typed `httpx` client + manifest plumbing that the `forktex` CLI uses to talk to the ForkTex Cloud control plane: project provisioning, server management, deployments, vault, manifest validation, and the docker-compose / Hetzner / Ansible bridge.

You can use it directly from any Python application — no `forktex` CLI required.

## Install

```bash
pip install forktex-cloud
```

**Requires Python 3.12+.** Tested on 3.12, 3.13, 3.14.

## Quick Start

### Authenticated client

```python
from forktex_cloud import ForktexCloudClient, CloudContext

ctx = CloudContext(controller="https://cloud.forktex.com", account_key="ftx-...")
with ForktexCloudClient.from_context(ctx) as client:
    projects = client.list_projects()
    servers  = client.list_servers()
    health   = client.health()
```

### Direct auth

```python
from forktex_cloud import ForktexCloudClient

# JWT bearer (user login)
with ForktexCloudClient("https://cloud.forktex.com", access_token="eyJ...") as client:
    me = client.me()

# Org-scoped API key (CI/CD)
with ForktexCloudClient(
    "https://cloud.forktex.com",
    account_key="ftx-...",
    org_id="00000000-0000-0000-0000-000000000001",
) as client:
    events = client.list_events(project_id="...")
    status = client.server_status("server-uuid")
```

### Local dev (point at your `make local` stack)

```python
client = ForktexCloudClient(
    base_url="http://localhost:8000",
    account_key="ftx-dev-key-2026",
    org_id="<your-org-uuid>",
)
```

### Trigger a deploy pipeline

```python
# Full up (provision + bootstrap + deploy + DNS + SSL)
job = client.up(project_dir=Path("./my-project"))      # reads forktex.json
print(job.job_id, job.deployment_id, job.status)

# Code push to an existing server (no re-provision)
job = client.deploy(server_id="...", service="api")    # Ansible deploy tag

# Tear down
job = client.down(keep_dns=True)                       # preserves DNS record
```

### Manifest loading + validation

```python
from forktex_cloud import Manifest, ManifestError

# Validates eagerly against the canonical Pydantic schema at construction
try:
    m = Manifest.load("forktex.json", env="production")
except ManifestError as e:
    print(f"Invalid manifest: {e}")
    raise

# Typed access to the cloud block (discriminated union over all 4 kinds)
print(m.cloud.kind)                     # "ProjectDeployment" | "StaticSite" | ...
print(m.cloud.metadata.name)
for svc in m.services_for_env(env="production"):
    print(svc.id, svc.type, svc.image)

# Wire format round-trips cleanly (model_dump → parse_cloud_block)
as_dict = m.cloud.model_dump(by_alias=True, exclude_none=True)
```

### Secrets vault (server-side, org-scoped)

```python
client.vault_set("POSTGRES_PASSWORD", "hunter2")
secret = client.vault_get("POSTGRES_PASSWORD")           # -> VaultGetResponse
keys   = client.vault_list()                             # -> list[str]
client.vault_delete("POSTGRES_PASSWORD")
```

## What's in the package

| Module | Purpose |
|---|---|
| `forktex_cloud.client` | Typed sync httpx client (`ForktexCloudClient`) + all OpenAPI-codegenned Pydantic models (`ServerRead`, `ProjectRead`, `EventRead`, `VaultGetResponse`, ...) |
| `forktex_cloud.manifest` | `Manifest` loader, discriminated-union schema (v1beta2), deep-merge for env overlays, `ManifestError` |
| `forktex_cloud.config` | `CloudContext` — controller URL, JWT / account-key, current org + project keys |
| `forktex_cloud.scaffold` | `forktex cloud init` template generator (ProjectDeployment / StaticSite / SingleContainer / NativeBuild) |
| `forktex_cloud.bridge` | docker-compose generator (local mode), Loki config, log formatters used by `forktex cloud up --env local` |
| `forktex_cloud.secrets` | Fernet vault + `${vault:KEY}` resolver for compile-time secret injection |
| `forktex_cloud.paths` | Cross-platform `.forktex/` + `~/.forktex/` filesystem spec (V1). See [docs/forktex-directory-spec.md](https://github.com/forktex/cloud/blob/master/docs/forktex-directory-spec.md) |

All response models come from the OpenAPI codegen pipeline — **one source of truth** shared between the server and every consumer. No hand-written model drift.

## Top-level re-exports

```python
from forktex_cloud import (
    # Client
    ForktexCloudClient, CloudAPIError,
    # Config
    CloudContext,
    # Manifest
    Manifest, ManifestError,
    # Response models (from OpenAPI codegen)
    ApiKeyCreated, ApiKeyRead,
    EnvironmentRead, EventRead,
    HealthRead, JobResponse, MeResponse,
    OrgRead, ProjectRead, ServerRead, UserRead,
    StatusResponse, TokenResponse, VaultGetResponse,
    WorkspaceRead,
)
```

## Versioning

The SDK follows [SemVer](https://semver.org/). The client's response models are generated from the server's OpenAPI spec at a fixed `SPEC_VERSION` + `SPEC_HASH` (inspectable at runtime via `forktex_cloud.client.generated.SPEC_VERSION`). When the server OpenAPI changes, the SDK is regenerated and released with a bumped version.

## Repository

This SDK lives inside the [`forktex/cloud`](https://github.com/forktex/cloud) monorepo alongside the API server (`api/`) and React Native client (`client/`). The SDK package is independently versioned and published to PyPI.

- Docs: [https://github.com/forktex/cloud/tree/master/docs](https://github.com/forktex/cloud/tree/master/docs)
- Production runbook: [production-runbook.md](https://github.com/forktex/cloud/blob/master/docs/production-runbook.md)
- Issues: [https://github.com/forktex/cloud/issues](https://github.com/forktex/cloud/issues)

## Development

The [`Makefile`](Makefile) is generated by `forktex fsd makefile sync` from [`forktex.json`](forktex.json) — do not hand-edit.

```bash
make help              # list every available target
make deps              # editable install with the dev group
make format            # ruff format
make lint              # ruff check
make test              # pytest tests/
make codegen-check     # verify the generated client imports cleanly
make build             # python3 -m build → dist/
make ci                # format-check + lint + license-check + audit + test + build
make clean             # remove caches and dist/
```

`make ci` is the single command that gates a publish: format-check, lint, dual-license header check, dependency CVE audit, full test suite, and `python -m build` + `twine check`.

### License headers

Every source file carries the AGPL-3.0 + Commercial dual-license SPDX header, applied idempotently via:

```bash
make license-check    # CI gate — fails if any source file is missing the header
make license-fix      # add or refresh headers across src/, tests/, scripts/
make license-strip    # remove headers (used before license-model changes)
```

## License

Dual-licensed — **AGPL-3.0-or-later** for open-source use, **commercial** for everything else (proprietary products, SaaS without source release, redistribution in closed-source form). See [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE) for the full terms.

Commercial licensing inquiries: info@forktex.com.

The 1.0.x releases on PyPI remain under MIT; from **0.2.3** onwards the package ships AGPL-3.0+Commercial.

