> For the complete documentation index, see [llms.txt](https://docs.clore.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.clore.ai/clore.ai/clore.ai-ru/razrabotchikam/cli-sdk.md).

# Руководство по CLI и SDK

## Обзор

Clore.ai предоставляет **REST API** который обеспечивает полный программный доступ к GPU-маркетплейсу — просмотр серверов, создание заказов, мониторинг развертываний и отмена аренды.

> **Примечание:** На данный момент официального CLI-исполняемого файла нет. Вся автоматизация выполняется напрямую через REST API с помощью таких инструментов, как `curl`, Python или Node.js.

**Базовый URL:** `https://api.clore.ai/v1`

**Формат ответа:** JSON. Каждый ответ включает поле `code` , указывающее статус.

***

## Аутентификация

Сгенерируйте ваш API-ключ в [панели управления Clore.ai](https://clore.ai):

1. Войдите в свою учетную запись
2. Перейдите в **API** раздел в настройках
3. Сгенерируйте и скопируйте ваш API-ключ

**Формат заголовка:**

```
auth: YOUR_API_KEY
```

> ⚠️ **Важно:** Заголовок auth — это `auth`, **не** `Authorization: Bearer`. Использование неверного формата вернет код `3` (Неверный API-токен).

**Пример:**

```bash
curl -H 'auth: YOUR_API_KEY' 'https://api.clore.ai/v1/marketplace'
```

***

## Быстрый старт

### Список серверов маркетплейса

Просмотрите все доступные GPU-серверы:

```bash
curl -XGET \
  -H 'auth: YOUR_API_KEY' \
  'https://api.clore.ai/v1/marketplace'
```

**Ответ:**

```json
{
  "servers": [
    {
      "id": 6,
      "owner": 4,
      "mrl": 73,
      "price": {
        "on_demand": { "bitcoin": 0.00001 },
        "spot": { "bitcoin": 0.000001 }
      },
      "rented": false,
      "specs": {
        "cpu": "Intel Core i9-11900",
        "ram": 62.67,
        "gpu": "1x NVIDIA GeForce GTX 1080 Ti",
        "gpuram": 11,
        "net": { "up": 26.38, "down": 118.42, "cc": "CZ" }
      }
    }
  ],
  "my_servers": [1, 2, 4],
  "code": 0
}
```

***

### Получить свои заказы

```bash
curl -XGET \
  -H 'auth: YOUR_API_KEY' \
  'https://api.clore.ai/v1/my_orders'
```

Включая завершенные/истекшие заказы:

```bash
curl -XGET \
  -H 'auth: YOUR_API_KEY' \
  'https://api.clore.ai/v1/my_orders?return_completed=true'
```

***

### Создать заказ (по требованию)

```bash
curl -XPOST \
  -H 'auth: YOUR_API_KEY' \
  -H 'Content-type: application/json' \
  -d '{
    "currency": "bitcoin",
    "image": "cloreai/ubuntu20.04-jupyter",
    "renting_server": 6,
    "type": "on-demand",
    "ports": {
      "22": "tcp",
      "8888": "http"
    },
    "ssh_password": "YourSSHPassword123",
    "jupyter_token": "YourJupyterToken123"
  }' \
  'https://api.clore.ai/v1/create_order'
```

**Ответ:**

```json
{ "code": 0 }
```

***

### Создать спотовый заказ

Спотовые заказы дешевле, но их могут перебить. Вы задаете свою цену за день:

```bash
curl -XPOST \
  -H 'auth: YOUR_API_KEY' \
  -H 'Content-type: application/json' \
  -d '{
    "currency": "bitcoin",
    "image": "cloreai/ubuntu20.04-jupyter",
    "renting_server": 6,
    "type": "spot",
    "spotprice": 0.000005,
    "ports": {
      "22": "tcp",
      "8888": "http"
    },
    "ssh_password": "YourSSHPassword123"
  }' \
  'https://api.clore.ai/v1/create_order'
```

***

### Проверить статус заказа

```bash
curl -XGET \
  -H 'auth: YOUR_API_KEY' \
  'https://api.clore.ai/v1/my_orders'
```

Активные заказы включают `pub_cluster` (имена хостов) и `tcp_ports` для доступа по SSH:

```json
{
  "id": 38,
  "pub_cluster": ["n1.c1.clorecloud.net", "n2.c1.clorecloud.net"],
  "tcp_ports": ["22:10000"],
  "http_port": "8888",
  "expired": false
}
```

Подключитесь по SSH к арендованному серверу:

```bash
ssh root@n1.c1.clorecloud.net -p 10000
```

***

### Отменить заказ

```bash
curl -XPOST \
  -H 'auth: YOUR_API_KEY' \
  -H 'Content-type: application/json' \
  -d '{
    "id": 38
  }' \
  'https://api.clore.ai/v1/cancel_order'
```

При желании сообщите о проблеме с сервером:

```bash
curl -XPOST \
  -H 'auth: YOUR_API_KEY' \
  -H 'Content-type: application/json' \
  -d '{
    "id": 38,
    "issue": "GPU перегревался и снижал производительность"
  }' \
  'https://api.clore.ai/v1/cancel_order'
```

***

## Python SDK

Легкая обертка с использованием `requests` библиотеки. Установите ее с помощью:

```bash
pip install requests
```

### Класс CloreClient

```python
import requests
import time

class CloreClient:
    """Простой Python SDK для REST API Clore.ai."""
    
    BASE_URL = "https://api.clore.ai/v1"
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.session = requests.Session()
        self.session.headers.update({"auth": api_key})
    
    def _get(self, endpoint: str, params: dict = None) -> dict:
        url = f"{self.BASE_URL}/{endpoint}"
        response = self.session.get(url, params=params)
        response.raise_for_status()
        data = response.json()
        if data.get("code") != 0:
            raise CloreAPIError(data)
        return data
    
    def _post(self, endpoint: str, body: dict) -> dict:
        url = f"{self.BASE_URL}/{endpoint}"
        self.session.headers.update({"Content-type": "application/json"})
        response = self.session.post(url, json=body)
        response.raise_for_status()
        data = response.json()
        if data.get("code") != 0:
            raise CloreAPIError(data)
        return data
    
    def list_servers(self) -> list:
        """Получить все доступные серверы на маркетплейсе."""
        data = self._get("marketplace")
        return data["servers"]
    
    def get_server_details(self, server_id: int) -> dict:
        """Получить информацию спотового маркетплейса для конкретного сервера."""
        data = self._get("spot_marketplace", params={"market": server_id})
        return data["market"]
    
    def create_order(
        self,
        server_id: int,
        image: str,
        order_type: str = "on-demand",
        currency: str = "bitcoin",
        spotprice: float = None,
        ports: dict = None,
        ssh_password: str = None,
        ssh_key: str = None,
        jupyter_token: str = None,
        env: dict = None,
        command: str = None,
    ) -> dict:
        """
        Создать заказ по требованию или спотовый заказ.
        
        Аргументы:
            server_id: ID сервера для аренды
            image: Docker-образ (например, 'cloreai/ubuntu20.04-jupyter')
            order_type: 'on-demand' или 'spot'
            currency: 'bitcoin' (по умолчанию)
            spotprice: Обязателен для спотовых заказов — цена в день в BTC
            ports: Переадресация портов, например {"22": "tcp", "8888": "http"}
            ssh_password: Пароль SSH (только буквенно-цифровые символы)
            ssh_key: Публичный ключ SSH
            jupyter_token: Токен Jupyter notebook
            env: Словарь переменных окружения
            command: Команда shell, выполняемая после запуска контейнера
        """
        if order_type == "spot" and spotprice is None:
            raise ValueError("для спотовых заказов требуется spotprice")
        
        body = {
            "currency": currency,
            "image": image,
            "renting_server": server_id,
            "type": order_type,
        }
        
        if spotprice is not None:
            body["spotprice"] = spotprice
        if ports:
            body["ports"] = ports
        if ssh_password:
            body["ssh_password"] = ssh_password
        if ssh_key:
            body["ssh_key"] = ssh_key
        if jupyter_token:
            body["jupyter_token"] = jupyter_token
        if env:
            body["env"] = env
        if command:
            body["command"] = command
        
        return self._post("create_order", body)
    
    def get_orders(self, include_completed: bool = False) -> list:
        """Получить ваши активные (и при необходимости завершенные) заказы."""
        params = {"return_completed": "true"} if include_completed else {}
        data = self._get("my_orders", params=params)
        return data["orders"]
    
    def cancel_order(self, order_id: int, issue: str = None) -> dict:
        """Отменить заказ. При желании сообщить о проблеме."""
        body = {"id": order_id}
        if issue:
            body["issue"] = issue
        return self._post("cancel_order", body)
    
    def get_wallets(self) -> list:
        """Получить ваши кошельки и балансы."""
        data = self._get("wallets")
        return data["wallets"]
    
    def get_my_servers(self) -> list:
        """Получить серверы, которые вы предоставляете на маркетплейс."""
        data = self._get("my_servers")
        return data["servers"]


class CloreAPIError(Exception):
    """Вызывается, когда API Clore возвращает ненулевой код."""
    
    ERROR_CODES = {
        0: "Нормально",
        1: "Ошибка базы данных",
        2: "Неверные входные данные",
        3: "Неверный API-токен",
        4: "Неверная конечная точка",
        5: "Превышен лимит запросов (1 запрос/сек)",
        6: "Ошибка (см. поле error)",
    }
    
    def __init__(self, response: dict):
        self.code = response.get("code")
        self.error = response.get("error", "")
        message = self.ERROR_CODES.get(self.code, f"Неизвестный код {self.code}")
        if self.error:
            message = f"{message}: {self.error}"
        super().__init__(f"Ошибка API Clore {self.code}: {message}")
```

### Полный рабочий пример

```python
import os
from clore_client import CloreClient, CloreAPIError

# Инициализация клиента
client = CloreClient(api_key=os.environ["CLORE_API_KEY"] )

# 1. Просмотр маркетплейса
servers = client.list_servers()
print(f"Найдено {len(servers)} серверов на маркетплейсе")

# 2. Фильтрация доступных серверов RTX 4090
rtx4090_servers = [
    s for s in servers
    if "4090" in s["specs"].get("gpu", "") and not s["rented"]
]

if not rtx4090_servers:
    print("Не найдено доступных серверов RTX 4090")
    exit(1)

# 3. Выбор самого дешевого
cheapest = min(rtx4090_servers, key=lambda s: s["price"]["on_demand"]["bitcoin"] )
print(f"Самый дешевый RTX 4090: ID сервера {cheapest['id']}, "
      f"цена {cheapest['price']['on_demand']['bitcoin']:.8f} BTC/день")

# 4. Создание заказа
try:
    client.create_order(
        server_id=cheapest["id"],
        image="cloreai/ubuntu20.04-jupyter",
        order_type="on-demand",
        currency="bitcoin",
        ports={"22": "tcp", "8888": "http"},
        ssh_password="SecurePass123",
        jupyter_token="MyToken123",
    )
    print("Заказ успешно создан!")
except CloreAPIError as e:
    print(f"Не удалось создать заказ: {e}")
    exit(1)

# 5. Проверка ваших заказов
orders = client.get_orders()
for order in orders:
    if not order.get("expired"):
        cluster = order.get("pub_cluster", [])
        tcp = order.get("tcp_ports", [])
        print(f"Заказ {order['id']}: сервер {order['si']}")
        if cluster and tcp:
            ssh_port = tcp[0].split(":")[1]
            print(f"  SSH: ssh root@{cluster[0]} -p {ssh_port}")
```

***

## Пример Node.js

Используя нативный `fetch` API (Node.js 18+):

```javascript
const BASE_URL = 'https://api.clore.ai/v1';

class CloreClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.defaultHeaders = {
      'auth': apiKey,
    };
  }

  async get(endpoint, params = {}) {
    const url = new URL(`${BASE_URL}/${endpoint}`);
    Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
    
    const res = await fetch(url.toString(), {
      headers: this.defaultHeaders,
    });
    
    const data = await res.json();
    if (data.code !== 0) {
      throw new Error(`Ошибка API Clore ${data.code}: ${data.error || 'неизвестно'}`);
    }
    return data;
  }

  async post(endpoint, body) {
    const res = await fetch(`${BASE_URL}/${endpoint}`, {
      method: 'POST',
      headers: {
        ...this.defaultHeaders,
        'Content-type': 'application/json',
      },
      body: JSON.stringify(body),
    });
    
    const data = await res.json();
    if (data.code !== 0) {
      throw new Error(`Ошибка API Clore ${data.code}: ${data.error || 'неизвестно'}`);
    }
    return data;
  }

  async listServers() {
    const data = await this.get('marketplace');
    return data.servers;
  }

  async getOrders(includeCompleted = false) {
    const params = includeCompleted ? { return_completed: 'true' } : {};
    const data = await this.get('my_orders', params);
    return data.orders;
  }

  async createOrder({ serverId, image, type = 'on-demand', currency = 'bitcoin', spotprice, ports, sshPassword, jupyterToken, env, command }) {
    const body = {
      currency,
      image,
      renting_server: serverId,
      type,
      ...(spotprice && { spotprice }),
      ...(ports && { ports }),
      ...(sshPassword && { ssh_password: sshPassword }),
      ...(jupyterToken && { jupyter_token: jupyterToken }),
      ...(env && { env }),
      ...(command && { command }),
    };
    return this.post('create_order', body);
  }

  async cancelOrder(orderId, issue = null) {
    const body = { id: orderId };
    if (issue) body.issue = issue;
    return this.post('cancel_order', body);
  }
}

// Пример использования
const client = new CloreClient(process.env.CLORE_API_KEY);

async function main() {
  // Просмотреть маркетплейс
  const servers = await client.listServers();
  console.log(`На маркетплейсе ${servers.length} серверов`);

  // Найти доступные серверы RTX 4090
  const available = servers.filter(
    s => s.specs.gpu.includes('4090') && !s.rented
  );
  console.log(`Доступные серверы RTX 4090: ${available.length}`);

  // Получить текущие заказы
  const orders = await client.getOrders();
  const activeOrders = orders.filter(o => !o.expired);
  console.log(`Активные заказы: ${activeOrders.length}`);

  for (const order of activeOrders) {
    const host = order.pub_cluster?.[0];
    const portMapping = order.tcp_ports?.[0];
    if (host && portMapping) {
      const sshPort = portMapping.split(':')[1];
      console.log(`Заказ ${order.id} → ssh root@${host} -p ${sshPort}`);
    }
  }
}

main().catch(console.error);
```

***

## Типовые рабочие процессы

### Найти самый дешёвый RTX 4090 и арендовать его

```python
from clore_client import CloreClient

client = CloreClient(api_key="YOUR_API_KEY")

def rent_cheapest_rtx4090(image="cloreai/ubuntu20.04-jupyter", ssh_password="SecurePass123"):
    servers = client.list_servers()
    
    # Фильтр: доступный RTX 4090
    candidates = [
        s for s in servers
        if "4090" in s["specs"].get("gpu", "")
        and not s["rented"]
    ]
    
    if not candidates:
        raise RuntimeError("Не найдено доступных серверов RTX 4090")
    
    # Сортировка по цене BTC по запросу
    candidates.sort(key=lambda s: s["price"]["on_demand"]["bitcoin"])
    best = candidates[0]
    
    price_btc = best["price"]["on_demand"]["bitcoin"]
    print(f"Арендуем сервер {best['id']}: {best['specs']['gpu']} @ {price_btc:.8f} BTC/день")
    
    client.create_order(
        server_id=best["id"],
        image=image,
        order_type="on-demand",
        currency="bitcoin",
        ports={"22": "tcp"},
        ssh_password=ssh_password,
    )
    
    print("Готово! Проверьте свои заказы для получения данных SSH-подключения.")
    return best["id"]

rent_cheapest_rtx4090()
```

***

### Мониторинг моих заказов

```python
import time
from clore_client import CloreClient

client = CloreClient(api_key="YOUR_API_KEY")

def monitor_orders(poll_interval_seconds=60):
    """Опрос заказов и вывод обновлений статуса."""
    print(f"Мониторинг заказов (опрос каждые {poll_interval_seconds}с). Нажмите Ctrl+C, чтобы остановить.\n")
    
    while True:
        orders = client.get_orders(include_completed=False)
        active = [o for o in orders if not o.get("expired")]
        
        print(f"--- {len(active)} активных заказ(ов) ---")
        for order in active:
            cluster = order.get("pub_cluster", [])
            tcp = order.get("tcp_ports", [])
            spend = order.get("spend", 0)
            
            ssh_info = ""
            if cluster and tcp:
                port = tcp[0].split(":")[1]
                ssh_info = f" | SSH: {cluster[0]}:{port}"
            
            print(f"  Заказ {order['id']}: сервер {order['si']}"
                  f" | потрачено {spend:.8f} BTC{ssh_info}")
        
        if not active:
            print("  Нет активных заказов.")
        
        print()
        time.sleep(poll_interval_seconds)

monitor_orders()
```

***

### Автоаренда при снижении цены ниже X

```python
import time
from clore_client import CloreClient

client = CloreClient(api_key="YOUR_API_KEY")

def auto_rent_on_price_drop(
    gpu_model: str = "RTX 4090",
    max_price_btc: float = 0.00015,
    image: str = "cloreai/ubuntu20.04-jupyter",
    ssh_password: str = "SecurePass123",
    check_interval_seconds: int = 120,
):
    """
    Следите за маркетплейсом и автоматически арендуйте GPU, когда цена опустится ниже порога.
    
    Аргументы:
        gpu_model: название GPU для поиска (без учёта регистра)
        max_price_btc: максимальная приемлемая цена в день в BTC
        image: Docker-образ для развертывания
        ssh_password: пароль SSH для контейнера
        check_interval_seconds: как часто проверять (соблюдайте лимиты запросов!)
    """
    print(f"Отслеживаем {gpu_model} по цене ≤ {max_price_btc:.8f} BTC/день...")
    
    while True:
        servers = client.list_servers()
        
        for server in servers:
            gpu = server["specs"].get("gpu", "")
            if gpu_model.lower() not in gpu.lower():
                continue
            if server["rented"]:
                continue
            
            price = server["price"]["on_demand"]["bitcoin"]
            if price <= max_price_btc:
                print(f"🎯 Найдено совпадение! Сервер {server['id']}: {gpu} @ {price:.8f} BTC/день")
                
                try:
                    client.create_order(
                        server_id=server["id"],
                        image=image,
                        order_type="on-demand",
                        currency="bitcoin",
                        ports={"22": "tcp"},
                        ssh_password=ssh_password,
                        required_price=price,  # Зафиксировать эту цену
                    )
                    print(f"✅ Заказ создан для сервера {server['id']}!")
                    return server["id"]
                except Exception as e:
                    print(f"Не удалось создать заказ: {e}. Будет повторная попытка...")
        
        print(f"Совпадения пока нет. Проверим снова через {check_interval_seconds}s...")
        time.sleep(check_interval_seconds)

auto_rent_on_price_drop(gpu_model="4090", max_price_btc=0.00012)
```

***

## WebSocket

REST API Clore.ai в настоящее время не предоставляет конечную точку WebSocket. Для мониторинга в реальном времени используйте опрос с разумным интервалом (см. ограничения по частоте запросов ниже).

***

## Ограничения по частоте запросов

| Эндпоинт                         | Лимит                          |
| -------------------------------- | ------------------------------ |
| Большинство эндпоинтов           | **1 запрос/сек**               |
| `create_order`                   | **1 запрос/5 секунд**          |
| `set_spot_price` (снижение цены) | Один раз каждые **600 секунд** |

**Ответ при превышении лимита запросов (код 5):**

```json
{ "code": 5 }
```

**Рекомендации:**

* Добавьте `time.sleep(1)` между последовательными вызовами API
* Для `create_order`, подождите как минимум 5 секунд между запросами
* Используйте интервалы опроса 60+ секунд для циклов мониторинга
* Кэшируйте данные маркетплейса локально, если нужно часто их запрашивать

**Вспомогательная функция для Python:**

```python
import time

def safe_api_call(fn, *args, delay=1.1, **kwargs):
    """Обернуть вызов API с защитой от превышения лимита запросов."""
    result = fn(*args, **kwargs)
    time.sleep(delay)
    return result
```

***

## Обработка ошибок

Каждый ответ API включает в себя `code` поле. Значение `0` означает успех.

### Коды ошибок

| Код | Значение                               | Действие                                    |
| --- | -------------------------------------- | ------------------------------------------- |
| `0` | Успех                                  | —                                           |
| `1` | Ошибка базы данных                     | Повторите попытку через некоторое время     |
| `2` | Неверные входные данные                | Проверьте тело запроса/параметры            |
| `3` | Недействительный API-токен             | Проверьте свой API-ключ в панели управления |
| `4` | Недействительная конечная точка        | Проверьте URL конечной точки                |
| `5` | Превышен лимит запросов (1 запрос/сек) | Добавляйте задержки между запросами         |
| `6` | Ошибка приложения (см. `ошибка` поле)  | Читайте `ошибка` поле для подробностей      |

### Подошибки кода 6

| `ошибка` значение             | Значение                                                                              |
| ----------------------------- | ------------------------------------------------------------------------------------- |
| `exceeded_max_step`           | Снижение спотовой цены слишком велико; проверьте `max_step` поле                      |
| `can_lower_every_600_seconds` | Нужно подождать перед повторным снижением спотовой цены; проверьте `time_to_lowering` |

### Пример обработки ошибок в Python

```python
from clore_client import CloreClient, CloreAPIError
import time

client = CloreClient(api_key="YOUR_API_KEY")

def create_order_with_retry(server_id, image, max_retries=3):
    for attempt in range(max_retries):
        try:
            return client.create_order(
                server_id=server_id,
                image=image,
                order_type="on-demand",
                currency="bitcoin",
                ports={"22": "tcp"},
                ssh_password="SecurePass123",
            )
        except CloreAPIError as e:
            if e.code == 5:  # Rate limit
                print(f"Ограничение по частоте. Ждём 5с... (попытка {attempt+1}/{max_retries})")
                time.sleep(5)
            elif e.code == 3:  # Bad API key
                print("Недействительный API-ключ! Проверьте ваш CLORE_API_KEY.")
                raise
            elif e.code == 2:  # Bad input
                print(f"Неверный запрос: {e}")
                raise
            else:
                print(f"Ошибка API: {e}. Повторная попытка через 3с...")
                time.sleep(3)
    
    raise RuntimeError(f"Не удалось после {max_retries} попыток")
```

### Пример обработки ошибок в JavaScript

```javascript
async function createOrderWithRetry(client, serverConfig, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await client.createOrder(serverConfig);
    } catch (err) {
      const code = parseInt(err.message.match(/error (\d+)/)?.[1]);
      
      if (code === 5) {
        console.log(`Ограничение по частоте. Ждём 5с... (попытка ${attempt + 1}/${maxRetries})`);
        await new Promise(r => setTimeout(r, 5000));
      } else if (code === 3) {
        throw new Error('Недействительный API-ключ');
      } else {
        console.log(`Ошибка API: ${err.message}. Повторная попытка через 3с...`);
        await new Promise(r => setTimeout(r, 3000));
      }
    }
  }
  throw new Error(`Не удалось после ${maxRetries} попыток`);
}
```

***

## Доступные Docker-образы

Clore.ai предоставляет готовые образы, оптимизированные для GPU-нагрузок:

| Образ                         | Описание                  |
| ----------------------------- | ------------------------- |
| `cloreai/ubuntu20.04-jupyter` | Ubuntu 20.04 + JupyterLab |
| `cloreai/ubuntu22.04-jupyter` | Ubuntu 22.04 + JupyterLab |

Вы также можете использовать любой публичный образ Docker Hub. Для доступа к GPU используйте образы с поддержкой CUDA, например:

```
nvidia/cuda:12.1.0-devel-ubuntu22.04
```

***

## Проброс портов

При создании заказа укажите порты, которые нужно открыть:

```json
{
  "ports": {
    "22": "tcp",
    "8888": "http",
    "6006": "http"
  }
}
```

* **`"tcp"`** — прямой проброс TCP-портов (для SSH, пользовательских серверов)
* **`"http"`** — HTTPS-прокси (для Jupyter, веб-интерфейсов). Разрешён только один HTTP-порт на `http_port` поле.

После создания заказа данные подключения появляются в `my_orders`:

```json
{
  "pub_cluster": ["n1.c1.clorecloud.net", "n2.c1.clorecloud.net"],
  "tcp_ports": ["22:10000"],
  "http_port": "8888"
}
```

Подключение по SSH:

```bash
ssh root@n1.c1.clorecloud.net -p 10000
```

Откройте Jupyter в браузере: `https://n1.c1.clorecloud.net` (использует `http_port`)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.clore.ai/clore.ai/clore.ai-ru/razrabotchikam/cli-sdk.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
