# floom - Complete Reference for AI Agents
> Turn Python functions into web apps. Type hints become the UI, API, and shareable links. Self-hosted with Docker. Open source (MIT).
## Overview
floom bridges the gap between writing a Python function and having it running as a usable web application. It extracts type hints, generates an OpenAPI schema, creates a web form UI, runs code in a Docker sandbox, and produces a shareable link.
Self-hosted with a single Docker command. No cloud account required.
## Installation
### Docker (recommended)
```bash
docker run -p 3000:3000 -p 3001:3001 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /tmp/floom-workspaces:/tmp/floom-workspaces \
-v /tmp/floom-storage:/tmp/floom-storage \
-v floom-data:/data \
ghcr.io/floomhq/floom
```
Web UI on port 3000, API on port 3001.
### From source
```bash
git clone https://github.com/floomhq/floom
cd floom
npm run setup:local
docker-compose up --build
```
### CLI
```bash
npm install -g @floomhq/cli
floom deploy my-app.py --name "My App"
floom run greet name=world
```
### MCP Server (for Claude, Cursor, and other AI agents)
```bash
npx @floomhq/cli setup-mcp
```
This prints a config block to paste into your MCP settings. Gives agents tools to deploy, run, list, and manage floom apps.
## Python SDK
### Basic action
```python
from floom import app
@app.action
def greet(name: str) -> dict:
return {"message": f"Hello, {name}!"}
```
### With persistent memory
```python
from floom import app, remember, forget
@app.action
def count_visits(name: str) -> dict:
visits = (remember("visits") or 0) + 1
remember("visits", visits)
return {"message": f"Hello {name}! Visit #{visits}"}
# remember(key, value) -> set
# remember(key) -> get
# forget(key) -> delete
```
### Full storage API
```python
from floom import app, storage
@app.action
def configure(theme: str = "dark") -> dict:
storage.set("config", {"theme": theme})
return storage.get("config")
# storage.set(key, value)
# storage.get(key, default=None)
# storage.list() -> list of keys
# storage.delete(key)
```
### SQLite database
```python
from floom import app, db, get_db
@app.action
def add_item(name: str) -> dict:
db.execute("CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, name TEXT)")
db.execute("INSERT INTO items (name) VALUES (?)", (name,))
rows = db.execute("SELECT * FROM items").fetchall()
return {"items": [dict(r) for r in rows]}
```
### File outputs (artifacts)
```python
from floom import app, save_artifact, save_dataframe, save_json
@app.action
def generate_report(query: str) -> dict:
save_artifact("report.html", "
Report
")
save_json("data.json", {"query": query, "results": []})
return {"status": "report generated"}
```
### Secrets
```python
from floom import app, context
@app.action
def fetch_data(query: str) -> dict:
api_key = context.get_secret("MY_API_KEY")
# use api_key to call external service
return {"result": "..."}
```
### Scheduled execution
```python
from floom import app
@app.schedule("0 9 * * *", timezone="UTC")
@app.action
def daily_report() -> dict:
return {"summary": "Daily report generated"}
```
### Custom action names
```python
@app.action(name="custom_name")
def my_func(y: str) -> dict:
return {"greeting": f"Hello, {y}!"}
```
### Type hints -> UI mapping
| Python type | Generated UI | Notes |
|-------------|-------------|-------|
| `str` | Text input | |
| `int` | Number input | |
| `float` | Number input (decimal) | |
| `bool` | Checkbox | |
| `Literal["a","b","c"]` | Dropdown select | Import from typing |
| `dict` | JSON editor | |
| Default values | Pre-filled placeholders | e.g. `city: str = "Berlin"` |
| Return `dict` | Structured output card | Always return dict |
## REST API Reference
Base URL: `http://localhost:3001` (self-hosted) or `https://floom.dev` (demo)
### Per-app API (agent-friendly, no IDs needed)
```bash
# Discover what an app can do
GET /v1/apps/{slug}
# Returns: actions list with input schemas
# Call an action (synchronous, returns result directly)
POST /v1/apps/{slug}/{action_name}
Content-Type: application/json
Body: { "param1": "value1", "param2": "value2" }
# Returns: {"status":"success","result":{...},"duration_ms":1200}
```
### Project management
```bash
# List all apps
GET /v1/projects
# Create a new app
POST /v1/projects
Body: {"name": "my-app", "code": "...python code..."}
# Get app details
GET /v1/projects/{id}
# Update app metadata (name, slug only; to update code, redeploy)
PATCH /v1/projects/{id}
Body: {"name": "new-name", "slug": "new-slug"}
# Delete app
DELETE /v1/projects/{id}
```
### Deployment
```bash
# Deploy (build and start)
POST /v1/projects/{id}/deploy
# Check deploy status
GET /v1/projects/{id}/deploy/status
```
### Execution
```bash
# Run an action
POST /v1/runs
Body: {"project_id": "...", "endpoint_id": "...", "input": {...}}
# Get run result
GET /v1/runs/{run_id}
```
### Secrets (encrypted at rest)
```bash
# Set a secret (one at a time)
POST /v1/projects/{id}/secrets
Body: {"key": "API_KEY", "value": "sk-..."}
# List secret names (values hidden)
GET /v1/projects/{id}/secrets
```
### Storage
```bash
# List storage keys
GET /v1/projects/{id}/storage
# Get a value
GET /v1/projects/{id}/storage/{key}
# Set a value
PUT /v1/projects/{id}/storage/{key}
Body: {"value": {...}}
```
### Templates
```bash
# List available templates
GET /v1/templates
# Create app from template
POST /v1/templates/{template_id}/create
```
### OpenAPI spec
```bash
GET /v1/openapi.json
```
Full OpenAPI 3.0.3 schema describing all endpoints, request/response types, and authentication.
## CLI Reference
```bash
floom deploy --name "App Name" # Deploy a Python file
floom run key=value # Execute an action
floom list # List all apps
floom logs # View execution logs
floom doctor # Check local setup
floom storage list # List storage keys
floom storage get # Get a value
floom storage set # Set a value
floom share create # Create a shareable link
floom setup-mcp # Configure MCP for AI agents
```
## MCP Tools (complete list, 32 tools)
When the MCP server is configured, agents get these tools:
### Core Workflow
- `deploy` - Deploy Python code, returns project ID and endpoint list
- `run` - Execute an action by slug+action or project_id+endpoint_id
- `list_projects` - List all deployed apps
- `get_project` - Get app details and endpoint schemas
- `delete_project` - Remove a project
- `update_project` - Update project name or slug
### Version Management
- `list_versions` - See all versions of a project with hashes
- `promote` - Promote a version to production with health check
- `rollback` - Roll back to a previous version
### Storage (persistent key-value)
- `storage_set` - Store a value (up to 10MB)
- `storage_get` - Retrieve a value by key
- `storage_delete` - Remove a key
- `storage_list` - List all keys for a project
### Secrets
- `manage_secrets` - Set, list, or delete encrypted API keys (action param)
### Sharing
- `create_share_link` - Generate a public URL
- `list_share_links` - List existing links
- `disable_share_link` - Revoke a share link
### Context (project metadata)
- `fetch_context` - Pull context from a URL
- `get_context` - Get a stored context
- `list_contexts` - List all contexts
- `delete_context` - Remove a context
- `refresh_context` - Re-fetch a context from its URL
### Scheduling
- `create_schedule` - Set up cron-based execution
- `list_schedules` - List schedules for a project
- `delete_schedule` - Remove a schedule
### Templates
- `list_templates` - Browse starter templates
- `get_template` - Get template details and code
- `create_from_template` - Create a project from a template
### GitHub
- `deploy_from_github` - Deploy directly from a GitHub repo URL
### Webhooks
- `enable_webhooks` - Enable inbound webhook triggers
- `disable_webhooks` - Disable webhooks
### Logs
- `get_logs` - View execution logs with error details and suggested fixes
## Agent Cookbook
### Pattern 1: Deploy from chat
Write code, deploy, get a URL back:
```
1. deploy(code="from floom import app\n\n@app.action\ndef greet(name: str) -> dict:\n return {\"message\": f\"Hello, {name}!\"}", name="greeter")
-> Returns: {project_id, slug: "greeter", endpoints: [{id, name: "greet", path: "/greet"}]}
2. run(app_slug="greeter", action="greet", json={"name": "world"})
-> Returns: {"message": "Hello, world!"}
3. create_share_link(project_id="...")
-> Returns: {url: "https://floom.dev/s/abc123"}
```
### Pattern 2: Stateful tool with remember()
Deploy an app that persists data across runs:
```python
from floom import app, remember
@app.action
def add_note(text: str) -> dict:
notes = remember("notes") or []
notes.append(text)
remember("notes", notes)
return {"notes": notes, "count": len(notes)}
@app.action
def get_notes() -> dict:
return {"notes": remember("notes") or []}
```
After deploying, use MCP storage tools to inspect state:
```
storage_list(project_id="...") -> ["notes"]
storage_get(project_id="...", key="notes") -> ["first note", "second note"]
```
### Pattern 3: Multi-action API with secrets
```python
from floom import app, context
@app.action
def search(query: str, max_results: int = 5) -> dict:
api_key = context.get_secret("SEARCH_API_KEY")
# use api_key to call search API
return {"results": [...]}
@app.action
def summarize(text: str) -> dict:
api_key = context.get_secret("LLM_API_KEY")
# use api_key to call LLM
return {"summary": "..."}
```
Set secrets before first run:
```
manage_secrets(project_id="...", action="set", key="SEARCH_API_KEY", value="sk-...")
manage_secrets(project_id="...", action="set", key="LLM_API_KEY", value="sk-...")
```
IMPORTANT: Deploy with network enabled since this calls external APIs:
```
deploy(code="...", name="search-tool", config={"network": true})
```
### Pattern 4: File processing pipeline
```python
from floom import app, save_artifact, save_dataframe
import pandas as pd
@app.action
def analyze_csv(data: str, include_nulls: bool = False) -> dict:
df = pd.read_csv(pd.io.common.StringIO(data))
if not include_nulls:
df = df.dropna()
save_dataframe(df, "cleaned.csv")
save_artifact("stats.html", df.describe().to_html())
return {"rows": len(df), "columns": list(df.columns)}
```
Deploy with requirements:
```
deploy(code="...", name="csv-analyzer", requirements=["pandas"])
```
### Pattern 5: Deploy from GitHub
One call to deploy a repo:
```
deploy_from_github(github_url="https://github.com/user/my-tool", name="my-tool")
```
With a specific branch or tag:
```
deploy_from_github(github_url="https://github.com/user/my-tool", name="my-tool", github_ref="v2.0")
```
Repo must contain `main.py` with `@app.action`. Optional: `requirements.txt`, `floom.yaml`.
### Pattern 6: Version management
Safe update workflow:
```
1. deploy(code=updated_code, name="my-app")
-> Creates new version automatically
2. run(app_slug="my-app", action="test", json={...})
-> Test the new version
3a. If broken: rollback(project_id="...")
-> Reverts to previous version
3b. If working: promote(project_id="...", version_id="...")
-> Locks this version as production
4. list_versions(project_id="...")
-> See all versions with status
```
## floom.yaml Configuration (optional)
Pass as `config` parameter in deploy():
```yaml
endpoints:
generate:
description: "Generate a report"
timeout_seconds: 120
lane: cpu # cpu or gpu
inputs:
query: {type: string}
secrets: ["API_KEY", "DB_URL"] # declare required secrets
network: true # enable outbound network (default: false)
dependencies: ["requests", "pandas"]
```
IMPORTANT: network defaults to false (--network none in Docker). If your function calls external APIs (requests.get, urllib, httpx), you MUST set network: true.
## Deploy Status Workflow
After deploy(), status transitions: draft -> deploying -> live (or failed).
Via MCP:
1. `deploy(code, name)` -> returns immediately with project_id
2. `get_project(project_id)` -> check status field
3. If "deploying", wait 2-3 seconds, check again
4. If "live", proceed to run()
5. If "failed", read error.message + error.suggested_fix, fix code, redeploy
Via REST:
```
GET /v1/projects/{id}/deploy/status -> {"status": "live"|"deploying"|"failed"}
```
## Debugging a Failed Run
1. `get_logs(project_id)` -> read print() output + tracebacks
2. If ImportError -> add missing package to requirements, redeploy
3. If "secret not found" -> `manage_secrets(project_id, action="set", key="KEY_NAME", value="...")`
4. If timeout -> increase timeout_seconds in run(), or optimize function
5. If network error -> set config.network: true, redeploy
6. Fix code -> `deploy(fixed_code, name)` -> redeploy (creates new version)
7. Re-run and verify
## Error Handling
Deploy errors: Check `status` field. If "failed", read `error.message` and `error.suggested_fix`.
Run timeouts: Default 60s. Pass timeout_seconds to extend (max 300s). If timeout, retry with longer timeout or simplify the function.
Rate limits: 429 response. Wait 60 seconds, retry. Authenticated requests get 120/min, anonymous get 60/min.
Missing secrets: Run returns error with "secret X not found". Use manage_secrets to set it, then re-run.
Network disabled: Function tries to reach internet but fails silently. Set config.network: true in deploy.
Import error: Package not installed. Add to requirements array in deploy().
Storage full: 10MB per value, 100MB per project. Delete old keys with storage_delete.
Resource limits (defaults):
- RAM: 512MB per container (RUNNER_MEMORY env var)
- CPU: 1 core per container (RUNNER_CPUS env var)
- Timeout: 60 seconds per run (max 300s)
- Network: disabled by default (--network none)
## Architecture
```
Python function (type hints)
-> OpenAPI schema extraction
-> Auto-generated web form
-> Docker sandbox execution
-> Shareable link
Stack:
- Frontend: Next.js (TypeScript)
- API: Hono.js (TypeScript)
- Runtime: Python 3.11 in Docker
- Database: SQLite (self-hosted) or PostgreSQL via Supabase (cloud)
- Secrets: AES-256-GCM envelope encryption
- Sandbox: Docker with --network none, --cap-drop ALL
```
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| MASTER_ENCRYPTION_KEY | auto-generated | 32-byte base64 key for secrets |
| COMPUTE_BACKEND | docker | Execution backend |
| PORT | 3001 | API server port |
| API_KEY | (none) | Bearer token for API auth |
| RUNNER_IMAGE | floom-runner:latest | Docker image for execution |
| RUNNER_MEMORY | 512m | Memory limit per container |
| RUNNER_CPUS | 1 | CPU limit per container |
| RUNNER_NETWORK | none | Network mode (none for isolation) |
| GEMINI_API_KEY | (none) | Enables AI smart ingest for raw scripts |
## Comparison with alternatives
| Feature | floom | FastAPI | Streamlit | Gradio |
|---------|-------|---------|-----------|--------|
| Auto UI from code | Yes (type hints) | No | Manual widgets | Manual components |
| Zero config deploy | Yes (Docker) | Manual | Streamlit Cloud | Hugging Face Spaces |
| Sandboxed execution | Yes (Docker) | No | No | No |
| Shareable links | Built-in | Manual | Built-in | Built-in |
| Persistent storage | Built-in (remember()) | Manual | Session state | Manual |
| REST API | Auto-generated | Manual (but excellent) | No | API mode |
| MCP integration | Built-in (32 tools) | No | No | No |
| Self-hosted | Yes | Yes | Yes | Yes |
| Open source | MIT | MIT | Apache 2.0 | Apache 2.0 |
floom is not a replacement for FastAPI (which is excellent for building production APIs). floom is for when you have a Python function and want it live as a usable app in under a minute, with no frontend work.
## Links
- Website: https://floom.dev
- GitHub: https://github.com/floomhq/floom
- PyPI: https://pypi.org/project/floom/
- npm CLI: https://www.npmjs.com/package/@floomhq/cli
- MCP Server: https://www.npmjs.com/package/@floomhq/mcp-server
- OpenAPI spec: https://floom.dev/v1/openapi.json
- Docker image: ghcr.io/floomhq/floom
- Agent workflow guide: https://github.com/floomhq/floom/blob/main/docs/AGENT_GUIDE.md