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.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.
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
- Fork the openhome-dev/abilities repo
- Copy
templates/basic-template/tocommunity/your-ability-name/ - Build your ability (edit
main.py) and write aREADME.md - Test it in the OpenHome Live Editor
- Open a Pull Request against
dev
Branching & Merging Strategy
We use a simplified Git Flow. All contributions follow this flow:| 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 |
How the Repo Is Organized
community/ only. Exceptional community abilities can be promoted to official over time.
Step-by-Step Guide
1. Fork and Clone
2. Create Your Ability Branch
Branch offdev — not main:
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 |
4. Build Your Ability
Editmain.py. Every ability must:
- Extend
MatchingCapability - Have
register_capability()(copy the boilerplate exactly from the template) - Have
call()that sets upworker+capability_workerand launches async logic - Call
self.capability_worker.resume_normal_flow()on every exit path - Handle errors with
try/except - Use
self.worker.editor_logging_handlerfor logging (neverprint())
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
| 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 |
5. Write Your README
Createcommunity/your-ability-name/README.md using this format:
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
8. Submit Your PR
- Base branch:
dev(notmain) - Compare branch:
add-your-ability-name - Fill out the PR template completely
What Happens After You Open a PR
- Automated checks run —
validate-ability,path-check,security-scan, and linting must all pass. - A maintainer reviews — typically within 3–5 business days.
- Feedback round — push additional commits to the same branch; the PR updates automatically.
- Merge to
dev— once approved, a maintainer squash-merges your PR intodev. - Promotion to
main— periodically, maintainers validatedevand merge it intomain. Your ability becomes available on the Marketplace at that point.
Review Checklist
Must Pass (Hard Requirements)
- PR targets the
devbranch (notmain) - Files are in
community/your-ability-name/(not inofficial/) main.pyfollows the SDK pattern (extendsMatchingCapability, hasregister_capability+call)README.mdis present with description, suggested trigger words, and setup instructionsresume_normal_flow()is called on every exit path- No
print()statements (useeditor_logging_handler) - No blocked imports (
redis,user_config,open()) - No
asyncio.sleep()orasyncio.create_task()(usesession_taskshelpers) - 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 |
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.

