
Write HTML. Render video. Built for agents.
flAPI generates read-only APIs from YAML endpoint files and SQL templates backed by DuckDB. The same configuration can serve REST routes, MCP tools, and cached data flows, with built-in auth, rate limits, and audit logging.

Builders who want one config to serve data as REST endpoints and MCP tools.
You can publish data APIs and agent tools from SQL templates instead of wiring each endpoint by hand.
A single YAML file can define a REST endpoint, an MCP tool, or an MCP resource.
Queries run through DuckDB and its extension ecosystem, including sources like BigQuery, Snowflake, Postgres, MySQL, Parquet, and Iceberg.
Template fields are validated and bound as prepared statements for safer query building.
Caches can do full refresh, append, or merge syncs, with snapshots, retention, and optional inlining.
Includes basic auth, CORS allowlists, per-user and per-tool rate limits, TLS support, audit logs, and config validation.
`flapi pack` can bundle config trees and small data files into one deployable binary.
# Run the flapi server (note: "flapi" is taken on PyPI, so the package is "flapi-io") uvx --from flapi-io flapi -c flapi.yaml # Run the flapii CLI client (also bundled in flapi-io) uvx --from flapi-io flapii
pip install flapi-io # installs both "flapi" and "flapii" commands
> docker pull ghcr.io/datazoode/flapi:latest
> docker run -it --rm -p 8080:8080 -p 8081:8081 -v $(pwd)/examples/:/config ghcr.io/datazoode/flapi -c /config/flapi.yaml
> docker run -it --rm -p 8080:8080 -p 8081:8081 -v $(pwd)/examples/:/config ghcr.io/datazoode/flapi -c /config/flapi.yaml --enable-mcp
flAPI is a powerful service that automatically generates read-only APIs for datasets by utilizing SQL templates. Built on top of DuckDB and leveraging its SQL engine and extension ecosystem, flAPI offers a seamless way to connect to various data sources and expose them as RESTful APIs.

2026-07-28 revision (dual-era: modern and legacy clients) — with the Tasks extension for long-running queries, typed schemas + structured results, OAuth discovery, per-tool RBAC, shadow/dry-run, response shaping, rate limiting, and a prompt-injection hygiene scanner{{ params.X }} references on int/double/boolean/date/time/uuid/enum/email/string fields are bound as DuckDB prepared statements — SQL injection is structurally impossible for those sitesflapii project init demos stay simpleflapi pack. scp flapi-prod user@host becomes the whole deploy. Reproducible (SOURCE_DATE_EPOCH), notarisable on macOS via a reserved Mach-O segment, with a secret deny list (*.env, secrets/*, *.pem, *.key) enforced at pack time.--no-telemetry flag, FLAPI_NO_TELEMETRY env var, or flapi.yamlThe fastest way to try flAPI — no download, no Docker:
# Run the flapi server (note: "flapi" is taken on PyPI, so the package is "flapi-io")
uvx --from flapi-io flapi -c flapi.yaml
# Run the flapii CLI client (also bundled in flapi-io)
uvx --from flapi-io flapii
Or install permanently — one package gives you both commands:
pip install flapi-io # installs both "flapi" and "flapii" commands
Pre-built binaries and Docker images are also available — see below.
The easiest way to get started with flAPI is to use the pre-built docker image.
> docker pull ghcr.io/datazoode/flapi:latest
The image is pretty small and mainly contains the flAPI binary which is statically linked against DuckDB v1.5.5. Details about the docker image can be found in the Dockerfile.
Once you have downloaded the binary, you can run flAPI by executing the following command:
> docker run -it --rm -p 8080:8080 -p 8081:8081 -v $(pwd)/examples/:/config ghcr.io/datazoode/flapi -c /config/flapi.yaml
The different arguments in this docker command are:
-it --rm: Run the container in interactive mode and remove it after the process has finished-p 8080:8080: Exposes port 8080 of the container to the host, this makes the REST API available at http://localhost:8080-p 8081:8081: Exposes port 8081 for the MCP server (when enabled)-v $(pwd)/examples/:/config: This mounts the local examples directory to the /config directory in the container, this is where the flAPI configuration file
is expected to be found.ghcr.io/datazoode/flapi: The docker image to use-c /config/flapi.yaml: This is an argument to the flAPI application which tells it to use the flapi.yaml file in the /config directory as the configuration file.To enable MCP support, you can either:
Option A: Use the command line flag
> docker run -it --rm -p 8080:8080 -p 8081:8081 -v $(pwd)/examples/:/config ghcr.io/datazoode/flapi -c /config/flapi.yaml --enable-mcp
Option B: Configure in flapi.yaml
mcp:
enabled: true
port: 8081
# ... other MCP configuration
If everything is set up correctly, you should be able to access the API at the URL specified in the configuration file.
> curl 'http://localhost:8080/'
___
___( o)> Welcome to
\ <_. ) flAPI
`---'
Fast and Flexible API Framework
powered by DuckDB
The flAPI server creates embedded Swagger UI at which provides an overview of the available endpoints and allows you to test them. It can be found at
You should see the familiar Swagger UI page:

The raw yaml Swagger 2.0 is also available at http://localhost:8080/doc.yaml
If MCP is enabled, you can test the MCP server as well:
# Check MCP server health
> curl 'http://localhost:8081/mcp/health'
{"status":"healthy","server":"flapi-mcp-server","version":"0.3.0","protocol_version":"2024-11-05","tools_count":0}
# Initialize MCP connection
> curl -X POST http://localhost:8081/mcp/jsonrpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "initialize"}'
# List available tools
> curl -X POST http://localhost:8081/mcp/jsonrpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}'
flAPI now supports the Model Context Protocol (MCP) in a unified configuration approach. Every flAPI instance automatically runs both a REST API server and an MCP server concurrently, allowing you to create AI tools alongside your REST endpoints using the same configuration files and SQL templates.
2026-07-28 (dual-era): serves the latest stateless MCP revision (server/discover, per-request metadata, cacheable results, OAuth discovery via RFC 9728) alongside the legacy initialize/session protocol — existing clients keep working unchangedasync and slow queries return a task handle immediately instead of blocking the connection; the durable task store survives a restart, with tasks/get / tasks/cancel and per-caller isolationstructuredContent, an outputSchema is learned after first use, and failures return actionable isError results the model can self-correct fromurl-path (REST), mcp-tool (MCP tool), or mcp-resource (MCP resource)allowed-roles), shadow/dry-run (_dryRun), response shaping, per-tool rate limiting, and a tool-description hygiene scannerflapi://customers/{id}), and x-mcp-header for per-tenant edge routingSee docs/MCP_REFERENCE.md — the dual-era model and all new capabilities are documented in §11.
POST /mcp/jsonrpc - Main JSON-RPC endpoint for tool callsGET /mcp/health - Health check endpointMCP is now automatically enabled - no separate configuration needed! Every flAPI instance runs both REST API and MCP servers concurrently.
Configuration files can define multiple entity types:
# Single configuration file serves as BOTH REST endpoint AND MCP tool
url-path: /customers/ # Makes this a REST endpoint
mcp-tool: # Also makes this an MCP tool
name: get_customers
description: Retrieve customer information by ID
result-mime-type: application/json
request:
- field-name: id
field-in: query
description: Customer ID
required: false
validators:
- type: int
min: 1
max: 1000000
preventSqlInjection: true
template-source: customers.sql
connection: [customers-parquet]
rate-limit:
enabled: true
max: 100
interval: 60
auth:
enabled: true
type: basic
users:
- username: admin
password: secret
roles: [admin]
# MCP Resource example
mcp-resource:
name: customer_schema
description: Customer database schema definition
mime-type: application/json
template-source: customer-schema.sql
connection: [customers-parquet]
Once MCP is enabled, you can interact with tools using JSON-RPC 2.0:
# Check MCP server health
curl 'http://localhost:8081/mcp/health'
# Initialize MCP connection
curl -X POST http://localhost:8081/mcp/jsonrpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "initialize"}'
# List available tools (discovered from unified configuration)
curl -X POST http://localhost:8081/mcp/jsonrpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}'
# Call a tool (same SQL template used for both REST and MCP)
curl -X POST http://localhost:8081/mcp/jsonrpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "get_customers", "arguments": {"id": "123"}}}'
Here's a simple example of how to create an API endpoint using flAPI:
flAPI uses the popular YAML format to configure the API endpoints. A basic configuration file looks like this:
project_name: example-flapi-project
project_description: An example flAPI project demonstrating various configuration options
template:
path: './sqls' # The path where SQL templates and API endpoint configurations are stored
environment-whitelist: # Optional: List of regular expressions for whitelisting envvars which are available in the templates
- '^FLAPI_.*'
duckdb: # Configuration of the DuckDB embedded into flAPI
db_path: ./flapi_cache.db # Optional: remove or comment out for in-memory database, we use this store also as cache
access_mode: READ_WRITE # See the https://duckdb.org/docs/configuration/overview) for more details
threads: 8
max_memory: 8GB
default_order: DESC
connections: # A YAML map of database connection configurations, a API endpoint needs to reference one of these connections
bigquery-lakehouse:
# SQL commands to initialize the connection (e.g., e.g. installing, loading and configuring the BQ a DuckDB extension)
init: |
INSTALL 'bigquery' FROM 'http://storage.googleapis.com/hafenkran';
LOAD 'bigquery';
properties: # A YAML map of connection-specific properties (accessible in templates via {{ context.conn.property_name }})
project_id: 'my-project-id'
customers-parquet:
properties:
path: './data/customers.parquet'
heartbeat:
enabled: true # The eartbeat worker is a background thread which can can be used to periodically trigger endpionts
worker-interval: 10 # The interval in seconds at which the heartbeat worker will trigger endpoints
enforce-https:
enabled: false # Whether to force HTTPS for the API connections, we strongly recommend to use a reverse proxy to do SSL termination
# ssl-cert-file: './ssl/cert.pem'
# ssl-key-file: './ssl/key.pem'
After that ensure that the template path (./sqls in this example) exists.
./sqls/customers.yaml):Each endpoint is at least defined by a YAML file and a corresponding SQL template in the template path. For our example we will create the file ./sqls/customers.yaml:
url-path: /customers/ # The URL path at which the endpoint will be available
request: # The request configuration for the endpoint, this defines the parameters that can be used in the query
- field-name: id
field-in: query # The location of the parameter, other options are 'path', 'query' and 'body'
description: Customer ID # A description of the parameter, this is used in the auto-generated API documentation
required: false # Whether the parameter is required
validators: # A list of validators that will be applied to the parameter
- type: int
min: 1
max: 1000000
preventSqlInjection: true
template-source: customers.sql # The path to the SQL template that will be used to generate the endpoint
connection:
- customers-parquet # The connection that will be used to execute the query
rate-limit:
enabled: true # Whether rate limiting is enabled for the endpoint
max: 100 # The maximum number of requests per interval
interval: 60 # The interval in seconds
auth:
enabled: true # Whether authentication is enabled for the endpoint
type: basic # The type of authentication, other options are 'basic' and 'bearer'
users: # The users that are allowed to access the endpoint
- username: admin
password: secret
roles: [admin]
- username: user
password: password
roles: [read]
heartbeat:
enabled: true # Whether the heartbeat worker if enabled will trigger the endpoint periodically
params: # A YAML map of parameters that will be passed by the heartbeat worker to the endpoint
id: 123
There are many more configuration options available, see the full documentation for more details.
./sqls/customers.sql):After the creation of the YAML endpoint configuration we need to connect the SQL template which connects the enpoint to the data connection. The template files use the Mustache templating language to dynamically generate the SQL query.
SELECT * FROM '{{{conn.path}}}'
WHERE 1=1
{{#params.id}}
AND c_custkey = {{{ params.id }}}
{{/params.id}}
The above template uses the path parameter defined in the connection configuration to directly query a local parquet file. If the id parameter is
provided, it will be used to filter the results.
To test the endpoint and see if everything worked, we can use curl. We should also provide the correct basic auth credentials (admin:secret in this case). To make the JSON result easier to read, we pipe the output to jq.
> curl -X GET -u admin:secret "http://localhost:8080/customers?id=123" | jq .
{
"next": "",
"total_count": 1,
"data": [
{
"c_mktsegment": "BUILDING",
"c_acctbal": 5897.82999999999992724,
"c_phone": "15-817-151-1168",
"c_address": "YsOnaaER8MkvK5cpf4VSlq",
"c_nationkey": 5,
"c_name": "Customer#000000123",
"c_comment": "ependencies. regular, ironic requests are fluffily regu",
"c_custkey": 123
}
]
}
flAPI uses the DuckDB DuckLake extension to provide modern, snapshot-based caching. You write the SQL to define the cached table, and flAPI manages schemas, snapshots, retention, scheduling, and audit logs.
cache by default):ducklake:
enabled: true
alias: cache
metadata-path: ./examples/data/cache.ducklake
data-path: ./examples/data/cache.ducklake
data-inlining-row-limit: 10 # Enable data inlining for small changes (optional)
retention:
max-snapshot-age: 14d
compaction:
enabled: false
scheduler:
enabled: true
primary-key/cursor → full refresh):url-path: /publicis
template-source: publicis.sql
connection: [bigquery-lakehouse]
cache:
enabled: true
table: publicis_cache
schema: analytics
schedule: 5m
retention:
max_snapshot_age: 14d
template_file: publicis/publicis_cache.sql
-- publicis/publicis_cache.sql
CREATE OR REPLACE TABLE {{cache.catalog}}.{{cache.schema}}.{{cache.table}} AS
SELECT
p.country,
p.product_category,
p.campaign_type,
p.channel,
sum(p.clicks) AS clicks
FROM bigquery_scan('{{{conn.project_id}}}.landing__publicis.kaercher_union_all') AS p
GROUP BY 1, 2, 3, 4;
-- publicis.sql
SELECT
p.country,
p.product_category,
p.campaign_type,
p.channel,
p.clicks
FROM {{cache.catalog}}.{{cache.schema}}.{{cache.table}} AS p
WHERE 1=1
Notes:
cache.analytics) is created automatically if missing.data-inlining-row-limit is configured, small cache changes (≤ specified row limit) are written directly to DuckLake metadata instead of creating separate Parquet files. This improves performance for small incremental updates.DuckLake supports writing very small inserts directly into the metadata catalog instead of creating a Parquet file for every micro-batch. This is called "Data Inlining" and can significantly speed up small, frequent updates.
Enable globally: configure once under the top-level ducklake block:
ducklake:
enabled: true
alias: cache
metadata_path: ./examples/data/cache.ducklake
data_path: ./examples/data/cache.ducklake
data_inlining_row_limit: 10 # inline inserts up to 10 rows
Behavior:
data-inlining-row-limit are inlined into the catalog metadata.Manual flush (optional): you can flush inlined data to Parquet files at any time using DuckLake’s function. Assuming your DuckLake alias is cache:
-- Flush all inlined data in the catalog
CALL ducklake_flush_inlined_data('cache');
-- Flush only a specific schema
CALL ducklake_flush_inlined_data('cache', schema_name => 'analytics');
-- Flush only a specific table (default schema "main")
CALL ducklake_flush_inlined_data('cache', table_name => 'events_cache');
-- Flush a specific table in a specific schema
CALL ducklake_flush_inlined_data('cache', schema_name => 'analytics', table_name => 'events_cache');
Notes:
data_inlining_row_limit, flAPI won’t enable inlining and DuckLake will use regular Parquet writes.The engine infers sync mode from your YAML:
primary-key, no cursor → full refresh (CTAS)cursor only → incremental appendprimary-key + cursor → incremental merge (upsert)Example YAMLs:
# Incremental append
cache:
enabled: true
table: events_cache
schema: analytics
schedule: 10m
cursor:
column: created_at
type: timestamp
template-file: events/events_cache.sql
# Incremental merge (upsert)
cache:
enabled: true
table: customers_cache
schema: analytics
schedule: 15m
primary-key: [id]
cursor:
column: updated_at
type: timestamp
template_file: customers/customers_cache.sql
Cache template variables available to your SQL:
{{cache.catalog}}, {{cache.schema}}, {{cache.table}}, {{cache.schedule}}{{cache.snapshotId}}, {{cache.snapshotTimestamp}} (current){{cache.previousSnapshotId}}, {{cache.previousSnapshotTimestamp}} (previous){{cache.cursorColumn}}, {{cache.cursorType}}{{cache.primaryKeys}}{{params.cacheMode}} is available with values full, append, or mergeIncremental append example:
-- events/events_cache.sql
INSERT INTO {{cache.catalog}}.{{cache.schema}}.{{cache.table}}
SELECT *
FROM source_events
WHERE {{#cache.previousSnapshotTimestamp}} event_time > TIMESTAMP '{{cache.previousSnapshotTimestamp}}' {{/cache.previousSnapshotTimestamp}}
Incremental merge example:
-- customers/customers_cache.sql
MERGE INTO {{cache.catalog}}.{{cache.schema}}.{{cache.table}} AS t
USING (
SELECT * FROM source_customers
WHERE {{#cache.previousSnapshotTimestamp}} updated_at > TIMESTAMP '{{cache.previousSnapshotTimestamp}}' {{/cache.previousSnapshotTimestamp}}
) AS s
ON t.id = s.id
WHEN MATCHED THEN UPDATE SET
name = s.name,
email = s.email,
updated_at = s.updated_at
WHEN NOT MATCHED THEN INSERT (*) VALUES (s.*);
cache.schedule on each endpoint (e.g., 5m).flAPI maintains an audit table inside DuckLake at cache.audit.sync_events and provides control endpoints:
curl -X POST "http://localhost:8080/api/v1/_config/endpoints/publicis/cache/refresh"
curl "http://localhost:8080/api/v1/_config/endpoints/publicis/cache/audit"
curl "http://localhost:8080/api/v1/_config/cache/audit"
cache.retention:cache:
retention:
max-snapshot-age: 7d # time-based retention
# keep-last-snapshots: 3 # version-based retention (subject to DuckLake support)
The system applies retention after each refresh and you can also trigger GC manually:
curl -X POST "http://localhost:8080/api/v1/_config/endpoints/publicis/cache/gc"
ducklake.scheduler, periodic file merging is performed via DuckLake ducklake_merge_adjacent_files.Use these variables inside your cache templates and main queries:
Identification
{{cache.catalog}} → usually cache{{cache.schema}} → e.g., analytics (auto-created if missing){{cache.table}} → your cache table nameMode and scheduling
{{params.cacheMode}} → full | append | merge{{cache.schedule}} → if set in YAMLSnapshots
{{cache.snapshotId}}, {{cache.snapshotTimestamp}}{{cache.previousSnapshotId}}, {{cache.previousSnapshotTimestamp}}Incremental hints
{{cache.cursorColumn}}, {{cache.cursorType}}{{cache.primaryKeys}} → comma-separated list, e.g., id,tenant_idAuthoring tips:
CREATE OR REPLACE TABLE ... AS SELECT ....INSERT INTO cache.table SELECT ... WHERE event_time > previousSnapshotTimestamp.MERGE INTO cache.table USING (SELECT ...) ON pk ....cache.schema is set; flAPI will auto-create it.max-snapshot-age first. Version-based retention depends on DuckLake support.flAPI extends plain YAML with lightweight include and environment-variable features so you can keep configurations modular and environment-aware.
{{env.VAR_NAME}} anywhere in your YAML.template:
path: './sqls'
environment-whitelist:
- '^FLAPI_.*' # allow all variables starting with FLAPI_
- '^PROJECT_.*' # optional additional prefixes
Examples:
# Substitute inside strings
project-name: "${{env.PROJECT_NAME}}"
# Build include paths dynamically
template:
path: "{{env.CONFIG_DIR}}/sqls"
You can splice content from another YAML file directly into the current document.
{{include from path/to/file.yaml}}{{include:top_level_key from path/to/file.yaml}} includes only that keyif <condition> to either formConditions supported:
true or falseenv.VAR_NAME (include if the variable exists and is non-empty)!env.VAR_NAME (include if the variable is missing or empty)Examples:
# Include another YAML file relative to this file
{{include from common/settings.yaml}}
# Include only a section (top-level key) from a file
{{include:connections from shared/connections.yaml}}
# Conditional include based on an environment variable
{{include from overrides/dev.yaml if env.FLAPI_ENV}}
# Use env var in the include path
{{include from {{env.CONFIG_DIR}}/secrets.yaml}}
Resolution rules and behavior:
#).Tips:
{{include:...}}) to avoid unintentionally overwriting unrelated keys.connections.yaml, auth.yaml) and include them where needed.The same flapi binary that serves the API can fold an entire
config tree into itself, producing one self-contained executable
deployable via scp.
# Pack a config tree into a new bundled binary
flapi pack --in ./examples --out flapi-prod
# Inspect what's bundled
./flapi-prod info
# Extract the bundle for debugging
./flapi-prod unpack --to /tmp/extracted
# Run it — serves the bundled config from any cwd
cd /tmp && ./flapi-prod
How it works: a ZIP archive is appended after the executable on
Linux/Windows (or written into a pre-allocated __FLAPI/__bundle
Mach-O segment on macOS, then re-codesign-ed so the result is
notarisable). At startup, flAPI reverse-scans for the bundle (or
probes the segment on macOS) and registers an
EmbeddedArchiveFileProvider plus an embed:// DuckDB
filesystem so config / SQL templates / read_csv() calls all
resolve to the in-memory bundle. If no bundle is present
(unbundled binary, truncated tail), all paths fall back to the
local filesystem unchanged — existing operators see no behaviour
change.
Secrets stay out of the bundle. flapi pack refuses files
matching *.env, secrets/*, *.pem, *.key by default. The
override (--allow-secrets) is for testing only. Credentials
come from the environment at runtime (AWS_*, GOOGLE_*,
AZURE_*, FLAPI_CONFIG_SERVICE_TOKEN, {{env.VAR}} YAML
interpolation).
Reproducible builds. Set SOURCE_DATE_EPOCH before
flapi pack and the output is byte-identical across runs:
SOURCE_DATE_EPOCH=1700000000 flapi pack --in examples --out a
SOURCE_DATE_EPOCH=1700000000 flapi pack --in examples --out b
sha256sum a b # identical
12-factor env vars. FLAPI_CONFIG falls back for -c /
--config; FLAPI_LOG_LEVEL falls back for --log-level. CLI
flag wins over env var wins over built-in default. Invalid log
levels exit non-zero with a single-line error.
macOS notes. The reserved-segment size is 16 MiB by default
(knob FLAPI_RESERVED_BUNDLE_MIB at CMake configure time);
oversized bundles exit non-zero with a corrective error. A
--macos-append flag is available for local debugging — it uses
the Linux/Windows append-after-EOF layout but the result is
intentionally not notarisable.
See docs/CLI_REFERENCE.md §3 and docs/spec/DESIGN_DECISIONS.md §9 for full reference + rationale.
The source code of flAPI is written in C++ and closely resembles the DuckDB build process. A good documentation of the build process is the GitHub action in build.yaml. In essecence a few prerequisites need to be met:
In essecence a few prerequisites need to be met:
sudo apt-get install -y build-essential cmake ninja-buildgit clone --recurse-submodules https://github.com/datazoode/flapi.gitmake releaseThe build process will download and build DuckDB v1.1.2 and install the vcpkg package manager. We depend on the following vcpkg ports:
argparse - Command line argument parsercrow - Our REST-Web framework and JSON handlingyaml-cpp - YAML parserjwt-cpp - JSON Web Token libraryopenssl - Crypto librarycatch2 - Testing frameworkNote: MCP support is built-in and doesn't require additional dependencies beyond what's already included.
For more detailed information, check out our full documentation:
flAPI is listed in the official MCP Registry under the name below (this line also serves as the registry's PyPI ownership marker):
mcp-name: io.github.datazoode/flapi
flAPI sends anonymous application_start and application_stop events to help the team understand adoption. No query data, credentials, or personal information is ever sent.
Opt out (any one of these is sufficient):
# One-off via CLI flag
./flapi --no-telemetry
# Per-session via environment variable
export FLAPI_NO_TELEMETRY=1
./flapi
# Permanently via config file (flapi.yaml)
telemetry:
enabled: false
See CLI Reference and Configuration Reference for full details.
We welcome contributions! Please see our Contributing Guide for more details.
flAPI is licensed under the Business Source License (BSL) Version 1.1. The BSL is a source-available license that gives you the following permissions:
For commercial licensing — embedding flAPI in a product, offering it as a hosted service, or any redistribution that the Additional Use Grant restricts — contact contact@data-zoo.de.
See the LICENSE file for the full text.
If you have any questions or need help, please open an issue or join our community chat.
If flAPI misbehaves — an endpoint that will not serve, a cache that will not invalidate,
an auth flow that will not complete — please
open an issue. Deployments differ in ways we
cannot reproduce here, so a report with your config is the fastest path to a fix. Every
JSON error response carries a report_issue link for exactly this reason.
If it saved you time, a star on the repo helps other people find it.
On an interactive start, a small banner says the same thing once a day. Under a container
or systemd there is no terminal, so it never prints — the startup log line carries the
pointer instead. Silence both with DATAZOO_NO_BANNER=1.
Sign in to join the discussion.
No comments yet. Be the first to say what this is good for.

Write HTML. Render video. Built for agents.
Ultra-lightweight, open-source, self-hosted personal AI agent framework in Python with WebUI, tools, memory, MCP, multi-agent workflows, automation, and chat apps
SkillOpt is a text-space optimizer that trains reusable natural-language skills for frozen LLM agents through trajectory-driven edits, validation-gated updates, and deployable best_skill.md artifacts.

Omnigent is an open-source AI agent framework and meta-harness: orchestrate Claude Code, Codex, Cursor, Pi, and custom agents — swap harnesses without rewriting, enforce policies and sandboxing, and collaborate in real time from any device.
A theoretical reconstruction of the Claude Mythos architecture, built from first principles using the available research literature.
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!