Model or dataset
ratel-ai/ratel avatar
ratel-ai/ratel

Ratel: token-aware tool and skill selection for AI agents without a vector DB

Context engineering for AI agents. ~80% fewer tokens. Fix tool overload. Skills and memory with in-process BM25 and semantic retrieval. Progressive Disclosure. No vector DB.

462 stars25 forksTypeScriptMIT

At a glance

What is it?
Ratel is a context engineering layer that indexes agent tools and skills and discloses only what each turn needs. It ships TypeScript and Python SDKs over a Rust retrieval core, uses BM25 by default, and needs no vector database.
Who is it for?
Adopt Ratel if you run an agent with a tool list that has outgrown the model's attention and you want retrieval without standing up a vector database. Do not adopt it if your agent exposes a handful of tools, or if you need a stable API today: the newest published releases are 0.13.0 release candidates.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Ratel targets: agents that pay for tools they never call

Every tool schema, every skill body, and every standing instruction in the system prompt is billed on every call. An agent wired to forty tools sends forty schemas whether the turn needs one of them or none. The README frames this as two failures at once: cost, because unused schemas are paid for repeatedly, and accuracy, because models degrade as context grows and start selecting the wrong option or drifting off task.

Ratel is aimed at people building agents whose capability list has outgrown what the prompt can hold cheaply. That is a narrower audience than "anyone using an LLM." If your agent exposes five tools, the overhead is small and the added indirection costs you more than it saves. The pitch only holds once the catalog is large enough that loading it all up front is visibly wasteful.

How the catalog, the two indexes, and progressive disclosure fit together

Ratel splits agent capabilities into two registries. A ToolCatalog holds executable tools with an id, name, description, input schema, output schema and an execute function. A SkillCatalog holds skills: a name, description, a list of tool ids, and a body of instructions. The two are indexed separately, and search returns focused results from each rather than one merged list.

When the agent needs to act, it calls search_capabilities. Retrieval runs over schema-aware tool metadata and over skill names, descriptions and tags. The default ranker is BM25, the algorithm the README describes as being behind most search engines, chosen because it is fast and deterministic. Skill bodies stay out of context until the agent loads one with get_skill_content, which is the progressive disclosure step: the index holds a thin description, and the full playbook arrives only on demand. Tools are invoked by id through invoke_tool.

Semantic and hybrid ranking are opt-in, per catalog or per call. That path is asynchronous: SDK callers register (which embeds) and search dense indexes, using either an in-process model or an OpenAI-compatible embedding endpoint. The default path needs no embedding service at all, which is the reason the project can claim no vector DB and no extra infrastructure.

A third concept, facts, covers constant grounding such as a shop's address or a brand's voice. Facts are pushed into context and re-injected only when they are no longer fresh in the transcript.

Installing the TypeScript SDK and wiring a first catalog

The TypeScript package is published as @ratel-ai/sdk. Install it with the package manager the README uses:

bash
pnpm add @ratel-ai/sdk

The README's example builds a ToolCatalog, registers one executable tool, and builds a SkillCatalog that references it:

ts
import { readFile } from "node:fs/promises";
import {
  SkillCatalog,
  ToolCatalog,
  getSkillContentTool,
  invokeToolTool,
  searchCapabilitiesTool,
} from "@ratel-ai/sdk";

const catalog = new ToolCatalog();
catalog.register({
  id: "read_file",
  name: "read_file",
  description: "Read a file from local disk.",
  inputSchema: { type: "object", properties: { path: { type: "string" } } },
  outputSchema: { type: "object", properties: { contents: { type: "string" } } },
  execute: async ({ path }) => ({ contents: await readFile(path, "utf8") }),
});

The three helpers returned at the end of the example are the ones you hand to your agent framework as tools:

ts
const search = searchCapabilitiesTool(catalog, skills);
const invoke = invokeToolTool(catalog);
const loadSkill = getSkillContentTool(skills);

What you should see is that your framework's tool list stops growing with your catalog. The agent gets search, invoke and skill loading as its fixed surface, and the real tools arrive through search results. The README points to docs.ratel.sh for the quickstart and the per-language SDK guides, and to examples/ai-sdk and examples/pydantic-ai for end-to-end wiring.

The Python SDK mirrors the TypeScript one, with PyO3 underneath

The Python package is ratel-ai on PyPI:

bash
pip install ratel-ai

The shape is the same as the TypeScript example, with snake_case names and an ExecutableTool and Skill pair instead of plain objects:

python
from ratel_ai import (
    ExecutableTool,
    Skill,
    SkillCatalog,
    ToolCatalog,
    get_skill_content_tool,
    invoke_tool_tool,
    search_capabilities_tool,
)

catalog = ToolCatalog()
catalog.register(ExecutableTool(
    id="read_file",
    name="read_file",
    description="Read a file from local disk.",
    input_schema={"properties": {"path": {"type": "string"}}},
    execute=lambda args: {"contents": open(args["path"]).read()},
))

Both SDKs bind to the same Rust engine in src/core, through NAPI for TypeScript and PyO3 for Python. That shared core is why the retrieval behaviour should match across languages, and why the release tags are split per unit (core-v*, sdk-ts-v*, sdk-py-v*) rather than versioned together.

Where Ratel is the wrong tool

The clearest boundary is catalog size. If your agent has a small, stable tool set, adding a search step means the model must first discover a tool and then invoke it, which is an extra turn and an extra failure point for no token saving worth having.

The second boundary is determinism versus recall. BM25 matches on terms in tool metadata and skill text. A tool whose name and description do not contain the words the model searches with will not surface, and the README does not describe a fallback that shows the agent what it missed. The semantic path exists for this, but it is opt-in, it is asynchronous on both register and search, and it needs either an in-process model or an OpenAI-compatible embedding endpoint. Choosing it means giving up the no-infrastructure property that makes the default path attractive.

The third is API stability. The most recent published releases listed for this repository are 0.13.0 release candidates for both the TypeScript and Python SDKs, dated 2026-09-02. Release candidates are not a promise of a frozen surface. Projects that cannot absorb interface churn between minor versions should wait or pin.

Finally, the README does not document rollback, migration between catalog versions, or what happens to in-flight skill loads when a catalog is re-registered. Those gaps matter if you plan to change tool sets at runtime.

How Ratel differs from a vector-database RAG stack

The obvious alternative is the standard RAG arrangement: embed your tool descriptions, store them in a vector database such as a hosted or self-managed store, and retrieve by nearest neighbour. The difference is not the goal, which is the same, but the machinery and the failure profile.

A vector stack gives you fuzzy matching, so a query phrased differently from the tool description can still hit. It costs you an embedding model, a store to run and back up, a re-embedding pass whenever a tool description changes, and non-deterministic ranking that is harder to debug when the wrong tool comes back. Ratel's default inverts those trade-offs: BM25 over an in-process index gives deterministic, inspectable results with no service to operate, at the price of exact-term sensitivity. Ratel does offer the embedding route as an opt-in, so the comparison is really about which mode you leave on.

A second alternative is a hosted MCP gateway or tool router. Those centralize tools across clients, which Ratel does not attempt. Ratel's own related project, ratel-ai/ratel-mcp, is the local distribution that puts Ratel in front of an existing MCP setup, so the two are meant to be layered rather than chosen between.

Maintenance, licence and the cost of upgrading

The repository is not archived, and the last push was on 2026-09-10, which is recent. The release cadence visible in the tags is active: four release candidates across the TypeScript and Python SDKs on 2026-09-02. That is a project still settling its interfaces, not one in a quiet maintenance phase.

Licensing is mixed. The README badge reads Apache-2.0 & MIT, and the repository root carries LICENSE-APACHE, LICENSE.md and NOTICE. The task description lists MIT. Because the two signals disagree, check the per-package licence files before you redistribute anything; the NOTICE file exists for a reason and this is not a decision to make from a badge. Nothing here is legal advice.

Upgrade cost is shaped by the workspace layout. Cargo.toml records that versions are per-package by design (ADR-0008), so core, sdk-ts and sdk-py are tagged independently. Upgrading the TypeScript SDK does not imply a matching Rust core bump, and vice versa. The release profile in the workspace root sets strip, lto = "thin" and codegen-units = 1, which the comment ties to install weight and to eliminating unused model and kernel code. In practice that means SDK upgrades are binary-sized events, and you should expect to re-verify retrieval behaviour after a core bump rather than assume ranking is unchanged.

Editorial conclusion

Adopt Ratel if you run an agent with a tool list that has outgrown the model's attention and you want retrieval without standing up a vector database. Do not adopt it if your agent exposes a handful of tools, or if you need a stable API today: the newest published releases are 0.13.0 release candidates. Before wiring it into production, check the SDK version for your language, confirm whether you need the opt-in semantic ranking path (which embeds on register and searches asynchronously), and read docs/adr for the decisions behind the catalog and release-unit split.

Frequently asked questions

Does Ratel need a vector database?

No. The default ranker is BM25 over schema-aware tool metadata and skill names, descriptions and tags, which runs in process. Semantic and hybrid ranking are opt-in per catalog or per call, and only that path embeds on register and searches dense indexes asynchronously.

How do I install the Ratel SDK?

For TypeScript, the README gives pnpm add @ratel-ai/sdk. For Python, it gives pip install ratel-ai. Both SDKs bind to the Rust retrieval engine in src/core.

What is the difference between a Ratel tool and a skill?

A tool is executable and is invoked by id. A skill is a playbook with a name, description, a list of tool ids and a body, and its instructions stay out of context until the agent loads it with get_skill_content.

Which licence does Ratel use?

The README badge says Apache-2.0 & MIT, and the repository root contains LICENSE-APACHE, LICENSE.md and NOTICE, while the project description states MIT. Check the per-package licence files before redistributing.

What are Ratel facts for?

Facts hold constant grounding an agent always needs, such as a shop's address or a brand's voice. They are pushed into context and re-injected only when they are no longer fresh in the transcript.

Official sources

  1. License: MIT
  2. Project website
  3. ratel-ai/ratel on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ratel-ai-ratel.svg)](https://hysenlabs.com/projects/ratel-ai-ratel)