Raw skill file — machine-readable. Append ?raw=1 for plain text.

---
name: floomit
description: How to use Floom v0.5 (hosted runtime for Python/TS apps). Thin pointer — fetch canonical docs from floom.dev/docs/<topic> for current truth; don't trust hardcoded knowledge.
version: 0.5.0
last_synced: 2026-05-05
canonical_source: https://floom.dev/skills/floomit
canonical_raw: https://floom.dev/skills/floomit?raw=1
auto_refresh_threshold_days: 7
---

# Floom v0.5 — Quick Orientation

Floom turns Python or TypeScript code into shareable, authenticated app URLs.
You deploy a bundle; Floom runs it in an E2B sandbox on demand. Every app gets:
- A browser permalink: `https://floom.dev/p/<slug>`
- A REST endpoint: `https://floom.dev/api/apps/<slug>/run`
- An incoming webhook endpoint when enabled: `https://floom.dev/w/<slug>`
- An MCP tool entry: `https://floom.dev/mcp`

**Production host:** `https://floom.dev` (not any `.vercel.app` URL — those are legacy/orphan)

**Install the CLI once:**
```bash
npm install -g @floomhq/cli@latest
```

**Auth:**
```bash
floom setup   # opens browser, stores token locally
```

**Deploy:**
```bash
floom deploy ./my-app-dir
```

---

## When you need to...

### Deploy an app end-to-end
**Read:** https://floom.dev/docs/quickstart
Install CLI, scaffold, deploy, run — the full flow.

### Write or fix the manifest (floom.yaml)
**Read:** https://floom.dev/docs/manifest
All fields: slug, command, runtime, entrypoint, public, input_schema, output_schema, dependencies, secrets, connections, bundle_exclude. Both legacy and modern forms. (`integrations:` is accepted as a deprecated alias; `composio:` is the old legacy form — both still accepted.)

**Single-file default:** input_schema and output_schema can be inline YAML objects — no separate .json files needed. Example:

```yaml
input_schema:
  type: object
  required: [text]
  properties:
    text: { type: string }
output_schema:
  type: object
  required: [result]
  properties:
    result: { type: string }
```

Path-reference form (`input_schema: ./input.schema.json`) still works as an escape hatch.

### Configure secrets (shared vs per-runner)
**Read:** https://floom.dev/docs/secrets
Creator-subsidized shared keys vs per-runner user-provided keys. Manifest schema and CLI commands.

### Send completion webhooks
**Read:** https://floom.dev/docs/webhooks
Declare `on_complete.webhook` to send a signed HTTPS callback when a run reaches `succeeded`, `failed`, `timed_out`, or `cancelled`.

```yaml
secrets:
  - OUTBOUND_WEBHOOK_SECRET

on_complete:
  webhook:
    url: https://example.com/floom-callback
    secret_env: OUTBOUND_WEBHOOK_SECRET
    retry: 3
    timeout_sec: 30
```

The `secret_env` value must reference a declared Floom secret. Floom signs `${timestamp}.${rawJsonBody}` with HMAC-SHA256 and sends `X-Floom-Signature: t=<unix seconds>,v1=<hex>` plus `X-Floom-Timestamp: <unix seconds>`. Receivers verify with a 5-minute replay tolerance. Delivery pins the DNS-validated public IP, blocks private/link-local/loopback egress, caps payloads at 1 MB, treats non-408/429 `4xx` as dead, retries transient failures with exponential backoff, and sweeps delivered/dead delivery rows after the retention window.

### Receive incoming webhooks
**Read:** https://floom.dev/docs/webhooks
Floom can expose `https://floom.dev/w/<slug>` for signed provider deliveries. Manifest field:

```yaml
secrets:
  - name: STRIPE_WEBHOOK_SECRET
    scope: shared
webhook:
  enabled: true
  verify: stripe
  secret_env: STRIPE_WEBHOOK_SECRET
  body_max_bytes: 1048576
  response_passthrough: true
```

Supported `verify` modes: `stripe`, `github`, `slack`, `twilio`, `linear`, `hmac`, and `none`. Webhook input reaches the app as `inputs.headers`, `inputs.body`, and `inputs.query`, then Floom validates the transformed input against the app `input_schema`. Webhook endpoints are POST-only and server-to-server; no browser CORS headers are emitted. Linear payloads must include `webhookTimestamp`. Error codes: `invalid_signature`, `missing_webhook_timestamp`, `replay_detected`, `body_too_large`, `rate_limit_exceeded`, `webhook_disabled`, `missing_webhook_secret`, `input_validation_failed`.

### Use Gmail, Slack, or other connections (external services)
**Read:** https://floom.dev/docs/connections
Manifest field uses a provider-to-tool allowlist, e.g. `connections: { gmail: [GMAIL_SEND_EMAIL] }`. Runtime auto-injects `COMPOSIO_<TOOLKIT>_CONNECTION_ID` plus scoped `FLOOM_COMPOSIO_TOKEN` / `FLOOM_COMPOSIO_PROXY_URL`; the platform key is never available in app env. Missing-connection: HTTP 412 handling.

Some toolkits also require creator-side admin credentials before publish. Current Case-B toolkits: `whatsapp`, `stripe_connect`, `twilio`, `sendgrid`, and `mailgun`. Publish returns `creator_credentials_missing` with the required keys until the app owner stores them through the credentials API. UI entry is a follow-up.

**Per-provider setup docs** (actions, gotchas, code examples):
`https://floom.dev/docs/connections/<provider>`

Examples:
- https://floom.dev/docs/connections/gmail — OAuth scopes, Google verification timeline, test-user workaround
- https://floom.dev/docs/connections/whatsapp — Meta Business approval, template requirements
- https://floom.dev/docs/connections/slack — workspace owner approval, bot vs user tokens
- https://floom.dev/docs/connections/github — rate limits, PAT alternative
- https://floom.dev/docs/connections/notion — page-scope gotcha (user must share pages explicitly)

**BEFORE writing app code that uses a connection**, fetch the provider doc page:
```
https://floom.dev/docs/connections/<provider>
```
It tells you what actions are available, what gotchas exist (e.g. Meta Business for WhatsApp), and includes working code examples. Don't guess — every provider has different setup requirements.

**GOTCHA — connection calls go through the Floom proxy:**
Do not call the provider API directly from app code. Use the injected `FLOOM_COMPOSIO_PROXY_URL` with `Authorization: Bearer $FLOOM_COMPOSIO_TOKEN`, or use the SDK-compatible `ComposioToolSet` import that Floom shims in the sandbox for common `execute_action` usage.
```python
req = urllib.request.Request(
    os.environ["FLOOM_COMPOSIO_PROXY_URL"],
    data=json.dumps({"tool_slug": "GMAIL_SEND_EMAIL", "args": {...}}).encode(),
    headers={"Authorization": "Bearer " + os.environ["FLOOM_COMPOSIO_TOKEN"]},
    method="POST",
)
```

**GOTCHA — User-Agent required for direct Composio REST calls:**
Floom's sandbox runtime now injects `FLOOM_USER_AGENT=floom-runtime/0.4 (+https://floom.dev)` and loads a Python preamble that applies it to default `urllib.request`, `requests`, and `httpx` calls. Default Python HTTP User-Agents are blocked by Composio's Cloudflare front door (error 1010); outside Floom, set a custom `User-Agent` yourself. Current `composio-core` uses `requests` without its own custom `User-Agent`, so the Floom preamble covers SDK calls too.
```python
# Outside Floom, wrong — blocked
req = urllib.request.Request(url, headers={"x-api-key": key})
# Outside Floom, right — works
req = urllib.request.Request(url, headers={"x-api-key": key, "User-Agent": "floom-runtime/0.4 (+https://floom.dev)"})
```

### Call the REST API directly
**Read:** https://floom.dev/docs/api
Endpoints, auth headers, sync vs async run patterns, poll pattern.

### Use the MCP server
**Read:** https://floom.dev/docs/mcp
Available tools, auth, integration with Claude Desktop / Cursor / Codex.

### Mint or revoke agent tokens
**Read:** https://floom.dev/docs/auth
Token format, scopes (read/run/publish), no expiry (revoke manually), CI usage.

### Debug a failed run
**Read:** https://floom.dev/docs/troubleshooting
Error codes (404/400/401/412/429/502/500) and fixes.

### See working real-world examples
**Read:** https://floom.dev/docs/examples
Deployable app slugs to use as starting points.

### Run deploys from CI / GitHub Actions
**Read:** https://floom.dev/docs/ci
FLOOM_API_KEY usage, GitHub Actions example.

---

## Refresh this skill

If this file is older than 7 days or you suspect it's stale:
```bash
curl -s "https://floom.dev/skills/floomit?raw=1"
```
That always returns the version live in production.

## CI gate: doc freshness

PRs are blocked by the `doc-freshness` CI check if they introduce stale strings
into public-facing files. If your PR is blocked, run:

```bash
npm run check-doc-freshness
```

It will print which file and line triggered, and why. Common fixes:
- Remove `Floom v0.1/v0.2/v0.3/v0.4` used as current branding (current version is v0.5).
- Replace `floomhq/floom-minimal` with `floomhq/floom`.
- Remove personal emails or internal filesystem paths.