Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,15 @@ crates/cli/
- `helix feedback` - Send feedback to the Helix team

**Runtime Targets:**
- Local Docker/Podman containers (`helix start`) — image `ghcr.io/helixdb/helixdb:v0.0.9`
- Local Docker/Podman containers (`helix start`) — image `ghcr.io/helixdb/helixdb:v0.0.10`
- Linked Helix Cloud databases for brokered `query`, `shell`, `status`, and `logs`

**Build & Deploy Flow:**

The v3 CLI is a runtime orchestrator — there is no `helix compile`/`helix check` step and no `.hx` query files.

1. Scaffold a project with `helix init` (writes `helix.toml` and a `.helix/` workspace).
2. Start a local instance with `helix start` — a Docker/Podman container running `ghcr.io/helixdb/helixdb:v0.0.9` (in-memory by default, on-disk with `--disk`). The CLI waits for `GET /healthz` before returning.
2. Start a local instance with `helix start` — a Docker/Podman container running `ghcr.io/helixdb/helixdb:v0.0.10` (in-memory by default, on-disk with `--disk`). The CLI waits for `GET /healthz` before returning.
3. Author queries with the Rust, TypeScript, Go, or Python DSL; they serialize to query JSON.
4. Send queries to a running instance via `POST /v2/query` (`helix query`); validation happens server-side.
5. For Cloud, sign in with `helix auth login`, link a project/database, and run queries through the authenticated backend broker.
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/cli/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The Helix CLI — binary `helix`, crate `helix-cli` (v3.0.1). It is a **runtime
This CLI has **no `helix compile` and no `helix check`**, and there is **no `.hx` query workflow** in it. (Older notes/memory that mention those commands describe the v2 CLI and are stale.) In v3:

- **Queries are JSON requests** sent to a *running* instance via `POST /v2/query` (`helix query`). Validation happens server-side, in the instance.
- **Local instances are Docker/Podman containers** (image `ghcr.io/helixdb/helixdb:v0.0.9`), managed by `LocalRuntime`. `helix start` starts one; in-memory by default, on-disk (SeaweedFS-backed) with `--disk`.
- **Local instances are Docker/Podman containers** (image `ghcr.io/helixdb/helixdb:v0.0.10`), managed by `LocalRuntime`. `helix start` starts one; in-memory by default, on-disk (SeaweedFS-backed) with `--disk`.
- **Cloud instances are linked resources.** The CLI authenticates only with a rotating WorkOS session and sends Cloud queries through WFE's backend broker. It does not deploy query bundles or call Cloud gateways directly.

The Rust DSL builder lives in `sdks/rust/` (a client library), not in this CLI.
Expand Down Expand Up @@ -134,7 +134,7 @@ Chef is framed as one `intro`/`outro` session. `Step` provides `println` (print
**Project config — `helix.toml`** (`HelixConfig` in `config.rs`, found via `ProjectContext::find_and_load`):

- `[project]` — `name` (required), optional `id` / `workspace_id`, `queries` (default `db/`), `container_runtime` (`docker` | `podman`, default docker).
- `[local.<name>]` — `port` (default `6969`), `image` (default `ghcr.io/helixdb/helixdb`), `tag` (default `v0.0.9`), `storage` (`memory` | `disk`, default memory).
- `[local.<name>]` — `port` (default `6969`), `image` (default `ghcr.io/helixdb/helixdb`), `tag` (default `v0.0.10`), `storage` (`memory` | `disk`, default memory).
- `[enterprise.<name>]` — typed `database = "cluster:<id>"|"tenant:<id>"`, plus optional stable `workspace_id` and `project_id` linkage. Gateway URLs, query keys, query bundles, and sync snapshots are rejected as obsolete.

`HelixConfig::validate` requires a non-empty project name, at least one instance, non-empty instance names, and a valid typed database for each Cloud instance. `default_config()` seeds a single in-memory `local.dev`.
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "helix-cli"
version = "3.4.2"
version = "3.4.3"
edition = "2024"

[dependencies]
Expand Down
4 changes: 2 additions & 2 deletions crates/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ The CLI defaults to its tested image version. `latest` is opt-in:

```bash
helix start dev --image-version latest
helix start dev --image-version v0.0.9 --persist
helix start dev --image-version v0.0.10 --persist
helix start dev --pull never
```

Expand All @@ -34,7 +34,7 @@ apply only to that invocation.
```toml
[local.dev]
image = "ghcr.io/helixdb/helixdb"
tag = "v0.0.9"
tag = "v0.0.10"
pull = "missing"
```

Expand Down
4 changes: 2 additions & 2 deletions crates/cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{fmt, str::FromStr};

pub const DEFAULT_LOCAL_PORT: u16 = 6969;
pub const DEFAULT_LOCAL_IMAGE: &str = "ghcr.io/helixdb/helixdb";
pub const DEFAULT_LOCAL_IMAGE_TAG: &str = "v0.0.9";
pub const DEFAULT_LOCAL_IMAGE_TAG: &str = "v0.0.10";
pub const DEFAULT_S3_REGION: &str = "us-east-1";
pub const DEFAULT_S3_PREFIX: &str = "db/";

Expand Down Expand Up @@ -767,7 +767,7 @@ tag = "latest"
fn local_config_defaults_to_published_standalone_image() {
let config = LocalInstanceConfig::default();

assert_eq!(config.image_ref(), "ghcr.io/helixdb/helixdb:v0.0.9");
assert_eq!(config.image_ref(), "ghcr.io/helixdb/helixdb:v0.0.10");
}

#[test]
Expand Down
12 changes: 6 additions & 6 deletions crates/cli/src/local_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1906,7 +1906,7 @@ mod tests {
fn memory_helix_args_match_existing_run_shape() {
let args = helix_run_args(
"helix-demo-dev",
"ghcr.io/helixdb/helixdb:v0.0.9",
"ghcr.io/helixdb/helixdb:v0.0.10",
9090,
true,
&HelixStorage::Memory,
Expand All @@ -1927,7 +1927,7 @@ mod tests {
"9090:8080",
"--label",
"helixdb.identity=4:demo/dev",
"ghcr.io/helixdb/helixdb:v0.0.9",
"ghcr.io/helixdb/helixdb:v0.0.10",
]
.into_iter()
.map(String::from)
Expand All @@ -1945,7 +1945,7 @@ mod tests {
};
let args = helix_run_args(
"helix-demo-dev",
"ghcr.io/helixdb/helixdb:v0.0.9",
"ghcr.io/helixdb/helixdb:v0.0.10",
8080,
true,
&storage,
Expand Down Expand Up @@ -1980,7 +1980,7 @@ mod tests {
assert!(has_pair(&args, "-e", "HELIX_TELEMETRY_LEVEL=off"));
assert_eq!(
args.last().map(String::as_str),
Some("ghcr.io/helixdb/helixdb:v0.0.9")
Some("ghcr.io/helixdb/helixdb:v0.0.10")
);
}

Expand All @@ -2004,7 +2004,7 @@ mod tests {
};
let args = helix_run_args(
"helix-my-helix-project-production",
"ghcr.io/helixdb/helixdb:v0.0.9",
"ghcr.io/helixdb/helixdb:v0.0.10",
8080,
true,
&storage,
Expand Down Expand Up @@ -2054,7 +2054,7 @@ mod tests {
};
let args = helix_run_args(
"helix-demo-dev",
"ghcr.io/helixdb/helixdb:v0.0.9",
"ghcr.io/helixdb/helixdb:v0.0.10",
8080,
true,
&storage,
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/tests/e2e_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn init_and_add_generate_expected_project_files() {
config["local"]["dev"]["image"].as_str(),
Some("ghcr.io/helixdb/helixdb")
);
assert_eq!(config["local"]["dev"]["tag"].as_str(), Some("v0.0.9"));
assert_eq!(config["local"]["dev"]["tag"].as_str(), Some("v0.0.10"));

let gitignore = fs::read_to_string(project.join(".gitignore")).unwrap();
assert!(gitignore.lines().any(|line| line == ".helix/"));
Expand Down
6 changes: 3 additions & 3 deletions crates/cli/tests/e2e_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ fn assert_e2e_count_is_one(output: &str) {
}

#[test]
#[ignore = "requires Docker and pulls ghcr.io/helixdb/helixdb:v0.0.9"]
#[ignore = "requires Docker and pulls ghcr.io/helixdb/helixdb:v0.0.10"]
fn local_runtime_lifecycle_and_query_smoke() {
let fixture = CliFixture::new();
let port = free_port();
Expand Down Expand Up @@ -243,7 +243,7 @@ fn local_runtime_lifecycle_and_query_smoke() {
}

#[test]
#[ignore = "requires Docker and pulls ghcr.io/helixdb/helixdb:v0.0.9 plus SeaweedFS"]
#[ignore = "requires Docker and pulls ghcr.io/helixdb/helixdb:v0.0.10 plus SeaweedFS"]
fn disk_runtime_persists_data_across_stop_and_start() {
let fixture = CliFixture::new();
let port = free_port();
Expand Down Expand Up @@ -370,7 +370,7 @@ fn docker(args: &[&str]) -> std::process::Output {
/// instance network and its data volume behind. Start must detach the old
/// sidecar so stop can still remove the network, and prune must delete both.
#[test]
#[ignore = "requires Docker and pulls ghcr.io/helixdb/helixdb:v0.0.9 plus SeaweedFS"]
#[ignore = "requires Docker and pulls ghcr.io/helixdb/helixdb:v0.0.10 plus SeaweedFS"]
fn disk_runtime_replaces_a_legacy_minio_sidecar() {
let fixture = CliFixture::new();
let port = free_port();
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/tests/runtime_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,7 @@ async fn configured_policy_applies_to_foreground_and_dependency_failures_preserv
result.failure();
}
let log = fixture.runtime_log();
assert!(log.contains("pull ghcr.io/helixdb/helixdb:v0.0.9"));
assert!(log.contains("pull ghcr.io/helixdb/helixdb:v0.0.10"));
assert!(log.contains(&format!("pull {SEAWEEDFS_IMAGE}")));
if !failed_image.is_empty() {
assert!(
Expand Down
11 changes: 9 additions & 2 deletions crates/db/tests/production_contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11567,8 +11567,15 @@ async fn public_query_boundary_keeps_scan_order_and_repeats_through_index_served
/// union branch, for node and edge sources. Each expected count is the
/// brute-force count over the seeded `User` nodes and `Link` edges. A
/// window over the intersection keeps the range's order, as its rows do.
#[tokio::test]
async fn counts_over_range_intersections_apply_every_filter() {
#[test]
fn counts_over_range_intersections_apply_every_filter() {
run_high_stack_contract(
"range-intersection-counts",
counts_over_range_intersections_apply_every_filter_contract,
);
}

async fn counts_over_range_intersections_apply_every_filter_contract() {
const USERS: i64 = 300;
let db = HelixDB::open(HelixDbSource::InMemory {
database: "production-range-intersection-counts".to_owned(),
Expand Down
2 changes: 1 addition & 1 deletion docker-image/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This directory owns the build and test surface for the standalone HelixDB image.

The canonical image repository is `ghcr.io/helixdb/helixdb`. The scripts require an explicit platform and image tag so local and CI runs exercise the same artifact.

The published release is `ghcr.io/helixdb/helixdb:v0.0.9`, available for Linux amd64
The published release is `ghcr.io/helixdb/helixdb:v0.0.10`, available for Linux amd64
and arm64. See the [local server guide](../docs/database/helix-db/start-here/local-development/local-server.mdx)
for release-image commands. The `local-amd64` and `local-arm64` tags below refer
to images built from your checkout.
Expand Down
4 changes: 2 additions & 2 deletions docs/cli/command-reference/start.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ helix start [INSTANCE] [OPTIONS]

## Behavior

- Defaults to `ghcr.io/helixdb/helixdb:v0.0.9`. Flags override the image tag and pull policy set in `[local.<instance>]`.
- Defaults to `ghcr.io/helixdb/helixdb:v0.0.10`. Flags override the image tag and pull policy set in `[local.<instance>]`.
- `always` requires a successful pull, `missing` uses a cached image when available, and `never` fails if the image is not cached. A failed pull never silently falls back to an older cached image.
- All required images are resolved before overrides are saved or containers are replaced, so a failed resolution leaves `helix.toml` unchanged. Helix and disk-mode dependencies start by their resolved immutable image IDs.
- The disk-mode SeaweedFS image defaults to `missing` unless a pull policy is explicitly configured.
Expand Down Expand Up @@ -86,7 +86,7 @@ helix start dev --disk
helix start dev --image-version latest

# Save a specific image version
helix start dev --image-version v0.0.9 --persist
helix start dev --image-version v0.0.10 --persist

# Start using cached images only
helix start dev --pull never
Expand Down
2 changes: 1 addition & 1 deletion docs/cli/workflows/local.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pageType: "Guide"

<div className="flex flex-wrap gap-2"><Badge color="blue" size="sm">Guide</Badge></div>

Local development runs the prebuilt `ghcr.io/helixdb/helixdb:v0.0.9` container and exposes the standalone server at `POST /v2/query`. By default, storage is in-memory. Use `--disk` when you want persistent local data backed by a CLI-managed SeaweedFS volume.
Local development runs the prebuilt `ghcr.io/helixdb/helixdb:v0.0.10` container and exposes the standalone server at `POST /v2/query`. By default, storage is in-memory. Use `--disk` when you want persistent local data backed by a CLI-managed SeaweedFS volume.

## Prerequisites

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pageType: "Guide"

<div className="flex flex-wrap gap-2"><Badge color="blue" size="sm">Guide</Badge></div>

The `ghcr.io/helixdb/helixdb:v0.0.9` image runs the standalone HelixDB server.
The `ghcr.io/helixdb/helixdb:v0.0.10` image runs the standalone HelixDB server.
It supports Linux on amd64 and arm64.
It exposes the same operation-tree request contract used by Helix Cloud at
`POST /v2/query`; gateway-only Cloud features are not included.
Expand Down Expand Up @@ -46,9 +46,15 @@ helix start dev # add --disk to persist this instance

The standalone server accepts queries at `http://localhost:6969/v2/query`.

For an existing project, set `tag = "v0.0.9"` in its `[local.dev]` block in
For an existing project, set `tag = "v0.0.10"` in its `[local.dev]` block in
`helix.toml` before starting it. An explicitly saved tag overrides the CLI default.

<Warning>
The first time v0.0.10 opens a persisted database, it upgrades the index storage
version, and v0.0.9 and earlier then refuse to open that database. Back up the data
before changing the tag if you may need to roll back.
</Warning>

```bash
helix query dev \
-e 'readBatch().varAs("count", g().nWithLabel("User").count()).returning(["count"])'
Expand Down Expand Up @@ -106,7 +112,7 @@ Memory mode is selected by leaving both `HELIX_DATA_DIR` and `S3_BUCKET` unset:
```bash
docker run --rm --name helixdb \
-p 6969:8080 \
ghcr.io/helixdb/helixdb:v0.0.9
ghcr.io/helixdb/helixdb:v0.0.10
```

The standalone server exposes liveness and readiness checks:
Expand All @@ -132,7 +138,7 @@ docker run --rm --name helixdb \
-p 6969:8080 \
-e HELIX_DATA_DIR=/var/lib/helix \
--mount type=volume,source=helixdb-data,target=/var/lib/helix \
ghcr.io/helixdb/helixdb:v0.0.9
ghcr.io/helixdb/helixdb:v0.0.10
```

Stop the server with `docker stop helixdb`. Starting a new container with the
Expand Down Expand Up @@ -191,7 +197,7 @@ services:
retries: 120

helix:
image: ghcr.io/helixdb/helixdb:v0.0.9
image: ghcr.io/helixdb/helixdb:v0.0.10
restart: unless-stopped
depends_on:
seaweedfs:
Expand Down Expand Up @@ -285,7 +291,7 @@ docker run --rm --name helixdb \
-e HELIX_DISK_CACHE_DIR=/var/cache/helix \
-e HELIX_DISK_CACHE_BYTES=107374182400 \
-v /data/helix-cache:/var/cache/helix \
ghcr.io/helixdb/helixdb:v0.0.9
ghcr.io/helixdb/helixdb:v0.0.10
```

In Compose, add a volume at `/var/cache/helix` to the `helix` service. A new
Expand Down
21 changes: 21 additions & 0 deletions docs/database/helix-db/start-here/release-notes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ pageType: "Reference"

<div className="flex flex-wrap gap-2"><Badge color="gray" size="sm">Reference</Badge></div>

<Update
label="October 2026"
rss={{
title: "Docker v0.0.10 and CLI 3.4.3: asynchronous vector and text indexing",
description: "Vector and text index work moves off the write path, searches choose strong or eventual consistency, and counts over range indexes with other filters are fixed"
}}
>
- **Upgrading: index storage version 5.** The first time a v0.0.10 writer opens a database, it upgrades the index storage version from 4 to 5. It rewrites only the version marker and rebuilds no index. After that, v0.0.9 and earlier refuse to open the database with `unsupported_index_storage_version`:
- Upgrade readers before the writer; v0.0.10 readers serve both versions.
- Never start a v0.0.9-or-earlier writer against an upgraded database.
- Take a backup before upgrading if you may need to roll back.
- **[Vector and text indexes publish asynchronously](/database/helix-db/query-guides/search-consistency).** A write commits its graph change together with a durable queued index operation, and a background index worker publishes it into the vector or text index, so writes no longer wait on index maintenance. Steady vector insert publication went from 6.2 to 239 per second. Index builds no longer livelock under concurrent writes: on a c7i.8xlarge with 100 writes/s during the build, backfilling 100K 768-dimension vectors on disk finished in about 2,500 s, where v0.0.9 never finished.
- **Search consistency.** Read requests set `search_consistency` to `strong` (the default) or `eventual`. `strong` searches include every committed write, published or not. `eventual` searches include a bounded amount of unpublished work and serve the rest as last published, so they can return a node or edge that has since changed tenant, label or indexed property. Write requests always search `strong`, and a write batch that searches an index fails with a retryable `transaction_conflict` if the index worker publishes into that index first. The SDK options ship in the next SDK releases; until then, send `search_consistency` in a direct HTTP request.
- **[Index backpressure](/database/helix-db/query-guides/search-consistency#index-backpressure).** Each index retains at most 1,000,000,000 bytes or 250,000 pending entities of unpublished work. Three cases fail with `index_backpressure` (HTTP 429, `retryable: true`) before the request takes effect: a write past either limit, a whole-index `strong` search behind more than 800 unpublished changes, and a `strong` text search that would analyze more unpublished text than one publication may (64 MiB by default). Retry it unchanged with bounded backoff. A single write that stages more than 8 MiB of index work for one index fails with `index_operation_batch_too_large` (HTTP 400); split it.
- **[Text write limits are per document](/database/helix-cloud/operate/limits#active-text-mutation-admission).** `active_text_mutation_limit_exceeded` now checks each indexed document against its own allowances, about 16,000 unique terms, instead of limiting a write to 512 text-indexed entities.
- **A failing index entry no longer stalls its index.** An entry whose index update fails the same way every time, for example on damaged index data, is held back while the rest of the index keeps publishing. `GET /healthz` counts it under `blocked_index_entity_count`, the server logs an error naming it, and the worker retries it about once a minute. See [troubleshooting](/database/helix-db/query-guides/troubleshooting).
- **Fixed: `missing simhash` after re-embedding and then deleting a node** (the v0.0.9 known issue). Re-embedding a node no longer loses track of the vector index (HNSW) links that point at it, so deleting it later removes them all, and a node is never linked to itself. Indexes written by v0.0.9 and earlier can still hold such links; drop and recreate the vector index to repair them.
- **Fixed: counts over a range index with other indexed filters.** A `.count()` over `N<L>.where(...)` or `E<L>.where(...)` that combined a range condition with other indexed conditions counted the range alone, for example 149 rows instead of 49. Counts now apply every filter.
- **CLI 3.4.3** defaults to image v0.0.10. Projects that saved a `tag` in `helix.toml` keep using it until you change it.
</Update>

<Update
label="October 2026"
rss={{
Expand Down
Loading
Loading