Contributing to taOS

August 2, 2026 ยท View on GitHub

Welcome - and thanks for your interest in contributing. taOS is a self-hosted AI agent platform for low-power hardware. Before diving in, please read the README for a project overview.

Note: The project is in early development. APIs and interfaces may change. That is fine - contributions of all sizes are welcome.


License & Contributor License Agreement

taOS is open source under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later; see LICENSE). A separate commercial license is available from jaylfc for uses the AGPL does not grant, for example embedding taOS in a proprietary product or offering it as a hosted service without releasing your modifications under the AGPL (see COMMERCIAL-LICENSE.md).

To keep this sustainable, all contributors must agree to the Contributor License Agreement (CLA.md) before their contributions are merged. The CLA grants jaylfc the right to include and relicense your contributions under the project's licenses; you keep ownership of your work. You sign once - on your first pull request, comment "I have read the CLA Document and I hereby sign the CLA" and the CLA check turns green; it then covers all your future contributions.


Getting Started for Contributors

git clone https://github.com/jaylfc/taOS.git
cd tinyagentos
uv sync
# Build the desktop SPA - static/desktop/ is gitignored (generated artifact)
cd desktop && npm install && npm run build && cd ..
uv run pytest tests/ --ignore=tests/e2e -n auto

Python 3.10 or later and Node.js 22 or later are required.

For frontend development, use cd desktop && npm run dev - Vite serves with hot reload on port 5173.


Contributing with an AI coding agent

If you work on taOS through a coding agent (Claude Code, opencode, Cursor, or similar), point it at .claude/skills/taos-development-skill/SKILL.md. It ships in the repo, so a clone already has it.

It is the operational companion to this file: repository layout, the architectural patterns worth knowing before touching a subsystem, the local test gate to run before marking work ready, the fork PR and CI specifics, and the pitfalls that have actually cost contributors time here. This file states the conventions; the skill states how to apply them without tripping over the setup.

Agents should read both. The skill deliberately does not restate the conventions in this file, so that the two cannot drift out of sync.

If you are an AI agent reading this: load that skill before making changes, and pay particular attention to "Verifying your work" and "Avoiding collisions with other contributors" below. Most problems here have come from trusting a signal that looked like success rather than from writing bad code.


How to Contribute

Bug Reports

Open a GitHub issue with:

  • A clear title describing the problem
  • Steps to reproduce
  • Expected vs actual behaviour
  • Platform and Python version

Feature Requests

Open a GitHub issue describing:

  • The use case you are trying to solve
  • Why it belongs in the core project rather than a plugin or external tool

Adding Apps to the Catalog

The app catalog is one of the easiest ways to contribute. See Adding an App to the Catalog below.

Code Contributions

  1. Fork the repository
  2. Create a branch: git checkout -b feat/my-feature
  3. Make your changes and add tests
  4. Run uv run pytest tests/ --ignore=tests/e2e -n auto - all tests must pass
  5. Open a pull request against dev, not master

Keep pull requests focused. One feature or fix per PR is easier to review.

Branches: master is the stable branch that installs track, so it only receives tested changes promoted from dev. All contributions target dev. If you open a PR against master by mistake, no problem - we'll retarget it to dev (the commits and review carry over).

Documentation

Documentation improvements are always welcome - typo fixes, clarifications, better examples. Open a PR directly.

The taOS agent manual is compiled: edit docs/agent-manual/ and run python3 scripts/build-agent-manual.py to regenerate docs/taos-agent-manual.md.


Adding an App to the Catalog

The catalog lives in app-catalog/. Each app has its own directory containing a manifest.yaml.

Step 1 - Create the directory

app-catalog/
  agents/        # agent frameworks
  models/        # LLM models
  plugins/       # tools and plugins
  services/      # background services

Pick the appropriate category and create a directory named after your app's id:

mkdir app-catalog/agents/my-framework

Step 2 - Write manifest.yaml

Use app-catalog/agents/langroid/manifest.yaml as a template:

id: my-framework
name: My Framework
type: agent-framework        # agent-framework | model | plugin | service
version: 1.0.0
description: "One-line description of what this does"
homepage: https://github.com/example/my-framework
license: MIT

requires:
  ram_mb: 512                # minimum RAM in MB
  python: ">=3.10"

install:
  method: pip                # pip | script | docker
  package: my-framework

config_schema:
  - name: model
    type: model-select
    label: LLM Model
    required: true

hardware_tiers:
  arm-npu-16gb: full         # full | limited | unsupported
  arm-npu-32gb: full
  x86-cuda-12gb: full
  x86-vulkan-8gb: full
  cpu-only: limited

All fields except config_schema are required. The hardware_tiers block controls which hardware profiles see the app as recommended.

Step 3 - Update catalog.yaml

Add an entry to app-catalog/catalog.yaml under the appropriate section:

- id: my-framework
  type: agent-framework
  version: 1.0.0
  name: My Framework
  description: "One-line description matching your manifest"

Step 4 - Open a PR

Submit a pull request. The CI will run the catalog tests automatically. Include a link to the upstream project in your PR description.


Code Style

Python

  • Follow the patterns already in the codebase - there is no strict linter, but keep it readable
  • One concern per module; avoid cross-importing between route files
  • Use async def for route handlers; use await for all I/O

Frontend

The UI is a React SPA (desktop/) built with Vite. Static assets are served from static/desktop/ after npm run build. If you are adding a new UI surface:

  • Follow existing React patterns in desktop/src/ - no server-rendered templates for new features
  • ARIA labels are required on interactive elements without visible text labels
  • One concern per component; keep API calls in dedicated hooks or service files

Tests

  • Use pytest; fixtures live in tests/conftest.py - use them
  • Mirror the module structure: tinyagentos/routes/agents.py -> tests/test_agents.py
  • All PRs must pass CI before merge

Commits

Use conventional commit style:

PrefixUse for
feat:new feature
fix:bug fix
docs:documentation only
refactor:code change with no behaviour change
test:adding or updating tests
chore:tooling, deps, CI

Do not include AI tool attribution in commit messages.


Design laws

Every taOS surface is a live surface: new or changed UI must auto-refresh and carry motion per docs/design/live-surface-law.md. PRs adding a static screen get bounced on review.

Testing

Run the full test suite:

uv run pytest tests/ --ignore=tests/e2e -n auto

Run a specific test file:

pytest tests/test_catalog_sync.py -v

The project has ~10,250 tests. CI runs against Python 3.12 and 3.13 on every pull request. Python 3.11 is added on the nightly scheduled run. A PR cannot be merged until all required checks pass.

When adding a feature, add tests that cover the new behaviour. When fixing a bug, add a regression test.


Verifying your work

A passing signal is a claim, not evidence. Most bad merges in this project came from something that looked like success without being one. Before trusting a green tick, ask what would have to be true for it to be lying.

Cases that have actually happened here:

  • A PR passed every required check while containing only a version bump. Green proves the suite ran, not that the work happened.
  • A test file reported green while every test in it skipped. pytest.importorskip is the correct way to land tests ahead of the code they cover, and it asserts nothing until that code exists. Once the implementation merges, confirm the skips became real passes. If the import path in the guard does not match what shipped, they skip forever and look identical to passing.
  • cmd | tail && echo OK prints OK when cmd failed, because && sees tail's exit status. Check the exit code of the command that matters.
  • Green on a branch with conflicts tested the old base, not the result of merging.

Applied to your own changes:

  • If you add a gate, prove it fails. A check only ever observed passing is unproven where it counts. Make it go red deliberately once.
  • Verify a review comment against the code before acting on it, including automated ones. Bot findings are often wrong, and confidently phrased.
  • Report honestly. If tests fail, say so and include the output. If you skipped a step, name it. "Done" should mean verified, not attempted.

Avoiding collisions with other contributors

  • Check whether an open PR already adds the file you are adding. Two PRs that both create the same path cannot both merge, and whichever lands first silently decides the design. This has cost duplicated implementations of the same feature more than once.
  • Renaming a CI job orphans its required check. Branch protection matches required checks by name, so a rename means the old name is never reported again and later PRs block on a check that can no longer exist. Keep the old name reported (an aggregate job whose explicit name: reproduces it) or update protection first.
  • Stage explicit paths rather than git add -A, which sweeps in untracked files you did not write.

Documentation gate

A gate blocks PRs that add or remove certain feature code without a matching doc update. It only fires on structural changes (a file added or deleted), never on a plain edit, and only for a small set of conservative rules configured in docs/doc-gate.toml:

ChangeRequires editing one of
A desktop app under desktop/src/apps/ is added or removedREADME.md
A route module under tinyagentos/routes/ is added or removeddocs/agent-coordination.md
An installer under tinyagentos/installers/ or scripts/install* is added or removedREADME.md
A manifest under app-catalog/ is added or removedREADME.md

If your PR trips a rule and there is genuinely nothing to document (or you already covered it elsewhere), add a trailer line to a commit message instead of editing a doc:

Docs-Reviewed: no user-facing change, internal refactor only

The trailer must have non-empty text after the colon; a bare Docs-Reviewed: does not count.

Run scripts/install-git-hooks.sh once to enable local hooks (.githooks/pre-commit and .githooks/commit-msg) so the gate runs before you push instead of after you open the PR. Local hooks are a convenience only: .github/workflows/doc-gate.yml is the authoritative check and runs on every PR regardless of local setup or --no-verify.

To add a new rule, edit docs/doc-gate.toml -- rules are data, no code changes needed.


Architecture Overview

tinyagentos/
  app.py               # FastAPI application factory, lifespan, route registration
  config.py            # Platform config, hardware detection
  routes/              # One module per feature area (86 route modules)
  templates/           # Minimal: only agent_debugger.html remains (frontend is a React SPA)
  channel_hub/         # Framework-agnostic messaging (6 connectors + message router)
  adapters/            # Framework adapters (15 adapters, ~25 lines each)
  cluster/             # Distributed compute (worker registration, task routing, optimiser)
  worker/              # Cross-platform worker apps (system tray, Android, iOS)
  stores/              # Data access layer (SQLite via aiosqlite)
app-catalog/           # YAML manifests for installable apps (108 apps)
tests/                 # pytest test suite (~3,590 tests)

Routes are registered in app.py. Route modules access stores via request.app.state (dependency injection set up in the app lifespan) - they do not import stores directly. The frontend is a React SPA; templates/ is minimal and only used for the agent debugger page.


Contact

Questions not suited for a GitHub issue? Email info@taos.my.