Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Prefix controller-managed skills with controller- and hide them from the slash picker #159

Description

@germanescobar

Summary

The orchestrator currently installs five app-managed skills into every agent's user skills home on startup (server/lib/managed-skills.ts):

  • browser
  • integrations
  • controller-scripts (already partial prefix)
  • search-skills
  • skill-creator

These skills are agent-facing: they tell the running agent how to drive the preview browser, use the integrations gateway, generate per-worktree setup/run scripts, search the unified skill catalog, and create new unified skills. They are not intended to be invoked by the user via /<name>.

We want to:

  1. Rename them with a consistent controller- prefix so it is obvious from the name alone that they are app-managed, and so they are grouped together in the / picker and the filesystem.
  2. Hide controller-managed skills from the / slash picker so they are not surfaced as user-invokable commands. The agent continues to discover them through the same filesystem location (so the body is still prepended when relevant), but the user does not see them in the autocomplete.

Motivation

  • Discoverability for users. Right now a user types / and sees /browser, /integrations, /controller-scripts, /search-skills, /skill-creator mixed in with their own per-agent and unified skills. They have no visual cue that these are app-managed, and there is nothing meaningful the user would do by typing them — the agent invokes them via read_body at runtime, not via the slash picker.
  • Grouping for the agent. A consistent prefix lets the agent (and the orchestrator) tell at a glance which skills come from the app and which come from the user, without parsing the MANAGED_MARKER HTML comment.
  • Cleaner picker. The / picker is a small UI surface. Today, on a fresh install, half the visible items are controller-managed. Hiding them keeps the picker focused on skills the user actually wants to invoke.

Current state

  • server/lib/managed-skills.ts writes each skill into ~/.anita/skills/<name>/SKILL.md, ~/.codex/skills/<name>/SKILL.md, and ~/.claude/skills/<name>/SKILL.md on startup, tagged with MANAGED_MARKER (<!-- managed-by: coding-orchestrator (issue #109) -->).
  • server/lib/skills.ts mergeSkillMetadata already surfaces unified skills first and dedupes per-agent skills by name, but it does not distinguish controller-managed per-agent skills from user-authored ones — both render in the picker with scope === "user".
  • client/src/pages/SessionView.tsx fetchAgentSkills returns the merged list and renders every entry under the / autocomplete, with a scope badge but no managed-vs-user distinction.
  • server/lib/skills.ts extractSkillInvocation accepts any leading /<name> token and server/routes/sessions.ts will activate it server-side. There is currently no filtering of managed skills from the slash path; a user can type /browser today and it will activate the body. We want to keep the agent-facing body available (the body is what tells the agent how to use the integration/browser/catalog), but stop the user from triggering it themselves via the picker.

Proposed design

1. Rename to a consistent controller- prefix

In server/lib/managed-skills.ts, rename the installed skill directories to:

  • browsercontroller-browser
  • integrationscontroller-integrations
  • controller-scriptscontroller-controller-scripts (or drop the redundant controller- and use controller-scripts, but that breaks the renaming. Recommend: controller-controller-scripts to keep the rule mechanical — "all controller-managed skills start with controller-". Alternatively, accept controller-scripts as the canonical name and document it as the only exception. See open questions.)
  • search-skillscontroller-search-skills
  • skill-creatorcontroller-skill-creator

Update the name field inside each SKILL.md body to match the new directory name so extractSkillInvocation and the per-agent skill loader (server/lib/skills.ts createDiskProvider) see consistent names.

Update each skill body to reference the new name where it documents itself ("name", "How to use it", examples that mention /name).

2. Add a managed flag (server) and use it to filter the picker

Extend SkillMetadata (in server/lib/skills.ts) with an optional managed?: boolean field, or extend SkillScope with "managed". (See open question — prefer extending Scope so the existing picker rendering and dedupe logic does not need a parallel path.)

When the disk provider reads a SKILL.md whose body contains MANAGED_MARKER, mark the resulting SkillMetadata with scope: "managed" instead of "user".

mergeSkillMetadata keeps managed skills discoverable for body lookup (the agent still needs to be able to readBody them), but the client filters them out of the / picker:

  • client/src/pages/SessionView.tsx filteredSkills excludes entries with scope === "managed" before rendering the popover.

3. Hardening on the slash path

Even though the picker is the primary surface, a user can still type /controller-browser manually and submit. Decide on one of:

  • Allow it. The body is harmless guidance for the agent; server/routes/sessions.ts continues to prepend it. This is the simplest path and matches how all per-agent skills work today.
  • Reject it server-side. server/routes/sessions.ts resolveSkillActivation returns a 400 for any skillName whose metadata has scope === "managed" on the active provider.

Recommend allowing it for v1 (matches the "the agent can still read the body" invariant) and revisit only if a managed body turns out to be confusing as a slash-command prefix.

4. Update the managed MANAGED_MARKER constant

The current marker comment references "issue #109", but the managed-skill installer has been extended multiple times since (#134, #146, #157, etc.). Update the marker string to reference this issue so future renames and unowned files can be detected accurately.

Open questions

  • Naming for controller-scripts. Two options:
    1. controller-controller-scripts — mechanically consistent with the controller- rule.
    2. controller-scripts is grandfathered because it was the first one shipped and the name is already stable.
      Lean: option 2 keeps the public name stable but option 1 keeps the rule simple. Need user input.
  • SkillScope extension vs. new managed boolean. The boolean is additive and doesn't disturb existing consumers; the new scope value is cleaner but forces an update everywhere scope is matched (skills-section.tsx, the picker badge, dedupe). Lean: new scope value, but check all consumers in the PR.
  • Hide on all surfaces, or just the picker? skills-section.tsx in Settings only lists unified skills today, so managed skills aren't visible there regardless. Confirm the picker is the only surface to touch.

Acceptance criteria

  • All five managed skills are installed under a controller--prefixed directory in each provider home (~/.anita/skills, ~/.codex/skills, ~/.claude/skills).
  • Each SKILL.md body's name: frontmatter matches the directory name.
  • Each skill body is updated to reference its new name where relevant (self-references and examples).
  • The / picker in the chat composer no longer lists controller-managed skills.
  • The MANAGED_MARKER constant is updated to reference this issue.
  • The orchestrator still loads the body of a managed skill on demand when an agent reaches for it (e.g. controller-browser, controller-integrations); filesystem discovery is unchanged.
  • Tests cover:
    • mergeSkillMetadata includes managed entries for body lookup.
    • fetchAgentSkills payloads expose scope: "managed" for the renamed skills.
    • The picker's filter excludes managed entries (extend skills.test.ts or add a new picker test).
    • extractSkillInvocation still matches the new names.
  • CHANGELOG entry under [Unreleased] describes the rename and the picker change.
  • README mention of /<skill-name> (if any) is updated; existing per-agent and unified skills are unaffected.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions