Skip to main content

Moonchild 🌙

Moonchild is a declarative Python workflow framework with a built-in real-time UI.

About this repository

Welcome to the repository of Moonchild, developed by Ally Bros. Moonchild lets you define multi-step workflows in pure Python — with parallel branches, conditional logic, human-in-the-loop wait states, and cron scheduling — then serves a real-time dashboard so you can monitor and interact with every run. You can use this source code under the terms of the MIT License.


🌟 Features

  • Declarative fluent builder: .when().step().and_().or_().if_().finish()
  • Parallel branches: .and_() (all complete) / .or_() (first wins)
  • Conditional branching: .if_(condition).then_(a).else_(b).end_if()
  • Human-in-the-loop wait actions with auto-rendered UI forms
  • Cron and manual triggers
  • Real-time dashboard over WebSocket
  • Zero-setup TinyDB persistence
  • Publish once, run anywhere — just pip install moonchild

📀 Installation

pip install moonchild

Requires Python 3.11+.


🕹 Usage

1. Define your actions

from moonchild import Action, Result

class FetchData(Action):
    def execute(self, ctx):
        ctx["data"] = "hello world"
        return Result.next()

class ProcessData(Action):
    def execute(self, ctx):
        ctx["result"] = {"value": ctx["data"].upper()}
        return Result.next()

2. Build your workflow

from moonchild import workflow, ManualTrigger

workflow("my-pipeline") \
    .when(ManualTrigger()) \
    .step(FetchData(),   name="fetch") \
    .step(ProcessData(), name="process") \
    .finish()

3. Start

from moonchild import Moonchild

Moonchild.start()   # serves at http://localhost:8000

Full example (app.py):

from moonchild import Moonchild, workflow, Action, Result, ManualTrigger

class FetchData(Action):
    def execute(self, ctx):
        ctx["data"] = "hello world"
        return Result.next()

workflow("my-pipeline") \
    .when(ManualTrigger()) \
    .step(FetchData(), name="fetch") \
    .finish()

Moonchild.start()
python app.py

🔀 Parallel branches

from moonchild import workflow, branch, ManualTrigger

workflow("parallel-wf") \
    .when(ManualTrigger()) \
    .step(Ingest(), name="ingest") \
    .and_(                                      # wait for ALL branches
        branch("validate")
            .step(ValidateSchema(), name="validate-schema")
            .step(ValidateRules(),  name="validate-rules"),
        branch("enrich")
            .step(EnrichGeo(),  name="enrich-geo")
            .step(EnrichTags(), name="enrich-tags"),
        name="validate-and-enrich",
    ) \
    .or_(                                       # continue on FIRST branch done
        branch("email").step(SendEmail(), name="email"),
        branch("sms").step(SendSMS(),     name="sms"),
        name="notify",
    ) \
    .step(Finalize(), name="finalize") \
    .finish()

Branches run in parallel threads. The shared ctx dict is lock-protected.


🔁 Conditional branching

from moonchild import Action, Result

class IsWeekend(Action):
    def execute(self, ctx):
        import datetime
        return Result.branch(datetime.date.today().weekday() >= 5)

workflow("conditional-wf") \
    .when(ManualTrigger()) \
    .if_(IsWeekend(), name="check-weekend")
        .then_(WeekendPipeline(), name="weekend")
        .else_(WeekdayPipeline(), name="weekday")
    .end_if() \
    .step(Finalize(), name="finalize") \
    .finish()

⏸ Human-in-the-loop

from moonchild import WaitAction, WaitHint, Field, HintAction, Result

class ReviewAction(WaitAction):
    def execute(self, ctx):
        ctx["_wait_hint"] = WaitHint(
            title="Review required",
            body="Please review the item below.",
            fields=[Field(key="note", type="textarea", label="Note")],
            actions=[
                HintAction(key="approve", label="Approve", style="success"),
                HintAction(key="reject",  label="Reject",  style="danger"),
            ],
        ).to_dict()
        return Result.next()

    def resume(self, ctx, input):
        ctx["decision"] = input.get("action")
        if ctx["decision"] == "reject":
            return Result.goto("fetch")
        return Result.next()

The dashboard renders the form automatically — no frontend code needed.

For simple prompts use the built-in:

from moonchild import PromptWaitAction

.step(PromptWaitAction("What is your name?", key="name"), name="ask")

⏰ Triggers

from moonchild import ManualTrigger, CronTrigger

ManualTrigger()              # start from UI or API
CronTrigger("*/5 * * * *")  # every 5 minutes
CronTrigger("0 9 * * 1-5")  # 9am weekdays

⚙️ Configuration

Moonchild.configure(
    db_path="./data/moonchild.json",
    host="0.0.0.0",
    port=8000,
)
Moonchild.start()

🌐 REST API

Method Path Description
GET /api/workflows List registered workflow IDs
POST /api/workflows/{id}/run Start a new run (202 Accepted)
GET /api/runs List all runs
GET /api/runs/{id} Get a single run
POST /api/runs/{id}/resume Resume a waiting run
WS /ws Real-time run updates

📁 Project layout

your-project/
├── app.py              # entry point
├── workflows/
│   ├── billing.py
│   ├── onboarding.py
│   └── reports.py
└── requirements.txt    # moonchild

👾 Tech Stack

  • Python 3.11+
  • FastAPI + Uvicorn
  • TinyDB
  • WebSocket (real-time UI)
  • Vanilla JS + SVG (zero frontend dependencies)

📄 License

GPL-3.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

moonchild-0.2.1.tar.gz (28.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

moonchild-0.2.1-py3-none-any.whl (31.4 kB view details)

Uploaded Python 3

File details

Details for the file moonchild-0.2.1.tar.gz.

File metadata

  • Download URL: moonchild-0.2.1.tar.gz
  • Upload date:
  • Size: 28.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for moonchild-0.2.1.tar.gz
Algorithm Hash digest
SHA256 a82bd556d961719ca1e4de02a3b3e5735b2cfaec583ebdc6d9b7972e88a7ac2d
MD5 07b6566f9446a0bc29afee35b99d06d3
BLAKE2b-256 6759e1a6d247ec1797fe2f6a20fbe7b51d23e41faadaf856e60595f108aae304

See more details on using hashes here.

Provenance

The following attestation bundles were made for moonchild-0.2.1.tar.gz:

Publisher: publish.yml on allybros/moonchild

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file moonchild-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: moonchild-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 31.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for moonchild-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c08b8a826a69faddc2c1b0d7874bf36fef8c8fa1e9b7a5b9c0a72a3ef18cfc35
MD5 bd008b7096342b1d7f54ed9dd236dfeb
BLAKE2b-256 6d4b842baf78a17d32a3bf083c4cde919b96dd6c3cead091050441c287d0db52

See more details on using hashes here.

Provenance

The following attestation bundles were made for moonchild-0.2.1-py3-none-any.whl:

Publisher: publish.yml on allybros/moonchild

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 files

0.2.0

2 files

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