Build Wireflow

KINDAreplaces $24/mosaves $288/yrback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A local visual pipeline runner whose hard problems are never spending money by accident, surviving a restart with in-flight jobs intact, and keeping outputs after the provider's URLs have expired.

estimated effort weekendthe files for this build are in the project pack

FrontendVite with React and React Flow in the same repository as the serverServerExpress with better-sqlite3, no authenticationProviderfal.ai through its queue API, one key in the environmentModelsDeclared in models.json with the path and which fields are ports versus settingsCachingNode outputs keyed by node id plus a hash of resolved inputs

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs both the Vite frontend and the Express server from one repository.

    Get it nodejs.org, or nvm. open ↗

    Verify node --version prints v20 or higher and both dev servers start

  2. API keypay per generation; check the current per-model prices before running a graph

    Why Every generate node costs money at submission, so this is the prerequisite that makes the ceiling work in the last phase meaningful rather than theoretical.

    Get it Create an account, add a key, and fund it with a small amount you are willing to lose while testing. open ↗

    Verify A single image generation submits, completes and returns a result

  3. have readyfree

    Why The cost estimate on the run plan is only useful if the figures behind it are real, and provider prices change without notice.

    Get it Read the provider's pricing for each model path in models.json and record the figure with the date checked.

    Verify models.json carries a price and a checked date for every entry

  4. installfree

    Why Restart recovery, duplicate submission and ceiling behaviour all need a provider you can kill, stall and count calls against, and doing that against the real one costs money each time.

    Get it A small local server implementing submit, status and result with configurable delays.

    Verify The suite can submit, restart the server mid-job and observe recovery

  5. decidefree

    Why They are asserted by tests and they refuse real submissions, so choosing them after an expensive evening means choosing whatever that evening cost.

    Get it Write down the most you are willing to spend in a day and in one run.

    Verify Both appear in the environment and are named in the ceiling tests

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- graphs(id, name, nodes_json, edges_json, updated_at) · autosaved on every canvas change, and autosaving never triggers a run
- nodes(graph_id, node_id, type, settings_json) · type is text, image_import, prompt_template, image_generate, video_generate or preview
- runs(id, graph_id, started_at, finished_at, state, estimated_cost, nodes_executed, nodes_from_cache)
- jobs(id, run_id, node_id, input_hash, provider, model_path, request_id, state, submitted_at, completed_at, error) · request_id is written before the first poll
- outputs(node_id, input_hash, kind, local_path, provider_url, bytes, created_at) · unique on node id and input hash, which is what makes a re-run free
- assets(sha256, path, mime, bytes) · imported images and downloaded results, stored locally because remote URLs expire
- The cache key is the node id plus a hash of its resolved inputs, so changing a prompt three nodes upstream re-executes everything downstream of it and nothing else.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
FAL_KEYsecretrequiredfal-...redactedThe provider key. Server side only; the canvas never sees it.
DATABASE_PATHrequired./data/wireflow.dbGraphs, runs, jobs and outputs.
STORAGE_DIRrequired./storageImported images and downloaded results, stored by content hash.
MODELS_FILErequired./models.jsonModel paths, port definitions and prices with the date each was checked.
DAILY_SPEND_CEILINGrequired5.00Checked before every submission, counting jobs already in flight.
RUN_SPEND_CEILINGrequired1.00Per run. Crossing it stops at the submission that would cross it.
POLL_MAX_SECONDSrequired900How long a job is polled before it is marked as needing manual checking.

The build, in order

  1. A canvas that saves and cannot spend

    The graph edits, autosaves and reloads, and no code path can call the provider yet.

    1. Every change persists; none of them executes anything.

      Files src/canvas/Graph.tsxserver/db/schema.sql

    2. Adding a model must never mean writing a component.

      Files models.jsonsrc/canvas/NodeFromModel.tsx

    3. A dependency test is the cheapest version of this rule.

      Files tests/no-provider-in-ui.test.ts

    done when · tick each as it passes
    watch out
    • Reaching for a reactive graph library that recomputes downstream nodes when an input changes is the natural choice here and it is the one that empties your account, because a generate node is just another computation to it. Keep execution out of the component tree entirely: the canvas edits data, the server executes, and only an explicit request crosses between them.
  2. Running on purpose, and knowing the price first

    Run executes a topologically sorted graph layer by layer, reusing cached outputs, after showing what it will cost.

    1. The difference between a correct cache and a confusing one.

      Files server/run/hash.tstests/cache-invalidation.test.ts

    2. A cycle plus a generate node is an unbounded bill.

      Files server/run/topo.ts

    3. The last moment where the run is still free.

      Files src/run/Plan.tsxmodels.json

    done when · tick each as it passes
    watch out
    • Hashing only a node's own settings means changing a prompt template three nodes upstream leaves every downstream generate node believing it is cached, and you spend an evening wondering why the video still shows the old prompt. Hash the resolved inputs, which include everything upstream, so a change anywhere invalidates exactly the nodes below it and nothing more.
  3. Jobs that survive the server restarting

    A submitted job is recoverable from its identifier alone, from a cold start.

    1. The order is the whole guarantee.

      Files server/provider/submit.tstests/restart-recovery.test.ts

    2. The table is the record; the poller is not.

      Files server/run/resume.ts

    3. Two clicks on run should cost what one costs.

      Files server/run/execute.ts

    done when · tick each as it passes
    watch out
    • Polling in a loop that holds the request identifier only in memory means a restart during a two minute video generation orphans a job you have already paid for, and the only way to find it is the provider's dashboard. Write the identifier first, resume from the table on boot, and treat the in-memory poller as a convenience rather than the record.
  4. Keeping what you paid for

    Every output lives on your disk before the run is called finished.

    1. Complete should mean the bytes are yours.

      Files server/assets/download.tstests/assets.test.ts

    2. Identical outputs cost one copy.

      Files server/assets/store.ts

    3. A preview that hits the provider is a preview that expires.

      Files src/nodes/Preview.tsx

    done when · tick each as it passes
    watch out
    • Storing the provider's URL as the output and rendering previews from it makes a graph look fine for a few days and then quietly fill with broken images, and the run that produced them has already been paid for. Download on completion, store by hash, keep the provider URL only as a note about where it came from, and have the preview fall back to a clear missing-asset state rather than a broken image.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more generative media.