# Constellation Execution
Source: https://docs.rotastellar.com/agent/constellation
Multi-satellite DAG orchestration with ISL coordination and automatic failover
# Constellation Execution
**WS4 Agent Mode**
Constellation Execution extends the Operator Agent to orchestrate workloads across multiple satellites. A DAG-based execution plan is distributed across the constellation, with steps assigned to individual satellites and data transferred between them via inter-satellite links (ISLs). The agent runtime handles step lifecycle, ISL coordination, and automatic failover when a satellite becomes unhealthy.
Constellation mode requires a multi-satellite deployment created from a constellation DAG plan. See [CAE Constellation DAG](/cae/constellation-dag) for how plans are generated.
## ConstellationState
Each agent participating in a constellation deployment maintains a `ConstellationState` that tracks its view of the distributed execution.
| Field | Type | Description |
| ------------------- | ----- | -------------------------------------------------- |
| `assigned_steps` | map | Steps assigned to this satellite, keyed by step ID |
| `active_transfers` | array | ISL transfers currently in progress |
| `completed_steps` | set | Step IDs that have completed successfully |
| `failed_over_steps` | set | Step IDs that were reassigned due to failover |
## Step Lifecycle
Each step in the constellation DAG follows a deterministic state machine:
```
Pending --> Executing --> Completed
|
v
FailedOver
```
| State | Description |
| ------------ | ----------------------------------------------------------------- |
| `Pending` | Step assigned but waiting for dependencies or resources |
| `Executing` | Step actively running on the assigned satellite |
| `Completed` | Step finished successfully, output available for downstream steps |
| `FailedOver` | Step reassigned to another satellite due to health check failure |
When a step completes, its output data is made available for dependent steps. If the dependent step is assigned to a different satellite, an ISL transfer is initiated automatically.
## Automatic Failover
The agent runtime continuously monitors satellite health during constellation execution. A failover is triggered when any of the following conditions are detected:
| Condition | Threshold | Description |
| ------------------- | -------------- | ----------------------------------------------- |
| Battery critical | \< 10% | Insufficient power to complete compute step |
| Thermal exceedance | > 75C | Risk of hardware damage or thermal shutdown |
| Compute unavailable | Battery \< 15% | Not enough power headroom for sustained compute |
Failover reassigns the step to the next eligible satellite in the DAG. If no eligible satellite is available, the step is marked as failed and the constellation plan terminates with a partial completion status.
When a failover occurs, the following sequence executes:
1. The current satellite emits `constellation.failover` with the reason
2. The orchestrator selects an alternate satellite from the DAG
3. The step is reassigned and a `constellation.failover_acknowledged` event is emitted
4. The new satellite begins execution from the last checkpoint (if available)
## ISL Transfer Lifecycle
Data transfers between satellites follow a multi-hop model. Each hop represents a direct ISL link between two satellites in range.
```
started --> hop_completed (x N) --> completed + quality_report
```
| State | Description |
| ---------------- | -------------------------------------------------------------------- |
| `started` | Transfer initiated between source and destination satellites |
| `hop_completed` | A single ISL hop finished, includes quality metrics for that segment |
| `completed` | All hops finished, data delivered to destination satellite |
| `quality_report` | Aggregate link quality metrics for the full transfer path |
### ISL Link Quality Model
Link quality between any two satellites is computed dynamically based on distance and eclipse state:
| Parameter | Formula / Value |
| ------------------- | -------------------------------------------------- |
| Distance factor | `1 - (distance_km / 5000) * 0.6` |
| Eclipse penalty | `0.9` (applied when either endpoint is in eclipse) |
| Effective bandwidth | `100 Mbps * quality` |
| Propagation latency | `distance_km / c + 2ms` (where c = 299,792 km/s) |
| Max range | 5,000 km (quality = 0 beyond this) |
The 2ms additional latency accounts for onboard processing and protocol overhead at each hop. For multi-hop transfers, latency is cumulative across all hops.
**Example:** Two satellites 2,000 km apart, one in eclipse:
* Distance factor: `1 - (2000 / 5000) * 0.6 = 0.76`
* Eclipse penalty: `0.76 * 0.9 = 0.684`
* Effective bandwidth: `100 * 0.684 = 68.4 Mbps`
* Propagation latency: `2000 / 299792 + 0.002 = 8.67ms`
## Event Enrichment
All constellation events are enriched with real-time satellite telemetry at the moment the event is generated:
| Field | Type | Description |
| ------------------------ | ------- | ------------------------------------------ |
| `actual_battery_percent` | number | Battery level at event time |
| `actual_temperature_c` | number | Temperature at event time |
| `lat` | number | Geodetic latitude |
| `lon` | number | Geodetic longitude |
| `altitude_km` | number | Altitude above Earth surface |
| `in_eclipse` | boolean | Whether the satellite is in Earth's shadow |
This telemetry is sourced from the `SimulatedSatellite` executor, which integrates with the [Simulation Sessions](/sim/sessions) service for subsystem state.
## Event Types
### Constellation Events
| Event | Description | Key Payload Fields |
| ------------------------------------- | ---------------------------------- | ------------------------------------------------------ |
| `constellation.step_assigned` | Step assigned to a satellite | `step_id`, `satellite_id`, `dependencies` |
| `constellation.step_started` | Step execution begins | `step_id`, `satellite_id` |
| `constellation.step_completed` | Step finished successfully | `step_id`, `duration_s`, `data_output_mb` |
| `constellation.failover` | Step failover initiated | `step_id`, `from_satellite`, `reason` |
| `constellation.failover_acknowledged` | Failover accepted by new satellite | `step_id`, `to_satellite` |
| `constellation.satellite_complete` | All steps on a satellite are done | `satellite_id`, `steps_completed`, `steps_failed_over` |
### ISL Events
| Event | Description | Key Payload Fields |
| ----------------------------- | --------------------------- | ---------------------------------------------------------------------------- |
| `isl_transfer.started` | ISL data transfer initiated | `from`, `to`, `data_mb`, `hop_count` |
| `isl_transfer.hop_completed` | Single hop finished | `from`, `to`, `hop_index`, `quality`, `latency_ms` |
| `isl_transfer.completed` | Full transfer delivered | `from`, `to`, `total_duration_s`, `data_mb` |
| `isl_transfer.quality_report` | Aggregate path quality | `avg_quality`, `min_quality`, `total_latency_ms`, `effective_bandwidth_mbps` |
## Integration with SimulatedSatellite
In simulation mode, the constellation executor uses the `SimulatedSatellite` backend to model each satellite's behavior. This executor:
* Maintains per-satellite subsystem state (battery, thermal, memory, CPU)
* Applies realistic charge/discharge and thermal models per tick
* Evaluates failover conditions against live subsystem values
* Generates ISL quality metrics from actual propagated positions
The `SimulatedSatellite` executor connects to the Sim service's [session API](/sim/sessions) to persist and retrieve constellation state.
Full protocol specification for agent communication
How constellation execution plans are generated
# Operator Agent
Source: https://docs.rotastellar.com/agent/overview
The execution layer for orbital compute — a pull-based agent protocol for running workloads on satellites
# Operator Agent
The RotaStellar Operator Agent is a lightweight runtime that executes compute workloads on satellites. It uses a **pull-based protocol** designed for intermittent connectivity — agents operate autonomously and sync with Mission Control during contact windows.
The Operator Agent is open source. See the [GitHub repository](https://github.com/rotastellar/rotastellar-agent) for the Rust SDK.
## Architecture
```mermaid theme={null}
sequenceDiagram
participant Agent as Satellite Agent
participant API as Console API
Agent->>API: POST /api/agent/register
API-->>Agent: agent_id confirmed
loop Every contact window
Agent->>API: GET /api/agent/workloads
API-->>Agent: pending workloads + events
end
Note over Agent: Execute workload steps locally
Agent->>API: POST /api/deployments/{id}/events
Note right of API: step.started, step.progress, step.completed, job.completed
loop Periodic
Agent->>API: POST /api/agent/telemetry
Note right of API: heartbeat, resource usage
end
```
The agent runs on the satellite (or in simulation on a development machine). It communicates exclusively with the Console API — there is no direct connection to the CAE planner.
## How It Works
1. **Poll** — Agent checks for pending workloads during contact windows
2. **Execute** — Agent runs workload steps locally on the satellite
3. **Report** — Agent streams execution events back to Console
4. **Telemetry** — Agent sends periodic health/status heartbeats
The protocol is pull-based by design. Satellites have intermittent ground station contact windows — typically a few minutes per orbit. The agent polls when connectivity is available, executes autonomously, and reports results on the next pass.
## Deployment Modes
| Mode | Description |
| ----------- | ------------------------------------------------------------------------------------------- |
| `simulated` | Console generates events from CAE plan data. No agent involved. Good for testing and demos. |
| `live` | Agent polls, executes, and reports events. Real or hardware-in-the-loop execution. |
## Event Types
The agent uses the same event format as the [CAE simulator](/cae/understanding-plans). Events track the full lifecycle of a workload execution:
| Event | Description |
| ------------------------------ | -------------------------------------------- |
| `job.accepted` | Workload received and queued |
| `placement.decided` | Step placement decision (on-board vs ground) |
| `plan.created` | Execution plan finalized |
| `step.started` | Compute step begins |
| `step.progress` | Progress update (25%, 50%, 75%) |
| `step.completed` | Compute step finished |
| `transfer.started` | Data transfer initiated |
| `transfer.completed` | Data transfer finished |
| `checkpoint.saved` | State checkpoint persisted |
| `security.encrypted` | Data encrypted |
| `job.completed` | All steps finished successfully |
| `job.failed` | Execution failed |
| `constellation.step_assigned` | DAG step assigned to satellite |
| `constellation.step_completed` | DAG step finished |
| `constellation.failover` | Step failed, reassigning |
| `isl_transfer.started` | ISL data transfer initiated |
| `isl_transfer.completed` | ISL transfer done |
| `checkpoint.predicted` | Hazard prediction generated |
Full protocol specification with auth, lifecycle, and error handling
Multi-satellite DAG orchestration with ISL coordination
Build agents with the Rust crate
Run your first simulation in 5 minutes
# Protocol Specification
Source: https://docs.rotastellar.com/agent/protocol
Full specification of the RotaStellar Agent Protocol — authentication, lifecycle, event types, and error handling
# Agent Protocol Specification
**Version:** 0.1.0
The RotaStellar Agent Protocol defines how satellite-side agents communicate with the Console API. It is a **pull-based** protocol designed for intermittent satellite connectivity.
## Authentication
All agent requests authenticate via API key in the `X-API-Key` header. The agent identifies itself via the `X-Agent-ID` header.
```
X-API-Key: rs_live_...
X-Agent-ID: sat-25544
```
API keys are created in Mission Control under **Developer > API Keys**. Keys are hashed (SHA-256) server-side and compared against stored hashes. Keys can be revoked at any time from the Console.
## Agent Lifecycle
```mermaid theme={null}
stateDiagram-v2
[*] --> Register
Register --> Poll
Poll --> Execute : Workload available
Poll --> Poll : No work (sleep)
Execute --> Execute : Report events & telemetry
Execute --> Complete : job.completed
Execute --> Failed : job.failed
Complete --> Poll : Ready for next workload
Failed --> Poll : Ready for next workload
```
### 1. Register
The agent registers with the Console on first startup. This creates or updates an agent record.
```
POST /api/agent/register
```
**Request:**
```json theme={null}
{
"agent_id": "sat-25544",
"satellite_id": "25544",
"satellite_name": "ISS (ZARYA)",
"agent_version": "0.1.0"
}
```
**Response (201):**
```json theme={null}
{
"id": "sat-25544",
"status": "idle"
}
```
If the `agent_id` already exists for this user, the record is updated (upsert).
### 2. Poll for Workloads
The agent polls periodically for pending deployments assigned to its satellite.
```
GET /api/agent/workloads
```
**Response (200) — Work available:**
```json theme={null}
{
"plan_id": "abc-123",
"deployment_id": "dep-456",
"satellite_id": "25544",
"plan_data": { ... },
"events": [
{
"type": "job.accepted",
"timestamp": "2026-03-07T12:00:00Z",
"job_id": "preset-001",
"payload": { "preset": "split-learning", "steps": 8 }
}
]
}
```
**Response (204) — No work available.**
The agent should sleep for `poll_interval_s` and retry.
The server returns the oldest pending deployment where:
* `mode = 'live'`
* `satellite_id` matches the agent's registered satellite
* `status = 'pending'`
On dispatch, the server updates the deployment status to `dispatched`.
### 3. Report Events
During execution, the agent reports events as they occur.
```
POST /api/deployments/{deployment_id}/events
```
**Request:**
```json theme={null}
{
"type": "step.completed",
"timestamp": "2026-03-07T14:23:45Z",
"job_id": "preset-001",
"step_id": "feature_extraction",
"payload": {
"duration_s": 180,
"location": "onboard",
"data_output_mb": 10.5
}
}
```
**Response (201):**
```json theme={null}
{
"id": "evt-789"
}
```
The server stores the event and updates the deployment status based on event type:
* `job.accepted` (when `dispatched`) → deployment status = `running`
* `job.completed` → deployment status = `completed`
* `job.failed` → deployment status = `failed`
### 4. Report Telemetry
Agents send periodic heartbeats with health data.
```
POST /api/agent/telemetry
```
**Request:**
```json theme={null}
{
"agent_id": "sat-25544",
"status": "executing",
"timestamp": "2026-03-07T14:23:45Z",
"cpu_percent": 67.5,
"memory_mb": 128.0,
"battery_percent": 82.0,
"temperature_c": 34.2
}
```
**Response (200):**
```json theme={null}
{
"ok": true
}
```
All fields except `agent_id`, `status`, and `timestamp` are optional.
## Event Types
All events follow this structure:
```json theme={null}
{
"type": "",
"timestamp": "",
"job_id": "",
"step_id": "",
"payload": { ... }
}
```
### Lifecycle Events
| Type | Description | Payload |
| --------------- | ------------------------------- | --------------------------------------------------- |
| `job.accepted` | Workload received and queued | `preset`, `category`, `steps`, `security` |
| `plan.created` | Execution plan finalized | `segments`, `windows_used`, `total_duration_s` |
| `job.completed` | All steps finished successfully | `total_duration_s`, `status`, `delivery_confidence` |
| `job.failed` | Execution failed | `total_duration_s`, `status` |
### Placement Events
| Type | Description | Payload |
| ------------------- | ----------------------- | ------------------------------------- |
| `placement.decided` | Step placement decision | `location` (onboard/ground), `reason` |
### Compute Events
| Type | Description | Payload |
| ---------------- | --------------------- | ------------------------------------------ |
| `step.started` | Compute step begins | `location`, `window`, `window_label` |
| `step.progress` | Progress update | `percent` (25, 50, 75) |
| `step.completed` | Compute step finished | `duration_s`, `location`, `data_output_mb` |
### Transfer Events
| Type | Description | Payload |
| ------------------------- | -------------------------- | -------------------------------------------------------- |
| `transfer.started` | Data transfer initiated | `type`, `raw_data_mb`, `total_transfer_mb`, `fec_scheme` |
| `transfer.pass_started` | Ground station pass begins | `ground_station`, `station_name`, `elevation_peak_deg` |
| `transfer.progress` | Transfer progress | `data_transferred_mb`, `total_mb` |
| `transfer.pass_completed` | Pass finished | `data_transferred_mb`, `ground_station` |
| `transfer.completed` | All transfers done | `total_transferred_mb`, `duration_s` |
| `transfer.retransmission` | Blocks retransmitted (BER) | `blocks_retransmitted`, `ber` |
### Security Events
| Type | Description | Payload |
| ----------------------- | ---------------------- | -------------------------- |
| `security.encrypted` | Data encrypted | `algorithm`, `data_mb` |
| `security.key_exchange` | Key exchange performed | `duration_s`, `encryption` |
### Checkpoint Events
| Type | Description | Payload |
| ---------------------- | --------------------------- | --------------------------------------------------------------------------------------------- |
| `checkpoint.saved` | State persisted | `checkpoint_number`, `progress_fraction` |
| `checkpoint.predicted` | Hazard prediction generated | `hazards_count`, `checkpoints_count`, `next_hazard`, `max_safe_window_s`, `overhead_fraction` |
### Orbital Compute Primitive Events
Eclipse, window, and pass steps emit specialized events. See [Orbital Compute Primitives](/cae/orbital-primitives) for details.
| Type | Description | Payload |
| ------------------------ | --------------------- | ---------------------------------------------------------------- |
| `eclipse_step.started` | Eclipse step begins | `energy_budget_j`, `eclipse_policy`, `actual_battery_wh` |
| `eclipse_step.completed` | Eclipse step finished | `energy_consumed_j`, `actual_battery_wh`, `actual_temperature_c` |
| `window_step.started` | Window step begins | `planned_tier`, `quality_tiers`, `actual_battery_percent` |
| `window_step.degraded` | Tier downgraded | `from_tier`, `to_tier`, `reason` |
| `window_step.completed` | Window step finished | `achieved_tier`, `output_quality`, `degradations` |
| `pass_step.started` | Pass step begins | `sequence_index`, `sequence_total`, `actual_battery_percent` |
| `pass_step.completed` | Pass step finished | `sequence_index`, `sequence_total`, `merge_strategy` |
### Constellation Events
Multi-satellite DAG orchestration events. See [Constellation Execution](/agent/constellation) for details.
| Type | Description | Payload |
| ---------------------------------- | -------------------------- | ----------------------------------------------------- |
| `constellation.step_assigned` | Step assigned to satellite | `step_id`, `step_name`, `satellite_id`, `window_id` |
| `constellation.step_started` | Agent began executing step | `step_id`, `actual_battery_percent` |
| `constellation.step_completed` | Step finished | `step_id`, `duration_s`, `actual_battery_percent` |
| `constellation.failover` | Step failed, reassigning | `step_id`, `from_satellite`, `to_satellite`, `reason` |
| `constellation.satellite_complete` | All assigned steps done | `satellite_id`, `completed_count` |
### ISL Transfer Events
| Type | Description | Payload |
| ---------------------------- | ---------------------- | ------------------------------------------------------------ |
| `isl_transfer.started` | ISL transfer initiated | `src_satellite`, `dst_satellite`, `data_mb`, `hops`, `route` |
| `isl_transfer.hop_completed` | One ISL hop done | `from`, `to`, `data_mb`, `quality`, `latency_ms`, `bw_mbps` |
| `isl_transfer.completed` | Full transfer done | `total_time_s`, `total_data_mb`, `hops`, `reliability` |
## Error Handling
All error responses follow this format:
```json theme={null}
{
"error": "Human-readable error message"
}
```
| Status | Meaning |
| ------ | ---------------------------------------------- |
| 400 | Invalid request body |
| 401 | Missing or invalid API key |
| 403 | API key valid but insufficient permissions |
| 404 | Resource not found |
| 409 | Conflict (e.g., deployment already dispatched) |
| 429 | Rate limited |
| 500 | Server error |
## Rate Limits
| Endpoint | Limit |
| --------- | ---------------------------------------- |
| Poll | Max 1 request per 10 seconds per agent |
| Events | Max 100 events per minute per deployment |
| Telemetry | Max 1 request per 30 seconds per agent |
## Versioning
The protocol version is included in the `User-Agent` header:
```
User-Agent: rotastellar-agent/0.1.0
```
Breaking changes will increment the minor version until 1.0. After 1.0, semantic versioning applies.
# Agent Quickstart
Source: https://docs.rotastellar.com/agent/quickstart
Run your first simulated satellite execution in 5 minutes
# Agent Quickstart
This guide walks you through running a simulated satellite execution using the RotaStellar Operator Agent.
## Prerequisites
* [Rust 1.75+](https://rustup.rs/) installed
* A RotaStellar Console account at [console.rotastellar.com](https://console.rotastellar.com)
* An API key (create one under **Developer > API Keys** in the Console)
## 1. Clone and Build
```bash theme={null}
git clone https://github.com/rotastellar/rotastellar-agent.git
cd rotastellar-agent
cargo build --release
```
The binary is at `target/release/rotastellar-agent`.
## 2. Create a Plan
Before running the agent, you need a deployment. In Mission Control:
1. Go to **Missions** and create a new mission
2. Open the mission and click **New Plan**
3. Select a satellite (e.g., ISS — NORAD ID `25544`) and a preset (e.g., On-Board ML Inference)
4. Review the plan and click **Deploy**
5. Choose **Live** mode — this creates a deployment that waits for an agent
Alternatively, create a plan via the CAE API and save the response:
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{"satellite_id": "25544", "preset_id": "onboard-ml-inference"}' \
-o plan.json
```
## 3. Run the Agent
### Option A: Poll mode (recommended)
Run the agent in long-running poll mode. It will register with the Console, then continuously poll for pending deployments.
```bash theme={null}
export ROTASTELLAR_API_KEY="rs_live_..."
./target/release/rotastellar-agent run \
--agent-id sat-25544 \
--api-url https://console.rotastellar.com \
--api-key $ROTASTELLAR_API_KEY
```
When you deploy a plan in Mission Control with **Live** mode, the agent will pick it up automatically.
### Option B: Simulate a plan file
If you have a saved CAE plan JSON, you can replay it directly:
```bash theme={null}
./target/release/rotastellar-agent simulate \
--plan plan.json \
--speed 100 \
--api-url https://console.rotastellar.com \
--api-key $ROTASTELLAR_API_KEY
```
## 4. Watch the Execution
Open the deployment in Mission Control. You'll see events appear in the timeline as the agent reports them:
```
[T+ 0s] job.accepted
[T+ 0s] placement.decided capture
[T+ 0s] placement.decided preprocess
[T+ 5s] step.started capture
[T+ 10s] step.progress capture (25%)
[T+ 25s] step.completed capture
[T+ 30s] step.started preprocess
...
[T+ 180s] job.completed
```
The deployment status transitions: `pending` → `dispatched` → `running` → `completed`.
## 5. Check Telemetry
While running, the agent sends periodic telemetry heartbeats. You can see agent status in the Console under **Agents** — including status, last heartbeat, and resource usage.
## What's Next
Deep dive into the pull-based protocol
Build a custom agent for your satellite hardware
# Rust SDK
Source: https://docs.rotastellar.com/agent/rust-sdk
Build satellite agents with the rotastellar-agent Rust crate
# Rust SDK
The `rotastellar-agent` crate provides everything you need to build a satellite agent: the `Agent` trait, a simulated satellite for testing, an HTTP client for the Console API, and a CLI binary.
**License:** [MPL-2.0](https://github.com/rotastellar/rotastellar-agent/blob/master/LICENSE) — modified files must be shared, but you can use the crate in proprietary projects.
## Installation
Add to your `Cargo.toml`:
```toml theme={null}
[dependencies]
rotastellar-agent = { git = "https://github.com/rotastellar/rotastellar-agent" }
```
Or clone and build directly:
```bash theme={null}
git clone https://github.com/rotastellar/rotastellar-agent.git
cd rotastellar-agent
cargo build --release
```
## The Agent Trait
The core abstraction is the `Agent` trait. It defines the satellite-side execution protocol:
```rust theme={null}
#[async_trait]
pub trait Agent: Send + Sync {
/// Poll the Console API for pending workloads.
async fn poll(&self) -> Result, AgentError>;
/// Report an execution event.
async fn report_event(&self, event: &AgentEvent) -> Result<(), AgentError>;
/// Report telemetry data (heartbeat, resource usage).
async fn report_telemetry(&self, telemetry: &AgentTelemetry) -> Result<(), AgentError>;
/// Execute a workload.
async fn execute(&self, workload: &WorkloadSpec) -> Result<(), AgentError>;
/// Start the agent run loop.
async fn start(&self) -> Result<(), AgentError>;
/// Stop the agent gracefully.
async fn stop(&self) -> Result<(), AgentError>;
}
```
## Using SimulatedSatellite
The built-in `SimulatedSatellite` replays pre-computed CAE event streams with realistic timing. Use it for testing and demos.
```rust theme={null}
use rotastellar_agent::{AgentConfig, SimulatedSatellite, Agent};
#[tokio::main]
async fn main() {
let config = AgentConfig {
agent_id: "sat-25544".into(),
api_url: "https://console.rotastellar.com".into(),
api_key: "rs_live_...".into(),
poll_interval_s: 30,
};
// 100x speed — a 90-minute orbit plays in ~1 minute
let agent = SimulatedSatellite::new(config, 100.0).unwrap();
agent.start().await.unwrap();
}
```
The `speed_multiplier` controls replay speed:
* `1.0` — real-time (events play at actual orbital timing)
* `10.0` — 10x faster
* `100.0` — 100x faster (default for demos)
* `10000.0` — near-instant (useful for automated tests)
## Building a Custom Agent
Implement the `Agent` trait to run real computations on satellite hardware:
```rust theme={null}
use async_trait::async_trait;
use rotastellar_agent::{Agent, AgentError, AgentEvent, AgentTelemetry, WorkloadSpec};
struct MyAgent {
config: AgentConfig,
client: ConsoleClient,
}
#[async_trait]
impl Agent for MyAgent {
async fn poll(&self) -> Result , AgentError> {
self.client.poll_workloads().await
}
async fn report_event(&self, event: &AgentEvent) -> Result<(), AgentError> {
self.client.report_event(&event.job_id, event).await
}
async fn report_telemetry(&self, telemetry: &AgentTelemetry) -> Result<(), AgentError> {
self.client.report_telemetry(telemetry).await
}
async fn execute(&self, workload: &WorkloadSpec) -> Result<(), AgentError> {
// Run your computation here.
// Report events for each step transition.
for event in &workload.events {
self.report_event(event).await?;
}
Ok(())
}
async fn start(&self) -> Result<(), AgentError> {
// Implement your run loop
todo!()
}
async fn stop(&self) -> Result<(), AgentError> {
// Signal graceful shutdown
todo!()
}
}
```
## Types
### AgentConfig
```rust theme={null}
pub struct AgentConfig {
pub agent_id: String, // Unique agent identifier (e.g., "sat-25544")
pub api_url: String, // Console API URL
pub api_key: String, // API key (rs_live_...)
pub poll_interval_s: u64, // Seconds between polls (default: 30)
}
```
### WorkloadSpec
```rust theme={null}
pub struct WorkloadSpec {
pub plan_id: String, // CAE plan ID
pub deployment_id: String, // Console deployment ID
pub satellite_id: String, // NORAD catalog ID
pub plan_data: serde_json::Value, // Full CAE plan data
pub events: Vec, // Pre-computed event timeline
}
```
### AgentEvent
```rust theme={null}
pub struct AgentEvent {
pub event_type: String, // Serializes as "type" in JSON
pub timestamp: String, // ISO 8601
pub job_id: String,
pub step_id: Option, // Omitted from JSON when None
pub payload: serde_json::Value,
}
```
### AgentTelemetry
```rust theme={null}
pub struct AgentTelemetry {
pub agent_id: String,
pub status: AgentStatus, // idle, executing, transferring, offline
pub timestamp: String,
pub cpu_percent: Option, // Omitted when None
pub memory_mb: Option,
pub battery_percent: Option,
pub temperature_c: Option,
}
```
### AgentError
```rust theme={null}
pub enum AgentError {
ApiError(String), // API request failed
NetworkError(reqwest::Error), // Network error
SerializationError(serde_json::Error),
ExecutionError(String), // Execution error
Stopped, // Agent stopped
}
```
## CLI
The crate builds a CLI binary with two subcommands:
### `simulate` — Replay a plan file
```bash theme={null}
rotastellar-agent simulate \
--plan plan.json \
--speed 100 \
--api-url https://console.rotastellar.com \
--api-key rs_live_...
```
### `run` — Long-running poll mode
```bash theme={null}
rotastellar-agent run \
--agent-id sat-25544 \
--api-url https://console.rotastellar.com \
--api-key rs_live_...
```
The agent will register, then loop: poll → execute → report → sleep → repeat.
# Constellation Pareto Frontier
Source: https://docs.rotastellar.com/api-reference/cae/constellation-pareto
POST /v1/constellation/pareto
Computes the Pareto frontier across a constellation for multi-objective trade-off analysis
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— No API key required. CORS-validated.
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/constellation/pareto \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"fleet": [
{
"norad_id": "99901",
"name": "RS-LEO-1",
"role": "compute",
"orbit": { "altitude_km": 550, "inclination_deg": 53 }
},
{
"norad_id": "99902",
"name": "RS-LEO-2",
"role": "compute",
"orbit": { "altitude_km": 550, "inclination_deg": 53 }
}
],
"preset_id": "split-learning"
}'
```
```json 200 OK theme={null}
{
"frontier": [
{
"satellite": "RS-LEO-1",
"pareto": [
{ "ocu": 0.25, "latency_s": 120, "reliability": 0.99 },
{ "ocu": 0.50, "latency_s": 80, "reliability": 0.97 },
{ "ocu": 0.75, "latency_s": 55, "reliability": 0.94 }
]
},
{
"satellite": "RS-LEO-2",
"pareto": [
{ "ocu": 0.25, "latency_s": 125, "reliability": 0.99 },
{ "ocu": 0.50, "latency_s": 82, "reliability": 0.96 },
{ "ocu": 0.75, "latency_s": 58, "reliability": 0.93 }
]
}
],
"constellation_metrics": {
"total_ocu": 1.50,
"min_latency_s": 55,
"avg_reliability": 0.963,
"isl_overhead_s": 14
}
}
```
# Plan Constellation DAG
Source: https://docs.rotastellar.com/api-reference/cae/constellation-plan
POST /v1/constellation/plan
Generates an optimized execution plan (DAG) for a satellite constellation workload
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— No API key required. CORS-validated.
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/constellation/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"fleet": [
{
"norad_id": "99901",
"name": "RS-LEO-1",
"role": "compute",
"orbit": { "altitude_km": 550, "inclination_deg": 53 }
},
{
"norad_id": "99902",
"name": "RS-LEO-2",
"role": "compute",
"orbit": { "altitude_km": 550, "inclination_deg": 53 }
},
{
"norad_id": "99903",
"name": "RS-LEO-3",
"role": "aggregator",
"orbit": { "altitude_km": 550, "inclination_deg": 53 }
}
],
"preset_id": "split-learning"
}'
```
```json 200 OK theme={null}
{
"plan_id": "plan_cst_7f3a1b",
"preset_id": "split-learning",
"metrics": {
"critical_path_s": 342,
"satellites_used": 3,
"isl_transfers": 4,
"reliability": 0.973
},
"steps": [
{
"step": 1,
"satellite": "RS-LEO-1",
"task": "forward_pass_split",
"duration_s": 45,
"depends_on": []
},
{
"step": 2,
"satellite": "RS-LEO-2",
"task": "forward_pass_split",
"duration_s": 45,
"depends_on": []
},
{
"step": 3,
"satellite": "RS-LEO-3",
"task": "aggregate_activations",
"duration_s": 30,
"depends_on": [1, 2],
"isl_route": ["RS-LEO-1 → RS-LEO-3", "RS-LEO-2 → RS-LEO-3"]
}
],
"isl_routing": [
{ "from": "RS-LEO-1", "to": "RS-LEO-3", "latency_ms": 12, "bandwidth_mbps": 100 },
{ "from": "RS-LEO-2", "to": "RS-LEO-3", "latency_ms": 14, "bandwidth_mbps": 100 }
]
}
```
# Create Plan
Source: https://docs.rotastellar.com/api-reference/cae/create-plan
POST /v1/plan
Create a constraint-aware execution plan for a satellite and workload
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— No API key required.
## Request
NORAD catalog ID (e.g., `"25544"` for ISS).
Preset workload ID. One of: `onboard-ml-inference`, `split-learning`, `earth-observation-qa`, `federated-learning`, `resilient-store-forward`. Mutually exclusive with `custom_job`.
Custom workload definition with arbitrary step DAG. Mutually exclusive with `preset_id`. See [Custom Workloads](/cae/custom-workloads) for the full schema.
* `name` (string) — Workload name
* `steps` (array, required) — Step definitions with dependencies
* `security` (object) — Security policy overrides
* `policy` (object) — Execution policy overrides
Override security settings from the preset or custom job:
* `encryption` — `none`, `aes128`, or `aes256`
* `data_classification` — `open`, `restricted`, or `confidential`
* `require_authenticated_uplink` — boolean
* `key_rotation_orbits` — number
Planning options:
* `prediction_hours` (number, 1–48, default: 12) — Orbital prediction window
* `min_elevation_deg` (number, 0–90, default: 5) — Minimum ground station elevation
Either `preset_id` or `custom_job` is required, but not both.
```bash Preset theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"preset_id": "onboard-ml-inference"
}'
```
```bash Custom Job theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"custom_job": {
"name": "Capture and Process",
"steps": [
{
"id": "capture",
"name": "Sensor Capture",
"location": "onboard",
"duration_s": 30,
"depends_on": [],
"requires": {"power_w": 40, "compute": 0.3, "thermal_w": 15, "memory_mb": 256, "storage_mb": 1024},
"input_data_mb": 0,
"output_data_mb": 500
},
{
"id": "process",
"name": "Ground Processing",
"location": "ground",
"duration_s": 60,
"depends_on": ["capture"],
"requires": {"power_w": 100, "compute": 1.0, "thermal_w": 50, "memory_mb": 2048, "storage_mb": 2048},
"input_data_mb": 500,
"output_data_mb": 50,
"data_reduction_ratio": 0.1
}
]
}
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan",
headers={
"Content-Type": "application/json",
"Origin": "https://rotastellar.com"
},
json={
"satellite_id": "25544",
"preset_id": "onboard-ml-inference"
}
)
plan = response.json()
print(f"Plan {plan['id']}: {plan['plan']['windows_used']} windows, "
f"confidence {plan['error_budget']['delivery_confidence']}")
```
```json 201 Created theme={null}
{
"id": "a92f33e8-a349-494c-8b4e-f87d859b9ec5",
"created_at": "2026-03-05T06:55:37.811Z",
"version": "1.0.0",
"satellite": {
"id": "25544",
"name": "ISS (ZARYA)",
"norad_id": 25544,
"altitude_km": 417,
"inclination_deg": 51.6,
"period_min": 93,
"tle_epoch": "26063.86671769"
},
"preset": {
"id": "onboard-ml-inference",
"name": "On-Board ML Inference",
"category": "ml-inference",
"steps": 4
},
"orbital_environment": {
"prediction_start": "2026-03-05T06:55:37.811Z",
"prediction_hours": 12,
"eclipse_fraction": 0.348,
"bus": { "..." : "..." },
"windows": [ "..." ],
"ground_passes": [ "..." ],
"summary": {
"total_windows": 14,
"comms_windows": 6,
"sunlit_windows": 9,
"eclipse_windows": 5,
"total_pass_time_s": 2847,
"ground_stations_visible": 8
}
},
"placement_decisions": [
{ "step_id": "capture", "location": "onboard", "reason": "preset_defined" },
{ "step_id": "preprocess", "location": "onboard", "reason": "preset_defined" },
{ "step_id": "inference", "location": "onboard", "reason": "preset_defined" },
{ "step_id": "encrypt_results", "location": "onboard", "reason": "preset_defined" }
],
"transfer_schedule": {
"transfers": [ "..." ],
"total_transfers": 1,
"total_downlink_mb": 11.03,
"total_uplink_mb": 0,
"passes_used": 1,
"total_transfer_time_s": 12
},
"error_budget": {
"worst_case_ber": 0.00001,
"total_fec_overhead_mb": 0.53,
"total_retransmission_reserve_mb": 0.11,
"delivery_confidence": 0.997
},
"security_summary": {
"encryption": "aes256",
"total_encryption_overhead_mb": 0.53,
"total_key_exchanges": 1,
"data_classification": "restricted"
},
"plan": {
"segments": [ "..." ],
"total_duration_s": 1382,
"total_compute_s": 170,
"total_transfer_s": 12,
"total_ground_s": 0,
"windows_used": 2,
"policy": {
"objective": "min_latency",
"deadline_orbits": 3
}
},
"events": [ "..." ]
}
```
```json 400 Validation Error theme={null}
{
"error": {
"code": "validation_error",
"message": "satellite_id is required"
}
}
```
```json 422 Planning Failed theme={null}
{
"error": {
"code": "planning_failed",
"message": "No feasible window for step 'inference': thermal constraint exceeded"
}
}
```
## Errors
| Status | Code | Description |
| ------ | -------------------- | --------------------------------------- |
| 400 | `validation_error` | Invalid request body or parameters |
| 400 | `invalid_body` | Request body is not valid JSON |
| 403 | `origin_not_allowed` | Request from disallowed origin |
| 422 | `planning_failed` | Planner cannot find a feasible schedule |
| 500 | `internal_error` | Unexpected server error |
# Get Plan
Source: https://docs.rotastellar.com/api-reference/cae/get-plan
GET /v1/plan/{plan_id}
Retrieve a previously created execution plan
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— No API key required. Plans expire after 1 hour.
## Request
UUID returned from `POST /v1/plan`.
```bash cURL theme={null}
curl https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan/a92f33e8-a349-494c-8b4e-f87d859b9ec5 \
-H "Origin: https://rotastellar.com"
```
```python Python theme={null}
import requests
plan_id = "a92f33e8-a349-494c-8b4e-f87d859b9ec5"
response = requests.get(
f"https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan/{plan_id}",
headers={"Origin": "https://rotastellar.com"}
)
print(response.json())
```
```json 200 OK theme={null}
{
"id": "a92f33e8-a349-494c-8b4e-f87d859b9ec5",
"created_at": "2026-03-05T06:55:37.811Z",
"version": "1.0.0",
"satellite": { "..." : "..." },
"preset": { "..." : "..." },
"orbital_environment": { "..." : "..." },
"placement_decisions": [ "..." ],
"transfer_schedule": { "..." : "..." },
"error_budget": { "..." : "..." },
"security_summary": { "..." : "..." },
"plan": { "..." : "..." },
"events": [ "..." ]
}
```
```json 404 Not Found theme={null}
{
"error": {
"code": "not_found",
"message": "Plan a92f33e8-... not found or expired"
}
}
```
# Get Plan Events
Source: https://docs.rotastellar.com/api-reference/cae/get-plan-events
GET /v1/plan/{plan_id}/events
Get the simulated execution event stream for a plan
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— No API key required. Plans expire after 1 hour.
## Request
UUID returned from `POST /v1/plan`.
```bash cURL theme={null}
curl https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan/a92f33e8-a349-494c-8b4e-f87d859b9ec5/events \
-H "Origin: https://rotastellar.com"
```
```python Python theme={null}
import requests
plan_id = "a92f33e8-a349-494c-8b4e-f87d859b9ec5"
response = requests.get(
f"https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan/{plan_id}/events",
headers={"Origin": "https://rotastellar.com"}
)
data = response.json()
for event in data["events"]:
print(f"[{event['type']}] {event.get('message', '')}")
```
```json 200 OK theme={null}
{
"plan_id": "a92f33e8-a349-494c-8b4e-f87d859b9ec5",
"events": [
{
"type": "job.accepted",
"timestamp_s": 0,
"message": "Workload accepted: On-Board ML Inference"
},
{
"type": "placement.decided",
"timestamp_s": 0,
"step_id": "capture",
"location": "onboard",
"message": "Step 'capture' placed on-board"
},
{
"type": "step.started",
"timestamp_s": 0,
"step_id": "capture",
"message": "Starting Sensor Data Capture"
},
{
"type": "step.completed",
"timestamp_s": 30,
"step_id": "capture",
"output_data_mb": 2000,
"message": "Completed Sensor Data Capture"
},
{
"type": "transfer.started",
"timestamp_s": 170,
"direction": "downlink",
"data_mb": 11.03,
"message": "Starting downlink transfer"
},
{
"type": "job.completed",
"timestamp_s": 1382,
"message": "Pipeline completed successfully",
"delivery_confidence": 0.997
}
],
"count": 73
}
```
```json 404 Not Found theme={null}
{
"error": {
"code": "not_found",
"message": "Plan a92f33e8-... not found or expired"
}
}
```
# Predict Hazards
Source: https://docs.rotastellar.com/api-reference/cae/hazards
POST /v1/hazards
Predicts orbital hazards and generates a checkpoint schedule for a satellite
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— No API key required. CORS-validated.
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/hazards \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"prediction_hours": 24
}'
```
```json 200 OK theme={null}
{
"hazards": [
{
"type": "eclipse_entry",
"start_epoch": "2026-03-10T14:22:00Z",
"duration_s": 2160,
"severity": 0.6
},
{
"type": "saa_crossing",
"start_epoch": "2026-03-10T16:45:00Z",
"duration_s": 480,
"severity": 0.8
},
{
"type": "eclipse_entry",
"start_epoch": "2026-03-10T15:54:00Z",
"duration_s": 2100,
"severity": 0.6
},
{
"type": "thermal_peak",
"start_epoch": "2026-03-11T02:10:00Z",
"duration_s": 300,
"severity": 0.4
}
],
"checkpoint_schedule": [
{ "epoch": "2026-03-10T14:18:00Z", "reason": "pre_eclipse" },
{ "epoch": "2026-03-10T16:40:00Z", "reason": "pre_saa" },
{ "epoch": "2026-03-11T02:05:00Z", "reason": "pre_thermal" }
],
"summary": {
"hazards_count": 4,
"checkpoints_count": 3,
"max_safe_window_s": 2400,
"overhead_fraction": 0.05
}
}
```
# List Presets
Source: https://docs.rotastellar.com/api-reference/cae/list-presets
GET /v1/presets
List available workload presets with metadata
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— No API key required.
## Request
No parameters.
```bash cURL theme={null}
curl https://rotastellar-cae.subhadip-mitra.workers.dev/v1/presets \
-H "Origin: https://rotastellar.com"
```
```python Python theme={null}
import requests
response = requests.get(
"https://rotastellar-cae.subhadip-mitra.workers.dev/v1/presets",
headers={"Origin": "https://rotastellar.com"}
)
for preset in response.json()["presets"]:
print(f"{preset['id']}: {preset['steps']} steps, {preset['data_flow']['overall_reduction']} reduction")
```
```json Response theme={null}
{
"presets": [
{
"id": "onboard-ml-inference",
"name": "On-Board ML Inference",
"description": "Run ML inference on-board to achieve 190:1 data reduction before downlink...",
"category": "ml-inference",
"steps": 4,
"onboard_steps": 4,
"ground_steps": 0,
"total_compute_s": 170,
"data_flow": {
"initial_capture_mb": 2000,
"final_output_mb": 10.5,
"overall_reduction": "190:1"
},
"needs_downlink": true,
"needs_uplink": false,
"security": {
"encryption": "aes256",
"data_classification": "restricted",
"allowed_ground_stations": null,
"require_authenticated_uplink": true,
"key_rotation_orbits": 24
},
"policy": {
"objective": "min_latency",
"deadline_orbits": 3,
"max_data_loss_fraction": 0.001,
"min_delivery_confidence": 0.99
}
}
],
"count": 5
}
```
# Service Metrics
Source: https://docs.rotastellar.com/api-reference/cae/metrics
GET /v1/metrics
Returns per-endpoint latency percentiles, request counts, and status distribution
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— No API key required. CORS-validated.
```bash theme={null}
curl https://rotastellar-cae.subhadip-mitra.workers.dev/v1/metrics \
-H "Origin: https://rotastellar.com"
```
```json 200 OK theme={null}
{
"endpoints": {
"POST /v1/constellation/plan": {
"requests": 1284,
"latency_ms": { "p50": 42, "p95": 110, "p99": 245 },
"status": { "200": 1260, "400": 18, "500": 6 }
},
"POST /v1/constellation/pareto": {
"requests": 873,
"latency_ms": { "p50": 55, "p95": 140, "p99": 310 },
"status": { "200": 861, "400": 10, "500": 2 }
},
"POST /v1/hazards": {
"requests": 2041,
"latency_ms": { "p50": 28, "p95": 72, "p99": 160 },
"status": { "200": 2018, "400": 20, "500": 3 }
},
"POST /v1/ocu/negotiate": {
"requests": 3512,
"latency_ms": { "p50": 18, "p95": 45, "p99": 98 },
"status": { "200": 3480, "400": 28, "500": 4 }
},
"GET /v1/ocu/summary/:busClass": {
"requests": 1890,
"latency_ms": { "p50": 8, "p95": 22, "p99": 50 },
"status": { "200": 1878, "400": 12 }
}
},
"uptime_s": 604800,
"collected_at": "2026-03-10T12:00:00Z"
}
```
# Negotiate OCU
Source: https://docs.rotastellar.com/api-reference/cae/ocu-negotiate
POST /v1/ocu/negotiate
Negotiates an Orbital Compute Unit allocation for a satellite workload
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— No API key required. CORS-validated.
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/ocu/negotiate \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"workload_power_w": 50
}'
```
```json 200 OK theme={null}
{
"satellite_id": "25544",
"ocu_negotiation": {
"ocu_allocated": 0.62,
"sunlit_hours": 10.4,
"eclipse_hours": 5.6,
"daily_compute_hours": 8.2,
"confidence": 0.94,
"cost_usd_per_hour": 0.035,
"limiting_resource": "power"
},
"power_budget": {
"generation_w": 120,
"bus_overhead_w": 45,
"available_w": 75,
"requested_w": 50,
"margin_w": 25
}
}
```
# OCU Summary
Source: https://docs.rotastellar.com/api-reference/cae/ocu-summary
GET /v1/ocu/summary/{busClass}
Returns the OCU capacity profile for a given satellite bus class
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— No API key required. CORS-validated.
### Path Parameters
| Parameter | Type | Description |
| ---------- | ------ | ---------------------------------------------------------------------- |
| `busClass` | string | Satellite bus class. One of: `1U`, `2U`, `3U`, `6U`, `12U`, `SmallSat` |
```bash theme={null}
curl https://rotastellar-cae.subhadip-mitra.workers.dev/v1/ocu/summary/6U \
-H "Origin: https://rotastellar.com"
```
```json 200 OK theme={null}
{
"bus_class": "6U",
"profile": {
"power_generation_w": 80,
"bus_overhead_w": 30,
"compute_available_w": 50,
"memory_mb": 4096,
"storage_gb": 32
},
"capacity_bands": [
{ "ocu": 0.25, "power_w": 12.5, "description": "Light sensing / telemetry" },
{ "ocu": 0.50, "power_w": 25.0, "description": "Edge inference" },
{ "ocu": 0.75, "power_w": 37.5, "description": "Split learning / compression" },
{ "ocu": 1.00, "power_w": 50.0, "description": "Full compute allocation" }
],
"ocu_reference": {
"sunlit_ocu_max": 1.0,
"eclipse_ocu_max": 0.4,
"daily_average_ocu": 0.72
}
}
```
# Service Index
Source: https://docs.rotastellar.com/api-reference/cae/service-index
GET /v1
Get CAE service capabilities and endpoints
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
— This is a separate service from the main RotaStellar API. No API key required.
## Request
No parameters.
```bash cURL theme={null}
curl https://rotastellar-cae.subhadip-mitra.workers.dev/v1 \
-H "Origin: https://rotastellar.com"
```
```python Python theme={null}
import requests
response = requests.get(
"https://rotastellar-cae.subhadip-mitra.workers.dev/v1",
headers={"Origin": "https://rotastellar.com"}
)
print(response.json())
```
```json Response theme={null}
{
"service": "rotastellar-cae",
"version": "1.0.0",
"description": "Constraint-Aware Execution — orbital compute orchestration across the space-ground boundary",
"capabilities": [
"SGP4 orbital propagation",
"Real eclipse detection (cylindrical shadow model)",
"Ground station pass prediction (12-station network)",
"Compute placement optimization (on-board vs ground)",
"Data transfer scheduling with FEC and encryption overhead",
"Multi-pass downlink allocation",
"Deterministic error budget and delivery confidence"
],
"endpoints": {
"GET /v1/presets": "List available workload presets",
"POST /v1/plan": "Create an execution plan for a satellite + workload",
"GET /v1/plan/:id": "Retrieve a previously created plan",
"GET /v1/plan/:id/events": "Get simulated execution event stream"
}
}
```
# Create Deployment
Source: https://docs.rotastellar.com/api-reference/deployments/create-deployment
POST /api/deployments
Create a new deployment from a plan
**Base URL:** `https://console.rotastellar.com`
— Requires session cookie or API key authentication.
## Request
The ID of the plan to deploy. The plan must belong to the authenticated user.
Simulation speed for simulated deployments. Default: `100`. A value of `100` means a 90-minute orbit plays in \~1 minute.
```bash cURL theme={null}
curl -X POST https://console.rotastellar.com/api/deployments \
-H "Content-Type: application/json" \
-H "Cookie: session=..." \
-d '{
"plan_id": "abc-123",
"speed_multiplier": 100
}'
```
```bash API Key theme={null}
curl -X POST https://console.rotastellar.com/api/deployments \
-H "Content-Type: application/json" \
-H "X-API-Key: rs_live_..." \
-d '{
"plan_id": "abc-123"
}'
```
```json 201 Created theme={null}
{
"id": "dep-456",
"status": "pending"
}
```
```json 400 Validation Error theme={null}
{
"error": "plan_id is required"
}
```
```json 404 Not Found theme={null}
{
"error": "Plan not found"
}
```
## Status Lifecycle
After creation, the deployment status transitions:
| Status | Meaning |
| ------------ | -------------------------------- |
| `pending` | Created, waiting to start |
| `dispatched` | Assigned to an agent (live mode) |
| `running` | Agent is executing |
| `completed` | All steps finished successfully |
| `failed` | Execution failed |
| `cancelled` | Cancelled by user |
# Deployment Events
Source: https://docs.rotastellar.com/api-reference/deployments/deployment-events
GET /api/deployments/{id}/events
Get and report execution events for a deployment
**Base URL:** `https://console.rotastellar.com`
## List Events
Retrieve execution events for a deployment, ordered chronologically.
```
GET /api/deployments/{id}/events
```
**Authentication:** Session cookie (Console UI) or API key.
The deployment ID.
Pagination offset. Default: `0`.
Maximum number of events to return. Default: `100`, max: `500`.
```bash cURL theme={null}
curl "https://console.rotastellar.com/api/deployments/dep-456/events?limit=50" \
-H "Cookie: session=..."
```
```json 200 OK theme={null}
{
"events": [
{
"id": "evt-001",
"event_type": "job.accepted",
"step_id": null,
"payload": {
"preset": "onboard-ml-inference",
"category": "ml-inference",
"steps": 4
},
"event_timestamp": "2026-03-07T12:00:00Z",
"created_at": "2026-03-07T12:00:01Z"
},
{
"id": "evt-002",
"event_type": "placement.decided",
"step_id": "capture",
"payload": {
"location": "onboard",
"reason": "preset_defined"
},
"event_timestamp": "2026-03-07T12:00:00Z",
"created_at": "2026-03-07T12:00:01Z"
}
],
"total": 24,
"offset": 0,
"limit": 50
}
```
***
## Report Event
Agents use this endpoint to report execution events during a live deployment.
```
POST /api/deployments/{id}/events
```
**Authentication:** API key only (`X-API-Key` + `X-Agent-ID` headers).
The event type. See [Event Types](/agent/protocol#event-types) for the full list.
ISO 8601 timestamp of when the event occurred.
Job identifier linking related events.
Step identifier, if the event relates to a specific compute or transfer step.
Event-specific data. Contents vary by event type.
```bash Agent Event theme={null}
curl -X POST https://console.rotastellar.com/api/deployments/dep-456/events \
-H "Content-Type: application/json" \
-H "X-API-Key: rs_live_..." \
-H "X-Agent-ID: sat-25544" \
-d '{
"type": "step.completed",
"timestamp": "2026-03-07T14:23:45Z",
"job_id": "preset-001",
"step_id": "feature_extraction",
"payload": {
"duration_s": 180,
"location": "onboard",
"data_output_mb": 10.5
}
}'
```
```json 201 Created theme={null}
{
"id": "evt-789"
}
```
```json 400 Validation Error theme={null}
{
"error": "type and timestamp are required"
}
```
## Status Side Effects
Terminal events automatically update the deployment status:
| Event Type | Deployment Status Change |
| --------------- | ------------------------ |
| `job.accepted` | `dispatched` → `running` |
| `job.completed` | → `completed` |
| `job.failed` | → `failed` |
# Get Deployment
Source: https://docs.rotastellar.com/api-reference/deployments/get-deployment
GET /api/deployments/{id}
Get deployment details including plan data and event count
**Base URL:** `https://console.rotastellar.com`
— Requires session cookie or API key authentication.
## Request
The deployment ID.
```bash cURL theme={null}
curl https://console.rotastellar.com/api/deployments/dep-456 \
-H "Cookie: session=..."
```
```json 200 OK theme={null}
{
"id": "dep-456",
"mission_id": "mis-123",
"plan_id": "plan-789",
"satellite_id": "25544",
"status": "completed",
"mode": "simulated",
"speed_multiplier": 100,
"started_at": "2026-03-07T12:00:05Z",
"completed_at": "2026-03-07T12:01:32Z",
"created_at": "2026-03-07T12:00:00Z",
"mission_name": "ISS ML Pipeline",
"plan_label": "On-Board ML Inference",
"plan_data": {
"id": "a92f33e8-...",
"satellite": { ... },
"preset": { ... },
"plan": {
"total_duration_s": 1382,
"windows_used": 2
},
"events": [ ... ]
},
"event_count": 24
}
```
```json 404 Not Found theme={null}
{
"error": "Deployment not found"
}
```
## Response Fields
Includes all fields from [List Deployments](/api-reference/deployments/list-deployments), plus:
| Field | Type | Description |
| ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------- |
| `plan_data` | object | Full CAE plan data (satellite, preset, orbital environment, placement decisions, transfer schedule, error budget, events) |
| `event_count` | number | Total number of execution events recorded |
## Delete / Cancel
```
DELETE /api/deployments/{id}
```
* If the deployment is `running`, it is marked as `cancelled`
* If the deployment is `pending`, it is deleted
# List Deployments
Source: https://docs.rotastellar.com/api-reference/deployments/list-deployments
GET /api/deployments
List all deployments for the authenticated user
**Base URL:** `https://console.rotastellar.com`
— Requires session cookie or API key authentication.
## Request
No parameters required. Returns the 50 most recent deployments for the authenticated user.
```bash cURL theme={null}
curl https://console.rotastellar.com/api/deployments \
-H "Cookie: session=..."
```
```bash API Key theme={null}
curl https://console.rotastellar.com/api/deployments \
-H "X-API-Key: rs_live_..."
```
```json 200 OK theme={null}
{
"deployments": [
{
"id": "dep-456",
"mission_id": "mis-123",
"plan_id": "plan-789",
"satellite_id": "25544",
"status": "completed",
"mode": "simulated",
"speed_multiplier": 100,
"started_at": "2026-03-07T12:00:05Z",
"completed_at": "2026-03-07T12:01:32Z",
"created_at": "2026-03-07T12:00:00Z",
"mission_name": "ISS ML Pipeline",
"sat_norad_id": "25544",
"plan_label": "On-Board ML Inference"
}
]
}
```
## Response Fields
| Field | Type | Description |
| ------------------ | ------ | ---------------------------------------------------------------------- |
| `id` | string | Deployment ID |
| `mission_id` | string | Parent mission ID |
| `plan_id` | string | Source plan ID |
| `satellite_id` | string | NORAD catalog ID |
| `status` | string | `pending`, `dispatched`, `running`, `completed`, `failed`, `cancelled` |
| `mode` | string | `simulated` or `live` |
| `speed_multiplier` | number | Simulation speed (simulated mode only) |
| `started_at` | string | ISO 8601 timestamp when execution started |
| `completed_at` | string | ISO 8601 timestamp when execution finished |
| `created_at` | string | ISO 8601 timestamp when deployment was created |
| `mission_name` | string | Name of the parent mission |
| `plan_label` | string | Label of the source plan |
# API Directory
Source: https://docs.rotastellar.com/api-reference/directory
Consolidated directory of all RotaStellar public APIs
# API Directory
RotaStellar exposes three categories of public APIs across multiple services. Each service is independently deployed and has its own base URL.
Internal Console APIs (session-authenticated) are documented in **Mission Control > Admin > API Directory** for authorized operators only.
***
## External APIs
Public APIs requiring a Bearer API key (`rs_...`). Available to all developers.
### Satellite Intelligence API
**Base URL:** `https://api.rotastellar.com/v1`
**Auth:** Bearer API key
**Docs:** [Full reference →](/api-reference)
| Method | Endpoint | Description |
| ------ | ------------------------------ | ---------------------------------------- |
| GET | `/satellites/active` | Active satellites with live orbital data |
| GET | `/satellites` | List satellites with filters |
| GET | `/satellites/{id}` | Satellite details |
| GET | `/satellites/{id}/position` | Current position (lat/lon/alt) |
| GET | `/satellites/{id}/orbit` | Orbital parameters |
| GET | `/satellites/{id}/visibility` | Ground station visibility |
| GET | `/satellites/{id}/passes` | Predict ground passes |
| GET | `/satellites/{id}/feasibility` | Compute feasibility analysis |
| GET | `/satellites/{id}/latency` | Communication latency analysis |
| GET | `/conjunctions` | Conjunction (collision) analysis |
| GET | `/patterns` | Anomaly and maneuver detection |
| GET | `/ground-stations` | Ground station network (12 stations) |
**Planning endpoints:**
| Method | Endpoint | Description |
| ------ | ------------------- | -------------------- |
| POST | `/planning/analyze` | Feasibility analysis |
| POST | `/planning/thermal` | Thermal simulation |
| POST | `/planning/latency` | Latency simulation |
**15 endpoints** — Intelligence + Planning
***
### Workloads API (Control Plane)
The developer API to run, track, and control workloads on the orbital fleet. One submission surface — the workload **class** (`single`, `data-parallel`, `spatial`, `federated`, `model-parallel`, `split-learning`) drives execution; the CAE places it and the durable lifecycle runs it.
**Base URL:** `https://api.rotastellar.com/v1`
**Auth:** Bearer API key
| Method | Endpoint | Description |
| ------ | ------------------------------ | --------------------------------------------------------------------------------------------------------- |
| POST | `/v1/workloads` | Submit (run) a workload of any class |
| POST | `/v1/workloads/preview` | **Plan** — the CAE verdict (feasibility + cut/partition + ISL-bound) **+ cost estimate**, without running |
| GET | `/v1/workloads` | List your workloads (newest first) |
| GET | `/v1/workloads/{id}` | Status + placement + outcome (poll `phase`) |
| GET | `/v1/workloads/{id}/stages` | Per-satellite execution — which satellite ran each stage |
| GET | `/v1/workloads/{id}/artifacts` | The result manifest (outputs + how to fetch each) |
| POST | `/v1/workloads/{id}/cancel` | Stop a queued/running workload |
**7 endpoints** — plan → run → track → retrieve → cancel. A *frontier* workload (`model-parallel` / `split-learning`) runs as a pipeline across the constellation; `distributed-training` is ISL-bound, so it's preview-only. Full guide: [Workloads →](/api-reference/workloads).
***
### Constraint-Aware Execution (CAE)
**Base URL:** `https://rotastellar-cae.subhadip-mitra.workers.dev`
**Auth:** None (CORS-restricted to allowed origins)
**Docs:** [CAE reference →](/api-reference/cae/service-index)
| Method | Endpoint | Description |
| ------ | ---------------------------- | ---------------------------------------- |
| GET | `/v1` | Service index and capabilities |
| GET | `/v1/presets` | List workload presets |
| POST | `/v1/plan` | Create execution plan (single satellite) |
| GET | `/v1/plan/{id}` | Retrieve a plan |
| GET | `/v1/plan/{id}/events` | Simulated execution events |
| POST | `/v1/ocu/negotiate` | OCU Negotiator — match workload to fleet |
| GET | `/v1/ocu/summary/{busClass}` | OCU capacity for a satellite class |
| POST | `/v1/hazards` | Predict orbital hazards + checkpoints |
| POST | `/v1/constellation/plan` | Multi-satellite DAG planning with ISL |
| POST | `/v1/constellation/pareto` | Fleet-level Pareto frontier planning |
| GET | `/v1/metrics` | Worker performance metrics |
**11 endpoints** — Orbital compute orchestration
***
### Orbital Simulation (Sim)
**Base URL:** `https://sim.rotastellar.com`
**Auth:** None (CORS-restricted)
**Docs:** [Sim reference →](/api-reference/sim/service-index)
| Method | Endpoint | Description |
| ------ | ----------------------------------------- | ----------------------------------- |
| POST | `/v1/state` | Orbital state at a timestamp |
| POST | `/v1/state/batch` | Batch state for multiple satellites |
| POST | `/v1/propagate` | Full trajectory over time window |
| POST | `/v1/passes` | Ground station pass computation |
| POST | `/v1/orbital-params` | Orbital parameters from altitude |
| GET | `/v1/templates` | Orbit templates |
| GET | `/v1/constellation-templates` | Constellation patterns |
| POST | `/v1/constellation-templates/{id}/expand` | Generate satellite definitions |
| GET | `/v1/ground-stations` | Ground station network |
**9 endpoints** — Stateless orbital computation
***
## Agent Protocol APIs
APIs used by the RotaStellar Operator Agent running on satellites (real or simulated). Authenticated via API key + Agent-ID headers.
**Base URL:** Console URL (e.g., `https://rotastellar.com`)
**Auth:** `X-API-Key` + `X-Agent-ID` headers
**Docs:** [Agent Protocol →](/agent/protocol)
| Method | Endpoint | Description |
| ------ | ------------------------------ | ------------------------------ |
| POST | `/api/agent/register` | Register agent with Console |
| GET | `/api/agent/workloads` | Poll for pending deployments |
| POST | `/api/agent/telemetry` | Report health/status heartbeat |
| POST | `/api/deployments/{id}/events` | Report execution events |
**4 endpoints** — Pull-based satellite agent protocol
***
## Summary
| Service | Endpoints | Auth Method | Base URL |
| ----------------------------- | --------- | ------------------ | ----------------------------- |
| Intelligence API | 15 | Bearer API key | `api.rotastellar.com/v1` |
| Workloads API (Control Plane) | 7 | Bearer API key | `api.rotastellar.com/v1` |
| CAE | 11 | CORS-restricted | `rotastellar-cae.workers.dev` |
| Sim | 9 | CORS-restricted | `sim.rotastellar.com` |
| Agent Protocol | 4 | API key + Agent-ID | Console URL |
| **Total** | **46** | | |
Internal Console APIs (88 routes for auth, billing, admin, missions, etc.) are documented in the Console's **Admin > API Directory** page, accessible to authenticated administrators only.
# Batch State
Source: https://docs.rotastellar.com/api-reference/sim/batch-state
POST /v1/state/batch
Compute orbital state for up to 100 satellites at once
**Base URL:** `https://sim.rotastellar.com`
— No API key required.
## Request
Array of satellite objects, each with `id` (string) and `elements` (orbital elements object). Maximum 100 satellites per request.
ISO 8601 timestamp for computation. Defaults to current time.
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/state/batch \
-H "Content-Type: application/json" \
-d '{
"satellites": [
{
"id": "rs-leo-1",
"elements": { "altitude_km": 550, "inclination_deg": 51.6, "raan_deg": 0, "mean_anomaly_deg": 0 }
},
{
"id": "rs-leo-2",
"elements": { "altitude_km": 550, "inclination_deg": 51.6, "raan_deg": 0, "mean_anomaly_deg": 180 }
}
],
"timestamp": "2026-03-08T12:00:00Z"
}'
```
```json 200 OK theme={null}
{
"states": {
"rs-leo-1": {
"lat": 42.15,
"lon": -73.82,
"altitude_km": 550.3,
"velocity_km_s": 7.59,
"in_eclipse": false,
"orbit_fraction": 0.234
},
"rs-leo-2": {
"lat": -38.90,
"lon": 106.18,
"altitude_km": 550.1,
"velocity_km_s": 7.59,
"in_eclipse": true,
"orbit_fraction": 0.734
}
},
"timestamp": "2026-03-08T12:00:00Z",
"count": 2
}
```
```json 400 Too Many theme={null}
{
"error": "too_many",
"message": "Maximum 100 satellites per batch request"
}
```
## Errors
| Status | Code | Description |
| ------ | ------------------- | ----------------------------------- |
| 400 | `invalid_request` | `satellites` array missing or empty |
| 400 | `too_many` | More than 100 satellites |
| 400 | `invalid_timestamp` | Invalid ISO 8601 timestamp |
# Create Session
Source: https://docs.rotastellar.com/api-reference/sim/create-session
POST /v1/sessions
Creates a new simulation session with the given satellite constellation
**Base URL:** `https://sim.rotastellar.com`
— No API key required.
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/sessions \
-H "Content-Type: application/json" \
-d '{
"satellites": [
{
"id": "sat-001",
"name": "RS-LEO-1",
"elements": { "altitude_km": 550, "inclination_deg": 53 }
},
{
"id": "sat-002",
"name": "RS-LEO-2",
"elements": { "altitude_km": 550, "inclination_deg": 53 }
},
{
"id": "sat-003",
"name": "RS-LEO-3",
"elements": { "altitude_km": 600, "inclination_deg": 97.4 }
}
]
}'
```
```json 200 OK theme={null}
{
"session_id": "ses_abc123",
"satellites": 3,
"created_at": "2026-03-10T12:00:00Z"
}
```
# Get Session State
Source: https://docs.rotastellar.com/api-reference/sim/get-session
GET /v1/sessions/{sessionId}
Returns the full state of a simulation session including satellite positions, subsystems, and events
**Base URL:** `https://sim.rotastellar.com`
— No API key required.
### Path Parameters
| Parameter | Type | Description |
| ----------- | ------ | ------------------------------------------- |
| `sessionId` | string | The session ID returned from Create Session |
```bash theme={null}
curl https://sim.rotastellar.com/v1/sessions/ses_abc123
```
```json 200 OK theme={null}
{
"session_id": "ses_abc123",
"epoch": "2026-03-10T12:05:00Z",
"tick_count": 5,
"satellites": [
{
"id": "sat-001",
"name": "RS-LEO-1",
"position": { "lat_deg": 32.4, "lon_deg": -118.2, "alt_km": 548.7 },
"velocity_km_s": 7.59,
"sunlit": true,
"subsystems": {
"power_w": 115,
"thermal_c": 22.4,
"comms_dbm": -82,
"memory_used_mb": 1024
},
"faults": []
},
{
"id": "sat-002",
"name": "RS-LEO-2",
"position": { "lat_deg": -14.1, "lon_deg": 45.8, "alt_km": 550.1 },
"velocity_km_s": 7.59,
"sunlit": true,
"subsystems": {
"power_w": 118,
"thermal_c": 21.8,
"comms_dbm": -79,
"memory_used_mb": 512
},
"faults": []
}
],
"isl_links": [
{ "from": "sat-001", "to": "sat-002", "distance_km": 1240, "latency_ms": 4.1, "active": true }
],
"recent_events": [
{ "epoch": "2026-03-10T12:03:00Z", "type": "eclipse_exit", "satellite": "sat-001" }
]
}
```
# Get State
Source: https://docs.rotastellar.com/api-reference/sim/get-state
POST /v1/state
Compute satellite position, velocity, and eclipse status at a timestamp
**Base URL:** `https://sim.rotastellar.com`
— No API key required.
## Request
Orbital elements defining the satellite orbit. Must include either `altitude_km` or `mean_motion`, plus `inclination_deg`. See [Orbital Elements](/sim/overview#orbital-elements) for full schema.
ISO 8601 timestamp for computation. Defaults to current time.
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/state \
-H "Content-Type: application/json" \
-d '{
"elements": {
"altitude_km": 550,
"inclination_deg": 53,
"eccentricity": 0.0001,
"raan_deg": 0,
"mean_anomaly_deg": 0,
"epoch": "2026-03-08T00:00:00Z"
},
"timestamp": "2026-03-08T12:00:00Z"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://sim.rotastellar.com/v1/state",
json={
"elements": {
"altitude_km": 550,
"inclination_deg": 53
}
}
)
state = response.json()
print(f"Position: {state['lat']:.2f}°, {state['lon']:.2f}°")
print(f"Eclipse: {state['in_eclipse']}")
```
```json 200 OK theme={null}
{
"lat": 42.15,
"lon": -73.82,
"altitude_km": 550.3,
"velocity_km_s": 7.59,
"in_eclipse": false,
"orbit_fraction": 0.234,
"timestamp": "2026-03-08T12:00:00Z"
}
```
```json 400 Invalid Elements theme={null}
{
"error": "invalid_elements",
"message": "elements must include altitude_km or mean_motion, and inclination_deg"
}
```
## Response Fields
| Field | Type | Description |
| ---------------- | ------- | -------------------------------------- |
| `lat` | number | Geodetic latitude (degrees) |
| `lon` | number | Geodetic longitude (degrees) |
| `altitude_km` | number | Height above WGS-84 ellipsoid |
| `velocity_km_s` | number | Orbital velocity |
| `in_eclipse` | boolean | Whether satellite is in Earth's shadow |
| `orbit_fraction` | number | Position in orbit (0–1) |
| `timestamp` | string | ISO 8601 computation timestamp |
# Inject Fault
Source: https://docs.rotastellar.com/api-reference/sim/inject-fault
POST /v1/sessions/{sessionId}/fault
Injects a fault into a satellite within a simulation session
**Base URL:** `https://sim.rotastellar.com`
— No API key required.
### Path Parameters
| Parameter | Type | Description |
| ----------- | ------ | ------------------------------------------- |
| `sessionId` | string | The session ID returned from Create Session |
### Fault Types
| Type | Description |
| -------------------- | ------------------------------------------------------------ |
| `power_loss` | Reduces available power generation |
| `thermal_exceedance` | Raises subsystem temperature beyond nominal range |
| `radiation_upset` | Simulates single-event upset from radiation |
| `comms_failure` | Degrades or disables communication links |
| `isl_degradation` | Reduces inter-satellite link bandwidth and increases latency |
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/sessions/ses_abc123/fault \
-H "Content-Type: application/json" \
-d '{
"satellite_id": "sat-001",
"fault_type": "power_loss",
"severity": 0.8
}'
```
```json 200 OK theme={null}
{
"session_id": "ses_abc123",
"satellite": {
"id": "sat-001",
"name": "RS-LEO-1",
"position": { "lat_deg": 33.8, "lon_deg": -114.5, "alt_km": 548.6 },
"sunlit": true,
"subsystems": {
"power_w": 23,
"thermal_c": 22.6,
"comms_dbm": -81,
"memory_used_mb": 1028
},
"faults": [
{
"type": "power_loss",
"severity": 0.8,
"injected_at": "2026-03-10T12:06:00Z",
"effect": "power_generation reduced by 80%"
}
]
}
}
```
# Ground Passes
Source: https://docs.rotastellar.com/api-reference/sim/passes
POST /v1/passes
Compute ground station AOS/LOS windows with elevation data
**Base URL:** `https://sim.rotastellar.com`
— No API key required.
## Request
Orbital elements. See [Orbital Elements](/sim/overview#orbital-elements).
ISO 8601 start time. Defaults to current time.
Prediction window in hours. Default: 24. Max: 72.
Minimum satellite elevation above horizon (degrees). Default: 5.
Custom ground station list. Defaults to the 12-station global network (KSAT, NASA, AWS). Each station needs `id`, `name`, `lat`, `lon`.
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/passes \
-H "Content-Type: application/json" \
-d '{
"elements": {
"altitude_km": 550,
"inclination_deg": 53
},
"duration_hours": 24,
"min_elevation_deg": 10
}'
```
```json 200 OK theme={null}
{
"passes": [
{
"station_id": "gs_svalbard",
"station_name": "Svalbard",
"provider": "KSAT",
"aos": "2026-03-08T12:34:56Z",
"los": "2026-03-08T12:45:23Z",
"duration_s": 627,
"max_elevation_deg": 45.6,
"points": [
{
"timestamp": "2026-03-08T12:34:56Z",
"elevation_deg": 10.0,
"azimuth_deg": 90.5,
"range_km": 2500.1
}
]
}
],
"count": 8,
"start": "2026-03-08T12:00:00Z",
"duration_hours": 24,
"stations_checked": 12
}
```
## Default Ground Stations
The service includes a 12-station global network:
| Station | Location | Provider |
| --------- | --------------- | -------- |
| Svalbard | 78.2°N, 15.4°E | KSAT |
| Troll | 72.0°S, 2.5°E | KSAT |
| Awarua | 46.5°S, 168.4°E | KSAT |
| Fairbanks | 64.9°N, 147.9°W | NASA |
| Wallops | 37.9°N, 75.5°W | NASA |
| McMurdo | 77.9°S, 166.7°E | NASA |
| Singapore | 1.4°N, 103.8°E | AWS |
| Bahrain | 26.1°N, 50.5°E | AWS |
| Oregon | 43.8°N, 120.6°W | AWS |
| Cape Town | 33.9°S, 18.4°E | AWS |
| Stockholm | 59.3°N, 18.1°E | AWS |
| Sydney | 33.9°S, 151.2°E | AWS |
# Propagate Trajectory
Source: https://docs.rotastellar.com/api-reference/sim/propagate
POST /v1/propagate
Generate full satellite trajectory as a time series over up to 48 hours
**Base URL:** `https://sim.rotastellar.com`
— No API key required.
## Request
Orbital elements. See [Orbital Elements](/sim/overview#orbital-elements).
ISO 8601 start time. Defaults to current time.
ISO 8601 end time. Default: start + 6 hours. Max window: 48 hours.
Seconds between trajectory points. Default: 60. Max 5,000 total points.
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/propagate \
-H "Content-Type: application/json" \
-d '{
"elements": {
"altitude_km": 550,
"inclination_deg": 53
},
"start": "2026-03-08T12:00:00Z",
"end": "2026-03-08T14:00:00Z",
"step_s": 60
}'
```
```json 200 OK theme={null}
{
"trajectory": [
{
"t": "2026-03-08T12:00:00Z",
"lat": 42.15,
"lon": -73.82,
"altitude_km": 550.3,
"velocity_km_s": 7.59,
"in_eclipse": false,
"orbit_fraction": 0.000
},
{
"t": "2026-03-08T12:01:00Z",
"lat": 42.58,
"lon": -72.14,
"altitude_km": 550.3,
"velocity_km_s": 7.59,
"in_eclipse": false,
"orbit_fraction": 0.010
}
],
"count": 121,
"start": "2026-03-08T12:00:00Z",
"end": "2026-03-08T14:00:00Z",
"step_s": 60
}
```
```json 400 Range Too Large theme={null}
{
"error": "range_too_large",
"message": "Propagation window exceeds 48 hours"
}
```
## Constraints
| Constraint | Limit |
| -------------- | ---------- |
| Max window | 48 hours |
| Max points | 5,000 |
| Default step | 60 seconds |
| Default window | 6 hours |
# Service Index
Source: https://docs.rotastellar.com/api-reference/sim/service-index
GET /v1
Returns service metadata and available endpoints
**Base URL:** `https://sim.rotastellar.com`
— No API key required.
```bash theme={null}
curl https://sim.rotastellar.com/v1
```
```json 200 OK theme={null}
{
"service": "rotastellar-sim",
"version": "1.0.0",
"description": "Orbital Simulation — stateless orbital computation for satellite digital twins",
"endpoints": [
{ "method": "POST", "path": "/v1/state", "description": "Compute orbital state at a timestamp" },
{ "method": "POST", "path": "/v1/state/batch", "description": "Batch orbital state for multiple satellites" },
{ "method": "POST", "path": "/v1/propagate", "description": "Propagate trajectory over a time window" },
{ "method": "POST", "path": "/v1/passes", "description": "Compute ground station passes" },
{ "method": "POST", "path": "/v1/orbital-params", "description": "Derive orbital parameters from altitude" },
{ "method": "GET", "path": "/v1/templates", "description": "List orbit templates" },
{ "method": "GET", "path": "/v1/constellation-templates", "description": "List constellation templates" },
{ "method": "GET", "path": "/v1/ground-stations", "description": "List ground station network" }
]
}
```
# Templates
Source: https://docs.rotastellar.com/api-reference/sim/templates
GET /v1/templates
Predefined orbit and constellation templates
**Base URL:** `https://sim.rotastellar.com`
— No API key required.
## Orbit Templates
`GET /v1/templates` returns predefined orbit profiles.
```bash Orbit Templates theme={null}
curl https://sim.rotastellar.com/v1/templates
```
```bash Constellation Templates theme={null}
curl https://sim.rotastellar.com/v1/constellation-templates
```
```bash Expand Constellation theme={null}
curl -X POST https://sim.rotastellar.com/v1/constellation-templates/walker-star-6-3/expand \
-H "Content-Type: application/json" \
-d '{"base_orbit": "leo-standard"}'
```
```json 200 Orbit Templates theme={null}
[
{
"id": "leo-standard",
"name": "LEO Standard",
"altitude_km": 550,
"inclination_deg": 53,
"eccentricity": 0.0001,
"description": "Standard low-Earth orbit at 550 km"
},
{
"id": "leo-low",
"name": "LEO Low",
"altitude_km": 420,
"inclination_deg": 51.6,
"eccentricity": 0.0002,
"description": "Low LEO at ISS altitude"
},
{
"id": "sun-sync-500",
"name": "Sun-Synchronous 500km",
"altitude_km": 500,
"inclination_deg": 97.4,
"eccentricity": 0.0001,
"description": "Dawn-dusk sun-synchronous orbit"
},
{
"id": "sun-sync-700",
"name": "Sun-Synchronous 700km",
"altitude_km": 700,
"inclination_deg": 98.2,
"eccentricity": 0.0001,
"description": "Higher sun-synchronous orbit"
},
{
"id": "polar-800",
"name": "Polar 800km",
"altitude_km": 800,
"inclination_deg": 98.7,
"eccentricity": 0.0001,
"description": "Near-polar orbit"
},
{
"id": "meo-navigation",
"name": "MEO Navigation",
"altitude_km": 20200,
"inclination_deg": 55,
"eccentricity": 0.001,
"description": "Medium Earth orbit (GPS/Galileo)"
},
{
"id": "geo-comms",
"name": "Geostationary",
"altitude_km": 35786,
"inclination_deg": 0,
"eccentricity": 0.0001,
"description": "Geostationary orbit"
}
]
```
```json 200 Constellation Templates theme={null}
[
{
"id": "walker-star-6-3",
"name": "Walker Star 6/3/1",
"satellite_count": 6,
"planes": 3,
"sats_per_plane": 2,
"base_orbit": "leo-standard",
"description": "6 satellites across 3 orbital planes"
},
{
"id": "walker-star-12-4",
"name": "Walker Star 12/4/1",
"satellite_count": 12,
"planes": 4,
"sats_per_plane": 3,
"base_orbit": "leo-standard",
"description": "12 satellites across 4 planes"
},
{
"id": "polar-ring-4",
"name": "Polar Ring",
"satellite_count": 4,
"planes": 2,
"sats_per_plane": 2,
"base_orbit": "sun-sync-500",
"description": "4 satellites in 2 sun-synchronous planes"
},
{
"id": "single-plane-3",
"name": "Single Plane Trio",
"satellite_count": 3,
"planes": 1,
"sats_per_plane": 3,
"base_orbit": "leo-standard",
"description": "3 satellites in a single plane"
}
]
```
## Expand Constellation
`POST /v1/constellation-templates/:id/expand` generates per-satellite orbital elements from a constellation template.
Override the template's base orbit. Must be a valid orbit template ID (e.g., `leo-standard`, `sun-sync-500`).
The response includes an `orbits` array with fully resolved orbital elements for each satellite, including computed RAAN spacing and mean anomaly offsets.
# Tick Session
Source: https://docs.rotastellar.com/api-reference/sim/tick-session
POST /v1/sessions/{sessionId}/tick
Advances the simulation by a given duration and returns the updated state
**Base URL:** `https://sim.rotastellar.com`
— No API key required.
### Path Parameters
| Parameter | Type | Description |
| ----------- | ------ | ------------------------------------------- |
| `sessionId` | string | The session ID returned from Create Session |
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/sessions/ses_abc123/tick \
-H "Content-Type: application/json" \
-d '{
"duration_s": 60
}'
```
```json 200 OK theme={null}
{
"session_id": "ses_abc123",
"epoch": "2026-03-10T12:06:00Z",
"tick_count": 6,
"duration_s": 60,
"satellites": [
{
"id": "sat-001",
"name": "RS-LEO-1",
"position": { "lat_deg": 33.8, "lon_deg": -114.5, "alt_km": 548.6 },
"velocity_km_s": 7.59,
"sunlit": true,
"subsystems": {
"power_w": 116,
"thermal_c": 22.6,
"comms_dbm": -81,
"memory_used_mb": 1028
},
"faults": []
}
],
"isl_links": [
{ "from": "sat-001", "to": "sat-002", "distance_km": 1235, "latency_ms": 4.1, "active": true }
],
"events": [
{ "epoch": "2026-03-10T12:05:30Z", "type": "isl_handover", "from": "sat-002", "to": "sat-003" }
]
}
```
# Workloads
Source: https://docs.rotastellar.com/api-reference/workloads
Run, preview, track, and control workloads on the orbital fleet — one API, class-driven.
A **workload** is a unit of compute you run on the satellite fleet. There is **one submission surface** — `POST /v1/workloads` — and the workload's **class** decides how it executes:
| `parallelism.class` | Runs as |
| ------------------- | ------------------------------------------------------------------- |
| `single` (default) | one satellite (the CAE places it) |
| `data-parallel` | sharded across satellites, recombined on the ground |
| `spatial` | each satellite processes its footprint of an area-of-interest |
| `federated` | a global model trained from on-board data (only deltas leave orbit) |
| `model-parallel` | a pipeline split across satellites — activations flow stage → stage |
| `split-learning` | a head on the data-owning satellite, the heavy tail offloaded |
**Base URL:** `https://api.rotastellar.com/v1` · **Auth:** `Authorization: Bearer rs_...`
## Lifecycle
`preview` (optional) → `submit` → poll `GET /{id}` → inspect `stages` / `artifacts` → `cancel` (any time).
## Preview — the plan
`POST /v1/workloads/preview` returns the CAE's verdict — feasibility, the model cut/partition, whether it's ISL-bound — **and a cost estimate**, *without running anything* (read-only; no quota, no billing). It's the "plan" to submit's "apply".
```bash theme={null}
curl -X POST https://api.rotastellar.com/v1/workloads/preview \
-H "Authorization: Bearer $RS_API_KEY" -H "content-type: application/json" -d '{
"placement": { "satellites": [25544, 48274, 53807] },
"parallelism": { "class": "model-parallel", "stages": 3 },
"model": { "layers": [{"name":"embed","compute_fwd":2,"activation_mb":4}] }
}'
```
```json theme={null}
{
"kind": "model_parallel",
"candidates": 3,
"plan": { "feasible": true, "stages": 3, "partition": [/* ... */], "isl_bound": false },
"cost_estimate": { "ocu": 450, "cents": 5400, "per_stage_ocu": 150, "stages": 3, "price_per_ocu_cents": 12 }
}
```
`distributed-training` is ISL-bound (gradient AllReduce over sparse inter-satellite links), so it is **preview-only** — preview it to see the honest verdict; it is not executable.
## Submit — run
`POST /v1/workloads` takes the same body and executes it. Returns the id + a `status_url`.
```json theme={null}
{ "id": "wl_9a0b…", "status": "scheduling", "status_url": "/v1/workloads/wl_9a0b…" }
```
A frontier workload (`model-parallel` / `split-learning`) runs as a pipeline across the constellation — the CAE places each stage on a satellite, and the stages run in sequence as a coordinated pipeline.
## Track status
Poll `GET /v1/workloads/{id}` and read `phase`: `submitted → scheduling → dispatching → awaiting_report → done` (or `failed` / `timed_out` / `canceled`). `workflow_status` is the coarse pill (`RUNNING` / `COMPLETED` / `FAILED` / …). The response also carries `placement`, the structured `outcome`, the `result` manifest, and `cost` once billable.
## Stages — per-satellite execution
`GET /v1/workloads/{id}/stages` — for a frontier / scatter-gather workload, which satellite ran each stage and its status.
```json theme={null}
{ "id": "wl_9a0b…", "stages": [
{ "index": 0, "satellite": "48274", "satellite_name": "CSS (TIANHE)", "status": "done", "role": "stage" },
{ "index": 1, "satellite": "25544", "satellite_name": "ISS (ZARYA)", "status": "done", "role": "stage" }
] }
```
## Results & cancel
* `GET /v1/workloads/{id}/artifacts` — the result manifest (the outputs + how to fetch each: custodied `contentId` or external `uri`).
* `POST /v1/workloads/{id}/cancel` — stop a queued or running workload; its queued / in-flight stages are dropped.
## SDKs & CLI
Every operation is in the SDKs and the CLI:
```python theme={null}
rs.workloads.preview(placement={...}, parallelism={"class": "model-parallel", "stages": 3}, model={...})
wl = rs.workloads.submit(type="fine-tune", placement={...}, parallelism={...}, model={...})
rs.workloads.get(wl["id"]); rs.workloads.stages(wl["id"]); rs.workloads.cancel(wl["id"])
```
```bash theme={null}
rotastellar jobs preview --file workload.json
rotastellar jobs submit --file workload.json
rotastellar jobs get ; rotastellar jobs stages ; rotastellar jobs cancel
```
# Authentication
Source: https://docs.rotastellar.com/authentication
Secure your API requests
# Authentication
The RotaStellar API uses API keys for authentication. All requests must include a valid API key.
## Getting an API Key
Sign up for [early access](https://rotastellar.com/developers) to receive your API credentials.
You'll receive an email with your API key (starts with `rs_`).
Store your API key securely. Never commit it to version control.
## Using Your API Key
Include your API key in the `Authorization` header with the `Bearer` prefix:
```bash theme={null}
Authorization: Bearer rs_your_api_key
```
### Example Request
```bash cURL theme={null}
curl https://api.rotastellar.com/v1/satellites/ISS \
-H "Authorization: Bearer rs_your_api_key"
```
```python Python theme={null}
from rotastellar import RotaStellarClient
# From parameter
client = RotaStellarClient(api_key="rs_your_api_key")
# Or from environment variable
# export ROTASTELLAR_API_KEY=rs_your_api_key
client = RotaStellarClient() # Reads from env
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
// From parameter
const client = new RotaStellarClient({ apiKey: 'rs_your_api_key' });
// Or from environment variable
// export ROTASTELLAR_API_KEY=rs_your_api_key
const client = new RotaStellar(); // Reads from env
```
```rust Rust theme={null}
use rotastellar::RotaStellar;
// From parameter
let client = RotaStellar::new("rs_your_api_key")?;
// Or from environment variable
// export ROTASTELLAR_API_KEY=rs_your_api_key
let client = RotaStellar::from_env()?;
```
## API Key Types
| Type | Prefix | Use Case |
| ---- | ---------- | ----------------------- |
| Live | `rs_live_` | Production applications |
| Test | `rs_test_` | Development and testing |
Test keys have rate limits and may return simulated data.
Use live keys for production applications.
## Security Best Practices
API keys should only be used in server-side code. Never include them in
JavaScript bundles, mobile apps, or anywhere users can inspect.
Store API keys in environment variables, not in code:
```bash theme={null}
export ROTASTELLAR_API_KEY=rs_live_...
```
Rotate your API keys periodically and immediately if you suspect compromise.
Use different API keys for development, staging, and production.
## Revoking Keys
If your API key is compromised:
1. Go to your [dashboard](https://rotastellar.com/dashboard/)
2. Navigate to API Keys
3. Click "Revoke" on the compromised key
4. Generate a new key
5. Update your applications
## Errors
| Code | Description |
| ----- | ------------------------------------------------- |
| `401` | Invalid or missing API key |
| `403` | API key doesn't have permission for this endpoint |
| `429` | Rate limit exceeded |
```json theme={null}
{
"error": {
"code": "invalid_api_key",
"message": "The API key provided is invalid or has been revoked."
}
}
```
# Constellation DAG
Source: https://docs.rotastellar.com/cae/constellation-dag
I-3 — multi-satellite workflow orchestration with ISL routing
# Constellation DAG
Single-satellite planning assigns steps to orbital windows on one spacecraft. Constellation DAG planning distributes a workload across multiple satellites, routing intermediate data through inter-satellite links (ISL) and ground relays to minimize end-to-end latency.
**When to use this** — Any workload that benefits from parallelism across satellites, or where a single satellite lacks the resources (compute, power, storage, contact time) to complete the job within the deadline.
## Architecture
Constellation planning is built on two core components:
### ContactGraph
The ContactGraph builds a time-expanded graph of all communication opportunities across the fleet within the planning horizon.
| Capability | Details |
| --------------------- | -------------------------------------------------------------------------------- |
| ISL detection | Line-of-sight between satellite pairs, accounting for Earth obstruction |
| Ground pass detection | Visibility windows to all 12 ground stations per satellite |
| Routing algorithm | Time-expanded Dijkstra — finds shortest-latency path through ISL and ground hops |
| Fleet construction | `buildContactGraph` generates the full fleet graph from TLE data |
The graph edges are weighted by link capacity (data rate x duration) and propagation delay. Dijkstra finds the minimum-latency path for transferring data from any satellite to any other satellite or ground station.
### ConstellationPlacer
The placer runs a 5-phase algorithm to assign steps to satellites:
| Phase | Description |
| -------------------- | --------------------------------------------------------------------------------------------------------------------- |
| 1. Preparation | Propagate orbits, build contact graph, compute per-satellite resource envelopes |
| 2. Greedy placement | Score each satellite for each step (resource fit, data locality, contact opportunity) and assign greedily by priority |
| 3. Replication | For critical steps, place redundant copies on backup satellites for fault tolerance |
| 4. Schedule assembly | Build the final timeline with ISL transfer segments between cross-satellite dependencies |
| 5. Metrics | Compute critical path, reliability estimate, and resource utilization |
**Scoring** considers four factors: available compute capacity, proximity to upstream data, upcoming contact windows, and current battery state-of-charge.
For fleets of 10 or more satellites, the placer uses a k-d tree spatial index to accelerate nearest-neighbor queries during ISL detection. This keeps planning time sub-linear with fleet size.
## ISL Transfer Segments
When two dependent steps are placed on different satellites, the planner inserts ISL transfer segments. These are scheduled during mutual visibility windows and include FEC overhead.
```json theme={null}
{
"type": "isl_transfer",
"from_satellite": "25544",
"to_satellite": "48274",
"data_mb": 36.75,
"fec_overhead_mb": 1.84,
"link_budget": {
"distance_km": 1240,
"data_rate_mbps": 10,
"duration_s": 31
},
"window": {
"start": "2026-03-10T08:12:00Z",
"end": "2026-03-10T08:18:30Z"
}
}
```
If no direct ISL path exists, the contact graph routes through intermediate satellites or ground relay (satellite A downlinks to a ground station, which uplinks to satellite B during a later pass).
## API Usage
### Create Constellation Plan
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/constellation/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_ids": ["25544", "48274", "55909"],
"custom_job": {
"name": "Distributed EO Pipeline",
"steps": [
{
"id": "capture_1",
"name": "Capture Region A",
"location": "onboard",
"compute_s": 60,
"output_mb": 2000,
"depends_on": []
},
{
"id": "capture_2",
"name": "Capture Region B",
"location": "onboard",
"compute_s": 60,
"output_mb": 2000,
"depends_on": []
},
{
"id": "merge",
"name": "Merge and Mosaic",
"location": "onboard",
"compute_s": 180,
"input_mb": 4000,
"output_mb": 500,
"depends_on": ["capture_1", "capture_2"]
},
{
"id": "downlink",
"name": "Deliver Results",
"location": "ground",
"depends_on": ["merge"]
}
],
"policy": { "objective": "min_latency", "deadline_orbits": 6 }
}
}'
```
### Request Parameters
| Parameter | Type | Required | Description |
| ------------------------ | --------- | -------- | ------------------------------------------------------------ |
| `satellite_ids` | string\[] | Yes | NORAD catalog IDs of satellites in the constellation |
| `preset_id` | string | No | Use a preset workload (mutually exclusive with `custom_job`) |
| `custom_job` | object | No | Custom DAG definition |
| `policy.objective` | string | No | `min_latency`, `balanced`, `max_reliability` |
| `policy.deadline_orbits` | number | No | Maximum orbits to complete the workflow |
| `replication_factor` | number | No | Number of redundant copies for critical steps (default: 1) |
### Response Structure
The response extends the standard plan format with constellation-specific fields:
```json theme={null}
{
"id": "const-7b2e4f...",
"constellation": {
"satellites_used": 3,
"satellites_available": 3,
"isl_transfers": 2,
"ground_relays": 0
},
"critical_path": {
"steps": ["capture_1", "isl_transfer_1", "merge", "downlink"],
"duration_s": 4320,
"bottleneck": "isl_transfer_1"
},
"metrics": {
"total_compute_s": 300,
"total_transfer_s": 186,
"isl_data_mb": 2038.5,
"ground_data_mb": 525,
"reliability": 0.964,
"satellites_used": 3
},
"placements": [
{ "step_id": "capture_1", "satellite_id": "25544", "reason": "best_resource_fit" },
{ "step_id": "capture_2", "satellite_id": "48274", "reason": "best_resource_fit" },
{ "step_id": "merge", "satellite_id": "55909", "reason": "data_locality" }
],
"plan": { ... },
"events": [ ... ]
}
```
## Metrics
| Metric | Description |
| -------------------------- | ------------------------------------------------------------ |
| `critical_path.duration_s` | Longest sequential chain through the DAG including transfers |
| `critical_path.bottleneck` | The step or transfer that dominates the critical path |
| `satellites_used` | Number of satellites with at least one assigned step |
| `isl_transfers` | Number of inter-satellite link transfers in the plan |
| `reliability` | Combined delivery confidence across all paths |
## Console Integration
The Console displays constellation plans in a **DAG tab** powered by React Flow:
* Each satellite is a swim lane
* Steps are nodes, colored by satellite assignment
* ISL transfers appear as animated edges between lanes
* The critical path is highlighted
* Clicking a node shows step detail, resource usage, and the scoring breakdown from the placement phase
Constellation planning requires valid TLE data for all satellites in the request. If any satellite ID is not found in the CelesTrak catalog, the request returns a 400 error with the missing IDs listed.
Multi-objective optimization for constellation plans
Agent constellation mode for multi-satellite execution
# Custom Workloads
Source: https://docs.rotastellar.com/cae/custom-workloads
Define your own orbital compute DAGs
# Custom Workloads
Instead of using a [preset](/cae/presets), you can define arbitrary step DAGs with `custom_job` in your plan request. The planner handles placement, transfer insertion, and scheduling the same way it does for presets.
## Request Structure
Send `custom_job` instead of `preset_id` in `POST /v1/plan`:
```json theme={null}
{
"satellite_id": "25544",
"custom_job": {
"name": "My Pipeline",
"steps": [ ... ],
"security": { ... },
"policy": { ... }
}
}
```
## Step Schema
Each step in the `steps` array:
Unique identifier within the job. Used in `depends_on` references.
Human-readable step name.
Where the step runs: `onboard`, `ground`, or `either`. When set to `either`, the planner decides based on data reduction ratio and transfer cost.
Execution duration in seconds. Must be positive.
IDs of prerequisite steps. Use `[]` for steps with no dependencies.
Resource requirements:
* `power_w` — Power consumption in watts
* `compute` — Fraction of compute capacity (0.0–1.0)
* `thermal_w` — Thermal dissipation in watts
* `memory_mb` — Memory required in MB
* `storage_mb` — Storage required in MB
Input data size in MB.
Output data size in MB.
Output/input ratio. `0.1` means 10:1 reduction. Set to `null` for data-generating steps.
Checkpoint frequency in seconds. `0` disables checkpointing.
`fail`, `retry_next_window`, or `retry_immediate`.
Maximum retry attempts.
`none`, `aes128`, or `aes256`. Adds data expansion overhead.
`none`, `crc32`, or `sha256`.
Fault tolerance. If set, provide `min_data_fraction` (0.0–1.0) and `reduced_duration_s`.
## Security Overrides
Optional `security` object at the job level:
```json theme={null}
"security": {
"encryption": "aes256",
"data_classification": "restricted",
"require_authenticated_uplink": true,
"key_rotation_orbits": 24
}
```
Defaults: AES-256 encryption, `restricted` classification, authenticated uplink, key rotation every 24 orbits.
## Policy
Optional `policy` object:
```json theme={null}
"policy": {
"objective": "balanced",
"deadline_orbits": 6,
"max_data_loss_fraction": 0.01,
"min_delivery_confidence": 0.95
}
```
| Field | Options | Default |
| ------------------------- | ---------------------------------------------------------- | ------------ |
| `objective` | `min_latency`, `min_energy`, `max_reliability`, `balanced` | `balanced` |
| `deadline_orbits` | Number of orbital periods | `6` |
| `max_data_loss_fraction` | 0.0–1.0 | `0.01` (1%) |
| `min_delivery_confidence` | 0.0–1.0 | `0.95` (95%) |
## Validation Rules
* Every step must have a unique `id`
* `depends_on` references must point to existing step IDs
* No circular dependencies (validated via DFS)
* `location` must be `onboard`, `ground`, or `either`
* `duration_s` must be positive
* `requires` must include all 5 resource fields
Invalid requests return `400` with a `validation_error` describing the issue.
## Example
A 2-step pipeline: capture sensor data on-board, then process on the ground.
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"custom_job": {
"name": "Capture and Process",
"steps": [
{
"id": "capture",
"name": "Sensor Capture",
"location": "onboard",
"duration_s": 30,
"depends_on": [],
"requires": {
"power_w": 40,
"compute": 0.3,
"thermal_w": 15,
"memory_mb": 256,
"storage_mb": 1024
},
"input_data_mb": 0,
"output_data_mb": 500
},
{
"id": "process",
"name": "Ground Processing",
"location": "ground",
"duration_s": 60,
"depends_on": ["capture"],
"requires": {
"power_w": 100,
"compute": 1.0,
"thermal_w": 50,
"memory_mb": 2048,
"storage_mb": 2048
},
"input_data_mb": 500,
"output_data_mb": 50,
"data_reduction_ratio": 0.1
}
]
}
}'
```
The planner automatically inserts transfer steps (downlink/uplink) at space-ground boundaries. Your 2-step job may produce a plan with 3+ segments.
# Hazard Prediction
Source: https://docs.rotastellar.com/cae/hazard-prediction
I-4 — eclipse-boundary preservation via predictive checkpointing
# Hazard Prediction
The HazardPredictor identifies upcoming orbital hazards — eclipse transitions, South Atlantic Anomaly (SAA) traversals, and thermal excursions — and schedules checkpoints so that in-progress computation can survive them without data loss.
**Why this matters** — An eclipse boundary can cut available power by 95% in seconds. Without predictive checkpointing, any in-flight step that spans an eclipse transition risks silent data corruption or abrupt termination.
## The 9-Phase Algorithm
The HazardPredictor runs a 9-phase pipeline over the planning horizon:
| Phase | Name | Description |
| ----- | --------------------------- | ---------------------------------------------------------------------------------------- |
| 1 | Orbit propagation | Keplerian + J2 perturbation model propagates the satellite state at 10-second intervals |
| 2 | Eclipse detection | Cylindrical shadow model identifies sunlit/eclipse transitions |
| 3 | Eclipse boundary refinement | Binary search narrows each transition to sub-second precision |
| 4 | SAA detection | Point-in-polygon test against the SAA boundary polygon for each propagation point |
| 5 | SAA window construction | Clusters SAA detections into contiguous traversal windows |
| 6 | Thermal prediction | Projects component temperatures using power dissipation and orbital thermal environment |
| 7 | Thermal excursion detection | Flags windows where predicted temperature exceeds component limits |
| 8 | Checkpoint scheduling | Places checkpoints before each hazard with sufficient margin for state serialization |
| 9 | Checkpoint merge | Consolidates checkpoints that fall within a configurable merge window to reduce overhead |
## Hazard Types
### Eclipse Boundaries
Detected using the cylindrical shadow model — the same model used in the CAE orbital environment builder. The predictor identifies both eclipse entry (sunlit-to-shadow) and eclipse exit (shadow-to-sunlit) transitions.
| Parameter | Value |
| --------------- | -------------------------------------------------- |
| Detection model | Cylindrical Earth shadow |
| Propagation | Keplerian + J2 secular perturbations |
| Time resolution | Sub-second (binary search refinement) |
| Margin | Configurable, default 30 seconds before transition |
### South Atlantic Anomaly
The SAA is a region of elevated radiation over the South Atlantic where the inner Van Allen belt dips closest to Earth. Sensitive electronics (GPUs, FPGAs) experience elevated single-event upset rates during SAA traversals.
| Parameter | Value |
| ---------------- | --------------------------------------------- |
| Detection method | Point-in-polygon against SAA boundary contour |
| Boundary model | AP-8/AE-8 derived, updated annually |
| Altitude scaling | Contour expands at lower altitudes |
| Typical duration | 10-20 minutes per traversal for LEO |
### Thermal Excursions
The thermal predictor models component temperature based on solar flux, Earth albedo, bus power dissipation, and radiator capacity. Excursions are flagged when any component is predicted to exceed its operational limit.
| Parameter | Value |
| ----------------- | ------------------------------------------ |
| Thermal model | Single-node lumped parameter per component |
| Heat sources | Solar flux, Earth IR, internal dissipation |
| Heat sinks | Radiator panels, thermal mass |
| Warning threshold | 5 degrees C below operational limit |
## Checkpoint Scheduling
For each detected hazard, the predictor inserts a checkpoint at `hazard_start - margin - serialization_time`. If two hazards are close together (within the merge window), their checkpoints are consolidated into one.
```
Timeline:
|---step running---|--ckpt--|--margin--|==ECLIPSE==|---step resumes---|
^ ^
checkpoint hazard start
```
The checkpoint includes full step state: intermediate buffers, model weights, progress counters, and RNG state. The agent serializes this to on-board storage before the hazard arrives.
## API Usage
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/hazards \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"prediction_hours": 24,
"hazard_types": ["eclipse", "saa", "thermal"],
"checkpoint_margin_s": 30,
"merge_window_s": 60
}'
```
### Request Parameters
| Parameter | Type | Required | Default | Description |
| --------------------- | --------- | -------- | ------- | ------------------------------------ |
| `satellite_id` | string | Yes | — | NORAD catalog ID |
| `prediction_hours` | number | No | 12 | Prediction horizon |
| `hazard_types` | string\[] | No | all | Filter to specific hazard types |
| `checkpoint_margin_s` | number | No | 30 | Seconds of margin before each hazard |
| `merge_window_s` | number | No | 60 | Merge checkpoints closer than this |
### Response Structure
```json theme={null}
{
"satellite_id": "25544",
"prediction_start": "2026-03-10T12:00:00Z",
"prediction_hours": 24,
"hazards": [
{
"type": "eclipse_entry",
"start": "2026-03-10T12:34:12.847Z",
"end": "2026-03-10T13:07:45.231Z",
"duration_s": 2012,
"severity": "high",
"details": {
"battery_soc_at_entry": 0.82,
"predicted_soc_at_exit": 0.41
}
},
{
"type": "saa",
"start": "2026-03-10T14:18:30.000Z",
"end": "2026-03-10T14:32:15.000Z",
"duration_s": 825,
"severity": "medium",
"details": {
"peak_flux_ratio": 3.2,
"upset_probability": 0.0012
}
},
{
"type": "thermal_excursion",
"start": "2026-03-10T16:45:00.000Z",
"end": "2026-03-10T17:02:00.000Z",
"duration_s": 1020,
"severity": "low",
"details": {
"component": "gpu",
"predicted_temp_c": 78.5,
"limit_c": 85
}
}
],
"checkpoint_schedule": [
{
"time": "2026-03-10T12:33:22.847Z",
"reason": "eclipse_entry",
"hazard_index": 0,
"serialization_budget_s": 20
},
{
"time": "2026-03-10T14:17:40.000Z",
"reason": "saa",
"hazard_index": 1,
"serialization_budget_s": 20
}
],
"max_safe_window_s": 6137,
"overhead_fraction": 0.018
}
```
### Response Fields
| Field | Type | Description |
| --------------------- | ------ | -------------------------------------------------------------- |
| `hazards` | array | All detected hazards in chronological order |
| `hazards[].severity` | string | `low`, `medium`, or `high` based on impact to computation |
| `checkpoint_schedule` | array | Recommended checkpoint times with reasons |
| `max_safe_window_s` | number | Longest uninterrupted compute window in the prediction horizon |
| `overhead_fraction` | number | Fraction of total time consumed by checkpoint serialization |
The `overhead_fraction` helps you decide whether predictive checkpointing is worth the cost. Values below 0.05 (5%) are typical for LEO orbits with 90-minute periods.
## Console Integration
The Console surfaces hazard predictions on the **Hazards tab** of the asset detail page:
* Timeline visualization shows hazards as colored bands (red for eclipse, orange for SAA, yellow for thermal)
* Checkpoint markers appear on the timeline with serialization budget indicators
* The max safe window is highlighted
* Clicking a hazard expands its detail panel with severity, duration, and predicted impact
## Agent Integration
When the agent receives a plan with predictive checkpoints, it listens for the `checkpoint.predicted` event and serializes state to on-board storage at the scheduled time. See the [Agent Protocol](/agent/protocol) documentation for event handling details.
Eclipse and window-aware step types
How to read plan responses including hazard data
# Orbital Compute Unit
Source: https://docs.rotastellar.com/cae/orbital-compute-unit
I-5 — standardized orbital compute capacity measurement
# Orbital Compute Unit
An Orbital Compute Unit (OCU) is a standardized measure of how much useful computation a satellite can deliver per orbit, accounting for power constraints, eclipse fractions, thermal limits, and ground contact availability.
**Why OCUs exist** — Satellite compute capacity is not a fixed number. It varies with orbit geometry, season, battery age, and thermal state. OCUs normalize this into a single comparable metric so you can plan workloads without modeling the physics yourself.
## Bus Profiles
OCU computation starts with a bus profile — a standardized description of the satellite's compute, power, and thermal capabilities. CAE includes 6 built-in bus classes.
| Bus Class | Typical Platform | Compute (GFLOPS) | Solar (W) | Battery (Wh) | Storage (GB) | Memory (MB) |
| ------------- | --------------------------- | ---------------- | --------- | ------------ | ------------ | ----------- |
| `1U_cubesat` | 1U CubeSat | 2 | 2.5 | 5 | 8 | 256 |
| `3U_cubesat` | 3U CubeSat | 10 | 7.5 | 20 | 32 | 512 |
| `6U_cubesat` | 6U CubeSat | 50 | 25 | 60 | 64 | 1024 |
| `12U_cubesat` | 12U CubeSat | 150 | 50 | 120 | 128 | 2048 |
| `microsat` | Microsatellite (50-100kg) | 500 | 150 | 400 | 256 | 4096 |
| `smallsat` | Small Satellite (100-500kg) | 2000 | 500 | 1500 | 512 | 8192 |
### Auto-Detection with inferBusClass
If you don't specify a bus class, CAE infers it from the satellite's NORAD ID using orbital parameters and known catalog metadata:
* **Altitude and inclination** narrow the platform category
* **Radar cross-section** (when available) estimates physical size
* **Catalog metadata** matches against known spacecraft databases
The inferred class is returned in the response so you can verify or override it.
## OCU Computation
The OCU model combines bus capabilities with orbital geometry to produce a per-orbit capacity estimate.
### Sunlit and Eclipse Hours
From the satellite's current TLE, CAE propagates the orbit and computes:
| Metric | Description |
| ------------------------- | ------------------------------------------------------------------ |
| `sunlit_hours_per_orbit` | Time in sunlight — full solar power and thermal headroom available |
| `eclipse_hours_per_orbit` | Time in Earth's shadow — battery-only, reduced thermal dissipation |
| `daily_orbits` | Number of complete orbits per 24-hour period |
| `daily_sunlit_hours` | Total sunlit time per day |
| `daily_eclipse_hours` | Total eclipse time per day |
### Confidence Model
OCU values carry a confidence score reflecting the quality of the input data:
| Factor | Impact on Confidence |
| -------------------------- | ------------------------------------------------------------------------------- |
| TLE age | Degrades as TLE epoch age increases (stale elements reduce positional accuracy) |
| Bus class source | Higher for explicit bus class, lower for inferred |
| Eclipse fraction stability | Higher when eclipse fraction is stable across the prediction horizon |
| Thermal margin | Higher when peak temperature is well below limits |
Confidence is reported as a value between 0 and 1. Values above 0.8 are considered high-confidence.
### Cost Model
Each OCU carries an estimated cost based on the bus class and orbital parameters:
| Component | Basis |
| ------------- | ------------------------------------------------------------------- |
| Compute cost | GFLOPS-hours available per orbit, weighted by bus class |
| Power cost | Watt-hours consumed, factoring solar generation and battery cycling |
| Storage cost | GB-hours of on-board storage occupied |
| Transfer cost | Data volume deliverable per orbit given contact window availability |
### Limiting Resource
The OCU computation identifies which resource constrains capacity:
```json theme={null}
"limiting_resource": {
"resource": "power",
"utilization": 0.92,
"headroom": 0.08,
"recommendation": "Reduce eclipse compute load or extend deadline to span more orbits"
}
```
Common limiting resources: `power` (eclipse battery budget), `thermal` (heat dissipation during sunlit compute), `storage` (on-board buffer for multi-pass transfers), `contact` (ground pass availability for data delivery).
## negotiateOCU Algorithm
The `negotiateOCU` function runs a 4-phase algorithm to determine achievable OCU for a specific workload:
| Phase | Description |
| ------------------------ | --------------------------------------------------------------------------------- |
| 1. Resource survey | Compute available GFLOPS-hours, watt-hours, storage, and contact time per orbit |
| 2. Workload mapping | Map workload resource requirements to per-orbit resource availability |
| 3. Constraint resolution | Identify the binding constraint and compute the maximum sustainable throughput |
| 4. OCU normalization | Express the result as a standardized OCU value with confidence and cost breakdown |
The negotiation accounts for workload-specific factors like checkpoint overhead, FEC requirements, and quality tier selection.
## API Usage
### Negotiate OCU for a Workload
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/ocu/negotiate \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"workload": {
"compute_gflops": 50,
"memory_mb": 512,
"storage_mb": 2048,
"output_mb": 100
}
}'
```
#### Response
```json theme={null}
{
"satellite_id": "25544",
"bus_class": "smallsat",
"bus_class_source": "inferred",
"ocu": {
"value": 14.2,
"unit": "OCU/orbit",
"daily": 218.7,
"confidence": 0.87
},
"orbital_geometry": {
"sunlit_hours_per_orbit": 0.96,
"eclipse_hours_per_orbit": 0.59,
"daily_orbits": 15.4
},
"limiting_resource": {
"resource": "power",
"utilization": 0.92,
"headroom": 0.08,
"recommendation": "Reduce eclipse compute load or extend deadline to span more orbits"
},
"cost": {
"compute_cost_per_orbit": 0.42,
"power_cost_per_orbit": 0.18,
"storage_cost_per_orbit": 0.05,
"total_cost_per_orbit": 0.65,
"currency": "OCU-credits"
}
}
```
### Get Bus Class Summary
Retrieve the reference profile for a bus class without specifying a satellite:
```bash theme={null}
curl https://rotastellar-cae.subhadip-mitra.workers.dev/v1/ocu/summary/6U_cubesat \
-H "Origin: https://rotastellar.com"
```
#### Response
```json theme={null}
{
"bus_class": "6U_cubesat",
"profile": {
"compute_gflops": 50,
"solar_w": 25,
"battery_wh": 60,
"storage_gb": 64,
"memory_mb": 1024
},
"reference_ocu": {
"value": 3.8,
"unit": "OCU/orbit",
"assumptions": {
"altitude_km": 550,
"inclination_deg": 97.5,
"eclipse_fraction": 0.35
}
}
}
```
### Negotiate and Summary Parameters
| Parameter | Type | Required | Description |
| ------------------------- | ------ | --------------- | ---------------------------------------------- |
| `satellite_id` | string | Yes (negotiate) | NORAD catalog ID |
| `workload` | object | No | Workload resource requirements for negotiation |
| `workload.compute_gflops` | number | No | Required compute in GFLOPS |
| `workload.memory_mb` | number | No | Required memory |
| `workload.storage_mb` | number | No | Required on-board storage |
| `workload.output_mb` | number | No | Output data to deliver to ground |
| `bus_class` | string | No | Override inferred bus class |
## Console Integration
The Console displays an **OCU Capacity** card in the sidebar of the asset detail page:
* OCU/orbit and OCU/day values with confidence indicator
* Bus class label (with "inferred" badge when auto-detected)
* Limiting resource bar chart showing utilization per resource
* Sunlit/eclipse breakdown as a ring chart
* Cost estimate per orbit
OCU values are estimates based on current orbital geometry and bus profiles. Actual capacity may vary due to battery degradation, thermal anomalies, or attitude constraints not captured in the bus model.
Predictive checkpointing around orbital hazards
Constraint-Aware Execution fundamentals
# Orbital Compute Primitives
Source: https://docs.rotastellar.com/cae/orbital-primitives
I-1 — 3 new step types for orbit-aware workload scheduling
# Orbital Compute Primitives
Standard compute steps treat satellites like ground servers. Orbital primitives don't — they decompose workloads around the physical realities of eclipse boundaries, contact windows, and ground passes.
**New in Orbital Resilience** — Eclipse, Window, and Pass steps extend the existing step schema. All existing presets and custom workloads continue to work unchanged.
## Eclipse Steps
Eclipse steps run during battery-only orbital night periods. They carry an explicit energy budget so the planner never over-commits the bus during eclipse.
| Parameter | Type | Description |
| ------------------ | ----------- | ---------------------------------------------------------------------- |
| `type` | `"eclipse"` | Marks the step as eclipse-aware |
| `energy_budget_wh` | number | Maximum energy the step may consume during eclipse |
| `eclipse_policy` | string | Power management strategy: `conservative`, `balanced`, or `aggressive` |
| `min_battery_soc` | number | Minimum battery state-of-charge to maintain (0-1) |
| `priority` | number | Scheduling priority relative to other eclipse steps |
### Eclipse Policies
| Policy | Behaviour |
| -------------- | -------------------------------------------------------------------------------------------------------- |
| `conservative` | Limits compute to 40% of eclipse battery capacity. Safe for missions where power margin is thin. |
| `balanced` | Uses up to 65% of eclipse battery. Default for most workloads. |
| `aggressive` | Uses up to 85% of eclipse battery. Use only when the next sunlit window is guaranteed to fully recharge. |
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"custom_job": {
"name": "Eclipse Compute",
"steps": [
{
"id": "night_inference",
"name": "Battery-Only Inference",
"type": "eclipse",
"location": "onboard",
"energy_budget_wh": 12.5,
"eclipse_policy": "balanced",
"min_battery_soc": 0.3,
"compute_s": 120,
"output_mb": 5
}
],
"policy": { "objective": "balanced", "deadline_orbits": 4 }
}
}'
```
***
## Window Steps
Window steps adapt their output quality based on how much time is available in the current orbital window. The planner selects a quality tier automatically — no manual tuning required.
| Parameter | Type | Description |
| ---------------- | ---------- | ------------------------------------------- |
| `type` | `"window"` | Marks the step as window-adaptive |
| `quality_tiers` | object | Map of tier names to resource requirements |
| `min_tier` | string | Lowest acceptable tier (default: `minimal`) |
| `preferred_tier` | string | Tier the planner targets if time allows |
### Quality Tiers
Each tier defines the compute time, memory, and output size the step needs at that quality level.
| Tier | Typical Use Case |
| ---------- | ------------------------------------------------------------ |
| `minimal` | Abbreviated result — good enough for monitoring or alerting |
| `standard` | Normal quality. Suitable for most operational workloads |
| `enhanced` | Higher fidelity output. Requires longer windows |
| `maximum` | Full-resolution result. Only feasible in long sunlit windows |
The planner evaluates the remaining time in the assigned orbital window and selects the highest tier that fits. If even `minimal` doesn't fit, the step is deferred to the next window.
```json theme={null}
{
"id": "process_imagery",
"name": "Adaptive Image Processing",
"type": "window",
"location": "onboard",
"quality_tiers": {
"minimal": { "compute_s": 30, "memory_mb": 256, "output_mb": 10 },
"standard": { "compute_s": 90, "memory_mb": 512, "output_mb": 50 },
"enhanced": { "compute_s": 180, "memory_mb": 1024, "output_mb": 120 },
"maximum": { "compute_s": 360, "memory_mb": 2048, "output_mb": 300 }
},
"preferred_tier": "enhanced"
}
```
The selected tier is recorded in the plan response under `placement_decisions[].quality_tier` and in the event stream as `window_step.tier_selected`.
***
## Pass Steps
Pass steps are atomic units of work that the planner decomposes around ground contact windows. A long-running task is broken into segments that align with pass start/end times, with configurable merge strategies for reassembling results.
| Parameter | Type | Description |
| --------------------- | -------- | ------------------------------------------------------------ |
| `type` | `"pass"` | Marks the step as pass-aligned |
| `merge_strategy` | string | How segments are recombined: `concat`, `reduce`, or `latest` |
| `max_segments` | number | Maximum number of pass-aligned segments (default: unlimited) |
| `min_pass_duration_s` | number | Ignore passes shorter than this |
### Merge Strategies
| Strategy | Behaviour |
| -------- | ------------------------------------------------------------------------------------- |
| `concat` | Append all segment outputs in chronological order. Use for streaming data collection. |
| `reduce` | Apply a reduction function across segments (e.g., averaging model gradients). |
| `latest` | Only the last segment's output is kept. Use for iterative refinement. |
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"custom_job": {
"name": "Multi-Pass Collection",
"steps": [
{
"id": "collect",
"name": "Pass-Aligned Data Collection",
"type": "pass",
"location": "onboard",
"merge_strategy": "concat",
"min_pass_duration_s": 120,
"compute_s": 60,
"output_mb": 200
}
],
"policy": { "objective": "max_reliability", "deadline_orbits": 6 }
}
}'
```
***
## Event Types
Orbital primitive steps emit dedicated events in the execution event stream.
| Event Type | Description |
| ----------------------------- | -------------------------------------------------- |
| `eclipse_step.scheduled` | Eclipse step assigned to an eclipse window |
| `eclipse_step.energy_check` | Energy budget validated against battery state |
| `eclipse_step.started` | Execution begins in eclipse |
| `eclipse_step.completed` | Eclipse step finished within energy budget |
| `eclipse_step.deferred` | Deferred — insufficient battery for this eclipse |
| `window_step.tier_selected` | Quality tier chosen based on available window time |
| `window_step.started` | Window-adaptive step begins at selected tier |
| `window_step.completed` | Window step finished |
| `window_step.deferred` | No window large enough for even the minimal tier |
| `pass_step.decomposed` | Step split into pass-aligned segments |
| `pass_step.segment_started` | Individual segment begins during a pass |
| `pass_step.segment_completed` | Segment finished |
| `pass_step.merged` | All segments merged using the configured strategy |
Eclipse steps with `aggressive` policy and low `min_battery_soc` can leave the satellite with insufficient power for the next sunlit boot sequence. Use conservative margins for early-stage missions.
## Combining Primitives
Orbital primitives can be mixed with standard steps and with each other in the same DAG. Use `depends_on` as usual:
```json theme={null}
{
"steps": [
{ "id": "capture", "type": "pass", "merge_strategy": "concat", "depends_on": [] },
{ "id": "process", "type": "window", "preferred_tier": "enhanced", "depends_on": ["capture"] },
{ "id": "compress", "type": "eclipse", "eclipse_policy": "balanced", "depends_on": ["process"] }
]
}
```
Built-in workloads that use orbital primitives
How agents handle orbital primitive events at runtime
# CAE Overview
Source: https://docs.rotastellar.com/cae/overview
Constraint-Aware Execution — orbital compute orchestration across the space-ground boundary
# Constraint-Aware Execution
POST a workload and a satellite ID. Get back a physically-accurate execution plan — computed from real orbital mechanics, real ground station passes, and real power/thermal constraints.
**Available now** — CAE v1.0 is live. No API key required.
## How It Works
1. **Choose a workload** — pick from 5 built-in [presets](/cae/presets) or define a [custom DAG](/cae/custom-workloads)
2. **CAE builds the orbital environment** — SGP4 propagation from real TLE data, eclipse detection, ground station pass prediction
3. **4-phase planner runs** — topological sort, compute placement (on-board vs ground), transfer insertion, window scheduling
4. **You get a complete plan** — placement decisions, transfer schedule, error budget, security summary, and a simulated execution event stream
5 ready-to-use orbital compute workloads
Define your own step DAGs with dependencies
How to read plan responses
Eclipse, window, and pass step types
Multi-objective trade-off analysis
Multi-satellite workflow orchestration
## Capabilities
| Capability | Details |
| -------------------- | -------------------------------------------------------------- |
| Orbital propagation | SGP4 from real CelesTrak TLE data |
| Eclipse detection | Cylindrical shadow model |
| Ground network | 12 stations (KSAT, NASA, AWS) |
| Compute placement | Automatic on-board vs ground optimization |
| Transfer scheduling | Multi-pass downlink/uplink with FEC overhead |
| Error correction | Reed-Solomon FEC, retransmission reserves |
| Security | AES-128/256 encryption, SHA-256/CRC32 integrity |
| Delivery confidence | Deterministic error budget calculation |
| Orbital primitives | Eclipse, window, and pass step types (I-1) |
| Pareto planning | Multi-objective frontier with 4 relaxation types (I-2) |
| Constellation DAG | Multi-satellite orchestration with ISL routing (I-3) |
| Hazard prediction | Eclipse-boundary checkpointing via SAA/thermal detection (I-4) |
| Orbital Compute Unit | Standardized capacity measurement across bus classes (I-5) |
| Monitoring | Per-endpoint latency percentiles and request metrics |
## Base URL
```
https://rotastellar-cae.subhadip-mitra.workers.dev
```
CAE does not require an API key. Access is controlled via CORS origin checking.
Requests from `rotastellar.com` and `localhost:4000` are allowed.
For cURL testing, include `-H "Origin: https://rotastellar.com"`.
## Quick Example
Create an execution plan for the ISS using the on-board ML inference preset:
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"preset_id": "onboard-ml-inference"
}'
```
The response includes the full execution plan with orbital environment, placement decisions, transfer schedule, error budget, and a simulated event stream. See [Understanding Plans](/cae/understanding-plans) for a walkthrough.
## Endpoints
| Method | Path | Description |
| ------ | --------------------------------------------------------------------- | ----------------------------- |
| `GET` | [`/v1/presets`](/api-reference/cae/list-presets) | List workload presets |
| `POST` | [`/v1/plan`](/api-reference/cae/create-plan) | Create an execution plan |
| `GET` | [`/v1/plan/:id`](/api-reference/cae/get-plan) | Retrieve a plan |
| `GET` | [`/v1/plan/:id/events`](/api-reference/cae/get-plan-events) | Get execution event stream |
| `POST` | [`/v1/constellation/plan`](/api-reference/cae/constellation-plan) | Plan a constellation DAG |
| `POST` | [`/v1/constellation/pareto`](/api-reference/cae/constellation-pareto) | Constellation Pareto frontier |
| `POST` | [`/v1/hazards`](/api-reference/cae/hazards) | Predict orbital hazards |
| `POST` | [`/v1/ocu/negotiate`](/api-reference/cae/ocu-negotiate) | Negotiate OCU capacity |
| `GET` | [`/v1/ocu/summary/:busClass`](/api-reference/cae/ocu-summary) | OCU summary by bus class |
| `GET` | [`/v1/metrics`](/api-reference/cae/metrics) | Service metrics and latency |
# Predictive Pareto Planning
Source: https://docs.rotastellar.com/cae/pareto-planning
I-2 — multi-objective optimization across the Pareto frontier
# Predictive Pareto Planning
A single execution plan optimizes for one objective. Pareto planning generates the full set of non-dominated trade-offs across four objectives simultaneously, letting you choose the plan that best fits your mission constraints.
**How it works** — CAE evaluates thousands of candidate plans with different relaxation combinations, filters dominated solutions, and returns only the Pareto-optimal frontier.
## Objectives
Every plan is scored on four axes:
| Objective | Unit | Direction | Description |
| ----------- | ----------- | --------- | ------------------------------------------------------------------ |
| Latency | seconds | minimize | Total time from job start to final output delivery |
| Energy | watt-hours | minimize | Total on-board energy consumed across all steps |
| Reliability | probability | maximize | Delivery confidence accounting for link errors and retransmissions |
| Quality | 0-1 score | maximize | Output fidelity — driven by quality tier selection in window steps |
A plan is **Pareto-optimal** (non-dominated) if no other plan is better on every objective. The frontier is the set of all non-dominated plans.
## Relaxation Types
To explore the frontier, the planner applies controlled relaxations — each trades one objective for gains in others.
| Relaxation | Trades Away | Gains |
| -------------------- | ----------- | ----------------------------------------------------------------------------------- |
| `extend_windows` | Latency | Reliability, Quality — more time allows higher tiers and more retransmission margin |
| `skip_checkpoint` | Reliability | Latency, Energy — removing checkpoints saves time and power |
| `reduce_fec` | Reliability | Latency, Energy — less FEC overhead means smaller transfers |
| `lower_quality_tier` | Quality | Latency, Energy — lower tiers complete faster with less compute |
The planner generates candidates by combining relaxations at multiple levels, then applies dominance filtering to discard any solution that is strictly worse than another.
## Dominance Filtering
Given two plans A and B, A **dominates** B if A is at least as good as B on all four objectives and strictly better on at least one. The Pareto frontier is the set of plans that no other plan dominates.
```
Plan A: latency=4200s energy=18Wh reliability=0.97 quality=0.85
Plan B: latency=5100s energy=22Wh reliability=0.95 quality=0.80
→ A dominates B (better on all four axes)
Plan C: latency=3800s energy=24Wh reliability=0.93 quality=0.90
→ A does not dominate C (C has better latency and quality)
→ Both A and C are on the frontier
```
## API Usage
### Single-Satellite Pareto
Add `pareto: true` to a standard plan request:
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_id": "25544",
"preset_id": "onboard-ml-inference",
"pareto": true
}'
```
The response includes a `frontier` array instead of a single plan:
```json theme={null}
{
"id": "pareto-a92f33e8-...",
"frontier": [
{
"plan_index": 0,
"objectives": {
"latency_s": 3240,
"energy_wh": 14.2,
"reliability": 0.991,
"quality": 0.95
},
"relaxations_applied": [],
"plan": { ... }
},
{
"plan_index": 1,
"objectives": {
"latency_s": 2880,
"energy_wh": 12.8,
"reliability": 0.967,
"quality": 0.85
},
"relaxations_applied": ["lower_quality_tier", "reduce_fec"],
"plan": { ... }
}
],
"frontier_size": 5,
"candidates_evaluated": 128,
"dominated_filtered": 123
}
```
### Fleet-Level Pareto
For constellation workloads, use the fleet Pareto endpoint:
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/constellation/pareto \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{
"satellite_ids": ["25544", "48274", "55909"],
"preset_id": "split-learning",
"pareto": true
}'
```
Fleet Pareto evaluates trade-offs across all satellites in the constellation, including ISL transfer alternatives and cross-satellite placement variations.
## Response Parameters
| Field | Type | Description |
| -------------------------------- | ------ | ------------------------------------------------ |
| `frontier` | array | Array of Pareto-optimal plan variants |
| `frontier[].plan_index` | number | Index within the frontier (0 = baseline) |
| `frontier[].objectives` | object | Objective scores for this variant |
| `frontier[].relaxations_applied` | array | Which relaxations produced this variant |
| `frontier[].plan` | object | Full plan object (same schema as standard plans) |
| `frontier_size` | number | Number of non-dominated solutions |
| `candidates_evaluated` | number | Total candidate plans generated |
| `dominated_filtered` | number | Candidates eliminated by dominance filtering |
## Console Integration
In the RotaStellar Console, the **Generate Trade-offs** button on the plan detail page triggers a Pareto analysis. Results are displayed as an interactive scatter chart where:
* Each axis maps to one of the four objectives
* Each point is a Pareto-optimal plan variant
* Clicking a point loads the full plan detail
* Hovering shows the relaxations applied and objective scores
Pareto planning takes longer than single-objective planning because the planner must evaluate and filter many candidates. For complex workloads with many steps, expect 2-5x the normal planning time.
API reference for POST /v1/plan
Fleet-level orchestration with ISL routing
# Workload Presets
Source: https://docs.rotastellar.com/cae/presets
5 ready-to-use orbital compute workloads
# Workload Presets
Presets are complete workload definitions you can use immediately with `POST /v1/plan`. Each defines a multi-step pipeline with resource requirements, dependencies, security policies, and optimization objectives.
List all presets:
```bash theme={null}
curl https://rotastellar-cae.subhadip-mitra.workers.dev/v1/presets \
-H "Origin: https://rotastellar.com"
```
## On-Board ML Inference
All computation on-board. Captures 2GB of sensor data, runs ML inference, and downlinks only the 10.5MB encrypted result — a **190:1 data reduction**.
| Property | Value |
| ------------ | ----------------------------------------------- |
| ID | `onboard-ml-inference` |
| Category | ml-inference |
| Steps | 4 (capture, preprocess, inference, encrypt) |
| All on-board | Yes |
| Data flow | 2,000 MB → 10.5 MB |
| Policy | `min_latency`, 3-orbit deadline, 99% confidence |
**Pipeline:** Sensor Capture → Data Preprocessing & Calibration → ML Model Inference → Encrypt Results
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{"satellite_id": "25544", "preset_id": "onboard-ml-inference"}'
```
***
## Split Learning Pipeline
Bidirectional training. Satellite runs the first 3 neural network layers (feature extraction, 40:1 reduction), downlinks 36.75MB of activations. Ground trains the remaining layers and uplinks 5.25MB of updated weights.
| Property | Value |
| -------- | ----------------------------------------------------------------------------------------------------------- |
| ID | `split-learning` |
| Category | ml-training |
| Steps | 9 (capture → feature extraction → compress → encrypt → train backend → compress weights → encrypt → deploy) |
| Downlink | 36.75 MB (activations) |
| Uplink | 5.25 MB (weights) |
| Policy | `balanced`, 6-orbit deadline, 95% confidence |
| Security | `confidential`, authenticated uplink, key rotation every 12 orbits |
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{"satellite_id": "25544", "preset_id": "split-learning"}'
```
***
## Earth Observation with QA
Captures 5GB of imagery, runs on-board quality assurance to discard bad frames and cloudy scenes, compresses to 400MB, applies Reed-Solomon FEC and AES-256, then downlinks 560MB across multiple ground station passes.
| Property | Value |
| ------------------- | -------------------------------------------------------------------------------------------------------- |
| ID | `earth-observation-qa` |
| Category | earth-observation |
| Steps | 8 (capture → QA → cloud filter → JPEG2000 compress → FEC encode → encrypt → ground validation → archive) |
| Data flow | 5,000 MB → 560 MB transferred |
| Multi-pass downlink | Yes |
| Policy | `max_reliability`, 8-orbit deadline, 95% confidence |
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{"satellite_id": "25544", "preset_id": "earth-observation-qa"}'
```
***
## Federated Learning
Privacy-preserving distributed training. The satellite trains locally on 500MB of data, computes and sparsifies gradients (top-k, 90% zeros), downlinks 3.7MB. Ground aggregates via FedAvg and uplinks 5.8MB updated global model. **Raw data never leaves the satellite.**
| Property | Value |
| -------- | ------------------------------------------------------------------------------------------------------------ |
| ID | `federated-learning` |
| Category | ml-training |
| Steps | 10 (local train → gradients → sparsify → compress → encrypt → aggregate → compress model → encrypt → deploy) |
| Downlink | 3.7 MB (sparse gradients) |
| Uplink | 5.8 MB (global model) |
| Policy | `balanced`, 6-orbit deadline, 95% confidence |
| Security | `confidential`, authenticated uplink, key rotation every 12 orbits |
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{"satellite_id": "25544", "preset_id": "federated-learning"}'
```
***
## Resilient Store-and-Forward Relay
Receives 100MB from a remote sensor during one pass, applies Reed-Solomon erasure coding (rate 2/3 — any 2-of-3 blocks reconstruct), buffers on-board, and transmits during a different ground pass.
| Property | Value |
| ---------------- | ---------------------------------------------------------------------------------------- |
| ID | `resilient-store-forward` |
| Category | relay |
| Steps | 5 (uplink receive → integrity check → erasure coding → encrypt & buffer → ground decode) |
| Data transferred | 157.5 MB (with erasure coding overhead) |
| Policy | `max_reliability`, 4-orbit deadline, 99% confidence |
```bash theme={null}
curl -X POST https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan \
-H "Content-Type: application/json" \
-H "Origin: https://rotastellar.com" \
-d '{"satellite_id": "25544", "preset_id": "resilient-store-forward"}'
```
***
## Comparison
| Preset | Steps | Data Reduction | Downlink | Uplink | Objective | Deadline |
| --------------------- | ----- | ----------------- | -------- | ------- | ---------------- | -------- |
| On-Board ML Inference | 4 | 190:1 | 10.5 MB | — | min\_latency | 3 orbits |
| Split Learning | 9 | 40:1 | 36.75 MB | 5.25 MB | balanced | 6 orbits |
| Earth Observation QA | 8 | 9:1 | 560 MB | — | max\_reliability | 8 orbits |
| Federated Learning | 10 | 135:1 | 3.7 MB | 5.8 MB | balanced | 6 orbits |
| Store-and-Forward | 5 | 1:1.6 (expansion) | 157.5 MB | — | max\_reliability | 4 orbits |
Need something different? Define a [custom workload](/cae/custom-workloads).
# Understanding Plans
Source: https://docs.rotastellar.com/cae/understanding-plans
How to read CAE execution plan responses
# Understanding Plans
When you create a plan via `POST /v1/plan`, the response contains a complete execution plan computed from real orbital mechanics. This page walks through each section.
## Response Structure
```json theme={null}
{
"id": "a92f33e8-...",
"created_at": "2026-03-05T06:55:37.811Z",
"version": "1.0.0",
"satellite": { ... },
"preset": { ... },
"orbital_environment": { ... },
"placement_decisions": [ ... ],
"transfer_schedule": { ... },
"error_budget": { ... },
"security_summary": { ... },
"plan": { ... },
"events": [ ... ]
}
```
## Satellite
Orbital parameters computed from real TLE data at plan creation time.
```json theme={null}
"satellite": {
"id": "25544",
"name": "ISS (ZARYA)",
"norad_id": 25544,
"altitude_km": 417,
"inclination_deg": 51.6,
"period_min": 93,
"tle_epoch": "26063.86671769"
}
```
## Orbital Environment
The physical context the planner works within: eclipse fraction, satellite bus capabilities, orbital windows (sunlit/eclipse periods with resource envelopes), and predicted ground station passes.
```json theme={null}
"orbital_environment": {
"prediction_start": "2026-03-05T06:55:37.811Z",
"prediction_hours": 12,
"eclipse_fraction": 0.348,
"bus": {
"peak_solar_w": 789,
"eclipse_battery_w": 20,
"max_thermal_w": 45,
"compute_sunlit": 1,
"compute_eclipse": 0.6,
"storage_mb": 4096,
"memory_mb": 2048
},
"windows": [ ... ],
"ground_passes": [ ... ],
"summary": {
"total_windows": 14,
"comms_windows": 6,
"sunlit_windows": 9,
"eclipse_windows": 5,
"total_pass_time_s": 2847,
"ground_stations_visible": 8
}
}
```
**Windows** are orbital time slots with available resources. The planner fits steps into windows based on power, thermal, and compute constraints. **Ground passes** are periods when the satellite is visible from a ground station — required for data transfer.
## Placement Decisions
For each step, the planner decides whether it runs on-board or on the ground. Steps with `location: "either"` are automatically placed based on data reduction ratio and transfer cost.
```json theme={null}
"placement_decisions": [
{ "step_id": "capture", "location": "onboard", "reason": "preset_defined" },
{ "step_id": "inference", "location": "onboard", "reason": "data_reduction_50x" },
{ "step_id": "validate", "location": "ground", "reason": "onboard_infeasible (thermal)" }
]
```
## Transfer Schedule
The planner auto-inserts transfer segments at space-ground boundaries. This section shows all data transfers with FEC overhead, encryption expansion, and ground station assignments.
```json theme={null}
"transfer_schedule": {
"transfers": [
{
"from_step": "encrypt",
"to_step": "ground_validation",
"direction": "downlink",
"raw_data_mb": 560,
"fec_overhead_mb": 28,
"encryption_overhead_mb": 5.6,
"total_transfer_mb": 593.6,
"passes": [
{ "station": "Svalbard", "data_mb": 350, "duration_s": 420 },
{ "station": "Fairbanks", "data_mb": 243.6, "duration_s": 310 }
]
}
],
"total_transfers": 1,
"total_downlink_mb": 593.6,
"total_uplink_mb": 0,
"passes_used": 2,
"total_transfer_time_s": 730
}
```
## Error Budget
Quantifies data integrity: worst-case bit error rate, FEC overhead, retransmission reserves, and the resulting delivery confidence.
```json theme={null}
"error_budget": {
"worst_case_ber": 0.00001,
"total_fec_overhead_mb": 28,
"total_retransmission_reserve_mb": 14,
"delivery_confidence": 0.967
}
```
The `delivery_confidence` is the probability that all data is delivered correctly within the deadline, accounting for link errors and retransmissions.
## Security Summary
Encryption overhead and key exchange details.
```json theme={null}
"security_summary": {
"encryption": "aes256",
"total_encryption_overhead_mb": 5.6,
"total_key_exchanges": 2,
"data_classification": "restricted"
}
```
## Plan Segments
The scheduled execution timeline. Each segment is a step assigned to an orbital window with a start time.
```json theme={null}
"plan": {
"segments": [
{
"step_id": "capture",
"location": "onboard",
"window_index": 0,
"start_offset_s": 0,
"duration_s": 60,
"resources": { ... }
}
],
"total_duration_s": 8940,
"total_compute_s": 253,
"total_transfer_s": 730,
"total_ground_s": 75,
"windows_used": 4,
"policy": { "objective": "max_reliability", "deadline_orbits": 8 }
}
```
The plan may contain more segments than your original step count — the planner auto-inserts transfer segments at every space-ground boundary.
## Event Stream
A simulated execution trace showing every significant moment. Retrieve via the plan response or separately via `GET /v1/plan/:id/events`.
| Event Type | Description |
| ------------------------- | ---------------------------------- |
| `job.accepted` | Workload received |
| `placement.decided` | Step location assigned |
| `plan.created` | Plan is ready |
| `step.started` | Step execution begins |
| `step.progress` | Progress at 25%, 50%, 75% |
| `checkpoint.saved` | Intermediate checkpoint |
| `step.completed` | Step finished |
| `transfer.started` | Data transfer begins |
| `transfer.pass_started` | Transfer via ground station |
| `transfer.progress` | Transfer midpoint |
| `transfer.retransmission` | Blocks retransmitted due to errors |
| `transfer.pass_completed` | Ground station pass finished |
| `transfer.completed` | All data transferred |
| `security.key_exchange` | Encryption key exchange |
| `security.encrypted` | Data encrypted |
| `job.completed` | Pipeline finished successfully |
| `job.failed` | Pipeline failed |
## Plan Storage
Plans are stored for **1 hour**. Retrieve a plan by ID:
```bash theme={null}
curl https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan/{plan_id} \
-H "Origin: https://rotastellar.com"
```
Get just the event stream:
```bash theme={null}
curl https://rotastellar-cae.subhadip-mitra.workers.dev/v1/plan/{plan_id}/events \
-H "Origin: https://rotastellar.com"
```
# Changelog
Source: https://docs.rotastellar.com/changelog
API version history and updates
# Changelog
All notable changes to the RotaStellar API.
## 2026-03-05 — CAE v1.0
### New: Constraint-Aware Execution
* **CAE API** — POST a workload + satellite ID, get a physically-accurate execution plan computed from real orbital mechanics
* **5 built-in presets:** on-board ML inference, split learning, earth observation with QA, federated learning, resilient store-and-forward
* **Custom workload DAGs** — define arbitrary step pipelines with dependencies, resource requirements, and security policies
* **4-phase planner:** topological sort, compute placement, transfer insertion, window scheduling
* **Real orbital mechanics:** SGP4 propagation, eclipse detection, 12-station ground network (KSAT, NASA, AWS)
* **Simulated execution events:** full event stream with transfer, checkpoint, and security events
***
## 2026-02-01 — SDK Updates & Documentation Improvements
### SDK Updates
* **Python SDK v0.2.0** — Fixed `Position` type to use `latitude`/`longitude` fields consistently
* **Node.js SDK v0.2.0** — Aligned field names with Python SDK (`latitude`, `longitude`, `altitudeKm`)
* **Rust SDK v0.1.1** — Types-only release with `Position`, `Orbit`, `Satellite`, `TimeRange` structs
### API Improvements
* **Trajectory API** — Now accepts ISO 8601 strings for `start` and `end` parameters
* **Patterns API** — Added `type` filter parameter for filtering by pattern type (`maneuver`, `anomaly`, `proximity`)
* **Conjunctions API** — Response now includes `miss_distance_km` and `collision_probability` fields
### Documentation
* Updated all SDK examples to use correct `RotaStellarClient` class name
* Fixed code examples across 20+ documentation pages
* Added comprehensive error handling examples
***
## 2026-01-28 — Dashboard Beta & Distributed Compute Preview
### New Features
* **Dashboard Beta** — Web-based dashboard for satellite tracking and conjunction monitoring at [app.rotastellar.com](https://app.rotastellar.com)
* Real-time satellite position visualization
* Conjunction risk timeline
* API usage metrics
* **Distributed Compute SDK Preview** — `rotastellar-distributed` package now available
* `FederatedClient` for gradient compression and federated learning
* `CompressionConfig` with TopK + quantization (100x compression)
* Python: `pip install rotastellar-distributed`
* Node.js: `npm install @rotastellar/distributed`
### API Updates
* **List Satellites** — Added `constellation` and `operator` filter parameters
* **Get Satellite** — Response now includes `orbit` object with computed properties
* **Rate Limits** — Increased Pro tier limits to 100 req/min
***
## 2026-01-24 — Intelligence API Enhancements
### New Endpoints
* `GET /v1/satellites/{id}/trajectory` — Get predicted positions over a time range
* `GET /v1/patterns` — Detect maneuvers, anomalies, and proximity operations
* `POST /v1/conjunctions/watch` — Set up webhook alerts for conjunction events
### Improvements
* **Conjunction Analysis** — Now includes avoidance maneuver recommendations
* **Pattern Detection** — Added confidence scores and detailed descriptions
* **Satellite Metadata** — Enhanced with operator, constellation, and launch date fields
***
## 2026-01-21 — Early Access Launch
Initial early access release of the RotaStellar API.
### Available
* **Planning Tools API** — Feasibility analysis, thermal modeling, latency simulation, power budgeting
* **Orbital Intelligence API** — Satellite tracking, conjunction analysis, pattern detection
* **Python SDK** — `pip install rotastellar`
* **Node.js SDK** — `npm install @rotastellar/sdk`
* **Rust SDK** — `cargo add rotastellar`
### Coming Soon
* **Orbital Runtime API** — Scheduled for Q2 2026
* **Webhook notifications** — Q1 2026
* **Bulk data export** — Q1 2026
***
## Versioning
The API uses date-based versioning in the URL path:
```
https://api.rotastellar.com/v1/...
```
Breaking changes will be released as new versions with migration guides.
## Deprecation Policy
* Deprecated features are announced 6 months before removal
* Deprecated endpoints return `X-Deprecated: true` header
* Migration guides are provided for all breaking changes
## Subscribe to Updates
Get notified about API changes and new features.
# Getting Started
Source: https://docs.rotastellar.com/console/getting-started
Sign up, create your first mission, build a plan, and deploy
# Getting Started with Mission Control
This guide walks you through your first satellite compute deployment — from sign-up to watching events roll in.
## 1. Create an Account
Go to [console.rotastellar.com](https://console.rotastellar.com) and sign up with your email. You'll receive a magic link — click it to log in. No password required.
## 2. Create a Mission
Missions group related satellite operations.
1. Click **Missions** in the sidebar
2. Click **New Mission**
3. Enter a name (e.g., "ISS ML Pipeline") and optional description
4. Click **Create**
## 3. Build a Plan
A plan is a complete execution schedule built by the [CAE engine](/cae/overview).
1. Open your mission and click **New Plan**
2. Search for a satellite by name or NORAD ID (e.g., "ISS" or "25544")
3. Choose a workload:
* **Preset** — Select from 5 built-in workloads like [On-Board ML Inference](/cae/presets#on-board-ml-inference) or [Split Learning](/cae/presets#split-learning-pipeline)
* **Custom** — Define your own step DAG with dependencies, resource requirements, and security policies
4. Click **Generate Plan**
The plan builder shows:
* **Timeline** — Step-by-step execution with orbital window scheduling
* **Placement** — Which steps run on-board vs on the ground
* **Transfers** — Ground station passes used for downlink/uplink
* **Error budget** — Delivery confidence based on link quality and FEC
* **Cost estimate** — Compute and transfer costs
## 4. Deploy
1. From the plan detail page, click **Deploy**
2. Choose a mode:
* **Simulated** — Events are generated server-side. Adjust the speed multiplier (default: 100x).
* **Live** — Requires a registered [Operator Agent](/agent/overview) on the target satellite.
3. Click **Deploy**
The deployment page shows a real-time event timeline as the execution progresses.
## 5. Create an API Key
To use the Agent SDK or call the Deploy API programmatically:
1. Go to **Developer > API Keys** in the sidebar
2. Click **Create Key**
3. Give it a name and copy the key (it won't be shown again)
Use the key in the `X-API-Key` header for API requests and agent authentication.
## Next Steps
Deep dive into mission management and plan configuration
Set up the Operator Agent for live deployments
# Missions & Plans
Source: https://docs.rotastellar.com/console/missions-and-plans
Organize satellite operations with missions and build execution plans with presets or custom workloads
# Missions & Plans
Missions and plans are the core organizing concepts in Mission Control.
## Missions
A **mission** is a workspace that groups related satellite operations. It contains plans, deployments, and an activity log.
### Creating Missions
Click **New Mission** from the missions page. Each mission has:
* **Name** — A descriptive label (e.g., "Arctic Monitoring Fleet", "ISS ML Pipeline")
* **Description** — Optional context about the mission's objectives
### Activity Feed
Every mission has an activity feed that logs:
* Plan creation and updates
* Deployment starts and completions
* Configuration changes
## Plans
A **plan** is a constraint-aware execution schedule generated by the [CAE engine](/cae/overview). It maps a workload to a specific satellite's orbital environment.
### Presets vs Custom
**Presets** are ready-to-use workload definitions:
| Preset | Steps | Use Case |
| ------------------------------------------------------------------- | ----- | ------------------------------------------------------- |
| [On-Board ML Inference](/cae/presets#on-board-ml-inference) | 4 | Run ML models entirely on-board, downlink only results |
| [Split Learning](/cae/presets#split-learning-pipeline) | 9 | Bidirectional training across space-ground boundary |
| [Earth Observation QA](/cae/presets#earth-observation-with-qa) | 8 | Capture, quality filter, compress, and downlink imagery |
| [Federated Learning](/cae/presets#federated-learning) | 10 | Privacy-preserving distributed training |
| [Store-and-Forward](/cae/presets#resilient-store-and-forward-relay) | 5 | Erasure-coded relay through orbit |
**Custom workloads** let you define your own step DAG:
```json theme={null}
{
"name": "My Pipeline",
"steps": [
{
"id": "capture",
"name": "Sensor Capture",
"location": "onboard",
"duration_s": 30,
"depends_on": [],
"requires": {
"power_w": 40,
"compute": 0.3,
"thermal_w": 15,
"memory_mb": 256,
"storage_mb": 1024
},
"output_data_mb": 500
},
{
"id": "process",
"name": "Ground Processing",
"location": "ground",
"duration_s": 60,
"depends_on": ["capture"],
"requires": {
"power_w": 100,
"compute": 1.0,
"memory_mb": 2048
},
"input_data_mb": 500,
"output_data_mb": 50
}
]
}
```
See [Custom Workloads](/cae/custom-workloads) for the full schema.
### Plan Contents
Every plan includes:
| Section | Description |
| ----------------------- | ------------------------------------------------------------ |
| **Orbital Environment** | Eclipse fraction, ground station passes, available windows |
| **Placement Decisions** | Which steps run on-board vs on the ground, with reasoning |
| **Transfer Schedule** | Ground station passes used, FEC overhead, data volumes |
| **Error Budget** | Worst-case BER, retransmission reserves, delivery confidence |
| **Security Summary** | Encryption algorithm, key exchanges, data classification |
| **Execution Timeline** | Step-by-step event stream with timestamps |
| **Cost Estimate** | Compute and transfer costs in USD |
### Plan Comparison
When you have multiple plans (different presets, satellites, or configurations), use the **Compare** feature on the mission page. Select 2-3 plans to see side-by-side metrics: duration, cost, confidence, and data volumes.
## Deployments
Deploy a plan to run it. Choose between:
* **Simulated** — Server generates events from the plan's event timeline. Configurable speed (1x to 10,000x). No agent required.
* **Live** — Creates a pending deployment that an [Operator Agent](/agent/overview) picks up during its next poll cycle.
Track deployment progress in real-time with the event timeline. Events are grouped by phase: placement, compute, transfer, security, and lifecycle.
### Status Flow
```
pending → dispatched → running → completed
→ failed
→ cancelled
```
# Mission Control
Source: https://docs.rotastellar.com/console/overview
The operations console for orbital compute — plan, deploy, and monitor satellite workloads
# Mission Control
Mission Control is the RotaStellar operations console. It provides a complete workflow for planning, deploying, and monitoring compute workloads on satellites.
Access Mission Control at [console.rotastellar.com](https://console.rotastellar.com).
## Capabilities
### Missions
Organize your satellite operations into missions. Each mission groups related plans, deployments, and activity into a single workspace.
### Plan Builder
Create execution plans using CAE presets or custom workload DAGs. The plan builder shows:
* Orbital environment (eclipse fraction, ground station passes)
* Placement decisions (on-board vs ground compute)
* Transfer schedule (downlink/uplink with FEC overhead)
* Error budget and delivery confidence
* Cost estimation
* Full execution timeline
### Deployments
Deploy plans in **simulated** or **live** mode:
* **Simulated** — Console generates events from CAE plan data with configurable speed. No agent required.
* **Live** — A satellite agent picks up the deployment and reports events in real-time.
Track deployment status: `pending` → `dispatched` → `running` → `completed`.
### Constellations
Group satellites into constellations for fleet operations. Add satellites by NORAD ID and view orbital parameters.
### Monitor
Real-time satellite tracking with an interactive 3D globe. View satellite positions, orbits, and ground station coverage.
### Developer Tools
* **API Keys** — Create and manage keys for agent authentication and API access
* **Usage** — Track API usage and billing
* **Settings** — Profile, preferences (timezone, units, globe style)
## Architecture
Mission Control is built on:
* **Next.js** — React-based web application
* **CAE API** — Constraint-Aware Execution engine for orbital compute planning
* **RotaStellar API** — Satellite tracking, feasibility analysis, orbital intelligence
* **Operator Agent** — Pull-based protocol for satellite-side execution
```mermaid theme={null}
graph TD
subgraph Mission Control
A[Missions] --> DB[(Postgres)]
B[Plans] --> CAE[CAE API]
C[Deploy] --> Agent[Agent Protocol]
D[Monitor] --> Tracking[Tracking API]
end
```
# Federated Learning
Source: https://docs.rotastellar.com/distributed/federated-learning
Train models across Earth and orbital nodes with gradient compression
# Federated Learning
**Coming Q1 2026** — This feature is in development.
[Request early access](https://rotastellar.com/developers) to be notified when available.
## Overview
Train machine learning models across distributed Earth and orbital infrastructure. Each node trains locally on its data, then synchronizes compressed gradients during ground station passes.
## Key Components
Local training client for Earth or orbital nodes
Central coordinator for gradient synchronization
Gradient compression settings (TopK + quantization)
Lossless compression via error accumulation
## Gradient Compression
Bandwidth between orbital and ground nodes is extremely limited. Raw gradient synchronization is infeasible for large models. Our compression pipeline achieves 100x reduction with minimal accuracy loss:
### Compression Pipeline
Raw gradient tensor from backpropagation, e.g., `∇ = [0.12, -0.08, 0.003, ...]`
Keep only top 1% of gradients by magnitude. Reduces size by 100x while preserving the most important updates.
Convert Float32 to Int8 with scale factor. Further 4x reduction with minimal precision loss.
Accumulate dropped gradients for the next round. Guarantees eventual convergence despite aggressive compression.
### Configuration
```python Python theme={null}
from rotastellar_distributed import CompressionConfig
# Standard compression (100x reduction)
compression = CompressionConfig(
method="topk_quantized",
k_ratio=0.01, # Keep top 1%
quantization_bits=8, # 8-bit quantization
error_feedback=True # Accumulate errors
)
# Aggressive compression (200x reduction)
aggressive = CompressionConfig(
method="topk_quantized",
k_ratio=0.005, # Keep top 0.5%
quantization_bits=4, # 4-bit quantization
error_feedback=True
)
# Light compression (10x reduction)
light = CompressionConfig(
method="topk",
k_ratio=0.1, # Keep top 10%
error_feedback=True
)
```
```typescript Node.js theme={null}
import { CompressionConfig } from '@rotastellar/distributed';
const compression = new CompressionConfig({
method: 'topk_quantized',
kRatio: 0.01,
quantizationBits: 8,
errorFeedback: true
});
```
```rust Rust theme={null}
use rotastellar_distributed::{CompressionConfig, CompressionMethod};
let compression = CompressionConfig::new()
.method(CompressionMethod::TopKQuantized)
.k_ratio(0.01)
.quantization_bits(8)
.error_feedback(true);
```
## Federated Client
The `FederatedClient` runs on each participating node (Earth or orbital):
```python Python theme={null}
from rotastellar_distributed import FederatedClient, CompressionConfig, CompressionMethod
# Initialize client
client = FederatedClient(
node_id="orbital-3",
node_type="orbital", # "orbital" or "ground"
compression=CompressionConfig(
method=CompressionMethod.TOP_K_QUANTIZED,
k_ratio=0.01,
quantization_bits=8,
error_feedback=True
)
)
# Training loop
for epoch in range(num_epochs):
for batch in dataloader:
# Compute local gradients
gradients = client.compute_gradients(model_params, batch)
# Compress gradients for transmission
compressed = client.compress(gradients)
# Send to aggregator (implementation-specific)
send_to_aggregator(compressed)
# Apply received global update
client.apply_update(global_update)
# Get compression statistics
stats = client.get_stats()
print(f"Compression ratio: {stats['compression_ratio']}x")
```
```typescript Node.js theme={null}
import { FederatedClient, CompressionConfig, CompressionMethod } from '@rotastellar/distributed';
const compression: CompressionConfig = {
method: CompressionMethod.TOP_K_QUANTIZED,
kRatio: 0.01,
quantizationBits: 8,
errorFeedback: true
};
const client = new FederatedClient({
nodeId: 'orbital-3',
nodeType: 'orbital',
compression
});
// Training loop
for (const batch of dataloader) {
const gradients = client.computeGradients(modelParams, batch);
const compressed = client.compress(gradients);
sendToAggregator(compressed);
}
// Apply received update
client.applyUpdate(globalUpdate);
```
```rust Rust theme={null}
use rotastellar_distributed::{FederatedClient, CompressionConfig, Priority};
let client = FederatedClient::new("orbital-3", compression);
for batch in dataloader {
let gradients = client.train_step(&model, &batch);
let compressed = client.compress(&gradients);
client.queue_sync(compressed, Priority::Normal);
}
client.sync_now().await?;
let global_weights = client.get_global_model().await?;
```
## Gradient Aggregator
The `GradientAggregator` runs on a ground station or cloud, coordinating updates from all nodes:
```python Python theme={null}
from rotastellar_distributed import GradientAggregator
# Initialize aggregator
aggregator = GradientAggregator(
api_key="rs_...",
strategy="async_fedavg", # Async Federated Averaging
min_nodes=3, # Wait for at least 3 nodes
staleness_limit=5 # Accept updates up to 5 rounds old
)
# Register callback for incoming gradients
@aggregator.on_gradient_received
def handle_gradient(node_id, gradients, metadata):
print(f"Received from {node_id}: {metadata['compression_ratio']}x compressed")
# Start aggregation loop
aggregator.start()
# Periodically get global model update
while training:
if aggregator.has_new_update():
global_update = aggregator.get_update()
broadcast_to_nodes(global_update)
```
```typescript Node.js theme={null}
import { GradientAggregator } from '@rotastellar/distributed';
const aggregator = new GradientAggregator({
apiKey: 'rs_...',
strategy: 'async_fedavg',
minNodes: 3,
stalenessLimit: 5
});
aggregator.onGradientReceived((nodeId, gradients, metadata) => {
console.log(`Received from ${nodeId}`);
});
aggregator.start();
// Get updates
const globalUpdate = await aggregator.getUpdate();
```
## Aggregation Strategies
| Strategy | Description | Best For |
| ----------------- | ------------------------------------- | ------------------------- |
| `sync_fedavg` | Wait for all nodes before aggregating | Reliable connectivity |
| `async_fedavg` | Aggregate as updates arrive | Intermittent connectivity |
| `weighted_fedavg` | Weight by dataset size | Heterogeneous data |
| `momentum_fedavg` | Add momentum to updates | Faster convergence |
## Handling Connectivity
Orbital nodes experience intermittent connectivity. The client handles this automatically:
```python theme={null}
# The FederatedClient handles:
# 1. Gradient compression for bandwidth-limited links
# 2. Error feedback for lossless compression over time
# 3. Statistics tracking for monitoring
from rotastellar_distributed import FederatedClient, CompressionConfig, CompressionMethod
client = FederatedClient(
node_id="orbital-3",
node_type="orbital",
compression=CompressionConfig(
method=CompressionMethod.TOP_K_QUANTIZED,
k_ratio=0.01,
quantization_bits=8,
error_feedback=True # Accumulate dropped gradients
)
)
```
## Convergence Guarantees
Despite compression and async updates, training converges to the same solution as centralized training:
| Property | Guarantee |
| ---------------- | ----------------------------------------------- |
| Compression loss | Under 0.5% final accuracy vs uncompressed |
| Staleness impact | Under 1% accuracy loss with staleness\_limit=10 |
| Error feedback | Mathematically lossless over time |
| Convergence rate | 1.2-1.5x more rounds than centralized |
## Example: Training LLaMA-70B
```python theme={null}
from rotastellar_distributed import FederatedClient, CompressionConfig, CompressionMethod
# Configure compression for LLaMA-70B gradients
compression = CompressionConfig(
method=CompressionMethod.TOP_K_QUANTIZED,
k_ratio=0.01, # Keep top 1%
quantization_bits=8, # 8-bit quantization
error_feedback=True # Lossless over time
)
# Initialize orbital node client
client = FederatedClient(
node_id="orbital-3",
node_type="orbital",
compression=compression
)
# Training loop with gradient compression
gradients = client.compute_gradients(model_params, local_batch)
compressed = client.compress(gradients)
# Check compression stats
stats = client.get_stats()
print(f"Compression ratio: {stats['compression_ratio']}x")
print(f"Total compressed: {stats['total_compressed']}")
# Training metrics for 8-node setup:
# - 100x gradient compression
# - ~40% energy savings vs all-terrestrial
# - +18% training time vs centralized
```
## Next Steps
Split models across nodes for inference
Optimize ground station pass utilization
# Model Partitioning
Source: https://docs.rotastellar.com/distributed/model-partitioning
Optimal layer placement across Earth and space infrastructure
# Model Partitioning
**Coming Q1 2026** — This feature is in development.
[Request early access](https://rotastellar.com/developers) to be notified when available.
## Overview
Large neural networks can be split across Earth and orbital nodes to optimize for latency, bandwidth, or energy efficiency. The Model Partitioning system finds optimal cut points based on your infrastructure topology.
## Key Components
Finds optimal model split points
Analyzes model layer characteristics
Specifies ground vs orbital assignment
Predicts end-to-end inference latency
## Why Partition Models?
| Scenario | Benefit |
| ------------------------------------ | --------------------------------------------------- |
| Large models, limited orbital memory | Run embedding layers on ground, attention in orbit |
| Latency-sensitive inference | Place early layers close to data source |
| Energy optimization | Compute-heavy layers on solar-powered orbital nodes |
| Bandwidth constraints | Minimize activation transfer between nodes |
## How It Works
Input tokens are received at a ground node where the **Embedding Layer** (150M params) and **Layers 0-10** (2.8B params) process the initial representation.
Compressed activations (12 MB) are transmitted to the orbital node via ground-to-space link.
**Layers 11-60** (35B params) run on the orbital node - the most compute-intensive portion of the model, powered by solar energy.
Output activations (12 MB) are transmitted back to a ground node.
**Layers 61-80** (14B params) and the **Output Head** generate the final output tokens.
The partition optimizer automatically finds cut points that minimize total latency while respecting memory constraints on each node type.
## Model Profile
First, analyze your model to understand layer characteristics:
```python Python theme={null}
from rotastellar_distributed import ModelProfile
# From PyTorch model
profile = ModelProfile.from_pytorch(model)
# From TensorFlow/Keras
profile = ModelProfile.from_tensorflow(model)
# From ONNX file
profile = ModelProfile.from_onnx("model.onnx")
# Inspect profile
print(f"Total parameters: {profile.total_params:,}")
print(f"Total layers: {profile.num_layers}")
print(f"Memory footprint: {profile.memory_mb:.1f} MB")
# Per-layer analysis
for layer in profile.layers:
print(f"{layer.name}: {layer.params:,} params, "
f"{layer.flops:,} FLOPs, "
f"{layer.activation_size_mb:.1f} MB activations")
```
```typescript Node.js theme={null}
import { ModelProfile } from '@rotastellar/distributed';
const profile = ModelProfile.fromOnnx('model.onnx');
console.log(`Total parameters: ${profile.totalParams}`);
console.log(`Total layers: ${profile.numLayers}`);
for (const layer of profile.layers) {
console.log(`${layer.name}: ${layer.params} params`);
}
```
```rust Rust theme={null}
use rotastellar_distributed::ModelProfile;
let profile = ModelProfile::from_onnx("model.onnx")?;
println!("Total parameters: {}", profile.total_params());
println!("Total layers: {}", profile.num_layers());
for layer in profile.layers() {
println!("{}: {} params", layer.name, layer.params);
}
```
## Partition Optimizer
Find optimal cut points based on your topology:
```python Python theme={null}
from rotastellar_distributed import PartitionOptimizer, ModelProfile
# Define your infrastructure
topology = {
"ground_nodes": 2,
"orbital_nodes": 4,
"ground_flops": 100e12, # 100 TFLOPS per ground node
"orbital_flops": 20e12, # 20 TFLOPS per orbital node
"uplink_bandwidth": 100e6, # 100 Mbps ground→orbit
"downlink_bandwidth": 500e6, # 500 Mbps orbit→ground
"isl_bandwidth": 10e9, # 10 Gbps inter-satellite
"ground_orbit_latency_ms": 25 # LEO latency
}
# Profile your model
profile = ModelProfile.from_pytorch(model)
# Find optimal partition
optimizer = PartitionOptimizer(api_key="rs_...")
partition = optimizer.optimize(
model=profile,
topology=topology,
objective="minimize_latency" # or "minimize_bandwidth", "balance"
)
# View results
print(f"Optimal cut points: {partition.cut_points}")
print(f"Ground layers: {partition.ground_layers}")
print(f"Orbital layers: {partition.orbital_layers}")
print(f"Estimated latency: {partition.estimated_latency_ms:.1f} ms")
print(f"Activation transfer: {partition.transfer_size_mb:.1f} MB")
```
```typescript Node.js theme={null}
import { PartitionOptimizer, ModelProfile } from '@rotastellar/distributed';
const profile = ModelProfile.fromOnnx('model.onnx');
const optimizer = new PartitionOptimizer({ apiKey: 'rs_...' });
const partition = await optimizer.optimize({
model: profile,
topology: {
groundNodes: 2,
orbitalNodes: 4,
groundFlops: 100e12,
orbitalFlops: 20e12,
uplinkBandwidth: 100e6,
downlinkBandwidth: 500e6
},
objective: 'minimize_latency'
});
console.log(`Cut points: ${partition.cutPoints}`);
console.log(`Estimated latency: ${partition.estimatedLatencyMs} ms`);
```
```rust Rust theme={null}
use rotastellar_distributed::{PartitionOptimizer, ModelProfile, Topology, Objective};
let profile = ModelProfile::from_onnx("model.onnx")?;
let topology = Topology::new()
.ground_nodes(2)
.orbital_nodes(4)
.ground_flops(100e12)
.orbital_flops(20e12);
let optimizer = PartitionOptimizer::new();
let partition = optimizer.optimize(&profile, &topology, Objective::MinimizeLatency)?;
println!("Cut points: {:?}", partition.cut_points());
println!("Estimated latency: {} ms", partition.estimated_latency_ms());
```
## Optimization Objectives
| Objective | Optimizes For | Best When |
| -------------------- | --------------------------- | ------------------------- |
| `minimize_latency` | End-to-end inference time | Real-time applications |
| `minimize_bandwidth` | Data transfer between nodes | Limited connectivity |
| `minimize_energy` | Total energy consumption | Battery/solar constraints |
| `balance` | Weighted combination | General purpose |
## Layer Placement
Manually specify or adjust layer placement:
```python theme={null}
from rotastellar_distributed import LayerPlacement
# Manual placement
placement = LayerPlacement()
placement.assign_ground(layers=[0, 1, 2, 3, 4]) # First 5 layers
placement.assign_orbital(layers=range(5, 75)) # Middle layers
placement.assign_ground(layers=[75, 76, 77, 78, 79]) # Last 5 layers
# Validate placement
validation = placement.validate(profile, topology)
if not validation.is_valid:
print(f"Issues: {validation.issues}")
# Or refine optimizer result
partition = optimizer.optimize(model=profile, topology=topology)
partition.move_layer(15, to="ground") # Manual adjustment
partition.recalculate()
```
## Latency Estimation
Predict inference latency for a given partition:
```python theme={null}
from rotastellar_distributed import LatencyEstimator
estimator = LatencyEstimator(topology=topology)
# Estimate for a partition
estimate = estimator.estimate(partition)
print(f"Total latency: {estimate.total_ms:.1f} ms")
print(f" Ground compute: {estimate.ground_compute_ms:.1f} ms")
print(f" Orbital compute: {estimate.orbital_compute_ms:.1f} ms")
print(f" Uplink transfer: {estimate.uplink_ms:.1f} ms")
print(f" Downlink transfer: {estimate.downlink_ms:.1f} ms")
print(f" Propagation: {estimate.propagation_ms:.1f} ms")
# Breakdown by layer
for layer_est in estimate.by_layer:
print(f" {layer_est.name}: {layer_est.total_ms:.1f} ms on {layer_est.node}")
```
## Example: LLaMA-70B Partitioning
```python theme={null}
from rotastellar_distributed import PartitionOptimizer, ModelProfile
# LLaMA-70B architecture
profile = ModelProfile.from_pytorch(llama_70b)
# 80 transformer layers, ~70B parameters
topology = {
"ground_nodes": 3,
"orbital_nodes": 5,
"ground_flops": 200e12, # A100 equivalent
"orbital_flops": 50e12, # Space-qualified GPU
"uplink_bandwidth": 200e6,
"downlink_bandwidth": 1e9,
"isl_bandwidth": 25e9
}
partition = optimizer.optimize(
model=profile,
topology=topology,
objective="minimize_latency"
)
# Result for LLaMA-70B:
# - Layers 0-8: Ground (embeddings + early attention)
# - Layers 9-72: Orbital (bulk computation)
# - Layers 73-79 + head: Ground (final layers)
# - Activation transfer: 24 MB per inference
# - Estimated latency: 180 ms (vs 400 ms all-ground)
```
## Next Steps
Schedule data transfer during ground passes
Route between orbital nodes via ISL
# Distributed Compute Overview
Source: https://docs.rotastellar.com/distributed/overview
Coordinate AI workloads across Earth and orbital infrastructure
# Distributed Compute
**Coming Q1 2026** — Distributed Compute is currently in development.
This documentation is a design preview. [Request early access](https://rotastellar.com/developers)
to be notified when it's available.
## Overview
Distributed Compute enables AI training and inference across hybrid Earth-space infrastructure. Coordinate federated learning, partition models optimally, and synchronize through bandwidth-constrained orbital links.
Train models across Earth and orbital nodes with gradient compression
Optimal layer placement across Earth and space infrastructure
Ground station pass planning and priority-based queuing
ISL routing for orbital node communication
## Why Earth-Space Distributed Compute?
Large AI models don't fit on any single node. Training and inference must span infrastructure. But space introduces unique constraints:
| Challenge | Solution |
| ------------------------------------------- | ---------------------------------------------------- |
| Bandwidth is scarce (limited ground passes) | 100x gradient compression with TopK + quantization |
| Latency varies wildly (5ms to 500ms+) | Async aggregation and intelligent model partitioning |
| Connectivity is intermittent | Priority-based sync scheduling across passes |
| Topology is dynamic | ISL mesh routing adapts to orbital geometry |
## Architecture
Your training job connects to RotaStellar Distributed Compute, which coordinates workloads across ground and orbital infrastructure:
The core coordination layer includes **Federated Learning** (gradient compression and aggregation), **Model Partitioning** (optimal layer placement), and **Sync Scheduler** (ground pass planning).
Inter-Satellite Link (ISL) routing enables orbital nodes to communicate with each other and relay data to ground stations.
**Ground Nodes** provide high-bandwidth terrestrial compute. **LEO Nodes** run solar-powered orbital compute, connected via ISL and synchronized during ground passes.
## Key Capabilities
### Gradient Compression
Reduce bandwidth by 100x with minimal accuracy loss:
```python theme={null}
from rotastellar_distributed import CompressionConfig
compression = CompressionConfig(
method="topk_quantized",
k_ratio=0.01, # Keep top 1% of gradients
quantization_bits=8, # 8-bit quantization
error_feedback=True # Accumulate compression error
)
# 4.2 MB gradient → 42 KB compressed
# Under 0.5% accuracy loss
```
### Async Aggregation
Handle intermittent connectivity with async federated averaging:
* Nodes train independently during eclipse/no-contact periods
* Gradients sync during ground station passes
* Central aggregator handles out-of-order updates
* Convergence guaranteed despite variable latency
### Intelligent Partitioning
Split models optimally across Earth and orbital nodes:
* Minimize data transfer at cut points
* Account for per-node compute capacity
* Adapt to changing orbital geometry
* Balance latency vs throughput
## Quick Start
```python Python theme={null}
from rotastellar_distributed import FederatedClient, CompressionConfig
# Configure compression
compression = CompressionConfig(
method="topk_quantized",
k_ratio=0.01,
quantization_bits=8
)
# Initialize federated client
client = FederatedClient(
api_key="rs_...",
node_id="orbital-3",
node_type="orbital",
compression=compression
)
# Train locally
gradients = client.train_step(model, batch)
# Sync during ground pass
client.sync(gradients, priority="high")
```
```typescript Node.js theme={null}
import { FederatedClient, CompressionConfig } from '@rotastellar/distributed';
const compression = new CompressionConfig({
method: 'topk_quantized',
kRatio: 0.01,
quantizationBits: 8
});
const client = new FederatedClient({
apiKey: 'rs_...',
nodeId: 'orbital-3',
nodeType: 'orbital',
compression
});
const gradients = client.trainStep(model, batch);
client.sync(gradients, { priority: 'high' });
```
```rust Rust theme={null}
use rotastellar_distributed::{FederatedClient, CompressionConfig, CompressionMethod};
let compression = CompressionConfig::new()
.method(CompressionMethod::TopKQuantized)
.k_ratio(0.01)
.quantization_bits(8);
let client = FederatedClient::new("orbital-3", compression);
let gradients = client.train_step(&model, &batch);
client.sync(gradients, Priority::High);
```
## Performance
| Metric | Value |
| -------------------- | --------------------------- |
| Gradient compression | 100x (4.2 MB → 42 KB) |
| Accuracy loss | Under 0.5% vs uncompressed |
| Sync efficiency | +45% bandwidth utilization |
| Training overhead | +15-20% time vs centralized |
| Energy savings | 35-45% vs terrestrial-only |
## Timeline
| Milestone | Target |
| ------------------------- | ------- |
| Design preview (this doc) | Now |
| SDK with simulators | Q1 2026 |
| Beta with partners | Q2 2026 |
| General availability | Q3 2026 |
## Get Notified
Be the first to know when Distributed Compute is available.
# Space Mesh
Source: https://docs.rotastellar.com/distributed/space-mesh
ISL routing for orbital node communication
# Space Mesh
**Coming Q1 2026** — This feature is in development.
[Request early access](https://rotastellar.com/developers) to be notified when available.
## Overview
Space Mesh enables communication between orbital nodes via Inter-Satellite Links (ISL). When direct ground contact isn't available, data can be routed through neighboring satellites to reach a ground station.
## Key Components
ISL network topology manager
Path between source and destination
Orbital node with ISL capability
ISL connection between nodes
## Why ISL Routing?
Without ISL, each orbital node must wait for its own ground pass. With ISL, data can relay through neighboring satellites:
Each satellite waits independently for ground contact. Long gaps between sync opportunities.
| Satellite | Sync Pattern |
| --------- | ------------------------------------- |
| Sat-1 | Sync - Wait 90min - Sync - Wait 90min |
| Sat-2 | Wait 30min - Sync - Wait 90min - Sync |
| Sat-3 | Wait 60min - Sync - Wait 90min - Sync |
Any satellite can relay through neighbors to reach ground. Continuous sync capability.
**Example route:** Sat-1 → Sat-2 → Sat-3 → Ground Station
All nodes can sync continuously via mesh routing.
## Mesh Topology
### Constellation Layout
The mesh connects orbital nodes via high-bandwidth Inter-Satellite Links (ISL):
**Sat-1, Sat-2, Sat-3, Sat-4** in LEO orbit, connected via 10 Gbps optical ISL links
Ground stations receive data from any satellite with line-of-sight
| Link Type | Bandwidth | Latency |
| ------------------------------ | ------------ | ------- |
| ISL (satellite to satellite) | 10 Gbps | 3-15 ms |
| Downlink (satellite to ground) | 1 Gbps | 5-25 ms |
| Uplink (ground to satellite) | 100-500 Mbps | 5-25 ms |
## Basic Usage
```python Python theme={null}
from rotastellar_distributed import SpaceMesh
# Initialize mesh
mesh = SpaceMesh(api_key="rs_...")
# Add orbital nodes
mesh.add_node("sat-1", orbit_alt=550, isl_range=5000)
mesh.add_node("sat-2", orbit_alt=550, isl_range=5000)
mesh.add_node("sat-3", orbit_alt=550, isl_range=5000)
mesh.add_node("sat-4", orbit_alt=550, isl_range=5000)
# Add ground stations
mesh.add_ground_station("svalbard", lat=78.2, lon=15.6)
mesh.add_ground_station("singapore", lat=1.3, lon=103.8)
# Find route
route = mesh.find_route(
source="sat-1",
destination="ground-svalbard",
data_size=100e6, # 100 MB
max_hops=3
)
print(f"Path: {' → '.join(route.path)}")
print(f"Hops: {route.num_hops}")
print(f"Total latency: {route.latency_ms:.1f} ms")
print(f"Bottleneck: {route.bottleneck_link}")
print(f"Available bandwidth: {route.bandwidth / 1e6:.0f} Mbps")
```
```typescript Node.js theme={null}
import { SpaceMesh } from '@rotastellar/distributed';
const mesh = new SpaceMesh({ apiKey: 'rs_...' });
mesh.addNode('sat-1', { orbitAlt: 550, islRange: 5000 });
mesh.addNode('sat-2', { orbitAlt: 550, islRange: 5000 });
mesh.addNode('sat-3', { orbitAlt: 550, islRange: 5000 });
mesh.addGroundStation('svalbard', { lat: 78.2, lon: 15.6 });
const route = await mesh.findRoute({
source: 'sat-1',
destination: 'ground-svalbard',
dataSize: 100e6,
maxHops: 3
});
console.log(`Path: ${route.path.join(' → ')}`);
console.log(`Latency: ${route.latencyMs} ms`);
```
```rust Rust theme={null}
use rotastellar_distributed::SpaceMesh;
let mut mesh = SpaceMesh::new();
mesh.add_node("sat-1", 550.0, 5000.0);
mesh.add_node("sat-2", 550.0, 5000.0);
mesh.add_node("sat-3", 550.0, 5000.0);
mesh.add_ground_station("svalbard", 78.2, 15.6);
let route = mesh.find_route("sat-1", "ground-svalbard", 100e6, 3)?;
println!("Path: {:?}", route.path());
println!("Latency: {} ms", route.latency_ms());
```
## Link Configuration
Configure ISL characteristics:
```python theme={null}
# Add node with detailed ISL config
mesh.add_node(
"sat-1",
orbit_alt=550, # km
orbit_inc=53, # degrees inclination
isl_config={
"range_km": 5000, # Max ISL range
"bandwidth": 10e9, # 10 Gbps
"latency_per_km": 0.003, # ms per km
"max_connections": 4, # Max simultaneous links
"optical": True # Optical vs RF
}
)
# View current links
links = mesh.get_links("sat-1")
for link in links:
print(f"{link.source} ↔ {link.target}")
print(f" Distance: {link.distance_km:.0f} km")
print(f" Bandwidth: {link.bandwidth / 1e9:.0f} Gbps")
print(f" Latency: {link.latency_ms:.1f} ms")
print(f" Status: {link.status}")
```
## Routing Algorithms
| Algorithm | Description | Best For |
| --------------- | ----------------------- | ---------------- |
| `shortest_path` | Minimum hops | Low latency |
| `max_bandwidth` | Highest capacity path | Large transfers |
| `min_latency` | Lowest total delay | Real-time |
| `load_balanced` | Distribute across paths | High utilization |
```python theme={null}
# Shortest path (default)
route = mesh.find_route(source, dest, algorithm="shortest_path")
# Maximum bandwidth
route = mesh.find_route(source, dest, algorithm="max_bandwidth")
# Minimum latency
route = mesh.find_route(source, dest, algorithm="min_latency")
# Load balanced
route = mesh.find_route(source, dest, algorithm="load_balanced")
```
## Dynamic Topology
The mesh adapts as satellites move:
```python theme={null}
# Update positions (typically from TLE)
mesh.update_positions(epoch=datetime.now())
# Or subscribe to position updates
@mesh.on_topology_change
def handle_change(event):
if event.type == "link_lost":
print(f"Link lost: {event.source} ↔ {event.target}")
# Routes using this link are automatically rerouted
elif event.type == "link_established":
print(f"New link: {event.source} ↔ {event.target}")
# Get current network state
state = mesh.get_state()
print(f"Active nodes: {state.active_nodes}")
print(f"Active links: {state.active_links}")
print(f"Network diameter: {state.diameter} hops")
print(f"Avg path length: {state.avg_path_length:.1f} hops")
```
## Multi-Path Routing
For reliability, use multiple paths:
```python theme={null}
# Find multiple disjoint paths
paths = mesh.find_paths(
source="sat-1",
destination="ground-svalbard",
num_paths=3,
disjoint=True # No shared links
)
for i, path in enumerate(paths):
print(f"Path {i+1}: {' → '.join(path.nodes)}")
print(f" Bandwidth: {path.bandwidth / 1e6:.0f} Mbps")
# Split data across paths
transfers = mesh.split_transfer(
data_size=1e9, # 1 GB
paths=paths,
strategy="proportional" # By bandwidth
)
```
## Traffic Shaping
Manage bandwidth allocation:
```python theme={null}
# Reserve bandwidth for critical traffic
reservation = mesh.reserve_bandwidth(
source="sat-1",
destination="ground-svalbard",
bandwidth=100e6, # 100 Mbps
duration_seconds=300,
priority="critical"
)
# Monitor traffic
traffic = mesh.get_traffic()
for link in traffic.links:
print(f"{link.id}: {link.utilization:.1%} utilized")
print(f" Current: {link.current_throughput / 1e6:.0f} Mbps")
print(f" Peak: {link.peak_throughput / 1e6:.0f} Mbps")
```
## Example: Global Coverage
```python theme={null}
from rotastellar_distributed import SpaceMesh
# Create mesh for a Walker constellation
mesh = SpaceMesh(api_key="rs_...")
# Add 40 satellites in polar orbit
for plane in range(8):
for sat in range(5):
mesh.add_node(
f"sat-{plane}-{sat}",
orbit_alt=550,
orbit_inc=97.5,
raan=plane * 45, # Right ascension
true_anomaly=sat * 72, # Position in plane
isl_range=5000
)
# Add global ground stations
stations = [
("svalbard", 78.2, 15.6),
("hawaii", 19.8, -155.5),
("singapore", 1.3, 103.8),
("chile", -33.4, -70.6),
("south-africa", -33.9, 18.4),
]
for name, lat, lon in stations:
mesh.add_ground_station(name, lat, lon)
# Network stats
state = mesh.get_state()
print(f"Satellites: {state.active_nodes}")
print(f"ISL links: {state.active_links}")
print(f"Ground stations: {state.ground_stations}")
print(f"Global coverage: {state.coverage:.1%}")
# Any satellite can reach ground within 2 hops
for sat in mesh.nodes:
routes = mesh.find_paths(sat, "any-ground", max_hops=2)
assert len(routes) > 0, f"{sat} has no route to ground!"
```
## Integration with Sync Scheduler
Space Mesh integrates with the Sync Scheduler for optimal routing:
```python theme={null}
from rotastellar_distributed import SyncScheduler, SpaceMesh
# Initialize both
mesh = SpaceMesh(api_key="rs_...")
scheduler = SyncScheduler(
api_key="rs_...",
mesh=mesh # Enable ISL routing
)
# Schedule sync - will use ISL if direct pass unavailable
sync = scheduler.schedule_sync(
node="sat-1",
data_size=100e6,
priority="critical",
allow_relay=True # Allow ISL relay
)
# Sync might go: sat-1 → sat-2 → ground-svalbard
print(f"Route: {' → '.join(sync.route.path)}")
```
## Next Steps
Schedule syncs with mesh routing
Train models across the mesh
# Sync Scheduler
Source: https://docs.rotastellar.com/distributed/sync-scheduler
Ground station pass planning and priority-based queuing
# Sync Scheduler
**Coming Q1 2026** — This feature is in development.
[Request early access](https://rotastellar.com/developers) to be notified when available.
## Overview
Orbital nodes can only sync with ground during ground station passes. The Sync Scheduler optimizes data transfer across these limited windows, ensuring critical updates are prioritized and bandwidth is fully utilized.
## Key Components
Main scheduler for pass planning
Ground station configuration
Bandwidth-aware priority queuing
Pass window with bandwidth estimate
## The Synchronization Challenge
Ground station passes are intermittent - each satellite only has line-of-sight to a ground station for a portion of each orbit.
| Ground Station | Location | Typical Pass Pattern |
| -------------- | -------- | ------------------------------- |
| Svalbard | 78°N | 8-10 passes/day, 10-15 min each |
| Singapore | 1°N | 4-6 passes/day, 8-12 min each |
**Combined coverage** from multiple ground stations reduces gaps but doesn't eliminate them. The Sync Scheduler optimizes data transfer across these limited windows.
## Ground Station Configuration
```python Python theme={null}
from rotastellar_distributed import SyncScheduler, GroundStation
# Define your ground stations
stations = [
GroundStation(
name="svalbard",
lat=78.2,
lon=15.6,
bandwidth=1e9, # 1 Gbps
elevation_min=10 # Minimum elevation angle
),
GroundStation(
name="singapore",
lat=1.3,
lon=103.8,
bandwidth=500e6 # 500 Mbps
),
GroundStation(
name="santiago",
lat=-33.4,
lon=-70.6,
bandwidth=500e6
)
]
# Initialize scheduler
scheduler = SyncScheduler(
api_key="rs_...",
ground_stations=stations,
orbital_nodes=["orbital-1", "orbital-2", "orbital-3"]
)
```
```typescript Node.js theme={null}
import { SyncScheduler, GroundStation } from '@rotastellar/distributed';
const stations = [
new GroundStation('svalbard', { lat: 78.2, lon: 15.6, bandwidth: 1e9 }),
new GroundStation('singapore', { lat: 1.3, lon: 103.8, bandwidth: 500e6 }),
new GroundStation('santiago', { lat: -33.4, lon: -70.6, bandwidth: 500e6 })
];
const scheduler = new SyncScheduler({
apiKey: 'rs_...',
groundStations: stations,
orbitalNodes: ['orbital-1', 'orbital-2', 'orbital-3']
});
```
```rust Rust theme={null}
use rotastellar_distributed::{SyncScheduler, GroundStation};
let stations = vec![
GroundStation::new("svalbard", 78.2, 15.6).bandwidth(1e9),
GroundStation::new("singapore", 1.3, 103.8).bandwidth(500e6),
GroundStation::new("santiago", -33.4, -70.6).bandwidth(500e6),
];
let scheduler = SyncScheduler::new()
.ground_stations(stations)
.orbital_nodes(vec!["orbital-1", "orbital-2", "orbital-3"]);
```
## Getting Sync Windows
Query upcoming sync opportunities:
```python Python theme={null}
from datetime import datetime, timedelta
# Get next 24 hours of sync windows
windows = scheduler.get_windows(hours=24)
for window in windows:
print(f"Node: {window.orbital_node}")
print(f"Station: {window.ground_station}")
print(f"Start: {window.start}")
print(f"Duration: {window.duration_seconds}s")
print(f"Max elevation: {window.max_elevation}°")
print(f"Bandwidth: {window.bandwidth / 1e6:.0f} Mbps")
print(f"Capacity: {window.capacity_mb:.0f} MB")
print()
# Filter for specific node
orbital_1_windows = scheduler.get_windows(
hours=24,
node="orbital-1"
)
# Filter for specific station
svalbard_windows = scheduler.get_windows(
hours=24,
station="svalbard"
)
```
```typescript Node.js theme={null}
const windows = await scheduler.getWindows({ hours: 24 });
for (const window of windows) {
console.log(`${window.orbitalNode} → ${window.groundStation}`);
console.log(`Start: ${window.start}, Duration: ${window.durationSeconds}s`);
console.log(`Capacity: ${window.capacityMb} MB`);
}
```
```rust Rust theme={null}
let windows = scheduler.get_windows(24).await?;
for window in windows {
println!("{} → {}", window.orbital_node, window.ground_station);
println!("Capacity: {} MB", window.capacity_mb);
}
```
## Scheduling Sync Operations
Schedule data transfers with priority:
```python Python theme={null}
from datetime import datetime, timedelta
# Schedule a sync operation
sync = scheduler.schedule_sync(
node="orbital-1",
data_size=50e6, # 50 MB
priority="critical", # "critical", "high", "normal", "low"
deadline=datetime.now() + timedelta(hours=2),
data_type="gradients"
)
print(f"Sync ID: {sync.id}")
print(f"Scheduled window: {sync.window.start}")
print(f"Estimated completion: {sync.estimated_completion}")
# Schedule multiple operations
syncs = scheduler.schedule_batch([
{"node": "orbital-1", "data_size": 50e6, "priority": "critical"},
{"node": "orbital-2", "data_size": 30e6, "priority": "high"},
{"node": "orbital-3", "data_size": 100e6, "priority": "normal"},
])
```
```typescript Node.js theme={null}
const sync = await scheduler.scheduleSync({
node: 'orbital-1',
dataSize: 50e6,
priority: 'critical',
deadline: new Date(Date.now() + 2 * 60 * 60 * 1000)
});
console.log(`Scheduled for: ${sync.window.start}`);
```
## Priority Queue
The scheduler maintains a priority queue for each orbital node:
```python theme={null}
# View queue for a node
queue = scheduler.get_queue("orbital-1")
for item in queue.items:
print(f"ID: {item.id}")
print(f"Priority: {item.priority}")
print(f"Size: {item.data_size / 1e6:.1f} MB")
print(f"Deadline: {item.deadline}")
print(f"Status: {item.status}")
print()
# Queue statistics
print(f"Total queued: {queue.total_size / 1e6:.1f} MB")
print(f"Critical items: {queue.critical_count}")
print(f"Estimated clear time: {queue.estimated_clear_time}")
```
### Priority Levels
| Priority | Description | Preemption |
| ---------- | --------------------------------------- | --------------------- |
| `critical` | Safety-critical or time-sensitive | Preempts all others |
| `high` | Important updates (e.g., model weights) | Preempts normal/low |
| `normal` | Standard sync (e.g., gradients) | No preemption |
| `low` | Background sync (e.g., telemetry) | Fills unused capacity |
## Optimization
Optimize sync schedule across all nodes and stations:
```python theme={null}
# Generate optimized schedule
plan = scheduler.optimize(
horizon_hours=24,
objectives={
"minimize_latency": 0.5, # Weight for latency
"maximize_throughput": 0.3, # Weight for throughput
"balance_load": 0.2 # Weight for load balancing
}
)
print(f"Scheduled {len(plan.operations)} sync operations")
print(f"Total data: {plan.total_data_mb:.0f} MB")
print(f"Bandwidth utilization: {plan.utilization:.1%}")
print(f"Average wait time: {plan.avg_wait_minutes:.1f} min")
# View schedule
for op in plan.operations:
print(f"{op.time}: {op.node} → {op.station} ({op.data_mb:.0f} MB)")
# Apply the optimized schedule
scheduler.apply(plan)
```
## Monitoring
Track sync operations in real-time:
```python theme={null}
# Get current sync status
status = scheduler.get_status()
print(f"Active syncs: {status.active_count}")
print(f"Queued: {status.queued_count}")
print(f"Completed (24h): {status.completed_24h}")
print(f"Failed (24h): {status.failed_24h}")
# Monitor specific operation
sync_status = scheduler.get_sync_status(sync_id)
print(f"Progress: {sync_status.progress:.1%}")
print(f"Bytes transferred: {sync_status.bytes_transferred}")
print(f"Current rate: {sync_status.rate_mbps:.1f} Mbps")
# Set up callbacks
@scheduler.on_sync_complete
def handle_complete(sync):
print(f"Sync {sync.id} completed: {sync.data_size / 1e6:.1f} MB")
@scheduler.on_sync_failed
def handle_failed(sync, error):
print(f"Sync {sync.id} failed: {error}")
# Auto-reschedule critical syncs
if sync.priority == "critical":
scheduler.reschedule(sync.id)
```
## Example: 24-Hour Sync Plan
```python theme={null}
from rotastellar_distributed import SyncScheduler, GroundStation
# Setup
scheduler = SyncScheduler(
api_key="rs_...",
ground_stations=[
GroundStation("svalbard", lat=78.2, lon=15.6, bandwidth=1e9),
GroundStation("singapore", lat=1.3, lon=103.8, bandwidth=500e6),
GroundStation("chile", lat=-33.4, lon=-70.6, bandwidth=500e6),
],
orbital_nodes=["sat-1", "sat-2", "sat-3", "sat-4", "sat-5"]
)
# Queue gradient syncs for all nodes
for i in range(1, 6):
scheduler.schedule_sync(
node=f"sat-{i}",
data_size=100e6, # 100 MB gradients per node
priority="high",
data_type="gradients"
)
# Optimize
plan = scheduler.optimize(horizon_hours=24)
# Results:
# - 5 nodes × 100 MB = 500 MB total
# - 12 ground passes utilized
# - Average wait time: 45 minutes
# - Bandwidth utilization: 78%
# - All syncs complete within 6 hours
```
## Next Steps
Route between orbital nodes via ISL
Train models with sync scheduler
# Conjunction Analysis
Source: https://docs.rotastellar.com/intelligence/conjunctions
Collision probability and avoidance recommendations
# Conjunction Analysis
Analyze potential collisions between space objects and receive recommendations for avoidance maneuvers.
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
## Overview
Conjunction analysis evaluates:
* **Time of Closest Approach (TCA)** — When objects will be nearest
* **Miss Distance** — Predicted separation at TCA
* **Collision Probability** — Statistical likelihood of collision
* **Avoidance Options** — Maneuver recommendations if needed
## Quick Start
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
# Get conjunctions for a satellite
conjunctions = client.list_conjunctions(
satellite_id="STARLINK-1234",
threshold_km=5.0,
limit=10
)
for conj in conjunctions:
print(f"TCA: {conj['tca']}")
print(f"Miss distance: {conj['miss_distance_km']} km")
print(f"Probability: {conj['collision_probability']:.2e}")
print()
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const conjunctions = await client.listConjunctions({
satelliteId: 'STARLINK-1234',
thresholdKm: 5.0,
limit: 10
});
for (const conj of conjunctions) {
console.log(`TCA: ${conj.tca}`);
console.log(`Miss: ${conj.miss_distance_km} km`);
console.log(`Probability: ${conj.collision_probability}`);
}
```
```rust Rust theme={null}
// Rust SDK provides types only (HTTP client coming soon)
// Use Python or Node.js SDK for full API access
// See /sdks/rust for available types
```
```bash cURL theme={null}
curl "https://api.rotastellar.com/v1/conjunctions?satellite=STARLINK-1234&threshold_km=5&days_ahead=7" \
-H "Authorization: Bearer rs_your_api_key"
```
## Get Conjunctions
```
GET /v1/conjunctions
```
Primary satellite (NORAD ID or name)
Maximum miss distance to report (km)
Prediction window (1-14 days)
Minimum collision probability to report (e.g., 1e-6)
### Response
```json theme={null}
{
"conjunctions": [
{
"id": "conj_abc123",
"tca": "2026-01-23T14:32:15Z",
"primary": {
"id": "12345",
"name": "STARLINK-1234",
"operator": "SpaceX"
},
"secondary": {
"id": "45678",
"name": "COSMOS 2251 DEB",
"type": "DEBRIS"
},
"miss_km": 0.45,
"probability": 2.3e-5,
"risk_level": "HIGH",
"relative_velocity_km_s": 14.2,
"geometry": {
"radial_km": 0.12,
"in_track_km": 0.38,
"cross_track_km": 0.18
},
"covariance_available": true,
"data_quality": "GOOD"
}
],
"screening_window": {
"start": "2026-01-21T00:00:00Z",
"end": "2026-01-28T00:00:00Z"
},
"total_count": 12
}
```
## Risk Levels
| Level | Probability Range | Recommended Action |
| ---------- | ----------------- | ------------------------- |
| `LOW` | \< 1e-5 | Monitor |
| `MEDIUM` | 1e-5 to 1e-4 | Review, consider maneuver |
| `HIGH` | 1e-4 to 1e-3 | Plan maneuver |
| `CRITICAL` | > 1e-3 | Execute maneuver |
## Conjunction Details
Get detailed information about a specific conjunction:
```
GET /v1/conjunctions/{conjunction_id}
```
```python Python theme={null}
# Get conjunction details via REST API
import requests
response = requests.get(
"https://api.rotastellar.com/v1/conjunctions/conj_abc123",
headers={"Authorization": "Bearer rs_your_api_key"}
)
conj = response.json()
print(f"TCA: {conj['tca']}")
print(f"Miss: {conj['miss_km']} km")
print(f"Radial: {conj['geometry']['radial_km']} km")
print(f"In-track: {conj['geometry']['in_track_km']} km")
print(f"Cross-track: {conj['geometry']['cross_track_km']} km")
# Check avoidance options
if conj['risk_level'] in ["HIGH", "CRITICAL"]:
for opt in conj.get('avoidance_options', []):
print(f"Maneuver: {opt['delta_v_m_s']} m/s at {opt['burn_time']}")
print(f"New miss distance: {opt['resulting_miss_km']} km")
```
```bash cURL theme={null}
curl https://api.rotastellar.com/v1/conjunctions/conj_abc123 \
-H "Authorization: Bearer rs_your_api_key"
```
### Detailed Response
```json theme={null}
{
"id": "conj_abc123",
"tca": "2026-01-23T14:32:15Z",
"miss_km": 0.45,
"probability": 2.3e-5,
"risk_level": "HIGH",
"primary": {
"id": "12345",
"name": "STARLINK-1234",
"position_at_tca": {
"lat": 45.2,
"lon": -122.5,
"altitude_km": 550
}
},
"secondary": {
"id": "45678",
"name": "COSMOS 2251 DEB",
"position_at_tca": {
"lat": 45.3,
"lon": -122.4,
"altitude_km": 550.3
}
},
"geometry": {
"radial_km": 0.12,
"in_track_km": 0.38,
"cross_track_km": 0.18
},
"covariance": {
"primary_sigma_r_km": 0.05,
"primary_sigma_t_km": 0.15,
"primary_sigma_n_km": 0.02,
"secondary_sigma_r_km": 0.50,
"secondary_sigma_t_km": 1.50,
"secondary_sigma_n_km": 0.30
},
"avoidance_options": [
{
"type": "in_track",
"delta_v_m_s": 0.5,
"burn_time": "2026-01-23T10:00:00Z",
"resulting_miss_km": 5.2,
"fuel_cost_kg": 0.02
},
{
"type": "radial",
"delta_v_m_s": 0.3,
"burn_time": "2026-01-23T08:00:00Z",
"resulting_miss_km": 3.8,
"fuel_cost_kg": 0.012
}
],
"updates": [
{
"timestamp": "2026-01-21T12:00:00Z",
"miss_km": 0.52,
"probability": 1.8e-5
},
{
"timestamp": "2026-01-22T00:00:00Z",
"miss_km": 0.45,
"probability": 2.3e-5
}
]
}
```
## Monitoring Conjunctions
Set up continuous monitoring for your satellites:
```python Python theme={null}
# Create a watch for conjunction alerts via REST API
import requests
response = requests.post(
"https://api.rotastellar.com/v1/conjunctions/watch",
headers={
"Authorization": "Bearer rs_your_api_key",
"Content-Type": "application/json"
},
json={
"satellites": ["SAT-001", "SAT-002", "SAT-003"],
"threshold_km": 5.0,
"min_probability": 1e-6,
"webhook_url": "https://your-app.com/conjunction-alerts"
}
)
watch = response.json()
print(f"Watch ID: {watch['id']}")
print(f"Status: {watch['status']}")
```
```bash cURL theme={null}
curl -X POST https://api.rotastellar.com/v1/conjunctions/watch \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"satellites": ["SAT-001", "SAT-002", "SAT-003"],
"threshold_km": 5.0,
"min_probability": 1e-6,
"webhook_url": "https://your-app.com/conjunction-alerts"
}'
```
## Fleet Screening
Screen multiple satellites at once:
```python theme={null}
# Screen entire constellation
satellites = ["SAT-001", "SAT-002", "SAT-003", "SAT-004"]
results = {}
for sat_id in satellites:
conjunctions = client.list_conjunctions(
satellite_id=sat_id,
threshold_km=5.0,
limit=50
)
results[sat_id] = conjunctions
for sat_id, conjunctions in results.items():
print(f"\n{sat_id}: {len(conjunctions)} conjunctions")
for conj in conjunctions:
print(f" - Miss: {conj['miss_distance_km']}km")
```
## Next Steps
Detect anomalies and maneuvers
Set up real-time alerts
# Orbital Intelligence Overview
Source: https://docs.rotastellar.com/intelligence/overview
Track, analyze, and understand objects in Earth orbit
# Orbital Intelligence
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
Orbital Intelligence provides real-time situational awareness for objects in Earth orbit. Track satellites, analyze conjunction risks, and detect anomalous behavior.
## Capabilities
Real-time positions for 10,000+ active satellites
Collision probability and avoidance recommendations
Detect anomalies and maneuvers in satellite behavior
Real-time alerts for events of interest
## Quick Start
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
# Track the International Space Station
iss = client.get_satellite("25544") # ISS NORAD ID
print(f"Location: {iss.position.latitude}, {iss.position.longitude}")
print(f"Altitude: {iss.position.altitude_km} km")
# Check for upcoming conjunctions
conjunctions = client.list_conjunctions(
satellite_id="25544",
threshold_km=5.0,
limit=10
)
for conj in conjunctions:
print(f"TCA: {conj['tca']}")
print(f"Miss distance: {conj['miss_distance_km']} km")
print(f"Probability: {conj['collision_probability']}")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
// Track ISS
const iss = await client.getSatellite('25544');
console.log(`Location: ${iss.position?.latitude}, ${iss.position?.longitude}`);
console.log(`Altitude: ${iss.position?.altitudeKm} km`);
// Check conjunctions
const conjunctions = await client.listConjunctions({
satelliteId: '25544',
thresholdKm: 5.0,
limit: 10
});
for (const conj of conjunctions) {
console.log(`TCA: ${conj.tca}, Miss: ${conj.miss_distance_km} km`);
}
```
```bash cURL theme={null}
# Get ISS position
curl https://api.rotastellar.com/v1/satellites/ISS \
-H "Authorization: Bearer rs_your_api_key"
# Check conjunctions
curl "https://api.rotastellar.com/v1/conjunctions?satellite=ISS&threshold_km=5&days_ahead=7" \
-H "Authorization: Bearer rs_your_api_key"
```
## Data Sources
| Source | Coverage | Update Frequency |
| ----------- | ----------------- | ---------------- |
| Space-Track | Global catalog | Every 8 hours |
| Commercial | Active satellites | Real-time |
| Proprietary | Enhanced accuracy | Continuous |
## Catalog Coverage
* **10,000+** active satellites
* **35,000+** debris objects tracked
* **45,000+** total tracked objects
* **Global** coverage from multiple sensor networks
## Use Cases
### Fleet Management
Track your entire satellite constellation and monitor health:
```python theme={null}
# Get all satellites in your constellation
constellation = client.list_satellites(
operator="YourCompany",
constellation="YourConstellation"
)
for sat in constellation:
print(f"{sat.name}: {sat.position.altitude_km}km")
```
### Collision Avoidance
Get alerts when conjunction risks exceed thresholds:
```python theme={null}
# Set up conjunction monitoring via webhook
# See /intelligence/webhooks for full setup
import requests
requests.post(
"https://api.rotastellar.com/v1/conjunctions/watch",
headers={"Authorization": "Bearer rs_your_api_key"},
json={
"satellites": ["SAT-001", "SAT-002", "SAT-003"],
"threshold_km": 1.0,
"webhook_url": "https://your-app.com/alerts"
}
)
```
### Anomaly Detection
Detect unexpected maneuvers or behavior changes:
```python theme={null}
anomalies = client.list_patterns(
satellite_id="TARGET-SAT",
type="anomaly",
lookback_days=30
)
for anomaly in anomalies:
print(f"{anomaly['timestamp']}: {anomaly['type']}")
print(f"Description: {anomaly['description']}")
```
## Rate Limits
| Endpoint | Free | Pro | Enterprise |
| --------------- | ------ | ------- | ---------- |
| Get Satellite | 10/min | 100/min | Custom |
| List Satellites | 5/min | 50/min | Custom |
| Conjunctions | 5/min | 50/min | Custom |
| Patterns | 2/min | 20/min | Custom |
## Next Steps
Deep dive into satellite tracking API
Learn about collision risk assessment
# Pattern Detection
Source: https://docs.rotastellar.com/intelligence/patterns
Detect anomalies and maneuvers in satellite behavior
# Pattern Detection
Detect unusual behavior, maneuvers, and anomalies in satellite operations using AI-powered pattern analysis.
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
## Overview
Pattern detection identifies:
* **Maneuvers** — Orbit-raising, lowering, plane changes
* **Anomalies** — Unexpected behavior deviations
* **Operational changes** — Mode changes, activation/deactivation
* **Proximity operations** — Rendezvous and docking
## Quick Start
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
# Get detected patterns for a satellite
patterns = client.list_patterns(
satellite_id="44832", # COSMOS-2542
lookback_days=30
)
for pattern in patterns:
print(f"Type: {pattern['type']}")
print(f"Time: {pattern['timestamp']}")
print(f"Confidence: {pattern['confidence']}")
print(f"Description: {pattern['description']}")
print()
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const patterns = await client.listPatterns({
satelliteId: '44832', // COSMOS-2542
lookbackDays: 30
});
for (const pattern of patterns) {
console.log(`${pattern.type}: ${pattern.description}`);
console.log(`Confidence: ${pattern.confidence}`);
}
```
```bash cURL theme={null}
curl "https://api.rotastellar.com/v1/patterns?satellite=COSMOS-2542&lookback_days=30" \
-H "Authorization: Bearer rs_your_api_key"
```
## Get Patterns
```
GET /v1/patterns
```
Satellite ID or name
Analysis window (1-365 days)
Filter by pattern type: `maneuver`, `anomaly`, `proximity`, `operational`
Minimum confidence threshold (0-1)
### Response
```json theme={null}
{
"satellite": {
"id": "44832",
"name": "COSMOS-2542"
},
"patterns": [
{
"id": "pat_xyz789",
"type": "maneuver",
"subtype": "orbit_raise",
"timestamp": "2026-01-15T08:23:00Z",
"confidence": 0.95,
"description": "Orbit raising maneuver detected, altitude increased by 12km",
"details": {
"delta_altitude_km": 12.3,
"delta_v_estimated_m_s": 2.1,
"pre_altitude_km": 538,
"post_altitude_km": 550.3
}
},
{
"id": "pat_abc456",
"type": "proximity",
"subtype": "approach",
"timestamp": "2026-01-10T14:45:00Z",
"confidence": 0.88,
"description": "Approached USA-245 within 50km, maintained position for 6 hours",
"details": {
"target": "USA-245",
"min_distance_km": 48.2,
"duration_hours": 6.2
}
},
{
"id": "pat_def123",
"type": "anomaly",
"subtype": "attitude_change",
"timestamp": "2026-01-05T22:10:00Z",
"confidence": 0.72,
"description": "Unusual attitude variation detected, possible sensor reorientation",
"details": {
"magnitude_deg": 15.3,
"duration_min": 45
}
}
],
"analysis_window": {
"start": "2025-12-22T00:00:00Z",
"end": "2026-01-21T00:00:00Z"
}
}
```
## Pattern Types
### Maneuvers
Detected orbital changes:
| Subtype | Description |
| ----------------- | ------------------------------- |
| `orbit_raise` | Altitude increase |
| `orbit_lower` | Altitude decrease |
| `plane_change` | Inclination adjustment |
| `phasing` | Along-track position adjustment |
| `station_keeping` | Maintenance maneuver |
| `deorbit` | End-of-life maneuver |
```python theme={null}
# Get only maneuvers
maneuvers = client.list_patterns(
satellite_id="STARLINK-1234",
type="maneuver",
lookback_days=90
)
for m in maneuvers:
print(f"{m['timestamp']}: {m['subtype']}")
print(f" Delta-V: {m['details']['delta_v_estimated_m_s']} m/s")
```
### Anomalies
Unexpected behavior deviations:
| Subtype | Description |
| ---------------------- | ----------------------------- |
| `attitude_change` | Unexpected orientation change |
| `tumbling` | Loss of attitude control |
| `fragmentation` | Debris generation event |
| `signal_loss` | Communication anomaly |
| `trajectory_deviation` | Unexpected position change |
```python theme={null}
# Get anomalies
anomalies = client.list_patterns(
satellite_id="DEBRIS-12345",
type="anomaly",
lookback_days=7
)
for a in anomalies:
if a['subtype'] == "fragmentation":
print(f"ALERT: Possible fragmentation at {a['timestamp']}")
```
### Proximity Operations
Close approaches and rendezvous:
```python theme={null}
# Detect proximity operations
proximity = client.list_patterns(
satellite_id="INSPECTOR-SAT",
type="proximity",
lookback_days=60
)
for p in proximity:
print(f"Approached {p['details']['target']}")
print(f" Min distance: {p['details']['min_distance_km']} km")
print(f" Duration: {p['details']['duration_hours']} hours")
```
## Real-Time Anomaly Detection
Get immediate alerts for anomalies:
```python Python theme={null}
# Set up anomaly monitoring via webhook
# See /intelligence/webhooks for full webhook setup
import requests
requests.post(
"https://api.rotastellar.com/v1/patterns/monitor",
headers={"Authorization": "Bearer rs_your_api_key"},
json={
"satellites": ["CRITICAL-SAT-1", "CRITICAL-SAT-2"],
"types": ["anomaly", "proximity"],
"min_confidence": 0.8,
"webhook_url": "https://your-app.com/pattern-alerts"
}
)
```
```bash cURL theme={null}
curl -X POST https://api.rotastellar.com/v1/patterns/monitor \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"satellites": ["CRITICAL-SAT-1", "CRITICAL-SAT-2"],
"types": ["anomaly", "proximity"],
"min_confidence": 0.8,
"webhook_url": "https://your-app.com/pattern-alerts"
}'
```
## Historical Analysis
Analyze long-term behavioral patterns:
```python theme={null}
# Get 1-year pattern history
history = client.list_patterns(
satellite_id="GEO-SAT-1",
lookback_days=365
)
# Analyze maneuver frequency
maneuvers = [p for p in history if p['type'] == "maneuver"]
print(f"Total maneuvers: {len(maneuvers)}")
print(f"Station-keeping: {sum(1 for m in maneuvers if m['subtype'] == 'station_keeping')}")
```
## Batch Analysis
Analyze patterns across multiple satellites:
```python theme={null}
# Analyze entire constellation
satellites = ["SAT-001", "SAT-002", "SAT-003"]
results = {}
for sat_id in satellites:
patterns = client.list_patterns(satellite_id=sat_id, lookback_days=30)
results[sat_id] = patterns
for sat_id, patterns in results.items():
anomalies = [p for p in patterns if p['type'] == "anomaly"]
if anomalies:
print(f"{sat_id}: {len(anomalies)} anomalies detected")
```
## Next Steps
Set up real-time pattern alerts
Track satellite positions
# Satellite Tracking
Source: https://docs.rotastellar.com/intelligence/satellites
Real-time positions for 10,000+ active satellites
# Satellite Tracking
Track any satellite in Earth orbit with real-time position data, orbital parameters, and historical trajectories.
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
## Overview
The Satellite Tracking API provides:
* **Real-time positions** — Current lat/lon/altitude for any tracked object
* **Orbital parameters** — Keplerian elements, period, inclination
* **Propagation** — Future position predictions
* **Historical data** — Past trajectory archive
## Catalog Coverage
| Category | Count | Sources |
| ----------------- | ------- | ----------------------- |
| Active satellites | 10,000+ | Space-Track, commercial |
| Debris objects | 35,000+ | Space-Track |
| Total tracked | 45,000+ | Multiple sources |
## Quick Start
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
# Get satellite by NORAD ID
iss = client.get_satellite("25544") # ISS
# Current position
print(f"Location: {iss.position.latitude}, {iss.position.longitude}")
print(f"Altitude: {iss.position.altitude_km} km")
# Orbital parameters
print(f"Period: {iss.orbit.orbital_period_minutes} minutes")
print(f"Inclination: {iss.orbit.inclination_deg} deg")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
// Get satellite
const iss = await client.getSatellite('25544'); // ISS
// Current position
console.log(`Location: ${iss.position?.latitude}, ${iss.position?.longitude}`);
console.log(`Altitude: ${iss.position?.altitudeKm} km`);
// Orbital parameters
console.log(`Period: ${iss.orbit?.periodMin} minutes`);
```
```rust Rust theme={null}
use rotastellar::types::{Position, Orbit};
fn main() -> Result<(), Box> {
// Rust SDK provides types only (HTTP client coming soon)
// Use Python or Node.js SDK for full API access
let pos = Position::new(41.264, -95.123, 420.5)?;
println!("Location: {}, {}", pos.latitude, pos.longitude);
println!("Altitude: {} km", pos.altitude_km);
Ok(())
}
```
```bash cURL theme={null}
curl https://api.rotastellar.com/v1/satellites/ISS \
-H "Authorization: Bearer rs_your_api_key"
```
## Get Satellite
Retrieve information about a specific satellite.
```
GET /v1/satellites/{satellite_id}
```
NORAD catalog ID or common name (e.g., "25544" or "ISS")
### Response
```json theme={null}
{
"id": "25544",
"name": "ISS (ZARYA)",
"names": ["ISS", "ZARYA", "INTERNATIONAL SPACE STATION"],
"type": "PAYLOAD",
"operator": "NASA/Roscosmos",
"launch_date": "1998-11-20",
"position": {
"lat": 41.264,
"lon": -95.123,
"altitude_km": 420.5,
"velocity_km_s": 7.66,
"timestamp": "2026-01-21T12:00:00Z"
},
"orbit": {
"period_min": 92.9,
"inclination_deg": 51.64,
"apogee_km": 422,
"perigee_km": 418,
"eccentricity": 0.0002
}
}
```
## List Satellites
Query the satellite catalog with filters.
```
GET /v1/satellites
```
Filter by object type: `PAYLOAD`, `ROCKET_BODY`, `DEBRIS`
Filter by operator (e.g., "SpaceX", "OneWeb")
Filter by constellation (e.g., "Starlink", "OneWeb")
Maximum results (1-1000)
Pagination cursor for next page
### Example: List Starlink Satellites
```python Python theme={null}
starlinks = client.list_satellites(
constellation="Starlink",
limit=100
)
for sat in starlinks:
print(f"{sat.name}: {sat.position.altitude_km} km")
```
```bash cURL theme={null}
curl "https://api.rotastellar.com/v1/satellites?constellation=Starlink&limit=100" \
-H "Authorization: Bearer rs_your_api_key"
```
## Get Position
Get current or predicted position.
```
GET /v1/satellites/{satellite_id}/position
```
ISO 8601 timestamp for prediction (default: now)
### Example: Predict Future Position
```python Python theme={null}
from datetime import datetime, timedelta
# Where will ISS be in 2 hours?
future = (datetime.utcnow() + timedelta(hours=2)).isoformat()
pos = client.get_satellite_position("25544", at=future)
print(f"Predicted: {pos.latitude}, {pos.longitude}")
```
```bash cURL theme={null}
curl "https://api.rotastellar.com/v1/satellites/ISS/position?at=2026-01-21T14:00:00Z" \
-H "Authorization: Bearer rs_your_api_key"
```
## Get Trajectory
Get position history or predictions over a time range.
```
GET /v1/satellites/{satellite_id}/trajectory
```
Start time (ISO 8601)
End time (ISO 8601)
Time between points in seconds
### Example: Get 24-hour Trajectory
```python Python theme={null}
from datetime import datetime, timedelta
trajectory = client.get_trajectory(
satellite_id="25544",
start=datetime.utcnow().isoformat(),
end=(datetime.utcnow() + timedelta(hours=24)).isoformat(),
interval_sec=300 # Every 5 minutes
)
for point in trajectory:
print(f"{point['timestamp']}: {point['lat']}, {point['lon']}")
```
```bash cURL theme={null}
curl "https://api.rotastellar.com/v1/satellites/ISS/trajectory?start=2026-01-21T00:00:00Z&end=2026-01-22T00:00:00Z&interval_sec=300" \
-H "Authorization: Bearer rs_your_api_key"
```
## Data Formats
### Position Object
```json theme={null}
{
"lat": 41.264,
"lon": -95.123,
"altitude_km": 420.5,
"velocity_km_s": 7.66,
"timestamp": "2026-01-21T12:00:00Z"
}
```
### Orbit Object
```json theme={null}
{
"epoch": "2026-01-21T00:00:00Z",
"period_min": 92.9,
"inclination_deg": 51.64,
"raan_deg": 123.45,
"arg_perigee_deg": 234.56,
"eccentricity": 0.0002,
"mean_anomaly_deg": 45.67,
"apogee_km": 422,
"perigee_km": 418
}
```
## Rate Limits
| Endpoint | Free | Pro | Enterprise |
| --------------- | ------ | ------- | ---------- |
| Get Satellite | 10/min | 100/min | Custom |
| List Satellites | 5/min | 50/min | Custom |
| Get Trajectory | 2/min | 20/min | Custom |
## Next Steps
Analyze collision risks between objects
Detect anomalies in satellite behavior
# Webhooks
Source: https://docs.rotastellar.com/intelligence/webhooks
Real-time alerts for orbital events
# Webhooks
Receive real-time notifications when orbital events occur, including conjunctions, anomalies, and pattern detections.
**Status:** Coming Q1 2026 — [Request early access](https://rotastellar.com/developers) to be notified when available.
## Overview
Webhooks deliver events to your application in real-time:
* **Conjunction alerts** — New conjunctions or risk level changes
* **Pattern detections** — Maneuvers, anomalies, proximity events
* **Satellite updates** — Status changes, new TLE data
* **System events** — API maintenance, data source updates
## Quick Start
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
# Create a webhook endpoint
webhook = client.webhooks.create(
url="https://your-app.com/rotastellar-events",
events=["conjunction.created", "conjunction.risk_changed", "pattern.detected"],
secret="your-webhook-secret"
)
print(f"Webhook ID: {webhook.id}")
print(f"Status: {webhook.status}")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const webhook = await client.webhooks.create({
url: 'https://your-app.com/rotastellar-events',
events: ['conjunction.created', 'conjunction.risk_changed', 'pattern.detected'],
secret: 'your-webhook-secret'
});
console.log(`Webhook ID: ${webhook.id}`);
```
```bash cURL theme={null}
curl -X POST https://api.rotastellar.com/v1/webhooks \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/rotastellar-events",
"events": ["conjunction.created", "conjunction.risk_changed", "pattern.detected"],
"secret": "your-webhook-secret"
}'
```
## Event Types
### Conjunction Events
| Event | Description |
| -------------------------- | --------------------------------------- |
| `conjunction.created` | New conjunction detected |
| `conjunction.updated` | Conjunction parameters updated |
| `conjunction.risk_changed` | Risk level changed |
| `conjunction.resolved` | Conjunction passed or maneuver executed |
### Pattern Events
| Event | Description |
| ------------------- | ------------------------------ |
| `pattern.detected` | New pattern identified |
| `pattern.maneuver` | Maneuver specifically detected |
| `pattern.anomaly` | Anomaly specifically detected |
| `pattern.proximity` | Proximity operation detected |
### Satellite Events
| Event | Description |
| -------------------------- | ------------------------------ |
| `satellite.tle_updated` | New orbital elements available |
| `satellite.status_changed` | Operational status changed |
| `satellite.decay_warning` | Reentry prediction issued |
## Webhook Payload
All webhook payloads follow this structure:
```json theme={null}
{
"id": "evt_abc123",
"type": "conjunction.created",
"timestamp": "2026-01-21T12:00:00Z",
"data": {
"conjunction": {
"id": "conj_xyz789",
"tca": "2026-01-23T14:32:15Z",
"primary": {
"id": "12345",
"name": "STARLINK-1234"
},
"secondary": {
"id": "45678",
"name": "COSMOS 2251 DEB"
},
"miss_km": 0.45,
"probability": 2.3e-5,
"risk_level": "HIGH"
}
}
}
```
## Verifying Webhooks
Verify webhook signatures to ensure authenticity:
```python Python theme={null}
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
# In your webhook handler
@app.post("/rotastellar-events")
def handle_webhook(request):
signature = request.headers.get("X-RotaStellar-Signature")
payload = request.body
if not verify_webhook(payload, signature, "your-webhook-secret"):
return {"error": "Invalid signature"}, 401
event = json.loads(payload)
print(f"Received event: {event['type']}")
return {"status": "ok"}
```
```typescript Node.js theme={null}
import crypto from 'crypto';
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(`sha256=${expected}`),
Buffer.from(signature)
);
}
// In your webhook handler
app.post('/rotastellar-events', (req, res) => {
const signature = req.headers['x-rotastellar-signature'];
if (!verifyWebhook(req.rawBody, signature, 'your-webhook-secret')) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = req.body;
console.log(`Received event: ${event.type}`);
res.json({ status: 'ok' });
});
```
## Managing Webhooks
### List Webhooks
```python theme={null}
webhooks = client.webhooks.list()
for wh in webhooks:
print(f"{wh.id}: {wh.url}")
print(f" Events: {', '.join(wh.events)}")
print(f" Status: {wh.status}")
```
### Update Webhook
```python theme={null}
webhook = client.webhooks.update(
id="wh_abc123",
events=["conjunction.created", "pattern.anomaly"], # Change events
enabled=True
)
```
### Delete Webhook
```python theme={null}
client.webhooks.delete("wh_abc123")
```
### Test Webhook
Send a test event to verify your endpoint:
```python theme={null}
result = client.webhooks.test("wh_abc123")
print(f"Test result: {result.status}")
print(f"Response time: {result.response_time_ms}ms")
```
## Filtering Events
Filter events to specific satellites:
```python theme={null}
# Only receive events for specific satellites
webhook = client.webhooks.create(
url="https://your-app.com/events",
events=["conjunction.created", "pattern.detected"],
filters={
"satellites": ["SAT-001", "SAT-002", "SAT-003"]
}
)
```
Filter by risk level:
```python theme={null}
# Only receive HIGH and CRITICAL conjunctions
webhook = client.webhooks.create(
url="https://your-app.com/alerts",
events=["conjunction.created", "conjunction.risk_changed"],
filters={
"risk_levels": ["HIGH", "CRITICAL"]
}
)
```
## Retry Policy
Failed webhook deliveries are retried with exponential backoff:
| Attempt | Delay |
| ------- | ---------- |
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 8 hours |
After 6 failed attempts, the webhook is disabled and you'll receive an email notification.
## Best Practices
Return a 2xx response within 30 seconds. Process events asynchronously
if needed.
Events may be delivered more than once. Use the event `id` to deduplicate.
Always verify the `X-RotaStellar-Signature` header to ensure authenticity.
Webhook endpoints must use HTTPS for security.
## Next Steps
Learn about conjunction events
Learn about pattern events
# Introduction
Source: https://docs.rotastellar.com/introduction
The API for computing beyond Earth
# RotaStellar API
The RotaStellar API provides programmatic access to orbital compute infrastructure — from planning tools to runtime execution.
**Early Access** — The API is currently in early access.
[Request an API key](https://rotastellar.com/developers) to get started.
## Platform Overview
The API is organized around four product layers:
Feasibility analysis, thermal modeling, latency simulation
Satellite tracking, conjunction analysis, pattern detection
Constraint-aware execution planning for orbital workloads
Orbit-aware scheduling, adaptive inference, resilient compute
## API Status
| Product | Status | Availability |
| -------------------- | -------------- | ------------ |
| Planning Tools | Early Access | Now |
| Orbital Intelligence | Early Access | Now |
| CAE | Available | Now |
| Orbital Runtime | Design Preview | Q2 2026 |
## Quick Example
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
# Check feasibility of orbital compute
result = client.planning.analyze(
workload="ai_inference",
compute_tflops=100
)
print(f"Recommended orbit: {result.orbit}")
print(f"Estimated cost: ${result.cost_monthly}/mo")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
// Check feasibility of orbital compute
const result = await client.planning.analyze({
workload: 'ai_inference',
computeTflops: 100
});
console.log(`Recommended orbit: ${result.orbit}`);
console.log(`Estimated cost: $${result.costMonthly}/mo`);
```
```rust Rust theme={null}
use rotastellar::RotaStellar;
#[tokio::main]
async fn main() -> Result<(), Box> {
let client = RotaStellar::new("rs_...")?;
let result = client.planning().analyze(
"ai_inference",
100.0 // compute_tflops
).await?;
println!("Recommended orbit: {}", result.orbit);
println!("Estimated cost: ${}/mo", result.cost_monthly);
Ok(())
}
```
```bash cURL theme={null}
curl https://api.rotastellar.com/v1/planning/analyze \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"workload": "ai_inference",
"compute_tflops": 100
}'
```
## Base URL
All API requests should be made to:
```
https://api.rotastellar.com/v1
```
## Authentication
The API uses Bearer token authentication. Include your API key in the `Authorization` header:
```bash theme={null}
curl https://api.rotastellar.com/v1/satellites \
-H "Authorization: Bearer rs_your_api_key"
```
Request early access to receive your API credentials.
# Feasibility Analysis
Source: https://docs.rotastellar.com/planning/feasibility
Evaluate orbital compute viability for your workload
# Feasibility Analysis
Determine whether your workload is suitable for orbital deployment and get recommendations for optimal configuration.
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
## Overview
Feasibility analysis evaluates:
* **Technical viability** — Can this workload run in space?
* **Optimal orbit** — Which orbital regime best fits your requirements?
* **Cost estimation** — What will deployment and operation cost?
* **Risk assessment** — What are the key challenges?
## Quick Start
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
result = client.planning.analyze(
workload="ai_inference",
compute_tflops=100,
storage_tb=10,
bandwidth_gbps=1,
latency_sla_ms=50
)
print(f"Viable: {result.viable}")
print(f"Recommendation: {result.recommendation}")
print(f"Orbit: {result.orbit}")
print(f"Cost: ${result.cost_monthly}/mo")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const result = await client.planning.analyze({
workload: 'ai_inference',
computeTflops: 100,
storageTb: 10,
bandwidthGbps: 1,
latencySlams: 50
});
console.log(`Viable: ${result.viable}`);
console.log(`Orbit: ${result.orbit}`);
```
```rust Rust theme={null}
use rotastellar::RotaStellar;
#[tokio::main]
async fn main() -> Result<(), Box> {
let client = RotaStellar::new("rs_...")?;
let result = client.planning().analyze(AnalyzeRequest {
workload: "ai_inference".to_string(),
compute_tflops: 100.0,
storage_tb: Some(10.0),
bandwidth_gbps: Some(1.0),
latency_sla_ms: Some(50),
}).await?;
println!("Viable: {}", result.viable);
println!("Orbit: {}", result.orbit);
Ok(())
}
```
```bash cURL theme={null}
curl https://api.rotastellar.com/v1/planning/analyze \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"workload": "ai_inference",
"compute_tflops": 100,
"storage_tb": 10,
"bandwidth_gbps": 1,
"latency_sla_ms": 50
}'
```
## Parameters
### Required
Type of workload. Options:
* `ai_inference` — ML model inference
* `ai_training` — ML model training
* `data_processing` — General data processing
* `edge_compute` — Edge computing workloads
* `storage` — Data storage and retrieval
Required compute capacity in TFLOPS (FP16 equivalent)
### Optional
Required storage in terabytes
Required bandwidth to/from ground in Gbps
Maximum acceptable latency in milliseconds
Required availability (e.g., 0.999 for 99.9%)
Geographic region for ground connectivity. Options: `global`, `north-america`, `europe`, `asia-pacific`
## Response
```json theme={null}
{
"viable": true,
"recommendation": "LEO constellation with 6 satellites provides optimal balance of latency and cost",
"orbit": {
"type": "LEO",
"altitude_km": 550,
"inclination_deg": 53,
"constellation_size": 6
},
"cost": {
"monthly": 125000,
"setup": 2500000,
"currency": "USD"
},
"power": {
"required_kw": 15.5,
"solar_array_m2": 45,
"battery_kwh": 120
},
"latency": {
"p50_ms": 25,
"p95_ms": 45,
"p99_ms": 65
},
"risks": [
{
"category": "thermal",
"severity": "medium",
"description": "Eclipse periods require thermal management"
}
],
"alternatives": [
{
"orbit": "MEO",
"tradeoff": "Higher latency (80ms) but 40% lower cost"
}
]
}
```
## Workload Types
### AI Inference
Best for models that need low-latency inference close to data sources.
```python theme={null}
result = client.planning.analyze(
workload="ai_inference",
compute_tflops=100,
latency_sla_ms=50
)
```
### AI Training
For training models on orbital data (e.g., Earth observation).
```python theme={null}
result = client.planning.analyze(
workload="ai_training",
compute_tflops=500,
storage_tb=100
)
```
### Data Processing
General-purpose compute for data transformation and analysis.
```python theme={null}
result = client.planning.analyze(
workload="data_processing",
compute_tflops=50,
bandwidth_gbps=10
)
```
## Cost Factors
| Factor | Impact |
| ------------------ | ---------------------------------------------- |
| Orbit altitude | Higher = cheaper launch, more latency |
| Constellation size | More satellites = better coverage, higher cost |
| Power requirements | Higher power = larger solar arrays |
| Bandwidth | More bandwidth = more ground stations |
| Redundancy | Higher availability = more satellites |
## Next Steps
Model heat management for your configuration
Detailed latency modeling for your use case
# Latency Simulation
Source: https://docs.rotastellar.com/planning/latency
Predict network latency based on orbital geometry
# Latency Simulation
Model end-to-end latency for orbital compute deployments, including propagation delay, ground station handovers, and inter-satellite links.
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
## Overview
Latency in orbital systems depends on:
* **Propagation delay** — Speed of light distance
* **Ground station availability** — Coverage and handover
* **Inter-satellite links (ISL)** — Routing through constellation
* **Processing delay** — On-board and ground processing
## Quick Start
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
latency = client.planning.latency(
orbit="LEO-550",
ground_stations=["us-west", "us-east", "europe", "asia"],
include_isl=True
)
print(f"P50 latency: {latency.p50_ms}ms")
print(f"P95 latency: {latency.p95_ms}ms")
print(f"P99 latency: {latency.p99_ms}ms")
print(f"Coverage: {latency.coverage_percent}%")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const latency = await client.planning.latency({
orbit: 'LEO-550',
groundStations: ['us-west', 'us-east', 'europe', 'asia'],
includeIsl: true
});
console.log(`P50: ${latency.p50Ms}ms`);
console.log(`P99: ${latency.p99Ms}ms`);
```
```bash cURL theme={null}
curl https://api.rotastellar.com/v1/planning/latency \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"orbit": "LEO-550",
"ground_stations": ["us-west", "us-east", "europe", "asia"],
"include_isl": true
}'
```
## Parameters
Orbit specification (e.g., `LEO-550`, `MEO-8000`, `GEO`)
List of ground station regions:
* `us-west`, `us-east`, `us-central`
* `europe`, `europe-north`
* `asia`, `asia-south`
* `australia`
* `south-america`
Include inter-satellite link routing
Number of satellites (affects ISL routing options)
Specific user location for point-to-point latency:
```json theme={null}
{"lat": 37.7749, "lon": -122.4194}
```
## Response
```json theme={null}
{
"p50_ms": 25,
"p95_ms": 48,
"p99_ms": 72,
"min_ms": 12,
"max_ms": 145,
"coverage_percent": 98.5,
"breakdown": {
"propagation_ms": 8,
"processing_ms": 5,
"handover_ms": 12,
"isl_hops_avg": 1.3
},
"ground_station_stats": [
{
"station": "us-west",
"contact_percent": 35,
"avg_elevation_deg": 42
},
{
"station": "europe",
"contact_percent": 28,
"avg_elevation_deg": 38
}
],
"gaps": [
{
"start_min": 23,
"duration_min": 4,
"region": "pacific"
}
]
}
```
## Latency by Orbit Type
| Orbit | Altitude | One-way Propagation | RTT (typical) |
| ----- | --------- | ------------------- | ------------- |
| LEO | 550 km | 1.8 ms | 20-50 ms |
| MEO | 8,000 km | 27 ms | 80-150 ms |
| GEO | 35,786 km | 120 ms | 480-600 ms |
## Latency Optimization
### With Inter-Satellite Links
ISLs can reduce latency by routing traffic through space instead of bouncing to ground:
```python theme={null}
# Without ISL - must wait for ground station contact
latency_no_isl = client.planning.latency(
orbit="LEO-550",
ground_stations=["us-west"],
include_isl=False
)
# With ISL - can route through constellation
latency_with_isl = client.planning.latency(
orbit="LEO-550",
ground_stations=["us-west"],
include_isl=True,
constellation_size=100
)
print(f"Without ISL: P99 = {latency_no_isl.p99_ms}ms")
print(f"With ISL: P99 = {latency_with_isl.p99_ms}ms")
```
### Geographic Coverage Analysis
Analyze latency from specific user locations:
```python theme={null}
# Latency from San Francisco to orbital compute
latency = client.planning.latency(
orbit="LEO-550",
ground_stations=["us-west", "us-east"],
user_location={"lat": 37.7749, "lon": -122.4194}
)
print(f"SF to orbit P50: {latency.p50_ms}ms")
```
## Coverage Gaps
LEO satellites don't provide continuous coverage. The API identifies gaps:
```python theme={null}
latency = client.planning.latency(
orbit="LEO-550",
ground_stations=["us-west"]
)
for gap in latency.gaps:
print(f"Gap at {gap.start_min}min, duration {gap.duration_min}min")
```
To eliminate gaps, add more ground stations or enable ISL:
```python theme={null}
# Add more ground stations
latency = client.planning.latency(
orbit="LEO-550",
ground_stations=["us-west", "us-east", "europe", "asia"],
include_isl=True
)
print(f"Coverage: {latency.coverage_percent}%") # ~99%+
```
## Next Steps
Plan power for your orbital deployment
Complete feasibility assessment
# Planning Tools Overview
Source: https://docs.rotastellar.com/planning/overview
Answer 'should we?' before 'how?'
# Planning Tools
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
Planning Tools help you evaluate the feasibility of orbital compute deployments before committing resources. Answer critical questions about thermal management, latency, power, and cost.
## Capabilities
Evaluate whether your workload is suitable for orbital compute
Model heat rejection and thermal cycles in orbit
Predict network latency based on orbital geometry
Plan power generation and consumption across orbit
## Quick Start
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
# Comprehensive feasibility analysis
result = client.planning.analyze(
workload="ai_inference",
compute_tflops=100,
storage_tb=10,
bandwidth_gbps=1
)
print(f"Recommendation: {result.recommendation}")
print(f"Optimal orbit: {result.orbit}")
print(f"Monthly cost: ${result.cost_monthly}")
print(f"Power required: {result.power_kw} kW")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const result = await client.planning.analyze({
workload: 'ai_inference',
computeTflops: 100,
storageTb: 10,
bandwidthGbps: 1
});
console.log(`Recommendation: ${result.recommendation}`);
console.log(`Optimal orbit: ${result.orbit}`);
console.log(`Monthly cost: $${result.costMonthly}`);
```
```bash cURL theme={null}
curl https://api.rotastellar.com/v1/planning/analyze \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"workload": "ai_inference",
"compute_tflops": 100,
"storage_tb": 10,
"bandwidth_gbps": 1
}'
```
## Workflow
A typical planning workflow:
```mermaid theme={null}
flowchart LR
A[Define Requirements] --> B[Feasibility Analysis]
B --> C{Viable?}
C -->|Yes| D[Thermal Simulation]
C -->|No| E[Adjust Requirements]
E --> B
D --> F[Latency Modeling]
F --> G[Power Budgeting]
G --> H[Deployment Plan]
```
## Orbit Options
| Orbit Type | Altitude | Period | Use Cases |
| ---------- | --------------- | ---------- | -------------------------------- |
| LEO | 300-600 km | 90-100 min | Low latency, Earth observation |
| MEO | 2,000-35,000 km | 2-24 hr | Navigation, regional coverage |
| GEO | 35,786 km | 24 hr | Fixed coverage, broadcasting |
| HEO | Variable | Variable | Polar coverage, specific regions |
## Next Steps
Start with a comprehensive feasibility check
View the full API specification
# Power Budgeting
Source: https://docs.rotastellar.com/planning/power
Plan power generation and consumption across orbit
# Power Budgeting
Model power generation, storage, and consumption for orbital compute systems across the full orbital cycle.
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
## Overview
Power in orbit is fundamentally different from Earth:
* **Solar only** — Primary power source is photovoltaic
* **Eclipse periods** — No generation during Earth shadow
* **Battery cycling** — Must store enough for eclipse
* **Degradation** — Solar cells degrade over mission life
## Quick Start
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
power = client.planning.power(
orbit="LEO-550",
compute_load_w=500,
duty_cycle=0.8,
mission_life_years=5
)
print(f"Solar array: {power.solar_array_m2} m2")
print(f"Battery: {power.battery_kwh} kWh")
print(f"Available during eclipse: {power.eclipse_power_w}W")
print(f"EOL margin: {power.eol_margin_percent}%")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const power = await client.planning.power({
orbit: 'LEO-550',
computeLoadW: 500,
dutyCycle: 0.8,
missionLifeYears: 5
});
console.log(`Solar array: ${power.solarArrayM2} m2`);
console.log(`Battery: ${power.batteryKwh} kWh`);
```
```bash cURL theme={null}
curl https://api.rotastellar.com/v1/planning/power \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"orbit": "LEO-550",
"compute_load_w": 500,
"duty_cycle": 0.8,
"mission_life_years": 5
}'
```
## Parameters
Orbit specification (e.g., `LEO-550`, `GEO`)
Peak compute power consumption in watts
Fraction of time compute is active (0-1)
Mission duration for degradation calculations
Non-compute power (thermal, comms, ADCS)
Maximum battery depth of discharge (0-1)
## Response
```json theme={null}
{
"solar_array": {
"area_m2": 3.2,
"power_bol_w": 960,
"power_eol_w": 768,
"degradation_percent_per_year": 2.5
},
"battery": {
"capacity_kwh": 0.85,
"cycles_per_day": 15.5,
"eol_capacity_percent": 80
},
"power_profile": {
"sunlit_available_w": 680,
"eclipse_available_w": 420,
"average_available_w": 580
},
"margins": {
"bol_margin_percent": 25,
"eol_margin_percent": 12
},
"recommendations": [
"Consider 10% larger array for operational margin",
"Battery supports 5-year mission with 80% EOL capacity"
],
"orbit_profile": [
{"phase": "sunlit", "duration_min": 57, "power_w": 680},
{"phase": "eclipse", "duration_min": 35, "power_w": 420}
]
}
```
## Power Budget Breakdown
### Typical LEO Power Budget
| Subsystem | Power (W) | Notes |
| -------------- | --------- | ---------------------- |
| Compute (peak) | 500 | GPU/TPU workloads |
| Compute (idle) | 50 | Standby mode |
| Thermal | 30-100 | Heaters during eclipse |
| Communications | 20-50 | Varies with data rate |
| ADCS | 10-20 | Attitude control |
| Housekeeping | 20-30 | Avionics, sensors |
### Power Modes
```python theme={null}
# Model different operating modes
power = client.planning.power(
orbit="LEO-550",
modes=[
{"name": "full_compute", "power_w": 500, "duration_percent": 60},
{"name": "reduced", "power_w": 200, "duration_percent": 30},
{"name": "idle", "power_w": 50, "duration_percent": 10}
],
mission_life_years=5
)
```
## Eclipse Operations
During eclipse, power is limited to battery capacity:
```python theme={null}
power = client.planning.power(
orbit="LEO-550",
compute_load_w=500,
eclipse_strategy="reduced" # or "full", "suspend"
)
# Check eclipse power availability
if power.eclipse_available_w < 500:
print(f"Must reduce to {power.eclipse_available_w}W during eclipse")
```
### Eclipse Strategies
| Strategy | Description | Use Case |
| --------- | ---------------------------------- | ---------------------------- |
| `full` | Maintain full power | Large battery, short eclipse |
| `reduced` | Reduce compute during eclipse | Balanced approach |
| `suspend` | Suspend compute, housekeeping only | Minimal battery |
## Degradation Over Mission Life
Solar arrays and batteries degrade over time:
```python theme={null}
# Compare BOL vs EOL power
power = client.planning.power(
orbit="LEO-550",
compute_load_w=500,
mission_life_years=7
)
print(f"Year 1 available: {power.solar_array.power_bol_w}W")
print(f"Year 7 available: {power.solar_array.power_eol_w}W")
print(f"Degradation: {power.solar_array.degradation_percent_per_year}%/year")
```
## Design Recommendations
Size for end-of-life (EOL) power needs plus 10-20% margin.
Account for degradation: \~2.5%/year in LEO due to radiation.
Size for eclipse duration + margin. Limit depth of discharge
to 30-40% for long cycle life.
Design for multiple power modes. Ability to reduce compute
load extends operational flexibility.
## Next Steps
Ensure thermal design matches power budget
Complete system feasibility check
# Thermal Simulation
Source: https://docs.rotastellar.com/planning/thermal
Model heat rejection and thermal cycles in orbit
# Thermal Simulation
Simulate thermal behavior of compute hardware in orbital environments, including eclipse cycles and varying solar flux.
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
## Overview
Space presents unique thermal challenges:
* **No convection** — Heat can only be rejected via radiation
* **Eclipse cycles** — Periodic loss of solar heating
* **Solar flux variation** — Changes with orbit and season
* **Internal heat** — Compute generates significant waste heat
## Quick Start
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
thermal = client.planning.thermal(
orbit="LEO-550",
power_dissipation_w=500,
radiator_area_m2=2.0,
internal_mass_kg=100
)
print(f"Steady state: {thermal.steady_state_c}C")
print(f"Max (sunlit): {thermal.max_temp_c}C")
print(f"Min (eclipse): {thermal.min_temp_c}C")
print(f"Thermal margin: {thermal.margin_c}C")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const thermal = await client.planning.thermal({
orbit: 'LEO-550',
powerDissipationW: 500,
radiatorAreaM2: 2.0,
internalMassKg: 100
});
console.log(`Steady state: ${thermal.steadyStateC}C`);
console.log(`Max temp: ${thermal.maxTempC}C`);
```
```bash cURL theme={null}
curl https://api.rotastellar.com/v1/planning/thermal \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"orbit": "LEO-550",
"power_dissipation_w": 500,
"radiator_area_m2": 2.0,
"internal_mass_kg": 100
}'
```
## Parameters
Orbit specification. Options:
* `LEO-400` to `LEO-600` — Low Earth Orbit at specified altitude
* `MEO-2000` to `MEO-20000` — Medium Earth Orbit
* `GEO` — Geostationary orbit
* Custom: `{"altitude_km": 550, "inclination_deg": 53}`
Internal heat generation in watts
Radiator surface area in square meters
Internal thermal mass in kg (affects transient response)
Radiator emissivity (0-1)
Solar absorptivity (0-1)
## Response
```json theme={null}
{
"steady_state_c": 35.2,
"max_temp_c": 52.8,
"min_temp_c": 12.4,
"margin_c": 17.2,
"eclipse_duration_min": 35.5,
"sunlit_duration_min": 57.3,
"cooling_rate_c_per_min": 0.65,
"heating_rate_c_per_min": 0.48,
"thermal_profile": [
{"time_min": 0, "temp_c": 35.2, "phase": "sunlit"},
{"time_min": 57, "temp_c": 52.8, "phase": "eclipse_start"},
{"time_min": 92, "temp_c": 12.4, "phase": "eclipse_end"}
],
"recommendations": [
"Consider active thermal control for tighter bounds",
"Heaters recommended for eclipse survival"
]
}
```
## Thermal Profiles
### LEO Thermal Cycle
```
Temperature (C)
60 | ____
| / \
40 | / \____
| / \
20 |/ \
+-----------------> Time
Sunlit Eclipse
```
### Operating Limits
| Component | Min (C) | Max (C) |
| --------- | ------- | ------- |
| GPU/TPU | 0 | 85 |
| CPU | -20 | 100 |
| Memory | -40 | 85 |
| Storage | -40 | 70 |
| Battery | 0 | 45 |
## Advanced: Time-Series Simulation
Get detailed thermal behavior over multiple orbits:
```python theme={null}
thermal = client.planning.thermal(
orbit="LEO-550",
power_dissipation_w=500,
radiator_area_m2=2.0,
simulation={
"duration_orbits": 10,
"time_step_sec": 60
}
)
# Plot thermal profile
for point in thermal.time_series:
print(f"{point.time_min}: {point.temp_c}C ({point.phase})")
```
## Design Considerations
Larger radiators = lower steady-state temperature but more mass and cost.
Rule of thumb: 0.1-0.2 m² per 100W dissipation for LEO.
Ensure minimum temperature stays above component limits.
May require heaters or thermal mass.
Consider worst-case solar flux (perihelion + beta angle = 0).
Add 10-15% margin to maximum temperature.
## Next Steps
Model network latency for your orbit
Plan power generation and storage
# Quickstart
Source: https://docs.rotastellar.com/quickstart
Get up and running in 5 minutes
# Quickstart
This guide will get you from zero to your first API call in under 5 minutes.
## 1. Get an API Key
Sign up to receive your API credentials.
## 2. Install the SDK
```bash Python theme={null}
pip install rotastellar
```
```bash Node.js theme={null}
npm install @rotastellar/sdk
```
```bash Rust theme={null}
cargo add rotastellar
```
## 3. Make Your First Request
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_your_api_key")
# Get ISS position
iss = client.get_satellite("25544") # ISS NORAD ID
print(f"ISS Location: {iss.position.latitude}, {iss.position.longitude}")
print(f"Altitude: {iss.position.altitude_km} km")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_your_api_key' });
// Get ISS position
const iss = await client.getSatellite('25544'); // ISS NORAD ID
console.log(`ISS Location: ${iss.position?.latitude}, ${iss.position?.longitude}`);
console.log(`Altitude: ${iss.position?.altitudeKm} km`);
```
```rust Rust theme={null}
use rotastellar::types::{Position, Orbit};
fn main() -> Result<(), Box> {
// Rust SDK provides types only (HTTP client coming soon)
// Use Python or Node.js SDK for full API access
// Create a position type for ISS-like coordinates
let pos = Position::new(41.264, -95.123, 420.5)?;
println!("Location: {}, {}", pos.latitude, pos.longitude);
println!("Altitude: {} km", pos.altitude_km);
Ok(())
}
```
```bash cURL theme={null}
curl https://api.rotastellar.com/v1/satellites/ISS \
-H "Authorization: Bearer rs_your_api_key"
```
## 4. Explore the API
Now that you're set up, explore what you can build:
Real-time positions for 10,000+ active satellites
Collision probability and avoidance recommendations
Feasibility analysis for space-based workloads
Heat rejection modeling for orbital hardware
## Rate Limits
| Tier | Requests/minute | Requests/day |
| ---------- | --------------- | ------------ |
| Free | 10 | 1,000 |
| Pro | 100 | 100,000 |
| Enterprise | Custom | Custom |
## Need Help?
* [API Reference](/api-reference) — Full endpoint documentation
* [GitHub Issues](https://github.com/rotastellar/rotastellar-python/issues) — Bug reports and feature requests
* [Contact Us](https://rotastellar.com/contact/) — Enterprise support
# Adaptive Runtime
Source: https://docs.rotastellar.com/runtime/adaptive
Energy and thermal-aware inference execution
# Adaptive Runtime
**Coming Q2 2026** — This is a design preview.
[Request early access](https://rotastellar.com/developers) to be notified when available.
## Overview
The Adaptive Runtime dynamically adjusts inference execution to stay within energy and thermal constraints. Instead of failing when resources are limited, it gracefully degrades while maintaining output quality bounds.
## Key Capabilities
* **Dynamic precision** — Switch between FP16/INT8/INT4 based on power
* **Layer skipping** — Skip non-critical layers when energy-constrained
* **Context adaptation** — Reduce context window under pressure
* **Thermal throttling** — Automatic frequency scaling near thermal limits
* **Quality guarantees** — Bounded degradation with quality metrics
## How It Works
Your inference request arrives with energy/thermal constraints specified.
**Energy Monitor** tracks battery level, solar input, and power draw. **Thermal Monitor** tracks CPU/GPU temperatures and cooling capacity.
Based on current constraints and monitor data, the controller makes decisions:
* Precision selection (FP16/INT8/INT4)
* Layer skip decisions
* Context window sizing
* Batch size adjustment
Executes the model with the selected adaptations applied.
Returns the response along with a detailed report of what adaptations were applied.
## API Preview
### Submit with Energy Constraints
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
result = client.runtime.generate(
model="llama-70b",
prompt="Summarize this document...",
constraints={
"energy_budget_wh": 0.5, # Max energy for this request
"thermal_limit_c": 75, # Throttle above this temp
"quality": "best_effort" # or "exact"
}
)
print(f"Response: {result.text}")
print(f"Energy used: {result.energy_wh} Wh")
print(f"Adaptations applied: {result.adaptations}")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const result = await client.runtime.generate({
model: 'llama-70b',
prompt: 'Summarize this document...',
constraints: {
energyBudgetWh: 0.5,
thermalLimitC: 75,
quality: 'best_effort'
}
});
console.log(`Response: ${result.text}`);
console.log(`Adaptations: ${JSON.stringify(result.adaptations)}`);
```
```bash cURL theme={null}
curl -X POST https://api.rotastellar.com/v1/runtime/generate \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "llama-70b",
"prompt": "Summarize this document...",
"constraints": {
"energy_budget_wh": 0.5,
"thermal_limit_c": 75,
"quality": "best_effort"
}
}'
```
### Adaptation Report
Every response includes what adaptations were applied:
```json theme={null}
{
"text": "The document discusses...",
"energy_wh": 0.42,
"latency_ms": 156,
"adaptations": {
"precision": "int8", // Reduced from FP16
"layers_skipped": 4, // Out of 80 total
"context_used": 4096, // Reduced from 8192
"batch_size": 1 // No batching
},
"quality_metrics": {
"estimated_perplexity_delta": 0.02,
"confidence": 0.94
}
}
```
### Configure Adaptation Policies
Set global adaptation preferences:
```python theme={null}
client.runtime.configure(
adaptive={
# Precision bounds
"precision_floor": "int8", # Never go below INT8
"precision_ceiling": "fp16", # Start at FP16
# Layer skipping
"layer_skip_max": 0.2, # Skip up to 20% of layers
"skip_strategy": "importance", # or "uniform", "early", "late"
# Context management
"context_min": 2048, # Minimum context window
"context_strategy": "truncate", # or "summarize", "slide"
# Thermal management
"thermal_threshold_c": 70, # Start throttling
"thermal_critical_c": 85, # Hard limit
# Quality guarantees
"quality_floor": 0.9 # Minimum acceptable quality score
}
)
```
## Adaptation Strategies
### Precision Scaling
| Precision | Relative Energy | Relative Quality |
| --------- | --------------- | ---------------- |
| FP16 | 1.0x | 1.0 |
| INT8 | 0.5x | 0.98 |
| INT4 | 0.3x | 0.92 |
```python theme={null}
# Force specific precision
result = client.runtime.generate(
model="llama-70b",
prompt="...",
constraints={
"precision": "int8" # Fixed precision
}
)
```
### Layer Skipping
Skip less important layers to save energy:
```python theme={null}
# Allow aggressive layer skipping
result = client.runtime.generate(
model="llama-70b",
prompt="...",
constraints={
"layer_skip_max": 0.3, # Up to 30%
"skip_strategy": "importance" # Skip least important
}
)
print(f"Layers skipped: {result.adaptations['layers_skipped']}")
```
### Context Adaptation
Reduce context window under constraints:
```python theme={null}
result = client.runtime.generate(
model="llama-70b",
prompt="...",
context=long_document, # 32k tokens
constraints={
"context_max": 8192, # Limit context
"context_strategy": "summarize" # Summarize overflow
}
)
```
## Quality Modes
### Best Effort
Maximize quality within constraints, may degrade:
```python theme={null}
result = client.runtime.generate(
model="llama-70b",
prompt="...",
constraints={
"energy_budget_wh": 0.3,
"quality": "best_effort"
}
)
# Will adapt to fit energy budget
```
### Exact
Fail if constraints can't be met at full quality:
```python theme={null}
result = client.runtime.generate(
model="llama-70b",
prompt="...",
constraints={
"energy_budget_wh": 0.3,
"quality": "exact"
}
)
# Will fail if 0.3 Wh isn't enough for full precision
```
### Bounded
Degrade only within specified bounds:
```python theme={null}
result = client.runtime.generate(
model="llama-70b",
prompt="...",
constraints={
"energy_budget_wh": 0.3,
"quality": "bounded",
"quality_floor": 0.95 # Must maintain 95% quality
}
)
# Will adapt but not below 95% quality
```
## Monitoring
Track adaptation patterns over time:
```python theme={null}
# Get adaptation statistics
stats = client.runtime.adaptation_stats(
period="24h"
)
print(f"Total requests: {stats.total_requests}")
print(f"Adapted requests: {stats.adapted_requests}")
print(f"Average energy savings: {stats.avg_energy_savings_percent}%")
print(f"Average quality maintained: {stats.avg_quality_maintained}")
```
## Next Steps
Learn about fault tolerance
Learn about workload placement
# Orbital Runtime Overview
Source: https://docs.rotastellar.com/runtime/overview
Execution primitives for computing beyond Earth
# Orbital Runtime
**Coming Q2 2026** — The Orbital Runtime is currently in development.
This documentation is a design preview. [Request early access](https://rotastellar.com/developers)
to be notified when it's available.
## Overview
The Orbital Runtime provides execution primitives designed for the unique constraints of space:
Workload orchestration across Earth and orbital nodes
Energy and thermal-aware inference execution
Fault-tolerant ML for radiation environments
## Why a New Runtime?
Standard cloud runtimes assume:
| Assumption | Reality in Space |
| ------------------- | ----------------------------- |
| Always-on network | Intermittent connectivity |
| Stable power | Variable solar/eclipse cycles |
| Predictable latency | Orbital geometry dependent |
| Reliable hardware | Radiation-induced faults |
The Orbital Runtime is built from first principles for these constraints.
## Architecture Preview
Your application connects to the RotaStellar Orbital Runtime, which orchestrates workloads across Earth and orbital infrastructure.
Routes jobs to optimal nodes based on latency, energy, and availability
Adjusts precision, layer execution, and context based on constraints
Radiation-tolerant execution with checksums and redundancy
**Infrastructure Layer:**
| Node Type | Location | Characteristics |
| --------- | ---------------- | -------------------------------------------------------- |
| Earth DC | Terrestrial | High bandwidth, stable power, lowest latency to users |
| LEO Node | 400-600 km orbit | Solar powered, 25ms latency, intermittent ground contact |
| GEO Node | 35,786 km orbit | Continuous coverage, 250ms latency, limited power |
## API Preview
This API is subject to change before release.
### Submit a Job
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
# Submit inference job with constraints
job = client.runtime.submit(
model="llama-70b",
prompt="Analyze this satellite telemetry...",
constraints={
"latency_sla_ms": 200,
"energy_budget_wh": 0.5,
"quality": "best_effort" # or "exact"
}
)
# Job is routed to optimal node (Earth or orbit)
print(f"Job ID: {job.id}")
print(f"Routed to: {job.node}") # e.g., "orbital-leo-1"
print(f"Estimated completion: {job.eta}")
# Get result
result = job.result(timeout=30)
print(f"Response: {result.text}")
print(f"Adaptations: {result.adaptations}")
print(f"Energy used: {result.energy_wh} Wh")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const job = await client.runtime.submit({
model: 'llama-70b',
prompt: 'Analyze this satellite telemetry...',
constraints: {
latencySlams: 200,
energyBudgetWh: 0.5,
quality: 'best_effort'
}
});
console.log(`Job ID: ${job.id}`);
console.log(`Routed to: ${job.node}`);
const result = await job.result({ timeout: 30000 });
console.log(`Response: ${result.text}`);
```
```rust Rust theme={null}
use rotastellar::RotaStellar;
#[tokio::main]
async fn main() -> Result<(), Box> {
let client = RotaStellar::new("rs_...")?;
let job = client.runtime().submit(JobRequest {
model: "llama-70b".to_string(),
prompt: "Analyze this satellite telemetry...".to_string(),
constraints: Constraints {
latency_sla_ms: Some(200),
energy_budget_wh: Some(0.5),
quality: Quality::BestEffort,
},
}).await?;
println!("Job ID: {}", job.id);
println!("Routed to: {}", job.node);
let result = job.result(30).await?;
println!("Response: {}", result.text);
Ok(())
}
```
```bash cURL theme={null}
curl -X POST https://api.rotastellar.com/v1/runtime/jobs \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "llama-70b",
"prompt": "Analyze this satellite telemetry...",
"constraints": {
"latency_sla_ms": 200,
"energy_budget_wh": 0.5,
"quality": "best_effort"
}
}'
```
### Configure Adaptive Behavior
```python theme={null}
# Set global adaptation preferences
client.runtime.configure(
adaptive={
"precision_floor": "int8", # Don't go below INT8
"layer_skip_max": 0.2, # Skip up to 20% of layers
"context_min": 2048, # Minimum context window
"thermal_threshold_c": 75 # Throttle above 75C
},
resilience={
"checksum_layers": True,
"redundant_attention": True,
"max_reexecute": 3
}
)
```
## Timeline
| Milestone | Target |
| ------------------------- | ------- |
| Design preview (this doc) | Now |
| Simulator SDK | Q2 2026 |
| Beta with early partners | Q4 2026 |
| General availability | 2027 |
## Get Notified
Be the first to know when Orbital Runtime is available.
# Resilient Compute
Source: https://docs.rotastellar.com/runtime/resilient
Fault-tolerant ML for radiation environments
# Resilient Compute
**Coming Q2 2026** — This is a design preview.
[Request early access](https://rotastellar.com/developers) to be notified when available.
## Overview
Resilient Compute provides fault-tolerant ML execution for radiation environments. Space radiation causes Single Event Upsets (SEUs) that flip bits in memory and computation. Instead of ignoring this reality, we build detection and recovery directly into the inference pipeline.
## The Problem
In LEO, a typical compute system experiences:
* **\~10-100 SEUs per day** in unshielded memory
* **Silent data corruption** in weights and activations
* **Accumulated errors** that compound through layers
* **Unpredictable failures** in traditional ML pipelines
## Our Approach
Verify integrity of model weights and input data before processing.
Execute each layer with optional redundancy for critical computations (e.g., attention).
Compare checksums and redundant outputs to detect bit flips or corruption.
When errors are detected, the system either:
* **Bounded Error Propagation** - Contains errors to prevent cascading through layers
* **Selective Re-execution** - Re-runs only the affected computation
Final validation ensures output integrity before returning results.
## Key Capabilities
* **Error detection** — Checksums and redundancy catch corruption
* **Bounded propagation** — Prevent errors from cascading
* **Selective re-execution** — Only re-run affected computation
* **Graceful degradation** — Maintain service despite faults
* **Transparency** — Report what happened and confidence level
## API Preview
### Enable Resilience Features
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
result = client.runtime.generate(
model="llama-70b",
prompt="Critical analysis of...",
resilience={
"checksum_layers": True, # Verify layer outputs
"redundant_attention": True, # Duplicate attention computation
"max_reexecute": 3, # Max re-executions per layer
"error_threshold": 0.01 # Max acceptable error rate
}
)
print(f"Response: {result.text}")
print(f"Errors detected: {result.resilience.errors_detected}")
print(f"Errors corrected: {result.resilience.errors_corrected}")
print(f"Confidence: {result.resilience.confidence}")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const result = await client.runtime.generate({
model: 'llama-70b',
prompt: 'Critical analysis of...',
resilience: {
checksumLayers: true,
redundantAttention: true,
maxReexecute: 3,
errorThreshold: 0.01
}
});
console.log(`Confidence: ${result.resilience.confidence}`);
```
```bash cURL theme={null}
curl -X POST https://api.rotastellar.com/v1/runtime/generate \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "llama-70b",
"prompt": "Critical analysis of...",
"resilience": {
"checksum_layers": true,
"redundant_attention": true,
"max_reexecute": 3,
"error_threshold": 0.01
}
}'
```
### Resilience Report
Every response includes a resilience report:
```json theme={null}
{
"text": "The analysis shows...",
"resilience": {
"errors_detected": 2,
"errors_corrected": 2,
"reexecutions": 1,
"confidence": 0.998,
"layers_validated": 80,
"checksum_failures": 0,
"details": [
{
"layer": 42,
"type": "activation_corruption",
"action": "reexecuted",
"resolved": true
},
{
"layer": 67,
"type": "weight_bitflip",
"action": "corrected_ecc",
"resolved": true
}
]
}
}
```
### Configure Resilience Globally
```python theme={null}
client.runtime.configure(
resilience={
# Detection methods
"checksum_layers": True, # Checksum layer outputs
"redundant_attention": True, # Duplicate attention
"weight_verification": "periodic", # or "continuous", "none"
# Recovery behavior
"max_reexecute": 3, # Max retries per layer
"reexecute_strategy": "selective", # or "full_layer"
"fallback_precision": "fp32", # Higher precision for re-exec
# Error bounds
"error_threshold": 0.01, # Max error rate before fail
"confidence_floor": 0.95 # Min acceptable confidence
}
)
```
## Detection Methods
### Layer Checksums
Verify outputs match expected ranges:
```python theme={null}
result = client.runtime.generate(
model="llama-70b",
prompt="...",
resilience={
"checksum_layers": True,
"checksum_granularity": "per_head" # or "per_layer"
}
)
```
### Redundant Computation
Run critical computations twice:
```python theme={null}
result = client.runtime.generate(
model="llama-70b",
prompt="...",
resilience={
"redundant_attention": True, # Duplicate attention
"redundant_ffn": False # Don't duplicate FFN (too expensive)
}
)
```
### ECC Memory
Use error-correcting memory when available:
```python theme={null}
result = client.runtime.generate(
model="llama-70b",
prompt="...",
resilience={
"require_ecc": True # Fail if ECC not available
}
)
```
## Recovery Strategies
### Selective Re-execution
Only re-run affected computation:
```python theme={null}
# If layer 42 has a checksum failure, only re-run layer 42
result = client.runtime.generate(
model="llama-70b",
prompt="...",
resilience={
"reexecute_strategy": "selective",
"max_reexecute": 3
}
)
```
### Full Restart
Re-run entire inference if errors exceed threshold:
```python theme={null}
result = client.runtime.generate(
model="llama-70b",
prompt="...",
resilience={
"reexecute_strategy": "full",
"error_threshold": 0.05 # Restart if >5% layers affected
}
)
```
## Resilience Modes
| Mode | Overhead | Protection | Use Case |
| ---------- | -------- | --------------------------- | --------------- |
| `minimal` | 5% | Basic detection | Low-criticality |
| `standard` | 15% | Full detection + correction | Default |
| `high` | 30% | Redundant execution | Safety-critical |
| `paranoid` | 100% | Triple redundancy | Life-critical |
```python theme={null}
result = client.runtime.generate(
model="llama-70b",
prompt="...",
resilience={"mode": "high"}
)
```
## Monitoring Radiation Effects
Track SEU rates and their impact:
```python theme={null}
# Get radiation statistics
stats = client.runtime.radiation_stats(
node="orbital-leo-1",
period="24h"
)
print(f"SEUs detected: {stats.seus_detected}")
print(f"SEUs corrected: {stats.seus_corrected}")
print(f"Inference impact: {stats.inference_impact_percent}%")
print(f"Current flux: {stats.current_flux}")
```
## Best Practices
Use `standard` mode for most workloads. Reserve `high` and `paranoid`
for safety-critical applications.
Track confidence over time. Degrading confidence may indicate
increasing radiation or hardware issues.
During solar events, radiation spikes. Consider pausing
non-critical workloads during high-flux periods.
## Next Steps
Learn about energy-aware inference
Learn about workload placement
# Orbit Scheduler
Source: https://docs.rotastellar.com/runtime/scheduler
Workload orchestration across Earth and orbital nodes
# Orbit Scheduler
**Coming Q2 2026** — This is a design preview.
[Request early access](https://rotastellar.com/developers) to be notified when available.
## Overview
The Orbit Scheduler orchestrates workloads across heterogeneous compute nodes spanning Earth datacenters and orbital infrastructure. It understands orbital mechanics, energy availability, and network topology to make optimal placement decisions.
## Key Capabilities
* **Orbit-aware scheduling** — Accounts for orbital position, eclipse periods, ground contacts
* **Energy optimization** — Routes work based on power availability
* **Latency-aware routing** — Minimizes round-trip time based on geometry
* **Fault tolerance** — Automatic failover between nodes
* **Workload splitting** — Distribute work across Earth + orbit
## Architecture
The Orbit Scheduler uses three models to make placement decisions:
Decides which node should handle each workload based on constraints and current state
Predicts satellite positions, ground contacts, and eclipse periods
Tracks power availability, battery state, and solar input across all nodes
**Available Nodes:**
| Node | Location | Characteristics |
| ------------------ | ------------ | ------------------------------------------ |
| Earth DC (us-west) | Terrestrial | Always available, lowest latency to US |
| LEO-1 | 550 km orbit | Solar-powered, intermittent ground contact |
| LEO-2 | 550 km orbit | Solar-powered, different orbital plane |
## API Preview
### Submit Job with Placement Hints
```python Python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(api_key="rs_...")
job = client.runtime.submit(
model="llama-70b",
prompt="...",
placement={
"prefer": "orbital", # Prefer orbital nodes
"fallback": "earth", # Fall back to Earth if needed
"region_affinity": "europe", # Prefer nodes with Europe visibility
"max_hops": 2 # Max ISL hops
},
constraints={
"latency_sla_ms": 100,
"energy_budget_wh": 0.5
}
)
print(f"Placed on: {job.node}")
print(f"Reason: {job.placement_reason}")
```
```typescript Node.js theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const job = await client.runtime.submit({
model: 'llama-70b',
prompt: '...',
placement: {
prefer: 'orbital',
fallback: 'earth',
regionAffinity: 'europe',
maxHops: 2
},
constraints: {
latencySlams: 100,
energyBudgetWh: 0.5
}
});
```
```bash cURL theme={null}
curl -X POST https://api.rotastellar.com/v1/runtime/jobs \
-H "Authorization: Bearer rs_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "llama-70b",
"prompt": "...",
"placement": {
"prefer": "orbital",
"fallback": "earth",
"region_affinity": "europe",
"max_hops": 2
},
"constraints": {
"latency_sla_ms": 100,
"energy_budget_wh": 0.5
}
}'
```
### Query Node Status
```python theme={null}
# Get current node availability
nodes = client.runtime.nodes()
for node in nodes:
print(f"{node.id}: {node.type}")
print(f" Location: {node.location}")
print(f" Status: {node.status}")
print(f" Available power: {node.available_power_w}W")
print(f" Queue depth: {node.queue_depth}")
if node.type == "orbital":
print(f" In eclipse: {node.in_eclipse}")
print(f" Ground contact: {node.has_ground_contact}")
```
### Schedule Future Work
Schedule jobs to run at optimal times:
```python theme={null}
# Schedule for optimal conditions
scheduled_job = client.runtime.schedule(
model="llama-70b",
prompt="...",
schedule={
"window_start": "2026-01-22T00:00:00Z",
"window_end": "2026-01-22T12:00:00Z",
"optimize_for": "energy" # or "latency", "cost"
}
)
print(f"Scheduled for: {scheduled_job.scheduled_time}")
print(f"Expected node: {scheduled_job.expected_node}")
print(f"Energy savings: {scheduled_job.energy_savings_percent}%")
```
## Placement Strategies
### Orbital-First
Prefer orbital nodes, fall back to Earth:
```python theme={null}
job = client.runtime.submit(
model="...",
prompt="...",
placement={"prefer": "orbital", "fallback": "earth"}
)
```
### Earth-First
Prefer Earth, use orbital for overflow:
```python theme={null}
job = client.runtime.submit(
model="...",
prompt="...",
placement={"prefer": "earth", "fallback": "orbital"}
)
```
### Latency-Optimized
Route to minimize latency to specific region:
```python theme={null}
job = client.runtime.submit(
model="...",
prompt="...",
placement={
"optimize_for": "latency",
"user_location": {"lat": 51.5, "lon": -0.1} # London
}
)
```
### Energy-Optimized
Route to nodes with best energy availability:
```python theme={null}
job = client.runtime.submit(
model="...",
prompt="...",
placement={"optimize_for": "energy"}
)
```
## Scheduling Factors
The scheduler considers:
| Factor | Weight | Description |
| ------------------- | ------ | --------------------------- |
| Energy availability | High | Current and predicted power |
| Latency | High | Network path to user |
| Queue depth | Medium | Current load on node |
| Thermal headroom | Medium | Temperature margin |
| Eclipse status | Medium | Upcoming power constraints |
| Ground contact | Low | Communication availability |
## Node Types
| Type | Location | Characteristics |
| ------- | ------------------ | ------------------------------------------- |
| `earth` | Terrestrial DC | Unlimited power, stable network |
| `leo` | Low Earth Orbit | Variable power, intermittent ground contact |
| `meo` | Medium Earth Orbit | Stable power, higher latency |
| `geo` | Geostationary | Continuous visibility, 240ms+ latency |
## Next Steps
Learn about energy-aware inference
Learn about fault tolerance
# Node.js SDK
Source: https://docs.rotastellar.com/sdks/node
Official Node.js/TypeScript SDK for the RotaStellar API
# Node.js SDK
The official Node.js SDK for RotaStellar with full TypeScript support, providing access to Planning, Intelligence, and Runtime APIs.
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
## Installation
```bash theme={null}
npm install @rotastellar/sdk
```
Or with other package managers:
```bash theme={null}
# Yarn
yarn add @rotastellar/sdk
# pnpm
pnpm add @rotastellar/sdk
# Bun
bun add @rotastellar/sdk
```
### Requirements
* Node.js 18+ or Bun
* TypeScript 4.7+ (optional, but recommended)
## Quick Start
```typescript theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
// Initialize client
const client = new RotaStellarClient({ apiKey: 'rs_your_api_key' });
// Or use environment variable
// export ROTASTELLAR_API_KEY=rs_your_api_key
const client = new RotaStellarClient();
// Track a satellite
const iss = await client.getSatellite('25544');
console.log(`ISS: ${iss.position?.latitude}, ${iss.position?.longitude}`);
```
## Client Configuration
```typescript theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({
apiKey: 'rs_...',
baseUrl: 'https://api.rotastellar.com/v1', // Default
timeout: 30000, // Request timeout in ms
maxRetries: 3, // Retry failed requests
debug: false // Enable debug logging
});
```
## Intelligence API
### Get Satellite
```typescript theme={null}
// Get satellite by NORAD ID
const sat = await client.getSatellite('25544'); // ISS
console.log(`Name: ${sat.name}`);
console.log(`Position: ${sat.position?.latitude}, ${sat.position?.longitude}`);
console.log(`Altitude: ${sat.position?.altitudeKm} km`);
// Get position only
const pos = await client.getSatellitePosition('25544');
console.log(`Position: ${pos.latitude}, ${pos.longitude} at ${pos.altitudeKm} km`);
```
### List Satellites
```typescript theme={null}
// List satellites with filters
const satellites = await client.listSatellites({
constellation: 'Starlink',
limit: 100
});
for (const sat of satellites) {
console.log(`${sat.name}: ${sat.noradId}`);
}
// Filter by operator
const spacexSats = await client.listSatellites({
operator: 'SpaceX',
limit: 50
});
```
### Conjunction Analysis
```typescript theme={null}
import { TimeRange } from '@rotastellar/sdk';
// Get conjunction risks for a satellite
const conjunctions = await client.listConjunctions({
satelliteId: '25544',
thresholdKm: 5.0,
limit: 10
});
for (const conj of conjunctions) {
console.log(`TCA: ${conj.tca}`);
console.log(`Miss distance: ${conj.miss_distance_km.toFixed(3)} km`);
console.log(`Probability: ${conj.collision_probability.toExponential(2)}`);
}
```
### Pattern Detection
```typescript theme={null}
// Detect maneuvers and anomalies
const patterns = await client.listPatterns({
satelliteId: '44832', // COSMOS-2542
lookbackDays: 30
});
for (const pattern of patterns) {
console.log(`${pattern.type}: ${pattern.description}`);
console.log(`Confidence: ${(pattern.confidence * 100).toFixed(1)}%`);
}
```
### Trajectory Prediction
```typescript theme={null}
// Get predicted trajectory
const trajectory = await client.getTrajectory({
satelliteId: '25544',
start: new Date(),
end: new Date(Date.now() + 2 * 60 * 60 * 1000), // +2 hours
intervalSec: 60
});
for (const point of trajectory) {
console.log(`${point.timestamp}: ${point.latitude.toFixed(2)}, ${point.longitude.toFixed(2)}`);
}
```
## Planning API
### Feasibility Analysis
```typescript theme={null}
// Analyze if orbital compute is viable for your workload
const result = await client.analyzeFeasibility({
workloadType: 'inference',
computeTflops: 10,
dataGb: 1.5,
latencyRequirementMs: 100,
orbitAltitudeKm: 550
});
console.log(`Feasible: ${result.feasible}`);
console.log(`Recommendation: ${result.recommendation}`);
```
### Thermal Simulation
```typescript theme={null}
// Model heat rejection in orbit
const thermal = await client.simulateThermal({
powerWatts: 500,
orbitAltitudeKm: 550,
radiatorAreaM2: 2.0,
durationHours: 24
});
console.log(`Max temp: ${thermal.max_temperature_c}°C`);
console.log(`Min temp: ${thermal.min_temperature_c}°C`);
```
### Latency Simulation
```typescript theme={null}
import { Position } from '@rotastellar/sdk';
// Model end-to-end latency
const source = new Position(37.7749, -122.4194); // San Francisco
const dest = new Position(51.5074, -0.1278); // London
const latency = await client.simulateLatency({
source,
destination: dest,
orbitAltitudeKm: 550,
relayCount: 2
});
console.log(`Total latency: ${latency.total_latency_ms?.toFixed(1)} ms`);
```
## Runtime API (Coming Q2 2026)
```typescript theme={null}
// Submit inference job to orbital compute
const job = await client.submitJob({
model: 'llama-70b',
prompt: '...',
constraints: {
latencySlams: 200,
energyBudgetWh: 0.5
}
});
// Get result
const result = await client.getJobResult(job.id, { timeout: 30000 });
console.log(result.text);
```
## Pagination
Handle large result sets with the `PaginatedResponse` class:
```typescript theme={null}
import { PaginatedResponse } from '@rotastellar/sdk';
// Manual pagination
let page = await client.listSatellites({
constellation: 'Starlink',
limit: 100
});
console.log(`Page has ${page.items.length} items, hasMore=${page.hasMore}`);
for (const sat of page.items) {
console.log(sat.name);
}
if (page.hasMore) {
page = await page.nextPage();
}
// Automatic pagination with async iteration
for await (const sat of client.listSatellites({ constellation: 'Starlink' })) {
console.log(sat.name);
}
```
### PaginatedResponse Properties
| Property | Type | Description |
| --------- | --------------------- | -------------------------- |
| `items` | `T[]` | Current page of items |
| `hasMore` | `boolean` | Whether more pages exist |
| `total` | `number \| undefined` | Total count (if available) |
| `limit` | `number` | Page size |
| `offset` | `number` | Current offset |
## TypeScript Support
Full TypeScript definitions are included:
```typescript theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
import type {
Satellite,
Position,
Orbit,
Conjunction,
Pattern
} from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
const sat: Satellite = await client.getSatellite('25544');
const pos: Position = sat.position!;
const orbit: Orbit = sat.orbit!;
// Full autocomplete and type checking
console.log(pos.latitude); // number
console.log(pos.longitude); // number
console.log(pos.altitudeKm); // number
console.log(orbit.periodMin); // number
```
## Error Handling
```typescript theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
import {
AuthenticationError,
RateLimitError,
NotFoundError,
ValidationError,
APIError
} from '@rotastellar/sdk';
const client = new RotaStellarClient({ apiKey: 'rs_...' });
try {
const sat = await client.getSatellite('INVALID-ID');
} catch (error) {
if (error instanceof NotFoundError) {
console.log('Satellite not found');
} else if (error instanceof RateLimitError) {
console.log(`Rate limited. Retry after ${error.retryAfter}s`);
} else if (error instanceof AuthenticationError) {
console.log('Invalid API key');
} else if (error instanceof ValidationError) {
console.log(`Invalid request: ${error.message}`);
} else if (error instanceof APIError) {
console.log(`API error: ${error.message}`);
}
}
```
## Request Cancellation
Cancel long-running requests:
```typescript theme={null}
const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
const result = await client.analyzeFeasibility({
workloadType: 'inference',
computeTflops: 100
}, { signal: controller.signal });
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request cancelled');
}
}
```
## Distributed Compute API (Coming Q1 2026)
The `@rotastellar/distributed` package enables Earth-space AI coordination:
```bash theme={null}
npm install @rotastellar/distributed
```
### Federated Learning
```typescript theme={null}
import { FederatedClient, CompressionConfig, CompressionMethod } from '@rotastellar/distributed';
// Configure gradient compression (100x reduction)
const compression: CompressionConfig = {
method: CompressionMethod.TOP_K_QUANTIZED,
kRatio: 0.01,
quantizationBits: 8,
errorFeedback: true
};
// Initialize client on orbital node
const client = new FederatedClient({
nodeId: 'orbital-3',
nodeType: 'orbital',
compression
});
// Compute and compress gradients for transmission
const gradients = client.computeGradients(modelParams, localData);
const compressed = client.compress(gradients);
```
See the [Distributed Compute documentation](/distributed/overview) for full API reference.
## Logging
Enable debug logging:
```typescript theme={null}
import { RotaStellarClient } from '@rotastellar/sdk';
const client = new RotaStellarClient({
apiKey: 'rs_...',
debug: true // Logs all requests/responses
});
// Or use custom logger
const client = new RotaStellarClient({
apiKey: 'rs_...',
logger: {
debug: console.debug,
info: console.info,
warn: console.warn,
error: console.error
}
});
```
## Source Code
View source, report issues, and contribute.
Package page and version history.
# Python SDK
Source: https://docs.rotastellar.com/sdks/python
Official Python SDK for the RotaStellar API
# Python SDK
The official Python SDK for RotaStellar, providing full access to Planning, Intelligence, and Runtime APIs.
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
## Installation
```bash theme={null}
pip install rotastellar
```
### Requirements
* Python 3.9+
* httpx (for HTTP requests)
### Optional Dependencies
```bash theme={null}
# For async support
pip install rotastellar[async]
# For data analysis utilities
pip install rotastellar[pandas]
# All optional dependencies
pip install rotastellar[all]
```
## Quick Start
```python theme={null}
from rotastellar import RotaStellarClient
# Initialize client
client = RotaStellarClient(api_key="rs_your_api_key")
# Or use environment variable
# export ROTASTELLAR_API_KEY=rs_your_api_key
client = RotaStellarClient()
# Track a satellite
iss = client.get_satellite("25544")
print(f"ISS: {iss.position.latitude}, {iss.position.longitude}")
```
## Client Configuration
```python theme={null}
from rotastellar import RotaStellarClient
client = RotaStellarClient(
api_key="rs_...",
base_url="https://api.rotastellar.com/v1", # Default
timeout=30.0, # Request timeout in seconds
max_retries=3, # Retry failed requests
debug=False # Enable debug logging
)
```
## Intelligence API
### Get Satellite
```python theme={null}
# Get satellite by NORAD ID
sat = client.get_satellite("25544") # ISS
print(f"Name: {sat.name}")
print(f"Position: {sat.position.latitude}, {sat.position.longitude}")
print(f"Altitude: {sat.position.altitude_km} km")
# Get position only
pos = client.get_satellite_position("25544")
print(f"Position: {pos.latitude}, {pos.longitude} at {pos.altitude_km} km")
```
### List Satellites
```python theme={null}
# List satellites with filters
satellites = client.list_satellites(
constellation="Starlink",
limit=100
)
for sat in satellites:
print(f"{sat.name}: {sat.norad_id}")
# Filter by operator
spacex_sats = client.list_satellites(operator="SpaceX", limit=50)
```
### Conjunction Analysis
```python theme={null}
from rotastellar.types import TimeRange
# Get conjunction risks for a satellite
conjunctions = client.list_conjunctions(
satellite_id="25544",
threshold_km=5.0,
limit=10
)
for conj in conjunctions:
print(f"TCA: {conj['tca']}")
print(f"Miss distance: {conj['miss_distance_km']:.3f} km")
print(f"Probability: {conj['collision_probability']:.2e}")
```
### Pattern Detection
```python theme={null}
# Detect maneuvers and anomalies
patterns = client.list_patterns(
satellite_id="44832", # COSMOS-2542
lookback_days=30
)
for pattern in patterns:
print(f"{pattern['type']}: {pattern['description']}")
print(f"Confidence: {pattern['confidence']:.1%}")
```
### Trajectory Prediction
```python theme={null}
from datetime import datetime, timedelta
# Get predicted trajectory (start/end are ISO 8601 strings)
trajectory = client.get_trajectory(
satellite_id="25544",
start=datetime.utcnow().isoformat(),
end=(datetime.utcnow() + timedelta(hours=2)).isoformat(),
interval_sec=60
)
for point in trajectory:
print(f"{point['timestamp']}: {point['lat']:.2f}, {point['lon']:.2f}")
```
## Planning API
### Feasibility Analysis
```python theme={null}
# Analyze if orbital compute is viable for your workload
result = client.analyze_feasibility(
workload_type="inference",
compute_tflops=10,
data_gb=1.5,
latency_requirement_ms=100,
orbit_altitude_km=550
)
print(f"Feasible: {result['feasible']}")
print(f"Recommendation: {result['recommendation']}")
```
### Thermal Simulation
```python theme={null}
# Model heat rejection in orbit
thermal = client.simulate_thermal(
power_watts=500,
orbit_altitude_km=550,
radiator_area_m2=2.0,
duration_hours=24
)
print(f"Max temp: {thermal['max_temperature_c']}°C")
print(f"Min temp: {thermal['min_temperature_c']}°C")
```
### Latency Simulation
```python theme={null}
from rotastellar.types import Position
# Model end-to-end latency
source = Position(latitude=37.7749, longitude=-122.4194) # San Francisco
dest = Position(latitude=51.5074, longitude=-0.1278) # London
latency = client.simulate_latency(
source=source,
destination=dest,
orbit_altitude_km=550,
relay_count=2
)
print(f"Total latency: {latency['total_latency_ms']:.1f} ms")
```
## Runtime API (Coming Q2 2026)
```python theme={null}
# Submit inference job to orbital compute
job = client.submit_job(
model="llama-70b",
prompt="...",
constraints={
"latency_sla_ms": 200,
"energy_budget_wh": 0.5
}
)
# Get result
result = client.get_job_result(job['id'], timeout=30)
print(result['text'])
```
## Async Client
For high-performance async applications:
```python theme={null}
import asyncio
from rotastellar import AsyncRotaStellarClient
async def main():
client = AsyncRotaStellarClient(api_key="rs_...")
# Async satellite tracking
iss = await client.get_satellite("25544")
print(f"ISS: {iss.position.latitude}, {iss.position.longitude}")
# Concurrent requests
satellites = ["25544", "43013", "20580"]
tasks = [client.get_satellite(s) for s in satellites]
results = await asyncio.gather(*tasks)
for sat in results:
print(f"{sat.name}: {sat.position.altitude_km} km")
asyncio.run(main())
```
## Pagination
Handle large result sets with the `PaginatedResponse` class:
```python theme={null}
from rotastellar import PaginatedResponse
# Manual pagination
page = client.list_satellites(constellation="Starlink", limit=100)
print(f"Page has {len(page.items)} items, has_more={page.has_more}")
for sat in page.items:
print(sat.name)
if page.has_more:
next_page = page.next_page()
# Automatic iteration (auto-fetches next pages)
for sat in client.list_satellites(constellation="Starlink"):
print(sat.name)
# Async auto-pagination
async for sat in async_client.list_satellites(constellation="Starlink"):
print(sat.name)
```
### PaginatedResponse Properties
| Property | Type | Description |
| ---------- | ------------- | -------------------------- |
| `items` | `List[T]` | Current page of items |
| `has_more` | `bool` | Whether more pages exist |
| `total` | `int \| None` | Total count (if available) |
| `limit` | `int` | Page size |
| `offset` | `int` | Current offset |
## Distributed Compute API (Coming Q1 2026)
The `rotastellar-distributed` package enables Earth-space AI coordination:
```bash theme={null}
pip install rotastellar-distributed
```
### Federated Learning
```python theme={null}
from rotastellar_distributed import FederatedClient, CompressionConfig, CompressionMethod
# Configure gradient compression (100x reduction)
compression = CompressionConfig(
method=CompressionMethod.TOP_K_QUANTIZED,
k_ratio=0.01,
quantization_bits=8,
error_feedback=True
)
# Initialize client on orbital node
client = FederatedClient(
node_id="orbital-3",
compression=compression,
node_type="orbital"
)
# Compute and compress gradients for transmission
gradients = client.compute_gradients(model_params, local_data)
compressed = client.compress(gradients)
```
See the [Distributed Compute documentation](/distributed/overview) for full API reference.
## Error Handling
```python theme={null}
from rotastellar import RotaStellarClient
from rotastellar.errors import (
AuthenticationError,
RateLimitError,
NotFoundError,
ValidationError,
APIError
)
client = RotaStellarClient(api_key="rs_...")
try:
sat = client.get_satellite("INVALID-ID")
except NotFoundError:
print("Satellite not found")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
except AuthenticationError:
print("Invalid API key")
except ValidationError as e:
print(f"Invalid request: {e.message}")
except APIError as e:
print(f"API error: {e.message}")
```
## Type Hints
The SDK includes full type annotations for IDE support:
```python theme={null}
from rotastellar import RotaStellarClient
from rotastellar.types import Position, Orbit, Satellite
client = RotaStellarClient(api_key="rs_...")
sat: Satellite = client.get_satellite("25544")
pos: Position = sat.position
orbit: Orbit = sat.orbit
# IDE will provide autocomplete for all fields
print(pos.latitude) # float
print(pos.longitude) # float
print(pos.altitude_km) # float
print(orbit.orbital_period_minutes) # float
```
## Logging
Enable debug logging:
```python theme={null}
import logging
logging.basicConfig(level=logging.DEBUG)
# Or configure specific logger
logger = logging.getLogger("rotastellar")
logger.setLevel(logging.DEBUG)
```
## Source Code
View source, report issues, and contribute.
Package page and version history.
# Rust SDK
Source: https://docs.rotastellar.com/sdks/rust
Official Rust SDK for the RotaStellar API
# Rust SDK
The official Rust SDK for RotaStellar, providing type-safe primitives for orbital compute and space intelligence applications.
**Status:** Early Access — [Request API key](https://rotastellar.com/developers)
The Rust SDK currently provides **types only**. The HTTP client is coming in a future release. For full API access, use the [Python SDK](/sdks/python) or [Node.js SDK](/sdks/node).
## Installation
Add to your `Cargo.toml`:
```toml theme={null}
[dependencies]
rotastellar = "0.1"
```
Or use cargo:
```bash theme={null}
cargo add rotastellar
```
## Quick Start
```rust theme={null}
use rotastellar::types::{Position, Orbit, Satellite};
fn main() -> Result<(), Box> {
// Create a position (e.g., Kennedy Space Center)
let pos = Position::new(28.5729, -80.6490, 0.0)?;
println!("Position: {}, {}", pos.latitude, pos.longitude);
// Create an ISS-like orbit
let orbit = Orbit::new(6778.0, 0.0001, 51.6, 100.0, 90.0, 0.0)?;
println!("Orbital period: {:.1} minutes", orbit.orbital_period_minutes());
println!("Apogee: {:.1} km, Perigee: {:.1} km", orbit.apogee_km(), orbit.perigee_km());
Ok(())
}
```
## Available Types
### Position
Geographic position with altitude:
```rust theme={null}
use rotastellar::types::Position;
// Create with validation
let pos = Position::new(28.5729, -80.6490, 408.0)?;
// Access fields
println!("Latitude: {}", pos.latitude);
println!("Longitude: {}", pos.longitude);
println!("Altitude: {} km", pos.altitude_km);
```
| Field | Type | Description |
| ------------- | ----- | ---------------------------------- |
| `latitude` | `f64` | Latitude in degrees (-90 to 90) |
| `longitude` | `f64` | Longitude in degrees (-180 to 180) |
| `altitude_km` | `f64` | Altitude above sea level in km |
### Orbit
Keplerian orbital elements:
```rust theme={null}
use rotastellar::types::Orbit;
// Create an orbit (ISS-like)
let orbit = Orbit::new(
6778.0, // semi_major_axis_km
0.0001, // eccentricity
51.6, // inclination_deg
100.0, // raan_deg
90.0, // arg_periapsis_deg
0.0 // true_anomaly_deg
)?;
// Computed properties
println!("Period: {:.1} minutes", orbit.orbital_period_minutes());
println!("Apogee: {:.1} km", orbit.apogee_km());
println!("Perigee: {:.1} km", orbit.perigee_km());
println!("Mean motion: {:.2} rev/day", orbit.mean_motion());
```
| Field | Type | Description |
| -------------------- | ----- | --------------------------------- |
| `semi_major_axis_km` | `f64` | Semi-major axis in km |
| `eccentricity` | `f64` | Orbital eccentricity (0-1) |
| `inclination_deg` | `f64` | Inclination in degrees (0-180) |
| `raan_deg` | `f64` | Right ascension of ascending node |
| `arg_periapsis_deg` | `f64` | Argument of periapsis |
| `true_anomaly_deg` | `f64` | True anomaly |
### Satellite
Satellite information with optional orbit and position:
```rust theme={null}
use rotastellar::types::{Satellite, Position, Orbit};
let sat = Satellite::new("sat_123", 25544, "ISS")
.with_operator("NASA/Roscosmos")
.with_constellation("Space Station")
.with_position(Position::new(28.5729, -80.6490, 408.0)?)
.with_orbit(orbit);
println!("Name: {}", sat.name);
println!("NORAD ID: {}", sat.norad_id);
if let Some(pos) = &sat.position {
println!("At: {}, {}", pos.latitude, pos.longitude);
}
```
### TimeRange
Time range for queries:
```rust theme={null}
use rotastellar::types::TimeRange;
// Create a 24-hour time range starting now
let range = TimeRange::next_hours(24.0);
println!("Start: {}", range.start);
println!("End: {}", range.end);
```
## Configuration
The SDK provides configuration utilities for when the HTTP client is available:
```rust theme={null}
use rotastellar::{Config, ConfigBuilder};
let config = Config::default();
println!("Base URL: {}", config.base_url);
println!("Timeout: {:?}", config.timeout);
```
## Authentication Utilities
Validate and mask API keys:
```rust theme={null}
use rotastellar::{validate_api_key, mask_api_key, Environment};
// Validate an API key
match validate_api_key(Some("rs_live_abc123")) {
Ok(env) => println!("Valid key for {:?} environment", env),
Err(e) => println!("Invalid: {}", e),
}
// Mask a key for logging
let masked = mask_api_key("rs_live_abc123def456");
println!("Masked: {}", masked); // rs_live_abc...
```
## Error Handling
```rust theme={null}
use rotastellar::error::{RotaStellarError, ValidationError};
use rotastellar::types::Position;
fn create_position() -> Result {
// This will fail validation (latitude > 90)
let pos = Position::new(91.0, 0.0, 0.0)?;
Ok(pos)
}
match create_position() {
Ok(pos) => println!("Created: {:?}", pos),
Err(RotaStellarError::Validation(e)) => {
println!("Validation error on '{}': {}", e.field, e.message);
}
Err(e) => println!("Error: {}", e),
}
```
### Error Types
| Error | Description |
| ---------------------------------- | --------------------------- |
| `RotaStellarError::Validation` | Input validation failed |
| `RotaStellarError::Authentication` | API key issues |
| `RotaStellarError::Api` | API returned an error |
| `RotaStellarError::Network` | Network connectivity issues |
## Constants
```rust theme={null}
use rotastellar::{EARTH_RADIUS_KM, EARTH_MU};
println!("Earth radius: {} km", EARTH_RADIUS_KM); // 6378.137
println!("Earth GM: {} km³/s²", EARTH_MU); // 398600.4418
```
## Serde Support
All types implement `Serialize` and `Deserialize`:
```rust theme={null}
use rotastellar::types::Position;
use serde_json;
let pos = Position::new(28.5729, -80.6490, 408.0)?;
// Serialize
let json = serde_json::to_string(&pos)?;
println!("{}", json);
// Deserialize
let parsed: Position = serde_json::from_str(&json)?;
```
## Coming Soon
The following features are planned for future releases:
* **HTTP Client** — Full API client with async support
* **Blocking Client** — Synchronous API for non-async contexts
* **Streaming** — Real-time satellite position updates
* **TLE Parsing** — Two-line element set parsing and propagation
## Source Code
View source, report issues, and contribute.
Package page and version history.
# Orbital Sim
Source: https://docs.rotastellar.com/sim/overview
Stateless orbital computation for satellite digital twins
The **Orbital Sim** service provides real-time satellite position computation, trajectory propagation, eclipse detection, and ground station pass prediction. It powers the RotaStellar agent constellation and planned asset live tracking.
## Base URL
```
https://sim.rotastellar.com
```
## Capabilities
| Capability | Endpoint | Description |
| ----------------------- | --------------------------------- | ---------------------------------------------- |
| Orbital state | `POST /v1/state` | Position, velocity, eclipse at any timestamp |
| Batch state | `POST /v1/state/batch` | Up to 100 satellites in one call |
| Trajectory | `POST /v1/propagate` | Full orbit path over up to 48 hours |
| Ground passes | `POST /v1/passes` | AOS/LOS windows with elevation data |
| Orbit templates | `GET /v1/templates` | Predefined orbit profiles (LEO, SSO, MEO, GEO) |
| Constellation templates | `GET /v1/constellation-templates` | Walker Star, Polar Ring patterns |
| Ground stations | `GET /v1/ground-stations` | 12-station global network |
| Sessions | `POST /v1/sessions` | Stateful constellation simulation |
| Tick simulation | `POST /v1/sessions/:id/tick` | Advance time with subsystem updates |
| Fault injection | `POST /v1/sessions/:id/fault` | Inject hardware/environment faults |
## Quick Example
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/state \
-H "Content-Type: application/json" \
-d '{
"elements": {
"altitude_km": 550,
"inclination_deg": 53
}
}'
```
```json theme={null}
{
"lat": 42.15,
"lon": -73.82,
"altitude_km": 550.3,
"velocity_km_s": 7.59,
"in_eclipse": false,
"orbit_fraction": 0.234,
"timestamp": "2026-03-08T12:00:00Z"
}
```
## Orbital Elements
All computation endpoints accept an `elements` object. You must provide either `mean_motion` (revolutions/day) or `altitude_km`.
| Field | Type | Required | Default | Description |
| ------------------ | ------ | -------- | ------- | --------------------------------------------- |
| `altitude_km` | number | \* | — | Orbit altitude in km |
| `mean_motion` | number | \* | — | Revolutions per day (alternative to altitude) |
| `inclination_deg` | number | yes | — | Orbital inclination in degrees |
| `eccentricity` | number | no | 0.0001 | Orbit eccentricity |
| `raan_deg` | number | no | 0 | Right ascension of ascending node |
| `arg_perigee_deg` | number | no | 90 | Argument of perigee |
| `mean_anomaly_deg` | number | no | 0 | Mean anomaly at epoch |
| `epoch` | string | no | now | ISO 8601 timestamp of elements |
| `bstar` | number | no | 0.00003 | Atmospheric drag term |
Either `altitude_km` or `mean_motion` is required, but not both.
## Access
The Sim service uses CORS-based access control. Allowed origins include `rotastellar.com`, `console.rotastellar.com`, `runtime.rotastellar.com`, and `localhost:3000`. No API key is required.
## Simulation Sessions (v1.1.0)
CAE v1.1.0 adds **stateful simulation sessions** for constellation-level testing with subsystem tracking, ISL link quality modeling, and fault injection. See [Simulation Sessions](/sim/sessions) for full documentation.
## API Reference
See the full API reference for each endpoint:
* [Service Index](/api-reference/sim/service-index)
* [Get State](/api-reference/sim/get-state)
* [Batch State](/api-reference/sim/batch-state)
* [Propagate](/api-reference/sim/propagate)
* [Ground Passes](/api-reference/sim/passes)
* [Templates](/api-reference/sim/templates)
* [Create Session](/api-reference/sim/create-session)
* [Get Session State](/api-reference/sim/get-session)
* [Tick Session](/api-reference/sim/tick-session)
* [Inject Fault](/api-reference/sim/inject-fault)
# Simulation Sessions
Source: https://docs.rotastellar.com/sim/sessions
Stateful satellite constellation simulation with subsystem tracking and fault injection
# Simulation Sessions
**Version:** 1.1.0
Simulation Sessions extend the Orbital Sim with **stateful, multi-satellite simulation**. Unlike the stateless propagation endpoints, sessions persist constellation state in KV and let you advance time step-by-step, track subsystem health, model inter-satellite link quality, and inject faults.
Sessions are designed for integration testing of constellation workloads. They power the agent executor's simulated satellite mode and the CAE constellation planner's test harness.
## Base URL
```
https://sim.rotastellar.com
```
## Concepts
### Session Lifecycle
A session represents a constellation of up to 50 satellites. On creation, each satellite is initialized with orbital elements and default subsystem state. You advance the simulation by calling the **tick** endpoint, which propagates orbits, updates subsystems, checks for natural faults, and recalculates ISL links.
Sessions are stored in the `SIM_STATE` KV binding with a **1-hour TTL**. If a session is not ticked within one hour, it is automatically evicted.
### Subsystem State
Every satellite in a session tracks five subsystems:
| Subsystem | Unit | Initial Value | Model |
| ------------- | ---- | -------------------------- | ----------------------------------------------------------------------- |
| `battery` | % | 100 | Charge in sunlight, discharge in eclipse. Rate depends on compute load. |
| `solar_power` | W | 100 (sunlit) / 0 (eclipse) | Binary based on eclipse state. |
| `temperature` | C | 20 | Rises under compute load, radiative cooling in eclipse. |
| `memory` | MB | 0 (of 512) | Accumulates with data generation, freed on downlink. |
| `cpu` | % | 0 | Set by active workload. Idle satellites report 0%. |
### ISL Link Quality
Inter-satellite links (ISLs) are modeled between all satellite pairs within range:
| Parameter | Value |
| ------------------- | -------------------------------------------------- |
| Max range | 5,000 km |
| Distance factor | `1 - (distance / 5000) * 0.6` |
| Eclipse penalty | `0.9` (applied when either endpoint is in eclipse) |
| Effective bandwidth | `100 Mbps * quality` |
A link quality of 0 means the satellites are out of range. Quality degrades linearly with distance and is further penalized during eclipse due to thermal effects on transponders.
### Natural Fault Detection
Each tick evaluates three natural fault conditions:
| Fault | Condition | Probability |
| ------------------- | ---------------------------------------------------------- | --------------------- |
| SAA radiation upset | Satellite passes through the South Atlantic Anomaly region | 2% per tick in region |
| Thermal exceedance | Temperature exceeds 50C | Deterministic |
| Power critical | Battery drops below 5% | Deterministic |
When a natural fault triggers, it is included in the tick response as a `faults` array entry.
## Endpoints
### Create Session
```
POST /v1/sessions
```
Creates a new simulation session with the specified satellites.
**Request body:**
| Field | Type | Required | Description |
| ----------------------- | ------ | -------- | ---------------------------------------------- |
| `satellites` | array | yes | Array of satellite definitions (max 50) |
| `satellites[].id` | string | yes | Unique satellite identifier within the session |
| `satellites[].elements` | object | yes | Orbital elements (same schema as `/v1/state`) |
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/sessions \
-H "Content-Type: application/json" \
-d '{
"satellites": [
{
"id": "sat-1",
"elements": {
"altitude_km": 550,
"inclination_deg": 53,
"raan_deg": 0,
"mean_anomaly_deg": 0
}
},
{
"id": "sat-2",
"elements": {
"altitude_km": 550,
"inclination_deg": 53,
"raan_deg": 0,
"mean_anomaly_deg": 120
}
},
{
"id": "sat-3",
"elements": {
"altitude_km": 550,
"inclination_deg": 53,
"raan_deg": 0,
"mean_anomaly_deg": 240
}
}
]
}'
```
**Response (201):**
```json theme={null}
{
"session_id": "ses-a1b2c3d4",
"satellite_count": 3,
"created_at": "2026-03-10T12:00:00Z",
"ttl_seconds": 3600
}
```
Sessions are limited to 50 satellites. Requests exceeding this limit return a 400 error.
### Get Session State
```
GET /v1/sessions/:id
```
Returns the full constellation state including all satellite positions, subsystems, and active ISL links.
**Response (200):**
```json theme={null}
{
"session_id": "ses-a1b2c3d4",
"tick": 5,
"sim_time": "2026-03-10T12:25:00Z",
"satellites": [
{
"id": "sat-1",
"position": {
"lat": 42.15,
"lon": -73.82,
"altitude_km": 550.3
},
"in_eclipse": false,
"subsystems": {
"battery": 94.2,
"solar_power": 100,
"temperature": 22.5,
"memory": 45.0,
"cpu": 30
}
}
],
"isl_links": [
{
"from": "sat-1",
"to": "sat-2",
"distance_km": 1823.4,
"quality": 0.78,
"bandwidth_mbps": 78.0,
"eclipse_penalty_applied": false
}
]
}
```
### Tick (Advance Simulation)
```
POST /v1/sessions/:id/tick
```
Advances the simulation by one time step. Each tick performs the following in order:
1. Propagate all satellite orbits forward
2. Detect eclipse transitions (sunlit/shadow)
3. Update subsystem state (battery, thermal, solar)
4. Check natural fault conditions
5. Recalculate all ISL links
**Request body:**
| Field | Type | Required | Default | Description |
| ------------ | ------ | -------- | ------- | ----------------------------- |
| `duration_s` | number | no | 300 | Time step duration in seconds |
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/sessions/ses-a1b2c3d4/tick \
-H "Content-Type: application/json" \
-d '{
"duration_s": 300
}'
```
**Response (200):**
```json theme={null}
{
"session_id": "ses-a1b2c3d4",
"tick": 6,
"sim_time": "2026-03-10T12:30:00Z",
"duration_s": 300,
"satellites": [ ... ],
"isl_links": [ ... ],
"eclipse_transitions": [
{
"satellite_id": "sat-2",
"transition": "entered_eclipse",
"sim_time": "2026-03-10T12:27:14Z"
}
],
"faults": []
}
```
The `eclipse_transitions` array only contains satellites whose eclipse state changed during this tick. An empty array means no transitions occurred.
### Inject Fault
```
POST /v1/sessions/:id/fault
```
Injects a fault into a specific satellite. The fault takes effect immediately and is reflected in the session state.
**Request body:**
| Field | Type | Required | Description |
| -------------- | ------ | -------- | ---------------------------- |
| `satellite_id` | string | yes | Target satellite |
| `fault_type` | string | yes | One of the fault types below |
**Fault types and effects:**
| Fault Type | Immediate Effect |
| -------------------- | --------------------------------------------------- |
| `power_loss` | Battery set to 0%, solar power disabled |
| `thermal_exceedance` | Temperature set to 85C |
| `radiation_upset` | CPU reset to 0%, memory corrupted (set to 0) |
| `comms_failure` | All ISL links to/from this satellite removed |
| `isl_degradation` | All ISL links to/from this satellite quality halved |
```bash theme={null}
curl -X POST https://sim.rotastellar.com/v1/sessions/ses-a1b2c3d4/fault \
-H "Content-Type: application/json" \
-d '{
"satellite_id": "sat-2",
"fault_type": "power_loss"
}'
```
**Response (200):**
```json theme={null}
{
"session_id": "ses-a1b2c3d4",
"satellite_id": "sat-2",
"fault_type": "power_loss",
"applied_at_tick": 6,
"effects": {
"battery": 0,
"solar_power": 0
}
}
```
Fault injection is irreversible within a session. To restore a satellite, create a new session.
## Storage
Sessions are stored in the `SIM_STATE` KV binding. Each session is a single JSON document keyed by `session:{session_id}`. The 1-hour TTL ensures stale sessions are automatically cleaned up.
| KV Binding | Key Pattern | TTL |
| ----------- | ---------------------- | -------------- |
| `SIM_STATE` | `session:{session_id}` | 3600s (1 hour) |
## Related
Stateless propagation, eclipse detection, and pass prediction
Full API reference for all Sim endpoints