# Dobby CI/CD, README, CHANGELOG & Publishing Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Bring Dobby's packaging, CI/CD, README, and publishing to production quality, matching VibeLens patterns. Publish as `dobby-orchestrator` on PyPI.

**Architecture:** Switch build backend from setuptools to hatchling. Add GitHub Actions for CI (lint+test), PyPI publishing (OIDC trusted publishing on version tags), and GitHub Releases. Refresh README with badges and PyPI install instructions. Restructure CHANGELOG to Keep a Changelog format.

**Tech Stack:** hatchling, ruff, GitHub Actions, uv, pypa/gh-action-pypi-publish (OIDC)

---

## File Structure

| Action | File | Purpose |
|--------|------|---------|
| Modify | `pyproject.toml` | Switch to hatchling, add metadata, ruff config |
| Create | `.github/workflows/ci.yml` | Lint + test on push/PR |
| Create | `.github/workflows/publish.yml` | PyPI publish on version tags |
| Create | `.github/workflows/release.yml` | GitHub Release on version tags |
| Modify | `README.md` | Add badges, PyPI install option |
| Modify | `CHANGELOG.md` | Restructure to Keep a Changelog with semver |
| Create | `.python-version` | Pin default Python to 3.12 |
| Create | `LICENSE` | MIT license |
| Modify | `.gitignore` | Add missing patterns |

---

### Task 1: Overhaul pyproject.toml

**Files:**
- Modify: `pyproject.toml`

- [ ] **Step 1: Replace build system**

Change the `[build-system]` section from setuptools to hatchling:

```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
```

- [ ] **Step 2: Update project metadata**

Replace the `[project]` section with full metadata. Keep all existing dependencies and entry points unchanged:

```toml
[project]
name = "dobby-orchestrator"
version = "0.2.0"
description = "A distributed meta-agent orchestrator that manages coding agents across your infrastructure"
readme = "README.md"
license = "MIT"
requires-python = ">=3.11"
authors = [{ name = "Simon Yu" }]
keywords = ["agent", "orchestrator", "meta-agent", "claude", "codex", "distributed", "automation", "ai"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Topic :: Software Development :: Libraries :: Application Frameworks",
]
dependencies = [
    "aiosqlite>=0.20.0",
    "aiohttp>=3.9.0",
    "click>=8.1.0",
    "pyyaml>=6.0",
    "croniter>=2.0",
    "mcp>=1.0.0",
    "slack-bolt>=1.20.0",
    "anthropic>=0.40.0",
]
```

- [ ] **Step 3: Update optional dependencies**

Add `ruff` to dev dependencies:

```toml
[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "pytest-asyncio>=0.23",
    "pytest-aiohttp>=1.0",
    "aioresponses>=0.7",
    "ruff>=0.8.0",
]
```

- [ ] **Step 4: Keep entry points unchanged**

Verify the `[project.scripts]` section stays as-is:

```toml
[project.scripts]
dobby = "dobby.cli.main:cli"
dobby-mcp = "dobby.mcp.server:main"
```

- [ ] **Step 5: Replace setuptools package find with hatchling config**

Remove:
```toml
[tool.setuptools.packages.find]
include = ["dobby*"]
```

Add:
```toml
[tool.hatch.build.targets.wheel]
packages = ["dobby"]
```

- [ ] **Step 6: Add project URLs**

```toml
[project.urls]
Homepage = "https://github.com/simonucl/dobby"
Repository = "https://github.com/simonucl/dobby"
"Bug Tracker" = "https://github.com/simonucl/dobby/issues"
Changelog = "https://github.com/simonucl/dobby/blob/main/CHANGELOG.md"
```

- [ ] **Step 7: Add ruff configuration**

```toml
[tool.ruff]
target-version = "py311"
line-length = 100

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "SIM"]

[tool.ruff.lint.isort]
known-first-party = ["dobby"]
```

- [ ] **Step 8: Verify pytest config unchanged**

Confirm this section remains:

```toml
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
```

- [ ] **Step 9: Verify build works**

Run:
```bash
cd /Users/simonyu/local/local_orby/dobby && uv sync --extra dev
```
Expected: Dependencies install successfully with hatchling.

- [ ] **Step 10: Commit**

```bash
git add pyproject.toml uv.lock
git commit -m "build: switch to hatchling, rename to dobby-orchestrator, add ruff config"
```

---

### Task 2: Create CI Workflow

**Files:**
- Create: `.github/workflows/ci.yml`

- [ ] **Step 1: Create workflows directory**

```bash
mkdir -p /Users/simonyu/local/local_orby/dobby/.github/workflows
```

- [ ] **Step 2: Write ci.yml**

```yaml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.11", "3.12", "3.13"]
    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v4

      - name: Set up Python ${{ matrix.python-version }}
        run: uv python install ${{ matrix.python-version }}

      - name: Install dependencies
        run: uv sync --extra dev

      - name: Lint
        run: uv run ruff check dobby/ tests/

      - name: Test
        run: uv run pytest tests/ -v
```

- [ ] **Step 3: Commit**

```bash
git add .github/workflows/ci.yml
git commit -m "ci: add lint and test workflow for Python 3.11-3.13"
```

---

### Task 3: Create Publish Workflow

**Files:**
- Create: `.github/workflows/publish.yml`

- [ ] **Step 1: Write publish.yml**

```yaml
name: Publish to PyPI

on:
  push:
    tags:
      - "v*"

permissions:
  id-token: write

jobs:
  publish:
    runs-on: ubuntu-latest
    environment: pypi
    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v4

      - name: Build package
        run: uv build

      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
```

- [ ] **Step 2: Commit**

```bash
git add .github/workflows/publish.yml
git commit -m "ci: add PyPI publish workflow with OIDC trusted publishing"
```

---

### Task 4: Create Release Workflow

**Files:**
- Create: `.github/workflows/release.yml`

- [ ] **Step 1: Write release.yml**

```yaml
name: Release

on:
  push:
    tags:
      - "v*"

permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          generate_release_notes: true
```

- [ ] **Step 2: Commit**

```bash
git add .github/workflows/release.yml
git commit -m "ci: add GitHub Release workflow on version tags"
```

---

### Task 5: Update README with Badges and PyPI Install

**Files:**
- Modify: `README.md`

- [ ] **Step 1: Update badges in hero section**

Replace the existing badge block (lines 11-14) with:

```html
<p align="center">
  <a href="https://pypi.org/project/dobby-orchestrator/"><img src="https://img.shields.io/pypi/v/dobby-orchestrator?style=flat-square" alt="PyPI"></a>
  <img src="https://img.shields.io/pypi/pyversions/dobby-orchestrator?style=flat-square" alt="Python 3.11+">
  <a href="https://github.com/simonucl/dobby/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/simonucl/dobby/ci.yml?style=flat-square&label=CI" alt="CI"></a>
  <a href="https://github.com/simonucl/dobby/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="MIT License"></a>
  <a href="http://localhost:8420/dashboard"><img src="https://img.shields.io/badge/dashboard-live-brightgreen?style=flat-square" alt="Dashboard"></a>
</p>
```

- [ ] **Step 2: Add PyPI install option to Installation section**

Insert before the existing "git clone" block in the Installation section (after the `### Installation` heading):

```markdown
### Installation

Install from PyPI:

```bash
pip install dobby-orchestrator
```

Or with uv:

```bash
uv pip install dobby-orchestrator
```

### Development Installation

For development or contributing:
```

Then keep the existing git clone block that follows.

- [ ] **Step 3: Update Quick Start commands**

Replace `uv run dobby` with just `dobby` in the Quick Start section since the package will be pip-installable. Keep `uv run dobby` as an alternative in comments:

```markdown
## Quick Start

```bash
# 1. Start the hub daemon
dobby start

# 2. Register a project
dobby register ~/projects/my-project --name myproject

# 3. Submit a task
dobby add "write unit tests for the auth module" --project myproject

# 4. Check status
dobby status
```
```

- [ ] **Step 4: Commit**

```bash
git add README.md
git commit -m "docs: add PyPI badges and install instructions to README"
```

---

### Task 6: Restructure CHANGELOG

**Files:**
- Modify: `CHANGELOG.md`

- [ ] **Step 1: Rewrite CHANGELOG with Keep a Changelog format**

Preserve all existing content but restructure with version numbers and proper sections:

```markdown
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/).

## [Unreleased]

## [0.2.0] - 2026-03-23 — Overnight Autonomy & Distributed Execution

### Added
- **Distributed hub-and-spoke architecture**: VPS hub + Mac/EC2/Tillicum spokes
- **Git worktree parallel execution**: Multiple tasks run simultaneously on same repo
- **Plan-then-execute approval flow**: Agent proposes plan → Slack approval → auto-execute
- **Claude Code remote control**: Persistent sessions accessible from anywhere via claude.ai/code
- **Overnight monitoring loop**: Auto-detects failures, debugs, and resubmits
- VibeLens-style Flow view for agent activity (SVG-based, phase grouping, tool chips)
- GitHub-style contribution heatmap (30 days, per-project)
- Usage Over Time SVG chart with 5h/24h/7d/All time ranges (persisted in SQLite)
- Agent Network visualization (hub + spokes with status dots, project tags)
- Project display names, GitHub links, spoke labels in sidebar
- Block Kit interactive buttons (Submit/Edit/Cancel/Approve)
- Free-form Claude Code conversations with :eyes: emoji + "thinking..." indicator
- `projects` command showing all repos with spoke status
- Plan approval notifications with Approve & Execute buttons
- Cloudflared tunnel for public dashboard access
- MCP server pointing to VPS hub
- Spoke result notifications via Slack
- Utilization history tracked in SQLite (survives restarts)

## [0.1.0] - 2026-03-22 — Foundation

### Added
- Task queue with scheduling (cron, interval, dependency chains)
- SQLite store with JSON blob storage
- Claude Code and Codex backend support
- Batch operations, project policies, auto-chaining
- Live jobs, operations summary, project cards in dashboard
- Claude API rate limit utilization bars
- Structured and raw log viewers
- Codex JSONL log parser
- NL task parsing with confirmation flow in Slack
- Status queries, overnight summaries
- Detail-status for specific tasks
- `dobby start`, `dobby add`, `dobby status`, `dobby slack` CLI commands
- MCP server (`dobby-mcp`)
```

- [ ] **Step 2: Commit**

```bash
git add CHANGELOG.md
git commit -m "docs: restructure CHANGELOG to Keep a Changelog format with semver"
```

---

### Task 7: Add Supporting Files

**Files:**
- Create: `.python-version`
- Create: `LICENSE`
- Modify: `.gitignore`

- [ ] **Step 1: Create .python-version**

```
3.12
```

- [ ] **Step 2: Create MIT LICENSE file**

```
MIT License

Copyright (c) 2025 Simon Yu

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

- [ ] **Step 3: Update .gitignore**

Add these missing patterns to the existing `.gitignore`:

```gitignore
# Compiled Python
*.py[cod]

# Coverage
.coverage
htmlcov/

# macOS
.DS_Store

# IDE
.idea/
.vscode/
*.swp
*.swo

# Claude Code
.claude/
```

Keep all existing entries (`__pycache__/`, `*.pyc`, `*.pyo`, `.pytest_cache/`, `*.egg-info/`, `dist/`, `build/`, `.venv/`, `dobby.db`, `results/`, `dobby.db*`, `.env`, `.dobby-worktrees`, `spoke.log`).

- [ ] **Step 4: Commit**

```bash
git add .python-version LICENSE .gitignore
git commit -m "chore: add LICENSE, .python-version, update .gitignore"
```

---

### Task 8: Verify Everything Works

- [ ] **Step 1: Verify uv sync with new pyproject.toml**

```bash
cd /Users/simonyu/local/local_orby/dobby && uv sync --extra dev
```
Expected: Installs successfully.

- [ ] **Step 2: Verify ruff lint passes (or note issues)**

```bash
cd /Users/simonyu/local/local_orby/dobby && uv run ruff check dobby/ tests/
```
Expected: Either passes or reports lint issues. If there are lint issues, note them but do NOT fix them in this plan — lint fixes are a separate task.

- [ ] **Step 3: Verify tests pass**

```bash
cd /Users/simonyu/local/local_orby/dobby && uv run pytest tests/ -v
```
Expected: Tests pass (same as before the changes).

- [ ] **Step 4: Verify package builds**

```bash
cd /Users/simonyu/local/local_orby/dobby && uv build
```
Expected: Creates `dist/dobby_orchestrator-0.2.0.tar.gz` and `dist/dobby_orchestrator-0.2.0-py3-none-any.whl`.

- [ ] **Step 5: Verify wheel contents**

```bash
python3 -c "
import zipfile, pathlib
wheels = list(pathlib.Path('dist').glob('*.whl'))
with zipfile.ZipFile(wheels[0]) as zf:
    names = zf.namelist()
    print(f'Total files: {len(names)}')
    for n in names[:20]:
        print(f'  {n}')
    if len(names) > 20:
        print(f'  ... and {len(names) - 20} more')
"
```
Expected: Shows `dobby/` package files in the wheel.

- [ ] **Step 6: Clean up build artifacts**

```bash
rm -rf dist/
```
