Skip to content

Implement agenting skills support via Vercel Labs' skills#41

Open
albertodebortoli wants to merge 6 commits intomainfrom
skills-support
Open

Implement agenting skills support via Vercel Labs' skills#41
albertodebortoli wants to merge 6 commits intomainfrom
skills-support

Conversation

@albertodebortoli
Copy link
Member

@albertodebortoli albertodebortoli commented Mar 21, 2026

Add skills support to Luca

Extends luca install to install agentic SKILL.md-based skills from Git repositories, alongside existing binary tool management.

Description

  • New skills: key in Lucafile: Declare agentic skills hosted in Git repositories. Each skill entry takes a repository (owner/repo shorthand or full HTTPS/GIT URL) and an optional name. Omitting name installs all skills from that repository.
  • New agents: key in Lucafile: Optional list of agent identifiers (e.g. claude-code, github-copilot, opencode) of supported agents to target when installing skills. When omitted, skills are installed for all supported agents.
  • --only-tools / --only-skills flags: Selective install modes on luca install to run only one half of the pipeline. Mutually exclusive; validated at argument parse time.
  • SkillInstaller: New component behind a SkillInstalling protocol. Builds and runs npx skills add <repository> --yes [--skill name...] [--agent name...] via SubprocessRunner. Verifies npx availability before proceeding and maps non-zero exit codes to typed errors. skills is a tool developed and maintained by Vercel Labs.
  • SubprocessRunner: New SubprocessRunning abstraction wrapping Foundation.Process. Uses terminationHandler + withCheckedThrowingContinuation (instead of waitUntilExit()) to avoid deadlocking on Swift Concurrency threads. Closes stdin via FileHandle.nullDevice so subprocesses do not block waiting for input.
  • SkillsInfoFactory: Groups Skill entries from the spec by repository into SkillSet batches, merging per-repo entries (a repo listed without a name takes precedence and installs all its skills).
  • ToolInstaller (refactor): Extracts the per-tool download, validate, and install pipeline out of Installer into a dedicated ToolInstaller struct behind ToolInstalling. This creates a symmetric architecture — one installer per domain — and leaves Installer as a pure orchestrator (spec loading, orphan unlinking, delegation).
  • reinstall moved to ToolInstaller: All tool-specific dependencies (binaryFinder, permissionManager, symLinker) already lived in ToolInstaller; reinstall moved there too, shedding those stored properties from Installer.

Lucafile example:

tools:
  - name: SwiftLint
    version: 0.61.0
    url: https://github.com/realm/SwiftLint/releases/download/0.61.0/portable_swiftlint.zip

skills:
  - name: frontend-design
    repository: vercel-labs/agent-skills
  - name: swift-testing-expert
    repository: https://github.com/AvdLee/Swift-Testing-Agent-Skill

agents:
  - claude-code
  - github-copilot

Type of Change

  • Feature
  • Bug fix
  • Maintenance / Refactor
  • Documentation
  • CI / Tooling
  • Other (specify)

How Has This Been Tested?

  • Added / updated unit tests
  • Manually tested locally (describe)
  • Tested on macOS (arch: arm64 / x86_64)
  • Other

New test files:

  • Tests/Core/SubprocessRunnerTests.swift — verifies SubprocessRunner against real /bin/true and /bin/false executables
  • Tests/Core/SkillInstallerTests.swift — covers npx availability check, argument construction, and error paths via SubprocessRunnerMock
  • Tests/Core/SkillsInfoFactoryTests.swift — covers spec-based grouping, "all skills" vs named skills merging, and empty/nil cases
  • Tests/Core/ToolInstallerTests.swift — full pipeline tests (zip/tar.gz/executable, arch validation, reinstall) extracted from the former InstallerTests, now calling ToolInstaller directly
  • InstallerTests updated to use ToolInstallerMock for orchestration tests and a real ToolInstaller + mock downloader for integration tests

Screenshots / Demo (if applicable)

$ luca install
# installs both tools and skills

$ luca install --only-tools
# installs binary tools only, skips skills

$ luca install --only-skills
# installs skills only, skips tools

Checklist

  • Swift code builds locally (swift build)
  • Tests pass locally (swift test)
  • Code style / formatting respected
  • Documentation updated (README / comments)
  • Version / tag alignment considered (if release related)
  • PR title follows conventional style (optional)

CI Considerations

  • Affects build time notably
  • Requires new secrets / env vars
  • Alters release process

Breaking Changes?

  • No
  • Yes (describe impact and migration path)

Additional Notes

npx (and Node.js) must be present in the environment for skill installation to work. If npx is not found, luca install fails with a clear error message pointing the user to install Node.js. Skills installation is silently skipped when the Lucafile contains no skills: key.

The SubprocessRunner deadlock fix (terminationHandler instead of waitUntilExit()) is required because Swift Concurrency tasks do not run a RunLoop, which waitUntilExit() depends on internally.

@albertodebortoli albertodebortoli marked this pull request as draft March 21, 2026 11:17
albertodebortoli and others added 6 commits March 21, 2026 21:23
Extends `luca install` to also install agentic SKILL.md-based skills from Git repositories by delegating to `npx skills add`. Adds a new `skills:` key alongside `tools:` in the Lucafile, and `--only-tools` / `--only-skills` flags to the install command for selective installs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a top-level `agents:` key to the Lucafile so skills can be targeted
at specific agents (e.g. claude-code, github-copilot) via `--agent` flags.
Also fixes the `npx skills add` hang by switching from `waitUntilExit()`
(which depends on RunLoop and deadlocks on Swift Concurrency threads) to
`terminationHandler` + `withCheckedContinuation`, closing stdin on the
subprocess, and moving skill installation outside Noora's progress step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract installArchive, installExecutable, and validateArchitectureIfNeeded
from Installer into a dedicated ToolInstaller struct behind a ToolInstalling
protocol, mirroring the existing SkillInstaller/SkillInstalling pattern.

Installer now delegates per-tool download and installation to ToolInstalling,
retaining only orchestration responsibilities (spec loading, orphan unlinking,
reinstall).

Tests are updated accordingly: ToolInstallerTests covers the installation
pipeline directly, InstallerTests wires a real ToolInstaller with a mock
downloader for integration tests and ToolInstallerMock for orchestration tests.
reinstall belongs alongside install inside ToolInstaller — all its dependencies (binaryFinder, permissionManager, symLinker) were already there. Installer sheds those three stored properties and delegates via toolInstaller.reinstall(tool:). The regression test for binaryPath-aware reinstall moves to ToolInstallerTests and calls ToolInstaller directly.
@albertodebortoli albertodebortoli changed the title Skills support Add skills support to Luca Mar 21, 2026
@albertodebortoli albertodebortoli changed the title Add skills support to Luca Implement agenting skills support via Vercel Labs' skills Mar 21, 2026
@albertodebortoli albertodebortoli marked this pull request as ready for review March 21, 2026 21:37
@albertodebortoli albertodebortoli added feature New feature refactoring Refactoring work labels Mar 21, 2026
@albertodebortoli albertodebortoli added this to the 0.11.0 milestone Mar 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature refactoring Refactoring work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant