# Ask your codebase

> A CLI that indexes a Rust codebase locally with tree-sitter, FastEmbed and LanceDB, and answers questions about it citing the files it used.

This showcase is a command-line tool with two commands. `index` turns a codebase into searchable chunks, and `ask` answers a question from those chunks and lists the files it used. Everything except the large language model (LLM) runs on your machine. You need no Docker and no database server.

## Prerequisites

- Rust 1.97.1, which the swiftide workspace pins in `rust-toolchain.toml`.
- `OPENAI_API_KEY` for any OpenAI-compatible endpoint. `OPENAI_BASE_URL` is optional and defaults to `https://api.openai.com/v1`. `OPENAI_MODEL` is optional and defaults to `gpt-5.4-mini`. An empty `OPENAI_API_KEY` or `OPENAI_BASE_URL` counts as unset. An empty `OPENAI_MODEL` does not: it sets the model to an empty name, so unset it instead.
- About 600MB of disk for the code embedding model. FastEmbed downloads it into `.fastembed_cache/` in the current directory on first use.

The crate turns off swiftide's default features and enables the `tree-sitter`, `fastembed`, `lancedb`, `redb` and `openai` feature flags. To build the same thing in your own crate:

```sh
cargo add swiftide@0.34 --no-default-features --features tree-sitter,fastembed,lancedb,redb,openai
cargo add fastembed@5 tree-sitter@0.26 --no-default-features
```

The crate also depends on `fastembed` to pick the embedding model and `tree-sitter` to find unit tests, each at the version swiftide uses. TLS needs no setup: swiftide's HTTP clients bring their own rustls crypto provider ([TLS](/integrations/overview/#tls)).

## Architecture

The tool runs two pipelines that share one local embedder. The indexing pipeline loads files, chunks them, describes each chunk with the LLM, embeds the result and stores it. The query pipeline embeds your question with the same model, retrieves the closest chunks and asks the LLM to answer from them.

![Indexing and query pipelines](/diagrams/diagram-pipeline.svg)

The index lives next to the code, in `<path>/.ask-your-codebase/`. It holds `cache.redb`, the node cache, and `lancedb/`, the vector table.

## Indexing pipeline

```rust title="examples/ask-your-codebase/src/index.rs"
let stats = indexing::Pipeline::from_loader(
    FileLoader::new(codebase.root()).with_extensions(&languages.extensions()),
)
.filter(test_code::not_test_files(codebase.clone()))
// Drop unit tests before the cache, which keys on path and content. Changing the content
// after it would make the cache miss on every run.
.then(test_code::without_unit_tests)
.then(files_found.count())
// Skip files whose path and content are unchanged since the last successful run
.filter_cached(codebase.node_cache()?)
.then(files_changed.count())
.then(record_relative_path(codebase.clone()))
// Split along syntax boundaries (functions, impls, ...) with tree-sitter
.then_chunk(ChunkByLanguage::try_new(languages, CHUNK_SIZE)?)
// Ask the LLM which questions each chunk answers; stored as metadata and embedded
.then(
    MetadataQACode::from_client(llm)
        .prompt_template(QUESTIONS_PROMPT)
        .num_questions(QUESTIONS_PER_CHUNK)
        .concurrency(concurrent_requests)
        .build()?,
)
// Embed chunk + metadata locally, in batches
.then_in_batch(Embed::new(embedding::local_model()?).with_batch_size(embedding::BATCH_SIZE))
.then_store_with(codebase.vector_store()?)
.run()
.await?;
```

Source: [`examples/ask-your-codebase/src/index.rs#L89-L115`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/index.rs#L89-L115)

`FileLoader` respects `.gitignore`. `filter_cached` skips files whose path and content are unchanged since the last successful run. `then_in_batch` sends 32 chunks to the embedder per call. The two `count` closures count files for the summary line. `run` returns the `PipelineStats` of the run, and its `nodes_stored` is the number of chunks in the summary.

The order of the test steps matters. The node cache keys on the file path and its content. If unit tests were removed after `filter_cached`, the content would differ on every run and the cache would never hit.

### Test filtering

```rust title="examples/ask-your-codebase/src/test_code.rs"
/// Drops test files before they are cached or chunked: files in a `tests/` directory, test
/// modules in their own file (`src/agent/tests.rs`) and test support modules such as
/// `src/test_utils.rs`.
///
/// Errors are kept, so they still surface.
pub fn not_test_files(codebase: Codebase) -> impl Fn(&Result<TextNode>) -> bool + Send + Sync {
    move |file| {
        !file
            .as_ref()
            .is_ok_and(|file| is_test_file(codebase.relative_path(&file.path)))
    }
}

/// Removes unit tests (`#[cfg(test)] mod tests { .. }`, `#[test] fn ..`) from Rust files.
///
/// This runs on whole files, before chunking, so a chunk never mixes implementation and tests.
pub fn without_unit_tests(mut file: TextNode) -> Result<TextNode> {
    if file
        .path
        .extension()
        .is_some_and(|extension| extension == "rs")
    {
        file.chunk = strip_test_items(&file.chunk)?;
    }
    Ok(file)
}
```

Source: [`examples/ask-your-codebase/src/test_code.rs#L16-L41`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/test_code.rs#L16-L41)

`Pipeline::filter` takes a closure over `&Result<TextNode>` and keeps the result when the closure returns true. The predicate keeps errors on purpose, so a failed load still surfaces. The second function is an ordinary transformer: any `Fn(TextNode) -> Result<TextNode>` works, and this one rewrites `chunk` for `.rs` files.

### Node cache and storage

```rust title="examples/ask-your-codebase/src/codebase.rs"
/// Remembers which files were fully indexed, so unchanged files are skipped next time.
pub fn node_cache(&self) -> Result<Redb> {
    std::fs::create_dir_all(&self.data_dir)?;

    Redb::builder()
        .database_path(self.data_dir.join("cache.redb"))
        .table_name("indexed_files")
        .build()
}

/// Embedded vector store with one vector per chunk and the source path next to it.
pub fn vector_store(&self) -> Result<LanceDB> {
    let uri = self.lancedb_dir();

    LanceDB::builder()
        .uri(uri.to_str().context("Index path is not valid UTF-8")?)
        .table_name("code_chunks")
        .vector_size(embedding::DIMENSIONS)
        .with_vector(EmbeddedField::Combined)
        .with_metadata(PATH_FIELD)
        .build()
}
```

Source: [`examples/ask-your-codebase/src/codebase.rs#L56-L77`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/codebase.rs#L56-L77)

`Redb` is the node cache, stored in one table of a local database file. `LanceDB` is the storage: one vector column over `EmbeddedField::Combined`, sized at 768 for the embedding model, plus a `path` metadata column. Since 0.33, the pipeline marks files in the node cache only after the whole run finishes without an error. If any file fails, or you interrupt the run, nothing from that run is cached. The next run prompts and embeds every file again, not only the one that failed.

### Chunking per language

```rust title="examples/ask-your-codebase/src/languages.rs"
/// Splits each file with a tree-sitter `ChunkCode` for the file's language.
///
/// `ChunkCode` is built for a single language; this chunker picks the right one per file from
/// its extension, so one pipeline can index a polyglot codebase.
#[derive(Clone)]
pub struct ChunkByLanguage {
    chunkers: Vec<(SupportedLanguages, ChunkCode)>,
}

impl ChunkByLanguage {
    /// Chunks are between `chunk_size.start` and `chunk_size.end` bytes; smaller ones are dropped.
    pub fn try_new(languages: &SourceLanguages, chunk_size: Range<usize>) -> Result<Self> {
        let chunkers = languages
            .0
            .iter()
            .map(|&language| {
                let chunker =
                    ChunkCode::try_for_language_and_chunk_size(language, chunk_size.clone())?;
                Ok((language, chunker))
            })
            .collect::<Result<_>>()?;

        Ok(Self { chunkers })
    }

    fn chunker_for(&self, path: &Path) -> Option<&ChunkCode> {
        let extension = path.extension()?.to_str()?;

        self.chunkers
            .iter()
            .find(|(language, _)| language.file_extensions().contains(&extension))
            .map(|(_, chunker)| chunker)
    }
}

#[async_trait]
impl ChunkerTransformer for ChunkByLanguage {
    type Input = String;
    type Output = String;

    async fn transform_node(&self, node: TextNode) -> IndexingStream<String> {
        match self.chunker_for(&node.path) {
            Some(chunker) => chunker.transform_node(node).await,
            None => anyhow!("No chunker for {}", node.path.display()).into(),
        }
    }
}
```

Source: [`examples/ask-your-codebase/src/languages.rs#L39-L85`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/languages.rs#L39-L85)

`ChunkCode` is built for one language. This chunker implements `ChunkerTransformer`, holds one `ChunkCode` per language and picks one by file extension through `SupportedLanguages::file_extensions`. The chunker aims for 10 to 4096 bytes, which keeps most functions in one piece. Chunks of 10 bytes or less are dropped. When tree-sitter finds a syntax error, the whole file becomes one chunk, whatever its size.

### Question metadata

````rust title="examples/ask-your-codebase/src/index.rs"
/// Asks for the questions a developer would ask that a chunk answers.
///
/// The default `MetadataQACode` prompt asks generic questions ("What does this code do?").
/// Questions about behaviour, phrased the way a developer would ask them, match real questions
/// much better.
const QUESTIONS_PROMPT: &str = r"
# Task

List the questions a developer could ask about this codebase that the code below answers, each
with a short answer. They are stored with the code to help a search find it.

Focus on behaviour: when and in which order things happen, what starts or ends a process, which
conditions and configuration change the outcome, what happens on errors, and which extension
points (traits, hooks, builders, options) exist and when they apply.

# Constraints

- Write {{ questions }} questions and answers.
- Phrase questions the way a developer would ask them, e.g. 'When does the agent stop?'.
- Name the relevant types, functions and variants in the answers.
- Only use what can be derived from the code.
- Respond only in this format:

Q1: <question>
A1: <answer>

# Code

```
{{ node.chunk }}
```
";
````

Source: [`examples/ask-your-codebase/src/index.rs#L39-L70`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/index.rs#L39-L70)

The default `MetadataQACode` prompt asks generic questions. This template asks for questions about behavior, phrased the way a developer asks them. It is a Tera template: `MetadataQACode` fills in `questions` with the count and `node` with the chunk. The answer is stored under the metadata key `Questions and Answers (code)`. It is embedded with the chunk, but LanceDB has no column for it.

```rust title="examples/ask-your-codebase/src/index.rs"
/// Stores the file path, relative to the codebase root, as metadata on the node.
///
/// The vector store keeps this field next to each chunk, so answers can cite their sources.
fn record_relative_path(
    codebase: Codebase,
) -> impl Fn(TextNode) -> Result<TextNode> + Clone + Send + Sync + 'static {
    move |mut node| {
        let path = codebase
            .relative_path(&node.path)
            .to_string_lossy()
            .into_owned();
        node.metadata.insert(PATH_FIELD, path);
        Ok(node)
    }
}
```

Source: [`examples/ask-your-codebase/src/index.rs#L127-L141`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/index.rs#L127-L141)

A closure that returns `Result<TextNode>` is a transformer too. This one writes the relative path into the metadata, where the `path` column picks it up.

### Local embeddings

```rust title="examples/ask-your-codebase/src/embedding.rs"
/// A code-aware embedding model that runs on the CPU and needs no API key.
///
/// The model (~600MB) is downloaded on first use.
pub fn local_model() -> Result<FastEmbed> {
    let model = TextEmbedding::try_new(
        InitOptions::new(EmbeddingModel::JinaEmbeddingsV2BaseCode).with_max_length(MAX_TOKENS),
    )?;

    FastEmbed::builder()
        .embedding_model(model)
        .batch_size(BATCH_SIZE)
        .build()
}
```

Source: [`examples/ask-your-codebase/src/embedding.rs#L18-L30`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/embedding.rs#L18-L30)

`JinaEmbeddingsV2BaseCode` is a code embedding model with 768 dimensions. It runs on the CPU and needs no key. Both pipelines call `local_model`, because query vectors and chunk vectors must come from the same model. After you change the model, delete the index and build it again.

## Query pipeline

```rust title="examples/ask-your-codebase/src/query.rs"
let search = SimilaritySingleEmbedding::default().with_top_k(top_k);

let pipeline = query::Pipeline::from_search_strategy(search)
    // Rephrase the question into several, to widen what the search can match
    .then_transform_query(
        GenerateSubquestions::builder()
            .client(llm.clone())
            .prompt_template(SUBQUESTIONS_PROMPT.into())
            .build()?,
    )
    // Embed with the same local model that embedded the chunks
    .then_transform_query(Embed::from_client(embedding::local_model()?))
    .then_retrieve(codebase.vector_store()?)
    // Answer the original question from the retrieved code, each chunk under its file path
    .then_answer(
        answers::Simple::builder()
            .client(llm)
            .prompt_template(ANSWER_PROMPT.into())
            .document_template(CHUNK_TEMPLATE)
            .build()?,
    );

let answered = pipeline.query(question).await?;
```

Source: [`examples/ask-your-codebase/src/query.rs#L36-L58`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/query.rs#L36-L58)

`SimilaritySingleEmbedding` returns 10 chunks by default, and `with_top_k` sets the `--top-k` value instead. `with_top_k` takes the strategy by value and returns it, so it chains onto `default()`. `default()` is only implemented for the unfiltered strategy, so the filter type is inferred as `()`, meaning no filter. `GenerateSubquestions` rewrites the question into several related ones. The `Embed` query transformer embeds the rewritten text, the question and its subquestions together, as one vector with the local model. `query` consumes the pipeline and returns the answered query.

### Prompts and document template

````rust title="examples/ask-your-codebase/src/query.rs"
/// Widens the question into the follow-up questions its answer involves.
///
/// They are phrased like the questions generated for each chunk while indexing, so the two
/// embed close together.
const SUBQUESTIONS_PROMPT: &str = r"
Your job is to help a search find the code that answers a developer's question about a codebase.

Question: {{ question }}

Write {{ num_questions }} short follow-up questions that the code answering this question would also
answer. Think about the mechanisms involved: the main loop, the types and enum variants, the
conditions that are checked, the functions that are called, and the configuration that changes
the outcome.

## Constraints
* Phrase them the way a developer would ask about this codebase, e.g. 'When does the agent stop?'.
* Do not guess names of types or functions.
* Respond with the original question and the follow-up questions only, one per line, prefixed
  with '- '.
";

/// Renders a retrieved chunk under its file path, so the answer can cite it.
///
/// `metadata.path` is the `PATH_FIELD` metadata; a test keeps the two in step.
const CHUNK_TEMPLATE: &str = r"### {{ metadata.path }}

```
{{ content }}
```
";

/// Answers from the retrieved code and cites files.
const ANSWER_PROMPT: &str = r"
Answer a developer's question about a codebase, using snippets of its source code.

Question: {{ question }}

## Constraints
* Only use the snippets below. If they do not answer the question, say briefly what is missing.
* Be concrete: name the types, functions and variants involved and explain when they apply.
* Describe behaviour: what calls what, in which order, and under which conditions.
* Cite the file each statement comes from in backticks, e.g. (`src/lib.rs`).
* Use concise markdown. Add a short code example only if it shows how to use the API.

## Snippets

{{ documents }}
";
````

Source: [`examples/ask-your-codebase/src/query.rs#L65-L112`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/query.rs#L65-L112)

The subquestion template receives `question` and `num_questions`, which defaults to 5. The answer template receives `question` and `documents`. With `document_template`, each retrieved document is rendered on its own, with `content` and `metadata.path` available, and the results are joined with `---` lines. That is how the answer sees which file each chunk came from.

### Sources

```rust title="examples/ask-your-codebase/src/query.rs"
impl From<Query<states::Answered>> for Answer {
    /// Keeps the distinct file paths of the retrieved chunks, most relevant first.
    fn from(query: Query<states::Answered>) -> Self {
        let mut sources: Vec<String> = Vec::new();

        for document in query.documents() {
            let Some(path) = document.metadata().get(PATH_FIELD).and_then(|v| v.as_str()) else {
                continue;
            };
            if !sources.iter().any(|source| source == path) {
                sources.push(path.to_owned());
            }
        }

        Self {
            text: query.answer().to_owned(),
            sources,
        }
    }
}
```

Source: [`examples/ask-your-codebase/src/query.rs#L123-L142`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/query.rs#L123-L142)

`documents` returns the retrieved documents in relevance order. The `path` column comes back as a `path` metadata entry. The tool keeps each path once and prints the list under the answer.

## Model client

```rust title="examples/ask-your-codebase/src/llm.rs"
impl LlmEndpoint {
    /// Builds a client for this endpoint.
    ///
    /// Rate limits and transient errors are retried with exponential backoff, which matters when
    /// indexing fires many prompts concurrently. After `retry_budget` the error is returned, so
    /// an unreachable or broken endpoint fails instead of hanging.
    pub fn client(&self, retry_budget: Duration) -> Result<Arc<dyn SimplePrompt>> {
        let openai = OpenAI::builder()
            .api_base(&self.base_url)
            .api_key(&self.api_key)
            .default_prompt_model(&self.model)
            .use_responses_api(matches!(self.api, OpenAiApi::Responses))
            .build()?;

        let backoff = BackoffConfiguration {
            max_elapsed_time_sec: retry_budget.as_secs(),
            ..BackoffConfiguration::default()
        };

        Ok(Arc::new(LanguageModelWithBackOff::new(openai, backoff)))
    }
}
```

Source: [`examples/ask-your-codebase/src/llm.rs#L79-L100`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/src/llm.rs#L79-L100)

The client is always swiftide's `OpenAI` integration. `api_base` points it at `OPENAI_BASE_URL` and `api_key` sets the key, without building an `async-openai` client yourself. `use_responses_api` switches from Chat Completions to the Responses API when you pass `--responses-api`. `LanguageModelWithBackOff` retries rate limits and transient errors with exponential backoff. `index` keeps retrying a failing prompt for up to 60 seconds, because it sends many prompts at once and expects rate limits. `ask` stops retrying after 30 seconds.

## Commands

The crate lives in `examples/ask-your-codebase` of the swiftide repository. Clone the repository and run from its root:

```sh
git clone https://github.com/bosun-ai/swiftide && cd swiftide
export OPENAI_API_KEY=sk-...
cargo run -p ask-your-codebase -- index swiftide-agents
cargo run -p ask-your-codebase -- ask --path swiftide-agents "How does an agent decide to stop?"
```

`index` and `ask` are separate runs, so each can use its own model. Through a gateway that serves Anthropic models, a small model writes the indexing prompts and a stronger one writes the answers:

```sh
export OPENAI_BASE_URL=http://127.0.0.1:8080/v1  # an OpenAI-compatible gateway that serves these models
cargo run -p ask-your-codebase -- index swiftide-agents --model claude-haiku-5-5
cargo run -p ask-your-codebase -- ask --path swiftide-agents --model claude-sonnet-5-5 "How does an agent decide to stop?"
```

| Flag                 | Applies to | Default        | Description                                                         |
| -------------------- | ---------- | -------------- | ------------------------------------------------------------------- |
| `--model <name>`     | both       | `gpt-5.4-mini` | Model for chunk metadata or answers. Also read from `OPENAI_MODEL`. |
| `--responses-api`    | both       | off            | Send prompts to the Responses API.                                  |
| `--lang <languages>` | `index`    | `rust`         | Comma-separated tree-sitter languages, such as `rust,python`.       |
| `--concurrency <n>`  | `index`    | `16`           | Prompts sent at once while indexing.                                |
| `--path <dir>`       | `ask`      | `.`            | Root of the codebase, as given to `index`.                          |
| `--top-k <n>`        | `ask`      | `20`           | Number of chunks to retrieve.                                       |

By default the tool logs only errors and turns off all logging from `swiftide_integrations`, which hides errors from LanceDB, FastEmbed, Redb, tree-sitter and OpenAI. Each retried attempt is logged at WARN, so it stays hidden too. Set `RUST_LOG=info` or `RUST_LOG=debug` to see what the pipelines do.

## Output

The captured run indexed the `swiftide-agents` crate with a debug build. It went through an OpenAI-compatible gateway that forwards to Anthropic models on AWS Bedrock. `claude-haiku-5-5` wrote the per-chunk questions, `claude-sonnet-5-5` wrote the answers, and FastEmbed ran `jina-embeddings-v2-base-code` on the CPU.

The first run indexes everything. The second finds nothing changed, so the node cache skips every file and no prompt is sent:

```text
$ ./target/debug/ask-your-codebase index swiftide-agents --model claude-haiku-5-5
Indexing Rust files in swiftide-agents ...
Indexed 34 chunks from 14 new or changed files (14 files found, 0 unchanged) in 91.9s

$ ./target/debug/ask-your-codebase index swiftide-agents --model claude-haiku-5-5
Indexing Rust files in swiftide-agents ...
Indexed 0 chunks from 0 new or changed files (14 files found, 14 unchanged) in 0.6s
```

The start of one answer, and its sources:

```text
$ ./target/debug/ask-your-codebase ask --model claude-sonnet-5-5 --path swiftide-agents "How does an agent decide to stop?"
# How an agent decides to stop

An agent stops when something calls `Agent::stop` (or `stop_with_error`), which moves the state to `State::Stopped(StopReason)`. The main loop in `run_agent` checks that state after each step. `Agent::stop` is a no-op if the agent is already stopped (`src/agent.rs`).

[...]

## Triggers, by `StopReason` variant (`src/state.rs`)

| Variant | When it applies |
|---|---|
| `RequestedByTool(ToolCall, Option<Value>)` | A tool returned `ToolOutput::Stop`. |
| `FeedbackRequired { tool_call, payload }` | A tool returned `ToolOutput::FeedbackRequired`. |
| `AgentFailed(Option<Value>)` | A tool returned `ToolOutput::AgentFailed`. |
| `ToolCallsOverLimit(ToolCall)` | The same tool call failed too many times. |
| `Error` | `step` returned an `Err`. |
| `NoNewMessages` | The completion loop ended without another reason. |
| `Other(String)` | Anything convertible from `AsRef<str>`, e.g. `agent.stop("done")`. |

[...]

Sources:
  - src/agent.rs
  - src/tools/control.rs
  - src/lib.rs
  - src/state.rs
  - src/errors.rs
  - src/task_agent.rs
  - src/hooks.rs
  - src/tasks.rs
  - src/default_context.rs
```

The answers in [`OUTPUT.md`](https://github.com/bosun-ai/swiftide/blob/e377c4a2e76fe2559629ae0efdae3c6e0fb4d829/examples/ask-your-codebase/OUTPUT.md) were checked against the source of `swiftide-agents`. Where a needed chunk was not among the 20 retrieved, the answer marked its claim as an inference.

## Limitations

- When a file changes, its new chunks are added, but the chunks of the old version stay in LanceDB. Delete `.ask-your-codebase/` to start over.
- Files under a `tests` directory, or named `tests`, `test_utils` or `test_helpers`, are dropped in every language. Unit tests inside a file are only removed from `.rs` files.
- Retrieval is a single vector search. Raise `--top-k` for broad questions.
- A file that produces no chunks is never marked in the node cache, so every run loads it again. It costs no LLM calls.

## Concept pages

- Loading and caching: [Loading](/indexing/loading/), [Caching](/indexing/caching/)
- Chunking: [Code-aware indexing](/indexing/code-aware-indexing/), [Chunking](/indexing/chunking/), [Tree-sitter](/integrations/tree-sitter/)
- Metadata and embeddings: [Transformers and metadata](/indexing/transformers-and-metadata/), [Embedding](/indexing/embedding/), [FastEmbed](/integrations/fastembed/)
- Storage: [Storage](/indexing/storage/), [LanceDB](/integrations/lancedb/)
- Querying: [Transforming queries](/querying/transforming-queries/), [Retrieval and search strategies](/querying/retrieval-and-search-strategies/), [Answering](/querying/answering/)
- Models: [OpenAI-compatible endpoints](/integrations/openai-compatible/), [Errors, backoff and usage](/models/errors-backoff-and-usage/)

## Reference

- [`indexing::Pipeline`](https://docs.rs/swiftide/0.34/swiftide/indexing/struct.Pipeline.html)
- [`FileLoader`](https://docs.rs/swiftide/0.34/swiftide/indexing/loaders/struct.FileLoader.html)
- [`ChunkCode`](https://docs.rs/swiftide/0.34/swiftide/indexing/transformers/struct.ChunkCode.html)
- [`ChunkerTransformer`](https://docs.rs/swiftide/0.34/swiftide/traits/trait.ChunkerTransformer.html)
- [`SupportedLanguages`](https://docs.rs/swiftide/0.34/swiftide/integrations/treesitter/enum.SupportedLanguages.html)
- [`MetadataQACode`](https://docs.rs/swiftide/0.34/swiftide/indexing/transformers/struct.MetadataQACode.html)
- [`Embed`](https://docs.rs/swiftide/0.34/swiftide/indexing/transformers/struct.Embed.html)
- [`EmbeddedField`](https://docs.rs/swiftide/0.34/swiftide/indexing/enum.EmbeddedField.html)
- [`Redb`](https://docs.rs/swiftide/0.34/swiftide/integrations/redb/struct.Redb.html)
- [`LanceDB`](https://docs.rs/swiftide/0.34/swiftide/integrations/lancedb/struct.LanceDB.html)
- [`FastEmbed`](https://docs.rs/swiftide/0.34/swiftide/integrations/fastembed/struct.FastEmbed.html)
- [`query::Pipeline`](https://docs.rs/swiftide/0.34/swiftide/query/struct.Pipeline.html)
- [`SimilaritySingleEmbedding`](https://docs.rs/swiftide/0.34/swiftide/query/search_strategies/struct.SimilaritySingleEmbedding.html)
- [`GenerateSubquestions`](https://docs.rs/swiftide/0.34/swiftide/query/query_transformers/struct.GenerateSubquestions.html)
- [`query_transformers::Embed`](https://docs.rs/swiftide/0.34/swiftide/query/query_transformers/struct.Embed.html)
- [`answers::Simple`](https://docs.rs/swiftide/0.34/swiftide/query/answers/struct.Simple.html)
- [`query::Query`](https://docs.rs/swiftide/0.34/swiftide/query/struct.Query.html)
- [`OpenAI`](https://docs.rs/swiftide/0.34/swiftide/integrations/openai/type.OpenAI.html)
- [`LanguageModelWithBackOff`](https://docs.rs/swiftide/0.34/swiftide/indexing/struct.LanguageModelWithBackOff.html)
- [`BackoffConfiguration`](https://docs.rs/swiftide/0.34/swiftide/indexing/struct.BackoffConfiguration.html)

## Next

[Release notes agent](/showcases/release-notes-agent/)