بنقرة واحدة
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