rob thijssen 4a51a54554
Some checks failed
build-prerelease / Build cortex binary (push) Blocked by required conditions
CI / Test (push) Waiting to run
build-prerelease / Resolve version stamps (push) Successful in 35s
CI / Format (push) Successful in 42s
CI / Clippy (push) Successful in 2m39s
build-prerelease / Build neuron-ada (push) Has been cancelled
build-prerelease / Package cortex RPM (push) Has been cancelled
build-prerelease / Package helexa-neuron-ada RPM (push) Has been cancelled
build-prerelease / Package helexa-neuron-ampere RPM (push) Has been cancelled
build-prerelease / Package helexa-neuron-blackwell RPM (push) Has been cancelled
build-prerelease / Publish to rpm.lair.cafe (unstable) (push) Has been cancelled
CI / Build cortex SRPM (push) Has been cancelled
CI / Build neuron SRPM (push) Has been cancelled
CI / Publish cortex to COPR (push) Has been cancelled
CI / Publish neuron to COPR (push) Has been cancelled
CI / Bump version in source (push) Has been cancelled
build-prerelease / Build neuron-ampere (push) Has been cancelled
build-prerelease / Build neuron-blackwell (push) Has been cancelled
fix(helexa-acp): describe Stage 3 tools in the default system prompt
The Stage 2 prompt told the model it had no tools, which models
trained for caution then dutifully repeat back ("Stage 2 build: no
tools available — I can't read files…"). Stage 3 ships tools in the
CompletionRequest.tools array, but the system message was still
overriding that. Update the default prompt to list the five tools
and instruct the model to use them rather than asking the user to
paste contents.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 10:33:17 +03:00

cortex

A Rust reverse-proxy and fleet management layer for multi-node GPU inference clusters. Cortex sits in front of one or more neuron daemons (each running candle-based inference on a local GPU host) and presents a unified OpenAI + Anthropic compatible API surface.

Problem

Running local LLMs across multiple GPU nodes (different VRAM tiers, different model affinities) requires a unified API surface that:

  • Presents a single /v1/models catalogue merging every model that can be served by any neuron in the fleet.
  • Routes requests to the correct node based on where a model is loaded (or can be loaded), handling cold-load and eviction transparently.
  • Manages model lifecycle — load on demand, unload cold models, pin critical ones — by calling each neuron's /models/{load,unload} API.
  • Translates between OpenAI and Anthropic request/response envelopes so every client speaks whichever dialect it prefers.
  • Captures per-request metrics (tokens, tok/s, TTFT, latency) and exposes them as Prometheus counters/histograms.

Architecture

┌──────────────┐  ┌──────────┐  ┌────────────┐  ┌────────────┐
│ Claude Code  │  │ Zed/IDE  │  │ Tidal / mm │  │ curl / etc │
└──────┬───────┘  └─────┬────┘  └──────┬─────┘  └──────┬─────┘
       │                │              │               │
       └────────────────┴──────┬───────┴───────────────┘
                               │
                    ┌──────────▼──────────┐
                    │      cortex         │
                    │  (cortex-gateway)   │
                    │                     │
                    │  Router · Metrics   │
                    │  Evictor · Translate│
                    └──┬──────┬────────┬──┘
                       │      │        │
            ┌──────────▼┐  ┌──▼─────┐  ┌▼──────────┐
            │  neuron   │  │ neuron │  │  neuron   │
            │  :13131   │  │ :13131 │  │  :13131   │
            │  candle   │  │ candle │  │  candle   │
            └───────────┘  └────────┘  └───────────┘
                  private network (.internal)

Crates

Crate Purpose
cortex-core Shared types: config, node/model state, metrics, OpenAI/Anthropic envelopes, harness trait, discovery types
cortex-gateway Axum HTTP server: proxy, router, evictor, poller, metrics exporter
neuron Per-node daemon: GPU discovery, in-process candle inference, model lifecycle API
cortex-cli CLI entrypoint (cortex serve, cortex status, etc.)

Node setup

Each GPU node runs neuron (listening on :13131). Neuron uses huggingface/candle for in-process inference — there is no external inference subprocess to manage.

Inside the daemon, every CUDA device gets one dedicated OS thread (named cuda-dev-N) that owns the device's CUDA context for the daemon's lifetime. Model loads, forward passes, KV-cache resets, NCCL collectives, VRAM queries, and unloads all route through that thread via a job channel; tensors never escape it alive. This pins context binding to a known thread, makes the CUDA Drop contract structurally safe, and isolates driver-error poisoning to one worker rather than the whole process. See CLAUDE.md for the design rationale and crates/neuron/src/harness/device_worker/ for the code.

The neuron RPM (helexa-neuron) ships a systemd unit:

dnf copr enable helexa/helexa
dnf install helexa-neuron
systemctl enable --now neuron

Gateway config

# /etc/cortex/cortex.toml
[gateway]
listen = "0.0.0.0:31313"
metrics_listen = "0.0.0.0:31314"

[eviction]
strategy = "lru"        # lru | priority
defrag_after_cycles = 50

[[neurons]]
name = "beast"
endpoint = "http://beast.internal:13131"

[[neurons]]
name = "benjy"
endpoint = "http://benjy.internal:13131"

Model placement profiles live in models.toml — see models.example.toml.

Building

cargo build --release

CI

Every push triggers format, lint, and test checks. Ensure these pass locally before pushing:

cargo fmt --check --all                    # must be clean
cargo clippy --workspace -- -D warnings   # warnings are errors
cargo test --workspace                     # all tests must pass

Tagged releases (v*) additionally build SRPMs for both cortex and helexa-neuron and publish to COPR.

Running

# start the gateway
cortex serve --config /etc/cortex/cortex.toml

# check fleet status
cortex status

# list all models across nodes
curl http://localhost:31313/v1/models

License

GPL-3.0

Description
No description provided
Readme GPL-3.0 5.2 MiB
Languages
Rust 96.9%
Cuda 1.7%
Shell 1.1%
Python 0.3%