openclaw - ✅(Solved) Fix [Bug] available_skills ordering is inconsistent depending on extraDirs config [4 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#64167Fetched 2026-04-11 06:16:06
View on GitHub
Comments
0
Participants
1
Timeline
6
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×4labeled ×1referenced ×1

available_skills ordering is inconsistent, varies by extraDirs config order instead of being sorted alphabetically

Root Cause

Root cause: In src/agents/skills/workspace.ts, loadSkillEntries() merges skills from multiple sources into a Map. Map preserves insertion order, so final order depends on which source provides each skill first. No final sort by skill name after merge.

Fix Action

Fixed

PR fix notes

PR #64189: Fix: sort merged workspace skills alphabetically for deterministic order (Resolves #64167)

Description (problem / solution / changelog)

Fixes #64167.

Problem

loadSkillEntries in src/agents/skills/workspace.ts merges skills from multiple sources (bundled, extraDirs, managed, personal/project .agents/skills, workspace) into a Map<string, Skill>. The final array is built from Array.from(merged.values()), which preserves Map insertion order — i.e. the order in which each skill name was first written.

That means the order of skills in <available_skills> depends on which source saw each skill first, and for extraDirs specifically on the order of entries in skills.load.extraDirs. In multi-instance cloud deployments where instances may list extraDirs in different orders, each instance produces a different prompt prefix, bypassing the LLM prompt cache and increasing API cost/latency.

Within a single source loadSkills() already sorts childDirs.slice().sort(), and the truncation path sorts by skill name — but there is no global sort after the cross-source merge.

Fix

Sort the merged Array.from(merged.values()) alphabetically by skill.name (via localeCompare) before constructing SkillEntry[]. Precedence-based overrides from the merge loop are untouched; only the traversal order of the resulting array becomes deterministic.

This satisfies the prompt-cache-stability guidance in CLAUDE.md: "Any code that assembles model or tool payloads from maps, sets, registries, plugin lists… must make ordering deterministic before building the request."

Test plan

  • Added loadWorkspaceSkillEntries regression test that creates four skills split across two extraDirs and asserts identical alphabetical ordering for both [A, B] and [B, A] extraDirs configurations.
  • pnpm test src/agents/skills.loadworkspaceskillentries.test.ts — 15/15 pass.
  • pnpm test src/agents/skills.test.ts src/agents/skills.buildworkspaceskillsnapshot.test.ts src/agents/skills.build-workspace-skills-prompt.*.test.ts src/agents/skills.agents-skills-directory.test.ts — 42/42 pass.

Changed files

  • src/agents/skills.loadworkspaceskillentries.test.ts (modified, +41/-0)
  • src/agents/skills/workspace.ts (modified, +9/-1)

PR #64198: fix(skills): sort available_skills alphabetically for prompt cache stability

Description (problem / solution / changelog)

Summary

Sort the merged skill entries by name before rendering into the <available_skills> prompt block.

Problem

The order of skills in <available_skills> depended on Map insertion order, which varies with the order of directories in skills.load.extraDirs. In multi-instance cloud deployments, each instance could produce a different prompt, bypassing LLM prompt caching and increasing API costs.

Fix

Two alphabetical sort points added:

  1. loadSkillEntries — canonical ordering at the data source, after the precedence-based merge
  2. resolveWorkspaceSkillPromptState — ensures prompt stability even when callers pass pre-built entry arrays directly

Both use name.localeCompare(name) for stable, locale-aware ordering.

Test

Added a test that passes entries in non-alphabetical order (zoo, apple, mango, banana) and verifies the prompt output contains them sorted as apple, banana, mango, zoo.

All 19 existing tests in compact-format.test.ts continue to pass.

Fixes #64167

Changed files

  • src/agents/skills/compact-format.test.ts (modified, +14/-0)
  • src/agents/skills/workspace.ts (modified, +28/-24)

PR #64215: fix(skills): sort available_skills alphabetically for deterministic prompt ordering (#64167)

Description (problem / solution / changelog)

Summary

The available_skills prompt section ordering depended on extraDirs config order instead of being deterministic. In multi-instance deployments, each instance could produce different prompts, bypassing LLM prompt cache and increasing API costs.

Root Cause

resolveWorkspaceSkillPromptState() in src/agents/skills/workspace.ts assembled skills from a Map that preserved insertion order from the config-ordered directory scan. No sort was applied before formatting into the prompt.

Changes

  • src/agents/skills/workspace.ts: Sort resolvedSkills alphabetically by name before passing to compactSkillPaths() and downstream formatting functions.
  • src/agents/skills/compact-format.test.ts: Added regression test verifying alphabetical ordering in the rendered <available_skills> block.

Test

39 tests passed (pnpm test src/agents/skills/). The new regression test feeds reverse-ordered skills and asserts alphabetical output.

Closes #64167

Changed files

  • src/agents/skills/compact-format.test.ts (modified, +26/-5)
  • src/agents/skills/workspace.ts (modified, +3/-1)

PR #64222: fix(skills): sort available skills after merge

Description (problem / solution / changelog)

Closes #64167

Summary

  • sort merged workspace skill entries alphabetically after precedence resolution
  • make available_skills ordering independent from skills.load.extraDirs ordering
  • add a regression test that exercises reversed extraDirs input

Test Plan

  • pnpm --dir /Users/wentao/Desktop/openclaw exec vitest run src/plugins/config-policy.test.ts src/plugins/loader.test.ts src/config/config.plugin-validation.test.ts src/agents/skills/workspace.load-order.test.ts
  • NODE_OPTIONS=--max-old-space-size=8192 pnpm --dir /Users/wentao/Desktop/openclaw exec tsc --noEmit --pretty false

Changed files

  • extensions/comfy/image-generation-provider.test.ts (modified, +26/-0)
  • extensions/comfy/music-generation-provider.test.ts (modified, +67/-0)
  • extensions/comfy/video-generation-provider.test.ts (modified, +28/-0)
  • extensions/comfy/workflow-runtime.ts (modified, +5/-2)
  • extensions/memory-core/src/memory/index.test.ts (modified, +6/-0)
  • extensions/memory-core/src/memory/provider-adapters.ts (modified, +39/-1)
  • extensions/whatsapp/src/session.runtime.ts (modified, +1/-0)
  • extensions/whatsapp/src/session.test.ts (modified, +67/-27)
  • extensions/whatsapp/src/session.ts (modified, +33/-1)
  • src/agents/skills/workspace.load-order.test.ts (added, +48/-0)
  • src/agents/skills/workspace.ts (modified, +25/-23)
  • src/agents/tools/sessions-announce-target.ts (modified, +15/-1)
  • src/agents/tools/sessions-helpers.ts (modified, +2/-0)
  • src/agents/tools/sessions.test.ts (modified, +27/-0)
  • src/infra/outbound/message-action-params.test.ts (modified, +36/-1)
  • src/infra/outbound/message-action-params.ts (modified, +7/-2)
  • src/memory-host-sdk/engine-embeddings.ts (modified, +4/-0)
  • src/plugins/config-normalization-shared.ts (modified, +3/-0)
  • src/plugins/config-policy.test.ts (modified, +12/-0)
  • src/plugins/loader.test.ts (modified, +3/-1)
  • src/plugins/loader.ts (modified, +1/-1)
  • test/mocks/baileys.ts (modified, +8/-0)
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

available_skills ordering is inconsistent, varies by extraDirs config order instead of being sorted alphabetically

Steps to reproduce

  1. Configure multiple directories in skills.load.extraDirs
  2. Each directory contains skills with alphabetical names
  3. Observe that the order of skills in <available_skills> varies depending on the order of extraDirs entries, not by skill name

Expected behavior

Skills in <available_skills> should be sorted alphabetically by skill name, regardless of the order of directories in extraDirs or source precedence

Actual behavior

The order of skills in <available_skills> varies depending on extraDirs order. In multi-instance cloud deployments, each instance may produce different prompts, bypassing LLM prompt cache and increasing API costs

OpenClaw version

2026.4.10

Operating system

macOS 25.3.0 (arm64)

Install method

npm global

Model

minimax-portal/MiniMax-M2.5

Provider / routing chain

openclaw -> minimax

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

Affected: Cloud deployments with multiple instances using extraDirs Severity: High (blocks prompt cache, increases API costs) Frequency: Always Consequence: Inconsistent prompts across instances, prompt cache cannot be used, higher latency and costs

Additional information

Root cause: In src/agents/skills/workspace.ts, loadSkillEntries() merges skills from multiple sources into a Map. Map preserves insertion order, so final order depends on which source provides each skill first. No final sort by skill name after merge.

Sorting only occurs within each source directory (childDirs.slice().sort()) and at line 403 when truncating due to maxSkillsLoadedPerSource limit. No global alphabetical sort applied to final merged result.

extent analysis

TL;DR

Apply a global alphabetical sort to the merged skills in loadSkillEntries() after all sources have been merged.

Guidance

  • Identify the loadSkillEntries() function in src/agents/skills/workspace.ts and locate where the skills from multiple sources are merged into a Map.
  • After the merge, apply a global sort to the skills by their names using Array.prototype.sort() or a similar method.
  • Verify that the sort is stable and does not interfere with other parts of the code that rely on the skills being in a specific order.
  • Test the change in a controlled environment to ensure it resolves the issue without introducing new problems.

Example

// Example of applying a global sort after merging skills
const mergedSkills = new Map();
// ... merge skills from multiple sources into mergedSkills ...
const sortedSkills = Array.from(mergedSkills.values()).sort((a, b) => a.name.localeCompare(b.name));

Notes

This fix assumes that the loadSkillEntries() function is the correct place to apply the global sort. If the issue persists after applying this fix, further investigation may be needed to identify other parts of the code that could be affecting the skills order.

Recommendation

Apply the workaround by adding a global sort to the merged skills in loadSkillEntries(), as this is a targeted fix that addresses the identified root cause of the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Skills in <available_skills> should be sorted alphabetically by skill name, regardless of the order of directories in extraDirs or source precedence

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING