Files
PiCloud/docs/git-workflow.md
MechaCat02 b8b544816d chore: initial scaffold — workspace, docs, blueprint
Sets up the PiCloud monorepo as a Cargo workspace organised around the
three-service architecture (manager / orchestrator / executor), each
backed by a *-core library crate so the same logic powers both the MVP
all-in-one `picloud` binary and the future split-process cluster mode.

  * crates/shared, executor-core, orchestrator-core, manager-core
    define the library surface and trait seams between the three
    services (`ExecutorClient`, `ScriptResolver`, `ScriptRepository`).
  * crates/picloud is the MVP entrypoint; serves /healthz on 8080
    (override via PICLOUD_BIND).
  * crates/picloud-{manager,orchestrator,executor} are skeleton
    binaries that keep the crate boundaries honest until cluster
    mode is built out in v1.3+.
  * docs/git-workflow.md defines the trunk-based workflow:
    short-lived branches, Conventional Commits, separate hotfix
    flow with mandatory reproduction tests.
  * CLAUDE.md captures the working rules for future Claude sessions.

Workspace passes `cargo fmt`, `cargo clippy -D warnings` (with
pedantic enabled), and `cargo test --workspace`. The all-in-one
binary responds on `/healthz` and `/`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 23:16:32 +02:00

8.4 KiB

Git Workflow

PiCloud uses trunk-based development: a single long-lived branch (main) that is always deployable, with short-lived branches for changes that need review.

This document defines how branches, commits, reviews, and releases work — and how bug fixes flow through the system.


1. Branches

Branch Purpose Lifetime
main The trunk. Always green, always deployable. Permanent
feat/<topic> New feature or non-trivial change. ≤ 2 days
fix/<topic> Bug fix (non-critical). ≤ 1 day
hotfix/<topic> Critical bug fix that needs to ship now. Hours
chore/<topic> Refactor, deps update, CI tweak, docs. ≤ 1 day
release/vX.Y Long-lived release branch for back-porting hotfixes to a shipped version. Per minor version, once we tag releases

Rules:

  • Branch directly off main. Never branch off another feature branch.
  • Keep branches short. If a branch lives longer than 2 days, you're doing too much in one go — split it.
  • Branch names use kebab-case after the prefix: feat/script-crud-endpoints, fix/executor-timeout-leak.
  • Delete the branch after merge.

2. Commits

Format: Conventional Commits.

<type>(<scope>): <subject>

<body — optional, wrapped at 72 chars>

<footer — optional: BREAKING CHANGE, issue refs>

Types: feat, fix, chore, refactor, docs, test, perf, build, ci.

Scopes (current crates / areas): executor-core, orchestrator-core, manager-core, shared, picloud, dashboard, caddy, compose, ci, docs.

Examples:

feat(executor-core): add operation budget enforcement

fix(orchestrator-core): release Postgres pool guard before dispatch

chore(ci): pin Rust toolchain to 1.92.0

Rules:

  • One logical change per commit. If you can't describe it in one line, split it.
  • Subject line: imperative, ≤ 72 chars, no trailing period.
  • Body explains why, not what — the diff already shows what.
  • No WIP, fixup, or oops commits on main. Squash or rewrite before merging.

3. The Feature Loop

                 ┌─────────────────────┐
                 │ Pull latest main    │
                 └──────────┬──────────┘
                            │
                 ┌──────────▼──────────┐
                 │ Branch: feat/<name> │
                 └──────────┬──────────┘
                            │
                 ┌──────────▼──────────┐
                 │ Commit small steps  │◄────┐
                 │ Run tests locally   │     │
                 └──────────┬──────────┘     │
                            │                │
                 ┌──────────▼──────────┐     │
                 │ Open PR to main     │─────┘  (iterate on feedback)
                 │ CI must be green    │
                 └──────────┬──────────┘
                            │
                 ┌──────────▼──────────┐
                 │ Squash-merge to main│
                 │ Delete branch       │
                 └─────────────────────┘

Before opening a PR:

git fetch origin
git rebase origin/main        # keep history linear
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --workspace

PR requirements:

  • CI green (fmt, clippy, tests, build).
  • At least one approving review for non-trivial changes. Solo dev exception: self-review the diff explicitly before merging.
  • PR description names why and links to any issue.
  • Squash-merge by default → one commit per PR on main.

4. Bug-fix Workflow

Bugs are classified by severity:

Non-critical bug — normal flow

  1. Branch fix/<topic> from main.
  2. Write a failing test that reproduces the bug.
  3. Fix it. The test now passes.
  4. PR → review → squash-merge.

Critical / production hotfix

                 ┌──────────────────┐
                 │ Bug reported     │
                 └────────┬─────────┘
                          │
              ┌───────────▼───────────┐
              │ Reproduce locally     │  ← required before any fix
              │ Write failing test    │
              └───────────┬───────────┘
                          │
              ┌───────────▼───────────┐
              │ Branch hotfix/<name>  │
              │ from main             │
              └───────────┬───────────┘
                          │
              ┌───────────▼───────────┐
              │ Minimal fix only      │  ← no refactors, no unrelated changes
              │ Test passes           │
              └───────────┬───────────┘
                          │
              ┌───────────▼───────────┐
              │ Fast-track review     │
              │ Merge to main         │
              └───────────┬───────────┘
                          │
              ┌───────────▼───────────┐
              │ Tag patch release     │  (vX.Y.Z+1)
              │ Deploy                │
              └───────────┬───────────┘
                          │
              ┌───────────▼───────────┐
              │ Cherry-pick to        │  ← only if old releases are
              │ release/vX.Y if active│    still in use
              └───────────────────────┘

Critical hotfix rules:

  • A hotfix fixes one bug. Nothing else. No "while I'm here" cleanups.
  • The reproduction test stays in the suite forever — it's our guarantee the bug doesn't return.
  • If the fix can't be minimal (e.g. requires an architectural change), ship a mitigation as the hotfix (feature flag off, rate limit, revert), then schedule the real fix as a normal feature.

5. Keeping main Green

Trunk-based only works if main is always green. Mechanisms:

  • CI gate: PRs cannot merge unless CI passes (fmt, clippy -D warnings, cargo test --workspace, dashboard build).
  • Feature flags: Code for incomplete features lives on main behind a flag, off by default. We finish features in small mergeable slices, not in long-lived branches.
  • Reverts are cheap: If something slips through and breaks main, revert first, debug after. git revert <merge-sha> and ship.
  • No force-push to main. Ever.

6. Releases

Until we ship publicly we deploy off main continuously. Once we have external users:

  • Tag releases on main: v0.1.0, v0.1.1, v0.2.0 (SemVer).
  • Patch releases (v0.1.1) come from hotfixes; bump the patch number on each fix.
  • Minor releases (v0.2.0) come from accumulated features on main.
  • For each minor version supported in the wild, create release/v0.1 and cherry-pick patches there. Otherwise don't bother — single trunk is simpler.

Tagging:

git tag -a v0.1.0 -m "v0.1.0 — MVP"
git push origin v0.1.0

7. What We Do Not Do

  • No GitFlow. No develop, no release branches by default, no next. They add merge overhead without buying anything at our scale.
  • No long-lived feature branches. If a feature is too big to land in 2 days, split it. Use a feature flag.
  • No merge commits on main from feature branches. Squash-merge keeps history linear and bisectable.
  • No commits straight to main — even for typo fixes. Go through a PR (it can take 30 seconds to review and merge).
  • No --no-verify to bypass hooks. If a hook fails, fix the underlying issue.