The job graph

Jobs, nodes, edges, fingerprints, staleness, approvals, and the planner that grows a video's graph.

A job is a graph of nodes, run like a build system, that the planner grows as the video takes shape.

Jobs

A job is one thing rapid makes: a video, an empty job for nodes added over the API (rapid new), or one command run through a lane (rapid lane). It has a title, a brief, a project folder, a style and format, an error when its plan failed, and a state:

Job stateWhen
runningsomething is queued or running, or still waiting
needs_youany node waits on you
doneevery node is done
faileda node failed and nothing else can move
cancelledyou cancelled it

Nodes

A node is one unit of work with its own output. Each has a type, a lane, a label, a group (the scene it belongs to), the nodes it needs, its outputs, its state, its attempt count, its timings, and a spec saying what to run.

TypeWhat it does
storyboardan agent writes storyboard.json
scenean agent builds or revises scenes/<id>.html, or builds its key frame
renderrenders a scene to MP4 with its boxes and cues
checkthe code checks, a contact sheet, a micro strip, a key-frame still, or the cut's sheet (rapid video-sheet)
reviewan agent reviews a key frame or a round into marks, or the director judges the storyboard or the video
approvalwaits for you
listenhears the video's track and writes its map (rapid listen)
blenderrenders a shot's key stills, a chunk of its frames, or its clips (rapid shot)
mixmixes the video's sound from the cues, over the track when there is one
muxjoins the scenes, or puts the mix under the picture
phonemakes the phone copy
scan, extract, customother work; custom is what rapid lane runs

A node is either a process node, which runs a command in its lane, or an agent node, which runs a prompt as a Claude Agent SDK session in the project folder, with the plugin's agent types and skills, a limited set of tools, and no permission prompts.

Node stateMeans
waitingsome node it needs isn't done
queuedready, waiting for a slot in its lane
runningin a slot
donemade its outputs
failedits command or session failed; the error is on the node
stalesomething upstream changed; it will run again
needs_youan approval, waiting for you
cancelledits job was cancelled

Edges

Edges are data: a node runs once every node it needs is done. The planner names a node's needs as it adds it, and the graph draws them as edges.

Fingerprints and staleness

A node's fingerprint is a hash of what its output depends on: its type and spec, what each node it reads made, and the engine version. A done node whose fingerprint still matches keeps its output and isn't run again.

When a node finishes with outputs that differ from what it made before, everything downstream of it goes stale. When a stale node's needs are done again, it goes back to done if its fingerprint still matches, and otherwise runs again. So when one scene's render changes, that scene's checks, sheet, and review run again, then the video's last steps, and nothing else.

A fingerprint covers a node's spec and its inputs' outputs, not the files a command reads by itself. After you edit scenes/<id>.html by hand, rapid redo that scene's render node; what depends on it follows.

A node that makes no files (an approval, a check that only passes) hands on its own fingerprint, so a change upstream of it still reaches what comes after.

Approvals

An approval node does no work. When its needs are done it goes to needs_you, and the job with it. rapid approve <node> (or Approve in the pane) completes it, and what waits on it moves on.

Retries

A node that fails for a transient reason (a network error, or an overloaded or rate-limited service) is tried again in the same run, after 5 s and then after 15 s, and each retry is logged as it happens. Any other error fails the node at once.

Redo

rapid redo <node> [--note <text>] runs a node again whatever its fingerprint says. The note is added to the node's spec, and an agent node reads every note in its prompt under "Notes on the last attempt". Whatever was waiting on the old outputs waits again; a cancelled branch comes back with it. A running node can't be redone.

Cancel

rapid cancel <job> stops the job's running nodes and marks it cancelled. A done job can't be cancelled.

The planner grows the graph

A video job starts small. The planner reads the project's files and the graph, and adds whatever comes next. It runs whenever a node in a video job finishes, and once for every running video job when the daemon starts, so a restarted daemon picks up where it was. Adding a node twice does nothing.

a look to finish        finish (agent) → style check → [finish again with its reasons …] → pin in rapid.lock
a track                 listen, before the storyboard
no storyboard.json      storyboard (agent) → [direct (agent) → revise (agent) → direct …] → approve the storyboard
per Blender shot        stills → review (agent) → [revise the recipe → stills …] → frames → clips
per scene, key frame    key (agent) → still → checks → review (agent) or approve (person)
per scene, round n      [build (agent)] → render → check, sheet, micro → [review (agent)]
a round that fails      round n + 1 builds from the review's marks, until the rounds run out
out of rounds           an approval: accept the scene as it is, or redo it
every scene accepted    join → [video sheet → direct (agent)] → mix → mux → phone
the video sent back     the scenes the director names get a round more, then join again

In detail:

  • The look. A video made in a look (--look, look in CreateFilm) starts with it: finish the look t<n> (agent rapid-extractor, lane think) finishes the draft without a person (a face that isn't installed gets a stand-in, noted in taste.md), then check the look t<n> (rapid style check --write --out .rapid/look-<k>-t<n>.checks.json). A check that fails sends its reasons to another finish, three tries in all; then the job fails with them. A check that passes is followed by pin the look (rapid style use --look), and nothing else is planned until it is pinned. A look rapid.lock already pins as it is (a replan, or a later video in the same look) is not finished again; one that changed since its pin is, under keys of its own.
  • The storyboard. If storyboard.json is missing, a storyboard node (agent rapid-storyboarder, lane think) writes it, and an approval follows. Nothing else is planned until you approve it.
  • The track. A video with --music (music in CreateFilm) starts with hear the track (a listen node, lane cpu), which writes the map the storyboarder reads. With no director, a storyboard that misses the beat goes back once to be cut to it. See music.
  • Directing the storyboard. With --review agent and --director agent (the defaults), a direct the storyboard d<n> node (agent rapid-director, lane think) judges the plan first and writes reviews/storyboard-d<n>.json, a Direction: the hook, the rhythm, each scene's move, camera, and secondary motion, variation, the redesign of every source section, and generated visuals where photos are thin. On revise, a storyboard v<n+1> node has the storyboarder answer its notes, and the director looks again, three looks in all. Code sends the plan back too, whatever the director said, while a scene names no primary move, camera, layout slot, scale, or transition out, has nothing alive while it holds, or shares its layout, primary move, or camera move with the scene before it; and while the plan is thin: a scene with no picture and no generated visual (a ground behind more than a third of the scenes doesn't count) that isn't the video's one breath, fewer than half the scenes with a visual where photos and clips are fewer than half the scenes, a screenshot of the source shown as it is, a scene showing the source's interface that no redesign names, or a key frame that doesn't say what fills its lower half (key.lower). The approval waits on the last look; with --stops none there is no approval, and the scenes wait on the last look instead.
  • Shots. Each shot in the storyboard's shots renders once the storyboard is settled: stills in the gpu lane, a review of them, a revised recipe if it's sent back (two tries), its frames in chunks, then its clips. A scene that shows a shot isn't planned until the shot settles, and is built once its clips exist. See Blender shots.
  • Key frames. With --keys agent (the default), a scene built fresh first gets a key node (agent rapid-builder) that writes the scene with its hero complete at meta.key and no motion, then a still node (rapid still --key, writing renders/<id>/key-k<n>.png), then a check node (rapid check --still, writing renders/<id>/key-k<n>.checks.json, every scene but the storyboard's one breath held to 40% empty field whatever its meta's room says), then a review node (agent rapid-reviewer, writing reviews/<id>-k<n>.json), which must answer the checks' marks and read the frame into its frame before its verdict. pass lets the scene move, unless the checks hold a blocker or major or the review never read the frame: then it is a revise; revise makes another try, which builds from the review's marks, three tries in all; a third revise, or needs_you, adds an approval to accept the frame. With --keys person, an approval on the still replaces the review. With --keys off, or --review none under agent, there are no key frames. The first motion build waits for the key frame and is told to keep it.
  • Builds. A scene is built (agent rapid-builder) on round 1 only when its file is missing, you passed --rebuild, or a key frame was built (the motion is still to build), and on every later round.
  • Render, check, sheet, micro. Process nodes in the web lane: rapid render, then rapid check, rapid sheet, and (with agent review) rapid sheet --micro, a strip of frames 0.3 s either side of the key and of every mark the review must answer, side by side.
  • Review. With --review agent, a review node (agent rapid-reviewer, lane think) reads the sheet, the micro strip, the checks, and the previous scene's sheet and writes reviews/<id>-r<n>.json. Its verdict decides: pass accepts the scene; revise starts round n + 1 while rounds remain (4 by default); needs_you, or revise on the last round, adds an approval. A review must list every earlier mark it was handed (the last round's, the key frame review's, or the director's) in answers; a pass that leaves one carried, or leaves one out, counts as a revise. With --review none, a scene whose checks pass is accepted, and one whose checks fail goes straight to an approval.
  • The video. Once every scene is accepted: join the scenes, drawing each hand-off with the transition the storyboard names (out: a cut, or one of the named moves, from a dissolve to a glyph swallow, drawn frame by frame in Chrome from both scenes and overlapping them by its duration). Then, with the director, a video sheet d<n> node (rapid video-sheet, renders/video-d<n>.sheet.png: every scene's first, key, and last frames and each hand-off as a pair) and a direct the video d<n> node writing reviews/video-r<n>.json. Its notes name scenes: each scene a revise names gets one more round (built from the notes, its review answering them), the video joins again, and the director looks again, two looks in all; after the last look's notes are built, the video goes on without another. A person's note after the video (rapid revise, revise_video) or a replan starts the looks afresh, filed as reviews/video-v<n>-r<d>.json or reviews/video-p<n>-r<d>.json. A scene that doesn't converge in a round the director asked for takes its best round like any other, with no stops. Then mix the sound (each scene's cues where its picture starts, overlaps included), the video (the mux), and the phone copy.
  • Stops. --stops (stops in CreateFilm) says which approvals wait for you: all (the default for rapid video and the API), storyboard, or none (the default for new_video). Without a stop, the storyboard goes straight on, and a key frame or a scene that would ask for you takes its best try or round instead: the least-bad verdict (pass, then revise, then needs_you), then the lightest marks (a blocker outweighs any number of nits), the later one on a tie. Its scene file, kept per try (renders/<id>/key-k<n>.html, renders/<id>/r<n>.html), is put back. Each choice is recorded in .rapid/film-<job>.choices.json, and video_status and rapid job name them. --keys person still asks for each key frame.

Keys, joins, and retired nodes

A scene's nodes are keyed by a hash of its storyboard entry. When an entry changes, the scene builds again from its key frame, and the builder is told why. The video's join, mix, mux, and phone copy are keyed by the renders they join, so a scene that passes a late round joins the video again. A node the plan no longer wants (a gate for a round that was redone, or a scene a new storyboard dropped) is retired: it is cancelled and does not count against the job.

rapid replan <job> --note <text> (or POST /api/videos/:job/replan, or the replan_video tool) asks the storyboarder for the storyboard again. The new storyboard waits for approval when the video has stops; scenes whose entries change build again.

rapid revise <job> --note <text> (or POST /api/videos/:job/revise, or the revise_video tool) acts on a note on a video, done or not, and sets its stops to none. A scene and a time add a person's mark and start a run of rounds for that scene alone; a scene alone starts that run with the note; no scene replans. The scene's new rounds are numbered after its earlier ones (a scene that passed in round 1 revises as round 2) and keyed apart from them, so its renders stay and the video joins again.

Watching

Every change is an event in the daemon's SQLite event log. The pane, the screening page, and rapid events all read the same stream. See the HTTP API.