> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openhome.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Contributing an Ability

> How to build, test, and submit a community ability to the OpenHome abilities repo.

Thanks for wanting to contribute! This guide walks you from idea to merged PR. If you're building great abilities with real, high-impact use cases, also check out [What Makes a Good Ability](/building-abilities/what-makes-a-good-ability).

<Card title="Source on GitHub" icon="github" href="https://github.com/openhome-dev/abilities/blob/dev/CONTRIBUTING.md">
  The canonical CONTRIBUTING.md in the abilities repo. This page mirrors it — refer to the GitHub copy if anything looks out of date.
</Card>

## The Two-Minute Version

1. Fork the [openhome-dev/abilities](https://github.com/openhome-dev/abilities) repo
2. Copy `templates/basic-template/` to `community/your-ability-name/`
3. Build your ability (edit `main.py`) and write a `README.md`
4. Test it in the [OpenHome Live Editor](https://app.openhome.com/dashboard/abilities)
5. Open a Pull Request **against `dev`**

That's it — maintainers will review and merge.

## Branching & Merging Strategy

We use a simplified Git Flow. All contributions follow this flow:

```
ability/your-ability-name  →  dev  →  main
```

| Branch               | Purpose                                          | Who merges                           |
| -------------------- | ------------------------------------------------ | ------------------------------------ |
| `main`               | Stable, production-ready. Always deployable.     | Maintainers only                     |
| `dev`                | Integration and testing. All PRs target this.    | Maintainers after review             |
| `ability/*`, `add-*` | Your working branch for a single ability/change. | You push; maintainers merge to `dev` |

<Warning>
  Never open a PR directly to `main`. All PRs must target `dev`. PRs targeting `main` will be closed and you'll be asked to re-open against `dev`.
</Warning>

## How the Repo Is Organized

```
official/    ← Maintained by OpenHome. Don't submit PRs here.
community/   ← Your contributions go here.
templates/   ← Starting points. Copy one to get going.
docs/        ← Guides and API reference.
```

You submit to `community/` only. Exceptional community abilities can be [promoted to official](#promotion-path) over time.

## Step-by-Step Guide

### 1. Fork and Clone

```bash theme={"system"}
git clone https://github.com/YOUR_USERNAME/abilities.git
cd abilities
git remote add upstream https://github.com/OpenHome-dev/abilities.git
git fetch upstream
git checkout dev
git pull upstream dev
```

### 2. Create Your Ability Branch

Branch off `dev` — not `main`:

```bash theme={"system"}
git checkout -b add-your-ability-name dev
```

Use a descriptive branch name like `add-dad-jokes`, `add-pomodoro-timer`, or `fix-weather-error-handling`.

### 3. Pick a Template

| Template                    | Use when                              |
| --------------------------- | ------------------------------------- |
| `templates/basic-template/` | Simple ask → respond → done           |
| `templates/api-template/`   | You're calling an external API        |
| `templates/loop-template/`  | Interactive / multi-turn conversation |

```bash theme={"system"}
cp -r templates/basic-template community/your-ability-name
```

### 4. Build Your Ability

Edit `main.py`. Every ability must:

* Extend `MatchingCapability`
* Have `register_capability()` (copy the boilerplate exactly from the template)
* Have `call()` that sets up `worker` + `capability_worker` and launches async logic
* Call `self.capability_worker.resume_normal_flow()` on **every exit path**
* Handle errors with `try/except`
* Use `self.worker.editor_logging_handler` for logging (never `print()`)

<Note>
  Trigger words are configured in the OpenHome dashboard, not in code. The `register_capability` boilerplate reads a platform-managed `config.json` at runtime — you never create or edit that file.
</Note>

#### Blocked Imports & Keywords

| Blocked                      | Why                             | Use instead                                           |
| ---------------------------- | ------------------------------- | ----------------------------------------------------- |
| `print()`                    | Bypasses structured logging     | `self.worker.editor_logging_handler`                  |
| `open()` (raw)               | Unmanaged filesystem access     | `self.capability_worker.read_file()` / `write_file()` |
| `redis`                      | Direct datastore coupling       | Platform-provided helpers                             |
| `user_config`                | Can leak/mutate global state    | `CapabilityWorker` / `worker` APIs                    |
| `exec()`                     | Insecure dynamic code execution | Not allowed                                           |
| `pickle/dill/shelve/marshal` | Insecure deserialization        | Not allowed                                           |

Full list → [Blocked Imports and Keywords](/building-abilities/how-to-build#blocked-imports-and-keywords).

### 5. Write Your README

Create `community/your-ability-name/README.md` using this format:

```markdown theme={"system"}
# Your Ability Name

![Community](https://img.shields.io/badge/OpenHome-Community-orange?style=flat-square)
![Author](https://img.shields.io/badge/Author-@yourusername-lightgrey?style=flat-square)

## What It Does
One or two sentences explaining what this ability does.

## Suggested Trigger Words
- "trigger phrase one"
- "another trigger"

## Setup
- Any API keys needed and where to get them
- Any other setup steps

## How It Works
Brief description of the conversation flow.

## Example Conversation
> **User:** "trigger phrase one"
> **AI:** "Response example..."
```

### 6. Test It

* Zip your ability folder
* Go to [app.openhome.com](https://app.openhome.com) → Abilities → Add Custom Ability
* Upload and test in the Live Editor
* Set trigger words in the dashboard
* Make sure all exit paths work (say "stop", "exit", etc.)

### 7. Sync with `dev` Before Submitting

```bash theme={"system"}
git fetch upstream
git rebase upstream/dev
```

Or use merge if you prefer:

```bash theme={"system"}
git fetch upstream
git merge upstream/dev
```

### 8. Submit Your PR

```bash theme={"system"}
git add community/your-ability-name/
git commit -m "Add your-ability-name community ability"
git push origin add-your-ability-name
```

Open a Pull Request on GitHub:

* **Base branch:** `dev` (not `main`)
* **Compare branch:** `add-your-ability-name`
* Fill out the PR template completely

## What Happens After You Open a PR

1. **Automated checks run** — `validate-ability`, `path-check`, `security-scan`, and linting must all pass.
2. **A maintainer reviews** — typically within 3–5 business days.
3. **Feedback round** — push additional commits to the same branch; the PR updates automatically.
4. **Merge to `dev`** — once approved, a maintainer squash-merges your PR into `dev`.
5. **Promotion to `main`** — periodically, maintainers validate `dev` and merge it into `main`. Your ability becomes available on the Marketplace at that point.

## Review Checklist

### Must Pass (Hard Requirements)

* PR targets the **`dev` branch** (not `main`)
* Files are in `community/your-ability-name/` (not in `official/`)
* `main.py` follows the SDK pattern (extends `MatchingCapability`, has `register_capability` + `call`)
* `README.md` is present with description, suggested trigger words, and setup instructions
* `resume_normal_flow()` is called on every exit path
* No `print()` statements (use `editor_logging_handler`)
* No blocked imports (`redis`, `user_config`, `open()`)
* No `asyncio.sleep()` or `asyncio.create_task()` (use `session_tasks` helpers)
* No hardcoded API keys (use `"YOUR_API_KEY_HERE"` placeholders)
* Error handling on all API calls and external operations

### Nice to Have

* Spoken responses are short and natural (this is voice, not text)
* Exit/stop handling in any looping ability
* Inline comments explaining non-obvious logic

## What NOT to Do

| Don't                            | Do instead                                       |
| -------------------------------- | ------------------------------------------------ |
| Open a PR to `main`              | Target `dev` — always                            |
| Branch off `main`                | Branch off `dev`                                 |
| Submit to `official/`            | Submit to `community/`                           |
| Use `print()`                    | Use `self.worker.editor_logging_handler.info()`  |
| Use `asyncio.sleep()`            | Use `self.worker.session_tasks.sleep()`          |
| Use `asyncio.create_task()`      | Use `self.worker.session_tasks.create()`         |
| Hardcode API keys                | Use placeholders + document in README            |
| Forget `resume_normal_flow()`    | Call it on every exit path                       |
| Write long spoken responses      | Keep it short — 1-2 sentences per `speak()` call |
| Push directly to `dev` or `main` | Push to your ability branch, open a PR           |

## Promotion Path

Community abilities that stand out can be promoted to Official status:

| Criteria              | Threshold                     |
| --------------------- | ----------------------------- |
| Marketplace installs  | 50+                           |
| Stability             | No critical bugs for 30+ days |
| Code quality          | Clean, follows SDK patterns   |
| Author responsiveness | Responds to issues            |
| Usefulness            | Fills a real gap              |

When promoted, the ability moves from `community/` to `official/`, gets the Official badge on Marketplace, and OpenHome takes over maintenance (author stays credited).

## Getting Help

<CardGroup cols={2}>
  <Card title="Discord" icon="discord" href="https://discord.gg/openhome">
    Ask questions and share works-in-progress with the community.
  </Card>

  <Card title="Report a Bug" icon="bug" href="https://github.com/openhome-dev/abilities/issues/new?template=bug-report.yml">
    Found a bug in an ability? Open an issue.
  </Card>

  <Card title="Suggest an Ability" icon="lightbulb" href="https://github.com/openhome-dev/abilities/discussions/categories/ability-ideas">
    Vote on and suggest new ability ideas in Discussions.
  </Card>

  <Card title="SDK Reference" icon="book" href="/api-sdk/sdk-reference">
    Full SDK docs for ability authors.
  </Card>
</CardGroup>

## License

By submitting a PR, you agree that your contribution is licensed under the [MIT License](https://github.com/openhome-dev/abilities/blob/dev/LICENSE). Original authorship is always credited in your ability's README and in CONTRIBUTORS.md.
