Skip to content

fix(manifest): declare kind=context-engine so install auto-binds slot#397

Merged
jalehman merged 1 commit into
Martian-Engineering:mainfrom
mjamiv:fix/manifest-kind-context-engine
Apr 11, 2026
Merged

fix(manifest): declare kind=context-engine so install auto-binds slot#397
jalehman merged 1 commit into
Martian-Engineering:mainfrom
mjamiv:fix/manifest-kind-context-engine

Conversation

@mjamiv

@mjamiv mjamiv commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a single top-level "kind": "context-engine" field to openclaw.plugin.json so OpenClaw core's slot resolver binds the contextEngine slot to this plugin on install.
  • Adds a matching manifest-shape test to test/config.test.ts so any future edit that drops or retypes the field fails fast.

Fixes #384.

Root cause (quoting the issue)

OpenClaw core's slot resolver lives in src/plugins/slots.ts (compiled to dist/slots-CFrDTeTR.js in the published build). Its pipeline:

const SLOT_BY_KIND = {
  memory: "memory",
  "context-engine": "contextEngine",
};

function slotKeysForPluginKind(kind) {
  return normalizeKinds(kind).map((k) => SLOT_BY_KIND[k]).filter((k) => k != null);
}

function applyExclusiveSlotSelection(params) {
  const slotKeys = slotKeysForPluginKind(params.selectedKind);
  if (slotKeys.length === 0) return { config: params.config, warnings: [], changed: false };
  // ...write plugins.slots[slotKey] = params.selectedId
}

Before this PR, openclaw.plugin.json has no top-level kind field, so slotKeysForPluginKind returns [] and applyExclusiveSlotSelection early-returns with changed: false. openclaw plugins install @martian-engineering/lossless-claw silently leaves plugins.slots.contextEngine unset, and OpenClaw falls back to the default legacy context engine at runtime.

The plugin still loads and still calls api.registerContextEngine("lossless-claw", () => lcm) — but the slot resolver never routes any traffic to that registration, so no conversation ever reaches lcm.handleContextPrepare / lcm.onTurnComplete.

User-visible symptom

lcm.db stays at the initial ~4 KB / 0 tables forever, even on an install that reports success and even with plugins.entries.lossless-claw.enabled: true. On one 4-week-old v0.3.0 install the DB was still empty until plugins.slots.contextEngine: "lossless-claw" was added manually, at which point all 21 LCM tables initialized on the next turn and LCM started writing normally. See #384 for the full trace.

Fix

One new top-level field in openclaw.plugin.json:

 {
   "id": "lossless-claw",
+  "kind": "context-engine",
   "skills": [

With kind present, slotKeysForPluginKind now returns ["contextEngine"] and applyExclusiveSlotSelection writes plugins.slots.contextEngine = "lossless-claw" — which is the exact config state users currently have to hand-edit to make LCM work.

Test

Adds one shape test next to the existing skill-path test:

it("declares context-engine kind so OpenClaw core binds the contextEngine slot on install", () => {
  expect(manifest.kind).toBe("context-engine");
});

Verification

  • npm test — all 40 test files / 694 tests pass locally
  • Traced against OpenClaw core dist/slots-CFrDTeTR.js (SLOT_BY_KIND, slotKeysForPluginKind, applyExclusiveSlotSelection) — the semantics match what is claimed above
  • No other files in this repo reference a top-level manifest kind field, so this is a pure addition

What this does NOT change

  • No runtime code changes
  • No config schema changes
  • No change to the api.registerContextEngine call or index.ts entrypoint
  • No change for users who have already hand-added the slot config — the slot resolver is idempotent, so this just makes the first install do the right thing

🤖 Generated with Claude Code

The OpenClaw core slot resolver in `plugins/slots.ts` reads a plugin's
top-level `kind` field, maps it via `SLOT_BY_KIND` (`context-engine ->
contextEngine`), and calls `applyExclusiveSlotSelection`. When `kind` is
missing, `slotKeysForPluginKind` returns an empty array and the
exclusive-slot selection path early-returns without assigning any slot.
As a result, `openclaw plugins install @martian-engineering/lossless-claw`
silently leaves `plugins.slots.contextEngine` unset, and OpenClaw falls
back to the built-in `legacy` context engine at runtime. The plugin loads
and registers its context engine with `api.registerContextEngine("lossless-claw", ...)`,
but nothing ever routes traffic to it.

The only user-visible symptom is that `lcm.db` stays at the initial
~4 KB / 0 tables forever, even on an install that reports success. The
README states that installation auto-sets the slot, which is the intended
behavior — it only fails because the manifest is missing this one field.

The fix is a single new top-level field in `openclaw.plugin.json`. A
matching manifest-shape test is added to `test/config.test.ts` so any
future edit that drops or retypes the field fails fast.

Verification:
- All 40 test files / 694 tests pass locally on `npm test`
- New manifest test explicitly checks `manifest.kind === "context-engine"`
- Traced against OpenClaw core `dist/slots-CFrDTeTR.js` (`SLOT_BY_KIND`,
  `slotKeysForPluginKind`, `applyExclusiveSlotSelection`): with `kind`
  present, `slotKeysForPluginKind` now returns `["contextEngine"]` and
  `applyExclusiveSlotSelection` writes `plugins.slots.contextEngine =
  "lossless-claw"`, which is the exact config state that activates LCM
  end-to-end.

Fixes Martian-Engineering#384.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jalehman

Copy link
Copy Markdown
Contributor

Thank you!

@jalehman jalehman merged commit 30903a8 into Martian-Engineering:main Apr 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

openclaw.plugin.json missing kind: "context-engine" — installer skips slot selection, plugin loads but never activates

2 participants