Curiosity

Code Indexes

A Custom Code Index runs C# you author against nodes in the graph, producing derived text, embeddings, or graph edges that the workspace's standard indexes then consume. Unlike a built-in index (Lucene, HNSW, time, geo), a code index is open-ended: you can call AI providers, run another query, transform fields, or pull in external data — anything you can express in C#.

Code indexes are configured under Manage → Indexes → Code Indexes in the admin UI. This section is the reference for what you can do inside the code, not the UI walkthrough.

For the full catalogue of indexes the workspace supports (Lucene, embeddings, parsers, linkers, filters), see Indexes.

When to use a code index

Need Use
Generate a derived text field that's a function of multiple properties Code index producing (uid, derived text)
Compute embeddings from an external API and have the workspace index them Code index producing (uid, float[])
Run an LLM extractor that writes back entities + Mentions edges Code index with side effects via Graph
Bulk-load static derived data without runtime work A data connector — not an index
Custom search execution / facet generation at query time A search execution scope

A code index is the right tool when the derivation needs to rerun automatically whenever the source node changes. If you only need to compute the field once at ingest time, do it in the connector.

In this section

  • Execution scope — variables and methods (Graph, Q(), ToIndex, ChatAI, …) available inside the code-index body.

Lifecycle

flowchart LR Commit[Node committed] --> Queue[(Index queue)] Queue --> Worker[Background worker] Worker -->|invokes| Code[Your code-index body] Code -->|yields| Output[Derived text / vector / edges] Output --> Index[(Indexed by workspace)]

The worker batches nodes (ToIndex is the list of UIDs in the current batch) and invokes your body. Whatever you yield return flows into the workspace's index. Side effects via Graph (adding nodes, linking edges) are committed automatically when the batch finishes.

Patterns

Derived text for embedding:

foreach (var uid in ToIndex)
{
    var node = Graph.Get(uid);
    var summary = node.GetString(N.SupportCase.Summary);
    var content = node.GetString(N.SupportCase.Content);
    yield return (uid, $"{summary}\n{content}");
}

LLM extraction with side effects:

foreach (var uid in ToIndex)
{
    var node    = Graph.Get(uid);
    var text    = node.GetString(N.Article.Body);
    var people  = await ChatAI.ExtractAsync<string[]>(
        prompt: "Extract person names as JSON array",
        input:  text,
        cancellationToken: CancellationToken);

    foreach (var name in people ?? Array.Empty<string>())
    {
        var person = Graph.TryAdd(new Person { Name = name });
        Graph.Link(node, person, "Mentions", "MentionedIn");
    }
}

The ChatAI helper uses whichever provider is configured under Settings → AI.

See also

© 2026 Curiosity. All rights reserved.