{"slug": "faaah-filesystem-as-an-ai-handler-agent-subscription-as-openai-api-via-files", "title": "Faaah (Filesystem as an AI Handler) – Agent Subscription as OpenAI API via Files", "summary": "Developer Sebastian Carlos released FAAAH, a 308-line, dependency-free Python tool that turns an existing AI coding-agent subscription (such as Claude Code or opencode) into an OpenAI-compatible local server by writing requests to `.txt` files in a queue directory and having the agent write responses back. FAAAH runs on Python's `http.server`, listens on 127.0.0.1:8000 by default, installs via `uv tool install`, and works with any tool expecting the OpenAI API format, including GraphRAG, LangChain, LlamaIndex, LiteLLM and the `openai` SDK. Carlos states it is his understanding that local, non-commercial use does not break any agent provider's terms of service, while warning users against processing massive datasets because some providers may deploy telemetry to detect infractions.", "body_md": "*The simplest OpenAI-compatible LLM proxy you will ever need.™️*\n\nFAAAH allows you to reuse your AI Agent subscription as a generic OpenAI-compatible local server.\n\nFAAAH is dependency-free, implemented as a plain-text file protocol\n*(UNIX-philosophy certified)*:\n\n1. Instead of sending your prompts to cloud LLM APIs, send them to FAAAH,\nwhich reads OpenAI-compatible requests and dumps them into a folder as\n`.txt` files.\n2. Then, tell your existing AI coding agent (Claude Code, opencode, etc) to\nread the files and write responses to other `.txt` files.\n3. FAAAH then packages the responses into OpenAI-compatible JSON, and returns them to your app.\n\nBecause you already pay for an AI coding assistant. Stop paying for API keys\njust for your weekend side projects! *faaah!*\n\nIt's also an agnostic proxy between any OpenAPI-expecting tool, and any LLM.\n\nAs an example, check [**GraphRAG fully driven through\nFAAAH**](https://github.com/sebastiancarlos/graphrag-faaah).\n\n## demo-9mb.mp4\n\nIt is my understanding that local, non-commercial use of this tool doesn't break the existing ToS of any AI agent provider.\n\nBut if any lawyer disagrees, kindly send me a message. I would then introduce you to a friend of mine: Miss Barbra Streisand.\n\n**Be cautious** about using FAAAH to process massive datasets. Some providers\n(you know [which ones](https://news.ycombinator.com/item?id=47963204)) might\ndo some Kafkaesque interpretations of their ambiguous ToS, and deploy\n*Orwellian telemetry* to detect infractions (hasn't happened to me yet, YOLO!)\n\n- **Zero Dependencies:** Uses Python's`http.server` . That's it.\n- **308 lines of code:** Have you seen the*bloat* of other tools in this\nspace? Yuck.\n- **Unix Philosophy:** Everything is a file. Do one thing well. Keep it KISS,\nya YAGNI.\n- **Universal Compatibility:** If a tool supports the*de-facto* OpenAI API\nformat (GraphRAG, LangChain, LlamaIndex, LiteLLM, the`openai` SDK), it\nsupports FAAAH.\n- **Agent Agnostic:** Due to the agent entrypoint being*a prompt* , it's not\ntied to any specific agent provider/version. Future-proof.\n- **Human-in-the-loop Fallback:** If the AI agent gets stuck or hits usage\nlimits, you can literally open the current response file (say`response-0004.txt` ), type the answer yourself (or copy-paste the request to\nyour favorite web chatbot), and hit save. FAAAH will succeed.\n\nInstall with `uv`, from inside this repo:\n\n```\nuv tool install .              # installs the `faaah` command on PATH\nuv tool install .[embeddings]  # with the local embeddings extra (see later)\n```\n\nOr straight from the git repository:\n\n```\nuv tool install git+https://github.com/sebastiancarlos/faaah\nfaaah                       # listens on 127.0.0.1:8000, queue ~/.cache/faaah/queue\nfaaah --port 8080           # override port\nfaaah --queue /tmp/q        # override queue directory\nfaaah --log-dir /tmp/logs   # override session log root (see below)\nfaaah -c                    # also copy the agent prompt to the clipboard\n```\n\nEach run creates a session-log dir (`~/.cache/faaah/sessions/<TIMESTAMP>-<RANDOM>` by\ndefault) that mirrors **every** queue file written or answered during that run,\nso you can debug a session even after the queue is wiped on restart:\n\n- `prompt-<id>.txt` ,`response-<id>.txt` — same files as the queue\n- `request-<id>.json` ,`response-<id>.json` — the raw OpenAI request/response\n- `embed-<id>-request.json` ,`embed-<id>-response.json` — embeddings traffic\n- `session.log` — plain-text copy of all log lines\n\nPass `--log-dir \"\"` to disable session logging.\n\nThe agent prompt is printed on startup. To grab it again:\n\n```\nfaaah --agent-message\n```\n\nPaste it into your coding agent, which then starts a **FAAAH coordinator\nloop**:\n\n- Call `faaah --watch` to obtain the next request (blocks until one exists).\n- Delegate the request to a worker subagent (to prevent accumulating context).\n- Repeat. If a worker leaves no response file, `faaah --watch` simply returns\nthe same path again, so the coordinator retries it.\n\n**Note:** FAAAH uses subagents to prevent exhaustion of context on multiple\nrequests. Thereby, your AI Agents *must support creation of subagents on\nrequest by prompt*.\n\nYou can use `curl`, for example:\n\n```\ncurl http://127.0.0.1:8000/v1/chat/completions \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer anything\" \\\n  -d '{\n    \"model\": \"faaah\",\n    \"messages\": [{\"role\": \"user\", \"content\": \"Write a haiku.\"}]\n  }'\n```\n\nOr any OpenAI-API shaped client:\n\n``` python\nfrom openai import OpenAI\nclient = OpenAI(base_url=\"http://127.0.0.1:8000/v1\", api_key=\"anything\")\nresponse = client.chat.completions.create(\n    model=\"faaah\", # this field is ignored anyway\n    messages=[{\"role\": \"user\", \"content\": \"Write a haiku.\"}],\n    timeout=None,           # agents can be slow\n).choices[0].message.content\nprint(response)\n```\n\nA dependency-free example lives in `examples/chat.py`.\n\nFor an advanced usage, **GraphRAG fully driven through FAAAH**, see\n[graphrag-faaah](https://github.com/sebastiancarlos/graphrag-faaah).\n\nFAAAH supports the OpenAI `tools` parameter, including multi-turn tool loops.\nSend a non-empty `tools` array and the prompt tells the agent which tools\nexist and how to request them. Without `tools`, the classic text-only behavior\nis unchanged.\n\nThe agent requests tool calls by committing a JSON object whose only key is\n`tool_calls`:\n\n```\n{\"tool_calls\": [{\"name\": \"get_weather\", \"arguments\": {\"city\": \"Lisbon\"}}]}\n```\n\nFAAAH mints the call ids, returns `finish_reason: \"tool_calls\"`, and expects the\nclient to execute the tool and send the result back as a `tool` message. On the\nnext request, tool results are rendered as `<tool_result>` blocks and the agent\nanswers in plain text with `finish_reason: \"stop\"`.\n\nSupported `tool_choice` values are `auto` (default), `none`, `required`, and a\nforced function. `parallel_tool_calls: false` limits the reply to one call.\nMalformed tool replies are retried up to twice with the error fed back to the\nagent; after that FAAAH returns `502`.\n\nStreaming is not supported; requests with `stream: true` get a `400`.\n\nA dependency-free example lives in `examples/tools.py`:\n\n```\n./examples/tools.py \"What's the weather in Lisbon?\"\n```\n\nFAAAH stays dependency-free by default, but can serve local embeddings via the\noptional `embeddings` `uv` extra (Installs a spaCy model, `en_core_web_md`):\n\n```\nuv tool install '.[embeddings]'   # global tool with embeddings (from inside this repo)\nuv sync --extra embeddings        # or just the dev environment\n```\n\nWhen installed, `POST /v1/embeddings` returns OpenAI-shaped vectors computed\nlocally. Without the extra dependencies, the endpoint just returns `503`.\n\n```\ncurl http://127.0.0.1:8000/v1/embeddings \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"model\": \"en_core_web_md\", \"input\": [\"hello world\"]}'\nusage: faaah [-h] [--host HOST] [--port PORT] [--queue QUEUE] [--log-dir LOG_DIR] [--timeout TIMEOUT] [--agent-message] [-c] [-d] [--watch]\n\nFilesystem As An AI Handler: an OpenAI-compatible proxy backed by an AI agent working over text files.\n\noptions:\n  -h, --help         show this help message and exit\n  --host HOST        Address to bind (default: 127.0.0.1).\n  --port PORT        Port to listen on (default: 8000).\n  --queue QUEUE      Directory where prompt/response files live (default: ~/.cache/faaah/queue).\n  --log-dir LOG_DIR  Parent dir for per-session logs (default: ~/.cache/faaah/sessions). A new <TIMESTAMP>-<RANDOM> subdir is created each run; pass empty string to disable.\n  --timeout TIMEOUT  Abort each call after N seconds. 0 (default) waits forever.\n  --agent-message    Print ONLY the agent prompt and exit (it's also printed on launch).\n  -c, --copy         Copy the agent prompt to the system clipboard on startup (uses wl-copy, xclip, xsel, pbcopy or clip.exe if available).\n  -d, --debug        Print the full request/response flow for each call once it completes.\n  --watch            Block until a pending prompt exists, print its path.\n```\n\nThe protocol relies on files on the queue directory (`~/.cache/faaah/queue` by\ndefault).\n\nEach request produces a `prompt-<id>.txt` file, where the first one's ID will be\n`00001` and increase monotonically.\n\nFAAAH then expects the agent (or anything really) to generate a corresponding\n`response-<id>.txt`.\n\nThe subagent workers are prompted to write a first pass as\n`response-<id>.txt.draft`, which they may revise, before renaming it to the\nfinal `response-<id>.txt` they consider *final*.\n\n| File | Who writes | Meaning | \n|---|---|---|\n| `prompt-<id>.txt` | server | an incoming request for the agent | \n| `response-<id>.txt.draft` | agent | an in-progress, editable draft | \n| `response-<id>.txt` | agent | the answer | \n\nRetry is automatic: a prompt with no response file is simply re-offered by\n`faaah --watch` to the coordinator until one appears. Tool-call validation\nretries also use a fresh prompt id, with the rejected reply and the reason\nincluded in the new prompt.\n\nIf the client disconnects, or the server-side `--timeout` fires, faaah removes\nthe prompt so `--watch` does not keep re-offering work nobody is waiting for.\n\nOther projects put an API in front of a CLI subscription:\n\n- [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) is a Go proxy\nthat exposes several CLI providers such as Claude Code, Codex, Gemini, and Grok\nthrough OpenAI, Gemini, Claude, Codex, and Grok compatible endpoints. It\nhandles OAuth, streaming, multimodal input, tool calling, and multi-account\nload balancing.\n- [opencode2api](https://github.com/jasonxu114514/opencode2api) is a Go\ngateway for OpenCode Zen and Zen Go.\n\nUnlike the above, *FAAAH doesn't talk to a provider at all: FAAAH tells you\nhow to prompt the model you already have to act as an OpenAI API*, so in\nprinciple any model that you can prompt locally works.\n\nMIT", "url": "https://wpnews.pro/news/faaah-filesystem-as-an-ai-handler-agent-subscription-as-openai-api-via-files", "canonical_source": "https://github.com/sebastiancarlos/faaah", "published_at": "2026-11-05 10:12:19+00:00", "updated_at": "2026-11-05 10:20:36.087436+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "large-language-models", "artificial-intelligence"], "entities": ["FAAAH", "Sebastian Carlos", "OpenAI", "Claude Code", "opencode", "GraphRAG", "LangChain", "LlamaIndex"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/faaah-filesystem-as-an-ai-handler-agent-subscription-as-openai-api-via-files", "markdown": "https://wpnews.pro/news/faaah-filesystem-as-an-ai-handler-agent-subscription-as-openai-api-via-files.md", "text": "https://wpnews.pro/news/faaah-filesystem-as-an-ai-handler-agent-subscription-as-openai-api-via-files.txt", "jsonld": "https://wpnews.pro/news/faaah-filesystem-as-an-ai-handler-agent-subscription-as-openai-api-via-files.jsonld"}}