|
| 1 | +# Durable GitHub → Mastra loop |
| 2 | + |
| 3 | +This is the small control plane we discussed for the webinar. GitHub events are |
| 4 | +recorded in SQLite first and acknowledged quickly. A coordinator then gives |
| 5 | +Mastra at most one implementation slot by default. Consequently, an event that |
| 6 | +arrives while Mastra is working is never used to interrupt the current model |
| 7 | +turn. |
| 8 | + |
| 9 | +For an event concerning the same issue, the coordinator attaches it to the |
| 10 | +existing run's inbox. For a different issue it creates another run, which waits |
| 11 | +for the local implementation slot. GitHub delivery IDs make retries harmless, |
| 12 | +and messages produced by the configured bot are ignored to prevent feedback |
| 13 | +loops. |
| 14 | + |
| 15 | +```mermaid |
| 16 | +flowchart LR |
| 17 | + GH["GitHub event"] --> IN["Durable SQLite inbox"] |
| 18 | + IN --> ROUTE{"Existing run for issue?"} |
| 19 | + ROUTE -->|yes| ATTACH["Attach to its inbox"] |
| 20 | + ROUTE -->|no| QUEUE["Create queued run"] |
| 21 | + ATTACH --> WAIT{"Waiting for human?"} |
| 22 | + WAIT -->|human comment| RESUME["Resume same Mastra run"] |
| 23 | + WAIT -->|currently working| BOUNDARY["Read at safe step boundary"] |
| 24 | + QUEUE --> SLOT["Acquire implementation slot"] |
| 25 | + SLOT --> MASTRA["Mastra workflow"] |
| 26 | + RESUME --> MASTRA |
| 27 | +``` |
| 28 | + |
| 29 | +## Run it locally |
| 30 | + |
| 31 | +Node 24 and pnpm are required. |
| 32 | + |
| 33 | +```sh |
| 34 | +pnpm install |
| 35 | +cp .env.example .env |
| 36 | +pnpm start |
| 37 | +``` |
| 38 | + |
| 39 | +The service listens only on `127.0.0.1:4317`. `GET /health` shows whether an |
| 40 | +implementation occupies the slot, and `GET /runs` shows the durable run state. |
| 41 | +The event database and Mastra's workflow snapshots live separately under |
| 42 | +`.data/`. |
| 43 | + |
| 44 | +The included [GitHub Actions workflow](.github/workflows/local-loop.yml) uses a |
| 45 | +self-hosted runner labelled `local-llm`. That runner opens an outbound |
| 46 | +connection to GitHub, receives the job, and posts the event to the loop service |
| 47 | +on the same machine. Therefore the local machine does not need a public inbound |
| 48 | +port. For a direct GitHub webhook instead, expose the receiver through a secure |
| 49 | +tunnel and set `GITHUB_WEBHOOK_SECRET`; the receiver validates |
| 50 | +`x-hub-signature-256` against the raw body. |
| 51 | + |
| 52 | +## Human decisions |
| 53 | + |
| 54 | +Add the label `needs-human` to an issue to demonstrate suspension. Mastra stores |
| 55 | +the suspended workflow snapshot and the control database marks the run as |
| 56 | +`waiting_human`. A subsequent human issue comment is correlated with that issue |
| 57 | +and resumes the exact Mastra run. Other issues may proceed while this one waits. |
| 58 | + |
| 59 | +## Where Codex fits |
| 60 | + |
| 61 | +The current implementation step deliberately waits for |
| 62 | +`SIMULATED_IMPLEMENTATION_MS`; this makes concurrency behavior deterministic in |
| 63 | +the demo and tests. Replace that delay inside `src/workflow.ts` with the Codex |
| 64 | +goal invocation. The durable inbox, one-writer rule, suspension, and event |
| 65 | +routing stay unchanged. Review agents can then be added after implementation as |
| 66 | +parallel Mastra branches, followed by the manager/consolidation node we designed. |
| 67 | + |
| 68 | +## Verify |
| 69 | + |
| 70 | +```sh |
| 71 | +pnpm typecheck |
| 72 | +pnpm test |
| 73 | +``` |
| 74 | + |
| 75 | +The integration tests cover the critical race: a second delivery arrives while |
| 76 | +the first Mastra run is active, attaches to that run, and does not create a |
| 77 | +second implementation. They also exercise real Mastra suspension and resumption |
| 78 | +from a GitHub comment. |
0 commit comments