Properties
category: spec tags: [ci, cd, github-actions, plan] last_updated: 2026-03-18 confidence: high
CI/CD Pipeline Plan
Current State
- Five repos:
robot.wtf,otterwiki(fork),otterwiki-api,otterwiki-mcp,otterwiki-semantic-search - All have pytest suites; no GitHub Actions workflows exist in any repo
- Deploy:
ansible-playbook ansible/deploy.yml -i ansible/inventory.ymlfromrobot.wtf/on a laptop - Ansible
deployrole installs each plugin directly from GitHub main branch viapip install git+https://... - Post-deploy smoke test is baked into the playbook
Test Infrastructure Summary
| Repo | Test runner | Dependencies |
|---|---|---|
robot.wtf |
pytest, no pyproject | requirements.txt (Flask, PyJWT, etc.) |
otterwiki |
pytest via pyproject / tox | Self-contained |
otterwiki-api |
pytest via pyproject | Requires otterwiki installed |
otterwiki-semantic-search |
pytest via pyproject | Requires otterwiki installed |
otterwiki-mcp |
pytest + pytest-asyncio | Standalone (no otterwiki dep) |
Phase 1: Per-Repo CI on PR (do this session)
Add a .github/workflows/ci.yml to each repo. The workflow is nearly identical across all five — differences are only in Python version and install steps.
Template (robot.wtf)
name: CI on: pull_request: push: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" - run: pip install -r requirements.txt - run: pip install pytest - run: pytest tests/
Plugin repos (otterwiki-api, otterwiki-semantic-search)
These depend on otterwiki. Install the fork's wikibot-io branch before installing the plugin:
- run: pip install "git+https://github.com/schuyler/otterwiki.git@wikibot-io" - run: pip install -e ".[dev]" - run: pytest
otterwiki-mcp
Standalone; no otterwiki dep. Standard pip install -e ".[dev]" && pytest.
otterwiki (fork)
Uses tox config in pyproject.toml. Can run pip install -e ".[dev]" && pytest directly to avoid tox overhead in CI.
Phase 2: Deploy Script (do this session)
The Ansible command is easy to forget. Add deploy.sh to robot.wtf/:
#!/usr/bin/env bash set -euo pipefail cd "$(dirname "$0")" ansible-playbook ansible/deploy.yml -i ansible/inventory.yml "$@"
This is the entire CD story for now. Manual deploy stays manual — that's the right call given:
- Deploy requires pulling from GitHub, so all plugin changes must be merged to main first
- No staging environment exists
- Smoke test is already part of the playbook
Phase 3: Auto-Deploy (deferred)
Options when ready:
- Webhook receiver on VPS — a tiny Flask endpoint that receives a GitHub
pushevent and runs the Ansible playbook. Avoids needing SSH keys in GitHub Actions secrets for the orchestrating repo. - GitHub Actions + SSH — store SSH key as a secret in
robot.wtf, runansible-playbookfrom Actions on push to main. Simpler setup but couples deploy to robot.wtf CI only. - Repository dispatch — plugin repos trigger a workflow in
robot.wtfvia the GitHub API on merge to main. Preserves separation of concerns.
Option 3 is cleanest given the multi-repo dependency model: a push to otterwiki-api shouldn't require a commit to robot.wtf to trigger a deploy, but the deploy logic lives in robot.wtf.
Integration Testing
Currently not feasible without a staging environment. The per-repo tests are isolated (plugin tests install otterwiki in CI but don't test the full stack together). Accept this gap for now.
When a staging environment exists, the right approach is a separate workflow in robot.wtf that deploys to staging and runs the smoke test suite, triggered after all plugin CI passes.
Task Checklist
- Add
.github/workflows/ci.ymltorobot.wtf - Add
.github/workflows/ci.ymltootterwiki(fork) - Add
.github/workflows/ci.ymltootterwiki-api - Add
.github/workflows/ci.ymltootterwiki-mcp - Add
.github/workflows/ci.ymltootterwiki-semantic-search - Add
deploy.shtorobot.wtf - Verify CI passes on each repo (push a test branch or trigger manually)
