# ID Generator

> 10xGraph uses ID generators to create unique identifiers for threads, messages, and other persisted records.

Source: https://10xgraph.com/docs/reference/api-cli/id-generator
Last updated: 2026-07-21

10xGraph uses ID generators to create unique identifiers for threads, messages, and other persisted records. The generator determines both the ID format and the ID type used in the system.

## Base ID generator interface

The core interface is `BaseIDGenerator` in `tenxgraph/utils/id_generator.py`. It defines:

- `id_type` — the ID type returned by the generator (`STRING`, `INTEGER`, or `BIGINT`).
- `generate()` — method that returns a new unique ID.

This interface lets 10xGraph support standard UUIDs, timestamp-based integers, and Snowflake-style distributed IDs.

## Built-in generators

10xGraph includes several built-in ID generators:

- `DefaultIDGenerator`
  - Returns an empty string.
  - This signals the framework to use a default UUID-based generator elsewhere in the stack.
  - Use this when you want a normal UUID fallback.

- `UUIDGenerator`
  - Produces UUID version 4 strings.
  - ID type: `STRING`.
  - Good for global uniqueness without coordination.

- `BigIntIDGenerator`
  - Produces a large integer based on current Unix time in nanoseconds.
  - ID type: `BIGINT`.
  - Sortable by creation time, but not ideal for extremely high-concurrency distributed systems.

## Snowflake ID generator

The API package includes `SnowFlakeIdGenerator` in `agentflow-api/agentflow_cli/src/app/utils/snowflake_id_generator.py`.

This generator uses the optional `snowflakekit` dependency and returns a 64-bit integer suitable for distributed systems.

### Configuration options

If you do not pass explicit constructor values, `SnowFlakeIdGenerator` reads these environment variables:

- `SNOWFLAKE_EPOCH` — default `1723323246031`
- `SNOWFLAKE_TOTAL_BITS` — default `64`
- `SNOWFLAKE_TIME_BITS` — default `39`
- `SNOWFLAKE_NODE_BITS` — default `7`
- `SNOWFLAKE_NODE_ID` — default `0`
- `SNOWFLAKE_WORKER_ID` — default `0`
- `SNOWFLAKE_WORKER_BITS` — default `5`

It reads `os.environ` directly, so these are process environment variables. A `.env` file loaded
through `10xgraph.json` is loaded before the graph module is imported, which covers the normal
case where the generator is constructed inside your graph module.

### The constructor is all-or-nothing

There are exactly two supported ways to construct it:

1. **Pass nothing.** All seven parameters are `None`, so the generator builds its config from the
   environment variables above.
2. **Pass all seven.** `snowflake_epoch`, `total_bits`, `snowflake_time_bits`,
   `snowflake_node_bits`, `snowflake_node_id`, `snowflake_worker_id`, and
   `snowflake_worker_bits` must all be supplied.

> **Passing only some arguments silently skips your configuration**
>
> The constructor tests for "all `None`" and then for "all not `None`". A partial call satisfies
> neither branch, so no config object is built and the generator is constructed with `config=None`.
> Your values are discarded without an error, and the environment variables are not consulted
> either.
>
> ```python
> # Wrong: only two arguments. Both are ignored.
> gen = SnowFlakeIdGenerator(snowflake_node_id=3, snowflake_worker_id=1)
> 
> # Right: environment-driven
> gen = SnowFlakeIdGenerator()
> 
> # Right: fully explicit
> gen = SnowFlakeIdGenerator(
>     snowflake_epoch=1723323246031,
>     total_bits=64,
>     snowflake_time_bits=39,
>     snowflake_node_bits=7,
>     snowflake_node_id=3,
>     snowflake_worker_id=1,
>     snowflake_worker_bits=5,
> )
> ```
>
> To vary only the node id, use the environment variables and pass nothing.

> **The Settings model declares different SNOWFLAKE_* defaults**
>
> The server's `Settings` model also declares `SNOWFLAKE_*` fields, and its defaults do **not**
> match the ones above: `SNOWFLAKE_EPOCH=1609459200000`, `SNOWFLAKE_NODE_ID=1`,
> `SNOWFLAKE_WORKER_ID=2`, `SNOWFLAKE_NODE_BITS=5`, `SNOWFLAKE_WORKER_BITS=8`, and no
> `SNOWFLAKE_TOTAL_BITS` at all.
>
> `SnowFlakeIdGenerator` never reads that model. The values in this page are the ones that take
> effect. Do not infer the generator's behaviour from `get_settings()`, and set every variable
> explicitly in any deployment running more than one node or worker rather than relying on either
> set of defaults.

### Example usage

```python
from agentflow_cli import SnowFlakeIdGenerator

id_generator = SnowFlakeIdGenerator()
```

Or configure explicitly:

```python
id_generator = SnowFlakeIdGenerator(
    snowflake_epoch=1723323246031,
    total_bits=64,
    snowflake_time_bits=39,
    snowflake_node_bits=7,
    snowflake_node_id=1,
    snowflake_worker_id=2,
    snowflake_worker_bits=5,
)
```

### Deployment notes

- Assign a unique `SNOWFLAKE_NODE_ID` per host or cluster node.
- Assign a unique `SNOWFLAKE_WORKER_ID` per worker process on the same host.
- Do not reuse node or worker IDs while old IDs are still valid in storage.
- Install the optional dependency with `pip install snowflakekit`.

## When to use Snowflake IDs

Choose `SnowFlakeIdGenerator` when you need:

- globally unique IDs across multiple servers,
- time-sortable identifiers,
- IDs without a central coordination service.

For local development, `UUIDGenerator` is usually sufficient.
