Skip to content

[Feature]: install local extensions without dev symlinks #3058

@Antoniogins

Description

@Antoniogins

Problem Statement

Spec Kit currently couples two separate concerns in specify extension add --dev:

  • The extension source is a local directory.
  • Generated agent artifacts are written as dev-mode symlinks where supported.

This creates a gap for private, repository-local extensions. A team may want to keep the extension source in the same repository as the codebase and install it locally as regular generated files, without publishing it to a catalog or release first.

Today, the practical options are:

specify extension add <extension-id>

This installs from a bundled extension or catalog entry and writes regular files, but it does not accept an arbitrary local extension directory.

specify extension add ./path/to/extension --dev --force

This accepts a local extension directory, but it writes symlinked agent artifacts. That is not safe for every agent integration. In particular, Codex does not reliably load symlinked skills under .agents/skills.

For a local extension such as:

.project-skills/
  extension.yml
  commands/
    backend-rest-controllers.md
    domain-data-model.md
    ...

running:

specify extension add .project-skills --dev --force

registers the extension, but the generated Codex skills become symlinks to .specify-dev. Those symlinked SKILL.md files are not reliably loaded by Codex.

This is especially problematic when the extension itself contains a refresh skill. In our workflow, agent instructions explain how to create or edit project-specific skills:

  1. Edit the extension source under commands/.
  2. Update extension.yml.
  3. Invoke the refresh skill so the local extension is reinstalled and the current agent receives the new or updated skill.

That makes refresh part of the normal agent-driven skill-authoring workflow, not just a manual maintenance step. If refresh installs symlinked skills, the workflow can leave Codex unable to use the skills it just refreshed.

Proposed Solution

Add a first-class way to install an extension from a local directory while writing normal generated files instead of symlinks.

One possible CLI design:

specify extension add ./path/to/extension --local --force

Where --local means: install this local directory as a regular extension install, not as a dev-linked install.

Another possible design:

specify extension add ./path/to/extension --force

Where a path containing extension.yml is treated as a normal local install by default, and --dev remains the opt-in mode for linked development behavior.

Expected result for Codex:

.specify/extensions/project-skills/
.agents/skills/speckit-project-skills-backend-rest-controllers/SKILL.md
.agents/skills/speckit-project-skills-domain-data-model/SKILL.md
...

Each generated SKILL.md should be a regular file, not a symlink.

This would keep the current --dev behavior available for users who want live linked artifacts, while supporting local/private extension installs that need regular files.

Alternatives Considered

--dev --no-symlinks

Another acceptable design would be:

specify extension add ./path/to/extension --dev --no-symlinks --force

This keeps the existing local-directory dev flow but disables symlink generation for agent artifacts.

That said, --dev --no-symlinks still mixes source location and output behavior under one dev mode. A separate regular local-install mode may be clearer because "local source directory" and "dev symlinks" are independent concerns.

Existing related issues and PRs

This request overlaps with, but is not fully covered by, existing issues:

PR #2988 would likely fix the immediate Codex-specific symptom, but this request is broader: local extension installation should not require dev symlinks or a published/cataloged package.

Manual symlink replacement

Users can install with --dev and then manually replace symlinked SKILL.md files with real copies.

This is too manual for an agent-driven refresh loop and easy to forget. It also makes the refresh skill responsible for compensating for installer behavior, which should not be necessary.

Publishing or packaging first

Users can publish or package the extension first and then install through a normal URL or catalog path.

That is unnecessary friction for private, repository-local extensions and does not fit workflows where the repository itself is the source of truth for the extension.

Component

Specify CLI (initialization, commands)

AI Agent (if applicable)

None

Use Cases

Repository-local skill ground truth

A repository can contain the ground truth for its own agent skills:

.project-skills/
  extension.yml
  commands/

The skills document how agents should work with that specific codebase, domain model, backend architecture, test strategy, operational workflows, and coding conventions.

Keeping the extension in the same repository has practical benefits:

  • Skill changes are reviewed with normal code review.
  • Skill source evolves with the code it describes.
  • Branches can change both code and agent guidance together.
  • The repository remains self-contained for onboarding.

Agent-agnostic skill source

Spec Kit extensions are useful as an agent-agnostic source of skills. The same commands/ markdown can be rendered into Codex, Claude, Copilot, Cursor, Gemini, or other agent-specific formats.

For this to work well, the source extension should be local and canonical, while generated agent artifacts should be ordinary installed outputs for the active agent.

Agent-driven skill authoring and refresh

The extension can include instructions that tell agents how to add or update project-specific skills:

  1. Create or edit a command markdown file.
  2. Register the command in extension.yml.
  3. Run a refresh skill to reinstall the extension for the current agent.

This allows users to ask the agent to create or update a project skill without manually knowing the extension layout.

That workflow needs a refresh command that can install from the local source of truth and produce agent-loadable artifacts. For Codex, that means regular SKILL.md files under .agents/skills, not symlinks.

Private extensions that should not be published

Many project-specific skill extensions are private by nature. They may include internal architecture, domain concepts, deployment workflows, or proprietary conventions.

These extensions should not need a public release, catalog entry, or external package location before they can be installed as regular files in a local Spec Kit project.

Acceptance Criteria

  • Users can install a Spec Kit extension from a local directory without publishing or packaging it first.
  • The local install mode can write regular generated agent artifacts instead of symlinks.
  • Existing --dev symlink behavior remains available for users who want linked development artifacts.
  • The workflow works for Codex and creates regular .agents/skills/*/SKILL.md files.
  • The command is safe with --force and does not delete the source directory if the source path is inside .specify/extensions.
  • The behavior is documented clearly, distinguishing:
    • local source directory installation
    • dev-mode linked artifacts
    • catalog or URL-based installation

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions