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.
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
.
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.
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.
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 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.
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.
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.
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.