Install usine, connect a scratch repository, and approve an agent run that opens your first pull request.
This quickstart opens a pull request that adds one sentence to a scratch repository’s README. It uses one local worker, one developer agent, and one loop that waits for your approval. The event-driven coordinator runs each attempt without a parent session, so the developer agent’s harness credential is the only model credential the instance needs.
Prerequisites
Section titled “Prerequisites”Use macOS or Linux with Node.js 22.22 or later, npm, Git, and the GitHub CLI installed. You need a GitHub account that can create a repository and a GitHub App.
You also need one model login or API key. Choose the harness that accepts it:
- Pi: an API key for a provider that Pi supports, such as OpenAI, Anthropic, or OpenRouter; an OpenCode Zen or OpenCode Go key; a ChatGPT subscription through Pi’s OpenAI Codex (legacy) login, the
openai-codexprovider; or an OpenAI-compatible or local endpoint that you add to Pi’smodels.json. Pi’s other account logins aren’t supported, including its OpenAI ChatGPT sign-in, its OpenRouter sign-in, and a Claude subscription. - Claude Code: a Claude subscription, which works only inside Claude Code, or an Anthropic API key.
- Codex: a ChatGPT subscription that includes Codex, or an OpenAI API key.
Subscription usage counts against your plan’s limits. The provider bills API-key usage per token.
Run the commands in the same terminal, as the user who will run usine up. Keep the computer awake while the run is open. The tabs in the following steps show each harness; select the one that matches your credential.
1. Install the CLI
Section titled “1. Install the CLI”npm install --global @usine/serverusine --versionExpected: npm finishes installing, and usine --version prints the installed release number.
2. Install the harness
Section titled “2. Install the harness”usine includes the Pi runtime. Install the Pi CLI to save your credential, then open its terminal interface:
npm install --global --ignore-scripts @earendil-works/pi-coding-agent@1.4.0piIn Pi, enter /login and choose your provider’s API key entry. For a ChatGPT subscription, choose Sign in with an account, then OpenAI Codex (legacy), the openai-codex provider. usine refuses the other entries under Sign in with an account, including OpenAI and OpenRouter. For an OpenAI-compatible or local endpoint, add the provider to ~/.pi/agent/models.json instead. Use /model to select the model, then ask it to reply with ready. Then enter /thinking to list the thinking levels that the selected model supports, and press Escape to close the list.
Expected: Pi replies ready, and /thinking lists at least one level. Note the model’s provider/model ID, such as openrouter/openai/gpt-6-astra or openai-codex/gpt-6-astra, and its levels, then exit Pi with Ctrl+C twice. Pi saves the credential for this user in ~/.pi/agent (or PI_CODING_AGENT_DIR if set). Pi also reads a provider’s key variable, such as OPENROUTER_API_KEY, from the environment of usine up; it doesn’t read the instance .env.
The bootstrap agent in step 4 sets effort: medium. usine refuses an effort that /thinking doesn’t list for the model, even though Pi replies ready here. Many models in Pi’s registry don’t list medium; for those, use one of the listed levels in step 4. A model from models.json lists only off unless its entry sets "reasoning": true. If the model supports reasoning, set "reasoning": true on its entry and check /thinking again. Otherwise, use off.
Install Claude Code:
npm install --global @anthropic-ai/claude-code@2.1.311claude --versionExpected: claude --version prints 2.1.311 (Claude Code). You connect Claude from usine after starting the orchestrator in step 5. On Linux, sign-in from usine also needs the script command from util-linux.
Install the Codex CLI version that usine accepts:
npm install --global @openai/codex@0.164.0codex --versionExpected: codex --version prints codex-cli 0.164.0. You connect ChatGPT or an OpenAI API key from usine after starting the orchestrator in step 5.
3. Create a scratch repository
Section titled “3. Create a scratch repository”Sign in to GitHub, save your login for the commands below, and create a private repository with a README:
gh auth loginexport GITHUB_LOGIN="$(gh api user --jq .login)"gh repo create "$GITHUB_LOGIN/usine-scratch" --private --add-readmeExpected: gh prints the URL of your new usine-scratch repository. Use a new repository so the example loop only sees the issue you create in this quickstart.
4. Create the bootstrap files
Section titled “4. Create the bootstrap files”Create a separate instance folder on persistent storage and write these files. The command substitutes the GitHub login from step 3 into usine.yaml. For Pi, replace the model value with the provider/model ID that you selected in step 2 before you run it. If /thinking didn’t list medium for that model, also replace medium in effort: medium with a level that it listed.
mkdir -p ~/usine-instance/agents ~/usine-instance/projects/scratch/loopscd ~/usine-instanceprintf '.usine/\n.env\n' > .gitignorecat > usine.yaml <<YAMLversion: 2repos: - name: $GITHUB_LOGIN/usine-scratchprojects: - id: scratch name: Scratch repositories: [$GITHUB_LOGIN/usine-scratch]labels: - name: ready-for-agentsettings: coordinator: eventsYAMLcat > agents/developer.md <<'AGENT'---harness: pimodel: openrouter/openai/gpt-6-astraeffort: medium---
Complete one repository task at a time. Follow the repository instructions anddo not merge pull requests. Push every commit before returning your final answer.AGENTcat > projects/scratch/loops/first-pr.md <<'LOOP'---trigger: on: issue if: >- item.state == "OPEN" && item.labels.nodes.exists(label, label.name == "ready-for-agent") && !item.closedByPullRequestsReferences.nodes.exists(pr, pr.state == "OPEN")approval: requiredagent: developer---
Complete issue #{{ item.number }}: {{ item.title }}.
First remove `ready-for-agent` from the issue with `gh issue edit`.Create a branch, make the requested README change, commit it, and push it.Open a non-draft pull request whose body includes `Closes #{{ item.number }}`.Do not merge it. Return the pull request URL.LOOPls agents projects/scratch/loopsmkdir -p ~/usine-instance/agents ~/usine-instance/projects/scratch/loopscd ~/usine-instanceprintf '.usine/\n.env\n' > .gitignorecat > usine.yaml <<YAMLversion: 2repos: - name: $GITHUB_LOGIN/usine-scratchprojects: - id: scratch name: Scratch repositories: [$GITHUB_LOGIN/usine-scratch]labels: - name: ready-for-agentsettings: coordinator: eventsYAMLcat > agents/developer.md <<'AGENT'---harness: claudemodel: sonneteffort: medium---
Complete one repository task at a time. Follow the repository instructions anddo not merge pull requests. Push every commit before returning your final answer.AGENTcat > projects/scratch/loops/first-pr.md <<'LOOP'---trigger: on: issue if: >- item.state == "OPEN" && item.labels.nodes.exists(label, label.name == "ready-for-agent") && !item.closedByPullRequestsReferences.nodes.exists(pr, pr.state == "OPEN")approval: requiredagent: developer---
Complete issue #{{ item.number }}: {{ item.title }}.
First remove `ready-for-agent` from the issue with `gh issue edit`.Create a branch, make the requested README change, commit it, and push it.Open a non-draft pull request whose body includes `Closes #{{ item.number }}`.Do not merge it. Return the pull request URL.LOOPls agents projects/scratch/loopsmkdir -p ~/usine-instance/agents ~/usine-instance/projects/scratch/loopscd ~/usine-instanceprintf '.usine/\n.env\n' > .gitignorecat > usine.yaml <<YAMLversion: 2repos: - name: $GITHUB_LOGIN/usine-scratchprojects: - id: scratch name: Scratch repositories: [$GITHUB_LOGIN/usine-scratch]labels: - name: ready-for-agentsettings: coordinator: eventsYAMLcat > agents/developer.md <<'AGENT'---harness: codexmodel: gpt-6-astraeffort: medium---
Complete one repository task at a time. Follow the repository instructions anddo not merge pull requests. Push every commit before returning your final answer.AGENTcat > projects/scratch/loops/first-pr.md <<'LOOP'---trigger: on: issue if: >- item.state == "OPEN" && item.labels.nodes.exists(label, label.name == "ready-for-agent") && !item.closedByPullRequestsReferences.nodes.exists(pr, pr.state == "OPEN")approval: requiredagent: developer---
Complete issue #{{ item.number }}: {{ item.title }}.
First remove `ready-for-agent` from the issue with `gh issue edit`.Create a branch, make the requested README change, commit it, and push it.Open a non-draft pull request whose body includes `Closes #{{ item.number }}`.Do not merge it. Return the pull request URL.LOOPls agents projects/scratch/loopsExpected: ls lists developer.md under agents and first-pr.md under projects/scratch/loops. The scratch project contains your repository. Omitting workers selects the default local worker, which runs children on this machine as this user.
The tabs differ only in the developer agent’s harness and model, which select the harness from step 2. The effort value must be a level that the model supports; medium works for each tab’s example model. For Pi, /thinking lists those levels, as shown in step 2. For Claude Code, sonnet selects the latest Sonnet model. Use another model ID that the harness accepts if you prefer.
The instance setting coordinator: events selects the event-driven coordinator. It starts one child with the task and turns the child’s report into the attempt’s outcome, so the instance needs no parent model or credential. See Coordinator.
The loop selects open issues labeled ready-for-agent and requires approval. Its task removes that label before changing the README, then opens a pull request that closes the issue. Review the instructions before continuing.
These are bootstrap files: the first start imports them into the configuration database. Later starts read the database. Use configuration editing to save later changes, and keep .usine/ and .env out of Git.
5. Start the orchestrator
Section titled “5. Start the orchestrator”From ~/usine-instance, run:
usine upExpected on the first start:
usine is running in setup mode at http://127.0.0.1:7331The terminal also prints a one-time sign-in link, and the browser opens setup. Open the printed sign-in link to start the temporary setup session. Leave usine up running; use a second terminal for later commands. If the link expires, run usine sign-in-link from ~/usine-instance to generate another.
6. Connect a GitHub App and your credential
Section titled “6. Connect a GitHub App and your credential”The App requires Contents, Issues, Pull requests, and Workflows read and write, with Checks and Metadata read-only. Write-access attempts can push changes under .github/workflows/; read-access tokens omit Workflows and cannot push code. For an existing App, enable Workflows: read and write in its repository permissions and accept the permission update on its installation. Installation checks report workflows:write until the installation grants it.
In the setup screen:
- Enter a unique App name, then select Create App on GitHub and confirm on GitHub. The instance supplies the required permissions and callback URLs.
- After GitHub returns you to setup, select Install App on GitHub. Install it on your account and select only
usine-scratch. - Return to setup and select Check installation. Then select Sign in with GitHub; this sign-in makes you the first instance admin.
Then connect the credential for your harness in Provider connections:
Skip Provider connections. Pi children use the credential that you saved in step 2.
Select Connect Claude. Open the displayed authorization page, sign in with your Claude account, and paste the resulting code into usine. Wait for Connected · Subscription. For an Anthropic API key, select Use an API key instead. On a headless host, run usine login claude from the instance folder in a second terminal.
Local preflight and children use the same CLAUDE_CONFIG_DIR as the orchestrator. Set it before starting usine up when you use a custom credential directory.
Select Connect ChatGPT. Open the displayed sign-in page and enter its device code. Enable device authorization in ChatGPT security settings if required. Wait for Connected · Subscription. For an OpenAI API key, select Use an API key instead. On a headless host, run usine login chatgpt from the instance folder in a second terminal.
usine saves the local worker’s Codex login in ~/.codex/auth.json (CODEX_HOME when set). Local preflight and children use the same CODEX_HOME as the orchestrator; set it before starting usine up when you use a custom credential directory. Local Codex preflight and children use file credential storage, overriding cli_auth_credentials_store in Codex configuration, and ignore keyring credentials. To sign in directly for usine, run codex -c 'cli_auth_credentials_store="file"' login --device-auth.
Finally, select Open usine to activate the runtime. The bootstrap already registered usine-scratch and created the Scratch project.
Expected: the terminal reports usine is running at http://127.0.0.1:7331, and the web UI lists Scratch. The App credentials are saved in .usine/github-app.json. Open Configuration > Loops and confirm that scratch/first-pr is running; select Resume if it is paused.
API-key children report usage in the API keys pool; subscription children use the matching plan pool. Configuration > Settings provides the same connect, replace, and disconnect actions as setup, and usine logout claude or usine logout chatgpt disconnects a local harness.
Setup can resume at /setup if interrupted. See Sign in to an instance for existing App credentials and member access.
7. Create and approve the issue
Section titled “7. Create and approve the issue”In a second terminal, sign in to GitHub if needed and create the issue:
export GITHUB_LOGIN="$(gh api user --jq .login)"gh issue create --repo "$GITHUB_LOGIN/usine-scratch" \ --title "Add a quickstart sentence to the README" \ --body 'Append this sentence to README.md: This repository runs its first usine loop.' \ --label ready-for-agentExpected: gh prints the issue URL. Within the next polling cycle (60 seconds by default), the UI shows a run waiting for approval. In Scratch > Tasks, open the task and its run, review the task text, and select Approve.
The run queues for a worker, then starts an attempt. Follow its messages on the run page. Follow a run explains approvals, transcripts, and recovery if the attempt fails.
8. Review the pull request
Section titled “8. Review the pull request”After the attempt succeeds, open the pull request linked from the run, or list it in the terminal:
gh pr list --repo "$GITHUB_LOGIN/usine-scratch" --state openExpected: one open pull request adds the requested sentence to README.md and includes a closing reference to the issue in its body. Review the diff before merging. The loop does not merge it for you.
To stop the instance after the run finishes, press Ctrl+C in the terminal running usine up. For another task, write a loop or change the agent.