Files
claude-playground/CLAUDE.md
T
christianandClaude Opus 5.5 f666bdf6b3 Give the PR workflow a hard stop
Only confirmed correctness bugs block approval; everything else is a note.
At most one fix round, then hand off. Don't widen scope to satisfy a
review. Merge main only on conflict or request. The token goes in a
private header file, and PR responses are checked for a number.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 00:56:51 +02:00

71 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# claude-playground
A tiny zero-dependency Node.js todo CLI, used as a sandbox for trying Claude Code features.
## Commands
- `npm test` — run the test suite (built-in `node:test`, no install needed)
- `npm start -- add "something"` / `npm start -- ls` — run the CLI (data in `todos.json`, override with `TODO_FILE`)
## Conventions
- ES modules, Node >= 20, no third-party dependencies.
- `src/todo.js` holds pure functions; keep I/O in `load`/`save` and `src/cli.js`.
- Every behavior change gets a test in `test/`.
- Commit messages: short imperative subject line.
## Workflow (required)
Never commit, merge, or push to `main`. Only a human (Christian) merges into `main`, in Gitea.
The git hooks installed by `npm install` and Gitea branch protection enforce this (see "Protecting `main`" in the README). Never get around them: no `--no-verify`, no changing `core.hooksPath`, no editing `.git/`.
1. **Branch.** Run `git fetch origin` on its own, then `git switch --no-track -c <type>/<short-name> origin/main` (e.g. `fix/duplicate-ids`).
2. **Commit, test, push.** `npm test` must pass. Check that `git branch --show-current` isn't `main`, then run `git push -u origin HEAD`.
3. **Open the PR**, once per branch (see "Gitea API").
4. **Review** with `/code-review <branch> medium`.
5. **Triage.** The review lists unverified candidates, and it will always find some. Check each one against the code. A finding **blocks** only if it is a correctness bug in this PR's change that you have confirmed, ideally with a test that fails. Everything else is a **note**: cleanups, judgement calls, hardening ideas and unconfirmed findings.
6. **Comment** on the PR:
- First line: **Needs fixes** if anything blocks, otherwise **Approved**.
- Second line: `_Automated self-review by Claude; not an independent review._`
- Then the blocking findings, then the notes, then the findings you rejected, each with the reason.
7. **At most one fix round.** If the PR needs fixes, fix only the blocking findings, each with a test. Push, review once more, and post the verdict from steps 5–6. Then stop, whatever that second review says. Findings about the fixes themselves go to the human as notes; don't fix them.
8. **Hand off.** Never merge, even if the PR is approved. Tell the human it's ready, with the verdict and any notes.
Don't widen scope beyond the PR's purpose to satisfy a review. If a fix would add significant new code (a new mechanism, not a correction), list it as a note for the human instead.
Bring in the latest `main` only when the PR conflicts or the human asks:
1. Run `git fetch origin`.
2. Run `git merge --no-ff --no-commit origin/main`.
3. If it says "Already up to date", stop here. Otherwise resolve any conflicts and run `npm test`.
4. Run `git commit --no-edit`.
Run each as its own command, and never rebase or force-push.
### Gitea API
No `gh`/`tea`: use `curl` with `$GITEA_TOKEN`.
One-time human setup in the git-ignored `.claude/settings.local.json`: set `env.GITEA_TOKEN`, and add `code.westerkam.org` to `sandbox.network.allowedDomains`. Then restart the session (`claude --continue`); settings load only at start. If the token is unset, stop and ask the human.
Rules for every API call:
- Make each call one self-contained command, because shell state doesn't carry over between commands.
- Put titles and bodies in files in `$TMPDIR` (never in the repo) and pass them with `--rawfile`, never inline in double quotes, where backticks and `$(…)` would run.
- The token goes in a private header file, so it doesn't show up in the process list.
- `pipefail`, `curl -f` and the `jq` checks make every failure exit non-zero.
```sh
# Open a PR for the current branch (once). Write $TMPDIR/pr-title.txt and $TMPDIR/pr-body.md first.
set -o pipefail; API=https://code.westerkam.org/api/v1/repos/christian/claude-playground
(umask 077; printf 'Authorization: token %s\n' "$GITEA_TOKEN" > "$TMPDIR/gitea-auth")
jq -n --arg head "$(git branch --show-current)" --rawfile title "$TMPDIR/pr-title.txt" --rawfile body "$TMPDIR/pr-body.md" \
'{head:$head, base:"main", title:($title|rtrimstr("\n")), body:$body}' \
| curl -fsS -X POST -H @"$TMPDIR/gitea-auth" -H "Content-Type: application/json" -d @- "$API/pulls" \
| jq -er 'if .number then "#\(.number) \(.html_url)" else error("no PR number in response") end'
# Comment on PR <number>. Write $TMPDIR/comment.md first.
set -o pipefail; API=https://code.westerkam.org/api/v1/repos/christian/claude-playground
(umask 077; printf 'Authorization: token %s\n' "$GITEA_TOKEN" > "$TMPDIR/gitea-auth")
jq -n --rawfile body "$TMPDIR/comment.md" '{body:$body}' \
| curl -fsS -X POST -H @"$TMPDIR/gitea-auth" -H "Content-Type: application/json" -d @- "$API/issues/<number>/comments" \
| jq -er .html_url
```
Commands listed under `sandbox.excludedCommands` in `.claude/settings.json` (`git fetch`, `git commit`, `git push` and others) run outside the sandbox only when they are run standalone: no `cd … &&` before them and nothing chained after. They need that to reach the remote and to sign commits.
## Remote
Gitea at code.westerkam.org — `origin` = `git@code.westerkam.org:christian/claude-playground.git`.