A Python runner that drives the Grok, Kimi Code and Claude Code command-line tools on one machine as a single system. Independent jobs start together and dependent ones form a DAG validated for cycles before anything executes; a done gate checks the artefact and the command rather than the exit code, a cancel reaps every child process group, and a retry reruns only what failed.
Grok, Kimi Code and Claude Code are command-line agents you already have installed and signed in; TrinityRun makes them one machine-local system instead of three terminals. The verbs are small: doctor, one per provider, batch to fan out concurrently from a JSON config, retry to rerun only the failed jobs, and dual, where one provider researches and another implements from the result.
One invariant holds the design: the scheduler, the process runner, the done gate and the run journal contain no provider-specific branches. Every difference between the three tools lives behind one adapter covering command construction, task validation and stream parsing. A fourth model leaves batching, logging, cancellation, verification and retry untouched.
A zero exit code is not success. A job is done only when the provider exited cleanly, every configured artefact exists at or above its declared size, and every verification command passes — argv arrays, never a shell string, with artefacts confined to the job's own directory and symlink escapes rejected. A provider that succeeded while its checks failed returns 3, a distinct outcome instead of a false green. The table is explicit: 0, 1, 2, 3, 124 on timeout, 127 on spawn failure, 130 on interrupt.
Every child spawns into its own POSIX process group under a shared registry, so an interrupt, a timeout and an exceptional exit all reap the entire group and leave no orphan holding a model connection. Adapters parse each CLI's native JSON and never copy raw reasoning text into public events. Run directories are 0700 and every file inside them 0600. Lifecycle events flush immediately, because those are the ones a crash needs written.
One recorded batch sent the same read-only prompt to all three providers: all three started within about two milliseconds and finished at 9.6, 16.7 and 17.4 seconds, so wall time tracked the slowest job instead of the 44-second serial sum. 19 of 19 unit and integration tests pass, on Linux and macOS.