fix(providers): remove ~anthropic, skip ~ prefixes in sync script (#69)

* fix(providers): remove ~anthropic, skip ~ prefixes in sync script

OpenRouter uses ~ prefixes for internal auto-routing aliases (e.g. ~anthropic).
These are not real providers — they already route through openrouter.toml.
The generated ~anthropic.toml was confusing (looked like a stale backup)
and redundant with the existing openrouter provider.

- Delete providers/~anthropic.toml
- Skip provider IDs starting with ~ in sync-pricing.py --create-missing

* fix(providers): remove morph, aider, kwaipilot

- morph: specialized code-editing/patching tool, not a general LLM provider
- aider: CLI meta-tool wrapper (base_url empty), redundant with claude-code/codex-cli/gemini-cli/qwen-code
- kwaipilot: Kwai internal coding assistant routed via OpenRouter, niche

* fix(sync): add morph/aider/kwaipilot to SKIP_PROVIDERS to prevent re-creation

* feat(sync): merge OpenRouter-only providers into openrouter.toml

Instead of generating standalone .toml files that just wrap the OpenRouter
endpoint, merge their models directly into openrouter.toml with the
standard 'openrouter/{provider}/{model}' ID convention.

- Add _build_model_fields() and _model_lines() helpers to deduplicate
  model rendering between standalone and merged paths
- Add merge_into_openrouter() that appends new models idempotently
- generate_provider_toml() now only runs for providers in PROVIDER_API
- --create-missing routes OpenRouter-only providers to merge_into_openrouter

* fix(providers): remove 14 OpenRouter-only standalone files

These providers have no direct public API and all route through
openrouter.ai/api/v1. Per the new sync-pricing.py policy, their models
will be merged into openrouter.toml on the next CI run instead of
living in separate files that just wrap the OpenRouter endpoint.

Removed: allenai, deepcogito, essentialai, inclusionai, inflection,
liquid, meituan, nex-agi, nousresearch, prime-intellect, relace,
switchpoint, tngtech, writer

* fix(providers): remove 7 niche providers with no driver support

No dedicated LLM driver code exists for these providers — they rely
purely on OpenAI-compatible passthrough with no special handling.
Removing them reduces registry noise; users can still reach them via
openrouter.toml if needed.

Removed: microsoft, ibm-granite, xiaomi, upstage, inception, aion-labs, arcee-ai

* fix(providers): remove ai21, chutes, venice

All three use ApiFormat::OpenAI with no special handling — pure passthrough.
No registry entry needed; users can reach them via openrouter.toml or by
adding a custom provider.

* docs(providers): rewrite README with full provider catalog and inclusion criteria

- List all 46 providers grouped by category with descriptions
- Document why each provider exists (direct API, unique endpoint, dedicated driver, local, CLI)
- Add inclusion criteria section explaining when to create standalone files vs merging into openrouter.toml
- Document sync script routing logic
- Update model counts: 49→46 providers, 339→232 models

* docs: add comprehensive READMEs for all registry sections + deepinfra provider

- agents/README.md: 32 agents across 7 categories with capability field reference
- channels/README.md: 44 channels across 5 categories with protocol reference table
- hands/README.md: 18 hands across 5 categories with HAND.toml format guide
- mcp/README.md: 33 MCP servers across 5 categories with transport/auth format
- plugins/README.md: 12 plugins with hook protocol documentation
- skills/README.md: 60 skills across 9 categories with SKILL.md format guide
- providers/deepinfra.toml: add DeepInfra serverless inference (5 models)
This commit is contained in:
Evan authored and GitHub committed 2026-04-24 00:02:33 +09:00
1 parent dbfb32d9d4
commit d43077afa9
38 files changed
+1146 -1215

No files matched your search

+3 -3
View File
@@ -11,8 +11,8 @@ This repository is the **single source of truth** for all installable content de
| [Hands](#hands) | 14 | User-facing "apps" — agent + tools + settings + dashboard | | [Hands](#hands) | 14 | User-facing "apps" — agent + tools + settings + dashboard |
| [Agents](#agents) | 32 | Autonomous agent definitions with model config and tools | | [Agents](#agents) | 32 | Autonomous agent definitions with model config and tools |
| [MCP Servers](#mcp-servers) | 25 | MCP server connections (GitHub, Slack, DBs, etc.) | | [MCP Servers](#mcp-servers) | 25 | MCP server connections (GitHub, Slack, DBs, etc.) |
| [Providers](#providers) | 49 | LLM provider & model metadata with pricing | | [Providers](#providers) | 46 | LLM provider & model metadata with pricing |
| [Models](#providers) | 339 | Individual model definitions across all providers | | [Models](#providers) | 232 | Individual model definitions across all providers |
| [Aliases](#aliases) | 70 | Short names mapped to canonical model IDs | | [Aliases](#aliases) | 70 | Short names mapped to canonical model IDs |
| [Plugins](#plugins) | 10 | Memory, guardrails, and conversation plugins | | [Plugins](#plugins) | 10 | Memory, guardrails, and conversation plugins |
| [Skills](#skills) | 2 | Reusable prompt templates and Python scripts | | [Skills](#skills) | 2 | Reusable prompt templates and Python scripts |
@@ -44,7 +44,7 @@ librefang-registry/
├── providers/ # LLM provider & model metadata ├── providers/ # LLM provider & model metadata
│ ├── anthropic.toml │ ├── anthropic.toml
│ ├── openai.toml │ ├── openai.toml
│ └── ... (49 providers, 339 models) │ └── ... (46 providers, 232 models)
├── plugins/ # Memory, guardrails, and utility plugins ├── plugins/ # Memory, guardrails, and utility plugins
│ ├── episodic-memory/ │ ├── episodic-memory/
│ ├── guardrails/ │ ├── guardrails/
+152 -37
View File
@@ -1,63 +1,178 @@
# Agents # Agents Registry
Autonomous agent definitions for LibreFang. Each agent is a directory containing an `agent.toml` manifest. Agent templates for LibreFang. Each entry is a ready-to-install agent definition with a pre-configured system prompt, model settings, capability declarations, and routing aliases.
## Structure These are the reference agents shipped with the registry. You can install them as-is, override individual fields (model, system_prompt, tools) after installation, or use them as `base` templates inside a Hand.
## File Format
Each agent lives in its own subdirectory containing a single `agent.toml`:
``` ```
agents/ agents/
├── hello-world/agent.toml ├── coder/
├── researcher/agent.toml │ └── agent.toml
├── coder/agent.toml ├── orchestrator/
│ └── agent.toml
└── ... └── ...
``` ```
## agent.toml Format ### agent.toml format
```toml ```toml
name = "agent-name" # Must match directory name name = "coder" # must match directory name
version = "0.1.0" version = "0.4.3-beta3-20260314"
description = "What this agent does" description = "Expert software engineer. Reads, writes, and analyzes code."
author = "author-name" author = "librefang"
module = "builtin:chat" # Runtime module module = "builtin:chat" # runtime module — builtin:chat for all current agents
[model]
provider = "default"
model = "default"
max_tokens = 4096
temperature = 0.7
system_prompt = """Behavioral instructions for the agent."""
[metadata.routing] [metadata.routing]
aliases = ["exact match phrases"] aliases = ["write code", "fix bug", "implement feature"] # exact activation phrases
weak_aliases = ["keyword hints"] weak_aliases = ["refactor", "patch", "code change"] # keyword hints
[model]
provider = "default" # default = use LibreFang's configured primary provider
model = "default"
api_key_env = "GEMINI_API_KEY" # optional override: use this key env var
max_tokens = 8192
temperature = 0.3
system_prompt = """You are Coder, an expert software engineer..."""
[[fallback_models]] # optional: try these providers on failure
provider = "default"
model = "default"
api_key_env = "GROQ_API_KEY"
[schedule] # optional: continuous or cron activation
continuous = { check_interval_secs = 120 }
[resources] [resources]
max_llm_tokens_per_hour = 100000 max_llm_tokens_per_hour = 200000
max_concurrent_tools = 10
[capabilities] [capabilities]
tools = ["web_search", "file_read"] tools = ["file_read", "file_write", "file_list", "shell_exec", "web_search", "web_fetch",
network = ["*"] "memory_store", "memory_recall"]
network = ["*"] # "*" = all, or list specific domains
memory_read = ["*"] memory_read = ["*"]
memory_write = ["self.*"] memory_write = ["self.*"] # "self.*" = own namespace only
shell = ["cargo *", "rustc *", "git *", "npm *", "python *"] # shell command allowlist
agent_spawn = false agent_spawn = false
agent_message = [] # agents this agent may message
[i18n.zh]
name = "编码工程师"
description = "资深软件工程师:阅读、编写与分析代码。"
``` ```
## Current Agents (33) ## Installing and Using Agents
| Agent | Description | ```bash
|-------|-------------| # List all available agent templates
| assistant | Default conversational assistant | librefang catalog agents
| researcher | Deep research with web search |
| coder | Code generation and editing | # Install an agent from the registry
| hello-world | Friendly greeting agent for new users | librefang agent install coder
| ... | See each directory for details |
# Install with a custom name
librefang agent install coder --name my-coder
# List installed agents
librefang agent list
# Send a message to an installed agent
librefang agent message coder "Implement a binary search function in Rust"
# Remove an agent
librefang agent remove my-coder
```
Agents can also be used as base templates in a Hand by setting `base = "coder"` in `HAND.toml`.
## All Agents (33 total)
### Development
| Name | Description | Key Tools |
|------|-------------|-----------|
| architect | System architect. Designs software architectures, evaluates trade-offs, creates technical specifications. | file_read, file_write, web_search, web_fetch |
| code-reviewer | Senior code reviewer. Reviews PRs, identifies issues, suggests improvements with production standards. | file_read, shell_exec, web_search |
| coder | Expert software engineer. Reads, writes, and analyzes code. | file_read, file_write, shell_exec, web_search |
| debugger | Expert debugger. Traces bugs, analyzes stack traces, performs root cause analysis. | file_read, shell_exec, web_search |
| devops-lead | DevOps lead. Manages CI/CD, infrastructure, deployments, monitoring, and incident response. | shell_exec, file_read, web_search |
| ops | DevOps agent. Monitors systems, runs diagnostics, manages deployments. | shell_exec, file_read, web_search |
| test-engineer | Quality assurance engineer. Designs test strategies, writes tests, validates correctness. | file_read, file_write, shell_exec |
### Research and Analysis
| Name | Description | Key Tools |
|------|-------------|-----------|
| academic-researcher | Academic research agent. Searches scholarly papers, summarizes findings, and generates literature reviews. | web_search, web_fetch, file_write |
| analyst | Data analyst. Processes data, generates insights, creates reports. | file_read, web_search, web_fetch |
| data-scientist | Data scientist. Analyzes datasets, builds models, creates visualizations, performs statistical analysis. | file_read, file_write, shell_exec |
| researcher | Research agent. Fetches web content and synthesizes information. | web_search, web_fetch, memory_store |
### Writing and Documentation
| Name | Description | Key Tools |
|------|-------------|-----------|
| doc-writer | Technical writer. Creates documentation, README files, API docs, tutorials, and architecture guides. | file_read, file_write, web_fetch |
| writer | Content writer. Creates documentation, articles, and technical writing. | file_read, file_write, web_search |
### Orchestration
| Name | Description | Key Capabilities |
|------|-------------|-----------------|
| orchestrator | Meta-agent that decomposes complex tasks, delegates to specialist agents, and synthesizes results. | agent_spawn, agent_send, agent_list, agent_kill |
| planner | Project planner. Creates project plans, breaks down epics, estimates effort, identifies risks and dependencies. | file_read, file_write, web_search |
### Business and Operations
| Name | Description | Key Tools |
|------|-------------|-----------|
| customer-support | Customer support agent for ticket handling, issue resolution, and customer communication. | memory_store, memory_recall, web_search |
| email-assistant | Email triage, drafting, scheduling, and inbox management agent. | memory_store, memory_recall, file_write |
| legal-assistant | Legal assistant agent for contract review, legal research, compliance checking, and document drafting. | file_read, file_write, web_search |
| meeting-assistant | Meeting notes, action items, agenda preparation, and follow-up tracking agent. | memory_store, memory_recall, file_write |
| recruiter | Recruiting agent for resume screening, candidate outreach, job description writing, and hiring pipeline management. | web_search, file_read, memory_store |
| sales-assistant | Sales assistant agent for CRM updates, outreach drafting, pipeline management, and deal tracking. | memory_store, memory_recall, web_search |
| security-auditor | Security specialist. Reviews code for vulnerabilities, checks configurations, performs threat modeling. | file_read, shell_exec, web_search |
### Personal Productivity
| Name | Description | Key Tools |
|------|-------------|-----------|
| assistant | General-purpose assistant agent. The default agent for everyday tasks, questions, and conversations. | file_read, file_write, web_search, memory_store |
| health-tracker | Wellness tracking agent for health metrics, medication reminders, fitness goals, and lifestyle habits. | memory_store, memory_recall, file_write |
| hello-world | A friendly greeting agent that can read files, search the web, and answer everyday questions. | file_read, web_search, web_fetch |
| home-automation | Smart home control agent for IoT device management, automation rules, and home monitoring. | shell_exec, memory_store, web_fetch |
| personal-finance | Personal finance agent for budget tracking, expense analysis, savings goals, and financial planning. | file_read, memory_store, web_search |
| recipe-assistant | Cooking assistant that helps with recipes, meal plans, ingredient substitutions, and portion adjustments. | web_search, memory_recall, file_write |
| social-media | Social media content creation, scheduling, and engagement strategy agent. | web_fetch, web_search, file_write |
| translator | Multi-language translation agent for document translation, localization, and cross-cultural communication. | file_read, file_write, web_fetch |
| travel-planner | Trip planning agent for itinerary creation, booking research, budget estimation, and travel logistics. | web_search, web_fetch, memory_store |
| tutor | Teaching and explanation agent for learning, tutoring, and educational content creation. | web_search, memory_recall, file_write |
## Capability Reference
| Capability field | Values | Effect |
|-----------------|--------|--------|
| `tools` | list of tool names | Which built-in tools the agent may invoke |
| `network` | `["*"]` or domain list | Outbound HTTP domain allowlist |
| `memory_read` | `["*"]` or namespace list | Which memory namespaces the agent can read |
| `memory_write` | `["self.*"]` or `["*"]` | Which memory namespaces the agent can write |
| `shell` | glob patterns | Shell command allowlist (e.g. `"cargo *"`) |
| `agent_spawn` | `true` / `false` | Whether the agent can spawn child agents |
| `agent_message` | `["*"]` or agent name list | Which agents this agent may send messages to |
## Adding a New Agent ## Adding a New Agent
1. Create `agents/<name>/agent.toml` 1. Create `agents/<name>/agent.toml` — `name` must match the directory name.
2. Ensure `name` matches the directory name 2. Set `module = "builtin:chat"` unless you have a custom runtime module.
3. Run `python scripts/validate.py` 3. Write a focused `system_prompt` — clear role definition, methodology, and constraints.
4. Submit a PR 4. Declare only the tools and capabilities the agent actually needs.
5. Add `[metadata.routing]` aliases so the router can activate the agent by intent.
6. Run `python scripts/validate.py`.
7. Submit a PR.
See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide. See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide.
+142 -3
View File
@@ -1,7 +1,146 @@
# Channel Adapters Registry # Channel Adapters Registry
This directory contains TOML metadata files for all supported LibreFang channel adapters. Channel adapters connect LibreFang agents to external messaging platforms. Each adapter in this directory is a flat `.toml` file describing the platform, its communication protocol, and any credentials required to operate.
Each `.toml` file describes a single channel adapter including its name, description, category, protocol, and relevant links. These files are used by the LibreFang registry to discover and display available channel integrations. Once a channel is configured, agents can receive messages from and send messages to that platform without any code changes — the adapter handles protocol translation.
See `../templates/channel.toml` for the file format template. ## File Format
Each channel is a single `.toml` file. The filename (without `.toml`) must match the `id` field.
```toml
id = "telegram"
name = "Telegram"
description = "Telegram Bot API adapter for sending and receiving messages"
category = "messaging" # messaging | enterprise | social | developer | iot
tags = ["popular"]
icon = "lucide:smartphone"
protocol = "bot-api" # see Protocol Reference below
[i18n.zh]
name = "Telegram"
description = "Telegram Bot API 适配器,收发消息"
[metadata]
url = "https://telegram.org"
docs = "https://core.telegram.org/bots/api"
```
## Protocol Reference
| Protocol | Description |
|----------|-------------|
| `bot-api` | Platform-specific bot HTTP API (e.g. Telegram Bot API) |
| `websocket` | Long-lived WebSocket connection (e.g. Slack RTM, Discord Gateway) |
| `webhook` | Agent receives POST requests from the platform |
| `rest-api` | Polling or push via generic HTTP REST |
| `imap` | Email protocols (IMAP for receive, SMTP for send) |
| `irc` | Internet Relay Chat protocol |
| `matrix` | Matrix client-server API |
| `mqtt` | MQTT pub/sub protocol for IoT messaging |
| `xmpp` | Extensible Messaging and Presence Protocol |
## Configuring a Channel
```bash
# List all available channel adapters
librefang catalog channels
# Install a channel adapter
librefang channel install telegram
# Configure credentials for a channel
librefang channel configure telegram
# Attach a channel to an agent
librefang channel attach telegram --agent assistant
# List configured channels
librefang channel list
# Remove a channel
librefang channel remove telegram
```
## All Channel Adapters (45 total)
### Messaging
| ID | Name | Protocol | Description |
|----|------|----------|-------------|
| discord | Discord | websocket | Discord bot adapter for sending and receiving messages in Discord servers and channels |
| email | Email | imap | Email adapter for sending and receiving messages via SMTP and IMAP protocols |
| irc | IRC | irc | IRC adapter for connecting to Internet Relay Chat networks and channels |
| keybase | Keybase | rest-api | Keybase adapter for encrypted messaging via the Keybase chat API |
| line | LINE | webhook | LINE Messaging API adapter for sending and receiving messages on the LINE platform |
| matrix | Matrix | matrix | Matrix adapter for decentralized messaging via the Matrix client-server API |
| messenger | Facebook Messenger | webhook | Facebook Messenger adapter for sending and receiving messages via the Messenger Platform |
| nostr | Nostr | websocket | Nostr adapter for publishing and reading events on the Nostr decentralized protocol |
| qq | QQ | websocket | QQ bot adapter for messaging within Tencent QQ groups and channels |
| signal | Signal | rest-api | Signal adapter for secure end-to-end encrypted messaging via Signal CLI |
| telegram | Telegram | bot-api | Telegram Bot API adapter for sending and receiving messages |
| threema | Threema | rest-api | Threema Gateway adapter for secure messaging via the Threema platform |
| viber | Viber | webhook | Viber bot adapter for sending and receiving messages via the Viber Bot API |
| wechat | WeChat | rest-api | WeChat Official Account adapter for messaging on the WeChat platform |
| whatsapp | WhatsApp | rest-api | WhatsApp Business API adapter for sending and receiving messages on WhatsApp |
| xmpp | XMPP | xmpp | XMPP adapter for messaging via the Extensible Messaging and Presence Protocol |
### Enterprise
| ID | Name | Protocol | Description |
|----|------|----------|-------------|
| dingtalk | DingTalk | webhook | DingTalk bot adapter for sending messages to DingTalk groups and conversations |
| feishu | Feishu (Lark) | webhook | Feishu (Lark) bot adapter for messaging within the Feishu collaboration platform |
| flock | Flock | webhook | Flock bot adapter for team messaging and notifications in Flock workspaces |
| google_chat | Google Chat | webhook | Google Chat adapter for sending messages and cards to Google Workspace conversations |
| guilded | Guilded | websocket | Guilded bot adapter for messaging in Guilded servers and channels |
| mattermost | Mattermost | websocket | Mattermost adapter for team messaging and notifications in Mattermost workspaces |
| pumble | Pumble | webhook | Pumble adapter for team messaging and notifications in Pumble workspaces |
| rocketchat | Rocket.Chat | rest-api | Rocket.Chat adapter for messaging in self-hosted Rocket.Chat instances |
| slack | Slack | websocket | Slack bot adapter for sending and receiving messages in Slack workspaces |
| teams | Microsoft Teams | webhook | Microsoft Teams adapter for messaging and notifications in Teams channels |
| twist | Twist | rest-api | Twist adapter for async team communication in Twist workspaces |
| webex | Cisco Webex | webhook | Cisco Webex adapter for messaging and notifications in Webex spaces |
| wecom | WeCom (WeChat Work) | webhook | WeCom (WeChat Work) adapter for enterprise messaging within WeCom organizations |
| zulip | Zulip | rest-api | Zulip adapter for topic-based team messaging in Zulip organizations |
### Social
| ID | Name | Protocol | Description |
|----|------|----------|-------------|
| bluesky | Bluesky | rest-api | Bluesky AT Protocol adapter for posting and reading from the decentralized social network |
| linkedin | LinkedIn | rest-api | LinkedIn adapter for posting updates and messages via the LinkedIn API |
| mastodon | Mastodon | rest-api | Mastodon adapter for posting toots and reading timelines on Mastodon instances |
| reddit | Reddit | rest-api | Reddit adapter for posting and reading content via the Reddit API |
| twitch | Twitch | irc | Twitch adapter for reading and sending messages in Twitch stream chats |
### Developer
| ID | Name | Protocol | Description |
|----|------|----------|-------------|
| discourse | Discourse | rest-api | Discourse forum adapter for posting topics and replies via the Discourse API |
| gitter | Gitter | rest-api | Gitter adapter for developer chat rooms linked to GitHub repositories |
| revolt | Revolt | websocket | Revolt adapter for messaging in the open-source Revolt chat platform |
| webhook | Webhook | webhook | Generic webhook adapter for sending and receiving messages via HTTP callbacks |
### IoT / Self-Hosted
| ID | Name | Protocol | Description |
|----|------|----------|-------------|
| gotify | Gotify | rest-api | Gotify adapter for sending push notifications to a self-hosted Gotify server |
| mqtt | MQTT | mqtt | MQTT adapter for publishing and subscribing to messages on MQTT brokers |
| mumble | Mumble | websocket | Mumble adapter for text messaging in Mumble voice communication servers |
| nextcloud | Nextcloud Talk | rest-api | Nextcloud Talk adapter for messaging within self-hosted Nextcloud instances |
| ntfy | ntfy | rest-api | ntfy adapter for sending push notifications via the ntfy pub-sub service |
## Adding a New Channel Adapter
1. Create `channels/<name>.toml` — the filename must match the `id` field.
2. Set `category` to one of: `messaging`, `enterprise`, `social`, `developer`, `iot`.
3. Set `protocol` to the appropriate value from the Protocol Reference table above.
4. Add `[metadata]` with `url` and `docs` links.
5. Add `[i18n.*]` blocks for supported locales.
6. Run `python scripts/validate.py`.
7. Submit a PR.
See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide.
+164 -97
View File
@@ -1,130 +1,197 @@
# Hands # Hands Registry
Hand definitions for LibreFang. Hands are pre-packaged capability bundles that compose **agents**, **tools**, **skills**, **MCP servers**, **workflows**, and **plugins** into a working application. Hands are pre-packaged capability bundles that compose agents, tools, skills, MCP servers, and plugins into a working application. Installing a hand gives you a complete, ready-to-use workflow — not just a single agent.
> "You have many hands helping you." > "You have many hands helping you."
## Structure A hand can contain one agent (single-agent) or multiple coordinated agents (multi-agent). Each agent in a multi-agent hand can have its own role-specific skills, model config, and capability restrictions.
## File Format
Each hand lives in its own subdirectory:
``` ```
hands/ hands/
├── researcher/
│ ├── HAND.toml # required: hand definition
│ └── SKILL.md # optional: shared reference knowledge for all agents
├── devteam/ ├── devteam/
│ ├── HAND.toml # Hand definition
│ ├── SKILL-pm.md # Per-agent reference knowledge (PM)
│ ├── SKILL-engineer.md # Per-agent reference knowledge (Engineer)
│ └── SKILL-qa.md # Per-agent reference knowledge (QA)
├── browser/
│ ├── HAND.toml │ ├── HAND.toml
│ └── SKILL.md # Shared reference knowledge (all agents) │ ├── SKILL-pm.md # optional: role-specific knowledge for PM agent
└── ... │ ├── SKILL-engineer.md # optional: role-specific knowledge for Engineer agent
│ └── SKILL-qa.md # optional: role-specific knowledge for QA agent
``` ```
## Composition Model ### HAND.toml format
A hand composes registry resources — it doesn't reinvent them:
| Resource | How to compose | Example |
|----------|----------------|---------|
| **Agent templates** | `base = "coder"` on `[agents.*]` | Inherit prompt, model config, fallbacks from `agents/coder/agent.toml` |
| **Tools** | `tools = [...]` at hand level | All agents get these built-in tools |
| **Skills** | `skills = [...]` at hand level | Skill allowlist (empty = all) |
| **MCP servers** | `mcp_servers = [...]` at hand level | Agent interacts via MCP tools, not hardcoded API calls |
| **Workflows** | `workflow_run` tool in agent prompts | Agent calls `workflow_run bug-triage` at runtime |
| **Plugins** | `allowed_plugins = [...]` at hand level | Plugin allowlist (empty = all) |
| **Per-agent skills** | `SKILL-{role}.md` files | Different reference knowledge per agent role |
| **Per-agent capabilities** | `[agents.*.capabilities]` | Fine-grained shell/network/memory per agent |
## HAND.toml Format
```toml ```toml
id = "hand-id" id = "researcher"
name = "Hand Name" version = "1.1.1"
description = "What this hand does" name = "Researcher Hand"
category = "development" description = "Autonomous deep researcher — exhaustive investigation, cross-referencing, fact-checking, and structured reports"
icon = "🔧" category = "productivity" # productivity | development | data | content | communication
icon = "lucide:flask-conical"
# ─── Resource composition ──────────────────────────────────── # Tools available to all agents in this hand
tools = ["shell_exec", "file_read", "web_fetch", "workflow_run"] tools = [
mcp_servers = ["github", "sentry"] "shell_exec", "file_read", "file_write", "web_fetch", "web_search",
skills = [] # empty = all "memory_store", "memory_recall", "knowledge_query", "event_publish",
allowed_plugins = ["todo-tracker"] ]
# ─── Requirements ──────────────────────────────────────────── # MCP servers all agents can use
[[requires]] mcp_servers = ["github"]
key = "git"
requirement_type = "binary"
check_value = "git"
# ─── Settings ──────────────────────────────────────────────── # Skills allowlist (empty = all available)
[[settings]] skills = []
key = "repo_url"
setting_type = "text"
default = ""
# ─── Agents ────────────────────────────────────────────────── # Plugin allowlist
allowed_plugins = ["todo-tracker", "auto-summarizer"]
# Multi-agent with base template inheritance: # ─── Routing ──────────────────────────────────────────────────────────────────
[agents.main]
coordinator = true
base = "planner" # inherits from agents/planner/agent.toml
invoke_hint = "Task coordination"
[agents.main.model]
system_prompt = """Custom prompt for this hand..."""
[agents.main.capabilities]
shell = ["gh *", "git *"] # preserved by kernel (not overwritten)
# Single-agent (legacy):
# [agent]
# name = "my-agent"
# system_prompt = """..."""
# ─── Routing ─────────────────────────────────────────────────
[routing] [routing]
aliases = ["activate phrases"] aliases = ["deep research", "investigate", "fact check"] # exact activation phrases
weak_aliases = ["keyword hints"] weak_aliases = ["research", "look into"] # keyword hints
# ─── Dashboard ─────────────────────────────────────────────── # ─── Configurable settings ────────────────────────────────────────────────────
[[settings]]
key = "research_depth"
label = "Research Depth"
description = "How exhaustive each investigation should be"
setting_type = "select" # select | toggle | text
default = "thorough"
[[settings.options]]
value = "quick"
label = "Quick (5-10 sources, 1 pass)"
[[settings.options]]
value = "thorough"
label = "Thorough (20-30 sources, cross-referenced)"
# ─── Single-agent definition ──────────────────────────────────────────────────
[agent]
name = "researcher"
base = "researcher" # inherits from agents/researcher/agent.toml
[agent.model]
system_prompt = """Custom prompt override..."""
# ─── Multi-agent definition (alternative to [agent]) ─────────────────────────
[agents.pm]
coordinator = true
base = "planner" # inherits from agents/planner/agent.toml
invoke_hint = "Task coordination and issue triage"
[agents.engineer]
base = "coder"
invoke_hint = "Implementation"
[agents.qa]
base = "test-engineer"
invoke_hint = "Quality assurance and validation"
# ─── Dashboard metrics ────────────────────────────────────────────────────────
[dashboard] [dashboard]
[[dashboard.metrics]] [[dashboard.metrics]]
label = "Tasks Done" label = "Reports Written"
memory_key = "metric_key" memory_key = "metric_reports_written"
format = "number" format = "number"
# ─── i18n ──────────────────────────────────────────────────── # ─── i18n ─────────────────────────────────────────────────────────────────────
[i18n.zh] [i18n.zh]
name = "中文名" name = "研究员"
description = "中文描述" description = "自主深度研究员 — 详尽调查、交叉核实、事实核查与结构化报告"
``` ```
## Current Hands (15) ## Installing and Using Hands
| Hand | Category | Agents | Description | ```bash
|------|----------|--------|-------------| # List all available hands
| analytics | data | multi | Data analytics, visualization, and automated reporting | librefang catalog hands
| apitester | development | single | API testing, endpoint discovery, and load testing |
| browser | productivity | single | Web navigation, form filling, and multi-step web tasks | # Install a hand
| clip | content | multi | Long-form video to short clips with captions | librefang hand install researcher
| collector | data | multi | Intelligence collection and change detection |
| **devteam** | **development** | **multi** | **Autonomous dev team — PM + Engineer + QA with base templates** | # Install with a specific agent name
| devops | development | multi | CI/CD management, monitoring, and incident response | librefang hand install researcher --name my-researcher
| lead | data | multi | Lead generation, enrichment, and scoring |
| linkedin | communication | multi | LinkedIn content creation and networking | # List installed hands
| predictor | data | single | Signal collection and calibrated predictions | librefang hand list
| reddit | communication | multi | Subreddit monitoring and content posting |
| researcher | productivity | multi | Deep research, fact-checking, and reports | # Remove a hand
| strategist | productivity | multi | Market research and competitive analysis | librefang hand remove my-researcher
| trader | data | multi | Market intelligence and risk management | ```
| twitter | communication | multi | Twitter/X content creation and scheduling |
## All Hands (18 total)
### Productivity
| ID | Name | Category | Description |
|----|------|----------|-------------|
| researcher | Researcher Hand | productivity | Autonomous deep researcher — exhaustive investigation, cross-referencing, fact-checking, and structured reports |
| strategist | Strategist Hand | productivity | Autonomous strategy analyst — market research, competitive analysis, business planning, and strategic recommendations |
| wiki | Wiki Hand | productivity | LLM-maintained personal knowledge base — builds an Obsidian-compatible wiki from raw sources with provenance tracking |
| browser | Browser Hand | productivity | Autonomous web browser — navigates sites, fills forms, clicks buttons, and completes multi-step web tasks |
### Development
| ID | Name | Category | Description |
|----|------|----------|-------------|
| devteam | Dev Team | development | Autonomous software development team — PM triages issues, Engineer implements, QA validates |
| devops | DevOps Hand | development | Autonomous DevOps engineer — CI/CD management, infrastructure monitoring, deployment automation, and incident response |
| apitester | API Tester Hand | development | Autonomous API testing agent — endpoint discovery, request validation, load testing, and regression detection |
### Data
| ID | Name | Category | Description |
|----|------|----------|-------------|
| analytics | Analytics Hand | data | Autonomous data analytics agent — data collection, analysis, visualization, dashboards, and automated reporting |
| collector | Collector Hand | data | Autonomous intelligence collector — monitors any target continuously with change detection and knowledge graphs |
| lead | Lead Hand | data | Autonomous lead generation — discovers, enriches, and delivers qualified leads on a schedule |
| predictor | Predictor Hand | data | Autonomous future predictor — collects signals, builds reasoning chains, makes calibrated predictions, and tracks accuracy |
| trader | Trading Hand | data | Autonomous market intelligence and trading engine — multi-signal analysis, adversarial bull/bear reasoning, and strict risk management |
### Content
| ID | Name | Category | Description |
|----|------|----------|-------------|
| clip | Clip Hand | content | Turns long-form video into viral short clips with captions and thumbnails |
| creator | Creator Hand | content | AI media studio — generates images, videos, music, and speech from text prompts |
### Communication
| ID | Name | Category | Description |
|----|------|----------|-------------|
| linkedin | LinkedIn Hand | communication | Autonomous LinkedIn manager — profile optimization, content creation, networking, and professional engagement |
| reddit | Reddit Hand | communication | Autonomous Reddit manager — monitors subreddits, posts content, replies to threads, and tracks engagement |
| twitter | Twitter Hand | communication | Autonomous Twitter/X manager — content creation, scheduled posting, engagement, and performance tracking |
### Data (additional)
| ID | Name | Category | Description |
|----|------|----------|-------------|
| clip | Clip Hand | content | Turns long-form video into viral short clips with captions and thumbnails |
## Resource Composition Summary
| Resource | How to compose | Notes |
|----------|----------------|-------|
| Agent templates | `base = "coder"` on `[agents.*]` | Inherits prompt, model config, fallbacks from `agents/coder/agent.toml` |
| Tools | `tools = [...]` at hand level | All agents in the hand share these built-in tools |
| Skills | `skills = [...]` at hand level | Empty list means all available skills are allowed |
| MCP servers | `mcp_servers = [...]` at hand level | Agent interacts via MCP tools, not hardcoded API calls |
| Plugins | `allowed_plugins = [...]` at hand level | Empty list means all installed plugins are allowed |
| Per-agent knowledge | `SKILL-{role}.md` files | Different reference prompts per agent role |
| Per-agent capabilities | `[agents.*.capabilities]` | Fine-grained shell / network / memory per agent |
## Adding a New Hand ## Adding a New Hand
1. Create `hands/<name>/HAND.toml` 1. Create `hands/<name>/HAND.toml` with at least `id`, `name`, `description`, and `category`.
2. Add `SKILL.md` (shared) or `SKILL-{role}.md` (per-agent) for reference knowledge 2. Add `SKILL.md` (shared) or `SKILL-{role}.md` (per-agent) files for reference knowledge.
3. Use `base = "agent-name"` to inherit from existing agent templates in `agents/` 3. Use `base = "agent-name"` in each `[agents.*]` block to inherit from existing agent templates.
4. Set `mcp_servers`, `skills`, `allowed_plugins` for resource composition 4. Specify `mcp_servers`, `skills`, and `allowed_plugins` for resource composition.
5. Ensure `id` matches the directory name 5. Ensure `id` matches the directory name.
6. Submit a PR 6. Run `python scripts/validate.py`.
7. Submit a PR.
See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide. See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide.
+121 -43
View File
@@ -1,70 +1,148 @@
# MCP Servers # MCP Servers Registry
MCP (Model Context Protocol) server templates for LibreFang. Each entry connects LibreFang to an external service (GitHub, Slack, databases, etc.). MCP (Model Context Protocol) servers connect LibreFang agents to external services. Each entry in this directory is a single `.toml` file describing an MCP server: how to launch it, what credentials it requires, and which category of functionality it provides.
## Structure When an agent has an MCP server attached, the server's tools appear automatically in the agent's tool list alongside built-in tools like `file_read` and `web_search`.
``` ## File Format
mcp/
├── github.toml
├── slack.toml
├── postgresql.toml
└── ...
```
## MCP Server TOML Format Each MCP server is a flat `.toml` file. The filename (without `.toml`) must match the `id` field.
```toml ```toml
id = "service-id" # Must match filename (without .toml) id = "github" # must match filename
name = "Service Name" name = "GitHub"
description = "What this MCP server provides" description = "Access GitHub repos, issues, PRs, and organizations"
category = "devtools" # devtools | communication | storage | monitoring | data category = "devtools" # devtools | data | cloud | communication | productivity | ai
icon = "🐙" icon = "lucide:github"
tags = ["relevant", "tags"] tags = ["git", "vcs", "code"]
[transport] # MCP server transport config [transport]
type = "stdio" # "stdio" or "sse" type = "stdio" # stdio | sse
command = "npx" command = "npx"
args = ["-y", "@pkg/mcp-server"] args = ["-y", "@modelcontextprotocol/server-github@2025.4.8"]
[[required_env]] # Required environment variables [[required_env]] # repeat block for each required credential
name = "SERVICE_API_KEY" name = "GITHUB_PERSONAL_ACCESS_TOKEN"
label = "API Key" label = "GitHub Personal Access Token"
help = "How to obtain this key" help = "A fine-grained or classic PAT with repo and read:org scopes"
is_secret = true is_secret = true
get_url = "https://..." get_url = "https://github.com/settings/tokens"
[oauth] # Optional: OAuth config [oauth] # optional: OAuth flow config
provider = "github" provider = "github"
scopes = ["repo"] scopes = ["repo", "read:org"]
auth_url = "https://..." auth_url = "https://github.com/login/oauth/authorize"
token_url = "https://..." token_url = "https://github.com/login/oauth/access_token"
[health_check] [health_check]
interval_secs = 60 interval_secs = 60
unhealthy_threshold = 3 unhealthy_threshold = 3
setup_instructions = """ setup_instructions = """
Step-by-step setup guide for users. 1. Go to https://github.com/settings/tokens and create a Personal Access Token.
2. Paste the token into the GITHUB_PERSONAL_ACCESS_TOKEN field.
3. Alternatively, use the OAuth flow to authorize LibreFang directly.
""" """
[i18n.zh]
name = "GitHub"
description = "通过官方 MCP 服务器访问 GitHub 仓库、Issue、Pull Request 与组织。"
``` ```
## Current MCP Servers (25) ## Installing an MCP Server
| MCP Server | Category | Service | ```bash
|------------|----------|---------| # List all available MCP servers
| github | devtools | GitHub repos, issues, PRs | librefang catalog mcp
| slack | communication | Slack messaging |
| notion | productivity | Notion pages and databases | # Install an MCP server and attach it to an agent
| postgresql | storage | PostgreSQL database | librefang mcp install github
| ... | | See each file for details | librefang mcp attach github --agent coder
# Or specify the agent when installing
librefang mcp install github --agent coder
# Set required credentials
librefang config set-env GITHUB_PERSONAL_ACCESS_TOKEN ghp_xxx
# List attached MCP servers for an agent
librefang mcp list --agent coder
# Remove an MCP server from an agent
librefang mcp detach github --agent coder
```
## All MCP Servers (33 total)
### Development Tools (devtools)
| ID | Name | Transport | Credentials Required | Description |
|----|------|-----------|---------------------|-------------|
| bitbucket | Bitbucket | stdio (npx) | `BITBUCKET_*` | Access Bitbucket repositories, pull requests, and pipelines |
| fetch | Fetch | stdio (npx) | none | Fetch any web URL and receive its content as clean Markdown |
| filesystem | Filesystem | stdio (npx) | none | Read, write, search, and manage local files |
| git | Git | stdio (npx) | none | Inspect local Git repos — commits, diffs, branches, blame |
| github | GitHub | stdio (npx) | `GITHUB_PERSONAL_ACCESS_TOKEN` | Access GitHub repos, issues, PRs, and organizations |
| gitlab | GitLab | stdio (npx) | `GITLAB_*` | Access GitLab projects, MRs, issues, and CI/CD pipelines |
| jira | Jira | stdio (npx) | `JIRA_*` | Access Jira issues, projects, boards, and sprints |
| linear | Linear | stdio (npx) | `LINEAR_API_KEY` | Manage Linear issues, projects, cycles, and teams |
| puppeteer | Puppeteer | stdio (npx) | none | Control headless Chrome — navigate, screenshot, scrape |
| sentry | Sentry | stdio (npx) | `SENTRY_AUTH_TOKEN` | Monitor Sentry error tracking, issues, and releases |
### Data
| ID | Name | Transport | Credentials Required | Description |
|----|------|-----------|---------------------|-------------|
| elasticsearch | Elasticsearch | stdio (npx) | `ELASTICSEARCH_*` | Search and manage Elasticsearch indices and documents |
| google-maps | Google Maps | stdio (npx) | `GOOGLE_MAPS_API_KEY` | Geocoding, directions, distance matrix, and place search |
| mongodb | MongoDB | stdio (npx) | `MONGODB_CONNECTION_STRING` | Query and manage MongoDB databases and collections |
| postgresql | PostgreSQL | stdio (npx) | `POSTGRES_CONNECTION_STRING` | Query and manage PostgreSQL databases |
| redis | Redis | stdio (npx) | `REDIS_URL` | Access and manage Redis key-value stores |
| sqlite-mcp | SQLite | stdio (npx) | none | Query and manage local SQLite databases |
### Cloud
| ID | Name | Transport | Credentials Required | Description |
|----|------|-----------|---------------------|-------------|
| aws | AWS | stdio (npx) | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` | Manage S3, EC2, Lambda, and other AWS resources |
| azure-mcp | Azure | stdio (npx) | `AZURE_*` | Manage Azure VMs, Storage, and App Services |
| gcp-mcp | GCP | stdio (npx) | `GOOGLE_APPLICATION_CREDENTIALS` | Manage GCP Compute, Cloud Storage, and BigQuery |
### Communication
| ID | Name | Transport | Credentials Required | Description |
|----|------|-----------|---------------------|-------------|
| discord-mcp | Discord | stdio (npx) | `DISCORD_TOKEN` | Access Discord servers, channels, and messages |
| slack | Slack | stdio (npx) | `SLACK_BOT_TOKEN` | Access Slack channels, messages, and users |
| teams-mcp | Microsoft Teams | stdio (npx) | `TEAMS_*` | Access Teams channels, chats, and messages |
### Productivity
| ID | Name | Transport | Credentials Required | Description |
|----|------|-----------|---------------------|-------------|
| dropbox | Dropbox | stdio (npx) | `DROPBOX_ACCESS_TOKEN` | Access and manage Dropbox files and folders |
| gmail | Gmail | stdio (npx) | `GMAIL_*` | Read, send, and manage Gmail messages and drafts |
| google-calendar | Google Calendar | stdio (npx) | `GOOGLE_*` | Manage Google Calendar events and availability |
| google-drive | Google Drive | stdio (npx) | `GOOGLE_*` | Browse, search, and read files from Google Drive |
| notion | Notion | stdio (npx) | `NOTION_API_KEY` | Access and manage Notion pages, databases, and blocks |
| time | Time | stdio (npx) | none | Get current time, convert timezones, calculate differences |
| todoist | Todoist | stdio (npx) | `TODOIST_API_TOKEN` | Manage Todoist tasks, projects, and labels |
### AI
| ID | Name | Transport | Credentials Required | Description |
|----|------|-----------|---------------------|-------------|
| brave-search | Brave Search | stdio (npx) | `BRAVE_API_KEY` | Perform web searches using the Brave Search API |
| exa-search | Exa Search | stdio (npx) | `EXA_API_KEY` | AI-powered neural search and web content retrieval |
| memory | Memory | stdio (npx) | none | Persistent knowledge graph for facts and relationships across sessions |
| sequential-thinking | Sequential Thinking | stdio (npx) | none | Structured multi-step reasoning with revisable thought chains |
## Adding a New MCP Server ## Adding a New MCP Server
1. Create `mcp/<name>.toml` 1. Create `mcp/<name>.toml` — the filename must match the `id` field.
2. Ensure `id` matches the filename 2. Test the transport command locally: run `npx -y <package>` and verify it starts without errors.
3. Test the MCP server command locally 3. List all `[[required_env]]` entries so the UI can prompt users for credentials.
4. Run `python scripts/validate.py` 4. Run `python scripts/validate.py`.
5. Submit a PR 5. Submit a PR.
See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide. See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide.
+78 -35
View File
@@ -1,71 +1,114 @@
# Plugins # Plugins Registry
Plugin packages for LibreFang. Plugins extend agent behavior through lifecycle hooks -- they can inject memories, modify context, or perform side effects during conversations. Plugins extend agent behavior through lifecycle hooks. They can inject memories into context before a turn, perform side-effect processing after a turn, or do both. Unlike skills (which add knowledge) or MCP servers (which add tools), plugins run as Python scripts that intercept the agent loop.
## Structure ## File Format
Each plugin lives in its own subdirectory:
``` ```
plugins/ plugins/
└── <plugin-name>/ └── <plugin-name>/
├── plugin.toml # Plugin manifest ├── plugin.toml # required: plugin manifest
├── hooks/ ├── hooks/
│ ├── ingest.py # Called on user message │ ├── ingest.py # called on each incoming user message
│ └── after_turn.py # Called after each turn │ └── after_turn.py # called after each completed agent turn
└── requirements.txt # Python dependencies └── requirements.txt # Python dependencies (prefer stdlib-only)
``` ```
## plugin.toml Format ### plugin.toml format
```toml ```toml
name = "plugin-name" # Must match directory name name = "episodic-memory" # must match directory name
version = "0.1.0" version = "0.1.0"
description = "What this plugin does" description = "Episode-based memory segmentation and recall for cross-conversation context continuity"
author = "author-name" author = "librefang"
[hooks] [hooks]
ingest = "hooks/ingest.py" # Receives user message, can return memories ingest = "hooks/ingest.py" # optional
after_turn = "hooks/after_turn.py" # Post-turn processing after_turn = "hooks/after_turn.py" # optional
[i18n.zh]
name = "情景记忆"
description = "基于情景的记忆分段与召回,实现跨会话的上下文延续。"
``` ```
## Hook Protocol ## Hook Protocol
Hooks communicate via stdin/stdout JSON: Hooks communicate with the agent runtime via stdin/stdout JSON lines.
### ingest hook ### ingest hook
Receives the incoming user message and returns zero or more memory objects to inject into the agent's context for this turn:
``` ```
stdin: {"type": "ingest", "agent_id": "...", "message": "user message"} stdin: {"type": "ingest", "agent_id": "abc123", "session_id": "...", "message": "user message text"}
stdout: {"type": "ingest_result", "memories": [{"content": "..."}]} stdout: {"type": "ingest_result", "memories": [{"content": "Relevant fact from earlier session"}]}
``` ```
### after_turn hook ### after_turn hook
Receives the full turn transcript after the agent responds. Used for persistence (saving summaries, updating profiles, appending logs):
``` ```
stdin: {"type": "after_turn", "agent_id": "...", "messages": [...]} stdin: {"type": "after_turn", "agent_id": "abc123", "session_id": "...", "messages": [...]}
stdout: {"type": "ok"} stdout: {"type": "ok"}
``` ```
## Current Plugins (10) ## Installing and Using Plugins
| Plugin | Hooks | Description | ```bash
|--------|-------|-------------| # List all available plugins
| auto-summarizer | ingest, after_turn | Running conversation summary for long context compression | librefang catalog plugins
| context-decay | ingest, after_turn | Time-based memory decay with relevance scoring for natural forgetting |
| conversation-logger | after_turn | Logs conversations to JSONL files for auditing and analytics | # Install a plugin globally
| episodic-memory | ingest, after_turn | Episode-based conversation segmentation and cross-session recall | librefang plugin install episodic-memory
| guardrails | ingest | Safety filter detecting PII, prompt injection, and credential exposure |
| keyword-memory | ingest | Extracts keywords and named entities as contextual memories | # Enable a plugin for a specific agent
| sentiment-tracker | ingest | Analyzes user sentiment and injects emotional context | librefang plugin enable episodic-memory --agent coder
| todo-tracker | ingest, after_turn | Detects, persists, and recalls action items from conversations |
| topic-memory | ingest, after_turn | Topic-aware keyword clustering with cross-conversation context recall | # Disable a plugin for an agent
| user-profile | ingest, after_turn | Persistent user profiling from conversation patterns for personalization | librefang plugin disable episodic-memory --agent coder
# List plugins active for an agent
librefang plugin list --agent coder
```
Hands can also declare an `allowed_plugins` list in `HAND.toml`, which restricts which installed plugins are active within that hand.
## All Plugins (12 total)
| Name | Version | Hooks | Description |
|------|---------|-------|-------------|
| auto-summarizer | 0.1.0 | ingest, after_turn | Maintains a running conversation summary to help agents handle long conversations without losing context |
| context-decay | 0.1.0 | ingest, after_turn | Time-based memory decay with relevance scoring for natural context forgetting |
| conversation-logger | 0.1.0 | after_turn | Logs all conversations to JSONL files for auditing, analytics, and debugging |
| episodic-memory | 0.1.0 | ingest, after_turn | Episode-based memory segmentation and recall for cross-conversation context continuity |
| guardrails | 0.1.0 | ingest | Safety filter that detects potentially harmful content patterns and injects warnings into agent context |
| keyword-memory | 0.1.0 | ingest | Extracts keywords and named entities from user messages and returns them as contextual memories |
| mempalace-indexer | 0.3.0 | ingest, after_turn | Auto-indexes conversations into MemPalace and recalls relevant memories — no API keys, no cloud |
| sentiment-tracker | 0.1.0 | ingest | Analyzes user message sentiment and injects emotional context so agents can respond with appropriate tone |
| todo-tracker | 0.1.0 | ingest, after_turn | Detects action items and tasks mentioned in conversations, persists them, and recalls them as context |
| topic-memory | 0.1.0 | ingest, after_turn | Topic-aware memory recall with keyword clustering for cross-conversation context |
| user-profile | 0.1.0 | ingest, after_turn | Persistent user profiling from conversation patterns for personalized agent responses |
Note: the `guardrails` and `mempalace-indexer` plugins have no `after_turn` hook; `conversation-logger` has no `ingest` hook.
## Hook Execution Order
For each agent turn, the runtime executes hooks in this order:
1. All `ingest` hooks run (in plugin installation order) — memories are collected and merged
2. Agent turn executes with the injected context
3. All `after_turn` hooks run (in plugin installation order)
## Adding a New Plugin ## Adding a New Plugin
1. Create `plugins/<name>/plugin.toml` 1. Create `plugins/<name>/plugin.toml` with `name`, `version`, `description`, and `[hooks]`.
2. Add hook scripts in `hooks/` 2. Add hook scripts under `hooks/` for each declared hook.
3. List dependencies in `requirements.txt` (prefer stdlib-only) 3. Keep hooks fast (under 500 ms) — they run synchronously on every turn.
4. Run `python scripts/validate.py` 4. List Python dependencies in `requirements.txt`; prefer standard library where possible.
5. Submit a PR 5. Run `python scripts/validate.py`.
6. Submit a PR.
See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide. See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide.
+150 -17
View File
@@ -1,16 +1,123 @@
# Providers # Providers
LLM provider and model metadata for LibreFang. Each provider file defines the provider's API configuration and all available models with pricing, context windows, and capability flags. LLM provider and model metadata for LibreFang. Each `.toml` file defines one provider's API configuration and all its available models with pricing, context windows, and capability flags.
## Structure **Current state: 46 providers, 232+ models**
``` ---
providers/
├── anthropic.toml ## Provider Categories
├── openai.toml
├── groq.toml ### Frontier / Major Cloud APIs
└── ... (46 providers, 220+ models)
``` | ID | Display Name | Base URL | API Key Env | Models | Description |
|----|-------------|----------|-------------|--------|-------------|
| `anthropic` | Anthropic | `https://api.anthropic.com` | `ANTHROPIC_API_KEY` | 7 | Claude family (Haiku / Sonnet / Opus); native Anthropic wire protocol, not OpenAI-compatible |
| `openai` | OpenAI | `https://api.openai.com/v1` | `OPENAI_API_KEY` | 15 | GPT-4.x, o-series reasoning, image generation, TTS; also the fallback for codex-cli |
| `gemini` | Google Gemini | `https://generativelanguage.googleapis.com` | `GEMINI_API_KEY` | 6 | Gemini 2.x family; native Google GenerativeLanguage protocol |
| `xai` | xAI | `https://api.x.ai/v1` | `XAI_API_KEY` | 7 | Grok-3 family from Elon Musk's xAI |
| `mistral` | Mistral AI | `https://api.mistral.ai/v1` | `MISTRAL_API_KEY` | 3 | Mistral Large / Small / Codestral; European frontier models |
| `cohere` | Cohere | `https://api.cohere.com/v2` | `COHERE_API_KEY` | 4 | Command R+ family; strong RAG and tool-use models |
| `deepseek` | DeepSeek | `https://api.deepseek.com/v1` | `DEEPSEEK_API_KEY` | 2 | DeepSeek-V3 (chat) + R1 (reasoning); extremely cost-effective |
| `meta-llama` | Meta Llama | `https://api.llama.com/v1` | `LLAMA_API_KEY` | 4 | Official Meta Llama API — direct access to Llama 3.x |
| `perplexity` | Perplexity AI | `https://api.perplexity.ai` | `PERPLEXITY_API_KEY` | 4 | Sonar family with live web search built in |
### Fast Inference / Compute Clouds
| ID | Display Name | Base URL | API Key Env | Models | Description |
|----|-------------|----------|-------------|--------|-------------|
| `groq` | Groq | `https://api.groq.com/openai/v1` | `GROQ_API_KEY` | 3 | GroqChip hardware; ~10× faster than GPU inference for supported models |
| `cerebras` | Cerebras | `https://api.cerebras.ai/v1` | `CEREBRAS_API_KEY` | 4 | Wafer-scale chip inference; best-in-class throughput for Llama |
| `sambanova` | SambaNova | `https://api.sambanova.ai/v1` | `SAMBANOVA_API_KEY` | 3 | Reconfigurable Dataflow Unit (RDU) inference; fast Llama variants |
| `fireworks` | Fireworks AI | `https://api.fireworks.ai/inference/v1` | `FIREWORKS_API_KEY` | 5 | Serverless open-model hosting; fast cold-start |
| `together` | Together AI | `https://api.together.xyz/v1` | `TOGETHER_API_KEY` | 8 | Open-model hosting (Llama, Qwen, Mistral) + fine-tuning API |
| `nvidia-nim` | NVIDIA NIM | `https://integrate.api.nvidia.com/v1` | `NVIDIA_API_KEY` | 26 | NVIDIA NIM microservices; largest model selection in registry |
| `replicate` | Replicate | `https://api.replicate.com/v1` | `REPLICATE_API_TOKEN` | 3 | Run any model as a serverless API; image + video + LLM |
| `huggingface` | Hugging Face | `https://api-inference.huggingface.co/v1` | `HF_API_KEY` | 3 | HF Serverless Inference API for hosted open models |
### Cloud Platform / Enterprise
| ID | Display Name | Base URL | API Key Env | Models | Description |
|----|-------------|----------|-------------|--------|-------------|
| `bedrock` | AWS Bedrock | `https://bedrock-runtime.us-east-1.amazonaws.com` | `AWS_ACCESS_KEY_ID` | 11 | AWS-managed models (Claude, Llama, Mistral, Nova); IAM auth |
| `vertex-ai` | Google Cloud Vertex AI | `https://us-central1-aiplatform.googleapis.com` | `GOOGLE_APPLICATION_CREDENTIALS` | 6 | GCP-hosted Gemini + third-party models; service account JSON auth |
| `github-copilot` | GitHub Copilot | `https://api.githubcopilot.com` | `GITHUB_TOKEN` | 1 | Uses `ApiFormat::Copilot` — proprietary protocol, not OpenAI-compatible; requires GitHub PAT with Copilot access |
### Aggregators / Routers
| ID | Display Name | Base URL | API Key Env | Models | Description |
|----|-------------|----------|-------------|--------|-------------|
| `openrouter` | OpenRouter | `https://openrouter.ai/api/v1` | `OPENROUTER_API_KEY` | 18+ | Meta-provider routing to 300+ models; also receives models from OpenRouter-only providers via sync script |
| `siliconflow` | SiliconFlow | `https://api.siliconflow.cn/v1` | `SILICONFLOW_API_KEY` | dynamic | 硅基流动 — Chinese open-model hosting; models discovered at runtime, not hardcoded in TOML |
### Chinese Providers
| ID | Display Name | Base URL | API Key Env | Models | Description |
|----|-------------|----------|-------------|--------|-------------|
| `qwen` | Qwen (Alibaba) | `https://dashscope.aliyuncs.com/compatible-mode/v1` | `DASHSCOPE_API_KEY` | 9 | Qwen3 family by Alibaba; multi-region support (`intl` / `us`) via `[provider.regions]` |
| `moonshot` | Moonshot (Kimi) | `https://api.moonshot.ai/v1` | `MOONSHOT_API_KEY` | 5 | Kimi general chat models (moonshot-v1-8k/32k/128k) |
| `minimax` | MiniMax | `https://api.minimax.io/v1` | `MINIMAX_API_KEY` | 8 | MiniMax M-series; strong Chinese + multilingual models |
| `zhipu` | Zhipu AI (GLM) | `https://open.bigmodel.cn/api/paas/v4` | `ZHIPU_API_KEY` | 6 | GLM-4 family by Zhipu AI (智谱); general chat + vision |
| `zai` | Z.AI | `https://api.z.ai/api/paas/v4` | `ZHIPU_API_KEY` | 2 | Z.AI general models; shares API key with zhipu |
| `baichuan` | Baichuan (百川) | `https://api.baichuan-ai.com/v1` | `BAICHUAN_API_KEY` | 2 | Baichuan4 family; strong Chinese-language performance |
| `volcengine` | Volcano Engine (Doubao) | `https://ark.cn-beijing.volces.com/api/v3` | `VOLCENGINE_API_KEY` | 8 | ByteDance Doubao models; Ark platform |
| `stepfun` | Stepfun (阶跃星辰) | `https://api.stepfun.com/v1` | `STEPFUN_API_KEY` | 4 | Step-2 family; strong long-context and reasoning |
| `tencent` | Tencent | `https://api.hunyuan.cloud.tencent.com/v1` | `HUNYUAN_API_KEY` | 1 | Hunyuan models by Tencent |
| `qianfan` | Baidu Qianfan | `https://qianfan.baidubce.com/v2` | `QIANFAN_API_KEY` | 3 | ERNIE family by Baidu; Qianfan platform |
### Coding-Specific Endpoints
Separate `base_url` for coding workloads — not just model aliases. Same API key as the general counterpart.
| ID | Display Name | Base URL | API Key Env | Models | vs. General |
|----|-------------|----------|-------------|--------|-------------|
| `kimi_coding` | Kimi for Code | `https://api.kimi.com/coding` | `KIMI_API_KEY` | 1 | vs `moonshot`: `api.moonshot.ai/v1` |
| `alibaba-coding-plan` | Alibaba Coding Plan (Intl) | `https://coding-intl.dashscope.aliyuncs.com/v1` | `ALIBABA_CODING_PLAN_API_KEY` | 9 | vs `qwen`: `dashscope.aliyuncs.com`; aggregates models from multiple vendors (MiniMax, GLM, Kimi) |
| `volcengine_coding` | Volcano Engine Coding Plan | `https://ark.cn-beijing.volces.com/api/coding/v3` | `VOLCENGINE_API_KEY` | dynamic | vs `volcengine`: `/api/v3`; models discovered at runtime |
| `zhipu_coding` | Zhipu Coding (CodeGeeX) | `https://open.bigmodel.cn/api/coding/paas/v4` | `ZHIPU_API_KEY` | 1 | vs `zhipu`: `/api/paas/v4`; CodeGeeX-4 coding model |
| `zai_coding` | Z.AI Coding | `https://api.z.ai/api/coding/paas/v4` | `ZHIPU_API_KEY` | 2 | vs `zai`: `/api/paas/v4`; GLM coding variants |
### CLI-Based Providers (No API Key)
Route through a locally-installed CLI tool. `key_required = false`, `base_url` is empty. Cost is $0.
| ID | Display Name | CLI Binary | Models | ApiFormat | Description |
|----|-------------|-----------|--------|-----------|-------------|
| `claude-code` | Claude Code | `claude` | 3 | `ClaudeCode` | Anthropic's official CLI; routes through Claude API with OAuth |
| `codex-cli` | Codex CLI | `codex` | 6 | `CodexCli` | OpenAI Codex CLI; also serves as fallback for `openai` provider |
| `gemini-cli` | Gemini CLI | `gemini` | 2 | `GeminiCli` | Google Gemini CLI; also serves as fallback for `gemini` provider |
| `qwen-code` | Qwen Code | `qwen-code` | 3 | `QwenCode` | Alibaba Qwen coding CLI |
### Local / Self-Hosted
| ID | Display Name | Default Base URL | API Key Env | Notes |
|----|-------------|-----------------|-------------|-------|
| `ollama` | Ollama | `http://localhost:11434/v1` | `OLLAMA_API_KEY` | No key required; models discovered dynamically at runtime via `/api/tags` |
| `lmstudio` | LM Studio | `http://localhost:1234/v1` | `LMSTUDIO_API_KEY` | No key required; GUI app for running GGUF models locally |
| `vllm` | vLLM | `http://localhost:8000/v1` | `VLLM_API_KEY` | No key required; high-throughput inference server for production self-hosting |
### Special / Niche
| ID | Display Name | Base URL | API Key Env | Notes |
|----|-------------|----------|-------------|-------|
| `chatgpt` | ChatGPT (Session Auth) | `https://chatgpt.com/backend-api` | `CHATGPT_SESSION_TOKEN` | Session cookie auth, not an API key. Exposes GPT-5.x Codex models (gpt-5.1-codex etc.) that are unavailable via the standard OpenAI API |
| `elevenlabs` | ElevenLabs | `https://api.elevenlabs.io/v1` | `ELEVENLABS_API_KEY` | TTS / voice generation only — has a dedicated `elevenlabs.rs` driver in librefang-runtime. No chat models; appears in the provider list for media capability routing |
---
## Inclusion Criteria
A provider gets its own `.toml` file when it meets **at least one** of:
1. Has a **direct public API** not accessible via OpenRouter
2. Has a **unique endpoint** for a specific workload (e.g. coding plan endpoints)
3. Has a **dedicated driver** (`ApiFormat` beyond generic `OpenAI`)
4. Is a **local/self-hosted** runtime
5. Is a **CLI-based** provider
Providers that only route through `openrouter.ai/api/v1` with `OPENROUTER_API_KEY` are **not** given standalone files — their models are merged into `openrouter.toml` by the sync script. See [scripts/sync-pricing.py](../scripts/sync-pricing.py).
---
## Provider TOML Format ## Provider TOML Format
@@ -39,26 +146,52 @@ aliases = ["short-name"]
## Tier Definitions ## Tier Definitions
| Tier | Description | Examples | | Tier | Description | Examples |
|------|-------------|----------| |------|-------------|---------|
| `frontier` | Most capable, cutting-edge | Claude Opus, GPT-4.1 | | `frontier` | Most capable, cutting-edge | Claude Opus, GPT-4.1 |
| `smart` | Smart, cost-effective | Claude Sonnet, Gemini 2.5 Flash | | `smart` | Smart, cost-effective | Claude Sonnet, Gemini 2.5 Flash |
| `balanced` | Balanced speed/cost | GPT-4.1 Mini, Llama 3.3 70B | | `balanced` | Balanced speed/cost | GPT-4.1 Mini, Llama 3.3 70B |
| `fast` | Fastest, cheapest | GPT-4o Mini, Claude Haiku | | `fast` | Fastest, cheapest | GPT-4o Mini, Claude Haiku |
| `local` | Local models, zero cost | Ollama, vLLM, LM Studio | | `local` | Local models, zero cost | Ollama, vLLM, LM Studio |
---
## Sync Script
`scripts/sync-pricing.py` runs daily via CI to keep model pricing current.
```bash
python scripts/sync-pricing.py # Update prices only
python scripts/sync-pricing.py --create-missing # Also add new providers
python scripts/sync-pricing.py --dry-run --create-missing # Preview changes
```
**`--create-missing` routing logic:**
| Condition | Action |
|-----------|--------|
| Provider in `PROVIDER_API` map (has direct API) | Create standalone `.toml` |
| Provider not in `PROVIDER_API` (OpenRouter-only) | Merge into `openrouter.toml` with `openrouter/{provider}/{model}` IDs |
| Provider in `SKIP_PROVIDERS` (morph, aider, kwaipilot, …) | Skip entirely |
| Provider ID starts with `~` (OpenRouter internal routing alias) | Skip entirely |
---
## Validation ## Validation
```bash ```bash
python scripts/validate.py python scripts/validate.py # Warn on issues
python scripts/validate.py --strict # Treat warnings as errors
``` ```
Checks: required fields, valid tiers, non-negative costs, no duplicate model IDs. Checks: required fields, valid tiers, non-negative costs, no duplicate model IDs.
## Adding or Updating a Model ## Adding or Updating a Provider
1. Edit or create the provider file in `providers/` 1. Check inclusion criteria above — if OpenRouter-only, don't create a new file
2. Use exact API model IDs and verify pricing from official sources 2. Create or edit the `.toml` in `providers/`
3. Run `python scripts/validate.py` 3. Use exact API model IDs; verify pricing from official sources
4. Submit a PR 4. Run `python scripts/validate.py`
5. Update the table in this README
6. Submit a PR
See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide and pricing source links. See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full guide.
-48
View File
@@ -1,48 +0,0 @@
# AI21 Labs — https://ai21.com
# Models: 3
[provider]
id = "ai21"
display_name = "AI21 Labs"
api_key_env = "AI21_API_KEY"
base_url = "https://api.ai21.com/studio/v1"
key_required = true
[[models]]
id = "jamba-1.5-large"
display_name = "Jamba 1.5 Large"
tier = "smart"
context_window = 256000
max_output_tokens = 4096
input_cost_per_m = 2.0
output_cost_per_m = 8.0
supports_tools = true
supports_vision = false
supports_streaming = true
aliases = ["jamba"]
[[models]]
id = "jamba-1.5-mini"
display_name = "Jamba 1.5 Mini"
tier = "fast"
context_window = 256000
max_output_tokens = 4096
input_cost_per_m = 0.20
output_cost_per_m = 0.40
supports_tools = true
supports_vision = false
supports_streaming = true
aliases = []
[[models]]
id = "jamba-instruct"
display_name = "Jamba Instruct"
tier = "balanced"
context_window = 256000
max_output_tokens = 4096
input_cost_per_m = 0.50
output_cost_per_m = 0.70
supports_tools = true
supports_vision = false
supports_streaming = true
aliases = []
-35
View File
@@ -1,35 +0,0 @@
[provider]
id = "aider"
display_name = "Aider"
api_key_env = ""
base_url = ""
key_required = false
[[models]]
id = "aider/sonnet"
display_name = "Claude Sonnet via Aider"
provider = "aider"
tier = "smart"
context_window = 200000
max_output_tokens = 64000
input_cost_per_m = 0.0
output_cost_per_m = 0.0
supports_tools = false
supports_vision = false
supports_streaming = false
supports_thinking = true
aliases = ["aider-sonnet"]
[[models]]
id = "aider/gpt-4o"
display_name = "GPT-4o via Aider"
provider = "aider"
tier = "smart"
context_window = 128000
max_output_tokens = 16384
input_cost_per_m = 0.0
output_cost_per_m = 0.0
supports_tools = false
supports_vision = false
supports_streaming = false
aliases = ["aider-gpt-4o"]
-48
View File
@@ -1,48 +0,0 @@
# aion-labs — auto-generated from OpenRouter API
[provider]
id = "aion-labs"
display_name = "Aion Labs"
api_key_env = "AION_LABS_API_KEY"
base_url = "https://api.aionlabs.ai/v1"
key_required = true
[[models]]
id = "aion-1.0"
display_name = "AionLabs: Aion-1.0"
tier = "frontier"
context_window = 131072
max_output_tokens = 32768
input_cost_per_m = 4.0
output_cost_per_m = 8.0
supports_streaming = true
[[models]]
id = "aion-1.0-mini"
display_name = "AionLabs: Aion-1.0-Mini"
tier = "smart"
context_window = 131072
max_output_tokens = 32768
input_cost_per_m = 0.7
output_cost_per_m = 1.4
supports_streaming = true
[[models]]
id = "aion-2.0"
display_name = "AionLabs: Aion-2.0"
tier = "smart"
context_window = 131072
max_output_tokens = 32768
input_cost_per_m = 0.8
output_cost_per_m = 1.6
supports_streaming = true
[[models]]
id = "aion-rp-llama-3.1-8b"
display_name = "AionLabs: Aion-RP 1.0 (8B)"
tier = "smart"
context_window = 32768
max_output_tokens = 32768
input_cost_per_m = 0.8
output_cost_per_m = 1.6
supports_streaming = true
-50
View File
@@ -1,50 +0,0 @@
# allenai — auto-generated from OpenRouter API
[provider]
id = "allenai"
display_name = "Allenai"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "olmo-2-0325-32b-instruct"
display_name = "AllenAI: Olmo 2 32B Instruct"
tier = "fast"
context_window = 128000
max_output_tokens = 16384
input_cost_per_m = 0.05
output_cost_per_m = 0.2
supports_streaming = true
[[models]]
id = "olmo-3-32b-think"
display_name = "AllenAI: Olmo 3 32B Think"
tier = "fast"
context_window = 65536
max_output_tokens = 65536
input_cost_per_m = 0.15
output_cost_per_m = 0.5
supports_streaming = true
supports_thinking = true
[[models]]
id = "olmo-3.1-32b-instruct"
display_name = "AllenAI: Olmo 3.1 32B Instruct"
tier = "fast"
context_window = 65536
max_output_tokens = 16384
input_cost_per_m = 0.2
output_cost_per_m = 0.6
supports_streaming = true
[[models]]
id = "olmo-3.1-32b-think"
display_name = "AllenAI: Olmo 3.1 32B Think"
tier = "fast"
context_window = 65536
max_output_tokens = 65536
input_cost_per_m = 0.15
output_cost_per_m = 0.5
supports_streaming = true
supports_thinking = true
-78
View File
@@ -1,78 +0,0 @@
# arcee-ai — auto-generated from OpenRouter API
[provider]
id = "arcee-ai"
display_name = "Arcee Ai"
api_key_env = "ARCEE_API_KEY"
base_url = "https://api.arcee.ai/v1"
key_required = true
[[models]]
id = "coder-large"
display_name = "Arcee AI: Coder Large"
tier = "smart"
context_window = 32768
max_output_tokens = 8192
input_cost_per_m = 0.5
output_cost_per_m = 0.8
supports_streaming = true
[[models]]
id = "maestro-reasoning"
display_name = "Arcee AI: Maestro Reasoning"
tier = "smart"
context_window = 131072
max_output_tokens = 32000
input_cost_per_m = 0.9
output_cost_per_m = 3.3
supports_streaming = true
[[models]]
id = "spotlight"
display_name = "Arcee AI: Spotlight"
tier = "fast"
context_window = 131072
max_output_tokens = 65537
input_cost_per_m = 0.18
output_cost_per_m = 0.18
supports_streaming = true
[[models]]
id = "trinity-large-preview:free"
display_name = "Arcee AI: Trinity Large Preview (free)"
tier = "fast"
context_window = 131000
max_output_tokens = 16384
input_cost_per_m = 0.0
output_cost_per_m = 0.0
supports_streaming = true
[[models]]
id = "trinity-large-thinking"
display_name = "Arcee AI: Trinity Large Thinking"
tier = "fast"
context_window = 262144
max_output_tokens = 262144
input_cost_per_m = 0.22
output_cost_per_m = 0.85
supports_streaming = true
[[models]]
id = "trinity-mini"
display_name = "Arcee AI: Trinity Mini"
tier = "fast"
context_window = 131072
max_output_tokens = 131072
input_cost_per_m = 0.045
output_cost_per_m = 0.15
supports_streaming = true
[[models]]
id = "virtuoso-large"
display_name = "Arcee AI: Virtuoso Large"
tier = "smart"
context_window = 131072
max_output_tokens = 64000
input_cost_per_m = 0.75
output_cost_per_m = 1.2
supports_streaming = true
-76
View File
@@ -1,76 +0,0 @@
# Chutes.ai — https://chutes.ai
# Models: 5
[provider]
id = "chutes"
display_name = "Chutes.ai"
api_key_env = "CHUTES_API_KEY"
base_url = "https://llm.chutes.ai/v1"
key_required = true
[[models]]
id = "chutes/deepseek-ai/DeepSeek-V3"
display_name = "DeepSeek V3 (Chutes)"
tier = "smart"
context_window = 128000
max_output_tokens = 8192
input_cost_per_m = 0.25
output_cost_per_m = 0.35
supports_tools = true
supports_vision = false
supports_streaming = true
aliases = ["chutes-deepseek-v3"]
[[models]]
id = "chutes/deepseek-ai/DeepSeek-R1"
display_name = "DeepSeek R1 (Chutes)"
tier = "smart"
context_window = 128000
max_output_tokens = 8192
input_cost_per_m = 0.55
output_cost_per_m = 2.19
supports_tools = false
supports_vision = false
supports_streaming = true
supports_thinking = true
aliases = ["chutes-deepseek-r1"]
[[models]]
id = "chutes/meta-llama/Llama-4-Maverick-17B-128E-Instruct"
display_name = "Llama 4 Maverick (Chutes)"
tier = "balanced"
context_window = 128000
max_output_tokens = 8192
input_cost_per_m = 0.20
output_cost_per_m = 0.30
supports_tools = true
supports_vision = false
supports_streaming = true
aliases = ["chutes-llama-maverick"]
[[models]]
id = "chutes/Qwen/Qwen3-235B-A22B"
display_name = "Qwen3 235B (Chutes)"
tier = "smart"
context_window = 128000
max_output_tokens = 8192
input_cost_per_m = 0.25
output_cost_per_m = 0.35
supports_tools = true
supports_vision = false
supports_streaming = true
supports_thinking = true
aliases = ["chutes-qwen3"]
[[models]]
id = "chutes/meta-llama/Llama-3.3-70B-Instruct"
display_name = "Llama 3.3 70B (Chutes)"
tier = "balanced"
context_window = 128000
max_output_tokens = 8192
input_cost_per_m = 0.10
output_cost_per_m = 0.15
supports_tools = true
supports_vision = false
supports_streaming = true
aliases = ["chutes-llama-70b"]
-18
View File
@@ -1,18 +0,0 @@
# deepcogito — auto-generated from OpenRouter API
[provider]
id = "deepcogito"
display_name = "Deepcogito"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "cogito-v2.1-671b"
display_name = "Deep Cogito: Cogito v2.1 671B"
tier = "smart"
context_window = 128000
max_output_tokens = 16384
input_cost_per_m = 1.25
output_cost_per_m = 1.25
supports_streaming = true
+69
View File
@@ -0,0 +1,69 @@
# DeepInfra — https://deepinfra.com
# Serverless open-model inference (Llama, Mistral, Qwen, etc.)
[provider]
id = "deepinfra"
display_name = "DeepInfra"
api_key_env = "DEEPINFRA_API_KEY"
base_url = "https://api.deepinfra.com/v1/openai"
key_required = true
[[models]]
id = "meta-llama/Meta-Llama-3.1-8B-Instruct"
display_name = "Llama 3.1 8B Instruct"
tier = "fast"
context_window = 128000
max_output_tokens = 8192
input_cost_per_m = 0.06
output_cost_per_m = 0.06
supports_tools = true
supports_vision = false
supports_streaming = true
[[models]]
id = "meta-llama/Meta-Llama-3.1-70B-Instruct"
display_name = "Llama 3.1 70B Instruct"
tier = "balanced"
context_window = 128000
max_output_tokens = 8192
input_cost_per_m = 0.35
output_cost_per_m = 0.4
supports_tools = true
supports_vision = false
supports_streaming = true
[[models]]
id = "meta-llama/Meta-Llama-3.1-405B-Instruct"
display_name = "Llama 3.1 405B Instruct"
tier = "smart"
context_window = 128000
max_output_tokens = 8192
input_cost_per_m = 0.8
output_cost_per_m = 0.8
supports_tools = true
supports_vision = false
supports_streaming = true
[[models]]
id = "mistralai/Mistral-7B-Instruct-v0.3"
display_name = "Mistral 7B Instruct v0.3"
tier = "fast"
context_window = 32768
max_output_tokens = 8192
input_cost_per_m = 0.07
output_cost_per_m = 0.07
supports_tools = true
supports_vision = false
supports_streaming = true
[[models]]
id = "Qwen/Qwen2.5-72B-Instruct"
display_name = "Qwen 2.5 72B Instruct"
tier = "balanced"
context_window = 32768
max_output_tokens = 8192
input_cost_per_m = 0.35
output_cost_per_m = 0.4
supports_tools = true
supports_vision = false
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# essentialai — auto-generated from OpenRouter API
[provider]
id = "essentialai"
display_name = "Essentialai"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "rnj-1-instruct"
display_name = "EssentialAI: Rnj 1 Instruct"
tier = "fast"
context_window = 32768
max_output_tokens = 8192
input_cost_per_m = 0.15
output_cost_per_m = 0.15
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# ibm-granite — auto-generated from OpenRouter API
[provider]
id = "ibm-granite"
display_name = "Ibm Granite"
api_key_env = "WATSONX_API_KEY"
base_url = "https://us-south.ml.cloud.ibm.com/ml/v1"
key_required = true
[[models]]
id = "granite-4.0-h-micro"
display_name = "IBM: Granite 4.0 Micro"
tier = "fast"
context_window = 131000
max_output_tokens = 16384
input_cost_per_m = 0.017
output_cost_per_m = 0.11
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# inception — auto-generated from OpenRouter API
[provider]
id = "inception"
display_name = "Inception"
api_key_env = "INCEPTION_API_KEY"
base_url = "https://api.inceptionlabs.ai/v1"
key_required = true
[[models]]
id = "mercury-2"
display_name = "Inception: Mercury 2"
tier = "fast"
context_window = 128000
max_output_tokens = 50000
input_cost_per_m = 0.25
output_cost_per_m = 0.75
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# inclusionai — auto-generated from OpenRouter API
[provider]
id = "inclusionai"
display_name = "Inclusionai"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "ling-2.6-flash:free"
display_name = "inclusionAI: Ling-2.6-flash (free)"
tier = "fast"
context_window = 262144
max_output_tokens = 32768
input_cost_per_m = 0.0
output_cost_per_m = 0.0
supports_streaming = true
-28
View File
@@ -1,28 +0,0 @@
# inflection — auto-generated from OpenRouter API
[provider]
id = "inflection"
display_name = "Inflection"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "inflection-3-pi"
display_name = "Inflection: Inflection 3 Pi"
tier = "smart"
context_window = 8000
max_output_tokens = 1024
input_cost_per_m = 2.5
output_cost_per_m = 10.0
supports_streaming = true
[[models]]
id = "inflection-3-productivity"
display_name = "Inflection: Inflection 3 Productivity"
tier = "smart"
context_window = 8000
max_output_tokens = 1024
input_cost_per_m = 2.5
output_cost_per_m = 10.0
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# kwaipilot — auto-generated from OpenRouter API
[provider]
id = "kwaipilot"
display_name = "Kwaipilot"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "kat-coder-pro-v2"
display_name = "Kwaipilot: KAT-Coder-Pro V2"
tier = "fast"
context_window = 256000
max_output_tokens = 80000
input_cost_per_m = 0.3
output_cost_per_m = 1.2
supports_streaming = true
-38
View File
@@ -1,38 +0,0 @@
# liquid — auto-generated from OpenRouter API
[provider]
id = "liquid"
display_name = "Liquid"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "lfm-2-24b-a2b"
display_name = "LiquidAI: LFM2-24B-A2B"
tier = "fast"
context_window = 32768
max_output_tokens = 8192
input_cost_per_m = 0.03
output_cost_per_m = 0.12
supports_streaming = true
[[models]]
id = "lfm-2.5-1.2b-instruct:free"
display_name = "LiquidAI: LFM2.5-1.2B-Instruct (free)"
tier = "fast"
context_window = 32768
max_output_tokens = 8192
input_cost_per_m = 0.0
output_cost_per_m = 0.0
supports_streaming = true
[[models]]
id = "lfm-2.5-1.2b-thinking:free"
display_name = "LiquidAI: LFM2.5-1.2B-Thinking (free)"
tier = "fast"
context_window = 32768
max_output_tokens = 8192
input_cost_per_m = 0.0
output_cost_per_m = 0.0
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# meituan — auto-generated from OpenRouter API
[provider]
id = "meituan"
display_name = "Meituan"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "longcat-flash-chat"
display_name = "Meituan: LongCat Flash Chat"
tier = "fast"
context_window = 131072
max_output_tokens = 131072
input_cost_per_m = 0.2
output_cost_per_m = 0.8
supports_streaming = true
-28
View File
@@ -1,28 +0,0 @@
# microsoft — auto-generated from OpenRouter API
[provider]
id = "microsoft"
display_name = "Microsoft"
api_key_env = "GITHUB_TOKEN"
base_url = "https://models.inference.ai.azure.com"
key_required = true
[[models]]
id = "phi-4"
display_name = "Microsoft: Phi 4"
tier = "fast"
context_window = 16384
max_output_tokens = 16384
input_cost_per_m = 0.065
output_cost_per_m = 0.14
supports_streaming = true
[[models]]
id = "wizardlm-2-8x22b"
display_name = "WizardLM-2 8x22B"
tier = "smart"
context_window = 65535
max_output_tokens = 8000
input_cost_per_m = 0.62
output_cost_per_m = 0.62
supports_streaming = true
-28
View File
@@ -1,28 +0,0 @@
# morph — auto-generated from OpenRouter API
[provider]
id = "morph"
display_name = "Morph"
api_key_env = "MORPH_API_KEY"
base_url = "https://api.morphllm.com/v1"
key_required = true
[[models]]
id = "morph-v3-fast"
display_name = "Morph: Morph V3 Fast"
tier = "smart"
context_window = 81920
max_output_tokens = 38000
input_cost_per_m = 0.8
output_cost_per_m = 1.2
supports_streaming = true
[[models]]
id = "morph-v3-large"
display_name = "Morph: Morph V3 Large"
tier = "smart"
context_window = 262144
max_output_tokens = 131072
input_cost_per_m = 0.9
output_cost_per_m = 1.9
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# nex-agi — auto-generated from OpenRouter API
[provider]
id = "nex-agi"
display_name = "Nex Agi"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "deepseek-v3.1-nex-n1"
display_name = "Nex AGI: DeepSeek V3.1 Nex N1"
tier = "fast"
context_window = 131072
max_output_tokens = 163840
input_cost_per_m = 0.135
output_cost_per_m = 0.5
supports_streaming = true
-68
View File
@@ -1,68 +0,0 @@
# nousresearch — auto-generated from OpenRouter API
[provider]
id = "nousresearch"
display_name = "Nousresearch"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "hermes-2-pro-llama-3-8b"
display_name = "NousResearch: Hermes 2 Pro - Llama-3 8B"
tier = "fast"
context_window = 8192
max_output_tokens = 8192
input_cost_per_m = 0.14
output_cost_per_m = 0.14
supports_streaming = true
[[models]]
id = "hermes-3-llama-3.1-405b"
display_name = "Nous: Hermes 3 405B Instruct"
tier = "smart"
context_window = 131072
max_output_tokens = 16384
input_cost_per_m = 1.0
output_cost_per_m = 1.0
supports_streaming = true
[[models]]
id = "hermes-3-llama-3.1-405b:free"
display_name = "Nous: Hermes 3 405B Instruct (free)"
tier = "fast"
context_window = 131072
max_output_tokens = 16384
input_cost_per_m = 0.0
output_cost_per_m = 0.0
supports_streaming = true
[[models]]
id = "hermes-3-llama-3.1-70b"
display_name = "Nous: Hermes 3 70B Instruct"
tier = "fast"
context_window = 131072
max_output_tokens = 16384
input_cost_per_m = 0.3
output_cost_per_m = 0.3
supports_streaming = true
[[models]]
id = "hermes-4-405b"
display_name = "Nous: Hermes 4 405B"
tier = "smart"
context_window = 131072
max_output_tokens = 16384
input_cost_per_m = 1.0
output_cost_per_m = 3.0
supports_streaming = true
[[models]]
id = "hermes-4-70b"
display_name = "Nous: Hermes 4 70B"
tier = "fast"
context_window = 131072
max_output_tokens = 16384
input_cost_per_m = 0.13
output_cost_per_m = 0.4
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# prime-intellect — auto-generated from OpenRouter API
[provider]
id = "prime-intellect"
display_name = "Prime Intellect"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "intellect-3"
display_name = "Prime Intellect: INTELLECT-3"
tier = "fast"
context_window = 131072
max_output_tokens = 131072
input_cost_per_m = 0.2
output_cost_per_m = 1.1
supports_streaming = true
-28
View File
@@ -1,28 +0,0 @@
# relace — auto-generated from OpenRouter API
[provider]
id = "relace"
display_name = "Relace"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "relace-apply-3"
display_name = "Relace: Relace Apply 3"
tier = "smart"
context_window = 256000
max_output_tokens = 128000
input_cost_per_m = 0.85
output_cost_per_m = 1.25
supports_streaming = true
[[models]]
id = "relace-search"
display_name = "Relace: Relace Search"
tier = "smart"
context_window = 256000
max_output_tokens = 128000
input_cost_per_m = 1.0
output_cost_per_m = 3.0
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# switchpoint — auto-generated from OpenRouter API
[provider]
id = "switchpoint"
display_name = "Switchpoint"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "router"
display_name = "Switchpoint Router"
tier = "smart"
context_window = 131072
max_output_tokens = 16384
input_cost_per_m = 0.85
output_cost_per_m = 3.4
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# tngtech — auto-generated from OpenRouter API
[provider]
id = "tngtech"
display_name = "Tngtech"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "deepseek-r1t2-chimera"
display_name = "TNG: DeepSeek R1T2 Chimera"
tier = "fast"
context_window = 163840
max_output_tokens = 163840
input_cost_per_m = 0.3
output_cost_per_m = 1.1
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# upstage — auto-generated from OpenRouter API
[provider]
id = "upstage"
display_name = "Upstage"
api_key_env = "UPSTAGE_API_KEY"
base_url = "https://api.upstage.ai/v1"
key_required = true
[[models]]
id = "solar-pro-3"
display_name = "Upstage: Solar Pro 3"
tier = "fast"
context_window = 128000
max_output_tokens = 16384
input_cost_per_m = 0.15
output_cost_per_m = 0.6
supports_streaming = true
-49
View File
@@ -1,49 +0,0 @@
# Venice.ai — https://venice.ai
# Models: 3
[provider]
id = "venice"
display_name = "Venice.ai"
api_key_env = "VENICE_API_KEY"
base_url = "https://api.venice.ai/api/v1"
key_required = true
[[models]]
id = "venice-uncensored"
display_name = "Venice Uncensored"
tier = "fast"
context_window = 32000
max_output_tokens = 8192
input_cost_per_m = 0.20
output_cost_per_m = 0.90
supports_tools = true
supports_vision = false
supports_streaming = true
aliases = ["venice"]
[[models]]
id = "llama-3.3-70b"
display_name = "Llama 3.3 70B (Venice)"
tier = "balanced"
context_window = 128000
max_output_tokens = 8192
input_cost_per_m = 0.1
output_cost_per_m = 0.32
supports_tools = true
supports_vision = false
supports_streaming = true
aliases = []
[[models]]
id = "qwen3-235b-a22b-instruct-2507"
display_name = "Qwen3 235B A22B (Venice)"
tier = "smart"
context_window = 128000
max_output_tokens = 8192
input_cost_per_m = 0.20
output_cost_per_m = 0.90
supports_tools = true
supports_vision = false
supports_streaming = true
supports_thinking = true
aliases = []
-18
View File
@@ -1,18 +0,0 @@
# writer — auto-generated from OpenRouter API
[provider]
id = "writer"
display_name = "Writer"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "palmyra-x5"
display_name = "Writer: Palmyra X5"
tier = "smart"
context_window = 1040000
max_output_tokens = 8192
input_cost_per_m = 0.6
output_cost_per_m = 6.0
supports_streaming = true
-38
View File
@@ -1,38 +0,0 @@
# xiaomi — auto-generated from OpenRouter API
[provider]
id = "xiaomi"
display_name = "Xiaomi"
api_key_env = "XIAOMI_ACCESS_KEY_ID"
base_url = "https://cnbj3-cloud-ml.api.xiaomi.net"
key_required = true
[[models]]
id = "mimo-v2-flash"
display_name = "Xiaomi: MiMo-V2-Flash"
tier = "fast"
context_window = 262144
max_output_tokens = 65536
input_cost_per_m = 0.09
output_cost_per_m = 0.29
supports_streaming = true
[[models]]
id = "mimo-v2-omni"
display_name = "Xiaomi: MiMo-V2-Omni"
tier = "fast"
context_window = 262144
max_output_tokens = 65536
input_cost_per_m = 0.4
output_cost_per_m = 2.0
supports_streaming = true
[[models]]
id = "mimo-v2-pro"
display_name = "Xiaomi: MiMo-V2-Pro"
tier = "smart"
context_window = 1048576
max_output_tokens = 131072
input_cost_per_m = 1.0
output_cost_per_m = 3.0
supports_streaming = true
-18
View File
@@ -1,18 +0,0 @@
# ~anthropic — auto-generated from OpenRouter API
[provider]
id = "~anthropic"
display_name = "~Anthropic"
api_key_env = "OPENROUTER_API_KEY"
base_url = "https://openrouter.ai/api/v1"
key_required = true
[[models]]
id = "claude-opus-latest"
display_name = "Anthropic: Claude Opus Latest"
tier = "frontier"
context_window = 1000000
max_output_tokens = 128000
input_cost_per_m = 5.0
output_cost_per_m = 25.0
supports_streaming = true
+118 -48
View File
@@ -34,6 +34,8 @@ PROVIDER_ALIAS = {
SKIP_PROVIDERS = { SKIP_PROVIDERS = {
"sao10k", "thedrummer", "undi95", "gryphe", "cognitivecomputations", "sao10k", "thedrummer", "undi95", "gryphe", "cognitivecomputations",
"anthracite-org", "alpindale", "alfredpros", "mancer", "anthracite-org", "alpindale", "alfredpros", "mancer",
# Specialized coding tools / CLI wrappers — not general LLM providers
"morph", "aider", "kwaipilot",
} }
# Skip creating NEW provider files for these — they overlap with hand-written # Skip creating NEW provider files for these — they overlap with hand-written
@@ -139,8 +141,102 @@ def update_toml_prices(toml_path, models_by_id, dry_run=False):
return updated return updated
def _build_model_fields(provider_id, m, model_id_prefix=""):
"""Extract and normalise fields for a single OpenRouter model entry.
Returns a dict of fields, or None if pricing is missing.
The caller supplies *model_id_prefix* (e.g. "openrouter/kwaipilot/") so
the same helper works for both standalone files and openrouter.toml merges.
"""
raw_id = m["id"].split("/")[-1] if "/" in m["id"] else m["id"]
model_id = f"{model_id_prefix}{raw_id}"
display = m.get("name", raw_id)
ctx = m.get("context_length", 0)
max_out = m.get("top_provider", {}).get("max_completion_tokens", 0)
inp, outp = parse_pricing(m)
if inp is None:
return None
supports_tools = "tool_use" in str(m.get("supported_parameters", []))
supports_vision = "vision" in str(m.get("architecture", {}).get("modality", ""))
if inp == 0 and outp == 0:
tier = "fast"
elif inp < 0.5:
tier = "fast"
elif inp < 3.0:
tier = "smart"
else:
tier = "frontier"
if not max_out:
max_out = min(ctx // 4, 16384) if ctx > 0 else 4096
return dict(
model_id=model_id, display=display, tier=tier,
ctx=ctx, max_out=max_out, inp=inp, outp=outp,
supports_tools=supports_tools, supports_vision=supports_vision,
)
def _model_lines(f):
"""Render a model-fields dict as TOML [[models]] lines."""
lines = [
"[[models]]",
f'id = "{f["model_id"]}"',
f'display_name = "{f["display"]}"',
f'tier = "{f["tier"]}"',
f'context_window = {f["ctx"]}',
f'max_output_tokens = {f["max_out"]}',
f'input_cost_per_m = {f["inp"]}',
f'output_cost_per_m = {f["outp"]}',
]
if f["supports_tools"]:
lines.append("supports_tools = true")
if f["supports_vision"]:
lines.append("supports_vision = true")
lines.append("supports_streaming = true")
lines.append("")
return lines
def merge_into_openrouter(provider_id, models, dry_run=False):
"""Append models from an OpenRouter-only provider into openrouter.toml.
Model IDs get the prefix "openrouter/{provider_id}/" so they stay
unambiguous and match the existing openrouter.toml convention.
Already-present IDs are skipped to keep the operation idempotent.
"""
openrouter_path = PROVIDERS_DIR / "openrouter.toml"
if not openrouter_path.exists():
return 0
existing = openrouter_path.read_text()
existing_ids = set(re.findall(r'^id\s*=\s*"([^"]+)"', existing, re.MULTILINE))
new_lines = []
for m in sorted(models, key=lambda x: x.get("id", "")):
prefix = f"openrouter/{provider_id}/"
f = _build_model_fields(provider_id, m, model_id_prefix=prefix)
if f is None or f["model_id"] in existing_ids:
continue
# Append provider name to display so provenance is clear in the UI
f["display"] = f'{f["display"]} (OpenRouter)'
new_lines.extend(_model_lines(f))
if not new_lines:
return 0
count = sum(1 for l in new_lines if l == "[[models]]")
print(f" openrouter.toml: +{count} models from {provider_id}")
if not dry_run:
with open(openrouter_path, "a") as fh:
fh.write("\n" + "\n".join(new_lines))
return count
def generate_provider_toml(provider_id, models, dry_run=False): def generate_provider_toml(provider_id, models, dry_run=False):
"""Generate a new provider TOML file from OpenRouter data.""" """Generate a new standalone provider TOML file (direct-API providers only)."""
our_name = PROVIDER_ALIAS.get(provider_id, provider_id) our_name = PROVIDER_ALIAS.get(provider_id, provider_id)
toml_path = PROVIDERS_DIR / f"{our_name}.toml" toml_path = PROVIDERS_DIR / f"{our_name}.toml"
@@ -150,13 +246,11 @@ def generate_provider_toml(provider_id, models, dry_run=False):
if our_name in SKIP_DUPLICATES: if our_name in SKIP_DUPLICATES:
return 0 return 0
# Check if provider has a known public API if our_name not in PROVIDER_API:
if our_name in PROVIDER_API: # No direct public API — caller should use merge_into_openrouter instead.
base_url, env_key = PROVIDER_API[our_name] return 0
else:
# No known public API — route through OpenRouter base_url, env_key = PROVIDER_API[our_name]
base_url = "https://openrouter.ai/api/v1"
env_key = "OPENROUTER_API_KEY"
key_required = "true" key_required = "true"
lines = [ lines = [
@@ -173,45 +267,10 @@ def generate_provider_toml(provider_id, models, dry_run=False):
count = 0 count = 0
for m in sorted(models, key=lambda x: x.get("id", "")): for m in sorted(models, key=lambda x: x.get("id", "")):
model_id = m["id"].split("/")[-1] if "/" in m["id"] else m["id"] f = _build_model_fields(provider_id, m)
display = m.get("name", model_id) if f is None:
ctx = m.get("context_length", 0)
max_out = m.get("top_provider", {}).get("max_completion_tokens", 0)
inp, outp = parse_pricing(m)
if inp is None:
continue continue
lines.extend(_model_lines(f))
supports_tools = "tool_use" in str(m.get("supported_parameters", []))
supports_vision = "vision" in str(m.get("architecture", {}).get("modality", ""))
# Infer tier from pricing
if inp == 0 and outp == 0:
tier = "fast"
elif inp < 0.5:
tier = "fast"
elif inp < 3.0:
tier = "smart"
else:
tier = "frontier"
# Default max_output_tokens if not provided
if not max_out:
max_out = min(ctx // 4, 16384) if ctx > 0 else 4096
lines.append("[[models]]")
lines.append(f'id = "{model_id}"')
lines.append(f'display_name = "{display}"')
lines.append(f'tier = "{tier}"')
lines.append(f"context_window = {ctx}")
lines.append(f"max_output_tokens = {max_out}")
lines.append(f"input_cost_per_m = {inp}")
lines.append(f"output_cost_per_m = {outp}")
if supports_tools:
lines.append("supports_tools = true")
if supports_vision:
lines.append("supports_vision = true")
lines.append("supports_streaming = true")
lines.append("")
count += 1 count += 1
if count == 0: if count == 0:
@@ -257,10 +316,21 @@ def main():
for provider_id, models in sorted(by_provider.items()): for provider_id, models in sorted(by_provider.items()):
if provider_id in SKIP_PROVIDERS: if provider_id in SKIP_PROVIDERS:
continue continue
# Skip OpenRouter internal auto-routing aliases (e.g. "~anthropic")
# These are not real providers — they map to openrouter.toml.
if provider_id.startswith("~"):
continue
our_name = PROVIDER_ALIAS.get(provider_id, provider_id) our_name = PROVIDER_ALIAS.get(provider_id, provider_id)
if not (PROVIDERS_DIR / f"{our_name}.toml").exists(): if (PROVIDERS_DIR / f"{our_name}.toml").exists():
continue
if our_name in PROVIDER_API:
# Provider has a known direct API — create a standalone file.
count = generate_provider_toml(provider_id, models, dry_run=dry_run) count = generate_provider_toml(provider_id, models, dry_run=dry_run)
total_created += count else:
# No direct API — merge models into openrouter.toml instead of
# creating a new file that just wraps the OpenRouter endpoint.
count = merge_into_openrouter(provider_id, models, dry_run=dry_run)
total_created += count
action = "Would" if dry_run else "Done:" action = "Would" if dry_run else "Done:"
print(f"\n{action} updated {total_updated} prices, created {total_created} new model entries") print(f"\n{action} updated {total_updated} prices, created {total_created} new model entries")
+149 -40
View File
@@ -1,52 +1,41 @@
# Skills # Skills Registry
Reusable skill definitions for LibreFang agents. A skill is either a prompt Skills are reusable expertise modules that can be attached to any agent. Each skill carries a system prompt that injects domain knowledge, best practices, and behavioral guidelines into an agent's context at conversation time. Skills are composable — a single agent can load multiple skills simultaneously.
template or a code script that an agent can invoke to perform a specific task.
## File Convention ## File Format
Every skill directory **must** contain a `SKILL.md` (the entry point). A skill lives in its own subdirectory. The only required file is `SKILL.md`. An optional `skill.toml` provides structured metadata when `[runtime]`, `[input]` schema, or explicit versioning is needed.
A `skill.toml` is **optional** and only needed for structured metadata that
does not fit in Markdown frontmatter (runtime, input schema, version, tags).
``` ```
skills/ skills/
├── docker/ ├── rust-expert/
│ └── SKILL.md # Prompt-only expert — no skill.toml needed │ └── SKILL.md # required: frontmatter + prompt body
├── custom-skill-prompt/ ├── meeting-agenda/
│ ├── SKILL.md # Prompt body + name/description │ ├── SKILL.md # required: frontmatter + prompt body
│ └── skill.toml # Runtime + input schema │ └── skill.toml # optional: runtime type, input schema, version
└── custom-skill-python/ └── code-runner/
├── SKILL.md # Overview (prompt body unused) ├── SKILL.md # overview (prompt body unused for script skills)
├── skill.toml # Runtime = python, entry = main.py ├── skill.toml # runtime = python, entry = main.py
└── main.py └── main.py
``` ```
### `SKILL.md` (required) ### SKILL.md format
The source of truth for the skill's prompt and identity. Must start with YAML
frontmatter containing at least `name` and `description`:
```markdown ```markdown
--- ---
name: docker name: rust-expert
description: Docker expert for containers, Compose, and Dockerfiles. description: "Rust programming expert for ownership, lifetimes, async/await, traits, and unsafe code"
--- ---
# Rust Programming Expertise
You are a Docker specialist. You help users build, run, debug, and optimize You are an expert Rust developer with deep understanding of the ownership system...
containers...
``` ```
This format is compatible with Claude Code skills, so a `SKILL.md` authored The frontmatter must contain `name` and `description`. The Markdown body becomes the injected prompt.
here can be dropped into other tools without modification.
### `skill.toml` (optional) ### skill.toml format (optional)
Add one only when you need to declare any of: Only required when you need `[runtime]`, `[input]` schema, or structured metadata beyond what frontmatter supports:
- `[runtime]` — `promptonly` / `python` / `node` / `shell` (default is `promptonly`)
- `[input]` — typed input parameter schema
- `version`, `author`, `tags` — structured metadata
```toml ```toml
[skill] [skill]
@@ -56,27 +45,147 @@ description = "Generate a structured meeting agenda from a topic and duration."
tags = ["meeting", "productivity"] tags = ["meeting", "productivity"]
[runtime] [runtime]
type = "promptonly" type = "promptonly" # promptonly | python | node | shell
[input] [input]
topic = { type = "string", description = "The meeting topic", required = true } topic = { type = "string", description = "The meeting topic", required = true }
duration_minutes = { type = "string", description = "Duration in minutes", required = true } duration_minutes = { type = "string", description = "Duration in minutes", required = true }
``` ```
**Consistency rule:** if both files exist, `skill.name` and `skill.description` If both files exist, `skill.name` and `skill.description` in `skill.toml` must match the frontmatter in `SKILL.md`. The validator enforces this to prevent drift.
in `skill.toml` must match the `name` and `description` in `SKILL.md`'s
frontmatter. The validator enforces this to prevent drift.
**Do not duplicate the prompt body in TOML.** The prompt lives in `SKILL.md`; ## Installing and Using Skills
`skill.toml` is for metadata the prompt cannot express.
## Testing Skills Locally
```bash ```bash
librefang skill test ./skills/custom-skill-prompt \ # List all available skills in the registry
librefang catalog skills
# Attach a skill to an agent
librefang skill attach <agent-name> rust-expert
# Attach multiple skills
librefang skill attach <agent-name> rust-expert security-audit
# Detach a skill
librefang skill detach <agent-name> rust-expert
# Test a skill locally with sample input
librefang skill test ./skills/meeting-agenda \
--input '{"topic": "Q1 planning", "duration_minutes": "30"}' --input '{"topic": "Q1 planning", "duration_minutes": "30"}'
``` ```
## All Skills (61 total)
### Programming Languages
| Name | Description |
|------|-------------|
| css-expert | CSS expert for flexbox, grid, animations, responsive design, and modern layout techniques |
| golang-expert | Go programming expert for goroutines, channels, interfaces, modules, and concurrency patterns |
| python-expert | Python expert for stdlib, packaging, type hints, async/await, and performance optimization |
| rust-expert | Rust programming expert for ownership, lifetimes, async/await, traits, and unsafe code |
| typescript-expert | TypeScript expert for type system, generics, utility types, and strict mode patterns |
| wasm-expert | WebAssembly expert for WASI, component model, Rust/C compilation, and browser integration |
### Web Frameworks and APIs
| Name | Description |
|------|-------------|
| graphql-expert | GraphQL expert for schema design, resolvers, subscriptions, and performance optimization |
| nextjs-expert | Next.js expert for App Router, SSR/SSG, API routes, middleware, and deployment |
| oauth-expert | OAuth 2.0 and OpenID Connect expert for authorization flows, PKCE, and token management |
| openapi-expert | OpenAPI/Swagger expert for API specification design, validation, and code generation |
| react-expert | React expert for hooks, state management, Server Components, and performance optimization |
### Databases
| Name | Description |
|------|-------------|
| elasticsearch | Elasticsearch expert for queries, mappings, aggregations, index management, and cluster operations |
| mongodb | MongoDB operations expert for queries, aggregation pipelines, indexes, and schema design |
| postgres-expert | PostgreSQL expert for query optimization, indexing, extensions, and database administration |
| redis-expert | Redis expert for data structures, caching patterns, Lua scripting, and cluster operations |
| sql-analyst | SQL query expert for optimization, schema design, and data analysis |
| sqlite-expert | SQLite expert for WAL mode, query optimization, embedded patterns, and advanced features |
| vector-db | Vector database expert for embeddings, similarity search, RAG patterns, and indexing strategies |
### Cloud and Infrastructure
| Name | Description |
|------|-------------|
| ansible | Ansible automation expert for playbooks, roles, inventories, and infrastructure management |
| aws | AWS cloud services expert for EC2, S3, Lambda, IAM, and AWS CLI |
| azure | Microsoft Azure expert for az CLI, AKS, App Service, and cloud infrastructure |
| docker | Docker expert for containers, Compose, Dockerfiles, and debugging |
| gcp | Google Cloud Platform expert for gcloud CLI, GKE, Cloud Run, and managed services |
| helm | Helm chart expert for Kubernetes package management, templating, and dependency management |
| kubernetes | Kubernetes operations expert for kubectl, pods, deployments, and debugging |
| nginx | Nginx configuration expert for reverse proxy, load balancing, TLS, and performance tuning |
| terraform | Terraform IaC expert for providers, modules, state management, and planning |
### DevOps and CI/CD
| Name | Description |
|------|-------------|
| ci-cd | CI/CD pipeline expert for GitHub Actions, GitLab CI, Jenkins, and deployment automation |
| git-expert | Git operations expert for branching, rebasing, conflicts, and workflows |
| github | GitHub operations expert for PRs, issues, code review, Actions, and gh CLI |
| linux-networking | Linux networking expert for iptables, nftables, routing, DNS, and network troubleshooting |
| prometheus | Prometheus monitoring expert for PromQL, alerting rules, Grafana dashboards, and observability |
| sentry | Sentry error tracking and debugging specialist |
| shell-scripting | Shell scripting expert for Bash, POSIX compliance, error handling, and automation |
| sysadmin | System administration expert for Linux, macOS, Windows, services, and monitoring |
### Security
| Name | Description |
|------|-------------|
| compliance | Compliance expert for SOC 2, GDPR, HIPAA, PCI-DSS, and security frameworks |
| crypto-expert | Cryptography expert for TLS, symmetric/asymmetric encryption, hashing, and key management |
| security-audit | Security audit expert for OWASP Top 10, CVE analysis, code review, and penetration testing methodology |
### AI and Machine Learning
| Name | Description |
|------|-------------|
| llm-finetuning | LLM fine-tuning expert for LoRA, QLoRA, dataset preparation, and training optimization |
| ml-engineer | Machine learning engineer expert for PyTorch, scikit-learn, model evaluation, and MLOps |
| prompt-engineer | Prompt engineering expert for chain-of-thought, few-shot learning, evaluation, and LLM optimization |
| web-search | Web search and research specialist for finding and synthesizing information |
### Productivity Tools
| Name | Description |
|------|-------------|
| confluence | Confluence wiki expert for page structure, spaces, macros, and content organization |
| figma-expert | Figma design expert for components, auto-layout, design systems, and developer handoff |
| jira | Jira project management expert for issues, sprints, workflows, and reporting |
| linear-tools | Linear project management expert for issues, cycles, projects, and workflow automation |
| notion | Notion workspace management and content creation specialist |
| pdf-reader | PDF content extraction and analysis specialist |
| slack-tools | Slack workspace management and automation specialist |
### Writing and Communication
| Name | Description |
|------|-------------|
| email-writer | Professional email writing expert for tone, structure, clarity, and business communication |
| presentation | Presentation expert for slide structure, storytelling, visual design, and audience engagement |
| technical-writer | Technical writing expert for API docs, READMEs, ADRs, and developer documentation |
| writing-coach | Writing improvement specialist for grammar, style, clarity, and structure |
### Engineering Practice
| Name | Description |
|------|-------------|
| api-tester | API testing expert for curl, REST, GraphQL, authentication, and debugging |
| code-reviewer | Code review specialist focused on patterns, bugs, security, and performance |
| data-analyst | Data analysis expert for statistics, visualization, pandas, and exploration |
| data-pipeline | Data pipeline expert for ETL, Apache Spark, Airflow, dbt, and data quality |
| interview-prep | Technical interview preparation expert for algorithms, system design, and behavioral questions |
| project-manager | Project management expert for Agile, estimation, risk management, and stakeholder communication |
| regex-expert | Regular expression expert for crafting, debugging, and explaining patterns |
## Adding a New Skill ## Adding a New Skill
1. Create `skills/<name>/SKILL.md` with frontmatter (`name`, `description`) and the prompt body. 1. Create `skills/<name>/SKILL.md` with frontmatter (`name`, `description`) and the prompt body.