Flaiwheel
Self-hosted memory and governance for coding agents: structured knowledge capture, hybrid search with reranking, codebase analysis and git-native storage.
ماذا يمكنك أن تفعل مع Flaiwheel؟
- Indexes your project documentation (
.md,.pdf,.html,.docx,.rst,.txt,.json,.yaml,.csv) into a vector database - Provides an MCP server that AI agents (Cursor, Claude Code, VS Code Copilot) connect to
- Hybrid search — combines semantic vector search with BM25 keyword search via Reciprocal Rank Fusion (RRF) for best-of-both-worlds retrieval
- Cross-encoder reranker — optional reranking step that rescores candidates with a cross-encoder model for significantly higher precision on vocabulary-mismatch queries
- Behavioral Directives — AI agents silently search Flaiwheel before every response, auto-document after every task, and reuse before recreating — all without being asked
get_file_context(filename)— pre-loads spatial knowledge for any file the agent is about to edit (complementsget_recent_sessionsfor full temporal + spatial context)- post-commit git hook — captures every
fix:,feat:,refactor:,perf:,docs:commit as a structured knowledge doc automatically - Living Architecture — AI agents are instructed to maintain self-updating Mermaid.js diagrams for system components and flows
التثبيت
خطوات التثبيت موجودة في التوثيق أدناه. التوثيق
التوثيق
مأخوذ من ملف README للمشروع على GitHub ويُحدَّث أسبوعيًا. تفتح الروابط على GitHub.
المحتويات
- Flaiwheel
- 🚀 Why Flaiwheel Exists
- 🧠 How Flaiwheel Is Different
- ✅ Who Flaiwheel Is For
- ❌ Not For
- 🆚 Where Flaiwheel Fits
- ⚙️ Key Technical Features
- What’s New in v3.15.3 — Plain HTTP remains the default
- v3.15.2 TLS caveat
- What’s New in v3.15.0 — Flaiwheel issues its own TLS certificate
- What’s New in v3.14.0 — Remote MCP without a reverse proxy
- Quick Start — One Command (recommended)
- Optional: Open Terminal Local Daemon (Open WebUI)
- Updating
- Manual Setup
- Knowledge Repo Structure
- Supported Input Formats
- Configuration
- Architecture
- Web UI
- Development
- License
Flaiwheel
Self-hosted memory & governance layer for AI coding agents. Turn every bug fix into permanent knowledge. Zero cloud. Zero lock-in.
🚀 Why Flaiwheel Exists
AI coding agents forget everything between sessions. That leads to repeated bugs, lost architectural decisions, and knowledge decay.
Flaiwheel ensures:
- Agents search before coding
- Agents document after fixing
- Commits automatically capture knowledge
- Memory compounds over time
Every bug fixed makes the next bug cheaper.
🧠 How Flaiwheel Is Different
- Persistent AI Memory That Compounds — knowledge doesn't reset between sessions.
- Git-Native Automation — commits automatically become structured knowledge.
- Governance, Not Just Storage — quality gates + enforced documentation.
- Hybrid Search + Reranking — high-precision context for real codebases.
- Fully Self-Hosted — single Docker container, no external infrastructure.
- Zero Lock-In — all knowledge stored as structured flat files in Git.
✅ Who Flaiwheel Is For
- Engineering teams using AI coding assistants in real projects
- Codebases where repeated bugs are expensive
- Teams requiring full data control
- AI-native development environments
❌ Not For
- Small hobby projects under a few thousand lines
- Developers who just want better autocomplete
- Pure SaaS workflows with no interest in self-hosting
🆚 Where Flaiwheel Fits
- AI coding tools generate code.
- RAG tools retrieve documents.
- Flaiwheel governs and compounds structured engineering knowledge inside your own infrastructure.
It does not replace your AI assistant. It makes it reliable at scale.
📄 Whitepaper (PDF) — Vision, architecture, and design in depth.
⚙️ Key Technical Features
Flaiwheel is a self-contained Docker service that operates on three levels:
Pull — agents search before they code (search_docs, get_file_context)
Push — agents document as they work (write_bugfix_summary, write_architecture_doc, …)
Capture — git commits auto-capture knowledge via a post-commit hook, even without an AI agent
- Indexes your project documentation (
.md,.pdf,.html,.docx,.rst,.txt,.json,.yaml,.csv) into a vector database - Provides an MCP server that AI agents (Cursor, Claude Code, VS Code Copilot) connect to
- Hybrid search — combines semantic vector search with BM25 keyword search via Reciprocal Rank Fusion (RRF) for best-of-both-worlds retrieval
- Cross-encoder reranker — optional reranking step that rescores candidates with a cross-encoder model for significantly higher precision on vocabulary-mismatch queries
- Behavioral Directives — AI agents silently search Flaiwheel before every response, auto-document after every task, and reuse before recreating — all without being asked
get_file_context(filename)— pre-loads spatial knowledge for any file the agent is about to edit (complementsget_recent_sessionsfor full temporal + spatial context)- post-commit git hook — captures every
fix:,feat:,refactor:,perf:,docs:commit as a structured knowledge doc automatically - Living Architecture — AI agents are instructed to maintain self-updating Mermaid.js diagrams for system components and flows
- Executable Test Flows — test scenarios are documented in machine-readable BDD/Gherkin format (
Given,When,Then) for QA automation - Learns from bugfixes — agents write bugfix summaries that are instantly indexed
- Structured write tools — 7 category-specific tools (bugfix, architecture, API, best-practice, setup, changelog, test case) that enforce quality at the source
- Structured relations (v1) —
relations()andtimeline()derive a per-project knowledge graph from optional YAML frontmatter on existing docs (id,replaces,depends_on,fixes,implements,status). No second store — markdown stays canonical and Git history is the validity window - Pre-commit validation —
validate_doc()checks freeform markdown before it enters the knowledge base, including unknown-relation-key warnings - Ingest quality gate — files with critical issues are automatically skipped during indexing (never deleted — you own your files)
- Auto-syncs via Git — pulls AND pushes to a dedicated knowledge repo
- Tool telemetry (persistent) — tracks every MCP call per project (searches, writes, misses, patterns), detects knowledge gaps, and nudges agents to document — persisted across restarts and visible in the Web UI
- Impact metrics API —
/api/impact-metricscomputes estimated time saved + regressions avoided; CI pipelines can post guardrail outcomes to/api/telemetry/ci-guardrail-report - Proactive quality checks — automatically validates knowledge base after every reindex
- Knowledge Bootstrap — "This is the Way": analyse messy repos, classify files, detect duplicates, propose a cleanup plan, execute with user approval (never deletes files)
- Cold-Start Codebase Analyzer —
analyze_codebase(path)scans a source code directory entirely server-side (zero tokens, zero cloud). Uses Python's built-inastmodule for Python, regex for TypeScript/JavaScript, the existing MiniLM embedding model for classification and duplicate detection. Returns a singlebootstrap_report.mdwith language distribution, category map, top 20 files to document first ranked by documentability score, duplicate pairs, and coverage gaps. Reduces cold-start token cost by ~90% on legacy codebases. - Multi-project support — one container manages multiple knowledge repos with per-project isolation
- Includes a Web UI for configuration, monitoring, and testing
What’s New in v3.15.3 — Plain HTTP remains the default
- A new installation uses
http://host:8081/sse. This is the recommended configuration until the Web UI provides TLS activation, CA download, and operating-system installation instructions. An update preserves its existing mode unlessFLAIWHEEL_TLS_AUTO=0or1is set explicitly. - Automatic TLS remains available as an opt-in feature. The generated certificate is valid, but Cursor/Electron and other clients may require the Flaiwheel CA to be installed in the operating-system trust store.
FLAIWHEEL_TLS_AUTO=0now explicitly returns an existing TLS-enabled installation to HTTP while preserving its volumes and otherMCP_*settings.- Leaving
FLAIWHEEL_TLS_AUTOunset during an update preserves the currently deployed mode.
v3.15.2 TLS caveat
v3.15.2 corrected endpoint schemes and certificate persistence, but its direct-SSE client guidance was incomplete. An env block containing NODE_EXTRA_CA_CERTS does not necessarily control TLS for a direct Cursor/Electron SSE connection. Direct clients may require the generated CA in the operating-system trust store. Use the default HTTP endpoint unless you have completed that trust step.
What’s New in v3.15.0 — Flaiwheel issues its own TLS certificate
- A LAN deployment can now be encrypted without the operator touching a certificate tool. No public CA will issue for
192.168.178.230, so the only previous options wereopensslby hand or a proxy. SetMCP_SSE_TLS_AUTO=trueand Flaiwheel generates a private CA plus a server certificate on first start, covering the configured hosts and loopback. - Everything on Flaiwheel's side is automatic, and repeated starts are safe. Material is persisted in
/data/tlsand reused while it is valid and still covers the requested names — an upgrade does not change the fingerprint, so a client that pinned the CA stays valid. A certificate that has gone stale, stopped covering a host, or lost its matching key is re-issued, with the reason logged. - One thing it genuinely cannot do: make another machine trust the CA. The container has no access to a client's trust store — the same boundary that forces
mkcertto run a per-machine step. So the startup log prints the fingerprint and the exactNODE_EXTRA_CA_CERTS=...line for the client's env block. That is the floor, and it is real TLS: encryption and identity, with the CA pinned by trust-on-first-use. - No
NODE_TLS_REJECT_UNAUTHORIZED=0anywhere in this path. The easy way to "make HTTPS work" is to disable verification, which defends against nothing; it is not offered as an option here. - Opt-in, because turning it on is a protocol change. Auto-TLS flips the endpoint from
http://tohttps://, and doing that unasked during an upgrade would break every existing client — the same class of failure as an installer that refuses to upgrade. It fails closed too: if provisioning fails, startup aborts rather than quietly serving cleartext. - Verified with a real TLS stack, not a fixture. A client trusting only the generated CA completes a TLSv1.3 handshake and gets a
200; an untrusting client is rejected. Both directions asserted. - Tests: 370 → 439, covering SAN derivation, signature chain verification, idempotence, stale/mismatched material, key permissions and every fail-closed path.
What’s New in v3.14.0 — Remote MCP without a reverse proxy
- Serve MCP to a LAN or remote client without adding a component. Until now the SSE endpoint was reachable only from
localhost: the socket bound0.0.0.0while the application layer answeredHTTP 421 Invalid Host headerto every otherHost. The workaround was a proxy that rewritesHost: localhost— a moving part, and a boot-ordering dependency. SetMCP_SSE_ALLOWED_HOSTS=flaiwheel.example.comand connect directly. - The root cause was not the bind address. Flaiwheel builds
FastMCPitself and passed neitherhostnortransport_security, so the SDK's loopback-only guard always applied.FASTMCP_HOSTlooks like the fix and is silently inert — init arguments outrank environment variables in pydantic-settings. Verified empirically before and after. - The guard stays ON. The tempting one-liner (
host='0.0.0.0') makes the SDK skip its auto-enable and turn DNS-rebinding protection off entirely. Instead, protection remains enabled with a wider allowlist —HostandOriginare still validated, and lookalike suffixes likeflaiwheel.example.com.evil.comare still rejected. - Nothing changes for existing installs. An unconfigured Flaiwheel is loopback-only, exactly as before, and still rejects remote hosts. Loopback entries are never dropped, so container health checks,
ssh -Lforwards and existing Host-rewriting proxies keep working. - Native TLS — a remote deployment needs no proxy at all. Set
MCP_SSE_TLS_CERTFILE+MCP_SSE_TLS_KEYFILEand the endpoint is served over HTTPS directly. Verified against a real TLS listener: TLSv1.3,200over HTTPS for the allowlisted host,421still enforced forevil.example.com, and a plain HTTP request to the same port rejected. - TLS fails closed. A half-configured or unreadable certificate aborts startup instead of quietly serving plaintext — an operator who asked for encryption must never silently get cleartext.
- Startup tells you when you are no longer loopback-only, and
SECURITY.mdcarries the deployment table so you can see which layer encrypts what. - Tests: 335 → 370, including the guard exercised through the SDK's real middleware and every fail-closed TLS path.
Previous: v3.13.0 — Observability
- Flaiwheel now knows whether its knowledge repo is still connected to its remote. Everything before this reported on pushes that were attempted. The failure that hid 325 documents in a Docker volume for 2.5 months attempted nothing: the clone had drifted from its remote, so there was never anything to commit, so no push could fail, so nothing went red.
check_divergence()comparesHEADagainst@{u}and classifies the result assynced/ahead/behind/diverged/no-upstream. - The "nothing to push" path is where this matters. That branch used to return an unconditional "already in sync". It now verifies the claim. Divergence is also checked after every successful push (did the commit actually land?), after a rejected push (a rejection is the classic symptom — now named instead of leaving you to read a git error), and on every pull.
- A repo that indexes perfectly and pushes nothing is no longer "healthy".
/healthgainsdivergence_status,commits_ahead,commits_behindandlast_divergence_at, and reportsdegradedondiverged,aheadorno-upstream. Beingbehindis the normal state between two pulls and deliberately does not alarm. - The agent is told directly.
write_*results append an explicit warning when the repo has diverged — including on "nothing to push". A warning in an endpoint nobody polls does not exist; the agent that just wrote the document is the one that needs to know it never left the machine. - Tests: 316 → 335, against real temp repos including a force-pushed rewritten upstream — the real-world trigger, where a secret purge or a squash silently desynchronises every clone.
- This closes the 2026-08-19 incident completely. The one item that looked outstanding — "watcher path scoping" — was retracted as a misdiagnosis after checking the running container. Its only evidence was the log line
knowledge: update flaiwheel/telemetry.json, read as one project's file being committed into all 11 repos. The real path is.flaiwheel/telemetry.json, with a leading dot: the signature of the porcelain off-by-one already fixed in v3.12.2. Every project owns an identically-named telemetry file, so all 11 watchers logged the same mangled string at once — uniformity caused by shared code, mistaken for shared state.
Previous: v3.12.3
- Every dependency is capped below the next major. Eleven requirements were unbounded
>=X. That fails silently: the breaking release lands, existing installs keep working off a stale resolve, and it only bites on the next fresh install — CI, a Docker rebuild, a new contributor. Exactly howmcp2.0.0 broke CI and the Docker build together three weeks after release while every dev machine stayed green. A clean install resolves to identical versions as before, so this constrains the future without moving anything today. - Sustained push failure now degrades
/health.HealthTrackerkept onlylast_push_ok— a single boolean the next attempt overwrites — so one blip and a repo failing for weeks looked the same.push_failures_consecutiveescalates past 3 consecutive failures. A single failure deliberately does not degrade; crying wolf on transients is how alerts get ignored. /healthnames the failing projects. Addslast_push_ok,last_push_error,push_failures_consecutiveanddegraded_projects— previously the endpoint could saydegradedwhile showing only the default project's numbers, with no way to tell which repo was broken.- Pre-deploy image smoke test documented. An image can build cleanly and still fail every import at runtime. The README now verifies
from flaiwheel.server import create_mcp_serverinside the image before starting a container, and renames rather than removes the previous container so rollback is instant. - Tests: 308 → 316.
Previous: v3.12.2
- Auto-commit no longer drops the first worktree-modified file.
git status --porcelainemitsXY <path>where a leading space is data (" M file"). Stripping the whole output before splitting ate that space on the first line only, soline[3:]truncated the filename's first character —.flaiwheel/telemetry.jsonbecameflaiwheel/telemetry.json,git addfailed, and the commit aborted. Intermittent and file-order dependent, which is why it survived so long. - Renamed and copied files are staged correctly. Porcelain reports
old -> new; the whole string was passed togit add, so renames were never committed.
Previous: v3.12.1
- Pinned
mcp[cli]<2.0.0.mcp2.0.0 removedmcp.server.fastmcp(FastMCP→mcp.server.mcpserver), breaking every import of the server on a fresh resolve.
Previous: v3.12.0
- Auto-push now reports what actually happened.
push_pending()returns a structured result (ok/noop/disabled/failed/blocked) and everywrite_*tool renders that outcome. Previously the success line was derived from configuration (git_auto_push and bool(git_repo_url)), so it readAuto-pushed to remote: Trueeven when every push was being rejected. A failed push now says "Auto-push: FAILED — this doc is NOT on the remote" with the git error attached. - Push errors are no longer swallowed. The bare
exceptinpush_pending()that only wrote to the diagnostic log now records toHealthTrackerand returns the error to the caller. A failinggit commitis reported instead of raising through an uncheckedcheck=True. - gitleaks runs inside the container, on the write path. Flaiwheel's commits are machine-generated and never human-reviewed, so secret scanning now happens in
_push_local_changes()before the commit — not as a per-clone git hook that gets lost on re-clone.MCP_GITLEAKS_MODE=block(default) refuses to commit and reports the findings through the MCP result;warncommits and reports;offdisables. Honours a.gitleaks.tomlin the knowledge repo for allowlisting. A missing or broken scanner is reported explicitly, never silently skipped. - Tests: 300 → 308 (
tests/test_watcher_push.py: push success/failure/noop/disabled reporting, gitleaks block/warn/clean, unavailable-scanner visibility).
Previous: v3.11.0
- Telemetry now survives
docker volume rm flaiwheel-data. A per-project summary slice is mirrored from the Docker volume into each knowledge repo at<docs_path>/.flaiwheel/telemetry.json. On the next cold start,hydrate_from_mirrors()rebuilds the in-memory state from these files so the Tool Telemetry dashboard does not reset to zero. Hot tier wins when both exist; mirror writes are rate-limited to 60s/project to avoid one Git commit per tool call. Events stay in the volume only (too noisy for the knowledge repo). Don't want it committed? Add.flaiwheel/to your knowledge repo's.gitignore— Flaiwheel will still read/write the file locally. - Reset Telemetry button on every per-project tile in the Web UI. Zeroes summary counters across both storage tiers via the new
POST /api/telemetry/reset?project=<name>endpoint. The 30-day impact-metrics window keeps working because events history is preserved. - Agent instructions taught the relations workflow.
AGENTS.mdand both install.sh templates now include a "Structured Relations Workflow" section with three concrete rules (when to addfixes, when to addreplaces, when to adddepends_on) so agents actually use the v3.10.x graph machinery instead of ignoring it. - Client Configuration's "VS Code" tab is now "VS Code + Copilot" with explicit help text pointing at GitHub Copilot agent mode. The
.vscode/mcp.jsonfile Flaiwheel emits already works for Copilot — no separate snippet needed. - Tests: 292 → 300 (8 new tests in
test_telemetry.pyfor mirror writes, rate limiting, cold-start hydration, hot-tier authority, and reset semantics).
Previous: v3.10.1
- Every structured writer now auto-emits frontmatter.
write_bugfix_summary,write_architecture_doc,write_api_doc,write_best_practice,write_setup_doc,write_changelog_entry, andwrite_test_caseprependid/type/status: active+ empty relation lists to every new doc. Every doc you create from now on is automatically a graph node — no manual frontmatter editing required. IDs are derived from the existing filename slugs (e.g.adr-2026-05-22-payment-service-architecture,bugfix-2026-05-22-fix-race-condition,api-create-user-endpoint). - New helper
flaiwheel.frontmatter.emit()with stable, deterministic key order so same-day overwrites produce minimal diffs.
Previous: v3.10.0
- Structured relations (v1) — two new read-only MCP tools,
relations(entity_id)andtimeline(entity_id), derive a per-project knowledge graph from YAML frontmatter on existing markdown docs. No new persistent store and nograph_add/invalidatewrites: markdown stays the single source of truth and Git history is the validity window. Recognised relation keys:replaces,depends_on,fixes,implements. Scalar keys:id,type,status,superseded_at. - Frontmatter-aware quality checks —
validate_doc()now warns on unknown relation keys (info severity) and invalidstatusvalues (warning severity); heading-structure checks strip the leading---block first so frontmatter does not confuse the "first heading is h1" rule. GitWatcher.log_for_file()— read-only helper returning newest-first commits (hash,author, ISOdate,subject); backs thetimeline()tool.- Zero new dependencies — frontmatter parsing is stdlib-only (
flaiwheel.frontmatter). Nopython-frontmatter/PyYAMLadded. - Total tools: 28 → 30.
Note: the SQLite ER store (
graph_add/graph_invalidate/valid_from/valid_tocolumns) originally proposed for this feature is deferred as v2, gated on a real query becoming measurably too slow on v1. AST-driven code↔symbol edges (v3) remain merged with thefeature_ideas_backlog#13 track.
Previous: v3.9.40
- Installer:
claude-mdno longer fails on repeat runs —claude mcp addnon-zero exits (e.g. MCP already registered) no longer abort the parallel phase underset -e; registration output is captured safely. - Installer: correct release version from GitHub —
_FW_VERSIONis refreshed frommainpyproject.tomlwhen reachable so Docker rebuild / version checks stay aligned with the package even if rawinstall.shonmainlags at the CDN.
Previous: v3.9.29
- Glama tool detection fix —
AuthManagercrashed on read-only/databefore the MCP server could start (the real reason Glama saw 0 tools). Skipped in stdio cold-start mode. - Zero print() on stdout — 36 remaining
print()in watcher, indexer, readers, bootstrap replaced withdiag()(stderr). Verified: full MCP handshake returns all 28 tools over stdio. config.save()resilient — read-only filesystem logs warning instead of crashing.
Previous: v3.9.28
- Glama / MCP stdio fix — all diagnostic output moved to stderr; stdout is now JSON-RPC only. Glama Inspector now detects all 28 tools correctly.
- Improved cold-start detection — stdio cold-start logic handles empty Docker volumes correctly (no bootstrap / model download during Glama inspection).
Previous: v3.9.27
- License cleanup — one
LICENSEfile (BSL 1.1) for correct GitHub/Glama detection; all docs and headers point toLICENSE(notLICENSE.md). - Glama / stdio inspection — optional
[inspect]deps and cold-start stdio path for lightweight MCP directory builds.
Previous: v3.9.26
- Claude Cowork skill — the Flaiwheel workflow is now distributed as a native Claude skill. The installer writes
.skills/skills/flaiwheel/SKILL.mdto your project. When you open the project in Claude (Cowork), the skill is auto-available — no extra setup needed. The skill drives session-start context restore, pre-coding knowledge search, mandatory post-bugfix documentation, and session-end summarisation. - Skill source also committed to
skills/flaiwheel/SKILL.mdin this repo for reference and manual install.
Previous: v3.9.25
- WSL2 automatic pre-flight setup — WSL2 is now detected automatically and a dedicated pre-flight block runs before the main installer flow. No manual steps required:
- Switches
iptablesto legacy backend (fixes Docker networking / DNAT errors) - Adds the current user to the
dockergroup (no morepermission denied) - Starts the Docker daemon via
service(no systemd on WSL2) - Adds a Docker auto-start snippet to
~/.bashrc(idempotent, runs on every WSL2 login)
- Switches
- Scattered WSL2 checks throughout the script consolidated into the single pre-flight block.
Previous: v3.9.24
- Fix: auto-install python3 if missing — the installer uses
python3extensively for JSON manipulation. On minimal Linux/WSL2 systems without python3, config file writes silently failed (/dev/fd/63: line N: python3: command not found). python3 is now checked as prerequisite #0 and auto-installed via apt/dnf/yum/pacman/brew if missing.
Previous: v3.9.23
- Fix: Docker daemon start on WSL2 with iptables-legacy — Docker on WSL2 often fails to start silently because the default
iptables-nftbackend is not supported. The installer now switches toiptables-legacyviaupdate-alternativesbefore starting Docker. Also adds the current user to thedockergroup automatically. - All install commands updated to
bash <(curl ...)— every displayed install/re-run command throughout the script (error messages, AGENTS.md, Cursor rules, etc.) now uses process substitution to avoid WSL2 pipe issues.
Previous: v3.9.22
- Fix:
curl | bashpipe write failures on WSL2 —curl | bashcan fail withcurl: (23) Failure writing outputon WSL2 due to pipe/tmp permission issues. The primary install command in README is nowbash <(curl ...)(process substitution), which avoids the pipe entirely. The re-exec block also tries$HOMEas a fallback temp dir when/tmpwrites fail. Error message explicitly recommends thebash <(curl ...)form.
Previous: v3.9.21
- Fix: sudo guard moved before re-exec block — when
sudo curl | bashwas used, thecurl: (23)pipe error truncated the script before the previous sudo guard (which was after colors/functions) was ever reached. The guard is now the very first executable line (set -euo pipefailaside), so it fires even on a truncated download. Duplicate guard after colors removed.
Previous: v3.9.20
- Fix: Docker daemon startup poll on WSL2 — instead of a fixed 5-second sleep, the installer now polls
docker infoevery 2 seconds for up to 30 seconds afterservice docker start. Also shows the actual output ofservice docker startso startup errors are visible instead of silently swallowed.
Previous: v3.9.19
- Fix: Docker daemon start on WSL2 — WSL2 typically has no
systemd, sosystemctl start dockersilently failed. The installer now detects WSL2 via/proc/versionand usessudo service docker startinstead. If Docker still isn't running after install, a clear WSL2-specific error is shown with the exact fix command and a tip to add it to~/.bashrcfor auto-start on login.
Previous: v3.9.18
- Fix: block
sudo curl | bashandsudo bash install.sh— running the installer as root viasudobreaks GitHub CLI authentication:gh authstores credentials in/root/.config/gh/instead of the real user's home, making every subsequentghcall fail. Also causedcurl: (23) Failure writing outputpipe errors on WSL. The installer now detectsSUDO_USERat startup and exits immediately with a clear message telling the user to re-run withoutsudo. Privilege escalation for package installs is handled internally.
Previous: v3.9.17
- Fix:
gh auth loginmust not be run with sudo — after auto-installingghon Linux/WSL, the installer now explicitly tells the user to rungh auth loginwithoutsudo. If auth was previously done withsudo, credentials ended up in/root/.config/gh/and were invisible to the current user, causing the auth check to fail. The error messages at both the post-install and the auth-check step now clearly warn: do not use sudo forgh auth.
Previous: v3.9.16
- Fix: installer works on WSL and non-root Linux — all Linux package manager commands (
apt-get,dnf,yum,zypper,pacman), Docker convenience script, andsystemctlcalls now automatically usesudowhen the installer is not running as root. Root installs are unaffected. FixesPermission denied/ lock file errors on WSL and standard Linux desktop users.
Previous: v3.9.15
- Cold-start report cached in
/data/—analyze_codebase()saves the report to/data/coldstart-<project>.mdafter the first run. Subsequent calls return the cached report instantly (<1s). The installer also writes the cache during install so the very first MCP call by any agent is instant. Call withforce=Trueto regenerate after major codebase changes. analyze_codebase()in all agent Session Setup templates —AGENTS.md,.cursor/rules/flaiwheel.mdc,CLAUDE.md, and.github/copilot-instructions.mdall now include it as step 3 of Session Setup. Agents automatically get the codebase overview before starting work.- Cold-start prompt asked before Docker rebuild — all interactive questions (embedding model + cold-start) are now batched upfront, then the rebuild runs unattended.
- Fix: used
docker execfor cold-start — replaced broken HTTP calls to the MCP SSE endpoint with directdocker exec python3. Analysis now works reliably in ~20s.
Previous: v3.9.14
- Fix: fast-path always prompts for cold-start — no more silent skip when cached report exists.
Previous: v3.9.13
- Improved cold-start classification — two-pass classifier: path heuristics first, code-specific embedding templates as fallback.
Previous: v3.9.12
- Fix: y/n answer respected before cache check — explicit
ynow always re-runs analysis even when cached report exists.
Previous: v3.9.11
- Fix: coldstart functions in global scope — moved
_run_coldstart/_do_coldstart_analysisto top of script so fast-path can call them.
Previous: v3.9.10
- Fix: version check —
LATEST_VERSIONnow uses_FW_VERSIONdirectly, no CDN fetch.
Previous: v3.9.9
- Fix: cold-start on all paths —
_run_coldstart()called from fast-path, update, and fresh install. Smart cache detection.
Previous: v3.9.8
- Cold-start report caching —
analyze_codebase()cached to/data/coldstart-<project>.mdfor instant reads. Newforce=Trueparam.
Previous: v3.9.7
- Agent Session Setup — all instruction templates now include
analyze_codebase()as a first-session step.
Previous: v3.9.6
- Fix: use docker exec — replaced broken HTTP calls to MCP SSE endpoint with direct
docker exec python3invocation. Cold-start report now actually works (~20s).
Previous: v3.9.5
- Fix: warm up embedding model — added model warm-up before cold-start analysis (superseded by v3.9.6).
Previous: v3.9.4
- Fix: cold-start retries while model loads — installer now retries
analyze_codebase()for up to 90s after container starts.
Previous: v3.9.3
- Fix: update detection always checks
main—LATEST_VERSIONnow fetched frommainbranch so stale cached installers no longer silently skip updates.
Previous: v3.9.2
- Cold-start prompt moved before Docker rebuild — all interactive questions now batched upfront.
Previous: v3.9.1
- Cold-start prompt moved upfront — the
install.shcold-start question is now asked right after the embedding model selection (before the Docker rebuild), so all interactive questions are gathered first and the user never misses the prompt after a long rebuild.
Previous: v3.9.0
analyze_codebase(path)— new 28th MCP tool for zero-token cold-start analysis of legacy codebases. Runs entirely server-side in Docker. Uses Pythonast, regex, MiniLM embeddings, and nearest-centroid classification. Returns a rankedbootstrap_report.mdwith language distribution, category map, top 20 files by documentability score, near-duplicate pairs, and recommended next steps. Reduces cold-start token cost by ∼90%.
Previous: v3.8.3
- No auto-index on project add — adding a project via the web UI no longer immediately pulls and embeds the knowledge repo. Indexing is now deferred until explicitly triggered (“Git Pull + Reindex” or
reindex()MCP tool), keeping the vector DB clean until the repo has been reviewed.
Previous: v3.6.x
- VS Code / GitHub Copilot support — installer writes
.vscode/mcp.jsonand.github/copilot-instructions.md. - Claude Desktop support — installer auto-configures Claude Desktop via
mcp-remote. - Web UI Client Configuration panel — VS Code and Claude Code CLI tabs added.
Previous: v3.5.x
- Claude Desktop + Claude Code CLI support added.
- README strategically rewritten with positioning, target audience, and competitive framing.
Previous: v3.4.x
- Search miss rate fix —
search_bugfixescalls no longer inflate miss rate above 100%. - Classification consistency —
_path_category_hintunified token-based approach across all categories. CHANGELOG.mdadded to repo root.
Quick Start — One Command (recommended)
Prerequisites: GitHub CLI authenticated (gh auth login), Docker running.
Platform support: macOS and Linux work out of the box. On Windows, run the installer from WSL or Git Bash (Docker Desktop must be running with WSL 2 backend enabled).
Run this from inside your project directory:
bash <(curl -sSL https://raw.githubusercontent.com/dl4rce/flaiwheel/main/scripts/install.sh)
WSL2 / Linux note: Use the
bash <(curl ...)form above — it avoidscurl: (23)pipe write errors that occur withcurl | bashon some WSL2 setups. Never prefix withsudo.
That's it. The installer automatically:
- Detects your project name and GitHub org from the git remote
- Creates a private
<project>-knowledgerepo with the standard folder structure - Starts the Flaiwheel Docker container pointed at that repo
- Configures Cursor — writes
.cursor/mcp.jsonand.cursor/rules/flaiwheel.mdc - Configures VS Code / GitHub Copilot — writes
.vscode/mcp.json(native SSE, VS Code 1.99+) and.github/copilot-instructions.md - Configures Claude Desktop (macOS app) — writes
claude_desktop_config.jsonviamcp-remotebridge (requires Node.js) - Configures Claude Code CLI — writes
.mcp.json+CLAUDE.mdand runsclaude mcp addautomatically if the CLI is on PATH - Installs Claude Cowork skill — writes
.skills/skills/flaiwheel/SKILL.mdso the full Flaiwheel workflow is available as a native Claude skill - Writes
AGENTS.mdfor all other agents - If existing
.mddocs are found, creates a migration guide — the AI will offer to organize them into the knowledge repo
After install:
| Agent | What to do |
|---|---|
| Cursor | Restart Cursor → Settings → MCP → enable flaiwheel toggle |
| Claude Desktop (macOS app) | Quit and reopen Claude for Mac — hammer icon appears when connected |
| Claude Code CLI | Already registered automatically — run /mcp inside Claude Code to verify |
| VS Code | Open project → Command Palette → MCP: List Servers → start flaiwheel |
| Claude (Cowork) | Skill auto-loads from .skills/skills/flaiwheel/SKILL.md — no further action needed |
The installer also sets up a post-commit git hook that automatically captures every fix:, feat:, refactor:, perf:, and docs: commit as a structured knowledge doc — no agent or manual action required.
Once connected, the AI has access to all Flaiwheel tools. If you have existing docs, tell the AI: "migrate docs".
Optional: Open Terminal Local Daemon (Open WebUI)
If you also use Open WebUI's Open Terminal integration, this repo includes helper installers for a local open-terminal daemon.
Third-party write-ups (for example AI·Collab — Open Terminal) may mirror only the Linux script; macOS uses scripts/macos/install-open-terminal-launchagent.sh below. After any mirror update, re-check the file with shasum -a 256 against the same revision on GitHub.
One-liner install via curl (no git clone)
Use main or pin a commit SHA / tag in the URL for reproducible bytes.
Linux / WSL2 (systemd --user):
curl -fsSL -o install-open-terminal-systemd-user.sh \
https://raw.githubusercontent.com/dl4rce/flaiwheel/main/scripts/install-open-terminal-systemd-user.sh
/bin/chmod +x install-open-terminal-systemd-user.sh
/bin/bash ./install-open-terminal-systemd-user.sh
macOS (LaunchAgent; do not use sudo):
curl -fsSL -o install-open-terminal-launchagent.sh \
https://raw.githubusercontent.com/dl4rce/flaiwheel/main/scripts/macos/install-open-terminal-launchagent.sh
/bin/chmod +x install-open-terminal-launchagent.sh
/bin/bash ./install-open-terminal-launchagent.sh
If chmod or bash are “not found”, your PATH is broken (often Conda base); the /bin/… paths above still work.
Linux / WSL2 (systemd --user)
./scripts/install-open-terminal-systemd-user.sh
- Service name:
com.flaiwheel.open-terminal-local.service - Default endpoint:
http://localhost:8000 - The script auto-generates an API key and prints it after install/reset.
- On WSL2, make sure
systemd=trueis enabled in/etc/wsl.conf.
Useful commands:
systemctl --user status com.flaiwheel.open-terminal-local.service
journalctl --user -u com.flaiwheel.open-terminal-local.service -f
macOS (launchctl LaunchAgent)
./scripts/macos/install-open-terminal-launchagent.sh
- LaunchAgent label:
com.flaiwheel.open-terminal-local - Default endpoint:
http://localhost:8000 - The script auto-generates an API key and prints it after install/reset.
- The LaunchAgent sets WorkingDirectory to
$HOMEby default so Open Terminal does not start in/private/tmp. - PATH:
launchddoes not load~/.zshrc, so the daemon used to see only/usr/bin:/bin:…and miss Homebrew / Supabase CLI. The generated wrapper prepends/opt/homebrew/bin,/usr/local/bin,~/.local/bin, and~/.npm-global/bin. Re-run the installer (menu →1 Update) after pulling this change so the wrapper is regenerated. - Persisted custom folder: the installer can save a path in
~/.config/flaiwheel/open-terminal-working-directory(fresh-install prompt, or menu →5 when re-running the script). Update (menu →1) keeps using that saved path. One-off override: setOPEN_TERMINAL_WORKING_DIRECTORYfor that run only.
Environment overrides (both scripts):
HOST=127.0.0.1 PORT=8000 OPEN_TERMINAL_CORS_ALLOWED_ORIGINS='https://your-openwebui.example' ./scripts/install-open-terminal-systemd-user.sh
HOST=127.0.0.1 PORT=8000 OPEN_TERMINAL_CORS_ALLOWED_ORIGINS='https://your-openwebui.example' ./scripts/macos/install-open-terminal-launchagent.sh
macOS only — custom initial folder for Open Terminal (must exist before you save it):
OPEN_TERMINAL_WORKING_DIRECTORY="$HOME/projects/my-repo" ./scripts/macos/install-open-terminal-launchagent.sh
Re-run the same script and choose 5 to change or clear the saved folder (or edit ~/.config/flaiwheel/open-terminal-working-directory). Non-interactive install: set the env var above or create that file with a single line (path); use AUTO_INSTALL_DEPS=1 to skip the first-run path prompt.
Updating
Run the same install command again from your project directory:
bash <(curl -sSL https://raw.githubusercontent.com/dl4rce/flaiwheel/main/scripts/install.sh)
The installer detects the existing container, asks for confirmation, then:
- Verifies the target host ports are actually free before touching anything (and refuses if a non-Flaiwheel process owns them)
- Rebuilds the Docker image with the latest code before stopping the old container, so a failed build is not an outage
- Recreates the container, preserving both volumes (
/dataand/docs), the host port bindings, and allMCP_*settings - Refreshes all agent configs and guides
Your knowledge base, index, and credentials are preserved — only the code is updated.
Shared hosts, custom ports, and proxies
If 8080/8081 are already taken (e.g. by a fronting proxy), point the installer at free ports instead of fighting over the defaults:
FLAIWHEEL_WEB_PORT=18080 FLAIWHEEL_SSE_PORT=18081 \
FLAIWHEEL_WEB_BIND=127.0.0.1 FLAIWHEEL_SSE_BIND=127.0.0.1 \
bash <(curl -sSL https://raw.githubusercontent.com/dl4rce/flaiwheel/main/scripts/install.sh)
| Variable | Default | Purpose |
|---|---|---|
FLAIWHEEL_WEB_PORT | 8080 | Host port for the Web UI |
FLAIWHEEL_SSE_PORT | 8081 | Host port for the MCP SSE endpoint |
FLAIWHEEL_WEB_BIND | 0.0.0.0 | Host bind address for the Web UI |
FLAIWHEEL_SSE_BIND | 0.0.0.0 | Host bind address for MCP SSE |
FLAIWHEEL_AGGRESSIVE_CLEANUP | 0 | Allow host-wide Docker pruning (docker image prune -af, docker container prune -f, systemctl stop docker) |
FLAIWHEEL_CLIENT_CA_PATH | $HOME/.flaiwheel/ca.pem | Where the installer exports the TLS CA so clients on this host can trust it |
On a shared host, leave FLAIWHEEL_AGGRESSIVE_CLEANUP unset. Those commands affect every project and container on the machine — systemctl stop docker stops all containers — so they are off by default and only run when you explicitly opt in.
Which ports does the installer change?
FLAIWHEEL_SSE_PORTchanges the container's published port only. Client config files generated for other tools still reference the default8081, so update those yourself if you remap it.
Manual Setup
Click to expand manual steps
1. Create a knowledge repo
# On GitHub, create: <your-project>-knowledge (private repo)
mkdir -p architecture api bugfix-log best-practices setup changelog
echo "# Project Knowledge Base" > README.md
git add -A && git commit -m "init" && git push
2. Build and start Flaiwheel
git clone https://github.com/dl4rce/flaiwheel.git /tmp/flaiwheel-build
docker build -t flaiwheel:latest /tmp/flaiwheel-build
# Smoke-test the image BEFORE starting or replacing a container.
# A broken transitive dependency only surfaces on a fresh resolve, so an
# image can build cleanly and still fail every import at runtime.
docker run --rm --entrypoint sh flaiwheel:latest -c \
'python -c "from flaiwheel.server import create_mcp_server; import flaiwheel; print(flaiwheel.__version__)"'
docker run -d \
--name flaiwheel \
-p 8080:8080 \
-p 8081:8081 \
-e MCP_GIT_REPO_URL=https://github.com/you/yourproject-knowledge.git \
-e MCP_GIT_TOKEN=ghp_your_token \
-v flaiwheel-data:/data \
flaiwheel:latest
Upgrading an existing container? Run the smoke test above first, then rename the old container instead of removing it (
docker rename flaiwheel flaiwheel-rollback) so you can restore it instantly if the new one fails its health check. Confirm every knowledge repo is pushed (git rev-list --count @{u}..HEAD→0) before swapping.
3. Connect your AI agent
Cursor — add to .cursor/mcp.json:
{
"mcpServers": {
"flaiwheel": {
"type": "sse",
"url": "http://localhost:8081/sse"
}
}
}
VS Code / GitHub Copilot (1.99+) — add to .vscode/mcp.json:
{
"servers": {
"flaiwheel": {
"type": "sse",
"url": "http://localhost:8081/sse"
}
}
}
Then: Command Palette → MCP: List Servers → start flaiwheel.
Claude Desktop (macOS app) — add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"flaiwheel": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:8081/sse"]
}
}
}
Requires Node.js. Restart Claude for Mac after editing.
Claude Code CLI — run once in your project directory:
claude mcp add --transport sse --scope project flaiwheel http://localhost:8081/sse
3b. Remote / LAN deployment (serving MCP beyond localhost)
By default the MCP endpoint is loopback-only: the transport guard accepts
only localhost, 127.0.0.1 and [::1], and any other client gets
HTTP 421 Invalid Host header. Binding is not the problem — the allowlist is,
and it is enforced at the application layer, so it is invisible from inside the
container.
To serve a shared or LAN instance, allowlist the hostname you connect with:
docker run -d --name flaiwheel -p 8080:8080 -p 8081:8081 \
-v flaiwheel-data:/data -v flaiwheel-docs:/docs \
-e MCP_SSE_ALLOWED_HOSTS=flaiwheel.example.com,flaiwheel.lan \
flaiwheel:latest
Both forms work: comma-separated (host1,host2) or JSON (["host1"]). Each
host matches with or without a port, so the same entry covers
flaiwheel.example.com and flaiwheel.example.com:8081. Loopback entries are
always kept, so an SSH tunnel or an existing Host-rewriting proxy keeps working
unchanged.
Then point your client at that hostname:
{ "mcpServers": { "flaiwheel": { "type": "sse",
"url": "http://flaiwheel.example.com:8081/sse" } } }
Default and recommended: use the HTTP endpoint on port
8081. This avoids client trust-store setup and is the configuration produced by the normal installer command. HTTP traffic is not encrypted, so use it only on a trusted LAN, localhost, an SSH tunnel, or an encrypted network such as WireGuard or Tailscale.
Optional automatic TLS — client trust required
Automatic TLS is available, but it is not the default recommendation yet.
Flaiwheel generates and persists a private CA and a server certificate. Each
client computer must trust that CA. Direct Cursor/Electron SSE connections use
the operating-system trust store; an env object in a direct remote-server
entry does not establish certificate trust.
New installation, with TLS off by default (an update preserves its current mode):
bash <(curl -sSL https://raw.githubusercontent.com/dl4rce/flaiwheel/main/scripts/install.sh)
Explicitly return an existing TLS-enabled installation to HTTP:
FLAIWHEEL_TLS_AUTO=0 bash <(curl -sSL https://raw.githubusercontent.com/dl4rce/flaiwheel/main/scripts/install.sh)
Enable automatic TLS only when the clients have been prepared to trust its CA:
FLAIWHEEL_TLS_AUTO=1 bash <(curl -sSL https://raw.githubusercontent.com/dl4rce/flaiwheel/main/scripts/install.sh)
The generated files are stored in /data/tls in the persistent data volume.
The installer exports the public CA certificate to
${HOME}/.flaiwheel/ca.pem; override that path with
FLAIWHEEL_CLIENT_CA_PATH. Flaiwheel reuses the generated CA across container
restarts and upgrades.
After enabling TLS, install the exported CA into the trust store used by the client operating system, restart the client, and use an HTTPS endpoint such as:
{ "mcpServers": { "flaiwheel": { "type": "sse",
"url": "https://192.168.178.230:8081/sse" } } }
macOS: verified direct Cursor/Electron setup
The following procedure was verified against the live v3.15.3 deployment on
2026-09-11. It uses the current user's login keychain and does not require
NODE_EXTRA_CA_CERTS for the direct SSE entry.
- Copy the CA from the Flaiwheel server to the Mac and verify its SHA-256 against the server copy:
mkdir -p "$HOME/.flaiwheel"
scp user@flaiwheel-host:/path/to/exported/ca.pem "$HOME/.flaiwheel/ca.pem"
chmod 644 "$HOME/.flaiwheel/ca.pem"
shasum -a 256 "$HOME/.flaiwheel/ca.pem"
- Add the verified CA to the login keychain as a trusted root:
security add-trusted-cert \
-r trustRoot \
-k "$HOME/Library/Keychains/login.keychain-db" \
"$HOME/.flaiwheel/ca.pem"
- Configure the direct SSE endpoint with
https://and the hostname or IP covered by the certificate. Do not add anenvblock:
{
"mcpServers": {
"flaiwheel": {
"type": "sse",
"url": "https://flaiwheel.example.com:8081/sse"
}
}
}
- Fully quit and restart Cursor after installing the CA or changing
.cursor/mcp.json. - Verify system trust without
-k,--cacert, or an environment override:
curl -i --max-time 5 https://flaiwheel.example.com:8081/sse
Expected: HTTP/1.1 200 OK, content-type: text/event-stream, and an
event: endpoint payload. curl exits after the timeout because an SSE stream
remains open; receiving the 200 and event proves the TLS and SSE connection.
Do not use NODE_TLS_REJECT_UNAUTHORIZED=0; it disables certificate
verification.
Native TLS — your own certificate, no proxy at all
Set a certificate and key and the endpoint is served over HTTPS directly:
docker run -d --name flaiwheel -p 8080:8080 -p 8081:8081 \
-v flaiwheel-data:/data -v flaiwheel-docs:/docs \
-v /etc/ssl/flaiwheel:/certs:ro \
-e MCP_SSE_ALLOWED_HOSTS=flaiwheel.example.com \
-e MCP_SSE_TLS_CERTFILE=/certs/fullchain.pem \
-e MCP_SSE_TLS_KEYFILE=/certs/privkey.pem \
flaiwheel:latest
{ "mcpServers": { "flaiwheel": { "type": "sse",
"url": "https://flaiwheel.example.com:8081/sse" } } }
Obtain the certificate from your CA (e.g. certbot certonly --standalone -d
flaiwheel.example.com), or generate an internal-CA cert for a LAN hostname.
Use fullchain.pem, not the bare leaf certificate, or clients will reject it
for an incomplete chain.
TLS fails closed. If only one of the two paths is set, or the file is
unreadable, Flaiwheel refuses to start rather than quietly falling back to
plain HTTP — an operator who asked for encryption must never silently get
cleartext. Check the logs for FATAL: MCP_SSE_TLS_... if the container exits
immediately. Note the Web UI on MCP_WEB_PORT is still plain HTTP; terminate
TLS for the UI at a proxy if you expose it beyond localhost.
FASTMCP_HOST will not help. It looks like the obvious knob and is
silently ignored: FastMCP.__init__ passes host and transport_security
into its Settings(...) as explicit init arguments, and pydantic-settings
gives init arguments precedence over environment variables. Use
MCP_SSE_HOST (bind address, default 0.0.0.0) and MCP_SSE_ALLOWED_HOSTS
(allowlist) instead.
4. Done. Start coding.
Knowledge Repo Structure
yourproject-knowledge/
├── README.md ← overview / index
├── architecture/ ← system design, decisions, diagrams
├── api/ ← endpoint docs, contracts, schemas
├── bugfix-log/ ← auto-generated bugfix summaries
│ └── 2026-02-25-fix-payment-retry.md
├── best-practices/ ← coding standards, patterns
├── setup/ ← deployment, environment setup
├── changelog/ ← release notes
└── tests/ ← test cases, scenarios, regression patterns
Supported Input Formats
Flaiwheel indexes 9 file formats. All non-markdown files are converted to markdown-like text in memory at index time — no generated files on disk, no repo clutter.
| Format | Extension(s) | How it works |
|---|---|---|
| Markdown | .md | Native (pass-through) |
| Plain text | .txt | Wrapped in # filename heading |
.pdf | Text extracted per page via pypdf | |
| HTML | .html, .htm | Headings/lists/code converted to markdown, scripts stripped |
| reStructuredText | .rst | Heading underlines converted to # levels, code blocks preserved |
| Word | .docx | Paragraphs + heading styles mapped to markdown |
| JSON | .json | Pretty-printed in fenced json code block |
| YAML | .yaml, .yml | Wrapped in fenced yaml code block |
| CSV | .csv | Converted to markdown table |
Quality checks (structure, completeness, bugfix format) apply only to .md files. Other formats are indexed as-is.
Configuration
All config via environment variables (MCP_ prefix), Web UI (http://localhost:8080), or .env file.
| Variable | Default | Description |
|---|---|---|
MCP_DOCS_PATH | /docs | Path to .md files inside container |
MCP_EMBEDDING_PROVIDER | local | local (free, private) or openai |
MCP_EMBEDDING_MODEL | all-MiniLM-L6-v2 | Embedding model name |
MCP_CHUNK_STRATEGY | heading | heading, fixed, or hybrid |
MCP_RERANKER_ENABLED | false | Enable cross-encoder reranker for higher precision |
MCP_RERANKER_MODEL | cross-encoder/ms-marco-MiniLM-L-6-v2 | Reranker model name |
MCP_RRF_K | 60 | RRF k parameter (lower = more weight on top ranks) |
MCP_RRF_VECTOR_WEIGHT | 1.0 | Vector search weight in RRF fusion |
MCP_RRF_BM25_WEIGHT | 1.0 | BM25 keyword search weight in RRF fusion |
MCP_MIN_RELEVANCE | 0 | Minimum relevance % to return (0 = no filter) |
MCP_GIT_REPO_URL | Knowledge repo URL (enables git sync) | |
MCP_GIT_BRANCH | main | Branch to sync |
MCP_GIT_TOKEN | GitHub token for private repos | |
MCP_GIT_SYNC_INTERVAL | 300 | Pull interval in seconds (0 = disabled) |
MCP_GIT_AUTO_PUSH | true | Auto-commit + push bugfix summaries |
MCP_GITLEAKS_MODE | block | Secret scan before auto-commit: block (refuse), warn (commit + report), off |
MCP_WEBHOOK_SECRET | GitHub webhook secret (enables /webhook/github HMAC verification) | |
MCP_TRANSPORT | sse | MCP transport: sse or stdio |
MCP_SSE_PORT | 8081 | MCP SSE endpoint port |
MCP_SSE_HOST | 0.0.0.0 | SSE bind address (an IP, not a hostname). Set 127.0.0.1 for loopback-only |
MCP_SSE_ALLOWED_HOSTS | Extra Host headers accepted by the transport guard, comma-separated or JSON. Required to serve remote/LAN clients directly | |
MCP_SSE_ALLOWED_ORIGINS | Extra Origin headers (browser-based MCP clients only) | |
MCP_SSE_DNS_REBINDING_PROTECTION | true | Keep on. false disables the Host and Origin guard for all clients |
MCP_SSE_TLS_CERTFILE | PEM certificate — with the key, serves MCP over HTTPS natively (no proxy) | |
MCP_SSE_TLS_KEYFILE | PEM private key. TLS is all-or-nothing: set both or neither | |
MCP_SSE_TLS_AUTO | false | Let Flaiwheel issue its own CA + certificate when none is configured. Opt-in: it flips the endpoint to HTTPS, so existing clients must trust the new CA |
MCP_SSE_TLS_DIR | /data/tls | Where generated certificates live. Must be persistent — regenerating the CA invalidates every client that trusts it |
MCP_WEB_PORT | 8080 | Web UI port |
Multi-Repo Support
A single Flaiwheel container can manage multiple knowledge repositories — one per project. Each project gets its own ChromaDB collection, git watcher, index lock, health tracker, and quality checker, while sharing one embedding model in RAM and one MCP/Web endpoint.
How it works:
- The first
install.shrun creates the Flaiwheel container with project A - Subsequent
install.shruns from other project directories detect the running container and register the new project via the API — no additional containers - All MCP tools accept an optional
projectparameter (e.g.,search_docs("query", project="my-app")) - Call
set_project("my-app")at the start of every conversation to bind all subsequent calls to that project (sticky session) - Without an explicit
projectparameter, the active project (set viaset_project) is used; if none is set, the first project is used - The Web UI has a project selector dropdown to switch between projects
- Use
list_projects()via MCP to see all registered projects (shows active marker)
Adding/removing projects:
- Via AI agent: call
setup_project(name="my-app", git_repo_url="...")— registers, clones, indexes, and auto-binds - Via install script: run
install.shfrom a new project directory (auto-registers) - Via Web UI: click "Add Project" in the project selector bar
- Via API:
POST /api/projectswith{name, git_repo_url, git_branch, git_token} - Remove:
DELETE /api/projects/{name}or the "Remove" button in the Web UI
Backward compatibility: existing single-project setups continue to work without changes. If no projects.json exists but MCP_GIT_REPO_URL is set, Flaiwheel auto-creates a single project from the env vars.
Embedding Model Hot-Swap
When you change the embedding model via the Web UI, Flaiwheel re-embeds all documents in the background using a shadow collection. Search remains fully available on the old model while the migration runs. Once complete, the new index atomically replaces the old one — zero downtime.
The Web UI shows a live progress bar with file count and percentage. You can cancel at any time.
Embedding Models (local, free)
| Model | RAM | Quality | Best for |
|---|---|---|---|
all-MiniLM-L6-v2 | 90MB | 78% | Large repos, low RAM |
nomic-ai/nomic-embed-text-v1.5 | 520MB | 87% | Best English quality |
BAAI/bge-m3 | 2.2GB | 86% | Multilingual (DE/EN) |
Select via Web UI or MCP_EMBEDDING_MODEL env var. Full list in the Web UI.
Cross-Encoder Reranker (optional)
The reranker is a second-stage model that rescores the top candidates from hybrid search. It reads the full (query, document) pair together, which produces much more accurate relevance scores than independent embeddings — especially for vocabulary-mismatch queries where the user and the document use different words for the same concept.
How it works:
- Hybrid search (vector + BM25) retrieves a wider candidate pool (
top_k × 5) - RRF merges and ranks the candidates
- The cross-encoder rescores the top candidates and returns only the best
top_k
Enable via Web UI (Search & Retrieval card) or environment variable:
docker run -d \
-e MCP_RERANKER_ENABLED=true \
-e MCP_RERANKER_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2 \
...
| Reranker Model | RAM | Speed | Quality |
|---|---|---|---|
cross-encoder/ms-marco-MiniLM-L-6-v2 | 90MB | Fast | Good — best speed/quality balance |
cross-encoder/ms-marco-MiniLM-L-12-v2 | 130MB | Medium | Better — higher precision |
BAAI/bge-reranker-base | 420MB | Slower | Best — state-of-the-art accuracy |
The reranker is off by default (zero overhead). When enabled, it adds ~50ms latency per search but typically improves precision by 10-25% on vocabulary-mismatch queries.
GitHub Webhook (instant reindex)
Instead of waiting for the 300s polling interval, configure a GitHub webhook for instant reindex on push:
- In your knowledge repo on GitHub: Settings → Webhooks → Add webhook
- Payload URL:
http://your-server:8080/webhook/github - Content type:
application/json - Secret: set the same value as
MCP_WEBHOOK_SECRET - Events: select "Just the push event"
The webhook endpoint verifies the HMAC signature if MCP_WEBHOOK_SECRET is set. Without a secret, any POST triggers a pull + reindex.
CI Guardrail Telemetry (ROI tracking)
Track non-vanity engineering impact directly in Flaiwheel:
- POST
/api/telemetry/ci-guardrail-report— CI reports guardrail findings/fixes per PR - GET
/api/impact-metrics?project=<name>&days=30— returns estimated time saved + regressions avoided
Example payload:
{
"project": "my-app",
"violations_found": 4,
"violations_blocking": 1,
"violations_fixed_before_merge": 2,
"cycle_time_baseline_minutes": 58,
"cycle_time_actual_minutes": 43,
"pr_number": 127,
"branch": "feature/payment-fix",
"commit_sha": "abc1234",
"source": "github-actions"
}
Flaiwheel persists telemetry on disk (<vectorstore>/telemetry) so metrics survive container restarts and updates.
Diff-aware Reindexing
Reindexing is incremental by default — only files whose content changed since the last run are re-embedded. On a 500-file repo, this means a typical reindex after a single-file push takes <1s instead of re-embedding everything.
Use reindex(force=True) via MCP or the Web UI "Reindex" button to force a full rebuild (e.g. after changing the embedding model).
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Docker Container (single process, N projects) │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Web-UI (FastAPI) Port 8080 │ │
│ │ Project CRUD, config, monitoring, search, health │ │
│ └─────────────────────┬─────────────────────────────────┘ │
│ │ shared state (ProjectRegistry) │
│ ┌─────────────────────┴─────────────────────────────────┐ │
│ │ MCP Server (FastMCP) Port 8081 │ │
│ │ 30 tools (search, write, classify, manage, projects,│ │
│ │ relations, timeline) │ │
│ └─────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────┴─────────────────────────────────┐ │
│ │ Shared Embedding Model (1× in RAM) │ │
│ └─────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────┴────────────────────────────────┐ │
│ │ Per-Project Contexts (isolated) │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Project A │ │ Project B │ │ Project C │ │ │
│ │ │ collection │ │ collection │ │ collection │ │ │
│ │ │ watcher │ │ watcher │ │ watcher │ │ │
│ │ │ lock │ │ lock │ │ lock │ │ │
│ │ │ health │ │ health │ │ health │ │ │
│ │ │ quality │ │ quality │ │ quality │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ /docs/{project}/ ← per-project knowledge repos │
│ /data/ ← shared vectorstore + config + projects │
└─────────────────────────────────────────────────────────────┘
Search Pipeline
query
│
├──► Vector Search (ChromaDB/HNSW, cosine similarity)
│ fetch top_k (or top_k×5 if reranker enabled)
│
├──► BM25 Keyword Search (bm25s, English stopwords)
│ fetch top_k (or top_k×5 if reranker enabled)
│
├──► RRF Fusion (configurable k, vector/BM25 weights)
│ merge + rank candidates
│
├──► [optional] Cross-Encoder Reranker
│ rescore (query, doc) pairs for higher precision
│
├──► Min Relevance Filter (configurable threshold)
│
└──► Return top_k results with relevance scores
Web UI
Access at **http://localhost:8080** (HTTP Basic Auth — credentials shown on first start).
Features:
- System health panel: last index, last git pull, git commit, version, search metrics, quality score, skipped files count
- Index status and statistics (including reranker status)
- Embedding model selection (visual picker)
- Search & Retrieval tuning: cross-encoder reranker toggle + model picker, RRF weights, minimum relevance threshold
- Chunking strategy configuration
- Git sync settings (URL, branch, auto-push toggle)
- Test search interface
- Knowledge quality checker (also runs automatically after every reindex)
- Search metrics (hits/total, miss rate, per-tool breakdown)
- Skipped files indicator (files excluded from indexing due to critical quality issues)
- "This is the Way" — Knowledge Bootstrap: agent-driven project classification + in-repo cleanup (Web UI shows guidance + advanced scan)
- Multi-project switcher (manage multiple repos from one instance)
- Client configuration snippets (Cursor, Claude Desktop, Docker)
- Password management
Development
# Clone
git clone https://github.com/dl4rce/flaiwheel.git
cd flaiwheel
# Install
pip install -e ".[dev]"
# Run tests (259 tests covering readers, quality checker, indexer, reranker, health tracker, MCP tools, model migration, multi-project, bootstrap, classification, file-context, cold-start analyzer)
pytest
# Run locally (needs /docs and /data directories)
mkdir -p /tmp/flaiwheel-docs /tmp/flaiwheel-data
MCP_DOCS_PATH=/tmp/flaiwheel-docs MCP_VECTORSTORE_PATH=/tmp/flaiwheel-data python -m flaiwheel
License
Business Source License 1.1 (BSL 1.1)
Flaiwheel is source-available under the Business Source License 1.1.
You may use Flaiwheel for free if:
- Your use is non-commercial (personal, educational, no revenue), or
- Your organization has no more than 10 individuals using it
Commercial use beyond these limits (e.g., teams of 11+ or commercial deployment) requires a paid license.
- Effective 2030-02-25, this version converts to Apache License 2.0 (fully open source)
- Commercial licenses: info@4rce.com | https://4rce.com
See LICENSE for full terms.
الأسئلة الشائعة
ما هو Flaiwheel؟
Self-hosted memory and governance for coding agents: structured knowledge capture, hybrid search with reranking, codebase analysis and git-native storage.
كيف أثبّت Flaiwheel؟
اتبع خطوات التثبيت في توثيقه المعروض في هذه الصفحة وفي مستودعه.
هل Flaiwheel مفتوح المصدر؟
شيفرته علنية على GitHub، لكن المستودع لا يعلن ترخيصًا قياسيًا.
من يصون Flaiwheel؟
ينشره dl4rce. يدرجه AI.tn لكنه لا يصونه ولا يوصي به.
من القوائم المجتمعية awesome-mcp-servers ومستودع المشروع على GitHub. الإدراج ليس توصية: راجع شيفرة الخادم وصلاحياته قبل منحه الوصول إلى بياناتك.