一键导入
add-new-agent-support
Add a new agent (tool) support to agent-command-sync following the registry pattern
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Add a new agent (tool) support to agent-command-sync following the registry pattern
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | add-new-agent-support |
| description | Add a new agent (tool) support to agent-command-sync following the registry pattern |
You are adding a new agent support to agent-command-sync. Follow this guide step by step.
All conversions use a hub-and-spoke architecture via SemanticIR. No pairwise converters are needed — implementing a single pair of toIR() / fromIR() automatically enables bidirectional conversion with all existing agents.
Source Format → Parser → toIR() → SemanticIR → fromIR() → Target Format
Agent-specific logic is colocated in a single agent class that implements the AgentDefinition interface and is centrally managed via AGENT_REGISTRY: Record<ProductType, AgentDefinition>. Adding a value to PRODUCT_TYPES will trigger a compile error if the registry is missing a corresponding entry.
src/types/intermediate.tsAdd the new agent name to the PRODUCT_TYPES array. ProductType is automatically derived.
// Before
export const PRODUCT_TYPES = ["claude", "gemini", "codex", "opencode"] as const;
// After
export const PRODUCT_TYPES = ["claude", "gemini", "codex", "opencode", "newagent"] as const;
This change alone will trigger a compile error if
AGENT_REGISTRYis missing an entry for the new agent.
src/types/command.tsAdd an agent-specific command type.
export interface NewAgentCommand {
// Define according to the agent's command file structure
frontmatter?: Record<string, unknown>; // If YAML frontmatter is used
content: string;
filePath: string;
}
src/types/skill.tsAdd an agent-specific skill type. The standard approach is to extend SkillBase.
export interface NewAgentSkill extends SkillBase {
frontmatter: {
name?: string;
description?: string;
[key: string]: unknown;
};
// Add agent-specific settings here
}
src/types/index.tsuses wildcard exports (export *), so adding types to command.ts / skill.ts automatically re-exports them. No changes needed.
src/agents/newagent.ts (new file)Create a single agent class that implements all interfaces: AgentConfig, BodyParser, CommandParser, CommandConverter, SkillParser, and SkillConverter. Each agent has one file (e.g., claude.ts, gemini.ts, codex.ts, opencode.ts).
import type { BodySegment } from "../types/body-segment.js";
import type { NewAgentCommand, NewAgentSkill } from "../types/index.js";
import type { ConverterOptions, SemanticIR } from "../types/semantic-ir.js";
import { parseBody, serializeBody } from "../utils/body-segment-utils.js";
import type {
AgentDefinition,
BodyParser,
CommandConverter,
CommandParser,
SkillConverter,
SkillParser,
} from "./types.js";
export class NewAgentAgent
implements
AgentDefinition,
BodyParser,
CommandParser<NewAgentCommand>,
CommandConverter<NewAgentCommand>,
SkillParser<NewAgentSkill>,
SkillConverter<NewAgentSkill>
{
// ── AgentConfig ───────────────────────────────────────────────────
readonly displayName = "NewAgent"; // human-readable name (used in CLI help)
readonly dirs = {
commandSubdir: "commands", // or "prompts" etc.
skillSubdir: "skills",
projectBase: ".newagent", // project root relative
userDefault: ".newagent", // homedir relative (e.g. ".config/newagent")
};
readonly fileExtension = ".md"; // or ".toml"
// ── BodyParser ────────────────────────────────────────────────────
parseBody(body: string): BodySegment[] {
// If using Claude-syntax placeholders, import from _claude-syntax-body-patterns.ts:
// import { CLAUDE_SYNTAX_PATTERNS } from "./_claude-syntax-body-patterns.js";
// return parseBody(body, CLAUDE_SYNTAX_PATTERNS);
// If using unique syntax, define custom PatternDef[] in this file.
return parseBody(body, /* patterns */);
}
serializeBody(segments: BodySegment[]): string {
// If using Claude-syntax placeholders:
// import { CLAUDE_SYNTAX_SERIALIZERS } from "./_claude-syntax-body-patterns.js";
// return serializeBody(segments, CLAUDE_SYNTAX_SERIALIZERS);
// Optionally pass an UNSUPPORTED set as the third argument.
return serializeBody(segments, /* serializers */);
}
// ── CommandParser ─────────────────────────────────────────────────
async parseCommand(filePath: string): Promise<NewAgentCommand> {
// Read and parse a command file into the agent-specific type
}
validateCommand(data: NewAgentCommand): boolean {
// Validate the data
}
stringifyCommand(command: NewAgentCommand): string {
// Convert the agent-specific type to file content string
}
// ── CommandConverter ──────────────────────────────────────────────
commandToIR(source: NewAgentCommand, _options?: ConverterOptions): SemanticIR {
// description → ir.semantic.description
// body → this.parseBody(...)
// other fields → ir.extras
}
commandFromIR(ir: SemanticIR, options?: ConverterOptions): NewAgentCommand {
// ir.semantic.description → agent-specific field
// ir.body → this.serializeBody(...)
// ir.extras → pass through (or skip with removeUnsupported)
}
// ── SkillParser ───────────────────────────────────────────────────
async parseSkill(dirPath: string): Promise<NewAgentSkill> {
// Read from a skill directory (SKILL.md + support files)
}
validateSkill(data: NewAgentSkill): boolean {
// Validate the data
}
stringifySkill(skill: NewAgentSkill): string {
// Convert to SKILL.md format
}
async writeSkillToDirectory(
skill: NewAgentSkill,
sourceDirPath: string,
targetDir: string,
): Promise<void> {
// Write a skill to a directory (SKILL.md + support files)
}
// ── SkillConverter ────────────────────────────────────────────────
skillToIR(source: NewAgentSkill, _options?: ConverterOptions): SemanticIR {
// Similar to commandToIR, with additional handling for:
// - modelInvocationEnabled semantic property (from disable-model-invocation)
}
skillFromIR(ir: SemanticIR, options?: ConverterOptions): NewAgentSkill {
// Similar to commandFromIR, with:
// - CLAUDE_SKILL_FIELDS for removeUnsupported filtering
// - Extras are passed through as-is (no prefixing)
}
}
export function createNewAgentAgent(): AgentDefinition {
return new NewAgentAgent();
}
Body patterns:
CLAUDE_SYNTAX_PATTERNS and CLAUDE_SYNTAX_SERIALIZERS from _claude-syntax-body-patterns.tsPatternDef[] and PlaceholderSerializers in the agent file (see gemini.ts for an example)CLAUDE_COMMAND_FIELDS: Define the list of fields not supported by the target.
// Example: OpenCode supports model, so only allowed-tools and argument-hint
const CLAUDE_COMMAND_FIELDS = ["allowed-tools", "argument-hint"] as const;
// Example: Codex doesn't support model either, so three fields
const CLAUDE_COMMAND_FIELDS = ["allowed-tools", "argument-hint", "model"] as const;
CLAUDE_SKILL_FIELDS: List of Claude-specific skill fields not supported by the target. These fields are passed through as-is when removeUnsupported=false (default), and removed when removeUnsupported=true. Include disable-model-invocation in this list. Additional considerations:
modelInvocationEnabled: A semantic property. Bidirectionally converted with Claude's disable-model-invocation (inverted) and Codex's allow_implicit_invocationSkill parser checklist:
isSkillDirectory()collectSupportFiles()agents/openai.yaml)src/agents/registry.tsAdd an entry to the registry.
import { createNewAgentAgent } from "./newagent.js";
export const AGENT_REGISTRY: Record<ProductType, AgentDefinition> = {
claude: createClaudeAgent(),
gemini: createGeminiAgent(),
codex: createCodexAgent(),
opencode: createOpenCodeAgent(),
newagent: createNewAgentAgent(), // Add this
};
That's all — no changes to sync.ts / file-utils.ts are needed. The registry lookup automatically integrates into all sync operations.
src/cli/index.ts dynamically generates CLI options (--xxx-dir), description, and customDirs mapping from PRODUCT_TYPES and AGENT_REGISTRY. No changes needed.
Optionally, you can add usage examples for the new agent in the help examples section.
src/agents/index.tsAdd re-export for the new agent.
export * from "./newagent.js";
src/index.tsre-exportssrc/agents/index.tsviaexport * from "./agents/index.js", so no additional changes needed there.
tests/fixtures/)tests/fixtures/newagent-commands/tests/fixtures/newagent-skills/test-skill/SKILL.md| File | Test Coverage |
|---|---|
tests/parsers/newagent-command-parser.test.ts | parseCommand, validateCommand, stringifyCommand |
tests/parsers/newagent-skill-parser.test.ts | parseSkill, validateSkill, stringifySkill, writeSkillToDirectory |
| File | Tests to Add |
|---|---|
tests/utils/body-segment-utils.test.ts | parseBody / serializeBody with new agent's patterns |
tests/converters/command-conversion.test.ts | Other agents ↔ NewAgent conversion |
tests/converters/skill-conversion.test.ts | Other agents ↔ NewAgent skill conversion |
tests/integration/cli.test.ts | End-to-end conversion tests |
tests/utils/file-utils.test.tsandtests/agents/registry.test.tsuseAGENT_REGISTRY, so simply adding to the registry will automatically be covered by existing tests.
CLAUDE.mdUpdate the following sections:
README.md / README_ja.mdUpdate the following sections:
--src / --dest description, add --newagent-dir option)Source:
src/agents/newagent.ts — Agent class (body + command + skill parsing/conversion)Tests:
tests/parsers/newagent-command-parser.test.tstests/parsers/newagent-skill-parser.test.tstests/fixtures/newagent-commands/*.md (or .toml)tests/fixtures/newagent-skills/test-skill/SKILL.mdSource:
src/types/intermediate.ts — Add to PRODUCT_TYPESsrc/types/command.ts — New command type (optional: existing types may suffice)src/types/skill.ts — New skill type (optional: existing types may suffice)src/agents/registry.ts — Add registry entrysrc/agents/index.ts — Add re-exportTests:
tests/utils/body-segment-utils.test.tstests/converters/command-conversion.test.tstests/converters/skill-conversion.test.tstests/integration/cli.test.tsDocumentation:
CLAUDE.md (If it exists)README.mdREADME_ja.mdsrc/types/index.ts — Wildcard exports automatically re-export new typessrc/index.ts — Re-exports src/agents/index.ts via wildcardsrc/cli/index.ts — CLI options dynamically generated from PRODUCT_TYPES / AGENT_REGISTRYsrc/cli/sync.tssrc/utils/file-utils.tssrc/cli/options.tstests/utils/file-utils.test.tstests/agents/registry.test.tstests/fixtures/fixtures.test.tspnpm verify && pnpm build