A simpler, modern open-source alternative to Jenkins.
Next.js frontend · FastAPI backend · Celery orchestration · Go build agent
Getting Started · Features · Architecture · Documentation · Contributing
Most teams use ~20 % of Jenkins' surface area. MegooCI re-implements that 20 % with a modern stack, opinionated defaults, a clean UI, first-class YAML pipelines, and a built-in AI assistant — delivering 80 %+ of the value with a fraction of the complexity and zero plugins to maintain.
- Declarative YAML pipelines — schema-validated
megooci.yamlwith stages, steps, conditionalwhen, and matrix builds. Edited in-browser with a CodeMirror 6 syntax-highlighted editor. - 12 built-in step action types —
run(shell),docker_build,docker_login,docker_push,git_clone,git_pull,git_push,ssh_exec,kube_apply,http_request,wait_webhook, andwait_input. Template interpolation resolves${{ secrets.NAME }}and${{ env.NAME }}at runtime. - AI pipeline assistant — chat-based interface that generates and refines YAML from natural-language prompts. It edits the pipeline with tools, checks the result with the pipeline validator, and shows the change as a diff you apply or discard. Aware of the project's secrets and env vars.
- Remote build agents — self-hosted
megooci-agentGo binary (~15 MB static binary) connects to the controller over an authenticated WebSocket and runs steps on remote hosts. Falls back to local execution when no agent is online. - Embedded OCI / Docker registry — OCI Distribution Spec v1.1 compliant.
docker login,push, andpullwork out of the box. Deploy tokens, anonymous pull, immutable tags, per-project quotas, and automatic garbage collection included. - Build artifacts — collect outputs from pipeline stages via
artifacts.pathsglob patterns. Browse, download, and manage artifacts from a dedicated/artifactspage or per-build detail view. Configurable retention by age.
- Modern UI — cyberpunk-inspired design system built with Next.js 15, React 19, TypeScript, and Tailwind. Three-way theme (Light / Dark / System) with flash-free SSR.
- Live log streaming — terminal-style build log viewer with line numbers, timestamps, stderr coloring, auto-scroll, fullscreen mode, and in-log search (
Ctrl/Cmd+F). - Visual stage graph — status-aware colored stage visualization with clickable navigation and spin animation on running stages.
- Global search — Meilisearch-powered
Cmd/Ctrl+Kcommand palette with instant, typo-tolerant search across projects, pipelines, and builds. - PWA support — installable as a Progressive Web App with service worker, manifest, and app icons.
- Git provider integration — GitHub / GitLab / generic Git with admin-scoped PAT connections, per-project repository linking, and manual-paste webhooks with HMAC verification. Pushes trigger builds automatically.
- RBAC — three system roles (admin, developer, viewer) with granular permissions (
projects,pipelines,builds,artifacts,secrets,agents,registry), scoped user-role assignments, and permission-gated endpoints + UI. - Secrets & environment management — Fernet-encrypted at rest, scoped at global / project / pipeline level, referenced by name (
${{ secrets.X }}), never inlined. Visibility toggles and edit support in the UI. - User invitations — admin-initiated invites with optional SMTP email delivery, configurable expiry, and role pre-assignment.
- Long-lived sessions — 12-hour access tokens with silent refresh up to 30 days.
- Two-step verification — after the password, a code from an authenticator app or a passkey. Recovery codes for a lost device, and a switch for administrators to require it for every account.
- Docker / SSH / Kubernetes executors (agent-side)
- Parallel stages, matrix expansion, parameterized builds
- Notifications (email / Slack / Teams / Discord)
- JUnit / coverage ingestion
- OIDC / SAML / LDAP / API tokens
- Scheduled (cron) pipeline triggers
- Image signing (cosign) + vulnerability scanning (Trivy)
| Dependency | Version |
|---|---|
| Docker + Compose plugin | 24+ |
| Git | any |
| GNU Make (recommended) | any (choco install make or scoop install make on Windows) |
git clone https://github.com/megooci/megooci.git
cd megooci
make init # copies .env.example → .env — edit secrets before proceedingEdit .env and set at minimum:
MEGOOCI_SECRET_KEY— master key for encrypting secrets at restMEGOOCI_JWT_SECRET— JWT signing keyPOSTGRES_PASSWORD— database password
Production
make up # docker compose up -d --build
make logs # tail all container logs
make down # stop (keeps volumes)Development (hot-reload)
make dev # foreground — Ctrl+C to stop
# or
make dev-up # detached
make dev-logs
make dev-downIn dev mode the backend runs with uvicorn --reload, the frontend runs next dev with file polling (reliable on Windows / WSL), and Postgres + Redis are exposed on localhost for direct tool access.
| Service | URL |
|---|---|
| Web UI | http://localhost:3000 |
| API docs (OpenAPI / Swagger) | http://localhost:8000/docs |
| Health check | GET http://localhost:8000/health |
The first user to sign up becomes admin automatically.
version: 1
name: my-app
stages:
- name: test
steps:
- name: unit-tests # optional; shown on the build page
run: npm test
- name: build
steps:
- name: build-image
docker_build:
context: "."
dockerfile: Dockerfile
tags:
- "ghcr.io/org/app:${{ env.VERSION }}"
- name: push-image
docker_push:
tags:
- "ghcr.io/org/app:${{ env.VERSION }}"
artifacts:
paths:
- "dist/*"
- "coverage/report.html"
- name: deploy
when:
branch: main
steps:
- name: approve-deploy
wait_input:
prompt: "Deploy to production?"
timeout: 86400
- name: deploy-app
ssh_exec:
host: deploy.example.com
user: deploy
private_key: ${{ secrets.SSH_KEY }}
commands:
- "cd /opt/app && docker compose pull"
- "docker compose up -d"A step's name is optional. Without one, the build page shows a label built from what the step does, such as npm test, Build app:1.0 or SSH deploy@deploy.example.com. Names are at most 255 characters and may repeat.
To deploy to Kubernetes instead, store a kubeconfig as a secret and use kube_apply — it applies the manifests, then waits for every applied Deployment/StatefulSet/DaemonSet to finish rolling out:
- name: deploy
when:
branch: main
steps:
- kube_apply:
kubeconfig: ${{ secrets.PROD_KUBECONFIG }}
manifests:
- k8s/deployment.yaml
- k8s/service.yaml
namespace: production # optional
context: prod-cluster # optional kubeconfig context
timeout: 300 # optional rollout wait in seconds (default 300)To call an external system — a chat webhook, a deployment or ticketing system, or your own service — use http_request. The payload has no fixed shape: write whatever the receiver expects under json, or use body for any other format.
- name: announce
steps:
- http_request:
url: ${{ secrets.DEPLOY_WEBHOOK_URL }}
headers:
Authorization: Bearer ${{ secrets.DEPLOY_API_TOKEN }}
json:
text: "Build #${{ build.number }} of ${{ pipeline.name }} deployed"
branch: ${{ build.branch }}
retries: 2 # optional; network errors, 5xx and 429 only
expect_status: [200, 202] # optional (default: any 2xx)The request is sent from the build agent, so it can reach systems on the agent's network, and the step fails the build when the status is not the expected one. The URL path, headers and body are never written to the build log; the first 2,000 characters of the response are, so avoid endpoints that return a secret. It needs an agent built from this release or later.
To be told what happens to a pipeline's builds, add a top-level notifications block. The server sends the messages through channels configured under Notification Channels, so they also go out when the build's agent goes offline mid-build:
name: deploy-staging
notifications:
on_start:
- team-chat # a channel name
on_failure:
- channel: ops-email # or a mapping
recipient: oncall@example.com
on_complete:
- team-chat
stages:
- name: deploy
steps:
- run: ./deploy.sh| Event | Sent when |
|---|---|
on_start |
the build starts running |
on_waiting |
the build pauses at a wait_input step and needs approval |
on_success |
the build ends successfully |
on_fixed |
the build succeeds and the last build of the same pipeline and branch that succeeded or failed had failed (cancelled builds are skipped) |
on_failure |
the build fails |
on_cancelled |
a running build is cancelled |
on_complete |
the build ends, whatever the result |
When a build ends, a channel listed under several matching events gets one message, from the most specific event (on_fixed, then on_success, then on_complete; on_failure or on_cancelled, then on_complete). A build that never started sends nothing: one still waiting for an agent stays pending, and one cancelled before it started is not announced.
Without a message, a default is sent with what happened, the pipeline, build number, branch, commit, the step that failed or is waiting, and a link to the build. In a message of your own, ${{ build.status }} is running, success, failed or cancelled. A notify step at the end of a pipeline cannot do this: a build stops at the first failed step.
Link the pipeline to a project whose repository points at your GitHub / GitLab repo — a push triggers the webhook and the pipeline runs on the next available agent.
Administrators can back up and restore the server's configuration under Backups in the sidebar: users, roles, projects, pipelines, secrets, notification channels, git connections, agents, API tokens and system settings. Build history, logs, artifacts and registry images are not part of a backup; back up the megooci_storage and postgres_data volumes for those.
- Passphrase. Set a backup passphrase first. Every backup is encrypted with it, and it is the only way to open one: it cannot be recovered from the server. A backup made on one server can be restored on another, even with a different
MEGOOCI_SECRET_KEY, given the passphrase. - Where backups live. Files are written to
<MEGOOCI_STORAGE_ROOT>/backups/on the storage volume. That disk can be lost with the server, so download the backups you need or turn on the remote copy. - Schedule. Daily or weekly at a time in UTC, keeping the newest N scheduled backups. Needs the
celery-workerandcelery-beatservices, which the default Compose file runs. - Remote copy (optional). Every backup can also be uploaded to S3-compatible storage (AWS S3, MinIO, Backblaze B2, …). Enter the endpoint, bucket and keys, and use Test connection.
- Restore. Turn maintenance mode on, wait for running builds to finish, then choose Restore and type
restore. The configuration becomes exactly what the backup holds: anything created since is removed together with its build history, and the build history of everything that still exists is kept. A backup of the current state is taken first, and the administrator doing the restore keeps their password and access. A backup can only be restored by the release that has the same database version as the one that made it.
Signing in always starts with the password. An account with two-step verification then proves itself a second time, with a 6-digit code from an authenticator app or with a passkey.
-
Turning it on. Under Settings → Two-step verification, set up an authenticator app (Google Authenticator, 1Password, Authy, …), add one or more passkeys, or both. Adding or removing a method asks for your password, and so does changing your email, which is where a password reset goes: a session left open on someone else's screen is not enough to change how you sign in.
-
Recovery codes. Adding your first method gives you ten one-time codes, shown once. Any of them works in place of the second step when you have neither your phone nor a passkey. Generate new ones in Settings at any time; the old ones stop working.
-
Passkeys and the server address. A passkey works only at the address in
MEGOOCI_PUBLIC_URL, over HTTPS or onlocalhost. Opened anywhere else, the app hides the passkey option and says where it works. If that address ever changes, existing passkeys stop working; authenticator and recovery codes do not. -
Requiring it. Administrators turn on Settings → Security → Require two-step verification, after setting it up on their own account. New accounts then set it up before their first sign-in. People already signed in see a notice, and within 12 hours their session ends and the sign-in page takes them through the setup.
-
Someone lost everything. On the Users page, Reset two-step verification removes a user's authenticator app, passkeys and recovery codes; they sign in with their password and set it up again. For an administrator with nobody left to reset them, run this where the backend runs:
docker compose exec backend python -m app.reset_two_step admin@example.com -
docker login. The registry cannot ask for a second step, so an account that uses two-step verification (or must set it up) cannot log in to it with its password. Create an API token under Settings → API tokens, with the Container registry scope for pulling and pushing, and use it as the password. Deploy tokens are unaffected. -
API tokens and MCP work as before, without a second step. A token cannot change how its owner signs in.
-
Backups include two-step verification. Restoring one never changes it for the administrator who runs the restore.
The megooci-agent is a single Go binary that connects to the controller over WebSocket.
# 1. Build the agent image
make agent-image
# 2. In the UI → Agents → Register agent → copy the one-shot token
# 3. Start the agent
make agent-up ID=<agent-uuid> TOKEN=megci_agt_...
# 4. Verify
make agent-logs| Variable | Default | Description |
|---|---|---|
ID |
— | Required. Agent UUID from the UI. |
TOKEN |
— | Required. Registration token. |
CONTROLLER |
http://backend:8000 |
Controller URL (use a public URL when running remotely). |
CAPACITY |
2 |
Max concurrent steps per agent. |
LOG_LEVEL |
info |
debug / info / warn / error |
NETWORK |
megooci_default |
Docker network name. |
NAME |
megooci-agent |
Container name (useful for multi-agent hosts). |
Agent lifecycle:
make agent-logs # tail logs
make agent-restart # restart (preserves CLI args)
make agent-shell # shell into the container
make agent-down # stop and removeFor a host-only run without Docker (requires Go 1.22+):
cd agent && make build
./bin/megooci-agent run --controller ... --agent-id ... --token ...See agent/README.md for the full operator guide.
- Admin → Integrations — register a GitHub / GitLab / generic Git connection (PAT auth).
- Project → Integrations tab — link a repository, copy the webhook URL + secret.
- Paste into your provider — MegooCI verifies each delivery with per-provider HMAC (GitHub
X-Hub-Signature-256, GitLabX-Gitlab-Token, genericX-MegooCI-Signature). - Pushes trigger builds automatically for matching pipelines.
Delivery history is visible per repository with signature validation status and error details.
MegooCI serves a Model Context Protocol endpoint so coding agents can list projects, edit and validate pipelines, trigger builds, and read build logs on your behalf.
-
In Settings → API Tokens, create a token with the Coding agent scope.
-
Point your agent at
{MEGOOCI_PUBLIC_API_URL}/mcpwith the token as a Bearer header. For Claude Code:claude mcp add --transport http --scope user megooci http://localhost:8000/mcp \ --header "Authorization: Bearer <your-token>"--scope usermakes MegooCI available in all your projects, not only the one where you run the command.
Setup for Cursor, VS Code, Codex CLI, Gemini CLI and other clients, the full tool list, and troubleshooting are in docs/mcp-agents.md.
The agent acts as you: it can never do more than your roles and the token's scope allow. Tools take IDs, so an agent first lists or searches, then acts. Cascade deletes are not available to agents; deleting a pipeline together with its build history must be done in the web UI.
If requests to /mcp are answered with 421, a proxy is rewriting the Host header: add that host to MEGOOCI_MCP_ALLOWED_HOSTS.
┌──────────────────┐
│ Next.js 15 UI │ React 19 · TypeScript · Tailwind
└────────┬─────────┘
│ HTTPS + WebSocket
▼
┌──────────────────┐
│ FastAPI backend │ /api/v1/* · /ws/* · /v2/* (OCI)
└──┬───────┬────┬──┘
│ │ │
┌────▼──┐ ┌──▼──┐ ┌▼────────────┐
│ PG │ │Redis│ │ Local FS │ MEGOOCI_STORAGE_ROOT
└───────┘ └──┬──┘ └─────────────┘
│
│ Celery broker + pub/sub
▼
┌──────────────────┐
│ Celery worker │ pipeline execution · registry GC
└────────┬─────────┘
│ WebSocket control plane
▼
┌──────────────────┐
│ megooci-agent │ Go binary on each build host
└──────────────────┘
| Layer | Stack |
|---|---|
| Frontend | Next.js 15 (App Router), React 19, TypeScript, Tailwind 3, TanStack Query, Zustand, CodeMirror 6, Lucide icons |
| Backend | FastAPI, SQLAlchemy 2 (async), Pydantic v2, Celery + Beat, Alembic, Meilisearch. Python 3.12+ |
| Agent | Go 1.22+, Cobra CLI, gorilla/websocket, single static binary (~15 MB) |
| Data | PostgreSQL 16, Redis 7, local filesystem for artifacts / logs / registry blobs |
MegooCI reads all configuration from environment variables. See .env.example for the full list. Key variables:
| Variable | Default | Description |
|---|---|---|
MEGOOCI_SECRET_KEY |
— | Master key for Fernet-encrypting secrets and tokens. |
MEGOOCI_JWT_SECRET |
— | JWT signing key. |
MEGOOCI_JWT_ACCESS_TOKEN_EXPIRE_MINUTES |
720 |
Access-token lifetime (12 h). |
MEGOOCI_JWT_REFRESH_TOKEN_EXPIRE_DAYS |
30 |
Refresh-token lifetime. |
MEGOOCI_SIGNUP_ENABLED |
true |
Public signup toggle. |
MEGOOCI_STORAGE_ROOT |
/var/lib/megooci |
Root folder for artifacts, logs, and registry blobs. |
MEGOOCI_PUBLIC_URL |
http://localhost:3000 |
Public URL of the frontend app (used in invite & password-reset email links). |
MEGOOCI_PUBLIC_API_URL |
http://localhost:8000 |
Externally-reachable backend API URL (webhooks, registry, artifact links, agent controller URL). |
MEGOOCI_MCP_ENABLED |
true |
Serve the MCP endpoint for coding agents at {MEGOOCI_PUBLIC_API_URL}/mcp. |
MEGOOCI_MCP_ALLOWED_HOSTS |
— | Extra Host values the MCP endpoint accepts (comma-separated), for reverse proxies that rewrite Host. |
MEGOOCI_AI_ENABLED |
true |
Enable/disable the AI pipeline assistant. |
MEGOOCI_AI_PROVIDER |
openai |
openai, anthropic, ollama, azure_openai, custom, or disabled. |
MEGOOCI_AI_API_KEY |
— | Provider API key (not needed for ollama). |
MEGOOCI_AI_MODEL |
provider default | Model identifier (e.g. gpt-4o-mini, claude-sonnet-4-5). |
MEGOOCI_AI_BASE_URL |
— | OpenAI-compatible API endpoint. Use custom provider + this URL for vLLM, LiteLLM, LM Studio, etc. All AI settings can also be changed at runtime from Settings → AI Configuration (admin only). |
MEGOOCI_REGISTRY_STORAGE_PATH |
— | Path for OCI registry blob storage. |
MEGOOCI_REGISTRY_MAX_UPLOAD_MB |
— | Max image layer upload size. |
MEGOOCI_ARTIFACT_RETENTION_DAYS |
30 |
Days to retain build artifacts before expiry. |
MEGOOCI_MEILISEARCH_URL |
— | Meilisearch connection URL for global search. |
Run Postgres + Redis in Docker and everything else on your host:
docker compose up db redis -d
# Backend
cd backend
python -m venv .venv
source .venv/bin/activate # .venv\Scripts\Activate.ps1 on Windows
pip install -e .
alembic upgrade head
uvicorn app.main:app --reload --port 8000
# Frontend (second terminal)
cd frontend
npm install
npm run devRun make with no arguments for the full list. Highlights:
| Target | Description |
|---|---|
init |
Create .env from .env.example. |
up / down / logs |
Production stack lifecycle. |
dev / dev-up / dev-down / dev-logs |
Dev stack with hot-reload. |
shell / db-shell / redis-shell |
Open a shell in backend / Postgres / Redis. |
migrate |
Run alembic upgrade head. |
migration m="..." |
Generate a new Alembic migration. |
agent-image |
Build the agent Docker image. |
agent-up ID=.. TOKEN=.. |
Start an agent container. |
agent-down / agent-restart / agent-logs |
Agent lifecycle. |
nuke CONFIRM=yes |
Destructive — drops all volumes (Postgres, Redis, storage). |
For Go-specific targets (build, test, vet, fmt, tidy, snapshot, clean), run make <target> inside agent/ — see agent/Makefile.
megooci/
├── agent/ Go agent binary + Dockerfile
├── backend/ FastAPI app, Celery workers, Alembic migrations
│ ├── app/api/v1/ REST + WebSocket + OCI registry routers
│ ├── app/models/ SQLAlchemy models
│ ├── app/services/ build executor, agent dispatcher, git providers, …
│ └── alembic/versions/ database migrations
├── frontend/ Next.js 15 app
│ ├── src/app/ App Router pages
│ ├── src/components/ UI primitives + pipeline editor + AI panel
│ └── src/lib/ API client, hooks, stores
├── docs/ PRD and documentation
├── docker-compose.yml Production stack
├── docker-compose.dev.yml Dev overrides (hot-reload, bind mounts)
├── Makefile Operator entry point
└── .env.example Configuration reference
- Product Requirements Document — full feature spec, architecture, and implementation status
- Agent Operator Guide — detailed agent setup, configuration, and troubleshooting
- API Reference — auto-generated OpenAPI/Swagger docs (available when the backend is running)
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Make your changes
- Run tests and linting
- Submit a pull request