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
| Directory | Purpose |
|---|---|
/server | Go backend — REST/GraphQL APIs, Kubernetes management, PostgreSQL |
/ui | Next.js/React frontend — MUI, Redux Toolkit, Relay GraphQL |
/mesheryctl | Go CLI with Cobra — install, lifecycle, pattern deployment |
/docs | Hugo documentation site |
/install | Dockerfiles, Kubernetes manifests, Helm charts |
/provider-ui | Provider-specific React UI extensions |
/.github | GitHub 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
| Layer | Form |
|---|---|
DB column / db: tag | snake_case — user_id, org_id, created_at |
| Go struct field | PascalCase with Go initialisms — UserID, OrgID, CreatedAt |
| JSON tag | camelCase — json:"userId", json:"orgId" |
| URL query/path param | camelCase — {orgId}, ?userId=... |
| TypeScript property | camelCase — response.userId |
| OpenAPI schema property | camelCase |
OpenAPI operationId | lower camelCase verbNoun — getWorkspaces |
components/schemas type name | PascalCase — WorkspacePayload |
Forbidden (MUST NOT)
- MUST NOT use a
json:tag matching thedb: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 — useId. - MUST NOT mix casing within a single resource; introduce a new API version to change wire format.
- MUST NOT import deprecated
v1beta1in new code; usev1beta3(orv1beta2where 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.mdis 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)
- Define the path + schemas in the matching construct's
api.yml(e.g.../schemas/schemas/constructs/v1beta1/system/api.ymlfor/api/system/*,.../connection/api.ymlfor/api/integrations/connections*). Follow the schemas conventions:operationId= lower-camelverbNoun, camelCase wire params/properties,x-internal: ["meshery"]for Meshery-only endpoints,additionalProperties: false,maxLengthon strings. - Regenerate in
../schemas:make bundle-openapi generate-rtk generate-golang(ormake buildfor the full dist). Verify the newuseXQuery/mesheryApi.endpoints.Xhooks appear. - Validate:
cd ../schemas && make validate-schemas && make consumer-audit. - Consume the generated hook in the UI (import from
@meshery/schemas/mesheryApi; wrap inui/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. - Release coupling: schemas releases are automated ("do not manually create
releases"). Until a new
@meshery/schemasis published and this repo's dependency is bumped, a local link is used for development (ui/package.json→"@meshery/schemas": "file:../schemas"and thereplace github.com/meshery/schemas => ../schemasdirective ingo.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 inapi.yml, but consume it with a nativeEventSourceclient underui/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.mutationinui/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-axiCLI tool to interact with GitHub. Prefergh-axiovergh. - Use
chrome-devtools-axifor 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-axito check local agent-provider quota windows before long-running work. - Use the
lavishskill (lavish-axiCLI) 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 withmake golangci(config:.golangci.yml). - Use MeshKit error utilities (
github.com/meshery/meshkit/errors); runmake errorfor codes.make errorskipsmesheryctl- a newmesheryctlcode is taken frommesheryctl/helpers/component_info.json(next_error_code) and that value bumped in the same commit..github/workflows/error-codes-updater.yamlre-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. Inmesheryctlcommands, log the structured error for the user and return it for the exit path. - Tests in
*_test.go; manage deps withgo mod tidy.
JavaScript/React
- ESLint + Prettier (config:
ui/.eslintrc.js). - Functional components with hooks; no class components.
- Use
@sistent/sistentdesign 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 ./...orgo 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-testsornpm run test:e2einui/ - 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 golangcimust pass - JS:
make ui-lintmust 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
Makefileorinstall/Makefile.core.mk
Coding Agents
Agent definitions in .agents/ (LLM-agnostic):
| Agent | File | Purpose |
|---|---|---|
| Code Reviewer | .agents/code-reviewer.md | Parallel review across Go + frontend |
| Security Reviewer | .agents/security-reviewer.md | Security audit |
| Meshery Code Contributor | .agents/meshery-code-contributor.md | Full-stack contributions |
| Meshery Docs Contributor | .agents/meshery-docs-contributor.md | Hugo docs contributions |
| GitHub Actions Engineer | .agents/github-actions-engineer.md | CI/CD design and debugging |
| Relationship Fixture Agent | .agents/relationship-fixture-agent.md | Relationship 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:
| Tool | How it finds these skills |
|---|---|
| Codex | Natively scans $REPO_ROOT/.agents/skills - nothing to configure (docs) |
| OpenCode | Natively scans .agents/skills, one of six roots it searches alongside .opencode/skills and .claude/skills (docs) |
| Claude Code | Reads .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/:
| Hook | Script | Trigger | Purpose |
|---|---|---|---|
| Format Frontend | .agents/hooks/format-frontend.sh | Post-edit | Auto-format JS/TS with Prettier |
| Block Lock Files | .agents/hooks/block-lockfiles.sh | Pre-edit | Prevent direct edits to lock files |
Further Reading
- Contributing Guide
- Meshery Documentation
- Architecture Overview
- API Documentation
- CLI Guide
- Extensibility
- Community Handbook
- Security Policy
- Governance
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.