Skip to content
mmhy2003Public

About

Open-source CI/CD with declarative YAML pipelines, an AI pipeline assistant, embedded Docker/OCI registry, self-hosted Go agents, and RBAC. Built on Next.js, FastAPI, and Celery.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

399 Commits

Folders and files

Repository files navigation

MegooCI

A simpler, modern open-source alternative to Jenkins.

Next.js frontend · FastAPI backend · Celery orchestration · Go build agent

License Python Go Next.js Docker

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.

Features

Core

  • Declarative YAML pipelines — schema-validated megooci.yaml with stages, steps, conditional when, 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, and wait_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-agent Go 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, and pull work 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.paths glob patterns. Browse, download, and manage artifacts from a dedicated /artifacts page or per-build detail view. Configurable retention by age.

Developer Experience

  • 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+K command 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.

Operations & Security

  • 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.

Planned

  • 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)

Getting Started

Prerequisites

Dependency Version
Docker + Compose plugin 24+
Git any
GNU Make (recommended) any (choco install make or scoop install make on Windows)

1. Clone and initialize

git clone https://github.com/megooci/megooci.git
cd megooci
make init          # copies .env.example → .env — edit secrets before proceeding

Edit .env and set at minimum:

  • MEGOOCI_SECRET_KEY — master key for encrypting secrets at rest
  • MEGOOCI_JWT_SECRET — JWT signing key
  • POSTGRES_PASSWORD — database password

2. Start the stack

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-down

In 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.

3. Open the UI

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.

Pipeline Example

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.

Backup and Restore

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-worker and celery-beat services, 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.

Two-Step Verification

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 on localhost. 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.

Running a Self-Hosted Build Agent

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 remove

For 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.

Git Provider Integration

  1. Admin → Integrations — register a GitHub / GitLab / generic Git connection (PAT auth).
  2. Project → Integrations tab — link a repository, copy the webhook URL + secret.
  3. Paste into your provider — MegooCI verifies each delivery with per-provider HMAC (GitHub X-Hub-Signature-256, GitLab X-Gitlab-Token, generic X-MegooCI-Signature).
  4. Pushes trigger builds automatically for matching pipelines.

Delivery history is visible per repository with signature validation status and error details.

Connecting a Coding Agent (MCP)

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.

  1. In Settings → API Tokens, create a token with the Coding agent scope.

  2. Point your agent at {MEGOOCI_PUBLIC_API_URL}/mcp with 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 user makes 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.

Architecture

              ┌──────────────────┐
              │  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

Configuration

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.

Host-Only Development (No Docker Stack)

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 dev

Makefile Reference

Run 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.

Repository Layout

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

Documentation

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Make your changes
  4. Run tests and linting
  5. Submit a pull request

License

Apache-2.0

About

Open-source CI/CD with declarative YAML pipelines, an AI pipeline assistant, embedded Docker/OCI registry, self-hosted Go agents, and RBAC. Built on Next.js, FastAPI, and Celery.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages