Skip to main content

Funmill

Funmill provides one stable task API while execution is delegated to a replaceable backend. The recommended local backend is self-hosted Dagu, pinned to v2.16.3. Windmill remains available for existing deployments.

client -> Funmill /v1 -> TaskBackend -> Dagu
                                  -> Windmill

Funmill owns the public request and response models. Backend job IDs remain opaque strings, and no backend-specific routes or payloads are exposed to clients.

Start

Install the project and the Dagu binary. The installer supports macOS and Linux on Intel/AMD and ARM64:

uv sync
uv run funmill install dagu

Start Dagu in the background. It stores state under ~/.farfarfun/funmill/services/dagu/data/ and needs no external database:

uv run funmill start dagu

The command reports its PID and log path. Open http://localhost:8813, then start Funmill:

FUNMILL_API_KEY='replace-me' \
FUNMILL_BACKEND=dagu \
DAGU_URL='http://127.0.0.1:8813' \
uv run funmill start

Managed HTTP services bind to 0.0.0.0: Funmill uses port 8812 and the active third-party service uses 8813. Local client URLs still use 127.0.0.1 or localhost; 0.0.0.0 is a listen address, not a client destination.

Dagu starts without authentication. Because it listens on every interface, restrict port 8813 with a firewall or enable Dagu authentication. When authentication is enabled, set DAGU_TOKEN for both funmill start dagu and funmill start so cross-run dependencies can query Dagu from worker processes.

Dagu runs submitted source with the service user's host permissions. Keep both services private and accept only trusted code; use isolated workers or containers before accepting untrusted jobs.

The Funmill API port is fixed at 8812; the active third-party UI/API port is fixed at 8813. OpenAPI docs are at http://localhost:8812/docs. All /v1 routes require X-API-Key. See the Dagu deployment guide or the Windmill deployment guide for backend-specific setup.

Run the end-to-end task and DAG checks with:

FUNMILL_API_KEY=the-value-from-env ./scripts/smoke.sh

Set FUNMILL_CALLBACK_URL to test callbacks. The URL must be reachable from the backend workers.

API

Operation Route
Health check GET /health
Submit Python/Bash POST /v1/tasks
Submit a DAG POST /v1/workflows
Status GET /v1/tasks/{task_id}
Logs GET /v1/tasks/{task_id}/logs
Progress GET /v1/tasks/{task_id}/progress
Result GET /v1/tasks/{task_id}/result
Cancel POST /v1/tasks/{task_id}/cancel
Rerun POST /v1/tasks/{task_id}/rerun

GET /health is unauthenticated and reports whether the Funmill process and its configured backend are reachable; it returns {"status": "ok", "backend": "..."} on success and a 503 with a detail message when the backend is unreachable or misconfigured.

Submit one task, optionally waiting for existing task IDs:

{
  "language": "python",
  "source": "def main(value: int):\n    return value * 2\n",
  "args": {"value": 21},
  "depends_on": ["EXISTING_TASK_ID"],
  "dependency_timeout_seconds": 3600,
  "retry": {"attempts": 2, "delay_seconds": 5},
  "timeout_seconds": 300,
  "callback_url": "https://example.internal/task-callback"
}

Submit A -> [B, C] as one workflow:

{
  "tasks": [
    {"key": "a", "language": "python", "source": "def main(): return 1"},
    {"key": "b", "language": "python", "source": "def main(): return 2", "depends_on": ["a"]},
    {"key": "c", "language": "bash", "source": "main() { echo 3; }", "depends_on": ["a"]}
  ]
}

Dependencies inside a workflow are task keys. Top-level depends_on values are IDs returned by earlier Funmill submissions. Backends check those dependencies from worker jobs, so waiting does not hold the Funmill API process. Failure or cancellation of a dependency fails the waiting task. Workflow results and callback payloads are objects keyed by every workflow task key. Each topological layer is a synchronization barrier; tasks in the same layer run in parallel.

Callbacks contain task_id, status, and payload; success and failure delivery retry three times. Delivery is at least once, so callback receivers must be idempotent.

Python SDK

A Python client for the /v1 routes plus /health lives in the separate funmill-sdk repository, published to PyPI as funmill (imported as funmill.client):

pip install funmill
from funmill.client import FunmillClient, TaskSubmit

with FunmillClient(base_url="http://127.0.0.1:8812", api_key="replace-me") as client:
    client.health()  # {"status": "ok", "backend": "dagu"}

    accepted = client.submit_task(
        TaskSubmit(language="python", source="def main(): return 21 * 2")
    )
    task = client.get_task(accepted.task_id)
    result = client.get_result(accepted.task_id)

See the funmill-sdk README for the full client API and error handling.

Backends

The public contract is TaskBackend in src/funmill/api/backends/base.py. Backend selection uses FUNMILL_BACKEND; registration lives in src/funmill/api/backends/__init__.py, following the same driver pattern as fundrive. Each third-party adapter lives in its own directory, such as src/funmill/api/backends/windmill/.

Every third-party adapter directory must include a README.md covering its supported platforms, installation, configuration, startup, verification, and security or operational constraints.

Every managed HTTP service must bind to SERVICE_BIND_HOST (0.0.0.0). Every third-party service must use the shared background lifecycle in src/funmill/api/backends/service.py and expose start, stop, and status; restart is composed from stop and start by the CLI.

Changing the backend does not change /v1, but it does not migrate old jobs or their IDs. Add a Funmill-owned ID mapping database only when jobs must remain queryable after a live backend migration.

Operations

funmill services
funmill install dagu
funmill start dagu
funmill status dagu
funmill restart dagu
funmill stop dagu
funmill install windmill
funmill start windmill
funmill start

Third-party services run in the background with PID and log files under ~/.farfarfun/funmill/services/<service>/; replace dagu with windmill in the lifecycle commands as needed. The Funmill API remains in the foreground and stops with Ctrl+C. Add authentication, TLS, firewall rules, PostgreSQL backups, callback egress restrictions, and a secrets manager before network exposure.

Metadata

Release files for funmill-api 0.1.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for funmill-api 0.1.8
File Interpreter ABI Platform
funmill_api-0.1.8-py3-none-any.whl Python 3 none any Details

Release files / funmill_api-0.1.8-py3-none-any.whl

Download URL funmill_api-0.1.8-py3-none-any.whl
Size 27.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6d301e217f512733a272127ac9a42337971b15f068b9e64f31ebf6bf05860cad
BLAKE2b-256 checksum
How to use checksums
bb52f4e77eddcf471fd9879b5371628587c4c60fea49c153cdf6975316ba2f4a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for funmill-api 0.1.8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.8 This release

1 release file No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page