Skip to content

Use skills from other agent harnesses #1277

Open
1 of 7 issues completed
Open

Description

@santoshkumarradha

Skills written for other agent harnesses should work in codeaf. This issue is the plan for the first version, settled in the thread below: parity with the other harnesses first, nothing self-evolving.

What we are building

  • Read skills from where they already live. A skill is an agentskills.io folder: a directory holding a SKILL.md with name and description in its frontmatter, and optionally scripts/, references/ and assets/ beside it. codeaf finds them in the standard folders and never asks you to move or rewrite one.
  • Every skill is yours to invoke, any time, by its own name. /<skill-name> [what you want] puts the skill's instructions in front of the model for this turn. Every discovered skill is a slash command, and the picker under the draft lists them beside codeaf's own commands.
  • A subset you choose is auto-invoked, and you see it happen. For the skills you turn on, the model sees a one-line catalog (name, description, size) and pulls a skill's body in itself when the work matches. Every such pull draws a row in the transcript naming the skill. Nothing auto-loads because it happened to be on disk.
  • You choose where. A skill is turned on globally, for a project, or for one conversation. Narrower wins: a skill on globally can be turned off in one project, and one off globally can be turned on in one conversation.
  • Adding a skill is one command. /skill add <folder> or /skill add <git url> copies it into codeaf's own skills folder, global or project. /skill is the management command: add, remove, on, off, and use for a skill whose name a built-in command already owns.
  • Skills work anywhere the model works. In the chat and inside a task node alike. Delegating to a task is possible, never required.
  • A Skills tab in /settings lists everything discovered as one catalog, its size, and its on/off per scope. It does not say which folder a skill came from; a skill in codeaf's own folder carries one mark, an imported one carries none.

The format

One SKILL.md per folder. Frontmatter fields: name (1–64 chars, lowercase letters, digits and hyphens), description (1–1024 chars), optional license, compatibility, metadata, allowed-tools. The body is Markdown and there is no format restriction on it. We read leniently the way the spec's client guide recommends: a name that does not match its folder or exceeds 64 chars loads with a warning shown in the Skills tab, a missing description or unparseable frontmatter skips the skill and the tab says why. The one common malformation, an unquoted description: containing a colon, is repaired before the YAML parse.

allowed-tools is read and shown on the skill's row, and pre-approves nothing. A tool call made while following a skill goes through the same approval settings as any other call, so a skill can never widen what you have allowed.

Three tiers of cost, and we pay each only when it is earned:

Tier What When Cost
catalog name + description + size every request, for skills turned on ~50–100 tokens per skill
instructions the SKILL.md body when invoked or auto-invoked the body, once per conversation
resources scripts/, references/, assets/ when the body points at them read on demand with read/bash

Where we read on day one

Project scope (the git root of where codeaf was opened, else the folder itself), in this order:

<project>/.codeaf/skills/     codeaf's own
<project>/.agents/skills/     the cross-client convention
<project>/.claude/skills/
<project>/.codex/skills/
<project>/.cursor/skills/
<project>/.gemini/skills/
<project>/.opencode/skills/
<project>/.goose/skills/

User scope, same order under ~:

~/.codeaf/skills/   ~/.agents/skills/   ~/.claude/skills/   ~/.codex/skills/   ~/.cursor/skills/   ~/.gemini/skills/   ~/.opencode/skills/   ~/.goose/skills/

Every folder is scanned silently, with no import step and no question; a folder that does not exist is skipped without a word. A skill is a direct child directory holding SKILL.md; nothing is walked deeper. The result is ONE catalog. The scan order above is the precedence: the first skill seen under a name is the skill, and a later folder's skill with the same name is ignored. So a project's skill shadows a user's, and .codeaf/skills shadows every other harness's at the same level. ~/.codeaf/skills/ is also where the resident keeps its promoted commands; those folders have no SKILL.md and the scan does not see them. A folder attached with /folder contributes its project-scope skills too, listed under its own path.

How a skill reaches the model

Invoked by you. /<skill-name> [words] sends the skill body plus your words as the turn. The transcript shows the line you typed, not the body. If the skill is already in this conversation's context, only your words are sent and the skill is named as already loaded. The slash table today is a fixed list, so this needs a second, dynamic source of commands that the picker ranks and the dispatcher consults after the fixed table. codeaf's own commands always win a name; a skill named like one of them is reached through /skill use <name> [words] instead, which does exactly what its own slash would have done, and its row in the tab says so. /skills opens the Skills tab.

Auto-invoked. Skills turned on for this scope are listed in the system prompt as a catalog, and one tool, skill, whose name argument is constrained to those names, returns the body wrapped so the model can tell it from conversation:

<skill name="pdf-processing" dir="/home/you/.agents/skills/pdf-processing">
...body...
resources: scripts/extract.py, references/REFERENCE.md
</skill>

Relative paths in the body resolve against dir; the skill's folder is allow-listed for read so bundled files do not each cost a permission prompt.

You always see an auto-invocation. The model pulling a skill in is a tool call like any other, so it draws its own row in the transcript at the moment it happens, naming the skill and what it cost:

  ◆ used skill pdf-processing · 3.1 KB

The row is never folded into the model's prose and never omitted, so a person can always tell a turn that followed a skill from one that did not. Inside a task the same row appears on the task page among the node's steps. When no skill is turned on, the catalog and the tool are absent, not empty (the absent-not-broken law). The catalog changes only when you change a setting or attach a folder, so it rides message[0] with the standing orders and folders and does not re-price the transcript per turn. A loaded skill is not summarised away by compaction.

Inside a task. A task node renders its own system prompt, so it gets the same catalog and the same tool for its scope. propose_task gains an optional skills list to pin named skills into a node's brief, so the chat can hand skilled work to a task with the skill attached. A worker on the bash belt gets the catalog and reads SKILL.md with the shell it has.

Where the choice is kept

Scope File Shape
global ~/.codeaf/skills.json, beside config.json in the profile on: [names], off: [names]
project <project>/.codeaf/skills.json the same two lists, written by the product like autonomy.json, gitignore it or commit it as you like
conversation the conversation's meta.json the same two lists

The global file is its own file rather than rows in config.json: a list of skill names is not a setting the registry can describe, and a config.json key nothing reads is one the unread-key notice would flag.

Effective state for a skill: conversation says on/off, else project, else global, else off. Every write goes through one engine door so the Skills tab and /skill on|off cannot disagree.

Adding a skill

/skill add ~/some/folder                    copies it into ~/.codeaf/skills/<name>/
/skill add ~/some/folder --project          into <project>/.codeaf/skills/<name>/
/skill add https://github.com/o/r           clones, finds every SKILL.md, copies each
/skill add https://github.com/o/r/tree/main/skills/pdf   one folder out of a repo

The URL form clones to a temp directory with the git on PATH and copies out; nothing is executed. A name already present asks before it overwrites. /skill remove <name> removes only from a codeaf folder, never from another harness's.

The Skills tab

One row per discovered skill:

◆ pdf-processing     3.1 KB    on here · on globally
  brand-voice        12 KB     off
  data-analysis      8.4 KB    on for this project

The mark on the first row says it lives in codeaf's own folder; the other two were found in another harness's folder, and the tab does not say which.

Enter cycles the row's state for the current conversation; a second key sets it for the project or globally. A row with a warning shows it dimly, and a skill declaring allowed-tools shows the list. The size is what an invocation costs, in bytes and an estimated token count, so the choice is yours with the number in front of you.

Not in this version

Kept from the design note in the thread for later, once the basics have been used: per-skill checks attached to task acceptance, a cost and outcome ledger per skill, demotion of skills that show no value, cue write-back, trust levels beyond "you turned it on", and forging skills from repeated runs. Editing a skill when it is wrong is the first tool, and the rest should earn its place from real use.

Build order

  1. Discover and parse. internal/skills: the ordered scan into one catalog, first-seen-wins by name, lenient frontmatter, warning records, size, the native mark. Pure, tested against fixtures under testdata/.
  2. Invoke. /<skill-name> [words]: the dynamic command source beside the fixed table, ranked by the picker and consulted by the dispatcher, body sent as the turn's text; the manual page and command-table gates.
  3. Choose and auto-invoke. Scope storage in the three files, the catalog in message[0], the skill tool with its belt-fact sentence, the transcript row every auto-invocation draws, dedup and compaction protection.
  4. Settings tab. The Skills tab, /skill on|off [--project|--global], warnings and shadowing shown.
  5. Add and remove. Folder and git URL, project or global.
  6. Tasks. propose_task.skills, catalog and tool in a node, the bash belt reads SKILL.md.

The six steps land as ONE pull request against dev, in that order of commits, with one change entry. docs/CHAT-V3.md records that v3 deliberately dropped "skills & rules" in favour of routed memory; step 3's entry invalidates that.

Settled since the first draft

  • A project's skills from a freshly cloned repository are invocable by you and never auto-invoked until turned on. The scope model gives this without a trust setting.
  • allowed-tools pre-approves nothing; a skill's tool use is judged by the existing approval settings like any other.
  • OpenCode and Goose folders are read on day one. Every folder is scanned silently into one catalog; there is no import step. First seen wins a name, in the scan order above.
  • A skill is invoked by its own name as a slash command, not through /skill <name>. /skill manages skills: add, remove, on, off, and use as the fallback when a built-in command owns the name.
  • An auto-invocation is always visible: one transcript row per pull, naming the skill and its size.

Drafted with CodeAF · reviewed and owned by the author

Activity

  1. added
    featureWork that adds a capability; developers break it into tasks
    area:toolsThe tool layer: built-in tools, registries, belts
    roadmapA public roadmap outcome; the card on the Agent-Field board links here for votes and discussion
    needs groomingShape and scope are still being decided — the approach is not settled
    on Sep 19, 2026
  2. santoshkumarradha commented on Sep 21, 2026

    @santoshkumarradha
    MemberAuthor

    Design note: skills as attachments, not injections

    The issue names the hard part correctly: the question is not whether we can read a skill file, it is when a skill earns its place in a run. This is the design that falls out of how CodeAF already works.

    The one law: the conversation holds the shelf; the work carries the skills.

    Skill bodies never load into the chat. Chat carries only a catalog: names, one-line docs, and cost cards, windowed to what is relevant right now, with search for the long tail. When work needs a skill, the skill is attached to the task node doing the work, where context is fresh, bounded, and disposable. If chat itself needs skilled work done, it hands that piece to a quick task with the skill attached and keeps only the result. The conversation stays clean enough to think.

    A skill here is five things, not one file:

    1. Trigger — cues and a one-line doc, what selection matches on.
    2. Payload — the body, scripts, and resources, stored content-addressed and pinned by digest, so a rerun next month uses the exact skill that ran today.
    3. Check — an executable "was this applied correctly," where one can be written. Attaching a skill attaches its check to the node's acceptance checks. Skill use becomes verified, not assumed.
    4. Cost card — what it costs to read, to run, or to delegate, learned from real runs.
    5. Trust level — authored, imported (provisional until it passes a trial in a clean workspace), or forged (distilled from repeated real jobs, arriving pre-trialed).

    Attachment is per node, several at a time, ordered. Real work is compositional: the render leaf of a task graph gets the video skill, the copy leaf gets the brand skill, and order is precedence. A skill can always be pinned ("use the pdf skill"), retrieval proposes from cues and scope, and a worker can pull a skill itself mid-run when it discovers the need. Pinned always outranks retrieved.

    Three ways a skill is consumed, chosen by its cost card:

    • Read — the body is pulled into the worker on demand. Cheap skills.
    • Run — the skill is an executable on PATH. Zero prompt tokens at all.
    • Delegate — the skill is itself a task shape; it runs as a sub-task and only the distilled result returns. Heavy pipelines, and the only way chat ever touches a non-trivial skill.

    What keeps it honest: every run records cost and check outcomes per attached skill. Skills whose attachments keep failing checks get rewritten. Skills that show no marginal value against similar runs without them are demoted to pin-only. Misses (a run that should have used a skill and didn't) write their cues back, so selection improves from real use. And a skill's check runs only when its payload was actually consumed; bodies are served from the store, so consumption is a fact, not a report. An attached-but-unused skill costs one doc line, nothing more.

    flowchart TD
        A["You ask for something"] --> C{"Chat (sees the shelf,<br/>never the bodies)"}
        C -->|"pocket-sized step"| C2["Chat does it inline"]
        C -->|"everything else"| N["Task node,<br/>skills attached by digest"]
        P["You pin a skill"] -. "always wins" .-> N
        R["Retrieval on cues + scope"] -. "proposes" .-> N
        N --> M{"Each attached skill is consumed by"}
        M -->|"read"| M1["Body pulled in on demand"]
        M -->|"run"| M2["Executable on PATH"]
        M -->|"delegate"| M3["Runs as a sub-task,<br/>only the result returns"]
        M1 --> K["Node checks: the task's own<br/>+ every consumed skill's"]
        M2 --> K
        M3 --> K
        K --> L[("Ledger: cost, pass/fail,<br/>marginal value")]
        L -->|"earns its tokens"| U["Attached more readily"]
        L -->|"no marginal value"| D["Demoted to pin-only"]
        L -->|"misses"| W["Cue write-back,<br/>selection improves"]
    
    Loading

    What this means for skills written for other harnesses: they stay where they are. The standard folders and formats are read unmodified, an imported skill works immediately at provisional trust, and it earns full trust by passing a trial rather than by assertion. Because bodies only ever enter disposable task contexts, imported skills get the same sandboxing as everything else the system runs. A skill collection becomes more valuable here, not merely compatible.

    Position on the open questions in the issue:

    • Which folders and formats on day one: the standard skill folders other harnesses read, unmodified.
    • How a skill gets chosen: pin > retrieval > worker self-serve, with the cost card and the ledger deciding how readily each is offered, and the shelf always visible for override.
    • Many skills on one folder: the catalog is windowed by scope and relevance; a folder's skills are candidates for attachment, never a bulk load.
    • Showing cost: the cost card sits on every skill row, and the ledger shows what each attached skill actually cost the run.

    Build order follows the loop: shelf and attachment first, checks and the ledger next, forge last.

    drafted with CodeAF

  3. santoshkumarradha commented on Sep 21, 2026

    @santoshkumarradha
    MemberAuthor

    CC @ZeroPoint95 take ?

  4. ZeroPoint95 commented on Sep 21, 2026

    @ZeroPoint95
    Collaborator

    CC @ZeroPoint95 take ?

    @santoshkumarradha The grading/performance ledger stuff is cool but I don't know that it's worth the complexity. It's usually easier to just edit a skill if there is something wrong with it, unless you are in a situation where your agents need to absorb a lot of niche knowledge over time.

    I think it's hard to find a real use case where you both need a self-evolving set of skills and have enough useful information to actually do the evolution in a productive way.

    Basically I would suggest starting with a simpler implementation to achieve parity with other harnesses:

    • Discover and index existing skills (from other harnesses) assuming they are agentskills.io compatible.
    • make it really easy to add new skills (via folder OR repo url)
    • all skills are user-invokable at any time
    • a subset of skills chosen by the user may be auto-invoked in scopes chosen by the user (global > project > session)
    • skills can be invoked or auto-invoked anywhere - don't require delegating to a task, but you still can
    • a skills tab in settings (or standalone) would be useful here

    Anyways open to discussion as always :)

  5. santoshkumarradha commented on Sep 21, 2026

    @santoshkumarradha
    MemberAuthor

    Gtg with me. Feel free to update issues sur. @ZeroPoint95

  6. AbirAbbas commented on Sep 23, 2026

    @AbirAbbas
    Collaborator

    Cross-link: #1399 opens the npx skills (vercel-labs/skills) listing for codeaf once this issue is in a release. That listing makes codeaf a "universal" agent there, so npx skills writes skills to <project>/.agents/skills and ~/.agents/skills. The scan in internal/skills already reads both folders.

    One thing relevant to codeaf's own folder: #1399 declares ~/.agents/skills as codeaf's global folder upstream, not ~/.codeaf/skills. Upstream's skills remove -g runs rm -rf <globalSkillsDir>/<name> for every agent in its table without checking that the path is a skill, and ~/.codeaf/skills also holds the resident's bin/ shelf.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:toolsThe tool layer: built-in tools, registries, beltsfeatureWork that adds a capability; developers break it into tasksneeds groomingShape and scope are still being decided — the approach is not settledroadmapA public roadmap outcome; the card on the Agent-Field board links here for votes and discussion

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions