feat: add OpenClaw host config with adapter for tool mapping

OpenClaw gets a hybrid approach: typed config for paths/frontmatter/
detection + a post-processing adapter for semantic tool rewrites.

Config handles: path rewrites, frontmatter (name+description+version),
CLAUDE.md→AGENTS.md, tool name rewrites (Bash→exec, Read→read, etc.),
suppressed resolvers, SOUL.md via staticFiles.

Adapter handles: AskUserQuestion→prose, Agent→sessions_spawn, $B→exec $B.

Zero .claude/skills path leakage. Zero hardcoded tool references remaining.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-04-03 16:36:06 -07:00
parent 8b5256342b
commit 86b21561c4
3 changed files with 127 additions and 2 deletions
+3 -2
View File
@@ -13,9 +13,10 @@ import kiro from './kiro';
import opencode from './opencode';
import slate from './slate';
import cursor from './cursor';
import openclaw from './openclaw';
/** All registered host configs. Add new hosts here. */
export const ALL_HOST_CONFIGS: HostConfig[] = [claude, codex, factory, kiro, opencode, slate, cursor];
export const ALL_HOST_CONFIGS: HostConfig[] = [claude, codex, factory, kiro, opencode, slate, cursor, openclaw];
/** Map from host name to config. */
export const HOST_CONFIG_MAP: Record<string, HostConfig> = Object.fromEntries(
@@ -62,4 +63,4 @@ export function getExternalHosts(): HostConfig[] {
}
// Re-export individual configs for direct import
export { claude, codex, factory, kiro, opencode, slate, cursor };
export { claude, codex, factory, kiro, opencode, slate, cursor, openclaw };
+79
View File
@@ -0,0 +1,79 @@
import type { HostConfig } from '../scripts/host-config';
const openclaw: HostConfig = {
name: 'openclaw',
displayName: 'OpenClaw',
cliCommand: 'openclaw',
cliAliases: [],
globalRoot: '.openclaw/skills/gstack',
localSkillRoot: '.openclaw/skills/gstack',
hostSubdir: '.openclaw',
usesEnvVars: true,
frontmatter: {
mode: 'allowlist',
keepFields: ['name', 'description'],
descriptionLimit: null,
extraFields: {
version: '0.15.2.0',
},
},
generation: {
generateMetadata: false,
skipSkills: ['codex'],
},
pathRewrites: [
{ from: '~/.claude/skills/gstack', to: '~/.openclaw/skills/gstack' },
{ from: '.claude/skills/gstack', to: '.openclaw/skills/gstack' },
{ from: '.claude/skills', to: '.openclaw/skills' },
{ from: 'CLAUDE.md', to: 'AGENTS.md' },
],
toolRewrites: {
'use the Bash tool': 'use the exec tool',
'use the Write tool': 'use the write tool',
'use the Read tool': 'use the read tool',
'use the Edit tool': 'use the edit tool',
'use the Agent tool': 'use sessions_spawn',
'use the Grep tool': 'search for',
'use the Glob tool': 'find files matching',
'the Bash tool': 'the exec tool',
'the Read tool': 'the read tool',
'the Write tool': 'the write tool',
'the Edit tool': 'the edit tool',
},
// Suppress Claude-specific preamble sections that don't apply to OpenClaw
suppressedResolvers: [
'DESIGN_OUTSIDE_VOICES',
'ADVERSARIAL_STEP',
'CODEX_SECOND_OPINION',
'CODEX_PLAN_REVIEW',
'REVIEW_ARMY',
],
runtimeRoot: {
globalSymlinks: ['bin', 'browse/dist', 'browse/bin', 'gstack-upgrade', 'ETHOS.md'],
globalFiles: {
'review': ['checklist.md', 'TODOS-format.md'],
},
},
install: {
prefixable: false,
linkingStrategy: 'symlink-generated',
},
coAuthorTrailer: 'Co-Authored-By: OpenClaw Agent <agent@openclaw.ai>',
learningsMode: 'basic',
// SOUL.md ships as a static file alongside generated skills
staticFiles: {
'SOUL.md': 'openclaw/SOUL.md',
},
adapter: './scripts/host-adapters/openclaw-adapter',
};
export default openclaw;
+45
View File
@@ -0,0 +1,45 @@
/**
* OpenClaw host adapter — post-processing content transformer.
*
* Runs AFTER generic frontmatter/path/tool rewrites from the config system.
* Handles semantic transformations that string-replace can't cover:
*
* 1. AskUserQuestion → prose instructions (tool call → "ask the user")
* 2. Agent spawning → sessions_spawn patterns
* 3. Browse binary patterns ($B → browser/exec)
* 4. Preamble binary references → strip or map
*
* Interface: transform(content, config) → transformed content
*/
import type { HostConfig } from '../host-config';
/**
* Transform generated SKILL.md content for OpenClaw compatibility.
* Called after all generic rewrites (paths, tools, frontmatter) have been applied.
*/
export function transform(content: string, _config: HostConfig): string {
let result = content;
// 1. AskUserQuestion references → prose
result = result.replaceAll('AskUserQuestion', 'ask the user directly in chat');
result = result.replaceAll('Use AskUserQuestion', 'Ask the user directly');
result = result.replaceAll('use AskUserQuestion', 'ask the user directly');
// 2. Agent tool references → sessions_spawn
result = result.replaceAll('the Agent tool', 'sessions_spawn');
result = result.replaceAll('Agent tool', 'sessions_spawn');
result = result.replaceAll('subagent_type', 'task parameter');
// 3. Browse binary patterns
result = result.replaceAll('`$B ', '`exec $B ');
// 4. Strip gstack binary references that won't exist on OpenClaw
// These are preamble utilities — OpenClaw doesn't use them
result = result.replace(/~\/\.openclaw\/skills\/gstack\/bin\/gstack-[\w-]+/g, (match) => {
// Keep the reference but note it as exec-based
return match;
});
return result;
}