Skip to content

feat(skills): synchronize managed skills at startup#111

Merged
BlackHole1 merged 1 commit into
mainfrom
add-auto-add-skills
Apr 28, 2026
Merged

feat(skills): synchronize managed skills at startup#111
BlackHole1 merged 1 commit into
mainfrom
add-auto-add-skills

Conversation

@BlackHole1
Copy link
Copy Markdown
Member

Keep supported agent hosts aligned before command execution so bundled skills and locally cached registry skills are available without an explicit install step. The startup path stays silent, avoids network fetches, and preserves unmanaged skill targets.

Keep supported agent hosts aligned before command execution so bundled
skills and locally cached registry skills are available without an
explicit install step. The startup path stays silent, avoids network
fetches, and preserves unmanaged skill targets.

Signed-off-by: Kevin Cui <bh@bugs.cc>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Summary by CodeRabbit

  • New Features

    • Added silent startup synchronization of AI agent skills across supported hosts. Bundled skills are automatically installed and updated to the current version (except during development builds). Published skills from local sources are synchronized to newly detected hosts without requiring authentication.
  • Documentation

    • Updated contributing guidelines and command documentation to clarify startup synchronization behavior, skill management, and safety boundaries.
  • Tests

    • Added tests verifying startup synchronization behavior and skill installation scenarios.

Walkthrough

This PR implements automatic startup synchronization of managed AI agent skills across all available host directories. The changes introduce a new synchronizeManagedSkillsForAvailableHosts() function that executes before CLI command dispatch, ensuring bundled skills (oo, oo-find-skills) are installed and synced across detected Codex/Claude Code/OpenClaw hosts, and published skills from canonical registries are propagated to newly detected hosts. Synchronization is skipped for development-version builds, does not require authentication, produces no additional output, and avoids overwriting unmanaged targets. The CLI bootstrap layer is updated to invoke this sync step, existing tests are updated to verify the new behavior, and documentation is added to describe the synchronization mechanics.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI Bootstrap
    participant Sync as Startup Sync Handler
    participant Hosts as Available Hosts
    participant Bundled as Bundled Skills
    participant Registry as Registry Skills
    participant FS as Filesystem

    CLI->>Sync: synchronizeManagedSkillsForAvailableHosts()
    Sync->>Hosts: Resolve available host directories
    Hosts-->>Sync: [Codex, Claude Code, OpenClaw, ...]
    
    loop For each host directory
        Sync->>Bundled: Check bundled skill state
        Bundled->>FS: Read managed/unmanaged/missing status
        FS-->>Bundled: Current state
        
        alt Managed but outdated (non-development)
            Bundled->>FS: Publish bundled skill installation
            FS-->>Bundled: Success/Warning
        else Skip (development version or unmanaged)
            Bundled-->>Sync: Skipped
        end
    end
    
    loop For each host directory
        Sync->>Registry: Enumerate canonical registry skills
        Registry->>FS: Read canonical skill metadata
        FS-->>Registry: Skill configuration
        
        alt Managed and version mismatch
            Registry->>FS: Publish registry skill
            FS-->>Registry: Success/Warning
        else Skip (up-to-date or unmanaged)
            Registry-->>Sync: Skipped
        end
    end
    
    Sync-->>CLI: Synchronization complete
    CLI->>CLI: Execute requested command
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required format with type(scope): subject and accurately describes the main change: implementing automatic synchronization of managed skills during CLI startup.
Description check ✅ Passed The description is directly related to the changeset, explaining the purpose and benefits of the startup synchronization feature for maintaining skill availability.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch add-auto-add-skills

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/application/commands/skills/list.cli.test.ts (1)

75-87: ⚠️ Potential issue | 🟡 Minor

This setup no longer proves skills list triggered the sync.

Line 81 now runs the same startup synchronization as every other CLI command, so skills install oo can create oo-find-skills before Line 85 executes. That means this test still passes even if the bootstrap sync inside skills list regresses. Seed only oo on disk, or assert oo-find-skills is absent before the skills list invocation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/application/commands/skills/list.cli.test.ts` around lines 75 - 87, The
test incorrectly relies on calling sandbox.run(["skills","install","oo"]) which
performs the same startup sync as skills list; instead seed only the on-disk
bundled package and ensure no pre-synced marker exists before invoking skills
list. Use resolveOpenClawHomeDirectory(sandbox.env) to locate the OpenClaw home,
create the minimal on-disk bundle for "oo" (e.g., a directory or manifest) with
mkdir(..., { recursive: true }) rather than calling sandbox.run install, or
alternatively after the install call explicitly assert that the "oo-find-skills"
sync artifact is absent before calling sandbox.run(["skills","list"]) so the
test actually verifies that skills list triggers the sync.
🧹 Nitpick comments (1)
src/application/commands/skills/index.cli.test.ts (1)

58-88: Extract a shared startup-test helper.

These new cases all repeat the same sandbox.run(["--help"]) / log-read / baseline assertions. A small local helper would keep the startup contract checks aligned and make later behavior changes much easier to update consistently.

Based on learnings: Extract repeated setup (mocks, stubs, setup objects) into local factory functions in test files; avoid copy-pasting test setup.

Also applies to: 94-196, 198-248, 250-272

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/application/commands/skills/index.cli.test.ts` around lines 58 - 88,
Multiple tests duplicate the same CLI startup flow (creating sandbox, running
sandbox.run(["--help"]), reading logs via readLatestLogContent, and asserting
baseline expectations). Extract a local helper (e.g., runCliStartupCheck or
createStartupSandbox) that accepts any per-test overrides and performs the
shared steps: createCliSandbox(), mkdir(codexHomeDirectory,...), run(["--help"],
{ version }), readLatestLogContent(sandbox), and the baseline assertions
(result.exitCode === 0, result.stderr === "", result.stdout contains "Options:",
etc.), then replace the repeated blocks in the tests (the test "auto-installs
bundled skills during cli startup" and the other ranges 94-196, 198-248,
250-272) to call that helper and only assert test-specific outcomes (e.g.,
existence of skillDirectoryPath, specific log messages). Ensure the helper
exposes returned values (sandbox, result, content, codexHomeDirectory) so tests
can make additional assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/application/commands/skills/list.cli.test.ts`:
- Around line 75-87: The test incorrectly relies on calling
sandbox.run(["skills","install","oo"]) which performs the same startup sync as
skills list; instead seed only the on-disk bundled package and ensure no
pre-synced marker exists before invoking skills list. Use
resolveOpenClawHomeDirectory(sandbox.env) to locate the OpenClaw home, create
the minimal on-disk bundle for "oo" (e.g., a directory or manifest) with
mkdir(..., { recursive: true }) rather than calling sandbox.run install, or
alternatively after the install call explicitly assert that the "oo-find-skills"
sync artifact is absent before calling sandbox.run(["skills","list"]) so the
test actually verifies that skills list triggers the sync.

---

Nitpick comments:
In `@src/application/commands/skills/index.cli.test.ts`:
- Around line 58-88: Multiple tests duplicate the same CLI startup flow
(creating sandbox, running sandbox.run(["--help"]), reading logs via
readLatestLogContent, and asserting baseline expectations). Extract a local
helper (e.g., runCliStartupCheck or createStartupSandbox) that accepts any
per-test overrides and performs the shared steps: createCliSandbox(),
mkdir(codexHomeDirectory,...), run(["--help"], { version }),
readLatestLogContent(sandbox), and the baseline assertions (result.exitCode ===
0, result.stderr === "", result.stdout contains "Options:", etc.), then replace
the repeated blocks in the tests (the test "auto-installs bundled skills during
cli startup" and the other ranges 94-196, 198-248, 250-272) to call that helper
and only assert test-specific outcomes (e.g., existence of skillDirectoryPath,
specific log messages). Ensure the helper exposes returned values (sandbox,
result, content, codexHomeDirectory) so tests can make additional assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 532f85e8-f839-4bd5-85c9-284c43101479

📥 Commits

Reviewing files that changed from the base of the PR and between c5fb287 and c1e90f7.

📒 Files selected for processing (8)
  • CONTRIBUTING.md
  • docs/commands.md
  • docs/commands.zh-CN.md
  • src/application/bootstrap/run-cli.ts
  • src/application/commands/skills/auto-sync.ts
  • src/application/commands/skills/index.cli.test.ts
  • src/application/commands/skills/list.cli.test.ts
  • src/application/commands/skills/shared.ts

Comment on lines +231 to +245
async function synchronizeRegistrySkills(
hosts: readonly ManagedSkillHost[],
context: SkillSyncContext,
): Promise<void> {
const skills = await listCanonicalRegistrySkills(context);

await Promise.all(
skills.flatMap(skill =>
resolveManagedSkillHostInstallations(hosts, skill.name).map(
installation =>
synchronizeRegistrySkill(installation, skill, context),
),
),
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Cap registry startup sync concurrency.

Lines 237-244 and 368-410 both fan out with unbounded Promise.all. Because this runs before every CLI invocation, a large local registry cache can turn even oo --help into hundreds of concurrent fs reads/writes here, which is enough to slow startup badly or hit file-descriptor pressure. Please batch or otherwise bound this work instead of launching one task per skill/host all at once.

Also applies to: 344-413

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.

1 participant