Ripul

Help · Working with agents

Trainyard: builds and deploys, in turn

Run several agents on one project and let them all ship, without one breaking another’s build.

7 minute read

Put more than one agent on a project and they soon share more than the code. They deploy the same web app, rebuild the same Mac app and install onto the same iPhone. Two at once, and one breaks the other’s build or relaunches the app the other is testing in. Trainyard runs on your Mac and puts those jobs in order, and your phone shows you the queue.

Trainyard on iPhone, with nothing on the line and five tracks — web, mac-host, ios, ios-sim and testflight — each showing its command and what it last shipped.
Every build and deploy in one placeEach track is a job. Its row says what it last shipped, how long ago, and what it disturbs.

How it works

Track
A job, such as deploying the web app or building the iPhone app. A project keeps its tracks in .ripul/trains.yaml, so everyone working on it shares them.
Train
One run of a track, at a fixed commit. Requests that arrive while a train is forming ride on it, so one deploy serves every agent that asked.
Resource
Something trains disturb and agents use: the phone under test, the simulator, the Mac app every agent runs inside.
Hold
Keeps the trains that would disturb a resource waiting in the yard while you use it. It expires by itself.
Held-back commit
A commit that must not ship yet. Any train carrying it stops before it leaves, so nothing ships around it.

Trainyard also waits for the right moment. A step that interrupts people, such as relaunching the Mac app the agents run inside, waits until the agents using it have finished their turn. iPhone, simulator and TestFlight builds share one lane, so they queue rather than fight over Xcode. Only committed work ships.

Sharing what there is only so much of

Trains are for jobs that go out. Pools are for things on the Mac that only one agent can use at a time. An agent asks for one, is told which it got, and gives it back. If none is free it waits in line. A loan lapses by itself when its holder goes quiet, so a stuck agent cannot keep one.

Simulators
Every simulator on the Mac is in a pool. An agent asks for the kind it needs and gets one of its own, started if it was off. Another agent’s install to that simulator waits.
A local model
Set how many turns a model on your own machine may run at once, so several agents do not swamp it. Today an agent asks for its place; Ripul does not yet take one for it.

The idea behind it

Trainyard is a release train, a practice from engineering teams that ship many times a day. Changes don’t go out one by one: they ride a train that leaves from a known commit and carries everything ready when it formed, and anything that misses it takes the next one. Agents change code faster and more in parallel than people do, so the collisions a train prevents happen far more often, and the practice matters more.

At Etsy, the engineers deploying at the same time form a push train with a designated driver, and take their changes to staging and then to production together. In Etsy’s words, “Everyone in that train must work together for the safe completion of their deployment.” In Trainyard the agents are the passengers and the yard is the driver: it runs the checks and the job, and waits for the agents still working before it does anything that would interrupt them.

Facebook moved facebook.com to pushes from master every few hours, each carrying “tens to hundreds of diffs” and rolled out in stages “so we can stop the push if we find any problems.” Because another push is always coming, “the vast majority of things that would have required a hotfix can simply be committed to master and pushed in the next release.” Trainyard keeps the same habits: a train ships committed work from a fixed commit, a held-back commit stops any train carrying it, and a change that misses one rides the next.

Elsewhere How Etsy Ships Apps

Sasha Friedenberg, Etsy Engineering, 2017. The push train, its driver, and the same thinking applied to app releases.

Elsewhere Rapid release at massive scale

Chuck Rossi, Engineering at Meta, 2017. Batching changes into regular pushes from master, and stopping a push that goes wrong.

Watch it from your phone

Open Trainyard from the sidebar. It shows the yard on the Mac named at the top of the screen; tap the name to switch Mac. It refreshes every few seconds, and you can pull down to refresh.

On the line
Trains running now, and what each is doing: forming, waiting for a resource, running its job, checking it went live, or waiting for agents to finish their turn.
Waiting to board
Requests queued for the next train.
Holds
What is held, by whom, why, and when the hold runs out.
Held-back commits
Commits that cannot ship until someone unblocks them.
Tracks
Every job, with the commit it last shipped and when.
Resources
Whether each is free, held, or in use right now.
Recent
The last trains to finish.
A mac-host train that shipped, asked for by the Appium runner chat. Its run step took 18 seconds; its arrive step waited 4 minutes for the agents to be idle.
One train, step by stepTap a train to see who asked for it and how long each step took. Here the Mac app was built in 18 seconds, then relaunched once the agents using it were idle.

What you can do from the phone

  1. Hold something while you testIn Resources, swipe right on it and tap Hold. Trains that would disturb it wait for 15 minutes, or until you release it.
  2. Release a hold, or unblock a commitSwipe the row in Holds or Held-back commits.
  3. Run a trackIn Tracks, swipe right on it and tap Run. The train runs on the Mac, from its main checkout, and waits for holds like any other.
  4. Skip the waitA train waiting for agents to finish their turn can go now: tap Arrive Now on its row or in its detail. The agents it was waiting for are interrupted, so it asks first.
  5. Cancel a trainSwipe left on it and tap Cancel. It stops at once; anything its job already changed stays changed.
  6. Change a track or a resourceTap it to edit, or use Add Track and Add Resource. Save to the repository to share it with everyone on the project (Ripul commits and pushes the change), or keep it on this Mac only.

From the Mac

Agents use Trainyard through the ripul-train command on the Mac, and you can too. Deploy scripts board their own trains, so an agent asking for a deploy goes through the yard without doing anything special.

ripul-train status
What is on the line, what is held, and what shipped last.
ripul-train request <track> --wait
Ask for a train and wait until it arrives.
ripul-train hold <resource> --reason "…"
Hold for 15 minutes, or set --ttl in minutes. ripul-train release <id> lets go.
ripul-train block <commit> --reason "…"
Hold a commit back. Holding a commit back is done from the Mac; the phone can unblock it.