Skip to content

feat(skills): add auto-trigger control for bundled skills - #333

Merged
BlackHole1 merged 2 commits into
mainfrom
feat/skills-auto-trigger
Jul 29, 2026
Merged

feat(skills): add auto-trigger control for bundled skills#333
BlackHole1 merged 2 commits into
mainfrom
feat/skills-auto-trigger

Conversation

@BlackHole1

Copy link
Copy Markdown
Member

Users told us the bundled skills act on their own too eagerly — a prompt that merely resembles a description is enough for an agent to route through oo. oo skills auto-trigger off --all (or naming individual skills) makes them manual-only: still installed, still invocable as /oo or $oo, just no longer volunteered.

The awkward part is that no two agents spell this the same way. Claude Code reads disable-model-invocation from the SKILL.md frontmatter; Codex reads policy.allow_implicit_invocation from agents/openai.yaml. Both markers are now written into every published copy, always explicitly and always inverse of each other, derived from one boolean in auto-trigger-policy.ts. Writing both everywhere instead of gating on a per-agent capability table is deliberate: the Agent Skills standard requires runtimes to ignore markers they don't recognize, and the behavior of the eight Claude Code derivatives couldn't be verified either way — a table would have been guesswork. agents/openai.yaml stays in the static file list and always states a value, so switching the policy never adds or removes a file from a published skill directory.

Both vendors also offer a config-file route (~/.codex/config.toml, Claude's skillOverrides). Neither is used: those files are hand-edited and concurrently written by those tools' own UIs, so oo would be merging into a foreign format and losing races it can't detect. ADR 0002 records that trade-off.

The main thing to have an opinion about while reviewing is that the policy is an input to publication, not a runtime switch. off/on republish immediately, and every other republication path — upgrade, newly detected agent host, oo skills add, oo skills repair — picks it up because the renderer reads it. The deliberate gap is a hand-edited [skills.auto_trigger]: detecting that would mean parsing every published SKILL.md on every oo invocation, so oo skills repair is the documented way to apply it. Relatedly, --all is a standing policy rather than a snapshot so bundled skills added by later releases stay covered, and --out-dir exports keep the shipped default — a vendored copy shouldn't carry one machine's preference to everyone who consumes it.

Worth knowing before merging: with auto-trigger off, Claude Code drops the skill's description from its context entirely, so the bundled oo skill can no longer ask the agent to run oo skills recommend plan and end-of-session suggestions stop until it's turned back on. That's inherent to the mechanism and documented alongside the command. Nothing changes by default — the feature is entirely opt-in. The nine flipped assertions in index.test.ts are a leftover guard from the Codex removal in #254 that asserted agents/openai.yaml was absent; they now assert it's present carrying the default policy.

Users reported that the bundled skills fire on their own whenever a
prompt happens to match their description, and asked to be able to
require naming them explicitly.

No two agents spell that policy the same way, so the effective value
is written into every published copy as both vendor markers, always
explicit and always inverse of each other: `disable-model-invocation`
in the SKILL.md frontmatter for Claude Code, and
`policy.allow_implicit_invocation` in `agents/openai.yaml` for Codex.
Both are written for every agent rather than gated on a per-agent
capability table: the Agent Skills standard requires runtimes to
ignore markers they do not recognize, and the behavior of the eight
Claude Code derivatives could not be verified either way.

Only directories oo already generates are touched. Codex's
`config.toml` and Claude's `skillOverrides` would work too, but both
are hand-edited and concurrently written by those tools' own UIs.
See ADR 0002.

The policy is an input to publication rather than a runtime switch, so
`off`/`on` republish immediately and startup synchronization keeps its
cheap short-circuit; `oo skills repair` applies a hand-edited value.
`--all` is a standing policy that keeps covering bundled skills added
by later releases, and `--out-dir` exports keep the shipped default so
a vendored copy never carries one machine's preference.

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

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 82f5e690-05ec-4f8a-90e1-be155b8503b7

📥 Commits

Reviewing files that changed from the base of the PR and between 4242918 and 4d07cdd.

📒 Files selected for processing (3)
  • src/application/commands/skills/auto-sync.ts
  • src/application/commands/skills/auto-trigger/index.cli.test.ts
  • src/application/commands/skills/install.cli.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/application/commands/skills/auto-trigger/index.cli.test.ts
  • src/application/commands/skills/install.cli.test.ts

Summary by CodeRabbit

  • New Features
    • Added skills auto-trigger command group with on, off, and status.
    • You can disable/enable bundled skills globally (--all) or selectively; changes persist and are applied via republishing.
    • Updated bundled skill artifacts so OpenAI invocation behavior is reflected consistently (with clear Claude Code /oo vs Codex $oo conventions).
  • Documentation
    • Expanded English and Chinese docs with configuration guidance and detailed status output (including JSON fields).
  • Bug Fixes
    • Improved sync/repair behavior to keep auto-trigger settings aligned across installations; unmanaged same-name directories are skipped safely.

Walkthrough

Adds persisted auto-trigger settings for bundled skills, including global and per-skill disablement. New oo skills auto-trigger off, on, and status commands update settings, publish policy-aware skill artifacts, report publication results, and record bounded telemetry. Bundled SKILL.md and agents/openai.yaml files now render inverse policy markers. Installation, synchronization, repair, exports, tests, localization, and command documentation were updated accordingly.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant AutoTriggerCLI
  participant SettingsStore
  participant BundledSkillPublisher
  participant ManagedAgent
  User->>AutoTriggerCLI: Run auto-trigger off or on
  AutoTriggerCLI->>SettingsStore: Persist policy
  AutoTriggerCLI->>SettingsStore: Read resolved policy
  AutoTriggerCLI->>BundledSkillPublisher: Publish bundled skills
  BundledSkillPublisher->>ManagedAgent: Write rendered skill artifacts
  ManagedAgent-->>AutoTriggerCLI: Return publication status
  AutoTriggerCLI-->>User: Print state and publication results
Loading

Possibly related PRs

  • oomol-lab/oo-cli#326: Both changes modify the skills repair command, including its output handling and bundled-skill repair path.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the required format and clearly summarizes the bundled-skill auto-trigger feature.
Description check ✅ Passed The description describes the same auto-trigger policy and publication behavior changes covered by the PR.
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.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/skills-auto-trigger

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (4)
src/application/commands/skills/auto-trigger-policy.test.ts (1)

29-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract repeated policy fixtures into a local factory.

Use a createPolicy() helper at the bottom of src/application/commands/skills/auto-trigger-policy.test.ts for the repeated { disabled, disabledAll } setup objects.

  • src/application/commands/skills/auto-trigger-policy.test.ts#L29-L30: create the standing-policy fixture through the factory.
  • src/application/commands/skills/auto-trigger-policy.test.ts#L38-L39: create the named-skill fixture through the factory.
  • src/application/commands/skills/auto-trigger-policy.test.ts#L92-L94: reuse the standing-policy fixture factory.
  • src/application/commands/skills/auto-trigger-policy.test.ts#L112-L113: reuse the named-skill fixture factory.

As per coding guidelines, “In test files, extract repeated setup (mock, stub, or setup objects) into a local factory function at the bottom of the file.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/auto-trigger-policy.test.ts` around lines 29
- 30, Extract the repeated { disabled, disabledAll } test setup into a local
createPolicy() factory at the bottom of
src/application/commands/skills/auto-trigger-policy.test.ts, then update the
fixtures at lines 29-30, 38-39, 92-94, and 112-113 to use it while preserving
their respective standing-policy and named-skill values.

Source: Coding guidelines

docs/commands.md (1)

1961-1964: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the command reference at the CLI-contract level.

Remove the explanation of agents hiding skill descriptions from their context; retain only the observable result: disabled skills are not implicitly invoked, including the bundled oo skill’s unprompted suggestions.

  • docs/commands.md#L1961-L1964: replace host-context mechanics with observable behavior.
  • docs/commands.zh-CN.md#L1645-L1647: make the equivalent Chinese revision.

As per coding guidelines, docs/commands*.md must describe only the user-facing CLI contract, not internal implementation details.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/commands.md` around lines 1961 - 1964, Replace the internal host-context
explanation in docs/commands.md lines 1961-1964 with only the observable CLI
behavior: disabled skills are not implicitly invoked, including the bundled `oo`
skill’s unprompted end-of-session suggestions. Apply the equivalent Chinese
revision in docs/commands.zh-CN.md lines 1645-1647, preserving the meaning while
removing implementation details.

Source: Coding guidelines

src/application/commands/skills/auto-trigger/index.cli.test.ts (1)

227-231: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the repeated resolveStorePaths setup into a local helper.

The same resolveStorePaths({ appName: APP_NAME, env: sandbox.env, platform: process.platform }) block appears five times; a single factory at the bottom of the file (returning store paths or the settings file path directly) removes the duplication.

♻️ Suggested helper
function resolveSandboxStorePaths(sandbox: CliSandbox) {
    return resolveStorePaths({
        appName: APP_NAME,
        env: sandbox.env,
        platform: process.platform,
    });
}

As per coding guidelines: "In test files, extract repeated setup (mock, stub, or setup objects) into a local factory function at the bottom of the file."

Also applies to: 256-260, 344-352, 402-406, 479-483

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/auto-trigger/index.cli.test.ts` around lines
227 - 231, Extract the repeated resolveStorePaths configuration into a local
resolveSandboxStorePaths helper at the bottom of the test file, accepting the
sandbox and returning the resolved store paths. Replace all five duplicated
setup blocks in the affected test cases with this helper, accessing
settingsFilePath where needed while preserving existing behavior.

Source: Coding guidelines

src/application/commands/skills/auto-trigger/on.ts (1)

12-13: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Pass the settings helper directly instead of wrapping it.

removeAutoTriggerDisabledSkills already matches the applySkills signature, so the arrow adds no logic.

♻️ Proposed simplification
-    applySkills: (settings, skillNames) =>
-        removeAutoTriggerDisabledSkills(settings, skillNames),
+    applySkills: removeAutoTriggerDisabledSkills,

As per coding guidelines: "Never create single-line functions that merely delegate to another function without adding logic, validation, or semantic value."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/application/commands/skills/auto-trigger/on.ts` around lines 12 - 13,
Update the applySkills property to reference removeAutoTriggerDisabledSkills
directly instead of wrapping it in a single-line arrow function, preserving the
existing settings and skillNames behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/application/commands/skills/auto-sync.ts`:
- Around line 59-64: Update the Promise.all construction in the auto-sync
command so readSkillAutoTriggerPolicy starts without being awaited during
operand creation, allowing synchronizeRegistrySkills to run even if policy
loading fails. Preserve policy usage for synchronizeBundledSkills while ensuring
both synchronization paths are started independently.

In `@src/application/commands/skills/auto-trigger-policy.test.ts`:
- Around line 79-127: The tests in “renders both markers…”, “flips both
markers…”, and “flips the markers only for the named skill” hardcode the POSIX
path “agents/openai.yaml”. Import or reuse the path join utility and construct
this expected relative path with join("agents", "openai.yaml") in each affected
readMarkerContent call.

In `@src/application/commands/skills/embedded-assets.test.ts`:
- Line 210: Update the expected asset list in the embedded-assets alignment test
to retain the existing skill-authoring.md, existing-workflow.md, and
oo-powered.md reference entries alongside agents/openai.yaml, matching the
outputs emitted by embedded-assets.ts.

In `@src/application/commands/skills/install.cli.test.ts`:
- Around line 508-511: Capture the result of the `skills auto-trigger off --all`
call in the test and assert that its exitCode is 0 before setting up the export
and running `skills add`. Keep the existing environment setup and export
assertions unchanged.

---

Nitpick comments:
In `@docs/commands.md`:
- Around line 1961-1964: Replace the internal host-context explanation in
docs/commands.md lines 1961-1964 with only the observable CLI behavior: disabled
skills are not implicitly invoked, including the bundled `oo` skill’s unprompted
end-of-session suggestions. Apply the equivalent Chinese revision in
docs/commands.zh-CN.md lines 1645-1647, preserving the meaning while removing
implementation details.

In `@src/application/commands/skills/auto-trigger-policy.test.ts`:
- Around line 29-30: Extract the repeated { disabled, disabledAll } test setup
into a local createPolicy() factory at the bottom of
src/application/commands/skills/auto-trigger-policy.test.ts, then update the
fixtures at lines 29-30, 38-39, 92-94, and 112-113 to use it while preserving
their respective standing-policy and named-skill values.

In `@src/application/commands/skills/auto-trigger/index.cli.test.ts`:
- Around line 227-231: Extract the repeated resolveStorePaths configuration into
a local resolveSandboxStorePaths helper at the bottom of the test file,
accepting the sandbox and returning the resolved store paths. Replace all five
duplicated setup blocks in the affected test cases with this helper, accessing
settingsFilePath where needed while preserving existing behavior.

In `@src/application/commands/skills/auto-trigger/on.ts`:
- Around line 12-13: Update the applySkills property to reference
removeAutoTriggerDisabledSkills directly instead of wrapping it in a single-line
arrow function, preserving the existing settings and skillNames behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a33030b3-4de6-4788-91bc-5883b56564b1

📥 Commits

Reviewing files that changed from the base of the PR and between 75f9506 and 4242918.

📒 Files selected for processing (34)
  • README-ZH_CN.md
  • README.md
  • contrib/skills/shared/oo-create-skill/SKILL.md
  • contrib/skills/shared/oo-create-skill/agents/openai.yaml
  • contrib/skills/shared/oo-find-skills/SKILL.md
  • contrib/skills/shared/oo-find-skills/agents/openai.yaml
  • contrib/skills/shared/oo-publish-skill/SKILL.md
  • contrib/skills/shared/oo-publish-skill/agents/openai.yaml
  • contrib/skills/shared/oo/SKILL.md
  • contrib/skills/shared/oo/agents/openai.yaml
  • docs/commands.md
  • docs/commands.zh-CN.md
  • src/application/commands/skills/auto-sync.ts
  • src/application/commands/skills/auto-trigger-policy.test.ts
  • src/application/commands/skills/auto-trigger-policy.ts
  • src/application/commands/skills/auto-trigger/index.cli.test.ts
  • src/application/commands/skills/auto-trigger/index.ts
  • src/application/commands/skills/auto-trigger/off.ts
  • src/application/commands/skills/auto-trigger/on.ts
  • src/application/commands/skills/auto-trigger/publish.ts
  • src/application/commands/skills/auto-trigger/report.ts
  • src/application/commands/skills/auto-trigger/status.ts
  • src/application/commands/skills/auto-trigger/toggle-command.ts
  • src/application/commands/skills/embedded-assets.test.ts
  • src/application/commands/skills/embedded-assets.ts
  • src/application/commands/skills/index.test.ts
  • src/application/commands/skills/index.ts
  • src/application/commands/skills/install.cli.test.ts
  • src/application/commands/skills/repair.ts
  • src/application/commands/skills/shared.ts
  • src/application/commands/telemetry-decisions.test.ts
  • src/application/schemas/settings.test.ts
  • src/application/schemas/settings.ts
  • src/i18n/catalog.ts

Comment thread src/application/commands/skills/auto-sync.ts Outdated
Comment thread src/application/commands/skills/auto-trigger-policy.test.ts
Comment thread src/application/commands/skills/embedded-assets.test.ts
Comment thread src/application/commands/skills/install.cli.test.ts Outdated
Awaiting `readSkillAutoTriggerPolicy()` while the caller built its
`Promise.all` array meant a settings file the run could not parse
stopped `synchronizeRegistrySkills()` from ever being called.
`FileSettingsStore.read()` throws `errors.store.readFailed` on a
corrupt file, and registry synchronization has nothing to do with the
auto-trigger policy, so one unreadable file took down both halves of
startup synchronization instead of one. The read moves into
`synchronizeBundledSkills()`, which is the only half that needs it.

Also assert the exit code of the `auto-trigger off` setup runs in two
tests whose expectations *are* the resulting state. Both would have
stayed green if setup had silently failed, proving nothing.

Signed-off-by: Kevin Cui <bh@bugs.cc>
@BlackHole1
BlackHole1 merged commit 5e89ed2 into main Jul 29, 2026
7 checks passed
@BlackHole1
BlackHole1 deleted the feat/skills-auto-trigger branch July 29, 2026 10:52
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