logicspike/docs

flow

Vlozi Flows — Vision

A detailed vision document (not a build ticket). Working name: Vlozi Flows. Purpose: capture the idea, the strategy, and the architecture in enough detail that it can be picked up and executed later. Nothing here has been built.


TL;DR

Vlozi has a set of first-party services (blog, newsletter, forms, content engine, chatbot), each already exposed as typed MCP tools. Flows is a light, n8n-style automation layer whose nodes are those services — "when a form is submitted, add the person to my newsletter and send a welcome email." Because the MCP tool descriptors already define { name, inputSchema, permission, route }, the node library is largely generatable from what exists. This is a "finish the bridge" project, not a "build n8n from scratch" project — and it's what turns a bundle of tools into a platform. And because Flows itself exposes an MCP namespace, an AI agent can create automations by chatting, not just run them — the jump from "the AI does a task once" to "the AI builds a machine that runs forever."


The problem

Today each vlozi service is an island. A user who wants "form → newsletter → welcome email" does it by hand, or not at all. The value isn't in any single tool — it's in the glue between them, and that glue doesn't exist. Meanwhile the suite reads as "several marketing tools," not "a system."

What it is

A workflow tool where:

  • Triggers start a flow (a form submission, a schedule, later: a new subscriber, a published post).
  • Actions are steps that call vlozi services (add subscriber, send email, create draft, schedule a post, notify, call a webhook).
  • Mappings carry data between steps ({{trigger.email}} → the subscriber's email).
  • Templates ("recipes") are pre-built flows a user turns on in seconds.

Light by design: linear flows, a handful of nodes, template-first. Not a 400-node beast.


The big idea: one substrate, three faces

The realization worth internalizing — vlozi isn't building features, it's building one typed catalogue of service capabilities and exposing it through three doors:

                         ┌─────────────────────────────┐
                         │   Vlozi service catalogue    │
                         │  (blog · newsletter · forms  │
                         │   · content · chatbot …)     │
                         │   = MCP tool descriptors      │
                         └───────────────┬──────────────┘
              ┌─────────────────┬────────┴────────┬─────────────────┐
              ▼                 ▼                 ▼
        ┌───────────┐     ┌───────────┐     ┌───────────┐
        │ Dashboard │     │    MCP    │     │   FLOWS   │
        │ (humans)  │     │  (agents) │     │(automation)│
        └───────────┘     └───────────┘     └───────────┘

Same engine, three audiences. The strategic consequence: anything that makes a service a cleaner, well-typed tool compounds across all three faces at once. "Vlozi is an AI-native marketing OS" stops being a tagline and becomes literally true in the architecture.

A corollary: the chatbot and Flows want to merge. The chatbot is the natural-language way to author and trigger flows; a flow step can be "ask the LLM." Build them as one action substrate, not two overlapping ones.


The unlock: agents build automations by chatting (Flows MCP)

Flows should expose its own MCP namespace (flow.*: create_flow, list_flows, enable_flow, disable_flow, list_nodes, get_run_history). The moment it does, an AI agent — the chatbot, Claude, any MCP client — can author and manage automations in plain language, not just trigger one-off actions. This is the deepest expression of the "one substrate" idea: the FLOWS face loops back into the MCP face.

Why this is the real payoff, not a nice-to-have:

  • Ephemeral → durable. Today an agent does a task and it's gone when the chat ends. With flow.* it can persist intent: "from now on, every form submission adds the person to my newsletter and pings me." The agent stops being an assistant that does the thing once and becomes an operator that builds the machine that does it forever.
  • Recursive substrate. Flows nodes are MCP tools; flow authoring is also an MCP tool. So the agent uses MCP to compose MCP tools into MCP-triggered automations — literally programming the platform in natural language. The node manifest now serves three consumers at once: the UI (humans), agent-doing (one-off actions), and agent-building (assembling flows). The keystone compounds again.
  • The chatbot becomes the builder. The recipe gallery and canvas become optional sugar; the primary way to create a flow is to describe it. "Anyone who fills my contact form, tag them and send the PDF."

But: persistent + outward-facing = guardrails. An agent creating standing automations that spend credits and email real people is higher-stakes than a one-off call. So:

  • New automations are draft / disabled by default — the agent assembles, the human flips it live.
  • flow.create returns a preview (trigger + steps + mappings + the permissions it needs) for confirmation before it's saved/enabled.
  • flow:create / flow:manage are their own PBAC scopes — not every key/agent can author automations.
  • The create tool validates the assembled flow (node exists, mapping types line up, scopes cover the actions) before persisting — an agent must not save a broken or over-privileged flow.

Why vlozi wins (the moat)

  1. Zero-config first-party nodes. Zapier/Make/n8n require OAuth + rate limits + brittle third-party APIs to connect tools. Every vlozi node is in-tenant: one credit wallet, one permission model, one latency domain, no credentials. The real competitor is "the user copying data between their own tabs."
  2. Retention via switching cost. A user with live cross-service automations can't easily churn — leaving means rebuilding their ops. Point tools cancel easily; a workflow graph does not.
  3. AI-native. Same nodes are MCP tools, so the chatbot can scaffold automations from plain language.
  4. Build native, thin (don't embed n8n/Windmill/Activepieces). Embedding fights our biggest asset — the typed registry — and inherits license baggage. Borrow only React Flow (MIT) for the canvas, later.

How it's sold / pricing

  • Orchestration is ~free; actions cost their normal rate. Don't double-charge: a flow that sends a newsletter already pays the email rate. Selling line: "automations don't cost extra — they run the same actions you'd pay for anyway, automatically."
  • Gate flow count by plan (e.g. free: 2 flows, pro: unlimited). Action credits stay the variable / revenue lever, billed through the existing ledger and visible via the billing namespace.
  • Packaging fork to decide: a standalone "Automations" tab (discoverable but often a ghost town) vs. invisible glue — contextual "when someone submits this form, automatically…" prompts baked into each service's UI at the moment of intent. The invisible approach likely converts far better.

V1 — the wedge

Discipline: one hero trigger, ~5 actions, linear flows, template-first. No branching, loops, or expression language. Build the whole thing to deliver one flow, and let the architecture generalize behind it.

Hero flow (lead capture → nurture):

[Trigger] form.submission.created
   └─▶ [Action] newsletter: add subscriber   (map form.email → subscriber.email)
        └─▶ [Action] newsletter: send "welcome" email

The most universal SMB need, and it spans three services. If a user can turn this on from a template in under 60 seconds, it runs reliably, and they can see the run in history — the entire thesis is validated.

In v1: the form.submission.created trigger (+ optional schedule/cron); ~5 existing actions (add subscriber, send email, create blog draft, schedule content slot, notify/webhook-out); a simple field mapper; a recipe gallery UI; and run history (per-step status — required, not optional).

Out of v1 (later): branching/conditionals, loops, sub-workflows, the drag-and-drop canvas, third-party nodes, an expression language.


Architecture

1. Nodes are generated from the MCP registries. Define a node manifest that extends the existing McpToolDescriptor (@repo/mcp-core) with automation metadata (trigger vs. action, output schema, mappable fields). Single source of truth — adding a tool to MCP near-automatically makes it a node. Source of descriptors: apps/mcp-gateway/src/registries/*.registry.ts + each service's src/mcp/index.ts. This is the keystone; protect it.

2. The event layer is the one genuinely new contract (and the riskiest pre-work). Services today expose actions (pull) but don't emit events (push). Flows needs push.

 service emits {type, tenantId, payload}  ─▶  Cloudflare Queue  ─▶  Dispatcher Worker
                                                                     │ match registered triggers
                                                                     ▼ for this tenant
                                                              start a run per match
 cron  ──────────────────────────────────────────────────────▶  (same dispatcher path)

Forms' existing deliverWebhook path (apps/forms-service) is the template for emitting submission.created. Define the normalized event schema + get forms emitting cleanly first — this foundation gates everything; spike it before the engine.

3. The execution engine = Cloudflare Workflows (preferred) or a Durable Object per run. On trigger, a durable instance walks the steps: resolve mapping → call the service binding (the same internal routes

  • x-gateway-key / x-tenant-id / x-user-permissions headers the gateway already uses) → persist the result → next step. We already have the DO muscle (AnalyticsScheduler DO); CF Workflows gives durable multi-step + retries + sleep for free. Decide Workflows-vs-DO at design time.

4. Storage (own DB, mirroring how forms keeps its own):

  • automations — flow definition: trigger + ordered steps + mappings (JSONB).
  • automation_runs — status, trigger payload, timing.
  • automation_run_steps — per-step input/output/status (backs run history).

5. Biggest reuse — factor the dispatch core. The gateway's callTool (apps/mcp-gateway/src/server.ts: resolveBinding → forward headers → read {data,error}) is what an action step does. Extract that into a shared package consumed by both the gateway and the engine — don't duplicate it. Also reuse CreditLedger (@repo/core-billing) for action charges and PBAC scopes (@repo/core-access) for run authorization.


Roadmap (build order — each phase independently demoable)

  1. Event contract spike — normalized event schema + forms emits submission.created to a Queue. (de-risks everything)
  2. Node manifest layer over the MCP registries.
  3. Run engine (CF Workflow/DO) executing a hardcoded hero flow against bindings — demo with no UI.
  4. Dispatcher + trigger registration — real form.submission.created starts real runs.
  5. Storage + run history.
  6. Recipe gallery UI (templates + field mapper) — first user-facing slice.
  7. Custom flow builder — linear list first; React Flow canvas as a later v2.

Observability is v1, not v2

An automation that silently fails is worse than none — it breaks trust and creates a support nightmare. Run history + "your flow broke" alerts are what make people depend on it. Pull this earlier than instinct says.

Risks & open questions

  • Scope creep — the #1 killer. Hold the "ship one template" line.
  • Event emission across services — the real foundation; uneven today.
  • CF Workflows vs. Durable Object for the engine.
  • Run authorization — owner scopes vs. a dedicated flow-scoped key.
  • Metering edges — confirm "orchestration free, actions normal" holds once flows fan out.
  • Packaging — standalone tab vs. invisible in-context glue.
  • Naming — "Vlozi Flows" vs. "Automations" vs. "Recipes".
  • Agent-authored flows — draft-by-default + preview/confirm + flow:create scope + validation; never let an agent silently enable an outward-facing automation.
  • Roadmap room — what gets deferred to clear space for the next big rock.

Appendix — likely starter node set (all already exist as MCP tools)

  • Triggers: form.submission.created, schedule (cron). Later: subscriber.added, post.published, slot.published.
  • Actions: newsletter add-subscriber, newsletter/email send, blog create-draft, content schedule-slot, notify / outbound webhook. Later: chatbot/LLM step, conditional, delay.
  • Flows MCP (flow.*): list_nodes, create_flow (draft-by-default, returns a preview), list_flows, enable_flow, disable_flow, get_run_history — lets agents author and manage automations conversationally, gated by flow:create / flow:manage scopes.
flow