Archived
make webhook
This commit is contained in:
@@ -1,325 +1,211 @@
|
||||
# Olixero CI Agents
|
||||
# Olixero Agent Server
|
||||
|
||||
This directory contains the source for a dedicated, Dockerized Gitea runner that uses OpenCode and an OpenAI ChatGPT Pro subscription to plan and implement issues.
|
||||
This repository contains a stateful, webhook-driven Gitea agent server. It plans issues, reviews plans, implements accepted plans, independently reviews diffs, and publishes pull requests without using Gitea Actions or a Gitea runner.
|
||||
|
||||
The runner handles two issue labels:
|
||||
## Architecture
|
||||
|
||||
- `agent:plan`: create a plan, independently review it, revise it up to three times, and publish the accepted plan as one issue comment.
|
||||
- `agent:implement`: read the accepted plan, implement it on a stable branch, independently review and revise the diff up to three times, then create or update a pull request.
|
||||
The deployment has two privilege-separated services:
|
||||
|
||||
The generated pull request is built and tested by the repository's existing PR workflow on a different runner. The credential-bearing agent runner never executes model-modified project code.
|
||||
- `controller` receives signed webhooks and owns the Gitea write token. It claims requests, publishes comments and labels, validates results, pushes branches, and creates pull requests. It does not contain the OpenCode executable or OAuth data.
|
||||
- `executor` owns the Gitea read token and OpenCode OAuth data. It checks out trusted revisions and runs agents. It never receives the Gitea write token or webhook secret.
|
||||
|
||||
Both services share a local SQLite database and disposable workspaces. SQLite runs in WAL mode, so the shared state directory must be on a local filesystem rather than NFS or another network filesystem. Execution concurrency is one because OpenAI OAuth refresh tokens can rotate.
|
||||
|
||||
OpenCode conversations are durable:
|
||||
|
||||
- One planner conversation is retained per issue.
|
||||
- One implementer conversation is retained per issue and accepted-plan digest.
|
||||
- Every review iteration uses a fresh reviewer session.
|
||||
- Current Gitea state, repository contents, and stored digests remain authoritative over conversation memory.
|
||||
|
||||
## Triggers
|
||||
|
||||
Existing labels remain supported:
|
||||
|
||||
- `agent:plan`
|
||||
- `agent:implement`
|
||||
|
||||
The controller consumes a trigger label after durably admitting its request. Gitea 1.26 label webhooks expose the resulting label set rather than the exact label that changed, so the controller reconciles current issue state and tracks each claim in SQLite.
|
||||
|
||||
New issue comments can use these commands:
|
||||
|
||||
```text
|
||||
/agent plan [optional instruction]
|
||||
/agent implement [optional instruction]
|
||||
/agent continue [optional instruction]
|
||||
/agent retry [optional instruction]
|
||||
/agent cancel
|
||||
/agent status
|
||||
```
|
||||
|
||||
Commands must begin the comment and are processed only on comment creation. Pull-request comments, command edits, bot comments, unauthorized users, and non-command comments are ignored. Ordinary human comments remain part of the issue digest and invalidate stale accepted plans. Agent command comments are control messages and are excluded from that digest.
|
||||
|
||||
## Security Model
|
||||
|
||||
- The runner is dedicated to this workflow and registers only `agentic:host`.
|
||||
- Host mode means jobs execute inside the runner container, not on the physical Docker host.
|
||||
- The Docker socket is not mounted.
|
||||
- OpenCode receives a read-only Gitea token. The Gitea write token exists only in the claim and publish steps, when OpenCode is not running.
|
||||
- All OpenCode agents deny shell commands, subagents, interactive questions, and external-directory access.
|
||||
- The implementation agent cannot edit `.gitea`, `.ci-agents`, `.opencode`, `AGENTS.md`, or `.gitmodules`. The publisher validates paths again before committing.
|
||||
- The OpenCode configuration and compiled publisher are baked into `/opt/ci-agents` in the image. Workflows never execute automation code from the checkout.
|
||||
- Runner capacity and workflow concurrency are both one because OpenAI OAuth refresh tokens can rotate.
|
||||
- Issue text, comments, repository files, and web results are treated as untrusted input.
|
||||
|
||||
Do not use this runner for pull-request workflows, arbitrary repositories, or unrelated jobs.
|
||||
|
||||
## Files
|
||||
|
||||
```text
|
||||
.ci-agents/
|
||||
├── Dockerfile Custom Gitea runner image
|
||||
├── compose.yaml Runner and one-shot registration services
|
||||
├── runner-config.yaml Capacity-one host runner configuration
|
||||
├── opencode/ Immutable CI-only OpenCode config and agents
|
||||
├── src/ TypeScript claim/run/publish orchestration
|
||||
├── bin/git-askpass.sh Immutable Git credential helper
|
||||
├── package.json
|
||||
├── package-lock.json
|
||||
└── .env.example
|
||||
|
||||
.gitea/workflows/issue-agents.yml
|
||||
```
|
||||
|
||||
Developers running OpenCode normally do not load `.ci-agents/opencode`. The workflow explicitly selects the image copy with `OPENCODE_CONFIG_DIR=/opt/ci-agents/opencode` while disabling project and external configuration discovery.
|
||||
- Webhooks require `X-Gitea-Signature`, verified as HMAC-SHA256 over the exact request bytes.
|
||||
- The webhook body is limited to 1 MiB and must be JSON.
|
||||
- The configured repository ID and full name must match every payload.
|
||||
- Actor authorization is fail-closed. Numeric Gitea user IDs are preferred over logins.
|
||||
- Webhook deliveries and logical requests are independently deduplicated.
|
||||
- OpenCode receives an explicitly limited tool policy and only the read token.
|
||||
- External Exa and grep.app MCPs are disabled by default to avoid private-repository data leakage.
|
||||
- Repository code is never executed by the credential-bearing services.
|
||||
- Git hooks, signing, global configuration, text conversion, symlinks, unsafe paths, and protected automation paths are blocked or independently validated.
|
||||
- The publisher revalidates the issue digest, accepted plan, default branch, Git metadata, changed files, file types, and remote branch state before writing.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Gitea 1.26 or newer. The current instance was verified as 1.26.4.
|
||||
- Docker Engine with Compose v2, or a compatible Podman deployment.
|
||||
- A repository-scoped Gitea runner registration token. Do not register this credential-bearing runner at organization or instance scope.
|
||||
- A dedicated Gitea account or token with repository read access for OpenCode and Gitea MCP.
|
||||
- An OpenAI account with an active ChatGPT Pro subscription.
|
||||
- Outbound HTTPS access to OpenAI, Gitea, Exa, `mcp.grep.app`, npm, Docker Hub, and `gitea.com` while building.
|
||||
- Gitea 1.26 or newer.
|
||||
- Docker Engine with Compose v2, or compatible Podman tooling.
|
||||
- A dedicated bot account with a repository-scoped write token.
|
||||
- A separate read-only Gitea token for the executor and Gitea MCP.
|
||||
- An OpenAI account usable by OpenCode.
|
||||
- A reverse proxy providing HTTPS to the controller.
|
||||
|
||||
The image pins:
|
||||
The images pin OpenCode CLI and SDK 1.17.18 and Gitea MCP 1.3.0.
|
||||
|
||||
- Gitea Runner `1.0.8`
|
||||
- OpenCode CLI and SDK `1.17.18`
|
||||
- Gitea MCP `1.3.0`
|
||||
- Node.js 24 from the pinned runner's Alpine base (Node.js 22 is used to compile the TypeScript bundle)
|
||||
## Configuration
|
||||
|
||||
## 1. Prepare Configuration
|
||||
|
||||
Run from root:
|
||||
Create the environment file and state directories:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
cp deploy/.env.example deploy/.env
|
||||
sudo install -d -o 10001 -g 10001 -m 0700 \
|
||||
/srv/olixero-agent/state \
|
||||
/srv/olixero-agent/workspaces \
|
||||
/srv/olixero-agent/opencode \
|
||||
/srv/olixero-agent/cache
|
||||
```
|
||||
|
||||
Edit `.env`:
|
||||
Set `GITEA_SERVER_URL`, `GITEA_REPOSITORY`, and `CI_AGENT_BOT_LOGIN` in `.env`. Configure at least one actor allowlist:
|
||||
|
||||
```dotenv
|
||||
GITEA_INSTANCE_URL=https://git.krtss.de
|
||||
GITEA_RUNNER_NAME=olixero-agentic
|
||||
CI_AGENT_IMAGE=olixero-ci-agent-runner:1.0.0
|
||||
RUNNER_DATA_DIR=/srv/olixero-ci-agent/runner
|
||||
OPENCODE_DATA_DIR=/srv/olixero-ci-agent/opencode
|
||||
CACHE_DIR=/srv/olixero-ci-agent/cache
|
||||
RUNNER_TOKEN_FILE=./secrets/runner-token
|
||||
CI_AGENT_ALLOWED_ACTOR_IDS=10,11
|
||||
CI_AGENT_ALLOWED_ACTORS=
|
||||
```
|
||||
|
||||
Create the bind-mount directories for the fixed container identity `10001:10001`:
|
||||
Create local secret files:
|
||||
|
||||
```bash
|
||||
sudo install -d -o 10001 -g 10001 -m 0700 \
|
||||
/srv/olixero-ci-agent/runner \
|
||||
/srv/olixero-ci-agent/opencode \
|
||||
/srv/olixero-ci-agent/cache
|
||||
install -d -m 0700 deploy/secrets
|
||||
install -m 0600 /dev/null deploy/secrets/gitea-write-token
|
||||
install -m 0600 /dev/null deploy/secrets/gitea-read-token
|
||||
install -m 0600 /dev/null deploy/secrets/gitea-webhook-secret
|
||||
```
|
||||
|
||||
Create the temporary registration-token file:
|
||||
Populate them as follows:
|
||||
|
||||
- `gitea-write-token`: bot PAT able to read issues and write comments, labels, branches, and pull requests.
|
||||
- `gitea-read-token`: separate PAT restricted to repository, issue, comment, and pull-request reads.
|
||||
- `gitea-webhook-secret`: a randomly generated webhook secret, for example `openssl rand -hex 32`.
|
||||
|
||||
Local Docker and Podman Compose implementations bind-mount file-backed secrets and may ignore the Compose `uid`, `gid`, and `mode` fields. After populating the files, make them readable only by the container identity:
|
||||
|
||||
```bash
|
||||
install -d -m 0700 secrets
|
||||
install -m 0600 /dev/null secrets/runner-token
|
||||
sudo chown 10001:10001 deploy/secrets/gitea-write-token deploy/secrets/gitea-read-token deploy/secrets/gitea-webhook-secret
|
||||
sudo chmod 0400 deploy/secrets/gitea-write-token deploy/secrets/gitea-read-token deploy/secrets/gitea-webhook-secret
|
||||
```
|
||||
|
||||
Paste one Gitea runner registration token into `secrets/runner-token`. The directory and `.env` are ignored by Git.
|
||||
Do not place tokens directly in `.env`.
|
||||
|
||||
## 2. Build The Runner Image
|
||||
## OpenCode Authentication
|
||||
|
||||
Build the executor and run the interactive login with the persistent OAuth volume:
|
||||
|
||||
```bash
|
||||
docker compose build --pull runner
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml build executor
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml run --rm --no-deps --entrypoint opencode executor \
|
||||
auth login --provider openai --method "ChatGPT Pro/Plus (headless)"
|
||||
```
|
||||
|
||||
The build verifies the official SHA-256 checksum for the architecture-specific Gitea MCP binary. Both `linux/amd64` and `linux/arm64` are supported.
|
||||
|
||||
## 3. Register The Runner Once
|
||||
Verify authentication:
|
||||
|
||||
```bash
|
||||
docker compose --profile register run --rm register
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml run --rm --no-deps --entrypoint opencode executor auth list
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml run --rm --no-deps --entrypoint opencode executor models openai
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml run --rm --no-deps --entrypoint opencode executor \
|
||||
run --model openai/gpt-5.6-sol "Reply with exactly: OPENCODE_AGENT_AUTH_OK"
|
||||
```
|
||||
|
||||
Confirm in Gitea that the runner is online or idle and has exactly this label:
|
||||
OAuth credentials and OpenCode's conversation database remain under `${OPENCODE_DATA_DIR}` and are never mounted into the controller.
|
||||
|
||||
## Gitea Webhook
|
||||
|
||||
Create a repository webhook with:
|
||||
|
||||
- Target URL: `https://agent.example.com/webhooks/gitea`
|
||||
- Content type: `application/json`
|
||||
- Secret: the exact content of `gitea-webhook-secret`
|
||||
- Events: issue label changes and issue comments
|
||||
- Active: enabled
|
||||
|
||||
Gitea's test-delivery button sends a push event rather than an issue event. The server accepts only the configured issue event types, so validate the installation by creating a test issue and adding `agent:plan` or posting `/agent status`.
|
||||
|
||||
The webhook endpoint commits each verified delivery before returning `204`. Gitea 1.26 does not automatically retry failed HTTP deliveries, but manual replay is safe because delivery and business keys are deduplicated separately.
|
||||
|
||||
## Start
|
||||
|
||||
```bash
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml build --pull
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml up -d
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml logs -f controller executor
|
||||
```
|
||||
|
||||
Health endpoints:
|
||||
|
||||
```text
|
||||
agentic:host
|
||||
GET /healthz
|
||||
GET /readyz
|
||||
```
|
||||
|
||||
After successful registration, erase the reusable registration token while leaving the file present for Compose validation:
|
||||
|
||||
```bash
|
||||
: > secrets/runner-token
|
||||
chmod 0600 secrets/runner-token
|
||||
```
|
||||
|
||||
The registration itself persists in `${RUNNER_DATA_DIR}/.runner`.
|
||||
The one-shot registration container runs as root only so it can read the mode-`0600` Compose secret, then changes `.runner` ownership to the daemon identity `10001:10001`. The long-running service remains non-root.
|
||||
|
||||
## 4. Authenticate OpenCode With ChatGPT Pro
|
||||
|
||||
Do this while the runner is stopped or before its first start. The interactive helper uses the same image, UID, environment, and OpenCode data mount as the daemon:
|
||||
|
||||
```bash
|
||||
docker compose run --rm --no-deps \
|
||||
--entrypoint /usr/local/bin/opencode \
|
||||
runner auth login \
|
||||
--provider openai \
|
||||
--method "ChatGPT Pro/Plus (headless)"
|
||||
```
|
||||
|
||||
OpenCode prints a URL and device code:
|
||||
|
||||
```text
|
||||
Go to: https://auth.openai.com/codex/device
|
||||
Enter code: ...
|
||||
Waiting for authorization...
|
||||
```
|
||||
|
||||
Open the URL on another computer, sign in to the intended Pro account, enter the code, approve access, and wait for the container to report success. No browser or inbound callback port is needed on the homelab host.
|
||||
|
||||
The credential is stored on the host at:
|
||||
|
||||
```text
|
||||
${OPENCODE_DATA_DIR}/opencode/auth.json
|
||||
```
|
||||
|
||||
Verify that it is owned by `10001:10001` with mode `0600`:
|
||||
|
||||
```bash
|
||||
sudo stat -c '%u %g %a %n' \
|
||||
/srv/olixero-ci-agent/opencode/opencode/auth.json
|
||||
```
|
||||
|
||||
Verify credential discovery:
|
||||
|
||||
```bash
|
||||
docker compose run --rm --no-deps \
|
||||
--entrypoint /usr/local/bin/opencode \
|
||||
runner auth list
|
||||
```
|
||||
|
||||
List subscription models:
|
||||
|
||||
```bash
|
||||
docker compose run --rm --no-deps \
|
||||
--entrypoint /usr/local/bin/opencode \
|
||||
runner models openai
|
||||
```
|
||||
|
||||
The checked-in agents use `openai/gpt-5.4`. If that model is not listed, update the `model` fields in `opencode/opencode.json` and `opencode/agents/*.md`, rebuild the image, and repeat the smoke test.
|
||||
|
||||
Make one live request:
|
||||
|
||||
```bash
|
||||
docker compose run --rm --no-deps \
|
||||
--entrypoint /usr/local/bin/opencode \
|
||||
runner run --model openai/gpt-5.4 \
|
||||
"Reply with exactly: OPENCODE_CI_AUTH_OK"
|
||||
```
|
||||
|
||||
OpenCode automatically refreshes access tokens and writes rotated refresh tokens back to this mount. Do not restore a static credential before jobs, copy Codex's `~/.codex/auth.json`, or put `auth.json` in Gitea secrets, caches, images, or artifacts.
|
||||
|
||||
To reauthenticate later:
|
||||
|
||||
```bash
|
||||
docker compose stop runner
|
||||
docker compose run --rm --no-deps \
|
||||
--entrypoint /usr/local/bin/opencode \
|
||||
runner auth login \
|
||||
--provider openai \
|
||||
--method "ChatGPT Pro/Plus (headless)"
|
||||
docker compose up -d runner
|
||||
```
|
||||
|
||||
## 5. Configure Gitea Repository Secrets And Variables
|
||||
|
||||
Create a dedicated read-only personal access token for the account used by OpenCode. It needs to read this repository, issues, comments, pull requests, and source. It must not be able to write repository content, comments, labels, or pull requests.
|
||||
|
||||
Create a second token for a dedicated CI bot account. It needs to write repository branches, issue comments and labels, and pull requests. It must be a normal bot PAT rather than Gitea's built-in Actions token: Gitea suppresses workflow triggers caused by its Actions identity, while pull requests created by the normal bot must trigger the separate test workflow.
|
||||
|
||||
Add these repository Actions secrets:
|
||||
|
||||
| Secret | Required | Purpose |
|
||||
|---|---:|---|
|
||||
| `CI_AGENT_READ_TOKEN` | Yes | Read-only Gitea REST, Git fetch, and Gitea MCP access |
|
||||
| `CI_AGENT_WRITE_TOKEN` | Yes | Claim labels/comments, push generated branches, and create or update pull requests |
|
||||
|
||||
The workflow passes `CI_AGENT_WRITE_TOKEN` only to immutable claim and publish code from the runner image. OpenCode receives only `CI_AGENT_READ_TOKEN`.
|
||||
|
||||
Add the repository Actions variable `CI_AGENT_ALLOWED_ACTORS` as a comma-separated list of Gitea logins allowed to trigger agents:
|
||||
|
||||
```text
|
||||
alice,bob
|
||||
```
|
||||
|
||||
If this variable is empty, any user who can add repository labels can trigger an agent run.
|
||||
|
||||
## 6. Create Labels
|
||||
|
||||
Create these repository labels exactly:
|
||||
|
||||
| Label | Required | Behavior |
|
||||
|---|---:|---|
|
||||
| `agent:plan` | Yes | Starts planning and is removed when claimed |
|
||||
| `agent:implement` | Yes | Starts implementation and is removed when claimed |
|
||||
| `agent:generated` | Recommended | Added to generated pull requests when present |
|
||||
| `agent:blocked` | Recommended | Added to issues after a failed run when present |
|
||||
| `agent:plan-ready` | Recommended | Added after an accepted plan when present |
|
||||
|
||||
Optional result labels are best-effort. Their absence does not fail a successful run.
|
||||
|
||||
## 7. Start The Runner
|
||||
|
||||
```bash
|
||||
docker compose up -d runner
|
||||
docker compose logs -f runner
|
||||
```
|
||||
|
||||
The main runner service does not mount the registration-token secret and has no Docker socket. Verify in Gitea that it is attached only to the Olixero repository, not to an organization or the whole instance.
|
||||
By default Compose binds the controller to `127.0.0.1:8080`; expose it through a reverse proxy. Do not expose the executor.
|
||||
|
||||
## Operation
|
||||
|
||||
### Plan an issue
|
||||
Planning creates or resumes the issue's planner conversation. An independent reviewer can request up to three revisions. The accepted plan is published in a protocol-v1 marked comment so plans created by the previous runner remain discoverable.
|
||||
|
||||
1. Create or update an issue with the complete feature requirements.
|
||||
2. Add `agent:plan`.
|
||||
3. The workflow removes the trigger label and maintains one status comment.
|
||||
4. A planning agent creates a plan and an independent reviewer accepts it or requests revisions.
|
||||
5. After at most three review cycles, the accepted plan is persisted in one bot-authored comment with a hidden digest marker.
|
||||
Keep `CI_AGENT_BOT_LOGIN` set to the account that authored existing protocol-v1 plan comments if those plans must remain implementable. Changing bot accounts requires replanning outstanding issues.
|
||||
|
||||
If the issue or default branch changes before publishing, the result is rejected as stale. Re-add `agent:plan`.
|
||||
Implementation requires an accepted plan whose issue digest and base SHA are current. The executor uses a deterministic branch named `agent/issue-<number>-p<digest>`. The controller publishes only after independently validating the reviewed workspace and remote branch state.
|
||||
|
||||
### Implement an accepted plan
|
||||
`/agent cancel` sets a durable cancellation flag. The executor checks it while heartbeating and propagates cancellation into Gitea requests, Git subprocesses, and OpenCode prompts. Interrupted running jobs return to the queue on service restart; interrupted publications remain in the outbox and are retried.
|
||||
|
||||
1. Ensure the issue has an accepted CI-agent plan comment.
|
||||
2. Add `agent:implement`.
|
||||
3. The implementation agent edits a stable branch named `agent/issue-<number>-p<digest>`.
|
||||
4. An independent reviewer accepts the diff or sends it back for revision, up to three cycles.
|
||||
5. The immutable publisher validates paths, commits without hooks, pushes without force, and creates or updates one pull request.
|
||||
6. The normal PR workflow runs build and tests on a runner that has no OpenAI OAuth credential.
|
||||
## Backup And Recovery
|
||||
|
||||
Changing the issue after planning invalidates the accepted plan. Run `agent:plan` again before implementation.
|
||||
|
||||
### Retry a failure
|
||||
|
||||
Inspect the status comment and workflow log, correct the issue, remove `agent:blocked` if desired, and re-add the trigger label. Stable markers, branch names, and PR lookup prevent normal retries from creating duplicate comments or pull requests.
|
||||
|
||||
## Updating The Automation
|
||||
|
||||
All active automation is baked into the image. After changing `.ci-agents`:
|
||||
Back up both application state and OpenCode data. For a simple consistent offline backup:
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
npm run check
|
||||
docker compose build --pull runner
|
||||
docker compose up -d --force-recreate runner
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml stop
|
||||
sudo cp -a /srv/olixero-agent/state /backup/olixero-agent-state
|
||||
sudo cp -a /srv/olixero-agent/opencode /backup/olixero-agent-opencode
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml start
|
||||
```
|
||||
|
||||
Run the npm commands from `.ci-agents`. Increment `CI_AGENT_IMAGE` for deployments where retaining previous images is useful.
|
||||
Workspaces are disposable and do not need backup. If an OpenCode session is unavailable after restore, the executor creates a replacement conversation while retaining durable job and Gitea artifacts.
|
||||
|
||||
Never configure the workflow to execute `.ci-agents/src`, install dependencies from the checkout, or load `.ci-agents/opencode` directly. The image copy is the trust boundary.
|
||||
## Development
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Check the runner:
|
||||
Biome provides formatting, import organization, and static analysis. It enforces four-space indentation; `lint:fix` applies safe fixes, while `lint:fix:unsafe` is available only for explicitly reviewed semantic fixes. The `check` command also enforces the repository limits of three files and four folders per directory and 250 lines per non-test source file.
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
docker compose logs runner
|
||||
npm --prefix app ci
|
||||
npm --prefix app run lint:fix
|
||||
npm --prefix app run check
|
||||
npm --prefix app test
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml config
|
||||
docker compose --env-file deploy/.env -f deploy/compose.yaml build
|
||||
```
|
||||
|
||||
Check OpenCode authentication:
|
||||
Tests cover webhook signatures and command parsing, canonical issue snapshots, delivery deduplication, label claims, job leases, outbox transitions, and restart-safe SQLite state.
|
||||
|
||||
```bash
|
||||
docker compose run --rm --no-deps \
|
||||
--entrypoint /usr/local/bin/opencode \
|
||||
runner auth list
|
||||
```
|
||||
## Cutover From The Runner
|
||||
|
||||
Check MCP startup with the workflow environment available:
|
||||
1. Build and deploy the controller in a non-executing environment and verify health.
|
||||
2. Disable the old Gitea Actions issue workflow and stop the registered agent runner.
|
||||
3. Configure the repository webhook.
|
||||
4. Start the controller and executor.
|
||||
5. Trigger one planning request and verify its status, accepted-plan marker, and durable conversation.
|
||||
6. Trigger implementation and verify branch and pull-request reuse.
|
||||
7. Remove the old runner registration after the rollback window.
|
||||
|
||||
```bash
|
||||
docker compose run --rm --no-deps \
|
||||
-e OPENCODE_CONFIG_DIR=/opt/ci-agents/opencode \
|
||||
-e OPENCODE_DISABLE_PROJECT_CONFIG=true \
|
||||
-e OPENCODE_DISABLE_EXTERNAL_SKILLS=true \
|
||||
-e GITEA_SERVER_URL=https://git.krtss.de \
|
||||
-e GITEA_READ_TOKEN='<read-only-token>' \
|
||||
--entrypoint /usr/local/bin/opencode \
|
||||
runner mcp list
|
||||
```
|
||||
|
||||
Do not place tokens directly in persistent Compose files or shell history. The final command above is diagnostic syntax; prefer a temporary environment file with mode `0600`.
|
||||
|
||||
If OpenCode reports that `ChatGPT Pro/Plus (headless)` is unavailable, confirm the image version, leave default plugins enabled, rebuild, and check the interactive method list with `opencode auth login --provider openai`.
|
||||
Do not run the old workflow and this server against the same trigger labels simultaneously.
|
||||
|
||||
Reference in New Issue
Block a user