> 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-eng-es/desarrolladores/cli-sdk.md).

# Guía de CLI y SDK

## Resumen

Clore.ai proporciona una **API REST** que permite acceso programático completo al mercado de GPU: listar servidores, crear pedidos, supervisar despliegues y cancelar alquileres.

> **Nota:** No hay un binario CLI oficial en este momento. Toda la automatización se realiza directamente a través de la API REST usando herramientas como `curl`, Python o Node.js.

**URL base:** `https://api.clore.ai/v1`

**Formato de respuesta:** JSON. Cada respuesta incluye un `code` campo que indica el estado.

***

## Autenticación

Genera tu clave de API desde el [panel de control de Clore.ai](https://clore.ai):

1. Inicia sesión en tu cuenta
2. Navega hasta **API** sección en la configuración
3. Genera y copia tu clave de API

**Formato del encabezado:**

```
auth: YOUR_API_KEY
```

> ⚠️ **Importante:** El encabezado auth es `auth`, **no** `Authorization: Bearer`. Usar el formato incorrecto devolverá el código `3` (Token de API no válido).

**Ejemplo:**

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

***

## Inicio rápido

### Listar servidores del marketplace

Explora todos los servidores GPU disponibles:

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

**Respuesta:**

```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
}
```

***

### Obtén tus pedidos

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

Incluye pedidos completados/caducados:

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

***

### Crear un pedido (bajo demanda)

```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'
```

**Respuesta:**

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

***

### Crear un pedido spot

Los pedidos spot son más baratos, pero pueden ser superados por una puja mayor. Tú estableces tu precio por día:

```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'
```

***

### Comprobar estado del pedido

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

Los pedidos activos incluyen `pub_cluster` (nombres de host) y `tcp_ports` para acceso SSH:

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

Conéctate por SSH a tu servidor alquilado:

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

***

### Cancelar un pedido

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

Opcionalmente, informa de un problema con el servidor:

```bash
curl -XPOST \
  -H 'auth: YOUR_API_KEY' \
  -H 'Content-type: application/json' \
  -d '{
    "id": 38,
    "issue": "La GPU se sobrecalentaba y limitaba el rendimiento"
  }' \
  'https://api.clore.ai/v1/cancel_order'
```

***

## SDK de Python

Una envoltura ligera que usa la `requests` biblioteca. Instálalo con:

```bash
pip install requests
```

### Clase CloreClient

```python
import requests
import time

class CloreClient:
    """SDK de Python sencillo para la API REST de 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:
        """Obtén todos los servidores disponibles en el marketplace."""
        data = self._get("marketplace")
        return data["servers"]
    
    def get_server_details(self, server_id: int) -> dict:
        """Obtén información del marketplace spot para un servidor específico."""
        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:
        """
        Crea un pedido bajo demanda o spot.
        
        Argumentos:
            server_id: ID del servidor a alquilar
            image: imagen de Docker (p. ej. 'cloreai/ubuntu20.04-jupyter')
            order_type: 'on-demand' o 'spot'
            currency: 'bitcoin' (predeterminado)
            spotprice: Requerido para pedidos spot — precio por día en BTC
            ports: reenvío de puertos, p. ej. {"22": "tcp", "8888": "http"}
            ssh_password: contraseña SSH (solo caracteres alfanuméricos)
            ssh_key: clave pública SSH
            jupyter_token: token de Jupyter Notebook
            env: diccionario de variables de entorno
            command: comando de shell para ejecutar después del inicio del contenedor
        """
        if order_type == "spot" and spotprice is None:
            raise ValueError("spotprice es obligatorio para pedidos spot")
        
        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:
        """Obtén tus pedidos activos y, opcionalmente, los completados."""
        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:
        """Cancela un pedido. Opcionalmente informa de un problema."""
        body = {"id": order_id}
        if issue:
            body["issue"] = issue
        return self._post("cancel_order", body)
    
    def get_wallets(self) -> list:
        """Obtén tus billeteras y saldos."""
        data = self._get("wallets")
        return data["wallets"]
    
    def get_my_servers(self) -> list:
        """Obtén los servidores que estás proporcionando al marketplace."""
        data = self._get("my_servers")
        return data["servers"]


class CloreAPIError(Exception):
    """Se lanza cuando la API de Clore devuelve un código distinto de cero."""
    
    ERROR_CODES = {
        0: "Normal",
        1: "Error de base de datos",
        2: "Datos de entrada no válidos",
        3: "Token de API no válido",
        4: "Punto de conexión no válido",
        5: "Límite de tasa superado (1 solicitud/seg)",
        6: "Error (consulta el campo error)",
    }
    
    def __init__(self, response: dict):
        self.code = response.get("code")
        self.error = response.get("error", "")
        message = self.ERROR_CODES.get(self.code, f"Código desconocido {self.code}")
        if self.error:
            message = f"{message}: {self.error}"
        super().__init__(f"Error de la API de Clore {self.code}: {message}")
```

### Ejemplo completo funcional

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

# Inicializar cliente
client = CloreClient(api_key=os.environ["CLORE_API_KEY"])

# 1. Explorar el marketplace
servers = client.list_servers()
print(f"Se encontraron {len(servers)} servidores en el marketplace")

# 2. Filtrar servidores RTX 4090 disponibles
rtx4090_servers = [
    s for s in servers
    if "4090" in s["specs"].get("gpu", "") and not s["rented"]
]

if not rtx4090_servers:
    print("No se encontraron servidores RTX 4090 disponibles")
    exit(1)

# 3. Elegir el más barato
cheapest = min(rtx4090_servers, key=lambda s: s["price"]["on_demand"]["bitcoin"])
print(f"RTX 4090 más barato: ID de servidor {cheapest['id']}, "
      f"precio {cheapest['price']['on_demand']['bitcoin']:.8f} BTC/día")

# 4. Crear un pedido
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("¡Pedido creado con éxito!")
except CloreAPIError as e:
    print(f"No se pudo crear el pedido: {e}")
    exit(1)

# 5. Comprobar tus pedidos
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"Pedido {order['id']}: servidor {order['si']}")
        if cluster and tcp:
            ssh_port = tcp[0].split(":")[1]
            print(f"  SSH: ssh root@{cluster[0]} -p {ssh_port}")
```

***

## Ejemplo de Node.js

Usando la API nativa `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(`Error de la API de Clore ${data.code}: ${data.error || 'desconocido'}`);
    }
    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(`Error de la API de Clore ${data.code}: ${data.error || 'desconocido'}`);
    }
    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);
  }
}

// Ejemplo de uso
const client = new CloreClient(process.env.CLORE_API_KEY);

async function main() {
  // Listar marketplace
  const servers = await client.listServers();
  console.log(`El marketplace tiene ${servers.length} servidores`);

  // Encontrar servidores RTX 4090 disponibles
  const available = servers.filter(
    s => s.specs.gpu.includes('4090') && !s.rented
  );
  console.log(`Servidores RTX 4090 disponibles: ${available.length}`);

  // Obtener órdenes actuales
  const orders = await client.getOrders();
  const activeOrders = orders.filter(o => !o.expired);
  console.log(`Órdenes activas: ${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(`Orden ${order.id} → ssh root@${host} -p ${sshPort}`);
    }
  }
}

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

***

## Flujos de trabajo comunes

### Encuentra la RTX 4090 más barata y alquílala

```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()
    
    # Filtro: RTX 4090 disponible
    candidates = [
        s for s in servers
        if "4090" in s["specs"].get("gpu", "")
        and not s["rented"]
    ]
    
    if not candidates:
        raise RuntimeError("No se encontraron servidores RTX 4090 disponibles")
    
    # Ordenar por precio BTC bajo demanda
    candidates.sort(key=lambda s: s["price"]["on_demand"]["bitcoin"])

    best = candidates[0]
    
    price_btc = best["price"]["on_demand"]["bitcoin"]
    print(f"Alquilando el servidor {best['id']}: {best['specs']['gpu']} @ {price_btc:.8f} BTC/día")
    
    client.create_order(
        server_id=best["id"],
        image=image,
        order_type="on-demand",
        currency="bitcoin",
        ports={"22": "tcp"},
        ssh_password=ssh_password,
    )
    
    print("¡Hecho! Revisa tus órdenes para ver los detalles de conexión SSH.")
    return best["id"]

rent_cheapest_rtx4090()
```

***

### Monitorear mis órdenes

```python
import time
from clore_client import CloreClient

client = CloreClient(api_key="YOUR_API_KEY")

def monitor_orders(poll_interval_seconds=60):
    """Consulta las órdenes e imprime actualizaciones de estado."""
    print(f"Monitoreando órdenes (sondeo cada {poll_interval_seconds}s). Ctrl+C para detener.\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)} orden(es) activa(s) ---")
        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"  Orden {order['id']}: servidor {order['si']}"
                  f" | gastado {spend:.8f} BTC{ssh_info}")
        
        if not active:
            print("  No hay órdenes activas.")
        
        print()
        time.sleep(poll_interval_seconds)

monitor_orders()
```

***

### Auto-alquilar cuando el precio baje por debajo de 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,
):
    """
    Observa el marketplace y alquila automáticamente una GPU cuando el precio baje por debajo del umbral.
    
    Argumentos:
        gpu_model: nombre de la GPU a buscar (sin distinción entre mayúsculas y minúsculas)
        max_price_btc: precio máximo aceptable por día en BTC
        image: imagen de Docker que se implementará
        ssh_password: contraseña SSH para el contenedor
        check_interval_seconds: cada cuánto comprobar (¡respeta los límites de tasa!)
    """
    print(f"Buscando {gpu_model} a ≤ {max_price_btc:.8f} BTC/día...")
    
    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"🎯 ¡Coincidencia encontrada! Servidor {server['id']}: {gpu} @ {price:.8f} BTC/día")
                
                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,  # Bloquear este precio
                    )
                    print(f"✅ ¡Orden creada para el servidor {server['id']}!")
                    return server["id"]
                except Exception as e:
                    print(f"Error al crear la orden: {e}. Reintentando...")
        
        print(f"Aún no hay coincidencias. Comprobando de nuevo en {check_interval_seconds}s...")
        time.sleep(check_interval_seconds)

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

***

## WebSocket

La API REST de Clore.ai no expone actualmente un endpoint WebSocket. Para el monitoreo en tiempo real, usa sondeo con un intervalo razonable (consulta los límites de tasa abajo).

***

## Límites de tasa

| Endpoint                               | Límite                          |
| -------------------------------------- | ------------------------------- |
| La mayoría de los endpoints            | **1 solicitud por segundo**     |
| `create_order`                         | **1 solicitud cada 5 segundos** |
| `set_spot_price` (reducción de precio) | Una vez cada **600 segundos**   |

**Respuesta de límite de tasa (código 5):**

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

**Buenas prácticas:**

* Añade `time.sleep(1)` entre llamadas consecutivas a la API
* Para `create_order`, espera al menos 5 segundos entre solicitudes
* Usa intervalos de sondeo de 60+ segundos para bucles de monitoreo
* Almacena en caché los datos del marketplace localmente si necesitas consultarlos con frecuencia

**Ayudante de Python:**

```python
import time

def safe_api_call(fn, *args, delay=1.1, **kwargs):
    """Envuelve una llamada a la API con seguridad frente a límites de tasa."""
    result = fn(*args, **kwargs)
    time.sleep(delay)
    return result
```

***

## Manejo de errores

Cada respuesta de la API incluye un `code` campo. Un valor de `0` significa éxito.

### Códigos de error

| Código | Significado                                | Acción                                      |
| ------ | ------------------------------------------ | ------------------------------------------- |
| `0`    | Éxito                                      | —                                           |
| `1`    | Error de base de datos                     | Reintenta después de un retraso             |
| `2`    | Datos de entrada inválidos                 | Revisa el cuerpo/parámetros de tu solicitud |
| `3`    | Token de API inválido                      | Verifica tu clave de API en el panel        |
| `4`    | Endpoint inválido                          | Comprueba la URL del endpoint               |
| `5`    | Límite de tasa superado (1 solicitud/seg)  | Añade retrasos entre solicitudes            |
| `6`    | Error de la aplicación (ver `error` campo) | Lee el `error` campo para más detalles      |

### Suberrores del código 6

| `error` valor                 | Significado                                                                        |
| ----------------------------- | ---------------------------------------------------------------------------------- |
| `exceeded_max_step`           | La reducción del precio spot es demasiado grande; comprueba `max_step` campo       |
| `can_lower_every_600_seconds` | Debes esperar antes de volver a bajar el precio spot; comprueba `time_to_lowering` |

### Ejemplo de manejo de errores en 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:  # Límite de tasa
                print(f"Límite de tasa alcanzado. Esperando 5s... (intento {attempt+1}/{max_retries})")
                time.sleep(5)
            elif e.code == 3:  # Clave de API incorrecta
                print("¡Clave de API inválida! Revisa tu CLORE_API_KEY.")
                raise
            elif e.code == 2:  # Entrada incorrecta
                print(f"Solicitud inválida: {e}")
                raise
            else:
                print(f"Error de API: {e}. Reintentando en 3s...")
                time.sleep(3)
    
    raise RuntimeError(f"Falló tras {max_retries} intentos")
```

### Ejemplo de manejo de errores en 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(`Límite de tasa alcanzado. Esperando 5s... (intento ${attempt + 1}/${maxRetries})`);
        await new Promise(r => setTimeout(r, 5000));
      } else if (code === 3) {
        throw new Error('Clave de API inválida');
      } else {
        console.log(`Error de API: ${err.message}. Reintentando en 3s...`);
        await new Promise(r => setTimeout(r, 3000));
      }
    }
  }
  throw new Error(`Falló tras ${maxRetries} intentos`);
}
```

***

## Imágenes de Docker disponibles

Clore.ai proporciona imágenes preconstruidas optimizadas para cargas de trabajo con GPU:

| Imagen                        | Descripción               |
| ----------------------------- | ------------------------- |
| `cloreai/ubuntu20.04-jupyter` | Ubuntu 20.04 + JupyterLab |
| `cloreai/ubuntu22.04-jupyter` | Ubuntu 22.04 + JupyterLab |

También puedes usar cualquier imagen pública de Docker Hub. Para acceso a la GPU, usa imágenes con CUDA, por ejemplo:

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

***

## Redirección de puertos

Al crear una orden, especifica los puertos a exponer:

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

* **`"tcp"`** — Redirección directa de puertos TCP (para SSH, servidores personalizados)
* **`"http"`** — Proxy HTTPS (para Jupyter, interfaces web). Solo se permite un puerto HTTP por `http_port` campo.

Después de crear la orden, los detalles de conexión aparecen en `my_orders`:

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

Conéctate vía SSH:

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

Accede a Jupyter desde el navegador: `https://n1.c1.clorecloud.net` (usa el `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-eng-es/desarrolladores/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.
