Contributing to XO Space
Set up a development checkout, follow the architecture contracts, and validate a contribution against development.
Contribute to the server, agent adapters, project services, or the build-free
Space UI. Start from development and submit your pull request to
development; main is the release branch.
The repository's AGENTS.md, CONTRIBUTING.md, and DEVELOPING.md are the working contracts. Check them in the revision you are changing.
Set up a checkout
Use Linux, macOS, or WSL. Contributor mode needs Python 3.12+ and git:
git clone https://github.com/quirq-ai/xo-space.git
cd xo-space
git checkout development
git switch -c fix/my-change
./cowork-api.sh install
QUIRQ_SKIP_BOOT_INSTALL=1 ./cowork-api.sh devOpen the printed /space/ URL. Development mode enables reload; the preferred
port is 5002, with a fallback when it is busy. Use PORT=5010 if you need an
explicit alternative.
To exercise the installation path instead, run ./install.sh from your checkout.
It creates a uv-managed environment and leaves your git working tree alone. That
venv has no pip; install extra packages with
uv pip install --python venv/bin/python <package>.
Choose explicit workspace/state roots when your development checkout should not
also be the project root.
Know where a change belongs
| Location | Responsibility |
|---|---|
server.py | Application wiring, lifespan jobs, router mounts. |
routers/ | HTTP request/response handling. |
services/ | Space-level services, shared storage, connections, Inbox, and swarm client. |
services/cowork_agent/ | Agent execution, registry, adapters, session plumbing, watcher. |
config/agents/<name>/ | Runtime manifests, settings, capabilities, lifecycle setup. |
space_ui/ | HTML, CSS, and browser ES modules, with no bundler. |
tests/ | Hermetic Python unittest suite and browser/module harnesses. |
plugin/ and .agents/ | Agent plugin/skill bundles that must stay synchronized. |
New API work uses modular Plane B, selected by AGENT_NAME. The older
/ask_question* Plane A, selected by AI_PROVIDER, remains a separate
compatibility surface.
Preserve the contracts
- Keep routers thin and API paths, request bodies, and response shapes compatible.
- Resolve agent-specific behavior through the capability loader. Agent-specific
implementations belong in
adapters/<name>/,config/agents/<name>/, or the legacyconfig/models/<name>/tree; follow the documented frozen exceptions. - Keep conversations and credentials out of project folders. Portable
.xo/records and machine-local.quirq/telemetry have different owners and lifetimes. - Use the owning service/API for writes. In particular, todos have one HTTP write path; the watcher does not mirror every agent's native task tool.
- Run external commands through
utils.commandswith argument lists. Route all xo-swarm-api calls throughservices/swarm_api/. - Use async network/subprocess operations and avoid logging secrets or prompt text.
- Isolate tests with temporary roots and mocked external services; never point a
test at a real
.quirq/directory or credential file.
Change the Space UI
Each view has a module under space_ui/js/views/. The registry owns navigation,
parents, hash routes, lazy mounting, and view isolation. Views do not import one
another: use ctx.switchTo() or the documented shared events. HTTP calls use
js/core/api.js.
When changing a view:
- Update its module, the matching documentation page, and the in-app Wiki topic summary or link when needed.
- Bump its
?v=import stamp injs/app.js, then the app stamp inindex.html. Bump changed stylesheet URLs and shared imports where appropriate. - Run
node --checkon changed JavaScript modules. - Exercise the actual user path in a browser, including deep links and any related lens transitions. Include screenshots in the PR for visible changes.
Add a runtime
Add config/agents/<name>/manifest.json and its settings/capability declarations,
then services/cowork_agent/adapters/<name>/adapter.py. Export Adapter as a
BaseAgentAdapter implementation with run, stream, and adapter_name.
Optional modules supply models, usage, sessions, streaming, watcher sources, or
session telemetry. routes.py supplies agent-owned routes, mounted only when
that agent is active. Missing optional capabilities degrade to their documented
empty/501 responses; an import failure inside an existing module is a bug and
must remain visible.
Use the adapter guide for the full contract. No central hardcoded agent registry should need editing.
Validate and submit
venv/bin/python -m unittest discover -s tests -t .
venv/bin/python scripts/check_route_parity.pyAlso run checks appropriate to the files changed:
# Installer changes
bash tests/install_sh_harness.sh
# Plugin or .agents changes
./scripts/check_plugin_sync.shReview the modularity invariant and smoke the relevant capabilities under affected runtimes. Route totals can differ by runtime; the parity script checks the shared core plus each runtime's own routes instead of a fixed count.
Target development. Describe the problem and resulting behavior, link the issue, list the validation you actually ran, and explain any changed contract. Keep the branch current with development. Maintainers promote development to main for releases.