Skip to content

skill sync: add ar skill sync subcommand with --tool choice and github-copilot/cursor/qoder support#10

Draft
Copilot wants to merge 5 commits into
mainfrom
copilot/add-sync-skills-support
Draft

skill sync: add ar skill sync subcommand with --tool choice and github-copilot/cursor/qoder support#10
Copilot wants to merge 5 commits into
mainfrom
copilot/add-sync-skills-support

Conversation

Copy link
Copy Markdown

Copilot AI commented May 11, 2026

Introduces ar skill sync as a new subcommand of the existing skill group, replacing the previously proposed top-level ar sync-skills command. The command bulk-syncs platform Skills to a local AI tool directory with change-detection and optional cleanup.

Changes

  • ar skill sync — registered under the skill group (not top-level), consistent with the noun-verb CLI model. ar skill --help now lists sync alongside create, list, get, download, delete, scan, load, read-file, exec

  • --tool <choice> option — single required option replacing the old --claude-code / --codex boolean flags; Click Choice validation lists all valid values in --help automatically

  • Five supported tools with conventional directory layouts:

    --tool user path project path
    claude-code ~/.claude/skills .claude/skills
    codex ~/.codex/skills .codex/skills
    github-copilot ~/.github/copilot/skills .github/copilot/skills
    cursor ~/.cursor/skills .cursor/skills
    qoder ~/.qoder/skills .qoder/skills
  • _TOOL_ROOTS dict replaces the if/elif chain in _resolve_target_dir; adding a tool is now one line

  • Tests: 14 tests covering all 5 tools, both scopes, workspace filter, update-skip, delete-unmanaged, and error paths; integration tests invoke via ["skill", "sync", ...]

  • Docs: sync section added to docs/en/skill.md and docs/zh/skill.md; standalone sync-skills.md pages removed; skill row in README/index tables updated to mention sync

# usage
ar skill sync --tool claude-code --user --workspace abc --workspace def
ar skill sync --tool cursor --project -y
ar skill sync --tool github-copilot --user --delete-unmanaged
ar skill sync --tool qoder --project --workspace my-workspace

Copilot AI and others added 4 commits May 11, 2026 03:16
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: OhYee <13498329+OhYee@users.noreply.github.com>
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: OhYee <13498329+OhYee@users.noreply.github.com>
…t/cursor/qoder

Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: OhYee <13498329+OhYee@users.noreply.github.com>
Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: OhYee <13498329+OhYee@users.noreply.github.com>
@Sodawyx
Copy link
Copy Markdown
Contributor

Sodawyx commented May 13, 2026

Suggestion: Move sync-skills under the skill command group

Strong suggestion to make sync-skills a subcommand of the existing skill group (e.g. ar skill sync) rather than introducing it as a new top-level command. Here's the reasoning and a concrete refactor.

Why this matters

  1. Conceptual cohesion. Everything in this PR operates on the same domain object — platform Skills. The skill group already owns the full lifecycle (create, list, get, download, delete, scan, load, read-file, exec). sync is just one more verb on that same noun. Splitting it out at the top level breaks the noun-verb mental model the rest of the CLI follows.

  2. Discoverability. A user who types ar skill --help will see every operation they can perform on skills. With a separate sync-skills command, that user has no signal it even exists unless they read the README. Having to know the existence of both ar skill ... and ar sync-skills ... is friction we don't need to create.

  3. Top-level namespace hygiene. Looking at the README table, every other entry is either a noun (agent, sandbox, tool, skill, super-agent) or an alias for one (sb, sa). sync-skills is the only verb-noun composite at the top level. That asymmetry is a smell. If we later add sync-tools, sync-agents, sync-mcps, the top level will accumulate verb-prefixed siblings of every existing noun group.

  4. Naming consistency. ar skill download already exists and downloads one skill. ar skill sync would naturally read as "download/refresh many skills based on a policy," which is exactly what this PR does. The two commands sit next to each other in --help and the relationship is obvious.

  5. Future extensibility. If we ever want skill-sync to share helpers with skill download (e.g. the metadata extraction, the Tool.get_by_name(...).download_skill(...) call already used here), having them in the same module makes that trivial. Right now sync_skills_cmd.py re-implements _extract_skill_name / _extract_updated_at / _extract_workspace_values next to a very similar _serialize_tool in skill_cmd.py.

Concrete refactor — how to change it

The change is mechanical and small. Roughly:

1. Rename the file (optional but cleaner):

src/agentrun_cli/commands/sync_skills_cmd.py
  → src/agentrun_cli/commands/skill_sync_cmd.py

…or just inline the code into skill_cmd.py since it's only ~317 lines and shares helpers.

2. Change the Click decorator in sync_skills_cmd.py:

# before
@click.command(
    \"sync-skills\",
    help=\"Sync platform skills to a local AI tool skill directory.\",
)
...
def sync_skills(ctx, ai_tool, user_scope, project_scope, ...):

# after
from agentrun_cli.commands.skill_cmd import skill_group

@skill_group.command(
    \"sync\",
    help=\"Sync platform skills to a local AI tool skill directory.\",
)
...
def skill_sync(ctx, ai_tool, user_scope, project_scope, ...):

Or, even cleaner, define the command directly inside skill_cmd.py next to skill_group.command(\"download\") so all skill verbs live in one file.

3. Update src/agentrun_cli/main.py:

# remove this import
from agentrun_cli.commands.sync_skills_cmd import sync_skills

# remove this line
cli.add_command(sync_skills)

That's it — registering it under skill_group is enough; the parent group is already added.

4. Update docs:

  • Delete the standalone docs/en/sync-skills.md and docs/zh/sync-skills.md, or move them under docs/en/skill.md / docs/zh/skill.md as a new "Sync" section.
  • Remove the new row from the command tables in README.md, README_zh.md, docs/en/index.md, docs/zh/index.md — the skill row already covers this.
  • Update the Examples section in docs/en/skill.md (and zh) to add:
    ar skill sync --tool claude-code --user --workspace abc
    

5. Update tests:

  • Rename tests/integration/test_sync_skills_cmd.pytests/integration/test_skill_sync_cmd.py (optional).
  • In each test, change runner.invoke(cli, [\"sync-skills\", ...]) to runner.invoke(cli, [\"skill\", \"sync\", ...]).
  • The same applies to tests/unit/test_sync_skills_cmd.py if it invokes via the CLI runner.

6. Update the PR description / commit message to reflect the new invocation:

# before
ar sync-skills --tool claude-code --user --workspace abc

# after
ar skill sync --tool claude-code --user --workspace abc
ar skill sync --tool cursor --project -y
ar skill sync --tool github-copilot --user --delete-unmanaged

Backward compatibility note

Since this PR is still in Draft and the command has never shipped, there is no backward-compatibility cost — we can rename freely now. If we merge it as sync-skills and rename later, we'd need to keep a deprecated alias, which is exactly the kind of debt worth avoiding by getting the shape right before the first release.

TL;DR

sync-skills belongs under ar skill sync. The refactor is: change one decorator to @skill_group.command(\"sync\"), drop the cli.add_command(sync_skills) line in main.py, fold the docs into skill.md, and update test invocations. No logic changes needed.

@OhYee
Copy link
Copy Markdown
Member

OhYee commented May 13, 2026

Suggestion: Move sync-skills under the skill command group

Strong suggestion to make sync-skills a subcommand of the existing skill group (e.g. ar skill sync) rather than introducing it as a new top-level command. Here's the reasoning and a concrete refactor.

Why this matters

  1. Conceptual cohesion. Everything in this PR operates on the same domain object — platform Skills. The skill group already owns the full lifecycle (create, list, get, download, delete, scan, load, read-file, exec). sync is just one more verb on that same noun. Splitting it out at the top level breaks the noun-verb mental model the rest of the CLI follows.
  2. Discoverability. A user who types ar skill --help will see every operation they can perform on skills. With a separate sync-skills command, that user has no signal it even exists unless they read the README. Having to know the existence of both ar skill ... and ar sync-skills ... is friction we don't need to create.
  3. Top-level namespace hygiene. Looking at the README table, every other entry is either a noun (agent, sandbox, tool, skill, super-agent) or an alias for one (sb, sa). sync-skills is the only verb-noun composite at the top level. That asymmetry is a smell. If we later add sync-tools, sync-agents, sync-mcps, the top level will accumulate verb-prefixed siblings of every existing noun group.
  4. Naming consistency. ar skill download already exists and downloads one skill. ar skill sync would naturally read as "download/refresh many skills based on a policy," which is exactly what this PR does. The two commands sit next to each other in --help and the relationship is obvious.
  5. Future extensibility. If we ever want skill-sync to share helpers with skill download (e.g. the metadata extraction, the Tool.get_by_name(...).download_skill(...) call already used here), having them in the same module makes that trivial. Right now sync_skills_cmd.py re-implements _extract_skill_name / _extract_updated_at / _extract_workspace_values next to a very similar _serialize_tool in skill_cmd.py.

Concrete refactor — how to change it

The change is mechanical and small. Roughly:

1. Rename the file (optional but cleaner):

src/agentrun_cli/commands/sync_skills_cmd.py
  → src/agentrun_cli/commands/skill_sync_cmd.py

…or just inline the code into skill_cmd.py since it's only ~317 lines and shares helpers.

2. Change the Click decorator in sync_skills_cmd.py:

# before
@click.command(
    \"sync-skills\",
    help=\"Sync platform skills to a local AI tool skill directory.\",
)
...
def sync_skills(ctx, ai_tool, user_scope, project_scope, ...):

# after
from agentrun_cli.commands.skill_cmd import skill_group

@skill_group.command(
    \"sync\",
    help=\"Sync platform skills to a local AI tool skill directory.\",
)
...
def skill_sync(ctx, ai_tool, user_scope, project_scope, ...):

Or, even cleaner, define the command directly inside skill_cmd.py next to skill_group.command(\"download\") so all skill verbs live in one file.

3. Update src/agentrun_cli/main.py:

# remove this import
from agentrun_cli.commands.sync_skills_cmd import sync_skills

# remove this line
cli.add_command(sync_skills)

That's it — registering it under skill_group is enough; the parent group is already added.

4. Update docs:

  • Delete the standalone docs/en/sync-skills.md and docs/zh/sync-skills.md, or move them under docs/en/skill.md / docs/zh/skill.md as a new "Sync" section.
  • Remove the new row from the command tables in README.md, README_zh.md, docs/en/index.md, docs/zh/index.md — the skill row already covers this.
  • Update the Examples section in docs/en/skill.md (and zh) to add:
    ar skill sync --tool claude-code --user --workspace abc
    

5. Update tests:

  • Rename tests/integration/test_sync_skills_cmd.pytests/integration/test_skill_sync_cmd.py (optional).
  • In each test, change runner.invoke(cli, [\"sync-skills\", ...]) to runner.invoke(cli, [\"skill\", \"sync\", ...]).
  • The same applies to tests/unit/test_sync_skills_cmd.py if it invokes via the CLI runner.

6. Update the PR description / commit message to reflect the new invocation:

# before
ar sync-skills --tool claude-code --user --workspace abc

# after
ar skill sync --tool claude-code --user --workspace abc
ar skill sync --tool cursor --project -y
ar skill sync --tool github-copilot --user --delete-unmanaged

Backward compatibility note

Since this PR is still in Draft and the command has never shipped, there is no backward-compatibility cost — we can rename freely now. If we merge it as sync-skills and rename later, we'd need to keep a deprecated alias, which is exactly the kind of debt worth avoiding by getting the shape right before the first release.

TL;DR

sync-skills belongs under ar skill sync. The refactor is: change one decorator to @skill_group.command(\"sync\"), drop the cli.add_command(sync_skills) line in main.py, fold the docs into skill.md, and update test invocations. No logic changes needed.

@copilot 改一下

Signed-off-by: GitHub <noreply@github.com>

Co-authored-by: OhYee <13498329+OhYee@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot May 13, 2026 12:23
Copy link
Copy Markdown
Author

Copilot AI commented May 13, 2026

Suggestion: Move sync-skills under the skill command group

Strong suggestion to make sync-skills a subcommand of the existing skill group (e.g. ar skill sync) rather than introducing...

Done in commit 6459e9b. ar sync-skills is now ar skill sync — the command is registered via @skill_group.command("sync") in sync_skills_cmd.py, the standalone top-level entry is removed from main.py, the standalone docs/{en,zh}/sync-skills.md pages are deleted and the content folded into docs/{en,zh}/skill.md as a new sync section, and all tests are updated to invoke via ["skill", "sync", ...].

Copilot AI changed the title sync-skills: replace per-tool flags with --tool choice, add github-copilot/cursor/qoder skill sync: add ar skill sync subcommand with --tool choice and github-copilot/cursor/qoder support May 13, 2026
Copilot finished work on behalf of OhYee May 13, 2026 12:25
Copilot AI requested a review from OhYee May 13, 2026 12:25
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.

3 participants