본문으로 건너뛰기
cccskills
무료GitHub에 공개

plugins

Wire a MeshWeaver deployment to the plugin catalog — as a CONSUMER (installs plugins from a registry over HTTP, no git credential) or as the REGISTRY (holds the git credential, serves private plugin repos at /api/plugins). Use when a deployment's Plugin Catalog says "not configured", when adding a new plugin source repo, when issuing an install its registry token, when a plugin won't appear or won't install, or when auditing who can read the catalog. Covers the credential-encapsulation model, the Helm keys (and the trap that un-templated keys are silently dropped), token issuance, and the anonymous-registry exposure that a missing token list causes.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Systemorph/MeshWeaver스타 12(GitHub 12 + cccskills 0)
연동 도구Kubernetes

실행 점수 미검증

설치 방법 보기

포함된 파일(1)

  • SKILL.md8.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

/plugins — the plugin catalog: registry and consumers

Plugins are folders of mesh nodes in private git repos. The point of the design is that only one install holds a git credential.

Systemorph/MeshWeaver.Plugins ─┐
                               ├─→ REGISTRY (public inst.) ── GET /api/plugins ──→ CONSUMER
Systemorph/education ──────────┘   holds the ONE credential   POST /api/plugins/files   no git access

npm/NuGet-style: the registry has source access, clients just speak HTTP. Model: PluginRegistry.md · Plugins.md.

Which am I configuring?

RegistryConsumer
Holds git credential✅❌ never
Helm valuespluginCatalog.sourcespluginCatalog.registryUrl (or .registries)
SecretPluginCatalog__RegistryTokens (the list it accepts)PluginCatalog__RegistryToken (the one it sends)
Todaythe public instance (the plugin registry instance)every other deployment

A registry is also a consumer of itself — the plugin registry instance sets both.

Consumer wiring

Zero-touch (preferred for new installs) — the install registers ITSELF on first boot with an admin-minted mwr_ registration key (Instance grants ▸ Registration keys on the registry; one key serves a whole scaffold, revocable), receives its mwi_ instance key and stores it (Admin/PluginRegistryCredential/…, master-key-encrypted). No token copying:

pluginCatalog:
  registryUrl: "https://registry.example.com"
  instanceId: "<this install's logical App ID>"   # REQUIRED with a bootstrap key; never derived
config:
  memex_portal:
    # Systemorph-operated deployments track their plugin repos continuously: a fresh install
    # record is seeded opted-in, so a plugin repo's green build lands with nobody clicking Update.
    # Install-time SEED only — flipping it later changes nothing for already-installed packages.
    PluginCatalog__AutoUpdateByDefault: "true"
secrets:
  memex_portal:
    PluginCatalog__BootstrapKey: "<an mwr_ registration key>"

Manual (unchanged, and always wins when both are set):

secrets:
  memex_portal:
    PluginCatalog__RegistryToken: "<the mwi_ key this install was issued in Settings ▸ Instances>"

Several registries instead of one:

pluginCatalog:
  registries:
    - {name: Plugins,   url: "https://registry.example.com"}
    - {name: Education, url: "https://<other-registry>"}

Registry wiring

pluginCatalog:
  sources:
    - {name: Plugins,   repoPath: "https://github.com/Systemorph/MeshWeaver.Plugins", ref: main}
    - {name: Education, repoPath: "https://github.com/Systemorph/education",          ref: main}
  # Sources every NEW instance registration is granted automatically (seeded into the instance's
  # Admin/_PluginGrant node — admins can still revoke per instance). Platform repo only; never
  # list private/paid sources here. Empty = registering grants nothing (the strict default).
  defaultGrants: ["Plugins/*"]
secrets:
  memex_portal:
    PluginCatalog__RegistryTokens: ["<token-for-install-a>", "<token-for-install-b>"]

format defaults to node-repo — a folder appears once it carries a <Folder>/index.json Space root with a PluginManifest. package-json is the alternative layout. Sources merge in configured order; on an id collision the first wins; a failing repo contributes nothing (logged) rather than breaking the catalog.

🚨 A registry with no tokens serves everyone

PluginCatalog:RegistryTokens empty ⇒ the registry answers anonymously. That is the local-dev / e2e stub mode. On a production registry it means the full catalog and every package's file content is readable by anyone who knows the URL.

Audit it — this is a one-line check, run it:

curl -sS https://<registry-host>/api/plugins -o /dev/null -w "%{http_code}\n"   # want 401
curl -sS -X POST https://<registry-host>/api/plugins/files \
  -H 'Content-Type: application/json' -d '{"id":"<some-id>"}' -o /dev/null -w "%{http_code}\n"  # want 401

200 unauthenticated = every private plugin repo behind that registry is public to anyone with the URL. Issue tokens and set RegistryTokens.

As of 2026-08-06 the plugin registry instance's /api/plugins returned 200 with 28 packages to an unauthenticated caller, including paid course content from Systemorph/education. Fixing it means issuing each install a token, setting RegistryTokens on the registry, and rolling — in that order, or consumers lose their catalog in the gap.

Issue a token:

openssl rand -base64 32

Store it in Key Vault (<env>-PluginCatalog-RegistryToken) and surface it through the SecretProviderClass — never in a values file.

Installing

Platform admin → Settings ▸ Administration ▸ Plugin Catalog → Install. It is an admin tab, not a browsable Space (a Space partition would correctly deny read to everyone else — that was the "Access denied on 'Plugins'" bug). The consumer pulls the package files over HTTP and imports them:

  • Content package → imports its folder into the target partition.
  • Code package → synthesizes its NodeType from the manifest, imports Source/*.cs as Code children, and requests a release so the mesh compiles the type live. No app rebuild, no NuGet.

Re-installing is an upsert; installing one module never disturbs another in a shared partition.

Troubleshooting

"Plugin catalog not configured" → EffectiveRegistries is empty: no registryUrl and no registries entry with a URL reached the pod. Check what actually landed, not what the values file says — first on the record: Deployments/<name> on the control instance carries the whole env precedence stack (inlineEnv, extraPortalConfig, the key-vault classes), and an Audit Hosting/InstanceAction compares it with the cluster. The direct read is break-glass (OperatingFromThePortal.md):

kubectl -n <env> get deploy memex-portal-deployment \
  -o jsonpath='{range .spec.template.spec.containers[0].env[*]}{.name}={.value}{"\n"}{end}' | grep -i plugin
kubectl -n <env> get configmap memex-portal-config -o jsonpath='{.data}' | tr ',' '\n' | grep -i plugin

The #1 cause: the chart only emits keys it templates. Before pluginCatalog existed in values.yaml, every plugin key except AutoUpdateByDefault was silently dropped — which is why the plugin registry instance's registry config was hand-applied as raw Deployment env vars that no redeploy reproduces. If a key isn't in deploy/helm/templates/memex-portal/config.yaml, it does not reach the pod. Verify by rendering:

helm template t deploy/helm -f <values>.yaml | grep PluginCatalog

401 from the registry → the consumer's token isn't in the registry's RegistryTokens. Both sides validate through PluginRegistryTokens, one shared contract, so a mismatch is a real value mismatch, not a format one.

A folder in the repo doesn't appear in the catalog → it has no <Folder>/index.json Space root with a PluginManifest, or its source's format is wrong.

Package installs but the type doesn't work → it's a Code package; the compile happens live. Check the NodeType's compile status before suspecting the install.

Related

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

async

무료

Forwarding AccessContext through async/reactive boundaries, and the no-async rule on the actor-model mesh. Use when writing or reviewing any hub-reachable / Blazor-view / agent-round / IIoPool code that creates, reads, or updates a mesh node, OR when a write "silently does nothing" / "Access denied" appears after a .Subscribe / IIoPool / Observable.Create hop. The async/await/ToTask/.Wait/.Result/.GetAwaiter/FirstAsync family and lost AccessContext are the two ways async boundaries cause wedges and storms. Grounded in AsynchronousCalls.md, SyncedMeshNodeQueries.md, AccessContextPropagation.md.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Systemorph/MeshWeaver122026년 10월 29일 업데이트

ci

무료

What CI proves, what it cannot prove, and how to write a gate that cannot pass on no evidence. Use when authoring or changing a GitHub Actions workflow, adding a required check, wiring a satellite repo CI, or reasoning about whether a green run actually covers your change. Covers the absolute no-skip-trapdoor rule (a gate must never carry continue-on-error on its input step nor an if that asks whether a secret is set — GitHub paints a skipped job the same colour as a passed one), the reusable workflow_call jobs satellite repos must call instead of hand-rolling, why runs on main are deliberately never cancelled, and the large body of in-mesh C# that no dotnet build or test ever type-checks.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Systemorph/MeshWeaver122026년 10월 29일 업데이트

debug

무료

Debug a deadlock / hang / timeout in the mesh — a test that times out, a hub handler whose response never arrives, a GetRemoteStream / GetMeshNodeStream / GetQuery that never emits, an agent round or per-instance-hub activation that parks forever. Use whenever something times out and you need to find WHERE the message flow breaks down. The timeout is the symptom, never the bug — raising it just hangs longer. Grounded in DebuggingMessageFlow.md.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Systemorph/MeshWeaver122026년 10월 29일 업데이트

Remove / reset a user (and their partition) on a running MeshWeaver portal (AKS). Use when you need to kick out a user — e.g. a throwaway test account — so they re-onboard from scratch. The normal delete API REFUSES a user's home ("user partition root … cannot be deleted"), so deletion is a Postgres-schema drop, not an MCP call. Covers where a user's data actually lives (per-user PG schemas named by BOTH id AND email, e.g. `rbuergi` + `rbuergi@systemorph.com`), how to reach PG (the connection string is inline in the portal's `ConnectionStrings__memex` env — NOT the `POSTGRES_PASSWORD` secret), the substring-match footgun (`buergi` also matches admin `rbuergi`), the in-memory resurrection gotcha (a recycle re-saves the node — a portal restart is what actually clears it), and the half-onboarded case where the user has NO schema at all (in-memory only → restart is the whole fix).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Systemorph/MeshWeaver122026년 10월 29일 업데이트

deploy

무료

Deploy MeshWeaver — the two routes (shared AKS cluster, and Azure Container Apps via the Aspire test/prod modes) and the traps that make a deploy look done when it is not. Use when rolling a code change onto a portal, standing up or patching an environment, or verifying that what is running is what you built. FIRST RULE (maintainer, 2026-09-08): on AKS an operation is a Hosting/InstanceAction on the control instance (Roll, Restart, Suspend, Audit, Reconcile, …) executed by the in-cluster operator — az aks command invoke / kubectl are break-glass, never the procedure. Also covers the bootstrap build-image / set-image / restart sequence the operator runs for you, why an env deploy.sh is first-time setup and not a code-update path, why the database migration is a run-once Job that a helm upgrade runs — never a Deployment to roll — and the DbVersionGate that makes a portal refuse to serve ahead of its schema.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Systemorph/MeshWeaver122026년 10월 29일 업데이트

gui

무료

Build or review ANY MeshWeaver UI — layout areas, editable views, forms, tables, content editing, side-panel composers — by wiring the framework's EXISTING data-binding pieces, NEVER hand-rolling. The one rule is ALWAYS DATA-BIND, especially editable views: the backend layout area declares WHAT to render (a UiControl tree + node PATHS), and every value read / write-back happens on the GUI side through the per-node IMeshNodeStreamCache. Hand-woven binding — replicating a node into a /data/{id} copy + a save subscription, emitting HTML strings, hand-built selects/checkboxes, .Take(1) on a live stream, async/await/QueryAsync in a layout area — is the bug class behind "awaiting first data" / "renders empty" / a stuck editable view. Use when writing or reviewing a layout area, control, editor, form, table, or any data-bound view. Grounded in src/MeshWeaver.Layout/DataBinding/, Doc/GUI/DataBinding.md + Editor.md, the Edit extension (EditorExtensions.cs), and the node-bound editor controls.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Systemorph/MeshWeaver122026년 10월 29일 업데이트

Systemorph의 스킬 모두 보기

이 스킬의 문제 신고