neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기An AI agent that doesn't burn your money.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
An AI agent that doesn't burn your money.
FreeClaw is a cost-efficient, tool-using AI agent that runs on your own machine. It comes with a password-protected, dark-themed web UI you can chat with from any browser on your network. It remembers things about you, searches the web, runs bash commands, connects to external tools through MCP servers, reads images, and reads/writes files — and does it all while routing as much traffic as possible to small, cheap models.
Runs natively, supervised by systemd. Needs git, python3, and sudo.README 전문 보기 ↗An AI agent that doesn't burn your money.
FreeClaw is a cost-efficient, tool-using AI agent that runs on your own machine. It comes with a password-protected, dark-themed web UI you can chat with from any browser on your network. It remembers things about you, searches the web, runs bash commands, connects to external tools through MCP servers, reads images, and reads/writes files — and does it all while routing as much traffic as possible to small, cheap models.
Runs natively, supervised by systemd. Needs git, python3, and sudo.
curl -fsSL https://freeclaw.eedeb.dev/install.sh | bash
The script will:
FreeClaw.service) so it starts automatically, and install the freeclaw terminal clientRuns natively — no Docker Desktop, no Homebrew, no Python of your own. Needs
git (xcode-select --install), which FreeClaw's bash tool wants anyway.
curl -fsSL https://freeclaw.eedeb.dev/install-mac.sh | bash
It will:
~/.freeclaw and download a private, checksum-pinned Python 3.12 for it — no administrator rights, and it doesn't touch any Python you already have~/Applications/FreeClaw.app, install the freeclaw command, and offer to start FreeClaw at loginClick the menu bar icon to open FreeClaw. The same menu has Restart, the logs folder, Start at Login, and Copy address for other devices — the LAN address to open on your phone.
Re-run the same line to update — your chats, files and settings are left alone, and Python is reused, so it takes seconds. To remove it, run the uninstaller that came with the install:
~/.freeclaw/uninstall-mac.sh
Your data stays unless you add --purge.
3.12 and not Apple's own python3, which is 3.9: the shipped browser MCP
server needs 3.10+, so an install built on the system Python would come up
quietly missing it. See mac/README.md for the rest — the
supervisor's exit-code contract, the LaunchAgent, and why PATH is resolved
from your login shell.
Coming from the Docker install? macOS used to run FreeClaw in a container, because there was no supervisor to be had otherwise. Run the one-liner, then remove the old one yourself with
docker rm -f freeclaw— nothing does it for you, because that container's bind mounts are the only copy of your old chats. Copy them (and your.env) over from the old checkout first; mac/README.md has the steps.
Runs natively — no WSL and no Docker Desktop. In PowerShell:
irm https://freeclaw.eedeb.dev/install.ps1 | iex
It clones the repo into %LOCALAPPDATA%\FreeClaw and puts a private Python
beside it, so it needs only Git
(winget install --id Git.Git -e) — which FreeClaw's bash tool wants anyway.
The Python it fetches matches your machine, x64 or ARM64, so a Surface or
Snapdragon laptop runs natively rather than under emulation.
It generates your web UI password and prints it, adds the freeclaw command
and a Start Menu shortcut, and starts FreeClaw when it's done.
No security warning, and that's the point. Mark of the Web is applied by
the browser, so a build fetched this way never carries it and never trips
SmartScreen. Downloading the .exe in a browser does: because the build is
unsigned you get "Windows protected your PC" with Run anyway hidden
behind More info, which reads to most people as a broken download.
Re-run the same line to update — your chats, files and settings are left alone. Updating takes seconds — the clone is refreshed and Python reused. To remove it, run the uninstaller that came with the install:
& "$env:LOCALAPPDATA\FreeClaw\uninstall.ps1"
Your data stays unless you add -Purge.
It will:
%LOCALAPPDATA%\FreeClaw and install a private Python for it — no administrator rights, no UAC prompt^ chevron at the right of the taskbar — where a small supervisor keeps the server running and restarts it on demand, the job systemd does on Linuxfreeclaw command on your PATH and add a Start Menu shortcutClick the tray icon to open FreeClaw. Right-click it for Restart, the logs folder, and Copy address for other devices — the LAN address to open on your phone. That address needs a firewall rule, which the install deliberately doesn't add because it would require administrator rights; the Windows notes have the one-line command.
To chat from a terminal instead, run freeclaw — the same CLI the Linux and
macOS installs put on PATH.
Uninstalling leaves your chats, context.md, .env and logs alone, and
re-installing merges into your existing .env rather than overwriting it.
The agent's bash tool runs commands through Git Bash, so install Git for Windows if you want it — without it FreeClaw falls back to
cmd.exe, where thels/grep/catthe model reaches for don't exist. Everything else works either way. See windows/README.md for the details.
Note: each installer checks out only the files for its own platform — a Linux install has no
mac/directory or*-mac.shscripts, a macOS install has no systemd scripts, and neither carries the Windows ones. Run the wrong one and it will tell you and point at the other.
Once installed, open the URL the installer printed — something like http://192.168.x.x:6767. You'll be asked for the password you set (or, on Windows, the one it generated for you), then dropped into the FreeClaw chat UI:
You can type these directly into the chat box:
| Command | What it does |
|---|---|
/reset | Clears the conversation history |
/startapi | Enables the OpenAI-compatible API at /v1/chat/completions |
/stopapi | Disables the API |
Classy classifier reads your message and tags its intent (greeting, search, coding, logic, banter, etc.) before any API call is madebrowser_do: the browser lists the page's controls as text, Jev picks each next move in ~0.3s, and the agent gets one screenshot at the end instead of one per click. It never pays, orders, sends, deletes or signs out, and hands back when unsure, stuck or facing a CAPTCHAsearch_history brings back exact wording from anywhere in the conversation — or from past conversations, which are archived on reset instead of deletedBrowser (chat UI, behind /login)
│ POST /chat
▼
Flask server (Flask/main.py, port 6767)
│
▼
Jev (optional) or Classy.classify()
│ with a Jev key: Jev picks the exact tools, earlier messages, memory
│ sections and temperature this message needs (src/jev.py)
│ without one: the local classifier (models/data.pth) picks temperature,
│ tools + how much history to send
▼
Configured provider API call ← trimmed message history + tools
│ (falls back to the next provider in Settings → Providers on failure)
│
├── Tool call? ───► bash? ──► approval gate (src/approvals.py)
│ │ │ saved rule → run · else ask the user and wait
│ │ │ refused/timed out → never runs
│ └──► Execute tool (search, file ops, MCP servers, vision…)
│ │
│ └──► Recursive agent turn with the tool result
│
└── Text response? ──► Streamed back to the browser as server-sent events
The search pipeline (src/scraper.py):
ddgs) supplies instant answers, news results (for news-flavored queries), and web snippetsFreeClaw/
├── Flask/
│ ├── main.py # Flask server — login, chat SSE endpoint, settings/provider/MCP APIs, /v1 API
│ ├── static/ # Created at first run; each user gets static/<user>/files/ holding context.md, uploads, and agent-created files,
│ │ # static/<user>/conversation.json and history/ (conversations archived by /reset) beside it — all browsable in the Files app —
│ │ # plus static/<user>/.bash_approvals.json — their always-allow rules, kept out of files/ so the agent can't edit it
│ └── templates/
│ ├── index.html # Home page — pick an agent, toggle the API
│ ├── chat.html # Chat UI (dark theme, markdown rendering, token counter, file upload)
│ ├── developer.html # Developer app — file list, editor and Run for static/<user>/files/projects/
│ ├── settings.html # Settings — providers, MCP servers, .env, restart
│ └── login.html # Password login screen
├── src/
│ ├── agent.py # Core agent loop — intent classification, provider fallback, tool dispatch
│ ├── approvals.py # Bash approval gate — per-user allow rules, blocking prompts (no LLM involvement)
│ ├── cli.py # Terminal chat client (the `freeclaw` command)
│ ├── users.py # User/conversation storage, shared by the web app and CLI
│ ├── scraper.py # DuckDuckGo search + page scraping + text cleaning
│ ├── mcp_client.py # MCP client — external MCP servers over HTTP or local stdio processes
│ ├── dev_server.py # The Developer app's coding tools (ls, read, write, edit, overview, outline, find, search, run, git_*, preview), a builtin stdio MCP server
│ ├── dev_map.py # The project map behind overview/outline/find: symbols per file (Python parsed, other languages by pattern), cached
│ ├── dev_git.py # Git for the Developer app: clone/status/diff/commit/push/pull/branch for GitHub repos
│ └── logging_setup.py # Central logger — full tracebacks go to logs/freeclaw.log
├── tests/ # Not installed — `python -m unittest discover -s tests`
├── models/
│ └── data.pth # Classy intent classifier weights
├── logs/
│ └── freeclaw.log # Created at first run; full error detail, see Debugging below
├── assets/ # Not installed — the icon source and its generator
│ ├── eagle.png # The FreeClaw eagle, as the website serves it
│ └── make_icons.py # Builds the .ico, the .icns and the menu bar .png
├── mac/ # macOS install only — see mac/README.md
│ ├── tray.py # Menu bar app; supervises the server, playing systemd's role
│ ├── freeclaw.png # Menu bar icon (drawn at 2x for Retina)
│ ├── freeclaw.icns # App bundle icon (Finder, Spotlight, Login Items)
│ └── requirements-mac.txt # pystray + pyobjc, the menu bar's own dependencies
├── windows/ # Windows install only — see windows/README.md
│ ├── tray.py # Notification-area app; supervises the server, playing systemd's role
│ ├── write_env.py # Seeds .env at install time; merges, never overwrites
│ └── freeclaw.ico # Tray and shortcut icon (nine sizes)
├── install.ps1 # One-line installer (Windows, clones this repo)
├── uninstall.ps1 # Uninstaller (Windows)
├── install.sh # One-line installer (Linux)
├── update.sh # Pull and apply updates (Linux)
├── uninstall.sh # Remove service + files (Linux)
├── install-mac.sh # One-line installer (macOS, clones this repo)
├── update-mac.sh # Pull and apply updates (macOS)
├── uninstall-mac.sh # Remove app + files (macOS)
├── requirements.txt # Python dependencies (web/agent libs)
└── .env # Password, providers, MCP servers, and other config (created during install)
Only one platform's files are checked out at install time, so you'll see one of those three sets, not all of them. The macOS and Windows installs additionally carry a python/ directory — a private interpreter fetched at install time, standing in for the virtualenv the Linux install builds.
FreeClaw can connect to external Model Context Protocol (MCP) servers to gain new tools — think GitHub, web search, databases, or your own custom server. Add one from Settings → MCP Servers, in either of two flavours.
The App Store icon on the desktop is the easier way in. It lists well-known servers (Composio, GitHub, Linear, Stripe, Supabase, Notion, Context7, Firecrawl and more) with their endpoint already filled in, where to get a key, and a link to each one's setup guide; the catalog lives in src/mcp_catalog.py. Its Add custom server tab takes any HTTP(S) or stdio server by hand. Only servers that can connect with a key are listed: FreeClaw can't complete an OAuth sign-in, so OAuth-only servers are left out.
Every installed server shows up on the desktop as an app, with its vendor's icon (or its first letter). Double-click one to switch it on or off for you; a switched-off app is greyed out, and an app glows while the agent is calling one of its tools. Deleting is done from the App Store's Installed tab.
The App Store can store two things Settings can't: a custom header for the key (Composio wants x-consumer-api-key), and environment variables handed to one stdio server only. Both go in .env under MCP_EXTRAS.
Enter the server's URL and (optionally) an auth token. FreeClaw connects over the Streamable HTTP transport, fetches the server's tools, and makes them available immediately — no restart required.
Enter a command instead. FreeClaw runs it as a child process and speaks JSON-RPC over its stdin/stdout. This is the transport most published MCP servers actually use, so it's what makes the wider ecosystem reachable:
npx -y @modelcontextprotocol/server-filesystem /srv/shared
Things worth knowing:
npx needs Node on the machine running FreeClaw, uvx needs uv, and so on. FreeClaw says exactly this rather than failing vaguely when the binary is missing. On macOS the menu bar app resolves PATH from your login shell before starting the server, so a Homebrew node is found even when FreeClaw was started at login by launchd — which otherwise hands a process a PATH with almost nothing on it..env. The child inherits FreeClaw's environment, so a server wanting GITHUB_TOKEN gets it by adding that key under Settings → Environment. There's no separate credential field for stdio servers.… "/My Files/notes"). Single quotes would break the .env encoding and are rejected.Adding a server is install-wide; switching it on is per user. A server you add is there for everyone to see, with its URL and token entered once — but each FreeClaw user decides for themselves whether it's on, so one person can have Composio while another's agent never sees those tools. The Enabled for picker at the top of the MCP list chooses whose switches you're setting, and each user's choices are saved in Flask/static/<user>/.mcp_enabled.json. A user who hasn't chosen about a server inherits the install default, so a server you add is on for everybody until they say otherwise.
Either kind can be switched off without losing its saved config. Connections live in your .env as the parallel MCP_NAMES, MCP_URLS, MCP_TOKENS, MCP_ENABLED, MCP_TRANSPORTS, and MCP_COMMANDS lists, so you can review or edit them by hand. An entry with no transport recorded is treated as HTTP, so configs written by older versions keep working untouched.
The agent can run shell commands — but not on its own initiative. Every run_bash_command call goes through a gate outside the conversation entirely:
"Always allow" saves a rule so the same thing isn't asked twice, per FreeClaw user — approving something as Elliot grants nothing to anyone else. An exact rule matches the command byte for byte; a program rule (always allow all "ls" commands) matches any simple command with that leading token.
The program option is only offered for a simple command: anything containing ;, &&, |, `, $(…), > or < can neither create such a rule nor be matched by one, since ls; rm -rf ~ would otherwise satisfy a rule that says ls.
Review and revoke under Settings → Bash Approvals. There's no field to type a rule in by hand, on purpose: a rule can only come from a command you were shown.
A ping firing at 3am has nobody to ask. Those turns still honour saved rules — that's what always-allow is for — but anything needing a prompt is refused rather than left hanging.
The gate stops commands running unasked. It is not a sandbox: an approved command has whatever access the FreeClaw process does, including rewriting the rule file, so approving one arbitrary command is in practice approving all of them. Running FreeClaw as a user that can't touch anything you care about is still the real containment story. Rules live at Flask/static/<user>/.bash_approvals.json, outside the files/ folder the agent's own file tools can reach.
A small code editor and a set of coding tools for the agent, both working in the same folder: each user's Flask/static/<user>/files/projects/.
For you: open Developer in the sidebar. Files are on the left (new file and new folder buttons; drag a file or folder onto another folder to move it, or onto the empty space below to move it to the top; Rename and Delete on hover), the editor in the middle (Ctrl/Cmd+S saves), and ▶ Run runs the open file — .py with the python3 on your PATH, .sh with bash — from the projects folder, streaming its output below with a Stop button. Running your own file asks nothing. When the agent changes the file you have open, the editor reloads it (or asks, if you have unsaved edits).
For the agent: a builtin MCP server, developer (src/dev_server.py), on by default and switchable per user like any other server. Its tools reach the model as mcp_developer_<tool>:
| Tool | What it returns |
|---|---|
ls | A tree to a small depth, capped, skipping .git, node_modules, virtualenvs, caches and build folders |
read | A numbered slice of a file (120 lines by default, 500 at most) and the file's total line count |
write | Creates or overwrites a file, making folders; answers in one line |
edit | Replaces an exact string; fails if it isn't found, or matches more than once without all: true |
overview | A one-screen summary of a project or folder: languages, the main folders, what the README and manifests (package.json, pyproject.toml…) say, likely entry points. About 1 KB however big the project |
outline | The classes, functions and headings of a file (methods under their class) or of a folder (top level), with line numbers and signatures and no bodies |
find | Where a name is defined: path:line signature; partial: true for names containing it |
search | Regex across the workspace (optional glob): path:line: text, 50 hits at most, or with files_only: true just the matching files and their hit counts |
run | Runs a bash command, or python <file> <args>, from the workspace or a folder in it (path, shown as cd <folder> && … so the approval and saved rules see it); exit code plus the head and tail of the output (3 KB each), saying how much was cut. 45 s by default, 580 s at most |
preview | Serves a folder on 127.0.0.1 and returns the URL, to open with the browser tools and screenshot |
They're built to keep coding cheap: nothing returns a whole file or a whole log, and the agent is told to search first, read slices and edit by exact replacement. Every path must stay inside the workspace — absolute paths, .. and symlinks leading out are refused.
run goes through Bash Approvals. The card shows exactly what will run (python app.py --port 8000), your saved always-allow rules apply to it, and background turns (pings, the API) are refused unless a rule allows it. Like bash it is not a sandbox: an approved command has the FreeClaw process's access.
GitHub. Connect GitHub in the App Store (a personal access token that can read and write your repos), and the Developer app can work on your repositories. The agent gets git_clone, git_status, git_diff, git_commit, git_push, git_pull and git_branch (src/dev_git.py), and the app gets a Git tab beside its file list with the same actions: pick one of your GitHub repos (or paste a URL) and Clone; see the repo's origin, its branch and how far ahead or behind it is; Check origin fetches and lists the commits on GitHub that aren't here yet, and Pull brings them in; the changed files are listed (click one to open it), with Commit and Push under them. The agent's git_fetch does the same check. Only https://github.com/ repos, and push and pull only go to a repo's GitHub origin. The agent's git_push asks you first, like run. The token reaches git as a header for github.com only, never a command line, a file or code you run, and a repo's own config can't make git run commands (hooks, fsmonitor, pagers and the like are forced off). Commits use your GitHub name and its private noreply address. Opening a pull request is the GitHub connector's job.
Common other names for arguments are accepted (filename or file_path for path, old_string/new_string for old/new, offset/limit for start/lines, cwd for run's path, path for a git tool's repo), so a model that misremembers the schema doesn't lose a step to it.
Switching it off. FC_DISABLE_DEVELOPER=1 (or FC_DISABLE_BASH=1) removes it entirely — the tools aren't offered, /developer and /api/dev/* answer 404, and the sidebar entry is gone. Self-hosted installs leave it unset.
Every turn resends the system prompt, so it's the single biggest repeated cost in a conversation. Providers will serve a repeated prefix from cache at a large discount — but only if it's byte-identical each time.
FreeClaw's used not to be. The system message opened with a live timestamp, which meant every turn differed from byte 0 and nothing could ever be cached. The layout is now stable-part-first:
<instructions> ← fixed for the whole conversation, cacheable
context.md: as much as fits + header names ← snapshotted at reset, re-read after a correction
--- live context (refreshed every turn) ---
Current date/time, upcoming pings, ← rewritten every turn
this conversation's saves, digest of
older messages
That alone is enough for providers that cache automatically (OpenAI, DeepSeek, Groq, Cerebras, xAI) — they need no request-side opt-in, just a stable prefix.
Anthropic, Gemini and Qwen models instead need an explicit breakpoint, so FreeClaw marks the boundary above with cache_control: ephemeral when the model id looks like one of those. There's nothing to configure: the models that need it are the ones whose names say so, and an endpoint that objects is handled by the same retry that covers token counts (see below). A provider behind an opaque model id just misses out.
Whether it's working is visible in the token counts below — cache reads are reported alongside them, for any provider that reports usage at all.
FreeClaw asks every provider for the exact token usage of each request and shows you what comes back. Where a provider reports nothing, it falls back to a length-based estimate — and says which you're looking at:
| Display | Meaning |
|---|---|
2,041 tokens (accent colour) | Exact, from the provider |
~362 tokens (grey, leading ~) | Estimated from message length |
Hover the counter for the breakdown: tokens sent, tokens received, how many came from cache, and how many requests the turn took. The CLI prints the same on its per-turn summary line:
2 requests · 1.4s · groq · 3,224 in / 118 out (1,024 cached)
The headline number is the last request's prompt size — what the model actually read, which is deliberately not the size of your whole conversation: history windowing sends only a slice. Counts are written to logs/freeclaw.log and ride along with the saved conversation, so they survive a reload.
Expect the exact number to disagree with the estimate: the estimate walks the saved conversation, so it counts the whole history rather than the windowed slice, and it can't see the tool definitions, which aren't part of the conversation but are resent with every request.
A streamed response carries no usage block unless the request asks for it, via stream_options: {"include_usage": true} — and not every OpenAI-compatible endpoint accepts that field. Same story for the cache_control breakpoint above. Since this is a fallback chain where one rejected request would cost you a provider, both are sent optimistically and share one safety net: if a provider 400s with them attached, FreeClaw retries the identical call without them and stops sending them to that provider. An endpoint that supports neither costs one wasted request, ever — nothing to configure, and no working call lost to a field you didn't know about. The verdict resets when you edit the provider list, so reusing a name for a different endpoint doesn't inherit the old one's quirk.
FreeClaw speaks the OpenAI chat format on the same port as the web UI, so any OpenAI-compatible client can talk to your agent. Toggle it with the API chip on the homepage, or with /startapi / /stopapi in chat. Authenticate with your FreeClaw password as the Bearer token.
Two things work differently from a plain completions endpoint, both on purpose:
model picks the FreeClaw user, not a model. Which LLM answers is FreeClaw's business (Settings → Providers). What you're choosing is whose memory, conversation and approval rules the turn runs against. GET /v1/models returns your users, so an off-the-shelf client's model dropdown becomes a user picker for free.
History lives on the server. Send one message; FreeClaw supplies everything before it from that user's stored conversation and appends the turn to it. Clients that resend the whole transcript every call still work — only the last user message is acted on, the rest is ignored rather than duplicated.
curl http://localhost:6767/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_FC_PASSWORD" \
-d '{"model": "Elliot", "messages": [{"role": "user", "content": "what did I say my cat was called?"}]}'
from openai import OpenAI
client = OpenAI(base_url="http://localhost:6767/v1", api_key="YOUR_FC_PASSWORD")
client.chat.completions.create(model="Elliot", messages=[{"role": "user", "content": "Hello!"}])
It's a full agent turn, not a raw model call: tools run, the web search fires, memory is read and written, and the reply comes back after all of it. It's the same thread the chat page shows — send a message here and it's there when you open the browser, and vice versa.
Streaming ("stream": true) is supported and emits assistant text only; tool calls run transparently. The usage block carries the providers' own token counts for the whole turn, including any tool round-trips (see Token Counts).
temperature and max_tokens from the request are ignored — the intent classifier sets those per turn, which is the point of the thing.
Bash on an API turn: there's nobody to answer an approval prompt, so a command runs only if it matches a saved always-allow rule for that user. Anything else is refused and the model is told, rather than the request hanging. See Bash Approvals.
Changed in this version. The endpoint used to be stateless, forwarding your
messagesarray straight to the provider chain withmodelnaming an LLM. Callers passing a model id (openai/gpt-oss-120b) now get a404listing the valid users.
Settings live in a .env file in the project root, created for you during install:
| Variable | Required | Purpose |
|---|---|---|
FC_PASSWORD | Yes | Password for the web UI login screen |
SECRET_KEY | Yes | Flask session secret (auto-generated at install time) |
PROVIDER_NAMES / PROVIDER_URLS / PROVIDER_KEYS / PROVIDER_MODELS / PROVIDER_ENABLED | Yes | Your LLM provider(s) — managed entirely from Settings → Providers; the agent has nothing to call until at least one exists here |
JEV_API_KEY | No | Turns on Jev routing — set it in Settings → Jev. Blank means the local classifier routes every message |
VISION_PROVIDER | No | Name of the configured provider (from Settings → Providers) used to describe uploaded images — pick it in Settings → Vision Model |
MCP_NAMES / MCP_URLS / MCP_TOKENS / MCP_ENABLED / MCP_TRANSPORTS / MCP_COMMANDS | No | Connected MCP servers — managed from Settings → MCP Servers. MCP_TRANSPORTS is http or stdio per entry (missing = http); MCP_COMMANDS holds the command line for stdio ones. MCP_ENABLED is the default a user inherits until they switch a server on or off for themselves |
CUSTOM_DOMAIN | No | Overrides the auto-detected local IP for file/page links the agent returns. Set it from Settings → Custom Domain if you reach FreeClaw through a name rather than an address |
FC_DISABLE_DEVELOPER | No | 1 switches the Developer app off entirely: no sidebar entry, no routes, no coding tools for the agent. Also off whenever FC_DISABLE_BASH is set. Read from the process environment, so set it where FreeClaw is started |
FC_DEBUG | No | 0 turns off Werkzeug's reloader and interactive debugger. Defaults to on when you run yourself; every supervisor sets it to , because the reloader forks a second process and would leave the supervisor watching the wrong one |
Off by default. The installer asks once (and never asks on Windows, where it simply stays off), the default answer is no, and if you say no nothing is ever sent.
If you say yes, FreeClaw sends one HTTP request, the first time it starts, containing exactly four fields:
{
"install_id": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
"version": "0.1.0",
"os": "darwin",
"install_method": "native"
}
That's the entire payload. Not sent, ever: your messages, prompts, provider names, URLs, API keys, file contents, file paths, hostname, or username. The receiving end (telemetry/) stores those four fields and a timestamp — its schema has no column for anything else — and does not log IP addresses.
It exists to answer one question: how many people actually installed this. That's it.
install_id is written to your .env as FC_INSTALL_ID and never sent again.FC_TELEMETRY=0 in .env.src/telemetry.py, and the log line it writes shows you the exact payload it sent.If the endpoint is unreachable the failure is swallowed silently and start-up is unaffected — the ping runs on a background thread with a 5-second timeout, and no install_id is saved, so it simply tries again next time.
Settings → Update FreeClaw does it from the browser on every platform. On
Linux and macOS it runs the updater that ships inside the install (update.sh
/ update-mac.sh), streams the output onto the page, and restarts the server
afterwards; on Windows it hands off to the notification-area app, which fetches
install.ps1 again, because there the files being replaced are open in the
process doing the replacing. A failed update changes nothing — the server is
only restarted after the script finishes cleanly, so you keep the version that
was working.
The button is absent only on an install that is not a git checkout and has no updater to run — FreeClaw unpacked from a tarball, say. Update that the way you installed it.
From the command line instead, in your FreeClaw install directory — on Linux:
./update.sh
On macOS:
~/.freeclaw/update-mac.sh
Both pull the latest src/, models/, Flask/templates/ and Flask/main.py
from origin/main, sync dependencies, and leave your Flask/static/ data
(context, uploads, generated pages) and .env untouched. Re-running the
installer does the same thing and is equally safe.
One macOS-only wrinkle: a change to the menu bar app itself (mac/tray.py)
only takes effect the next time it starts, since it is the one process an
update can't replace underneath itself. The updater says so when that
happens — quit FreeClaw from the menu bar and open it again.
./update.sh --no-service is the same update without touching
FreeClaw.service — what the Settings button uses, since it is running inside
the very service the script would otherwise stop. The caller restarts FreeClaw
afterwards.
Every unexpected failure — a provider erroring out, a tool crashing, an MCP server going unreachable, an unhandled exception in a route — gets logged with its full traceback to logs/freeclaw.log at the repo root, rotated at 5MB (5 backups kept). This is separate from what you see in the chat UI or API response, which stays short on purpose; the log file is where the real cause lives.
tail -f logs/freeclaw.log
Warnings and errors are also mirrored to the console. On Linux that means journalctl -u FreeClaw.service -f. On macOS and Windows the supervisor captures them instead: logs/server-console.log beside logs/freeclaw.log, plus logs/tray.log for the supervisor's own account of what it started, restarted, or gave up on. The menu bar's Open logs folder item goes straight there.
logs/ is never served by the app (unlike Flask/static/), so it's safe to keep tracebacks there even though they can include file paths and request shapes.
FreeClaw is built around one principle: use the cheapest model that can do the job.
context.md under a header, sent from the cached part of the prompt, and reduced to header names only once memory outgrows its budgetsearch_history) rather than a summarising model callThis keeps API costs near zero for everyday use.
MIT — do whatever you want with it.
context.md, filed under ## headers alongside your other files. The About and Preferences sections always go in full, and every other section is inlined too while it fits a ~6k-character budget; beyond that, sections are listed by name and entry count. search_context opens a section by name or finds entries by keyword, and add_context saves. A correction made with edit_file reaches the prompt on the very next turnadd_ping, writing it to ping.md, and remove one with cancel_ping; the upcoming ones are listed in its prompt every turn, so it always knows what's scheduled. A background thread delivers each as a turn with every tool available when its time comes (a late delivery says so), so the exchange is waiting the next time you open the chat. Times in the past are refused rather than fired immediately, and a delivery that fails is noted in the chat and retried once. Pass repeat as hourly, daily, or weekly and it reschedules itself on every fire. Nothing runs while nothing is due — there's no polling loop spending tokens on your behalf/v1/chat/completions on the same port for use from other apps and scripts. Send one message and the server supplies the history; the model field picks which FreeClaw user you're talking to, so any OpenAI client drives the same conversation the web UI showspython -m Flask.main0FC_TELEMETRY | No | 1 sends the one-off anonymous install ping described under Telemetry. Off unless you opted in during install |
FC_INSTALL_ID | No | Random UUID written here after that ping is sent, so it's only ever sent once. Delete the line to reset |