Table of Contents
[![Crate Badge]][Crate]
[![Docs Badge]][API Docs]
[![Contributors][contributors-shield]][contributors-url]
[![Stargazers][stars-shield]][stars-url]
[![MIT License][license-shield]][license-url]
[![LinkedIn][linkedin-shield]][linkedin-url]
Fast, streaming indexing, query, and agentic LLM applications in Rust
<a href="https://swiftide.rs"><strong>Read more on swiftide.rs »</strong></a>
<a href="https://docs.rs/swiftide/latest/swiftide/">API Docs</a>
·
<a href="https://github.com/bosun-ai/swiftide/issues/new?labels=bug&template=bug_report.md">Report Bug</a>
·
<a href="https://github.com/bosun-ai/swiftide/issues/new?labels=enhancement&template=feature_request.md">Request Feature</a>
·
<a href="https://discord.gg/3jjXYen9UY">Discord</a>
Swiftide is a Rust library for building LLM applications. From performing a simple prompt completion, to building fast, streaming indexing and querying pipelines, to building agents that can use tools and call other agents.
Langfuse support

Part of the bosun.ai project. An upcoming platform for autonomous code improvement.
We <3 feedback: project ideas, suggestions, and complaints are very welcome. Feel free to open an issue or contact us on discord.
[!CAUTION] Swiftide is under heavy development and can have breaking changes. Documentation might fall short of all features, and despite our efforts be slightly outdated. We recommend to always keep an eye on our github and api documentation. If you found an issue or have any kind of feedback we'd love to hear from you.
More on our blog
Indexing a local code project, chunking into smaller pieces, enriching the nodes with metadata, and persisting into Qdrant:
indexing::Pipeline::from_loader(FileLoader::new(".").with_extensions(&["rs"]))
.with_default_llm_client(openai_client.clone())
.filter_cached(Redis::try_from_url(
redis_url,
"swiftide-examples",
)?)
.then_chunk(ChunkCode::try_for_language_and_chunk_size(
"rust",
10..2048,
)?)
.then(MetadataQACode::default())
.then(move |node| my_own_thing(node))
.then_in_batch(Embed::new(openai_client.clone()))
.then_store_with(
Qdrant::builder()
.batch_size(50)
.vector_size(1536)
.build()?,
)
.run()
.await?;
Querying for an example on how to use the query pipeline:
query::Pipeline::default()
.then_transform_query(GenerateSubquestions::from_client(
openai_client.clone(),
))
.then_transform_query(Embed::from_client(
openai_client.clone(),
))
.then_retrieve(qdrant.clone())
.then_answer(Simple::from_client(openai_client.clone()))
.query("How can I use the query pipeline in Swiftide?")
.await?;
Running an agent that can search code:
#[swiftide::tool(
description = "Searches code",
param(name = "code_query", description = "The code query")
)]
async fn search_code(
context: &dyn AgentContext,
code_query: &str,
) -> Result<ToolOutput, ToolError> {
let command_output = context
.executor()
.exec_cmd(&Command::shell(format!("rg '{code_query}'")))
.await?;
Ok(command_output.into())
}
agents::Agent::builder()
.llm(&openai)
.tools(vec![search_code()])
.build()?
.query("In what file can I find an example of a swiftide agent?")
.await?;
Agents loop over LLM calls, tool calls, and lifecycle hooks until a final answer is reached.
You can find more detailed examples in /examples
Our goal is to create a fast, extendable platform for building LLM applications in Rust, to further the development of automated AI applications, with an easy-to-use and easy-to-extend api.
tracing supported for logging and tracing, see /examples and the tracing crate for more information.| Feature | Details |
|---|---|
| Supported Large Language Model providers | OpenAI (and Azure) |
Anthropic
Gemini
OpenRouter
AWS Bedrock - Anthropic and Titan
Groq - All models
Ollama - All models | | Agents | All the boiler plate for autonomous agents so you don't have to | | Tasks | Build graph like workflows with tasks, combining all the above to build complex applications | | Loading data | Files
Scraping
Fluvio
Parquet
Kafka
Other pipelines and streams | | Example and pre-build transformers and metadata generation | Generate Question and answerers for both text and code (Hyde)
Summaries, titles and queries via an LLM
Extract definitions and references with tree-sitter | | Splitting and chunking | Markdown
Text (text_splitter)
Code (with tree-sitter) | | Storage | Qdrant
Redis
LanceDB
Postgres
Duckdb | | Query pipeline | Similarity and hybrid search, query and response transformations, and evaluation |
Make sure you have the rust toolchain installed. rustup Is the recommended approach.
To use OpenAI, an API key is required. Note that by default async_openai uses the OPENAI_API_KEY environment variables.
Other integrations might have their own requirements.
sh
cargo add swiftide
Cargo.tomlBefore building your streams, you need to enable and configure any integrations required. See /examples.
We have a lot of examples, please refer to /examples and the Documentation
[!NOTE] No integrations are enabled by default as some are code heavy. We recommend you to cherry-pick the integrations you need. By convention flags have the same name as the integration they represent.
An indexing stream starts with a Loader that emits Nodes. For instance, with the Fileloader each file is a Node.
You can then slice and dice, augment, and filter nodes. Each different kind of step in the pipeline requires different traits. This enables extension.
Nodes are generic over their inner type. This is a transition in progress, but when you BYO, feel free to slice and dice. The inner type can change midway through the pipeline.
(impl Loader) starting point of the stream, creates and emits Nodes(impl NodeCache) filters cached nodes(impl Transformer) transforms the node and puts it on the stream(impl BatchTransformer) transforms multiple nodes and puts them on the stream(impl ChunkerTransformer) transforms a single node and emits multiple nodes(impl Storage) stores the nodes in a storage backend, this can be chainedAdditionally, several generic transformers are implemented. They take implementers of SimplePrompt and EmbedModel to do their things.
[!WARNING] Due to the performance, chunking before adding metadata gives rate limit errors on OpenAI very fast, especially with faster models like gpt-5-nano. Be aware. The
async-openaicrate provides an exmponential backoff strategy. If that is still a problem, there is also a decorator that supports streaming inswiftide_core/indexing_decorators.
A query stream starts with a search strategy. In the query pipeline a Query goes through several stages. Transformers and retrievers work together to get the right context into a prompt, before generating an answer. Transformers and Retrievers operate on different stages of the Query via a generic statemachine. Additionally, the search strategy is generic over the pipeline and Retrievers need to implement specifically for each strategy.
That sounds
$ claude mcp add swiftide \
-- python -m otcore.mcp_server <graph>