Skip to main content
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.

Source on GitHub

The canonical CONTRIBUTING.md in the abilities repo. This page mirrors it — refer to the GitHub copy if anything looks out of date.

The Two-Minute Version

  1. Fork the 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
  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
BranchPurposeWho merges
mainStable, production-ready. Always deployable.Maintainers only
devIntegration 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
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.

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 over time.

Step-by-Step Guide

1. Fork and Clone

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:
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

TemplateUse when
templates/basic-template/Simple ask → respond → done
templates/api-template/You’re calling an external API
templates/loop-template/Interactive / multi-turn conversation
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())
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.

Blocked Imports & Keywords

BlockedWhyUse instead
print()Bypasses structured loggingself.worker.editor_logging_handler
open() (raw)Unmanaged filesystem accessself.capability_worker.read_file() / write_file()
redisDirect datastore couplingPlatform-provided helpers
user_configCan leak/mutate global stateCapabilityWorker / worker APIs
exec()Insecure dynamic code executionNot allowed
pickle/dill/shelve/marshalInsecure deserializationNot allowed
Full list → Blocked Imports and Keywords.

5. Write Your README

Create community/your-ability-name/README.md using this format:
# 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 → 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

git fetch upstream
git rebase upstream/dev
Or use merge if you prefer:
git fetch upstream
git merge upstream/dev

8. Submit Your PR

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 runvalidate-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’tDo instead
Open a PR to mainTarget dev — always
Branch off mainBranch 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 keysUse placeholders + document in README
Forget resume_normal_flow()Call it on every exit path
Write long spoken responsesKeep it short — 1-2 sentences per speak() call
Push directly to dev or mainPush to your ability branch, open a PR

Promotion Path

Community abilities that stand out can be promoted to Official status:
CriteriaThreshold
Marketplace installs50+
StabilityNo critical bugs for 30+ days
Code qualityClean, follows SDK patterns
Author responsivenessResponds to issues
UsefulnessFills 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

Discord

Ask questions and share works-in-progress with the community.

Report a Bug

Found a bug in an ability? Open an issue.

Suggest an Ability

Vote on and suggest new ability ideas in Discussions.

SDK Reference

Full SDK docs for ability authors.

License

By submitting a PR, you agree that your contribution is licensed under the MIT License. Original authorship is always credited in your ability’s README and in CONTRIBUTORS.md.