diff --git a/bin/install.js b/bin/install.js
index 62792da60..93d909ed1 100755
--- a/bin/install.js
+++ b/bin/install.js
@@ -567,6 +567,8 @@ function convertClaudeToCopilotContent(content, isGlobal = false) {
c = c.replace(/\.claude\//g, '.github/');
// CONV-07: Command name conversion (all gsd: references → gsd-)
c = c.replace(/gsd:/g, 'gsd-');
+ // Runtime-neutral agent name replacement (#766)
+ c = neutralizeAgentReferences(c, 'copilot-instructions.md');
return c;
}
@@ -657,6 +659,8 @@ function convertClaudeToAntigravityContent(content, isGlobal = false) {
c = c.replace(/\.claude\//g, '.agent/');
// Command name conversion (all gsd: references → gsd-)
c = c.replace(/gsd:/g, 'gsd-');
+ // Runtime-neutral agent name replacement (#766)
+ c = neutralizeAgentReferences(c, 'GEMINI.md');
return c;
}
@@ -867,6 +871,8 @@ function convertSlashCommandsToCodexSkillMentions(content) {
function convertClaudeToCodexMarkdown(content) {
let converted = convertSlashCommandsToCodexSkillMentions(content);
converted = converted.replace(/\$ARGUMENTS\b/g, '{{GSD_ARGS}}');
+ // Runtime-neutral agent name replacement (#766)
+ converted = neutralizeAgentReferences(converted, 'AGENTS.md');
return converted;
}
@@ -1175,6 +1181,36 @@ function installCodexConfig(targetDir, agentsSrc) {
* Terminals don't support subscript — Gemini renders these as raw HTML.
* Converts text to italic *(text)* for readable terminal output.
*/
+/**
+ * Runtime-neutral agent name and instruction file replacement.
+ * Used by ALL non-Claude runtime converters to avoid Claude-specific
+ * references in workflow prompts, agent definitions, and documentation.
+ *
+ * Replaces:
+ * - Standalone "Claude" (agent name) → "the agent"
+ * Preserves: "Claude Code" (product), "Claude Opus/Sonnet/Haiku" (models),
+ * "claude-" (prefixes), "CLAUDE.md" (handled separately)
+ * - "CLAUDE.md" → runtime-appropriate instruction file
+ * - "Do NOT load full AGENTS.md" → removed (harmful for AGENTS.md runtimes)
+ *
+ * @param {string} content - File content to neutralize
+ * @param {string} instructionFile - Runtime's instruction file ('AGENTS.md', 'GEMINI.md', etc.)
+ * @returns {string} Content with runtime-neutral references
+ */
+function neutralizeAgentReferences(content, instructionFile) {
+ let c = content;
+ // Replace standalone "Claude" (the agent) but preserve product/model names.
+ // Negative lookahead avoids: Claude Code, Claude Opus/Sonnet/Haiku, Claude native, Claude-based
+ c = c.replace(/\bClaude(?! Code| Opus| Sonnet| Haiku| native| based|-)\b(?!\.md)/g, 'the agent');
+ // Replace CLAUDE.md with runtime-appropriate instruction file
+ if (instructionFile) {
+ c = c.replace(/CLAUDE\.md/g, instructionFile);
+ }
+ // Remove instructions that conflict with AGENTS.md-based runtimes
+ c = c.replace(/Do NOT load full `AGENTS\.md` files[^\n]*/g, '');
+ return c;
+}
+
function stripSubTags(content) {
return content.replace(/(.*?)<\/sub>/g, '*($1)*');
}
@@ -1279,7 +1315,9 @@ function convertClaudeToGeminiAgent(content) {
// is equivalent bash and invisible to Gemini's /\$\{(\w+)\}/g regex.
const escapedBody = body.replace(/\$\{(\w+)\}/g, '$$$1');
- return `---\n${newFrontmatter}\n---${stripSubTags(escapedBody)}`;
+ // Runtime-neutral agent name replacement (#766)
+ const neutralBody = neutralizeAgentReferences(escapedBody, 'GEMINI.md');
+ return `---\n${newFrontmatter}\n---${stripSubTags(neutralBody)}`;
}
function convertClaudeToOpencodeFrontmatter(content, { isAgent = false } = {}) {
@@ -1295,6 +1333,8 @@ function convertClaudeToOpencodeFrontmatter(content, { isAgent = false } = {}) {
convertedContent = convertedContent.replace(/\$HOME\/\.claude\b/g, '$HOME/.config/opencode');
// Replace general-purpose subagent type with OpenCode's equivalent "general"
convertedContent = convertedContent.replace(/subagent_type="general-purpose"/g, 'subagent_type="general"');
+ // Runtime-neutral agent name replacement (#766)
+ convertedContent = neutralizeAgentReferences(convertedContent, 'AGENTS.md');
// Check if content has frontmatter
if (!convertedContent.startsWith('---')) {
@@ -3319,6 +3359,7 @@ if (process.env.GSD_TEST_MODE) {
installCodexConfig,
convertClaudeCommandToCodexSkill,
convertClaudeToOpencodeFrontmatter,
+ neutralizeAgentReferences,
GSD_CODEX_MARKER,
CODEX_AGENT_SANDBOX,
getDirName,
diff --git a/tests/runtime-converters.test.cjs b/tests/runtime-converters.test.cjs
index 5da337310..0dc33cd11 100644
--- a/tests/runtime-converters.test.cjs
+++ b/tests/runtime-converters.test.cjs
@@ -17,6 +17,7 @@ process.env.GSD_TEST_MODE = '1';
const {
convertClaudeToOpencodeFrontmatter,
convertClaudeToGeminiAgent,
+ neutralizeAgentReferences,
} = require('../bin/install.js');
// Sample Claude agent frontmatter (matches actual GSD agent format)
@@ -183,3 +184,56 @@ Use \${PHASE} in shell examples.
assert.ok(!result.includes('${PHASE}'), 'removes Gemini template-string pattern');
});
});
+
+// ─── neutralizeAgentReferences (#766) ─────────────────────────────────────────
+
+describe('neutralizeAgentReferences', () => {
+ test('replaces standalone Claude with "the agent"', () => {
+ const input = 'Claude handles these decisions. Claude should read the file.';
+ const result = neutralizeAgentReferences(input, 'AGENTS.md');
+ assert.ok(!result.includes('Claude handles'), 'standalone Claude replaced');
+ assert.ok(result.includes('the agent handles'), 'replaced with "the agent"');
+ });
+
+ test('preserves Claude Code (product name)', () => {
+ const input = 'This is a Claude Code bug. Use Claude Code settings.';
+ const result = neutralizeAgentReferences(input, 'AGENTS.md');
+ assert.ok(result.includes('Claude Code bug'), 'Claude Code preserved');
+ assert.ok(result.includes('Claude Code settings'), 'Claude Code preserved');
+ });
+
+ test('preserves Claude model names', () => {
+ const input = 'Use Claude Opus for planning. Claude Sonnet for execution. Claude Haiku for research.';
+ const result = neutralizeAgentReferences(input, 'AGENTS.md');
+ assert.ok(result.includes('Claude Opus'), 'Opus preserved');
+ assert.ok(result.includes('Claude Sonnet'), 'Sonnet preserved');
+ assert.ok(result.includes('Claude Haiku'), 'Haiku preserved');
+ });
+
+ test('replaces CLAUDE.md with runtime instruction file', () => {
+ const input = 'Read CLAUDE.md for project instructions. Check ./CLAUDE.md if exists.';
+ const result = neutralizeAgentReferences(input, 'AGENTS.md');
+ assert.ok(result.includes('AGENTS.md'), 'CLAUDE.md -> AGENTS.md');
+ assert.ok(!result.includes('CLAUDE.md'), 'no CLAUDE.md remains');
+ });
+
+ test('uses different instruction file per runtime', () => {
+ const input = 'Read CLAUDE.md for instructions.';
+ assert.ok(neutralizeAgentReferences(input, 'GEMINI.md').includes('GEMINI.md'));
+ assert.ok(neutralizeAgentReferences(input, 'copilot-instructions.md').includes('copilot-instructions.md'));
+ assert.ok(neutralizeAgentReferences(input, 'AGENTS.md').includes('AGENTS.md'));
+ });
+
+ test('removes AGENTS.md load-blocking instruction', () => {
+ const input = 'Do NOT load full `AGENTS.md` files — they contain agent definitions.';
+ const result = neutralizeAgentReferences(input, 'AGENTS.md');
+ assert.ok(!result.includes('Do NOT load full'), 'blocking instruction removed');
+ });
+
+ test('preserves claude- prefixes (CSS classes, package names)', () => {
+ const input = 'The claude-ctx session and claude-code package.';
+ const result = neutralizeAgentReferences(input, 'AGENTS.md');
+ assert.ok(result.includes('claude-ctx'), 'claude- prefix preserved');
+ assert.ok(result.includes('claude-code'), 'claude-code preserved');
+ });
+});