- deploy.md: /srv/configs -> /srv/config (singular is canonical) across the compose mount, paths table, secrets path, and rotation snippet. Add the repo+compose row (/srv/docker/<workspace>/<project>, created by the clone, not pre-provisioned) and a note that all /srv paths are owned by the services user (1337) — rounding out the canonical layout. - workflow.md: the first 'per-project git identity' link pointed at a nonexistent #per-project-git-identity anchor; point it at #handy-shell-setup (where the gitsetup alias lives), matching the other link to the same spot. Did not touch pip/requirements, chmod a+rwX + user 1337, HOME=/tmp, init, layer caching, or the git-install caveat — all intentional standards. Verified: mkdocs build --strict clean (validates anchors); table renders. Signed-off-by: disqualifier <dev@disqualifier.me>
244 lines
10 KiB
Markdown
244 lines
10 KiB
Markdown
# Workflow
|
|
|
|
Get hands on with how we dev — where code lives, how we use git, the AI-assisted
|
|
flow we recommend, and the shell setup that ties it together. This is the
|
|
**our-flavored** version: why *we* do it this way and how *our* setup is wired. For
|
|
the truly generic parts (installing WSL, learning git), we link the official docs
|
|
rather than reteach them.
|
|
|
|
!!! info "Public, sanitized"
|
|
Examples use placeholders — `<you>`, `<key>`, `dev@<you>`, `/mnt/c/<your>/...`.
|
|
Swap in your own real values locally; never commit personal paths, key names,
|
|
or emails.
|
|
|
|
## Why git, why WSL
|
|
|
|
**Git** is the backbone of everything here. Version history and branching are the
|
|
obvious part, but our whole deploy model is built on git too: we `pip install`
|
|
libraries straight from git by tag, servers pull via per-repo deploy keys, and
|
|
changes flow `develop → main` before they ship. If you know git, you already
|
|
understand how our code moves from your machine to production.
|
|
|
|
**WSL2 (Ubuntu)** is where we develop — a real Linux toolchain on a Windows
|
|
desktop. You get native Linux tooling (the same environment our servers run) plus
|
|
the Windows apps you actually use day to day. Install WSL2 from Microsoft's docs;
|
|
this page documents the *our-setup* layer that goes on top.
|
|
|
|
- [Install WSL (Microsoft)](https://learn.microsoft.com/windows/wsl/install)
|
|
- [VS Code Remote — WSL](https://code.visualstudio.com/docs/remote/wsl)
|
|
|
|
## Signing up on our Gitea
|
|
|
|
Our code lives on **Gitea** at
|
|
[git.rethinkstudios.io](https://git.rethinkstudios.io). Two orgs you'll use:
|
|
|
|
- **[rethink-public](https://git.rethinkstudios.io/rethink-public)** — public
|
|
libraries, resources, and assets.
|
|
- **[rethink-software](https://git.rethinkstudios.io/rethink-software)** — our
|
|
applications.
|
|
|
|
**Get an account:**
|
|
|
|
1. Register at [git.rethinkstudios.io](https://git.rethinkstudios.io) and verify
|
|
your email.
|
|
2. Add your **SSH public key** under *Settings → SSH / GPG Keys* so you can clone
|
|
and push over SSH.
|
|
3. For servers, we use a **per-repo deploy-key** model rather than your personal
|
|
key — see the [Deploy guide](deploy.md) for how a box gets read access to just
|
|
the repos it needs.
|
|
|
|
## Our git vs. public git (GitHub / GitLab)
|
|
|
|
It's the same git — just a different host. The thing most devs trip on is
|
|
**identity and keys per host**: you may have a GitHub identity *and* a Gitea
|
|
identity on one machine, and commits need to be attributed (and signed/pushed)
|
|
with the right one per project.
|
|
|
|
We solve that with **per-repo local git config** — run a small alias inside a repo
|
|
to set its local user and the SSH key it pushes with (see
|
|
[per-project git identity](#handy-shell-setup) below). No global identity
|
|
juggling.
|
|
|
|
Our conventions, in short:
|
|
|
|
- **Signed commits** — `git commit -s`.
|
|
- **No AI co-author trailer** on your own work. (Intern/dev work you're crediting
|
|
gets that dev's `Co-Authored-By` — nothing else.)
|
|
- **`develop` is staging**, merge to **`main`** via MR when it's ready to ship.
|
|
- **Libraries install from git by tag** — pin a version in your deps, bump the
|
|
tag when the lib releases.
|
|
|
|
!!! warning "Set your per-repo identity *before* the first commit"
|
|
One machine often carries more than one Gitea identity/key. If you forget to
|
|
run `gitsetup` in a fresh clone, your commits attribute to the wrong
|
|
user — or push with the wrong key and bounce. Run it right after cloning;
|
|
see [per-project git identity](#handy-shell-setup).
|
|
|
|
## Git basics (our-flavored)
|
|
|
|
Not a git tutorial — just how the everyday loop looks against our Gitea. For the
|
|
generic command reference, keep the
|
|
[Git cheat sheet](https://training.github.com/downloads/github-git-cheat-sheet/)
|
|
or the [Pro Git book](https://git-scm.com/book) handy.
|
|
|
|
**Clone** over SSH (the alias maps to a key — see the shell setup):
|
|
|
|
```bash
|
|
git clone git@<alias>:rethink-public/<repo>.git
|
|
```
|
|
|
|
**The everyday loop:**
|
|
|
|
```bash
|
|
git switch -c <feature> # branch off
|
|
# ...make a logical change...
|
|
git commit -s -m "..." # commit, signed
|
|
git push -u origin <feature> # push
|
|
# open an MR: develop -> main
|
|
```
|
|
|
|
**Commit small and often** — one commit per logical change, not a giant
|
|
end-of-day dump. Small commits are easier to review, revert, and `git bisect`
|
|
when something breaks.
|
|
|
|
**Read history** as a graph with the `gl` alias below:
|
|
|
|
```bash
|
|
gl # git log --graph, oneline, decorated
|
|
```
|
|
|
|
## The dev workflow
|
|
|
|
This is the part that's distinctly *ours*. AI is a force multiplier, but only with
|
|
discipline around it — the two habits that matter most are **plan before you
|
|
build** and **verify by executing, not asserting**.
|
|
|
|
You can use whatever AI you like — but we **recommend Claude** (via
|
|
[Claude Code](https://docs.claude.com/en/docs/claude-code/overview), in the
|
|
terminal or VS Code). The whole project structure we recommend below — the
|
|
`.claude/` folder, `CLAUDE.md` instructions, numbered specs — is built on that
|
|
preference: it's designed around how Claude Code reads project context and takes
|
|
handoffs. Other tools can read these files too, but the convention assumes
|
|
Claude-first.
|
|
|
|
**Plan here, build in Claude Code.** Do the thinking in chat — plan, write the
|
|
spec, make the decisions. Then hand that spec to a Claude Code agent that does the
|
|
build: it implements, **verifies by running**, and pushes. The chat plans; the
|
|
agent implements.
|
|
|
|
**tmux + Claude Code split.** In practice that's a Claude Code agent running in a
|
|
tmux pane doing the build work while you plan/review in another. One spec in, a
|
|
verified change out.
|
|
|
|
**claudedo (optional, hands-free).** Voice control for Claude Code over tmux: a
|
|
wake-word plus local Whisper speech-to-text drives your tmux session without the
|
|
keyboard — handy when you're fullscreen or away from the desk. It's available
|
|
here:
|
|
[git.rethinkstudios.io/rethink-software/claudedo](https://git.rethinkstudios.io/rethink-software/claudedo).
|
|
|
|
**The `.claude/` project convention.** Every project has a top-level `.claude/`
|
|
folder (always gitignored — nothing under it is committed):
|
|
|
|
- **`CLAUDE.md`** — project-specific instructions for the agent (stack, layout,
|
|
conventions). Layered on top of your global instructions.
|
|
- **`compact.md`** — a running state log (done / decided / in-flight), updated at
|
|
checkpoints so a fresh session catches up fast.
|
|
- **`commands.log`** — an append-only record of shell commands run.
|
|
- **`spec/`** — numbered, per-change specs named `NN-<type>-<short>.md`
|
|
(e.g. `01-feature-logging.md`).
|
|
|
|
Tell the agent to **"setup project"** to scaffold all of that (and add `.claude/`
|
|
to `.gitignore`) in a new repo.
|
|
|
|
**AI-assist habits.** When you're stuck, give the AI the *exact* context instead
|
|
of describing it — the WSL clipboard bridge makes this trivial:
|
|
|
|
```bash
|
|
git diff | clip.exe # then paste the diff straight into the chat
|
|
```
|
|
|
|
Use AI for the plan and the spec, let the agent build, and always **prove it
|
|
works by running it** — don't accept "this should work."
|
|
|
|
!!! tip "Verify by executing, not asserting"
|
|
The single habit that separates good AI-assisted work from plausible-looking
|
|
nonsense: **run it**. A passing build, a real screenshot, actual output — that
|
|
is proof. "It should work" is not.
|
|
|
|
## Recommended setup
|
|
|
|
- **WSL2 (Ubuntu) + VS Code + Claude Code.** Develop in WSL, edit in VS Code over
|
|
[Remote — WSL](https://code.visualstudio.com/docs/remote/wsl), and run
|
|
[Claude Code](https://docs.claude.com/en/docs/claude-code/overview) as your
|
|
agent (terminal or the VS Code extension).
|
|
- **[pyenv](https://github.com/pyenv/pyenv)** for per-project Python versions
|
|
(we target **3.10+**) and isolated `.venv`s — full setup on the
|
|
[Virtual environments](environments.md) page.
|
|
- **[flake8](https://flake8.pycqa.org/)** with a shared config — max line length
|
|
**120** (see the alias below).
|
|
|
|
## Handy shell setup
|
|
|
|
Copy-paste these into your `.zshrc` / `.bashrc`. Replace every placeholder with
|
|
your real values. The high-value ones are explained underneath.
|
|
|
|
```bash
|
|
# --- WSL <-> Windows bridges ---
|
|
alias explorer="explorer.exe ." # open current dir in Windows Explorer
|
|
# pipe to the Windows clipboard (great for pasting context into AI):
|
|
# git diff | clip.exe -> paste the diff straight into a chat
|
|
# auto-alias Windows .exe tools on PATH (e.g. adb/platform-tools):
|
|
export PATH="$PATH:/mnt/c/<your>/platform-tools"
|
|
for exe in /mnt/c/<your>/platform-tools/*.exe; do
|
|
alias "$(basename "${exe}" .exe)"="${exe}"
|
|
done
|
|
|
|
# --- pyenv (Python version management) ---
|
|
export PYENV_ROOT="$HOME/.pyenv"
|
|
export PATH="$PYENV_ROOT/bin:$PATH"
|
|
eval "$(pyenv init --path)"
|
|
eval "$(pyenv init -)"
|
|
eval "$(pyenv virtualenv-init -)"
|
|
|
|
# --- flake8 with a shared config ---
|
|
alias flake8='flake8 --config ~/.config/flake8'
|
|
|
|
# --- per-project git identity (switch identity per repo) ---
|
|
# set the LOCAL (per-repo) user + the key to sign/push with:
|
|
alias gitsetup='git config --local user.name "<you>"; \
|
|
git config --local user.email "dev@<you>"; \
|
|
git config --local core.sshCommand "ssh -i $HOME/.ssh/<key>"'
|
|
# a second identity for a different account, same pattern:
|
|
alias gitea='git config --local user.name "<alt>"; \
|
|
git config --local user.email "<alt>@<host>"; \
|
|
git config --local core.sshCommand "ssh -i $HOME/.ssh/<alt-key>"'
|
|
|
|
# --- git log graph ---
|
|
alias gl='git log --graph --abbrev-commit --pretty=oneline --decorate'
|
|
|
|
# --- local bins on PATH ---
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
export PATH="$HOME/.npm-global/bin:$PATH"
|
|
```
|
|
|
|
```bash
|
|
# cherry-pick a commit onto master/main quickly
|
|
gitcs() {
|
|
if [ -z "$1" ]; then echo "Usage: gitcs <commit>"; return 1; fi
|
|
git checkout master && git cherry-pick "$1"
|
|
}
|
|
```
|
|
|
|
**The ones worth understanding:**
|
|
|
|
- **`git diff | clip.exe`** — the killer WSL trick for AI-assisted dev. Pipe your
|
|
working changes straight to the Windows clipboard and paste them into the chat
|
|
so the AI sees *exactly* what changed instead of your paraphrase of it.
|
|
- **`gitsetup` / `gitea`** — per-repo identity. One machine, multiple Gitea
|
|
identities and keys; run the alias inside a repo to set its **local** user and
|
|
signing/push key, so commits attribute correctly without touching your global
|
|
config.
|
|
- **`gl`** — a readable branch graph for understanding history at a glance.
|
|
- **`pyenv`** — per-project Python versions, so each repo builds against the
|
|
version it targets.
|