Metadata-Version: 2.1
Name: fhenomai
Version: 1.5.0
Summary: Official Python SDK for FHEnom for AI™ - Confidential AI with fully encrypted models and data
Author-email: DataKrypto <support@datakrypto.ai>
Project-URL: Homepage, https://datakrypto.ai
Project-URL: LinkedIn, https://www.linkedin.com/company/datakrypto/
Keywords: fhe,fully-homomorphic-encryption,confidential-ai,encrypted-ai,machine-learning,deep-learning,privacy,security,datakrypto,fhenom
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28.0
Requires-Dist: paramiko>=3.0.0
Requires-Dist: urllib3>=1.26.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: tqdm>=4.65.0
Requires-Dist: rich>=13.0.0
Requires-Dist: click>=8.0.0
Requires-Dist: dk-tee-attestation>=0.2.4
Requires-Dist: cryptography>=46.0.0
Requires-Dist: reportlab>=4.0.0
Provides-Extra: all
Requires-Dist: fhenomai[dev,docs,testing]; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: flake8>=6.0.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Requires-Dist: isort>=5.12.0; extra == "dev"
Provides-Extra: docs
Requires-Dist: sphinx>=6.0.0; extra == "docs"
Requires-Dist: sphinx-rtd-theme>=1.2.0; extra == "docs"
Requires-Dist: sphinx-autodoc-typehints>=1.22.0; extra == "docs"
Provides-Extra: testing
Requires-Dist: pytest>=7.0.0; extra == "testing"
Requires-Dist: pytest-timeout>=2.1.0; extra == "testing"
Requires-Dist: pandas>=1.5.0; extra == "testing"
Requires-Dist: pyarrow>=10.0.0; extra == "testing"

# FHEnom for AI™ — Python SDK and CLI

[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

`fhenomai` is the official client for **FHEnom for AI™** by DataKrypto. It lets you
encrypt AI models, serve them from a Trusted Execution Environment (TEE), and run
inference on them, from the command line or from Python.

**Requirements**

- Python 3.8 or newer
- Access to a FHEnom for AI node: **TEE 1.9.3+** and **FHEnom AI Server 1.5.3+**
  (these are minimums; newer nodes work). `fhenomai health live` checks your node.

## Installation

```bash
pip install fhenomai
fhenomai --version
```

## Configuration

Run the setup wizard and answer the prompts (node address, admin token, SFTP
credentials, inference server):

```bash
fhenomai config init
```

This writes `~/.fhenomai/config.yaml`. Keep that file private: it holds your
admin token. Then check the settings and the connection:

```bash
fhenomai config show
fhenomai test connection
```

<details>
<summary>Example <code>config.yaml</code></summary>

```yaml
admin:
  host: "tee.example.com"
  port: 9099
  auth_token: "your-admin-token"

user:                     # inference endpoint
  host: "tee.example.com"
  port: 9999

sftp:
  host: "tee.example.com"
  port: 22
  username: "your-sftp-user"
  key_path: "~/.ssh/fhenom_sftp"   # or: password: "..."
```

You can also set any value through an environment variable, for example
`FHENOM_ADMIN_HOST`, `FHENOM_AUTH_TOKEN` or `FHENOM_SFTP_PASSWORD`.
</details>

## Quick start

To encrypt and serve a Hugging Face model (in `.safetensors` format):

```bash
# 1. Upload the plaintext model to the node
fhenomai sftp upload ./my-model my-model --recursive

# 2. Encrypt it inside the TEE
fhenomai model encrypt my-model --wait

# 3. Serve the encrypted model (starts vLLM and registers it with the TEE)
fhenomai model serve my-model-encrypted

# 4. Send it a prompt
fhenomai test chat "What is the capital of France?"
```

To stop serving the model, run `fhenomai model stop my-model-encrypted`.

If you run vLLM yourself, register it with the TEE directly:

```bash
fhenomai serve start my-model-encrypted \
  --server-url http://GPU_HOST:8000 \
  --display-model-name my-model-encrypted
```

### Encryption options

| Option | What it does |
|---|---|
| `--encryption-impl` | Selects the encryption profile for the model's architecture. Omit it and the node picks the profile from the model's `config.json`; pass it alone and the matching preprocessing and inference mode follow. `fhenomai model encrypt --help` lists the values. |
| `--lora-adapter` | Encrypts a LoRA adapter on top of its base model: pass the adapter folder in `upload/`, plus the base model's `--encryption-impl`. |
| `--optimize-accuracy` | Keeps the encrypted model accurate if you quantize it later. Encryption takes a little longer. |
| `--secure-channel` | Encrypts the token channel used during inference. You choose this when you encrypt the model. |

## Inference

The node exposes an **OpenAI-compatible** API, so any OpenAI client works:

```python
from openai import OpenAI

client = OpenAI(base_url="http://tee.example.com:9999/v1", api_key="unused")

response = client.chat.completions.create(
    model="my-model-encrypted",
    messages=[{"role": "user", "content": "Explain confidential computing."}],
    max_tokens=200,
)
print(response.choices[0].message.content)
```

## Python SDK

```python
from fhenomai import FHEnomClient, FHEnomConfig

client = FHEnomClient(FHEnomConfig.from_file())   # reads ~/.fhenomai/config.yaml

# Upload, encrypt, wait
client.upload_model("./my-model", "my-model")
job_id = client.admin.encrypt_model("my-model", "my-model-encrypted")
job = client.admin.wait_for_job(job_id, timeout=3600)
model_id = job["result"]["encrypted_model_id"]

# Serve through your vLLM server
client.admin.start_serving(
    encrypted_model_id=model_id,
    server_url="http://GPU_HOST:8000",
    display_model_name="my-model-encrypted",
)
```

`FHEnomConfig.from_env()` builds the configuration from environment variables
instead of a file.

## Verify the endpoint

Before you send it a prompt, check that the inference endpoint is running in a
genuine TEE. This check needs no admin token:

```bash
fhenomai attest        # exits 0 only if verification succeeds
```

```python
from fhenomai.inference_attestation import verify_endpoint

result = verify_endpoint("tee.example.com", 9999)
if not result.verified:
    raise SystemExit(result.error)
```

Node operators can also generate and verify a full attestation report with
`fhenomai admin attestation` and `fhenomai admin verify-attestation`.

## Optional features

### Encrypted prompts and responses (thick client)

By default, prompts and responses travel in plaintext. In thick-client mode,
each client has its own key, and the node refuses any prompt that is not
encrypted with it.

```bash
fhenomai model serve my-model-encrypted --thick-client
fhenomai thick-client add my-model-encrypted --label my-app --save my-app.json
fhenomai test chat "Hello" --thick-key-file my-app.json
```

The node shows each key only once, so store it when you create it. A
thick-client model refuses every request until you have added at least one
client. In Python, use `ThickClientSession`.

### Sovereign split inference

Split inference keeps part of the model inside the TEE and runs the rest on
your own GPU server, in the `datakrypto-vllm` image. The TEE connects to that
server's inference port (50052).

```bash
fhenomai model split my-model --first-layers 2 --last-layers 2
fhenomai model serve my-model --sovereign-host GPU_SERVER_ADDRESS_SEEN_FROM_THE_TEE
```

**The TEE and the sovereign server must use the same dtype and the same
max_model_len.** `model serve` starts both with the same values: `--dtype`
(default: the model's own dtype, float16 on a GPU without bfloat16 support)
and `--max-model-len` (default 4096). If you run the sovereign server yourself,
pass the same explicit values it was started with:

```bash
fhenomai serve start my-model --sovereign-server-host HOST \
  --sovereign-max-model-len 4096 --sovereign-dtype float16
```

`fhenomai serve list` shows the values the TEE uses. Thick-client mode
(`--thick-client`) works with sovereign serving too.

## Administration

| Command | Purpose |
|---|---|
| `fhenomai provision` | Activate a new node with the licence details supplied by DataKrypto |
| `fhenomai admin license` | Show licence state and remaining budget |
| `fhenomai admin usage --from … --to …` | Signed inference usage for a period |
| `fhenomai admin token create/list/revoke` | Manage scoped admin tokens |
| `fhenomai whoami` | Show what the configured token is allowed to do |
| `fhenomai health check` | Check every service the CLI talks to |

For security, always provision with `--admin-token` and `--rotation-token`.
Without them `provision` asks for confirmation, and `fhenomai health check`
warns about the node.

## Command reference

| Group | Commands |
|---|---|
| `config` | `init`, `show`, `get`, `validate` |
| `model` | `list`, `info`, `upload`, `download`, `encrypt`, `encrypt-dataset`, `serve`, `stop`, `split`, `delete`, `delete-encrypted`, `chat-template` |
| `serve` | `start`, `stop`, `list` |
| `sftp` | `upload`, `download`, `list`, `clear` |
| `job` | `list`, `status`, `wait`, `cancel` |
| `thick-client` | `add`, `list`, `remove` |
| `health` | `check`, `live`, `ready`, `status`, `admin`, `sftp`, `server` |
| `test` | `connection`, `admin`, `sftp`, `chat` |
| `admin` | `license`, `usage`, `token`, `attestation`, `verify-attestation`, `logs`, `ssl`, `sync`, `ita`, `reload`, `deprovision` |
| top level | `provision`, `attest`, `whoami` |

Add `--help` to any command to see its options.

If a command fails, the CLI exits with a non-zero status, so you can safely chain
commands in scripts (`fhenomai … && next-step`).

## Support

- Website: [datakrypto.ai](https://datakrypto.ai)
- Email: [support@datakrypto.ai](mailto:support@datakrypto.ai)

## License

MIT License. Copyright (c) 2024-2026 DataKrypto. See the LICENSE file for details.
