Agent Bot is designed to autonomously manage the entire lifecycle of software development tasks on GitLab/GitHub. It follows a strictly prioritized workflow to ensure existing work is maintained before starting new tasks.
The bot operates in two main phases:
Before looking for new work, the bot ensures its existing contributions are healthy. It scans for Merge Requests assigned to it or created by it that need attention:
- Conflict Resolution: If an MR has merge conflicts, the bot merges the target branch and invokes AI to resolve the conflicts.
- Addressing Reviews: If a human reviewer provides feedback, the bot reads the feedback and asks AI to implement the requested changes.
- Fixing Pipelines: If the CI/CD pipeline fails, the bot automatically downloads the failure logs and asks AI to fix the root cause.
Once all existing MRs are healthy, the bot looks for new issues assigned to it:
- It clones the repository and creates a dedicated branch.
- It passes the issue description to AI to implement the feature or fix.
- It automatically handles forking if it doesn't have direct push access to the repository.
- It creates a new Merge Request and assigns itself to it for continued maintenance.
The bot supports multiple AI backends via the Engine configuration:
| Engine | CLI | Authentication |
|---|---|---|
Claude |
claude --dangerously-skip-permissions --print |
API key |
Codex |
codex exec --dangerously-bypass-approvals-and-sandbox |
ChatGPT device login persisted under CODEX_HOME |
When Engine is Claude, you can point it to any Anthropic-compatible API (DeepSeek, Ollama, etc.) via ApiEndpoint.
When Engine is Codex, no OpenAI API key is required. Log in once with a ChatGPT account inside the container and persist /home/bot/.codex. Model is optional: set it to pass --model to Codex, or omit it to use the model selected by Codex and the account configuration. ReasoningEffort optionally passes an explicit model_reasoning_effort override to every Codex invocation.
Configuration follows standard .NET conventions: appsettings.json → environment variables → CLI args. Environment variables use __ as separator.
{
"Servers": [
{
"Provider": "GitLab",
"EndPoint": "https://gitlab.aiursoft.com",
"PushEndPoint": "https://{0}@gitlab.aiursoft.com",
"DisplayName": "Bot",
"UserName": "agent-bot",
"UserEmail": "bot@aiursoft.com",
"ContributionBranch": "users/agent/auto-fix-issue",
"Token": "",
"OnlyUpdate": false
}
],
"AgentBot": {
"Engine": "Claude",
"ReplyLanguage": "En",
"Model": "deepseek-v4-pro",
"ApiKey": "sk-xxx",
"ApiEndpoint": "https://api.deepseek.com/anthropic",
"Reviewer": "senior-dev",
"PlanningModeEnabled": true
}
}| Key | Env var | Required | Description |
|---|---|---|---|
Engine |
AgentBot__Engine |
No | AI backend: Codex (default) or Claude |
ReplyLanguage |
BOT_REPLY_LANGUAGE |
No | Preferred language for user-facing Issue/MR content: en (default) or zh |
Model |
AgentBot__Model |
No | Optional model name passed to the selected CLI with --model |
ReasoningEffort |
AgentBot__ReasoningEffort |
Codex only | Optional Codex reasoning effort: minimal, low, medium, high, or xhigh |
ApiKey |
AgentBot__ApiKey |
Claude only | API key for the AI provider; not used by Codex |
ApiEndpoint |
AgentBot__ApiEndpoint |
Claude only | Custom API base URL for Anthropic-compatible endpoints |
WorkspaceFolder |
AgentBot__WorkspaceFolder |
No | Temp directory for cloned repos (default: OS temp) |
AiTimeout |
AgentBot__AiTimeout |
No | CLI timeout (default: 00:35:00) |
Reviewer |
AgentBot__Reviewer |
No | GitLab username to auto-assign as reviewer on new MRs (GitLab only) |
PlanningModeEnabled |
AgentBot__PlanningModeEnabled |
No | For Codex + GitLab issues, require an approved plan before implementation (default: true) |
Servers__N__Provider |
Servers__N__Provider |
Yes | Git host: GitLab, GitHub, Gitea |
Servers__N__Token |
Servers__N__Token |
Yes | Personal access token for the git host |
Servers__N__EndPoint |
Servers__N__EndPoint |
Yes | API endpoint URL |
Servers__N__PushEndPoint |
Servers__N__PushEndPoint |
Yes | Git push URL template (use {0} for username placeholder) |
Servers__N__DisplayName |
Servers__N__DisplayName |
Yes | Bot's display name for commits |
Servers__N__UserName |
Servers__N__UserName |
Yes | Bot's username on the git host |
Servers__N__UserEmail |
Servers__N__UserEmail |
Yes | Bot's email for commits |
Servers__N__ContributionBranch |
Servers__N__ContributionBranch |
Yes | Branch name for bot's MRs/PRs |
Server config → Docker env vars:
AgentBot__WorkspaceFolder=/workspace
AgentBot__Engine=Claude
BOT_REPLY_LANGUAGE=zh
AgentBot__Model=deepseek-v4-pro
AgentBot__ApiKey=sk-xxx
AgentBot__Reviewer=senior-dev
AgentBot__PlanningModeEnabled=true
Servers__0__Provider=GitLab
Servers__0__EndPoint=https://gitlab.aiursoft.com
Servers__0__PushEndPoint=https://{0}@gitlab.aiursoft.com
Servers__0__DisplayName=Agent Bot
Servers__0__UserName=agent-bot
Servers__0__UserEmail=bot@aiursoft.com
Servers__0__ContributionBranch=users/agent/auto-fix-issue
Servers__0__Token=glpat-...
With Codex and PlanningModeEnabled=true, normal GitLab issues begin in planning mode. AgentBot posts a versioned plan and discusses it in issue comments. The planning worker can inspect the full checkout and Git history. It runs without Codex's inner sandbox because AgentBot relies on the outer Docker container as its process-isolation boundary. PLANNING_ONLY is a behavioral prompt constraint: the worker is instructed not to edit, commit, push, or open a merge request before approval, but the operating system does not enforce a read-only checkout.
Planning discussion is conversational. Questions, objections, and unresolved choices receive a direct reply without republishing or incrementing the current plan. AgentBot publishes a complete new plan version only after a material product or scope decision is settled. Hidden discussion markers remember which human notes have already been answered, preventing repeated replies across polling cycles and container restarts. The current plan is supplied to Codex once together with only the discussion that followed it, so superseded plans do not accumulate in the prompt.
Set BOT_REPLY_LANGUAGE=zh to make generated plans, Issue replies, merge request descriptions, and code-review comments use Simplified Chinese. The default is en. Values are case-insensitive and may contain surrounding whitespace; any value other than en or zh stops startup with a clear configuration error. This preference affects natural-language output only: code, identifiers, paths, commands, logs, and quoted text remain unchanged. AgentBot:ReplyLanguage may be used in appsettings.json, while the top-level BOT_REPLY_LANGUAGE environment variable takes precedence.
The issue author or the configured Reviewer can approve the current plan with an unambiguous natural-language instruction such as 批准当前计划,开始开发。 or Approve the current plan and start implementation. Quoted examples, conditional approval, comments from other users, and AgentBot's own comments do not approve a plan. Plan and approval state is stored as hidden markers in GitLab comments, so it survives restarts.
After approval, AgentBot starts a separate write-enabled implementation workflow using the approved plan as locked scope. Automatically generated pipeline-recovery issues bypass planning to avoid an unattended approval deadlock. Planning mode currently applies only to Codex on GitLab; other engines and providers retain the existing immediate implementation workflow.
Requirements:
- .NET 10 SDK
- The CLI for the selected AI engine
dotnet tool install --global Aiursoft.AgentBotFor local Codex usage, install the official CLI and log in with ChatGPT:
npm install --global @openai/codex
codex login -c cli_auth_credentials_store=file --device-authagent-botThe container runs silently in the background via cron. No ports exposed.
Create a persistent volume for the Codex login, then start AgentBot. AgentBot__Model and AgentBot__ReasoningEffort are optional and may be removed to use Codex's configured defaults.
docker volume create agent-bot-codex-home
docker run -d \
--name agent-bot \
-e AgentBot__Engine=Codex \
-e BOT_REPLY_LANGUAGE=zh \
-e AgentBot__Model=gpt-5.6-sol \
-e AgentBot__ReasoningEffort=high \
-e AgentBot__WorkspaceFolder=/workspace \
-e Servers__0__Provider=GitLab \
-e Servers__0__EndPoint=https://gitlab.aiursoft.com \
-e Servers__0__PushEndPoint="https://{0}@gitlab.aiursoft.com" \
-e Servers__0__DisplayName="Bot" \
-e Servers__0__UserName=agent-bot \
-e Servers__0__UserEmail=bot@aiursoft.com \
-e Servers__0__ContributionBranch=users/codex/auto-fix-issue \
-e Servers__0__Token=glpat-xxx \
-v agent-bot-codex-home:/home/bot/.codex \
-v agent-bot-workspace:/workspace \
-v agent-bot-logs:/logs \
hub.aiursoft.com/aiursoft/agentbotComplete the one-time device login interactively and verify it:
docker exec -it --user bot agent-bot \
codex login -c cli_auth_credentials_store=file --device-auth
docker exec --user bot agent-bot \
codex login -c cli_auth_credentials_store=file statusThe device login prints a URL and one-time code. Open the URL in a browser, sign in with the ChatGPT account, and enter the code. Device-code login must be enabled in the ChatGPT account security settings or by the ChatGPT workspace administrator. Codex writes the reusable credentials to /home/bot/.codex/auth.json and refreshes them in place. The volume must be protected like a secret.
docker run -d \
--name agent-bot \
-e AgentBot__Engine=Claude \
-e BOT_REPLY_LANGUAGE=zh \
-e AgentBot__Model=deepseek-v4-pro \
-e AgentBot__ApiKey=sk-xxx \
-e AgentBot__ApiEndpoint=https://api.deepseek.com/anthropic \
-e AgentBot__Reviewer=senior-dev \
-e Servers__0__Provider=GitLab \
-e Servers__0__EndPoint=https://gitlab.aiursoft.com \
-e Servers__0__PushEndPoint="https://{0}@gitlab.aiursoft.com" \
-e Servers__0__DisplayName="Bot" \
-e Servers__0__UserName=agent-bot \
-e Servers__0__UserEmail=bot@aiursoft.com \
-e Servers__0__ContributionBranch=users/agent/auto-fix-issue \
-e Servers__0__Token=glpat-xxx \
hub.aiursoft.com/aiursoft/agentbotversion: "3.8"
services:
agent-bot:
image: hub.aiursoft.com/aiursoft/agentbot
restart: unless-stopped
environment:
AgentBot__Engine: Claude
BOT_REPLY_LANGUAGE: zh
AgentBot__Model: deepseek-v4-pro
AgentBot__ApiKey: sk-xxx
AgentBot__ApiEndpoint: https://api.deepseek.com/anthropic
AgentBot__Reviewer: senior-dev
Servers__0__Provider: GitLab
Servers__0__EndPoint: https://gitlab.aiursoft.com
Servers__0__PushEndPoint: "https://{0}@gitlab.aiursoft.com"
Servers__0__DisplayName: Bot
Servers__0__UserName: agent-bot
Servers__0__UserEmail: bot@aiursoft.com
Servers__0__ContributionBranch: users/agent/auto-fix-issue
Servers__0__Token: glpat-xxx
volumes:
- agent-bot-workspace:/workspace
- agent-bot-logs:/logs
volumes:
agent-bot-workspace:
agent-bot-logs:apiVersion: batch/v1
kind: CronJob
metadata:
name: agent-bot
spec:
schedule: "*/5 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: agent-bot
image: hub.aiursoft.com/aiursoft/agentbot
env:
- name: AgentBot__Engine
value: Claude
- name: BOT_REPLY_LANGUAGE
value: zh
- name: AgentBot__Model
value: deepseek-v4-pro
- name: AgentBot__ApiKey
valueFrom:
secretKeyRef:
name: agent-bot-secrets
key: api-key
- name: AgentBot__ApiEndpoint
value: https://api.deepseek.com/anthropic
- name: AgentBot__Reviewer
value: senior-dev
- name: Servers__0__Provider
value: GitLab
- name: Servers__0__EndPoint
value: https://gitlab.aiursoft.com
- name: Servers__0__PushEndPoint
value: "https://{0}@gitlab.aiursoft.com"
- name: Servers__0__DisplayName
value: Bot
- name: Servers__0__UserName
value: agent-bot
- name: Servers__0__UserEmail
value: bot@aiursoft.com
- name: Servers__0__ContributionBranch
value: users/agent/auto-fix-issue
- name: Servers__0__Token
valueFrom:
secretKeyRef:
name: agent-bot-secrets
key: gitlab-token
volumeMounts:
- name: workspace
mountPath: /workspace
- name: logs
mountPath: /logs
volumes:
- name: workspace
emptyDir: {}
- name: logs
emptyDir: {}
restartPolicy: OnFailure
---
apiVersion: v1
kind: Secret
metadata:
name: agent-bot-secrets
type: Opaque
stringData:
api-key: sk-xxx
gitlab-token: glpat-xxxdocker service create \
--name agent-bot \
--restart-condition any \
-e AgentBot__Engine=Claude \
-e BOT_REPLY_LANGUAGE=zh \
-e AgentBot__Model=deepseek-v4-pro \
-e AgentBot__ApiKey=sk-xxx \
-e AgentBot__ApiEndpoint=https://api.deepseek.com/anthropic \
-e AgentBot__Reviewer=senior-dev \
-e Servers__0__Provider=GitLab \
-e Servers__0__EndPoint=https://gitlab.aiursoft.com \
-e Servers__0__PushEndPoint="https://{0}@gitlab.aiursoft.com" \
-e Servers__0__DisplayName="Bot" \
-e Servers__0__UserName=agent-bot \
-e Servers__0__UserEmail=bot@aiursoft.com \
-e Servers__0__ContributionBranch=users/agent/auto-fix-issue \
-e Servers__0__Token=glpat-xxx \
hub.aiursoft.com/aiursoft/agentbot- Open the
.slnfile in the project path. - Press
F5.
There are many ways to contribute to the project: logging bugs, submitting pull requests, reporting issues, and creating suggestions.
Even if you with push rights on the repository, you should create a personal fork and create feature branches there when you need them. This keeps the main repository clean and your workflow cruft out of sight.
We're also interested in your feedback on the future of this project. You can submit a suggestion or feature request through the issue tracker. To make this process more effective, we're asking that these include more information to help define them more clearly.