Repository navigation
Expand file tree
/
Copy path.env.example
More file actions
246 lines (227 loc) · 14 KB
/
Copy path.env.example
File metadata and controls
246 lines (227 loc) · 14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# Copy to .env and fill in your values.
# .env is gitignored; this file is not.
# ── OpenProject ───────────────────────────────────────────
# URL of your OpenProject instance
OPENPROJECT_URL=https://community.openproject.org
# API token (My Account → Access Tokens). Read access to work packages is enough
# for `op` and `chat` — except `op wp create`; agent mode also needs permission to
# comment, and the `pd` pipeline additionally needs add-work-packages (it creates
# the FEATURE tree). `@opilot create wp` needs add-work-packages too, plus
# manage-work-package-relations for the link back to the source work package, and
# manage-subtasks when it is asked for subtasks (without the link permissions the
# work packages are still created — only unlinked, or related instead of nested).
OPENPROJECT_TOKEN=your_api_token_here
# ── Repos ─────────────────────────────────────────────────
# The set of product repos opilot fixes is defined in repos.json (name, upstream
# owner/repo, base branch, and a description). The LLM picks which repo(s) a fix
# lands in, per work package. Edit repos.json to add or change repos.
#
# Optional: point the openproject clone at a local checkout to seed a faster
# clone (git clone --reference-if-able … --dissociate). Absent → clones fresh.
# OP_REPO_PATH=../openproject
# ── GitHub ────────────────────────────────────────────────
# The BOT account opilot publishes as — not you. It forks each product repo,
# pushes fix branches to its fork, and opens cross-repo draft PRs; it must NOT be
# a collaborator on the canonical repos (that lack of access is the isolation).
# Classic token, scopes: public_repo, workflow, gist. Fine-grained tokens cannot
# open fork→upstream PRs. Without it nothing can be published.
GITHUB_CONTRIBUTOR_TOKEN=ghp_your_bot_token_here
# ── Behaviour ─────────────────────────────────────────────
# Comma-separated list of OpenProject user ids allowed to trigger the agent via
# @opilot comments (the number in a profile URL, /users/<id> — not emails, since a
# non-admin API token can't read other users' emails).
# If unset or empty, every OpenProject user may trigger the agent — and
# `@opilot create wp` is switched off entirely, because a work package can never
# be deleted and an open trigger would let anyone mint them without limit.
# OPILOT_ALLOWED_OP_USER_IDS=534,557
# Comma-separated GitHub logins allowed to trigger @opilot on a PR (gh-agent).
# If unset or empty, any GitHub user can trigger on opilot's own PRs.
# OPILOT_ALLOWED_GH_USERS=thykel
# Also track the product repos' UPSTREAM PRs, so an @opilot mention on someone
# else's PR gets answered (read-only: opilot replies and can offer GitHub
# suggestions, but has no push access there). Off unless set — this is the only
# thing that makes opilot search outside its own PRs, so enabling it is a
# deliberate spend decision. Requires OPILOT_ALLOWED_GH_USERS as well.
# OPILOT_TRACK_UPSTREAM_PRS=1
# Matrix chat interface: chat with opilot in ONE room (like `./opilot chat`),
# plus the @opilot words with the work package first: `@opilot build #1323`,
# `health #1323`, `grill #1323`, `summarize #1323`, `create wp #1323 <what>`.
# `./opilot agent` runs it when the first three are set; `agent matrix` runs it alone.
# - The URL is the client API address (see https://<server>/.well-known/matrix/client),
# not always the server name in the bot's MXID. From Docker on a Mac, a local
# Synapse is http://host.docker.internal:8008.
# - The token is the bot account's access token.
# - The room must be UNENCRYPTED (opilot cannot read encrypted rooms); the bot
# joins it once by hand. Use the room ID exactly as the server shows it, not an
# alias. Room version 12 IDs have no ":server" part (!Aqc4…), older ones do.
# - The allowlist is REQUIRED: the loop refuses to start without it, because a
# Matrix user reaches everything OPENPROJECT_TOKEN can read, and can `build`
# (a draft PR on the fork) and `create wp`.
# - Every room member reads the answers, and chat reads every local mirror;
# only the prompt keeps internal comments out. Keep membership to people who
# may see those work packages in OpenProject.
# MATRIX_HOMESERVER_URL=http://host.docker.internal:8008
# MATRIX_ACCESS_TOKEN=
# MATRIX_ROOM_ID=!Aqc4uMSr1mIwT2tRgiu9SI6b-EntdwHfyxHwjdWaNx0
# OPILOT_ALLOWED_MATRIX_USERS=@you:localhost
# gh-agent's CI chasing: how many times it will fix one PR's CI before asking for
# a human, and the check names it should not try to fix (comma-separated,
# case-insensitive; "SaaS tests" needs secrets a fork PR cannot have).
# OPILOT_CI_MAX_ATTEMPTS=5
# OPILOT_CI_IGNORE_CHECKS=SaaS tests
# AppSignal (`./opilot appsignal fix <incident-number>`) — turn a production
# error into a work package and a draft PR.
#
# A PERSONAL API token, from your AppSignal personal settings. A narrower MCP
# token is not enough, and that is a finding rather than a preference: the
# REQUEST PAYLOAD that makes an error diagnosable ("Invalid params" — which
# params?) is reachable only through the V2 tracing API, which an MCP token
# cannot read. Holding a narrow token beside a broad one buys nothing, so there
# is one. It can read every app in your organisations.
# APPSIGNAL_API_TOKEN=
#
# Which app to read: AppSignal's 24-character app id, or its name (opilot
# resolves a name to its id; a name used in two environments is refused rather
# than guessed at). Leave it unset once to have opilot list what your token can
# see.
# APPSIGNAL_APP_ID=openproject-production
#
# Where `appsignal fix` creates the work package (identifier or numeric id).
# --project overrides it per run.
# OPILOT_APPSIGNAL_PROJECT=COMMS
#
# NOTE: `appsignal fix` sends production error messages, backtraces AND request
# payloads to the model, so it REFUSES TO RUN unless inference-gw resolves
# OPILOT_INFERENCE_URL (below) to a private address. That refusal is the whole
# reason this integration is allowed to exist.
# Lets the plan/chat/gh-reply phases look up live OpenProject data (a possible
# duplicate ticket, a project/status/type id) through the instance's own MCP
# server, instead of only what opilot has already mirrored to disk. ON BY
# DEFAULT — an instance with no Enterprise MCP server enabled (Administration
# → Artificial Intelligence → MCP) leaves the tools absent, which is a
# normal, quiet state, not an error. Read-only: a small sidecar gateway (mcp-gw)
# allows only eight read-only MCP operations and refuses every write tool the
# instance offers. Set to 0 to turn it off entirely (no `mcp-gw`
# container, no OpenProject MCP tools):
# OPILOT_OP_MCP=0
# How long one LLM run may take, in MINUTES. The tight bound is on IDLE time —
# silence, rearmed on every byte the model writes — because a real
# implementation run streams the whole way and only a wedged one falls quiet.
# The second value is the absolute ceiling under it: the harness runs one call
# at a time, so a run that never finishes blocks every other poll. Raise the
# ceiling for very large fixes — the runner's own read timeout derives itself
# from these two values, so it follows on its own.
# OPILOT_PI_IDLE_TIMEOUT_MIN=5
# OPILOT_PI_MAX_RUN_MIN=45
# ── Product development (`pd`, all optional) ──────────────
# Work-package types the pipeline maps onto: a change becomes one parent, each
# tasks.md section a child. Neither is a stock OpenProject type, and ids differ
# per instance, so both are resolved BY NAME at `pd init`.
# OPILOT_PD_PARENT_TYPE=FEATURE
# OPILOT_PD_CHILD_TYPE=IMPLEMENTATION
# Statuses `pd implement` sets when it starts, and once the draft PR is open.
# Resolved by name (case-insensitively); set empty to skip that transition.
# OPILOT_PD_IMPLEMENTING_STATUS=In progress
# OPILOT_PD_IMPLEMENTED_STATUS=Developed
# ── Models (all optional) ─────────────────────────────────
# Model values carry a provider prefix (<provider>/<model-id>). THE PREFIX IS
# LOAD-BEARING: "openrouter" uses the provider config committed in
# pi-models.json, and any other prefix makes the harness generate one pointing
# at OPILOT_INFERENCE_URL below. There is no separate mode variable, so the two
# can never disagree.
#
# Heavy model for all planning and implementation.
# OPILOT_MODEL_HEAVY=openrouter/anthropic/claude-opus-5.5
# Light model for stateless one-shot passes (e.g. the gh-agent commit subject,
# or a PR description).
# OPILOT_MODEL_LIGHT=openrouter/anthropic/claude-haiku-4.5
#
# Self-hosted instead — pick any prefix you like; it just names the provider.
# `./opilot appsignal` requires this, since it refuses a public endpoint.
# OPILOT_MODEL_HEAVY=local/qwen3.8:27b-mlx
# OPILOT_MODEL_LIGHT=local/qwen3.8:27b-mlx
#
# On a Mac with 32 GB, qwen3.8:27b (~18 GB, or ~20 GB for the -mlx build) fits
# with room for a 64K context. qwen3-coder:30b is the faster trade: a
# mixture-of-experts model activating 3.3B parameters per token, so it generates
# roughly an order of magnitude quicker for somewhat weaker code.
#
# Wire protocol. Only change this for an upstream that is not OpenAI-shaped —
# it is a different axis from the auth header below, and a native Anthropic or
# Google endpoint needs BOTH set.
# One of: openai-completions (default), openai-responses, anthropic-messages,
# google-generative-ai
# OPILOT_MODEL_API=openai-completions
#
# Context window for a self-hosted model. Omit to use pi's default — but do NOT
# omit it for Ollama, whose own default num_ctx is small enough that an agentic
# run silently loses its context. It also costs RAM: on a 32 GB Mac holding a
# ~20 GB model, 64K is the balance, and more needs the GPU wired limit raised
# (sudo sysctl iogpu.wired_limit_mb=28672).
# OPILOT_MODEL_CONTEXT_WINDOW=65536
# Whether that self-hosted model can SEE pictures. opilot mirrors a work
# package's screenshots next to its item.json and the model reads them as
# images — but pi treats a model with no declared image input as text-only and
# drops every one of them, silently, mid-run. Set this for a vision model
# (qwen2.5-vl, llama3.2-vision, gemma3, …). Leave it off for a text-only one:
# claiming vision there makes the upstream reject the request instead.
# Not needed for openrouter/… models — pi's own catalog knows which ones see.
# OPILOT_MODEL_VISION=1
# ── Inference upstream ────────────────────────────────────
# Where inference-gw forwards. Everything reaches the model through that gateway —
# holding the key is only one of its four jobs, and the other three (a fixed
# upstream, an address pinned at boot, a path allowlist) are what keep the
# harness container contained. A keyless self-hosted endpoint still goes
# through it.
#
# Default is OpenRouter, so an existing .env needs no change:
# OPILOT_INFERENCE_URL=https://openrouter.ai/api/v1
# Your own OpenAI-compatible server (vLLM, Ollama, llama.cpp, TGI, LM Studio):
# OPILOT_INFERENCE_URL=http://10.0.0.5:8000/v1
# Ollama running on this machine, from inside the containers:
# OPILOT_INFERENCE_URL=http://host.docker.internal:11434/v1
#
# ── GitHub reads (the GitHub MCP tools) ───────────────────────────────────
# The switch, on both sides — the gateway route and the runner's tool grant.
# OFF unless set, because GitHub is a third party:
# the same reasoning that keeps OPILOT_TRACK_UPSTREAM_PRS off while
# OPILOT_OP_MCP (your own instance) is on.
# OPILOT_GH_MCP=1
#
# The credential is GITHUB_CONTRIBUTOR_TOKEN above — there is no second token
# to create. It can write, but no write is REACHABLE through this route: the
# upstream path is pinned to /readonly and the allowlist holds only read
# operations.
#
# Optional. Defaults to GitHub's own hosted MCP server on its readonly path
# (https://api.githubcopilot.com/mcp/readonly) — readonly is IN THE PATH, which
# a probe confirmed beats a hostile X-MCP-Readonly header. Point it at a locally
# run `github-mcp-server http` instead if you would rather pin the version.
# OPILOT_GH_MCP_URL=
#
# `./opilot appsignal` reads this address back from inference-gw (GET /upstream) and
# refuses to run unless it is loopback, private or link-local — it sends
# production error data to the model, so a public endpoint is not a choice it
# will make for you. The check fails closed.
# The key, if the upstream wants one. Held only by inference-gw and never passed to
# the harness container (which reads untrusted work-package text). Leave empty
# for a server that needs none. Required for OpenRouter — get one at
# https://openrouter.ai/keys
OPILOT_INFERENCE_KEY=sk-or-...
# How to present that key. The default suits OpenAI, OpenRouter, vLLM,
# llama.cpp, TGI, Ollama and LM Studio. Azure OpenAI is the common exception:
# it takes a 32-hex value in an `api-key` header, not a Bearer token.
# Default: OPILOT_INFERENCE_AUTH=Authorization: Bearer {key}
# Azure OpenAI: OPILOT_INFERENCE_AUTH=api-key: {key}
# Anthropic-native: OPILOT_INFERENCE_AUTH=x-api-key: {key}
# (also needs OPILOT_MODEL_API=anthropic-messages)
# Google-native: OPILOT_INFERENCE_AUTH=x-goog-api-key: {key}
# (also needs OPILOT_MODEL_API=google-generative-ai)
# OPILOT_INFERENCE_AUTH=Authorization: Bearer {key}
# ── Harness / Docker ──────────────────────────────────────
# Resource caps on the harness container. The defaults are generous and
# unmeasured — a limit set too low produces OOM-killed runs that look like the
# idle timeout firing. Measure a real `wp build` with `docker stats`, then set
# these to roughly twice the observed peak.
# OPILOT_HARNESS_MEM=4g
# OPILOT_HARNESS_CPUS=2