Project Overview

July 28, 2026 · View on GitHub

Meshery is a self-service engineering platform and open source cloud native manager for Kubernetes infrastructure. A CNCF project supporting 300+ integrations with visual GitOps, multi-cluster management, and workspace collaboration.

Repository Structure

DirectoryPurpose
/serverGo backend — REST/GraphQL APIs, Kubernetes management, PostgreSQL
/uiNext.js/React frontend — MUI, Redux Toolkit, Relay GraphQL
/mesheryctlGo CLI with Cobra — install, lifecycle, pattern deployment
/docsHugo documentation site
/installDockerfiles, Kubernetes manifests, Helm charts
/provider-uiProvider-specific React UI extensions
/.githubGitHub Actions, issue templates, Copilot agent definitions

Identifier Naming Conventions — MANDATORY

Authoritative guide: https://github.com/meshery/schemas/blob/master/docs/identifier-naming-contributor-guide.md

Wire is camelCase; DB is snake_case; Go fields follow Go idiom; the ORM layer is the sole translation boundary.

Per-layer canonical forms

LayerForm
DB column / db: tagsnake_caseuser_id, org_id, created_at
Go struct fieldPascalCase with Go initialisms — UserID, OrgID, CreatedAt
JSON tagcamelCasejson:"userId", json:"orgId"
URL query/path paramcamelCase{orgId}, ?userId=...
TypeScript propertycamelCaseresponse.userId
OpenAPI schema propertycamelCase
OpenAPI operationIdlower camelCase verbNoungetWorkspaces
components/schemas type namePascalCaseWorkspacePayload

Forbidden (MUST NOT)

  • MUST NOT use a json: tag matching the db: tag — wire is camel, DB is snake.
  • MUST NOT hand-roll an RTK query endpoint when @meshery/schemas/{mesheryApi,cloudApi} provides one.
  • MUST NOT locally redeclare a Go type with an equivalent in github.com/meshery/schemas/models/....
  • MUST NOT use ID (ALL CAPS) in URL params, JSON tags, or TypeScript properties — use Id.
  • MUST NOT mix casing within a single resource; introduce a new API version to change wire format.
  • MUST NOT import deprecated v1beta1 in new code; use v1beta3 (or v1beta2 where v1beta3 absent).

Required on every PR

  • Run schemas validator: cd ../schemas && make validate-schemas && make consumer-audit
  • Include test updates for casing/tag changes.
  • Include doc updates for user-visible API changes.
  • Sign off commits: git commit -s

meshery/schemas/AGENTS.md is authoritative. On conflicts, schemas wins.

API Changes — MUST Go Through Schemas — MANDATORY

Any new or changed HTTP API (new endpoint, new/renamed query param, new request/response field) MUST be defined in meshery/schemas first and consumed via the generated client. Do NOT hand-roll RTK Query endpoints, response types, or ad-hoc fetch/axios calls for an API that can live in schemas.

Schemas is the single source of truth: one OpenAPI definition drives the Go models, TypeScript types, and the RTK Query client (@meshery/schemas/{mesheryApi,cloudApi}) consumed here. Hand-rolling any of these silently diverges the wire contract across meshery/meshery and meshery-cloud.

Workflow (adding/updating an endpoint)

  1. Define the path + schemas in the matching construct's api.yml (e.g. ../schemas/schemas/constructs/v1beta1/system/api.yml for /api/system/*, .../connection/api.yml for /api/integrations/connections*). Follow the schemas conventions: operationId = lower-camel verbNoun, camelCase wire params/properties, x-internal: ["meshery"] for Meshery-only endpoints, additionalProperties: false, maxLength on strings.
  2. Regenerate in ../schemas: make bundle-openapi generate-rtk generate-golang (or make build for the full dist). Verify the new useXQuery / mesheryApi.endpoints.X hooks appear.
  3. Validate: cd ../schemas && make validate-schemas && make consumer-audit.
  4. Consume the generated hook in the UI (import from @meshery/schemas/mesheryApi; wrap in ui/rtk-query/* only for thin ergonomics like bare-id args or cache tags — never to re-declare the request). Use the generated Go models on the server where applicable.
  5. Release coupling: schemas releases are automated ("do not manually create releases"). Until a new @meshery/schemas is published and this repo's dependency is bumped, a local link is used for development (ui/package.json"@meshery/schemas": "file:../schemas" and the replace github.com/meshery/schemas => ../schemas directive in go.mod). Both the version bump and reverting the local link happen as part of the normal release/upgrade flow — do not commit the local link as the permanent dependency.

Narrow exceptions (still prefer schemas)

  • Server-Sent Events / streaming: RTK codegen can't produce a useful hook for text/event-stream. Still document the endpoint in api.yml, but consume it with a native EventSource client under ui/lib/* (e.g. ui/lib/controllersStatusSubscription.ts).
  • Truly Meshery-internal endpoints with no cross-repo consumer may skip schemas, but must be justified in the PR description.

Forbidden

  • MUST NOT add a builder.query/builder.mutation in ui/rtk-query/* that issues a request to an API which is (or should be) defined in schemas.
  • MUST NOT hand-write response/param TypeScript types or Go structs that duplicate a schemas-generated type.
  • MUST NOT change wire casing/field names only in this repo — change the schema and regenerate (see the naming conventions above).

Build & Development Commands

  • Use the gh-axi CLI tool to interact with GitHub. Prefer gh-axi over gh.
  • Use chrome-devtools-axi for browser automation (navigate, snapshot, click, fill forms, run JS, inspect console/network) in place of raw Playwright/chrome-devtools MCP for ad hoc tasks.
  • Run quota-axi to check local agent-provider quota windows before long-running work.
  • Use the lavish skill (lavish-axi CLI) to turn a plan, comparison, or report into a reviewable HTML artifact.

Server (Go)

make server                    # Run server locally (port 9081)
make server-local              # Run with local provider
make build-server              # Build binary
make golangci                  # Lint Go code
make server-skip-compgen       # Run without Kubernetes components
make server-without-operator   # Run without operator deployment
make error                     # Generate error codes

UI (Next.js/React)

make ui-setup              # Install dependencies
make ui                    # Dev server (port 3000)
make ui-build              # Build and export
make ui-lint               # Lint UI code
make ui-integration-tests  # Run E2E tests

ui/tsconfig.tsbuildinfo is a tracked build artifact that is not gitignored, so any local tsc --noEmit leaves it modified and it has repeatedly been committed by accident. Stage explicit paths rather than git add -A, and git checkout -- ui/tsconfig.tsbuildinfo before committing.

When a change depends on an unreleased @sistent/sistent (or any sibling-repo package), ui/node_modules/@sistent/sistent is often overwritten in place with a locally-built dist. A local test run is then green against code that is not published, and CI fails on the same commit. Re-verify with npm ci after any local sibling build before trusting a green run or declaring a dependency bump done - a local build usually keeps the published version string, so matching versions are not evidence that the installed contents are the published ones. A version mismatch against ui/package.json is a useful tell that this has happened, but a match proves nothing.

CLI (mesheryctl)

cd mesheryctl && make                       # Build binary
cd mesheryctl && go test --short ./...      # Unit tests
cd mesheryctl && go test -run Integration ./...  # Integration tests
make docs-mesheryctl                        # Generate CLI docs

make docs-mesheryctl (i.e. cd mesheryctl/doc && go run doc.go) bakes the machine's $HOME into every generated page's "Options inherited from parent commands" block (the --config default path). Running it locally rewrites all ~100 pages under docs/content/en/reference/references/mesheryctl/ with your local home directory even though only one command changed. CI/committed docs use /home/runner/... (the GitHub Actions runner home). After regenerating, git diff --stat the docs dir, git checkout -- every file whose only change is that path, and manually fix the path back to /home/runner/... in the pages you actually intended to change.

Docker

make docker-build           # Build container
make docker-cloud           # Run with production Remote Provider
make docker-local-cloud     # Run with local Remote Provider

Documentation

make docs        # Run docs site (port 1313)
make docs-build  # Build docs site

API & Helm

make graphql-build  # Build GraphQL schema
make helm-lint      # Lint Helm charts
make helm-docs      # Generate Helm chart docs

Code Style & Conventions

Go

  • Format with gofmt/goimports; lint with make golangci (config: .golangci.yml).
  • Use MeshKit error utilities (github.com/meshery/meshkit/errors); run make error for codes. make error skips mesheryctl - a new mesheryctl code is taken from mesheryctl/helpers/component_info.json (next_error_code) and that value bumped in the same commit. .github/workflows/error-codes-updater.yaml re-runs errorutil and fails the PR if its analysis reports anything.
  • Only utils.Log.Error(err) renders a MeshKit error's code, cause and remediation; cobra's default print shows just the message. In mesheryctl commands, log the structured error for the user and return it for the exit path.
  • Tests in *_test.go; manage deps with go mod tidy.

JavaScript/React

  • ESLint + Prettier (config: ui/.eslintrc.js).
  • Functional components with hooks; no class components.
  • Use @sistent/sistent design system; fall back to MUI.
  • Redux Toolkit for global state; GraphQL via Relay; REST via Axios.
  • Playwright for E2E tests.

Commits

  • Format: [component] descriptive message (e.g., [UI] Add workspace filter dropdown)
  • Sign off: git commit -s
  • Reference issues: Fixes #1234

Architecture

┌──────────────────────────────────────────────────────┐
│                  Meshery UI (Next.js)                │
│   MUI Components │ Redux Toolkit │ Relay + Axios     │
└──────────────────────────┬───────────────────────────┘
                     HTTP/WebSocket
┌──────────────────────────┴───────────────────────────┐
│                 Meshery Server (Go)                  │
│   REST (9081) │ GraphQL │ PostgreSQL │ NATS          │
│         Provider Plugins (gRPC/Remote)               │
└──────────────────────────┬───────────────────────────┘
                  gRPC / Kubernetes API
┌──────────────────────────┴───────────────────────────┐
│              Kubernetes Clusters                     │
│  Meshery Operator │ MeshSync │ Adapters (gRPC)       │
└──────────────────────────────────────────────────────┘

Data flow: UI → REST/GraphQL → Server → PostgreSQL + Kubernetes API → NATS → MeshSync → GraphQL subscriptions → UI.

Testing

Go

  • Unit: go test ./... or go test --short ./...
  • Integration setup: make server-integration-tests-meshsync-setup (requires Docker, kind, kubectl, helm)
  • Integration run: make server-integration-tests-meshsync-run
  • Target ≥70% coverage on business logic.

UI

  • E2E (Playwright): make ui-integration-tests or npm run test:e2e in ui/
  • Setup: make test-setup-ui

Local Validation

make golangci    # before Go commits
make ui-lint     # before UI commits

Security & Compliance

  • Report vulnerabilities: security@meshery.dev — acknowledged in 10 business days.
  • Never commit secrets; use env vars (PROVIDER_BASE_URLS, KEYS_PATH) and GitHub Secrets.
  • CodeQL runs on every PR; OpenSSF Scorecard tracks security posture.
  • Apache 2.0 license — verify dependency compatibility.
  • Use parameterized queries; validate/sanitize all user inputs.

Agent Guardrails

Do Not Modify

LICENSE, CODE_OF_CONDUCT.md, GOVERNANCE.md, MAINTAINERS.md, .github/copilot-instructions.md, .github/agents/, go.sum, ui/package-lock.json, provider-ui/package-lock.json

Require Human Review

  • Security changes (auth, secrets, encryption)
  • Database migrations
  • API breaking changes
  • Helm chart templates (install/kubernetes/helm/)
  • CI/CD workflows (.github/workflows/)

Quality Gates

  • Go: make golangci must pass
  • JS: make ui-lint must pass
  • New features need docs; breaking changes need deprecation notices
  • Keep PRs under 500 lines; don't merge on CI failure

Extensibility

Provider Plugins

Interface: server/models/provider.go — implement auth, preferences, and sync externally.

Adapters (gRPC)

Protocol: server/meshes/meshops.proto — adapters self-register on startup. Examples: meshery-istio, meshery-linkerd, meshery-consul.

UI Extensions

Remote Components loaded via @paciolan/remote-component. Bundle must expose module.exports = { default: Component, __esModule: true }; a bundle built without output.library.type = "commonjs2" resolves to undefined with no loader error, so NavigatorExtension guards for it explicitly and reports the export shape as the cause. See ui/components/layout/Navigator/NavigatorExtension.tsx.

The host <-> extension contract (injected capability keys, event-bus event literals, contract version) is declared once in @sistent/sistent's mesheryExtensionContract module and shared by both sides. Derive every event literal from MESHERY_EXTENSION_EVENT and every injected key from that module rather than typing strings: hand-duplicated literals are why OPEN_DESIGN_IN_KANVAS -> OPEN_DESIGN_IN_EXTENSION and capabilitiesRegistry -> providerCapabilities both shipped as silent runtime no-ops. ui/utils/eventBus.ts must stay typed as EventBus<MesheryExtensionEvent>; a bare new EventBus() widens T to its constraint and disables publish-site checking entirely. The NavigatorExtension unit test asserts the built injectProps bag against the contract, which is the gate that catches a capability rename before merge.

GraphQL

Schema: server/internal/graphql/schema.graphql. Add queries/mutations/subscriptions then run make graphql-build.

Feature Flags

Env vars: PLAYGROUND, DEBUG, SKIP_COMP_GEN. Runtime config: ~/.meshery/config.yaml.

Event System

NATS topics: meshsync.request, meshery.broker. MeshSync publishes cluster state changes.

Hooks & Scripts

  • Pre-commit: Husky hooks in ui/.husky/
  • Build: extend Makefile or install/Makefile.core.mk

Coding Agents

Agent definitions in .agents/ (LLM-agnostic):

AgentFilePurpose
Code Reviewer.agents/code-reviewer.mdParallel review across Go + frontend
Security Reviewer.agents/security-reviewer.mdSecurity audit
Meshery Code Contributor.agents/meshery-code-contributor.mdFull-stack contributions
Meshery Docs Contributor.agents/meshery-docs-contributor.mdHugo docs contributions
GitHub Actions Engineer.agents/github-actions-engineer.mdCI/CD design and debugging
Relationship Fixture Agent.agents/relationship-fixture-agent.mdRelationship test fixtures

Skills

.agents/skills/ is the single source of truth for every packaged workflow in this repo - one directory per skill, each with a SKILL.md. Do not enumerate them here; list the directory. Add a new skill only there.

Per-tool discovery, so no skill is ever copied per tool:

ToolHow it finds these skills
CodexNatively scans $REPO_ROOT/.agents/skills - nothing to configure (docs)
OpenCodeNatively scans .agents/skills, one of six roots it searches alongside .opencode/skills and .claude/skills (docs)
Claude CodeReads .claude/skills, which is a relative symlink to ../.agents/skills

.claude/skills is that symlink and nothing else. Never replace it with real directories or copies - that reintroduces the drift this layout removes. It is also a runtime dependency, not just a discovery path: .agents/skills/iterate-pr/SKILL.md invokes its scripts through .claude/skills/iterate-pr/scripts/<script>.py in 13 places (12 python3, one uv run), which resolve only through it. Deleting the symlink later - say on learning Claude Code reads .agents/skills natively - breaks iterate-pr with no other signal.

The four skills tracked in skills-lock.json - chrome-devtools-axi, gh-axi, lavish, quota-axi - are installed by the AXI installer, and its layout is skill content at .agents/skills/<name>/ plus a per-skill symlink at .claude/skills/<name>. Those per-skill symlinks were installer-owned, not hand-made, and this layout removed them as redundant. The next installer run recreates them, and .claude/skills/<name> now resolves through the directory symlink onto .agents/skills/<name> - an existing real directory holding the canonical content. Best case the installer fails with EEXIST. Worst case a force-replacing installer destroys that canonical directory and leaves a self-referential symlink loop. Which of the two occurs is not established, and must not be determined by running the installer against a real checkout: the failure mode under test is destruction of the canonical skill content.

Neither .codex/skills nor .opencode/skills is created: both tools already read .agents/skills natively, so a second copy or link would be redundant. .opencode/skills is a real OpenCode search root, just an unnecessary one here; .codex/skills is not a path Codex scans at all.

Windows caveat: on a checkout with core.symlinks=false - the default outside developer mode - git materialises .claude/skills as a regular text file containing the literal string ../.agents/skills. Claude Code then discovers no project skills, and the iterate-pr script paths above fail with "No such file or directory". Enable Windows developer mode or set git config core.symlinks true, then re-checkout.

Automation Hooks

Scripts in .agents/hooks/:

HookScriptTriggerPurpose
Format Frontend.agents/hooks/format-frontend.shPost-editAuto-format JS/TS with Prettier
Block Lock Files.agents/hooks/block-lockfiles.shPre-editPrevent direct edits to lock files

Further Reading

Maintaining this file

Keep this file for knowledge useful to almost every future agent session in this project. Do not repeat what the codebase already shows; point to the authoritative file or command instead. Prefer rewriting or pruning existing entries over appending new ones. When updating this file, preserve this bar for all agents and keep entries concise.