Skip to content

skills: new ~/.agents/skills skill not discovered until reload when ~/.agents was absent at startup #61410

Closed

Description

@sathvicp

Summary

Skills installed into the global ~/.agents/skills compatibility source after the background server starts are not registered when ~/.agents did not exist at server start. /skills, /api/skill, and @skill-id omit them until opencode reload or a service restart.

Environment

Reproduction

  1. Start OpenCode with ~/.agents absent. The background server started at 2026-11-03T12:43:55Z.
  2. Install a skill at ~/.agents/skills/caveman/SKILL.md. This creates ~/.agents and ~/.agents/skills at 2026-11-03T13:20:43Z.
  3. Wait several minutes, then run /skills or opencode api get /api/skill.

Expected Behavior

The new skill is discovered by the existing directory watch and appears in /skills and /api/skill without a manual reload. @caveman loads it.

Actual Behavior

/api/skill returned only opencode, report, and browser. caveman was absent from the model's available skill list. After opencode reload, caveman appeared and loaded normally.

Additional Context

The startup log shows watchers registered for ~/.config/opencode/skills even though that directory did not exist, because its parent did. No watcher was registered for ~/.agents/skills because ~/.agents did not exist:

timestamp=2026-11-03T12:43:55.277Z message="watcher subscribe" path=/home/sathvic/.config/opencode/skill type=file
timestamp=2026-11-03T12:43:55.278Z message="watcher subscribe" path=/home/sathvic/.config/opencode/skills type=file

After opencode reload the compatibility root was watched:

timestamp=2026-11-03T13:25:03.254Z message="watcher subscribe" path=/home/sathvic/.claude/skills type=directory ignores=8
timestamp=2026-11-03T13:25:03.255Z message="watcher subscribe" path=/home/sathvic/.agents/skills type=directory ignores=8

Probe skills created live in ~/.agents/skills and ~/.claude/skills after that reload were picked up within seconds, so watching works once registered. The failure is only initial watcher registration when the compatibility root does not exist at server start.

Workarounds that worked:

  • Run opencode reload after the first install into ~/.agents/skills.
  • Add "skills": ["~/.agents/skills"] to the global opencode.json, which triggers a config reload.
  • Restart the background service.

Reproducible: observed once with the real install; the startup-versus-reload watcher difference in the log is consistent.

Activity

  1. opencodejr commented on Nov 3, 2026

    @opencodejr
    Contributor

    Thanks for the detailed report and logs. I reproduced this on 2.2.5, and it still happens on the latest dev (6d1c444).

    Steps, using an isolated HOME with no ~/.agents and the background service running:

    1. Create ~/.agents (for example, an installer writing a lock file there), and about a second later create ~/.agents/skills/caveman/SKILL.md.
    2. After 15s, opencode api get /api/skill still doesn't list caveman.
    3. After opencode reload, it does.

    If the whole path ~/.agents/skills/caveman/SKILL.md is created in one step, the skill is picked up without a reload. So the trigger seems to be ~/.agents appearing before skills/. When ~/.agents appears, OpenCode rescans once; skills/ isn't there yet, so nothing gets watched and its later creation is missed. The script below reproduces it.

    Related:

    Until this is fixed, your workarounds still work: run opencode reload, or list ~/.agents/skills under skills in your config.

    Reproduction script (repro.sh)
    #!/usr/bin/env bash
    # Reproduces #61410: a skill created in ~/.agents/skills after the service starts
    # (with ~/.agents absent at startup) is not discovered until `opencode reload`.
    # Usage: OC="opencode" bash repro.sh   (or OC="bun ... packages/cli/src/index.ts")
    # From source: PROJ=/workspace/repo/packages/cli OC="bun --conditions=browser --preload=.../preload.js .../packages/cli/src/index.ts" bash repro.sh
    # (PROJ inside packages/cli so the spawned service picks up its bunfig preload)
    set -u
    OC=${OC:-opencode}
    export HOME=$(mktemp -d /tmp/opencode/home.XXXX)
    export XDG_CONFIG_HOME=$HOME/.config XDG_DATA_HOME=$HOME/.local/share XDG_STATE_HOME=$HOME/.local/state XDG_CACHE_HOME=$HOME/.cache
    mkdir -p $XDG_CONFIG_HOME/opencode; echo "{}" > $XDG_CONFIG_HOME/opencode/opencode.json
    PROJ=${PROJ:-$(mktemp -d /tmp/opencode/proj.XXXX)}; mkdir -p $PROJ; cd $PROJ
    echo "HOME=$HOME"; $OC --version
    skills() { $OC api get /api/skill 2>&1 | grep -o '"id": *"[^"]*"\|"name": *"[^"]*"' | sort -u | tr '\n' ' '; echo; }
    echo "--- initial (~/.agents absent)"; ls -d ~/.agents 2>&1; skills; sleep 2; skills
    sleep 3
    # Like a skill installer: ~/.agents is created first (e.g. a lock file), skills/ a moment later
    mkdir -p ~/.agents; echo "{}" > ~/.agents/.skill-lock.json; sleep 1
    mkdir -p ~/.agents/skills/caveman
    printf -- '---\nname: caveman\ndescription: Talk like a caveman\n---\nUse short words.\n' > ~/.agents/skills/caveman/SKILL.md
    echo "--- created ~/.agents/skills/caveman/SKILL.md, waiting 15s"; sleep 15
    skills
    echo "--- opencode reload"; $OC reload 2>&1 | tail -2; sleep 5
    skills
    $OC service stop >/dev/null 2>&1 || true

    Run it: bash repro.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions