Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions .github/workflows/skills.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: skills

on:
pull_request:
push:
branches: [main]

jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# An installed skill never receives the final-override slot: it is the one
# position from which a prompt can overrule a shared safety rule, and a
# downloaded file does not get it. So a contributor who writes one has
# written something that silently does nothing. Better to learn that from
# a failing check than from a skill that quietly has no effect.
- name: No override blocks, which an installed skill never receives
run: |
if grep -rl "oxcode:final-override" plugins/ ; then
echo "::error::An installed skill cannot use the final-override slot."
echo "::error::It is ignored at load, so this block would do nothing. Remove it."
exit 1
fi

# Model ids change under us and a skill that names one goes stale for
# everybody at once. capability is the field to use; OxCode routes.
- name: No model or provider named
run: |
if grep -rniE "^model:|\bkimi\b|\bdeepseek\b|\bgpt-[0-9]|\bclaude-|\bgemini\b" plugins/ --include=SKILL.md ; then
echo "::error::A skill must not name a model or provider. Use capability."
exit 1
fi

- name: Every plugin declares a manifest, and it parses
run: |
fail=0
for d in plugins/*/ ; do
m="$d.oxcode-plugin/plugin.json"
if [ ! -f "$m" ]; then
echo "::error::$d has no .oxcode-plugin/plugin.json"; fail=1; continue
fi
python3 -c "import json,sys; json.load(open('$m'))" || { echo "::error::$m is not valid JSON"; fail=1; }
done
python3 -c "import json,sys; json.load(open('.oxcode-plugin/marketplace.json'))" \
|| { echo "::error::marketplace.json is not valid JSON"; fail=1; }
exit $fail

# The manifest lists what exists, so a plugin nobody can find is a plugin
# nobody installs, and a listing that points at nothing is worse.
- name: Every plugin is listed, and every listing exists
run: |
python3 - <<'PY'
import json, os, sys
mk = json.load(open('.oxcode-plugin/marketplace.json'))
listed = {p['name']: p['source'] for p in mk['plugins']}
on_disk = sorted(d for d in os.listdir('plugins') if os.path.isdir(f'plugins/{d}'))
fail = False
for d in on_disk:
if d not in listed:
print(f"::error::plugins/{d} exists but is not in marketplace.json"); fail = True
for name, src in listed.items():
if not os.path.isdir(src):
print(f"::error::marketplace.json lists {name} at {src}, which does not exist"); fail = True
elif not os.path.isdir(os.path.join(src, 'skills')):
print(f"::error::{src} has no skills/ directory"); fail = True
sys.exit(1 if fail else 0)
PY

# A skill that will not parse cannot be merged. Two core keys, and a
# frontmatter block to carry them.
- name: Every SKILL.md has frontmatter with name and description
run: |
python3 - <<'PY'
import glob, sys
fail = False
for f in glob.glob('plugins/**/SKILL.md', recursive=True):
t = open(f, encoding='utf-8').read()
if not t.lstrip().startswith('---'):
print(f"::error::{f} has no frontmatter block"); fail = True; continue
head = t.split('---', 2)[1]
for key in ('name:', 'description:'):
if key not in head:
print(f"::error::{f} frontmatter is missing {key}"); fail = True
sys.exit(1 if fail else 0)
PY
15 changes: 11 additions & 4 deletions .oxcode-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,24 @@
"plugins": [
{
"name": "code-review",
"source": "./plugins/code-review",
"description": "Review a change for defects that would reach a user, with a reproducing input for every one.",
"category": "development",
"author": "Oxlo.ai",
"source": "./skills/code-review"
"author": "Oxlo.ai"
},
{
"name": "ui-review",
"source": "./plugins/ui-review",
"description": "Review an interface for what a user would actually hit: contrast, focus, overflow, empty and error states.",
"category": "design",
"author": "Oxlo.ai",
"source": "./skills/ui-review"
"author": "Oxlo.ai"
},
{
"name": "ml",
"source": "./plugins/ml",
"description": "The seven-stage machine learning pipeline, one skill per stage.",
"category": "data",
"author": "Oxlo.ai"
}
]
}
98 changes: 71 additions & 27 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
# Contributing a skill

One pull request, one skill folder. That keeps review fast and lets us take
yours without waiting on anything else in the same branch.
One pull request, one plugin. That keeps review fast and lets us take yours
without waiting on anything else in the same branch.

## What review means here

Read this part first, because it is what makes this repository different from a
docs repository.

A skill is a system prompt that runs on someone else's machine with file and
command tools. So **a pull request here is a security review, not a docs
review**, and these are what a reviewer checks:

- **The body instructs rather than describes.** A skill that restates the docs
changes no answer and costs tokens on every request.
- **Nothing needs a secret.** If it only works with your API key, it is not a
skill.
- **No model or provider is named anywhere.** Model ids change under us and a
skill naming one goes stale for everybody at once. Use `capability` and let
OxCode route. CI rejects this, so you will see it before we do.
- **The skill does not try to widen its own tools.** `tools` is a request that
gets clamped to whatever the session already allows. It is never a grant.
- **No `oxcode:final-override` block.** An installed skill never receives that
slot, so writing one ships something that silently does nothing. CI rejects it.

Expect questions. We would rather ask than merge something that adds tokens to
every request and nothing to any answer.

## What we are looking for

Expand All @@ -24,26 +48,50 @@ payments work.
- **Generic advice.** If it reads like it could apply to any task, it will not
change any answer. "Follow best practices", "write clean code", "consider edge
cases" cost tokens on every request and buy nothing.
- **A model or provider named anywhere.** Model ids change under us and a skill
that names one goes stale for everybody at once. Use `capability` and let
OxCode route. A `model:` key is rejected by the parser, not ignored.
- **A restatement of the docs.** Link the docs. Put the things the docs get
wrong or bury in the skill.
- **Anything that needs a secret.** Skills are prompts. If it only works with
your API key, it is not a skill.
- Anything failing the review checks above.

## Writing it
## The layout

Start from [`template/SKILL.md`](template/SKILL.md).
The installable unit is a **plugin**. A plugin is a directory that may carry
several skills, which is why the ML pipeline ships as one plugin with seven.

```
skills/
your-skill/
SKILL.md
plugins/
your-plugin/
.oxcode-plugin/
plugin.json
skills/
your-skill/
SKILL.md
```

The folder name is the skill's id and should match `name` in the frontmatter.
Use lowercase with hyphens.
Start from [`template/SKILL.md`](template/SKILL.md).

The skill's directory name is its id and should match `name` in the frontmatter.
Lowercase with hyphens. A plugin carrying one skill usually gives them the same
name.

`plugin.json`:

```json
{
"name": "your-plugin",
"version": "1.0.0",
"description": "Same one line as the marketplace entry.",
"author": { "name": "Your name or handle" },
"license": "MIT",
"requires": { "oxcode": ">=0.4.0" }
}
```

`requires.oxcode` is the lowest version your plugin works on. Leave it at
`>=0.4.0` unless you use something newer, and raise it if you do: a user on an
older extension is then told what they need instead of installing something that
half works.

## Writing it

**Write the description as a trigger.** It is what the model reads to know your
skill exists, and it is the one line a person reads in the picker. Say what it
Expand All @@ -64,11 +112,11 @@ following it.

## Testing it before you open the PR

You do not need to install anything or wait for us. Copy your folder into your
own skills directory:
You do not need to install anything or wait for us. Copy the skill into your own
skills directory:

```bash
cp -r skills/your-skill ~/.oxcode/skills/
cp -r plugins/your-plugin/skills/your-skill ~/.oxcode/skills/
```

OxCode picks it up on save. Type `/your-skill` and give it a real task. If the
Expand All @@ -85,24 +133,20 @@ Add your entry to `.oxcode-plugin/marketplace.json`:

```json
{
"name": "your-skill",
"description": "Same one line as the frontmatter",
"name": "your-plugin",
"description": "Same one line as the manifest",
"category": "development",
"author": "Your name or handle",
"source": "./skills/your-skill"
"source": "./plugins/your-plugin"
}
```

CI checks that every plugin on disk is listed and every listing exists, so a
missing entry fails before a human looks at it.

In the description, tell us:

- What task you used it on, and what changed in the answer.
- What you deliberately left out, and why.

That second one is the part we read first. It tells us you drew a boundary.

## Review

We review for whether the skill changes an answer, and for whether its
instructions are specific enough to follow. Expect questions about anything
that reads as general advice. We would rather ask than merge something that
adds tokens to every request and nothing to any answer.
13 changes: 13 additions & 0 deletions plugins/code-review/.oxcode-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "code-review",
"version": "1.0.0",
"description": "Review a change for defects that would reach a user, with a reproducing input for every one.",
"author": {
"name": "Oxlo.ai"
},
"license": "MIT",
"homepage": "https://github.com/Cyborg-Network/oxcode-skills",
"requires": {
"oxcode": ">=0.4.0"
}
}
12 changes: 12 additions & 0 deletions plugins/ghost/.oxcode-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "ghost",
"version": "1.0.0",
"description": "A plugin nobody listed.",
"author": {
"name": "x"
},
"license": "MIT",
"requires": {
"oxcode": ">=0.4.0"
}
}
6 changes: 6 additions & 0 deletions plugins/ghost/skills/ghost/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: ghost
description: A plugin nobody listed.
---

Body.
13 changes: 13 additions & 0 deletions plugins/ml/.oxcode-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "ml",
"version": "1.0.0",
"description": "The seven-stage machine learning pipeline, one skill per stage.",
"author": {
"name": "Oxlo.ai"
},
"license": "MIT",
"homepage": "https://github.com/Cyborg-Network/oxcode-skills",
"requires": {
"oxcode": ">=0.4.0"
}
}
64 changes: 64 additions & 0 deletions plugins/ml/skills/ml-data/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
name: ml-data
command: "ml-mode:data"
label: "ML: Data"
hint: Load, explore, and understand the dataset
description: Load, explore, and understand the dataset
order: 61
icon: ◈
capability: Coding
workspace: required
tools: full
---

You are OxCode in ML Mode, a senior machine learning engineer powered by Oxlo.ai.

You have tools to read files, edit files, run commands, and list directories. Use them; do not describe work you have not done.

WHAT MAKES ML WORK DIFFERENT FROM ORDINARY CODE: a script that is WRONG still runs, still prints a number, and still looks like a success. There is no exception and no red underline, so the discipline below is the only thing standing between a result and a confident wrong number.

1. SPLIT BEFORE YOU FIT ANYTHING. Any transform that learns from data (a scaler, an encoder, a vocabulary, an imputation value) is fitted on the training split ONLY, then applied to the test split. Fitting on the whole dataset first leaks test information into training and produces a score that looks good and means nothing.
2. SEED EVERYTHING, as a named constant at the top of the file. An unseeded run cannot be reproduced or compared, so a change that made things worse is indistinguishable from noise.
3. ALWAYS HAVE A BASELINE. A metric on its own is not a result. Predicting the majority class, or a trivial rule, gives the number that says whether the model learned anything: 98% is excellent on balanced data and worthless when 98% of rows are one class. Compute it from the data; never state one you did not measure.
4. EVALUATE ONLY ON DATA THE MODEL HAS NOT SEEN, and report the metric the run actually printed.

HOW YOU WORK:
- USE THE PROJECT'S OWN ENVIRONMENT, not a bare python. If a .venv, venv, or conda environment exists, run through it, and install into the same one you run with. Installing with one interpreter and running with another is a ModuleNotFoundError three steps into a pipeline that looked fine, and it is the most common way an ML setup wastes an hour before any real work starts.
- Write scripts to FILES and run the files. Never send a training script as python -c: it cannot be re-run, diffed, or fixed a line at a time, and it reaches the user as one unreadable approval card.
- Put every hyperparameter at the TOP as a named constant, written once. A number buried in a call is a number the user cannot tune, and a number written twice will disagree with itself.
- RAISE THE TIMEOUT for anything slow, and estimate the cost before you start a search. Expanding a hyperparameter grid multiplies: six parameters with four values each is 4096 fits before cross-validation, which is hours rather than minutes. Say the size first, and start anything that long with start_process so the user keeps their editor.
- Report what ran, what it printed, and what it means. Lead with the number and the baseline beside it. Never estimate a metric, round one up, or describe a result you did not see.

DATA AND EXPLORATION, and the failure here is proceeding without looking.

- ANSWER THE BASIC QUESTIONS FIRST and put the numbers in your reply: how many rows, how many columns, what type is each, what is the target, and what is its distribution. A model plan written without these is a guess.
- CLASS BALANCE IS THE ONE THAT DECIDES EVERYTHING DOWNSTREAM. Report it explicitly. It determines whether accuracy is a meaningful metric, whether stratifying matters, and what a baseline should be.
- MISSING VALUES: report the count and the share per column, and say whether missingness itself looks informative. Never silently drop rows; say how many would go and what that costs.
- LOOK FOR A COLUMN THAT LEAKS THE TARGET, an id that encodes ordering, or duplicate rows. Finding one of these now saves a whole training cycle spent trusting a bad number.
- SAVE FIGURES TO FILES rather than trying to display them, and say what each one shows in one line. A plot nobody can see is not analysis.
- Do NOT model yet. Finish with what you found and what it implies for the split, the features, and the metric.

<!-- oxcode:orchestrated-guidance -->
WHAT MAKES ML WORK DIFFERENT FROM ORDINARY CODE: a script that is WRONG still runs, still prints a number, and still looks like a success. There is no exception and no red underline, so the discipline below is the only thing standing between a result and a confident wrong number.

1. SPLIT BEFORE YOU FIT ANYTHING. Any transform that learns from data (a scaler, an encoder, a vocabulary, an imputation value) is fitted on the training split ONLY, then applied to the test split. Fitting on the whole dataset first leaks test information into training and produces a score that looks good and means nothing.
2. SEED EVERYTHING, as a named constant at the top of the file. An unseeded run cannot be reproduced or compared, so a change that made things worse is indistinguishable from noise.
3. ALWAYS HAVE A BASELINE. A metric on its own is not a result. Predicting the majority class, or a trivial rule, gives the number that says whether the model learned anything: 98% is excellent on balanced data and worthless when 98% of rows are one class. Compute it from the data; never state one you did not measure.
4. EVALUATE ONLY ON DATA THE MODEL HAS NOT SEEN, and report the metric the run actually printed.

HOW YOU WORK:
- USE THE PROJECT'S OWN ENVIRONMENT, not a bare python. If a .venv, venv, or conda environment exists, run through it, and install into the same one you run with. Installing with one interpreter and running with another is a ModuleNotFoundError three steps into a pipeline that looked fine, and it is the most common way an ML setup wastes an hour before any real work starts.
- Write scripts to FILES and run the files. Never send a training script as python -c: it cannot be re-run, diffed, or fixed a line at a time, and it reaches the user as one unreadable approval card.
- Put every hyperparameter at the TOP as a named constant, written once. A number buried in a call is a number the user cannot tune, and a number written twice will disagree with itself.
- RAISE THE TIMEOUT for anything slow, and estimate the cost before you start a search. Expanding a hyperparameter grid multiplies: six parameters with four values each is 4096 fits before cross-validation, which is hours rather than minutes. Say the size first, and start anything that long with start_process so the user keeps their editor.
- Report what ran, what it printed, and what it means. Lead with the number and the baseline beside it. Never estimate a metric, round one up, or describe a result you did not see.

DATA AND EXPLORATION, and the failure here is proceeding without looking.

- ANSWER THE BASIC QUESTIONS FIRST and put the numbers in your reply: how many rows, how many columns, what type is each, what is the target, and what is its distribution. A model plan written without these is a guess.
- CLASS BALANCE IS THE ONE THAT DECIDES EVERYTHING DOWNSTREAM. Report it explicitly. It determines whether accuracy is a meaningful metric, whether stratifying matters, and what a baseline should be.
- MISSING VALUES: report the count and the share per column, and say whether missingness itself looks informative. Never silently drop rows; say how many would go and what that costs.
- LOOK FOR A COLUMN THAT LEAKS THE TARGET, an id that encodes ordering, or duplicate rows. Finding one of these now saves a whole training cycle spent trusting a bad number.
- SAVE FIGURES TO FILES rather than trying to display them, and say what each one shows in one line. A plot nobody can see is not analysis.
- Do NOT model yet. Finish with what you found and what it implies for the split, the features, and the metric.
<!-- /oxcode:orchestrated-guidance -->
Loading
Loading