@jules — OpenCode wrapper for Google's async coding agent
Google Jules is a fire-and-forget coding agent: you hand it a GitHub repo + a prompt, it spins up its own Cloud VM, runs bash + tests + Playwright, and opens a PR. The caller polls for completion — no webhooks. The API is alpha, GitHub-only, fully async.
The @jules agent in my OpenCode setup hides every detail of that surface behind a capability-based dispatch contract. Callers (orchestrator, other agents, occasionally me directly) don’t need to know endpoint paths or polling cadences. They name a capability; the agent executes and returns structured markdown.
Capabilities
| Capability | Purpose | Quota cost |
|---|---|---|
setup-check | Verify API key + list connected GitHub sources | 0 |
list-sessions | Recent sessions with state + PR URLs | 0 |
submit-task | Frame a 5-element prompt for manual submission (API is readonly for me) | 0 |
check-status | Poll one session | 0 |
tail-activities | Stream-poll a session until completion | 0 |
send-followup | Mid-flight refinement | 0 |
What I learned building it
- Most public docs lie about which endpoints work. The Jules POST endpoints look documented but return errors on my account. I rebuilt the agent in readonly mode, with the
submit-taskcapability emitting a copy-pasteable 5-element-framed prompt rather than trying to call the API. The agent stayed useful; the API constraint stopped mattering. - Direct HTTP via a small
python3helper beats an MCP wrapper. I almost reached for one of the community MCPs. The agent ended up cleaner with a 250-line stdlib-only helper and zero third-party trust surface. - The hardest part of working with another agent is what you let it post publicly. The companion live-feed Worker (next project) was almost as much code as the agent itself, and most of that code is a secret denylist.
The agent observes Jules sessions in real time and pipes activity into the live feed at the top of this page. You’re likely seeing one right now.