Your first pull request

Go from the demo to a real PR

The demo on the install page ran entirely offline. This rung costs three things it didn't: a signed-in agent harness, a provider token (GitHub or Azure DevOps), and a repository with a labelled backlog for the agent to work against.

01

Sign in to a harness

Every agentic stage needs one signed-in coding-agent harness. There are three: GitHub Copilot CLI, Claude Code CLI, or Codex CLI.

npm install -g @anthropic-ai/claude-code
claude auth login

Verify Goobers can see it once you have an instance (below): --check-harness execs the harness CLI directly, in your process's own environment, and prints HARNESS claude-code: OK (or HARNESS copilot: OK, HARNESS codex: OK) once it's installed and signed in.

Codex is the odd one out: it authenticates with an OpenAI API key only, via the agent:model capability (CODEX_API_KEY) — the ChatGPT-login codex login flow is not a supported auth path here. Install it the same way:

npm install -g @openai/codex

It also fails closed on tool policy: a goober whose tools: list is non-empty cannot be seeded with --harness codex, so a shipped tools: [shell] template needs an empty list under Codex. See the Codex harness guide .

02

The minimum token

Pick a provider first — GitHub or Azure DevOps — it decides which token and which connect form below apply.

GitHub. One fine-grained PAT, scoped to the one repository, covers this rung: Contents (read and write), Issues (read and write), Pull requests (read and write), and Actions (read-only — GitHub's fine-grained UI has no separate Checks permission, so this is what lets CI status resolve on a private Actions-only repo). Export it as GOOBERS_GITHUB_TOKEN; one export covers both connecting and seeding below.

Running Copilot headless (no interactive sign-in on this machine) also needs a second, personal PAT with account-level Copilot Requests: Read-only, exported as COPILOT_GITHUB_TOKEN. That one has to be in the process environment directly — the startup preflight execs the harness CLI before any run exists, so a token.env reference in instance.yaml isn't resolved yet at that point; it only reaches a stage's subprocess once a run actually dispatches. Real least-privilege scoping, both identities, and why they end up distinct, is on tokens and permissions.

Azure DevOps. Export a personal access token as GOOBERS_ADO_TOKEN, or use azure-cli, workload-identity, or managed-identity auth instead of a PAT — see tokens and permissions for the full set.

03

Create and connect

The quickstart template's shipped sample needs Node.js 20+ and npm on the same PATH Goobers will use — confirm with node --version / npm --version before materializing it; Goobers preflights the CI executable and fails before claiming any work if it's missing.

goobers onboarding stub-sample --destination ./getting-started-task-api --json
goobers init --template=quickstart ./tutorial-instance

stub-sample writes a disposable Node/npm project; it's non-interactive, safe to re-run, and never creates or pushes a remote itself. Create an empty repository on your provider of choice and push that directory to it — any name, delete it whenever you're done — then point the instance at it.

GitHub:

export GOOBERS_GITHUB_TOKEN=<your token>
goobers connect <owner>/<repo> --seed ./tutorial-instance

Azure DevOps: pick the provider at init time instead of leaving it at the GitHub default, then connect with the three-part organization/project/repository form:

goobers init --template=standard --provider=ado ./tutorial-instance
export GOOBERS_ADO_TOKEN=<your token>
goobers connect <organization>/<project>/<repository> --seed ./tutorial-instance

connect will not convert an already-connected GitHub instance to Azure DevOps (or back) — pick the provider at init and stick with it for that instance. See the noninteractive ADO onboarding guide for the full scaffold.

connect rewrites the template's placeholder your-org/your-repo in instance.yaml and every materialized gaggle, records the token by name only — the value itself never passes through this command, and a value that looks like a pasted token is rejected — and validates the result in-process before touching anything else. --seed idempotently ensures the two label sets the workflow's backlog selector needs actually exist on the repository (without them a run dies at its first park or close-out) and files one starter issue carrying selector labels only. Configuration already pointing at a real repository is left untouched unless you pass --replace.

04

Prove it before you spend anything

goobers validate --check-harness --check-repos ./tutorial-instance

--check-repos resolves the repository's token and verifies authenticated access before a run can claim anything against it — the same failure mode either flag catches here is one you'd otherwise hit mid-run instead. On Azure DevOps, add --strict too:

goobers validate --strict --check-harness --check-repos ./tutorial-instance
05

Run it

goobers run quickstart ./tutorial-instance

This is a real autonomous run against your disposable repository, so it takes noticeably longer than the offline demo: it claims one approved issue, implements it, performs an advisory code review, pushes the run branch, and opens a pull request. Watch it the same way as the demo, goobers dashboard ./tutorial-instance in a second terminal.

06

What the template leaves out

quickstart@v1 is deliberately not production-safe: no CI gates, no remediation loops, no bounded escalation, no merge policy, no issue close-out. The onboarding happy path has no stall points on purpose — production configuration is its own step, past this page.

07

Guided alternatives

goobers init --guided is a first-run-only path toward a regular production instance instead of the disposable sample: it proposes one neighboring Goobers Instance and keeps active configuration and runtime state there, pinning a custom durable location instead with --instance-path <path>. It refuses a target that already has an instance.yaml or a populated config/, so it's safe to attempt and hard to trigger by accident. A separately reviewed configuration source stays an advanced opt-in past this default path.

08

Two things that will bite you

The daemon's PATH is not your interactive shell's — a tool your dotfiles put on PATH can still be invisible to a stage. And if a provider rate limit stalls you, goobers reset-rate-limit clears the hourly run budget without touching runs/ — the instinct to rm -rf the instance instead destroys the run journals along with it.

Next: change what it does, or read what it did. The full ladder, including a checked-in source-tree variant of this template, is in the product repo.