Skip to content

Make ig ai-config agent-agnostic instead of hard-coding .claude/skills#1664

Open
Copilot wants to merge 23 commits intomasterfrom
copilot/update-ai-config-agent-agnostic
Open

Make ig ai-config agent-agnostic instead of hard-coding .claude/skills#1664
Copilot wants to merge 23 commits intomasterfrom
copilot/update-ai-config-agent-agnostic

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 24, 2026

ig ai-config hard-coded .claude/skills as the only skill destination. The CLI positions this as general AI tooling, but the implementation only supported Claude Code.

Core (packages/core/util/ai-skills.ts)

  • Add AIAgentTarget type: claude | copilot | cursor | codex | windsurf | gemini | junie | generic
  • Add AI_AGENT_SKILLS_DIRS mapping each agent to its conventional skills directory
  • Add getSkillsDir(target?) resolver
  • copyAISkillsToProject(skillsDir?) now accepts an optional output directory; defaults to .claude/skills for backward compat

CLI (packages/cli/lib/commands/ai-config.ts)

  • --agent (-a) — pick a known agent target
  • --skills-dir (-d) — arbitrary path, overrides --agent
  • configureSkills() and configure() thread through the resolved directory

Angular Schematics (packages/ng-schematics/src/cli-config)

  • ai-config schematic now accepts agent and skillsDir options, matching the CLI command behavior
  • Added ai-config-schema.json with agent (enum of supported targets) and skillsDir (custom path) properties
  • Updated collection.json to reference the schema
  • addAIConfig() resolves skillsDir from agent/skillsDir options (skillsDir overrides agent)
  • aiConfig() passes the resolved directory through to copyAISkillsToProject()

Agent → directory mapping

Agent Directory
claude .claude/skills
copilot .github/skills
cursor .cursor/skills
codex .codex/skills
windsurf .windsurf/skills
gemini .gemini/skills
junie .junie/skills
generic .agents/skills

Usage

ig ai-config                         # default (.claude/skills)
ig ai-config --agent cursor          # .cursor/skills
ig ai-config --agent generic         # .agents/skills
ig ai-config --skills-dir my/path    # custom

Tests

15 new core specs covering agent-aware destinations, getSkillsDir() for each target, custom paths, and the AI_AGENT_SKILLS_DIRS shape. 6 new schematic specs verifying agent/skillsDir option resolution and passthrough. Existing tests pass unchanged — no-arg calls still write to .claude/skills.

Copilot AI and others added 2 commits April 24, 2026 07:42
…ions

- Add AIAgentTarget type and AI_AGENT_SKILLS_DIRS mapping for claude,
  copilot, cursor, codex, windsurf, gemini, junie, and generic agents
- Add getSkillsDir() utility to resolve agent name to skills directory
- Accept optional skillsDir parameter in copyAISkillsToProject()
- Add --agent (-a) and --skills-dir (-d) CLI options to ig ai-config
- Default to .claude/skills for backward compatibility when no option given
- Add 15 new unit tests for agent-aware destinations and getSkillsDir

Agent-Logs-Url: https://github.com/IgniteUI/igniteui-cli/sessions/6ffa80e2-ee1c-4982-8606-c428fb045137

Co-authored-by: kdinev <1472513+kdinev@users.noreply.github.com>
Copilot AI changed the title [WIP] Make ig ai-config agent-agnostic instead of hard-coding .claude/skills Make ig ai-config agent-agnostic instead of hard-coding .claude/skills Apr 24, 2026
Copilot AI requested a review from kdinev April 24, 2026 07:46
@Marina-L-Stoyanova
Copy link
Copy Markdown
Contributor

@copilot Update angular schematics to accepts an optional output directory, when copying the skills. The ai-config schematic should work same as ai-config cli command

…lls-dir options

- Add ai-config-schema.json with agent and skillsDir properties
- Update collection.json to reference the schema
- Update aiConfig() to accept and pass through skillsDir
- Update addAIConfig() to resolve skillsDir from agent/skillsDir options
- Add 6 new schematic tests verifying agent-aware skill copy

Agent-Logs-Url: https://github.com/IgniteUI/igniteui-cli/sessions/235a5b72-55c7-4dda-a33d-47abfb77073e

Co-authored-by: Marina-L-Stoyanova <6087266+Marina-L-Stoyanova@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 24, 2026

@copilot Update angular schematics to accepts an optional output directory, when copying the skills. The ai-config schematic should work same as ai-config cli command

Done in d4478a9. The ai-config schematic now accepts --agent and --skillsDir options, matching the CLI command behavior:

  • Added ai-config-schema.json with agent (enum of supported targets) and skillsDir (custom path) properties
  • Updated collection.json to reference the schema
  • addAIConfig() resolves skillsDir from agent/skillsDir options (with skillsDir overriding agent)
  • aiConfig() passes the resolved directory through to copyAISkillsToProject()
  • Added 6 schematic tests verifying: default (no args), agent-based resolution (cursor, copilot, generic), custom skillsDir, and skillsDir overriding agent

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • www.google-analytics.com
    • Triggering command: /usr/local/bin/node node packages/cli/bin/execute.js new --help de_modules/.bin/tsx (dns block)
    • Triggering command: /usr/local/bin/node node packages/cli/bin/execute.js config --help (dns block)
    • Triggering command: /usr/local/bin/node node packages/cli/bin/execute.js generate --help (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@Marina-L-Stoyanova Marina-L-Stoyanova marked this pull request as ready for review April 24, 2026 11:11
Copilot AI review requested due to automatic review settings April 24, 2026 11:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates ig ai-config to support multiple AI agents by resolving agent-specific (or custom) skills destination directories instead of always writing to .claude/skills.

Changes:

  • Core: add agent target type + agent→directory mapping, getSkillsDir(), and allow copyAISkillsToProject() to accept an optional output directory (defaulting to .claude/skills).
  • CLI: add --agent / --skills-dir options and thread the resolved directory through skills configuration.
  • Angular schematics: add ai-config schema/options for agent/skillsDir, pass resolved directory through, and add schematic specs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/core/util/ai-skills.ts Introduces agent targets + mapping + resolver; makes skills copy destination configurable.
packages/cli/lib/commands/ai-config.ts Adds CLI flags to select agent/custom directory and passes destination into core copy routine.
packages/ng-schematics/src/cli-config/index.ts Adds schematic options and resolves skillsDir from agent/skillsDir.
packages/ng-schematics/src/cli-config/ai-config-schema.json Defines schema for agent enum and skillsDir override.
packages/ng-schematics/src/collection.json Wires the new schema into the ai-config schematic entry.
packages/ng-schematics/src/cli-config/index_spec.ts Adds tests validating option resolution and passthrough behavior.
spec/unit/ai-skills-spec.ts Adds core unit coverage for agent-aware destinations, resolver, and mapping shape.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/util/ai-skills.ts Outdated
Comment on lines +12 to +34
const DEFAULT_SKILLS_DIR = ".claude/skills";
const SKILLS_DIR_TEMPLATE = "__dot__claude/skills";

export type AIAgentTarget = "claude" | "copilot" | "cursor" | "codex" | "windsurf" | "gemini" | "junie" | "generic";

export const AI_AGENT_SKILLS_DIRS: Record<AIAgentTarget, string> = {
claude: ".claude/skills",
copilot: ".github/skills",
cursor: ".cursor/skills",
codex: ".codex/skills",
windsurf: ".windsurf/skills",
gemini: ".gemini/skills",
junie: ".junie/skills",
generic: ".agents/skills"
};

/**
* Returns the project-level skills directory for the given AI agent target.
* Falls back to `.claude/skills` when no target is specified.
*/
export function getSkillsDir(target?: AIAgentTarget): string {
return AI_AGENT_SKILLS_DIRS[target ?? "claude"];
}
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEFAULT_SKILLS_DIR duplicates the value of AI_AGENT_SKILLS_DIRS.claude, and the fallback logic is split between copyAISkillsToProject and getSkillsDir. This makes it easy for the defaults to drift if one is updated later. Consider deriving the default from a single source (e.g., set AI_AGENT_SKILLS_DIRS.claude = DEFAULT_SKILLS_DIR and/or have copyAISkillsToProject default to getSkillsDir()).

Copilot uses AI. Check for mistakes.
Comment thread packages/core/util/ai-skills.ts Outdated
Comment on lines 102 to 132
@@ -102,8 +127,8 @@ export function copyAISkillsToProject(): AISkillsCopyResult {
const normRoot = skillsRoot.replace(/\\/g, "/").replace(/^\//, "");
const rel = path.posix.relative(normRoot, normP);
const dest = multiRoot
? `${CLAUDE_SKILLS_DIR}/${pkgDirName}/${rel}`
: `${CLAUDE_SKILLS_DIR}/${rel}`;
? `${outputDir}/${pkgDirName}/${rel}`
: `${outputDir}/${rel}`;

Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outputDir is concatenated into destination paths without normalization. If callers pass a trailing slash (e.g. .cursor/skills/ or custom/path/) or Windows-style separators, this can produce paths with // or mixed separators, which may break fileExists checks (especially for virtual FS implementations) and lead to duplicate writes. Consider normalizing outputDir (convert \\/, trim trailing /) and building dest via a join helper to ensure consistent paths.

Copilot uses AI. Check for mistakes.
…llsDir handling

Co-authored-by: Copilot <copilot@github.com>
Comment thread packages/core/util/ai-skills.ts Fixed
@coveralls
Copy link
Copy Markdown

coveralls commented Apr 27, 2026

Coverage Status

coverage: 85.857% (-0.4%) from 86.279% — copilot/update-ai-config-agent-agnostic into master

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/cli/lib/commands/ai-config.ts Outdated
Comment on lines +60 to +79
let skillsDir = argv.skillsDir as string | undefined;

if (!skillsDir) {
let agent = argv.agent as AIAgentTarget | undefined;

if (!agent) {
agent = await InquirerWrapper.select({
message: "Which AI agent are you using?",
choices: AI_AGENT_CHOICES
}) as AIAgentTarget;
}

GoogleAnalytics.post({
t: "event",
ec: "$ig ai-config",
ea: `agent: ${agent}`
});

skillsDir = getSkillsDir(agent);
}
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When --skills-dir is provided, the handler skips posting the $ig ai-config analytics event entirely (only the screenview is sent). If telemetry for this command is expected to be consistent regardless of flags, move the event post outside the if (!skillsDir) block and avoid sending the raw custom path (e.g., record a boolean like customSkillsDir: true and/or the selected agent when present).

Copilot uses AI. Check for mistakes.
Comment thread packages/core/util/ai-skills.ts Outdated
Comment on lines +12 to +16
const SKILLS_DIR_TEMPLATE = "__dot__claude/skills";

export type AIAgentTarget = "claude" | "copilot" | "cursor" | "codex" | "windsurf" | "gemini" | "junie" | "generic";

export const AI_AGENT_SKILLS_DIRS: Record<AIAgentTarget, string> = {
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SKILLS_DIR_TEMPLATE is still hard-coded to __dot__claude/skills, but the new name no longer reflects that Claude-specific meaning. This is likely to confuse future maintainers (it reads like a generic template path). Consider renaming it back to something Claude-specific (e.g., CLAUDE_SKILLS_DIR_TEMPLATE) or to a name that clarifies it's the source template location used for fallback discovery.

Copilot uses AI. Check for mistakes.
Comment on lines 259 to +271
describe("handler", () => {
it("posts analytics and calls configure", async () => {
it("prompts for agent when neither --agent nor --skills-dir is provided", async () => {
App.container.set(FS_TOKEN, createMockFs());
spyOn(InquirerWrapper, "select").and.returnValue(Promise.resolve("claude"));

await aiConfig.default.handler({ _: ["ai-config"], $0: "ig" });

expect(Util.log).toHaveBeenCalledWith(jasmine.stringContaining("MCP servers configured"));
expect(InquirerWrapper.select).toHaveBeenCalledWith(jasmine.objectContaining({
message: "Which AI agent are you using?"
}));
expect(GoogleAnalytics.post).toHaveBeenCalledWith(jasmine.objectContaining({ t: "screenview", cd: "MCP" }));
expect(GoogleAnalytics.post).toHaveBeenCalledWith(jasmine.objectContaining({ t: "event", ec: "$ig ai-config" }));
expect(GoogleAnalytics.post).toHaveBeenCalledWith(jasmine.objectContaining({ t: "event", ea: "agent: claude" }));
});
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test asserts that ig ai-config (no flags) prompts for an agent. That behavior contradicts the PR description/usage examples stating no-arg should default to .claude/skills for backward compatibility, and it makes the command non-scriptable in non-interactive contexts. If the intended behavior is to default to Claude without prompting, update the handler and adjust this test to verify the non-interactive default instead of expecting a prompt.

Copilot uses AI. Check for mistakes.
Comment thread packages/cli/lib/commands/ai-config.ts Outdated
Comment on lines +62 to +70
if (!skillsDir) {
let agent = argv.agent as AIAgentTarget | undefined;

if (!agent) {
agent = await InquirerWrapper.select({
message: "Which AI agent are you using?",
choices: AI_AGENT_CHOICES
}) as AIAgentTarget;
}
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CLI now prompts via Inquirer when neither --agent nor --skills-dir is provided. This changes the documented/expected no-arg behavior (PR description says ig ai-config should default to .claude/skills) and can hang in non-interactive environments (CI/scripts). Consider defaulting agent to "claude" when no flags are provided (preserving prior behavior) and only prompting when an explicit interactive mode is requested or when running in a TTY and the user opted into prompting.

Copilot uses AI. Check for mistakes.
… Google Analytics event tracking

Co-authored-by: Copilot <copilot@github.com>
Comment on lines +43 to +53
.option("agent", {
alias: "a",
describe: "AI agent to configure skills for (determines the target skills directory)",
choices: AI_AGENT_CHOICES,
type: "string"
})
.option("skills-dir", {
alias: "d",
describe: "Custom skills directory path (overrides --agent)",
type: "string"
}),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we roll that option into one thing? Kinda odd to be able to pass both - like --agent claude --dir .github/skills

… updating skills directory handling

Co-authored-by: Copilot <copilot@github.com>
Marina-L-Stoyanova and others added 11 commits April 28, 2026 13:03
…and remove skillsDir option

Co-authored-by: Copilot <copilot@github.com>
…o copilot/update-ai-config-agent-agnostic
Co-authored-by: Copilot <copilot@github.com>
… logic that extracts skills from the templates

Co-authored-by: Copilot <copilot@github.com>
…ction logic

Co-authored-by: Copilot <copilot@github.com>
…rompt messages for Angular schematics

Co-authored-by: Copilot <copilot@github.com>
…d updating agent selection logic

Co-authored-by: Copilot <copilot@github.com>
Marina-L-Stoyanova and others added 4 commits May 4, 2026 15:07
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
…uction file generation

Co-authored-by: Copilot <copilot@github.com>
Comment on lines +32 to +33
public static async checkbox(message: InputConfig & { choices: (string | { value: string; name?: string; checked?: boolean } | Separator)[] }, context?: Context): Promise<string[]> {
return checkbox(message as any, context);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual type from package is:

choices: readonly (string | Separator)[] | readonly (Separator | Choice<Value>)[];

so either strings + separators or objects+separators, but not a mix like this describes, which is why it'd complain and the as any had to be put in :). If you split the conditionals correctly it'll match just fine.

On a side note, this wrapper is pretty useless and the typing is only somewhat correct for input and not the rest, so it'd be better to remove it afterwards

Comment thread packages/cli/lib/commands/ai-config.ts Outdated
Comment on lines +29 to +32
export function configure(agents: AIAgentTarget[]): void {
configureMCP();
if (skills) {
configureSkills();
for (const agent of agents) {
configureSkills(getSkillsDir(agent));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect we might still want the options to turn on/off some parts of the config (the skills = true option) but though that's not critical to keep as the flag IIRC was added for new projects from prompt since they had skills baked in the base template, which is no-longer the case. Can be added back as needed.

However, now sure what's the point of calling getSkillsDir(agent) for configureSkills - its not used for anything else useful, so just bake that into the method and call it with the agents to configure just like copyAgentInstructionFiles?

Comment on lines +37 to 54
const AI_AGENT_CHOICES = Object.keys(AI_AGENT_SKILLS_DIRS) as AIAgentTarget[];

const AI_AGENT_CHECKBOX_CHOICES = [
{ value: "none", name: "None (skip AI configuration)" },
...AI_AGENT_CHOICES.map(agent => ({
value: agent,
name: AI_AGENT_LABELS[agent],
checked: agent === "generic" || agent === "claude"
}))
];

export async function promptForAgents(): Promise<AIAgentTarget[]> {
const selected = await InquirerWrapper.checkbox({
message: "Which AI tools do you want to generate configuration files for?",
choices: AI_AGENT_CHECKBOX_CHOICES
});
return selected.includes("none") ? [] : selected as AIAgentTarget[];
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a bit iffy on prompt logic here, in the past it was concentrated behind the prompt class explicitly to contain the prompting solution behind a single facade if you will. The wrapper might be enough good enough for now, but need to see the rest.

Comment on lines +79 to +82
if (!agents.length) {
Util.log("No AI configuration selected. Skipping.");
return;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Erm, is there a case where there is no selection after the prompt? If there's a None option in there, should it not have a required flag to force an option and this check should compare if there's a "none" value selected? Also not sure if we want to skip analytics for this case, so this might need to move after

Comment on lines +174 to +183
let agents = argv.agent as AIAgentTarget[] | undefined;
if (!agents?.length) {
agents = await promptForAgents();
}
if (agents.length) {
process.chdir(argv.name);
configure(agents);
process.chdir("..");
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we might want to wait on the install eventually if we re-arrange functionality, but in the meantime I'd move this before the git init, so the AI configs don't end up as uncommitted changes

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS: Also can we roll the prompt into the call as well, so this is a single function call? Not that important if it causes trouble.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note: Also, if we're changing folders (might combine multiples at some point or parametrize instead) - I know some functionality relies on cwd, but unlike calling install it's not obvious so could use a doc comment for that.

Comment thread packages/cli/lib/PromptSession.ts Outdated
}))
]
});
const agents = selected.includes("none") ? [] : selected as AIAgentTarget[];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, okay so this is a duplicate - either use promptForAgents here or move this into a reusable method to be called in its place. Point being - only need this setup in one place.

Comment on lines +109 to +117
const aiConfigProject = projectLib?.getProject("ai-config");
if (aiConfigProject) {
const filePaths = aiConfigProject.templatePaths ?? [];
roots.push(
...filePaths
.map((p) => path.join(p, "..", "skills"))
.slice(0, 1),
);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhat prefer the old code if we're keeping the ?? [] fallback after which the ... spread, map, etc are no-op if empty anyway and don't need the check:

Suggested change
const aiConfigProject = projectLib?.getProject("ai-config");
if (aiConfigProject) {
const filePaths = aiConfigProject.templatePaths ?? [];
roots.push(
...filePaths
.map((p) => path.join(p, "..", "skills"))
.slice(0, 1),
);
}
const filePaths = projectLib?.getProject("ai-config").templatePaths ?? [];
roots.push(
...filePaths
.map((p) => path.join(p, CLAUDE_SKILLS_DIR_TEMPLATE))
.slice(0, 1),
);

Could consider putting "ai-config" into some overarching const (ideally a symbol but that's likely out of scope)

Comment on lines +130 to +133
let outputDir = skillsDir.replace(/\\/g, "/");
while (outputDir.endsWith("/")) {
outputDir = outputDir.slice(0, -1);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Um, unless we're doing path operations, outputDir comes directly from the AI_AGENT_SKILLS_DIRS map and need no processing.

*/
function resolveAgentsContent(): string | null {
const srcFs = new FsFileSystem();
const skillsRoots = resolveSkillsRoots();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guess we should rename that function? But also its not the same work as it will return node_modules/<package>/skills if possible which doesn't have instructions file, so maybe refactor the bit you need for the project template paths as a separate one?

Comment on lines +196 to +199
const agentsPath = path.join(path.dirname(skillsRoot), "AGENTS.md");
if (srcFs.fileExists(agentsPath)) {
return srcFs.readFile(agentsPath);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And also no need to check there, just attach the "AGENTS.md" (could also be a constant) at the end and carry on. It must be there if the templates are correct and the copy logic will check too as well.

Edit: Oh, saw the copy logic and it doesn't since that's here. More of a getContent then.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which gets me thinking - actually the constants are not optional. Make them. Even if not used in the template itself directly (hard for the file name), make explicit unit tests for those specific templates to exist and this file and skills to be present

Comment on lines +65 to +70
.option("agent", {
alias: "a",
describe: "AI agent(s) to configure skills for (determines the target skills directory)",
choices: AI_AGENT_CHOICES,
type: "array"
})
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on the behavior we want, might set defaults here too

…lls handling

Co-authored-by: Copilot <copilot@github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CLI MCP] Make ig ai-config agent-agnostic instead of hard-coding .claude/skills

7 participants