← Back to Skills

Agile Workflow — Issues, PRs, Autonomous Merge, Releases, Villages

The unified development process for every Tawa repo. If your Claude Code session loads `tawa-docs/.claude/rules/tawa-agile-workflow.md`, it will follow this…

Ruleplatform

About

The unified development process for every Tawa repo. If your Claude Code session loads `tawa-docs/.claude/rules/tawa-agile-workflow.md`, it will follow this flow automatically.

Skill Content

This is the raw markdown that gets installed as a Claude Code rule.

# Agile Workflow — Issues, PRs, Autonomous Merge, Releases, Villages

The unified development process for every Tawa repo. If your Claude Code session
loads `tawa-docs/.claude/rules/tawa-agile-workflow.md`, it will follow this flow
automatically.

## Ground Rules

- **Git host is Forgejo only** — everything lives at `git.tawa.pro`. No GitHub, no
  `mcp__github__*` tools. Git operations go through `mcp__jci-mcp__git_*` or the `git` CLI.
- **Remotes are always HTTPS** (`https://git.insureco.io/org/repo.git`). Never switch to
  SSH to fix auth — run `tawa login`, see [Auth failures](#auth-failures--run-tawa-login).
- **`main` is PR-only.** Never commit to `main`; it advances solely through a merged PR —
  one the **agent merges itself** (see Autonomous Merge below).

## Issue-Driven Development (required)

Every feature, bug fix, or non-trivial task **must have a git issue** before code is written.

```
Create issue → branch → implement → PR → self-merge → close via commit message
```

1. Check for an existing issue first (`git_issue_list`); create one if missing (`git_issue_create`).
2. Reference the issue number in the commit: `feat: add tagline to branding (#42)`.
3. Auto-close from the commit body with `fix #N`, `close #N`, or `resolve #N`.

Only truly trivial one-liners are exempt.

## The Feature Loop

1. **Create issue first** — `git_issue_create`
2. **Plan** — `planner` agent breaks down the work
3. **TDD** — `tdd-guide` agent, tests written first (RED → GREEN → refactor, 80%+ coverage)
4. **Branch** — in your own worktree off `origin/main`: `claw/<task>-<shortid>`
5. **Code review** — `code-reviewer` agent after writing code
6. **Commit & push** — explicit paths, reference the issue (`feat: add X (#N)`)
7. **Open PR** — `git_pr_create`
8. **Rebase & verify green** — `git fetch origin && git rebase origin/main`, then run the
   repo's typecheck / lint / tests. This is the gate that replaces human review.
9. **Self-merge** — `git_pr_merge`. Automatic; do not wait for a human (see below).
10. **Cut release** — `git_release_create` after a deploy-worthy batch

## Autonomous Merge — Agents Self-Merge Their PRs

**Every agent runs the full pipeline end-to-end and merges its own PR. The merge is the
default terminal step, not a handoff.** The human ("vibe coder") does not review or click
merge — they tell the agent to *test before merging*, and a green, rebased PR merges
itself. Agents are pulled in **only on a major error**.

**Do NOT wait for the human:**
- Never end a turn at "PR is open, ready for you to merge." A PR you opened is yours to merge.
- Never ask "want me to merge this?" for a routine change — merging is the assumed intent.
- When agents fan out, the orchestrator **serializes** merges (one PR at a time, each
  rebased on the prior merge) and **merges them itself** — nothing is parked for a person.

**Escalate instead of merging — STOP and surface to the human ONLY when:**
- A **merge/rebase conflict** you cannot cleanly and confidently resolve.
- **Typecheck / lint / tests / build fail** and you can't green them.
- A **deploy-gate or smoke-test failure**, or a red post-merge signal.
- The change is **destructive, irreversible, or outside the task's stated scope** (schema
  drops, data migrations, mass deletions, secret rotation, force-push to a protected branch).
- A **security-sensitive** change you're not confident is correct.
- Genuinely **ambiguous requirements** where the wrong guess is expensive.

"I'm slightly unsure the feature is perfect" is **not** a major error — that's what the
issue, the diff, and the next iteration are for. Outside the list above, proceed to merge.

**Permissions & enforcement (already in place):**
- Claude Code's global settings allow `Bash(*)` and the Forgejo PR tools (`git_pr_create`,
  `git_pr_merge`, `git_pr_get`, `git_pr_list`) with no prompt.
- Branch protection on `main` (`required_approvals=0`) enforces PR-only mechanically while
  still letting the agent self-merge — that is exactly why approvals are 0.
- Release tags are protected too: only the accounts on a repository's tag rule can create,
  move or delete a tag matching `v*` or `*-v*`. See [Release Management](#release-management).
- Both are applied by the `tawa` CLI (**0.27.0+**). `tawa git create` and `tawa sample --git`
  protect `main` and release tags on the repository they create, with no further step. For a
  repository that already exists, run `tawa git protect <owner/repo>` — a **dry run** that
  prints what would change — then add `--apply`. `tawa git protect --all` sweeps every
  repository in the org (`--org <name>`, default `insureco`); `--all --apply` prints how many
  repositories need changes and asks first (`--yes` skips the question). `--main` or `--tags`
  limits it to one kind of rule.

> **Correction (2026-09-29):** this section used to name `forgejo-protect-main` as what
> enforces PR-only `main`. No such command exists in the `tawa` CLI, so anyone who went
> looking for it found nothing and may have left a repository unprotected. Use
> `tawa git protect` (tawa 0.27.0+) instead. Forgejo 14 has tag protection per repository
> only, with no org-wide setting, which is why the CLI applies it repository by repository.

**Deploy is still a separate, single-owner step.** After the merge(s) land on `origin/main`,
one agent runs `tawa deploy --prod` once. Autonomous merge changes the *merge* gate, not the
*ship* gate. See `deploy-pipeline`.

## Labels — the board's source of truth

**Type labels:** `feature`, `bug`, `ux`, `infra`, `debt`, `phase`

**Status labels → Kanban columns** (moving a card = swap the `status:*` label):

| Label | Column | Color |
|-------|--------|-------|
| `status:backlog` | Backlog | `#64748b` |
| `status:in-progress` | In Progress | `#2563eb` |
| `status:review` | In Review | `#d97706` |
| `status:blocked` | Blocked | `#dc2626` |
| (closed, no label) | Done | automatic |

### Labels live on the org, not on each repo

Forgejo labels are per-repo, and nothing creates them when a repo is made — so until
2026-09-18 most repos had none, and the first labelled issue on any of them failed with
`Label "feature" does not exist in <repo>. Labels there: (none)`. Agents then hand-built a
label set one repo at a time, with drifting colors.

The ten labels above now exist **once, on the `insureco` org**, and jci-mcp resolves org
labels alongside a repo's own ([jci-mcp#126](https://git.insureco.io/insureco/jci-mcp/issues/126)).
Every `insureco` repo — including one created five minutes ago — accepts them with zero
labels of its own. There is nothing to bootstrap.

```
git_label { action: "list",   org: "insureco" }                      # the shared taxonomy
git_label { action: "create", org: "insureco", name, color }         # add to it — every repo gets it
git_label { action: "create", repo: "insureco/my-svc", name, color } # one repo only
git_issue_labels_list { repo }                                       # what an issue here can carry; each label marked scope: org | repo
```

- **A missing standard label is an org problem.** Add it to the org, never to the repo.
- **Repo-level labels are for something genuinely specific to one repo.** A repo label
  **shadows** an org label of the same name, so a repo-level `bug` with its own color
  silently replaces the shared one there.
- **An unknown name still fails loudly**, on issues *and* PRs, listing both the repo's and
  the org's labels. That is deliberate: the old behaviour dropped unknown labels and
  reported success, leaving issues with no labels at all.
- A few repos (`jci-mcp`, `bio-vault`, `iec-insurebio`) still carry repo-level copies that
  predate this. They are harmless. Do not delete them casually — deleting a label strips it
  from every issue that carries it.

## Sprint Rhythm

1. **Plan** — review open issues, pick the sprint's work, label with milestone
2. **Build** — one issue per branch/feature, commit often
3. **Ship** — the agent **self-merges its own PR** (rebase → verify green → `git_pr_merge`),
   cuts a release, closes issues. No human merge gate.
4. **Retrospect** — which issues stayed open, and why?

### Commit message format

```
<type>: <description> (#N)
```

Types: `feat, fix, refactor, docs, test, chore, perf, ci`. Always link the issue when one
exists. Attribution is disabled globally.

## Release Management

Cut a release after every meaningful, deployed batch. Check existing releases first
(`git_release_list`), then `git_release_create`.

| Bump | Meaning |
|------|---------|
| Patch `v1.0.x` | Bug fixes, minor tweaks |
| Minor `v1.x.0` | New features, UI additions |
| Major `vX.0.0` | Breaking changes, rewrites |

### Who can create a release tag

Every repository created with `tawa git create` or `tawa sample --git` (tawa **0.27.0+**), and
every repository `tawa git protect --apply` has been run on, carries tag rules for `v*` and
`*-v*`. Only the accounts on the rule's allow-list can create, move or delete a matching tag.
Forgejo has **no admin bypass**: a site or org admin who is not on the list is refused like
anyone else.

| | Default allow-list |
|--|--|
| Org-owned repository | the person who ran the command, plus the org's `Owners` team, plus its `runners` team when the org has one |
| Personal repository | the person who ran the command |

`iec-admin` is on the list only when it was the account that ran the command; it is never
added to a repository where it is only the builder's read collaborator. Each run prints who
is allowed. `--allow-user`, `--allow-team` and `--pattern` (all repeatable), or
`release_tags` in `~/.tawa/config.yaml`, replace the defaults.

Patterns are Forgejo globs matched against the **whole** tag name, and `*` matches any
characters. `v*` matches `v1.2.3` and also any other tag that starts with `v`, such as
`vendor-thing`; `*-v*` matches `agent-v0.7.0` and any tag containing `-v`. A tag you did not
mean as a release can therefore be protected too.

#### When a tag push or `git_release_create` is refused

The repository's tag rule does not include the account you are using. Do not work around it
(a different account, a tag name chosen to dodge the pattern, deleting the rule). Check the
rule instead:

```bash
tawa git protect <owner/repo> --tags     # dry run: prints the current rule and who it allows
```

A rule whose allow-list is not the default is reported as `DIFFERS` and left alone; the line
says when it leaves you out. If you should be on it, ask an owner of the repository to add
you (`--allow-user`, then `--apply --update`). Changing someone else's rule to include
yourself is an owner's decision, not a workaround.

`tawa git protect` refuses to write a rule that would leave the person running it unable to
create matching tags, unless `--lock-me-out` is passed. If your git username is not known,
it makes no rule at all; run `tawa login`.

## Documentation & Decisions

Use the **wiki** to capture the *why* — architecture decisions, non-obvious "why X instead
of Y" choices, onboarding context (data model, auth flow, deploy process). Tools:
`git_wiki_create` / `git_wiki_update`. Write a wiki page when a new pattern is introduced or
a non-obvious decision is made; update it when behavior changes.

## Villages — Cross-Repo System Tracking

The ecosystem is organized into **Villages** — high-level system components spanning multiple
repos. All 15 Villages reaching v1 constitutes **Voyager** (Ecosystem Release 1).

- Issues live in the repo where the code lives; a **Forgejo org-level Project** (one per
  Village) is the cross-repo board.
- Each constituent repo tracks its own `v1` milestone (`git_milestone_create`).
- Each Village gets a lightweight `{village}-wiki` repo (`has_issues: false`) for roadmap + ADRs.
- When all repos in a Village hit v1 → cut Village v1 release → Voyager milestone advances.

| Layer | Tool |
|-------|------|
| Village roadmap & ADRs | Wiki on `{village}-wiki` repo |
| Village v1 target | `v1` milestone per repo |
| Cross-repo board | Forgejo org Project (one per Village) |
| Ecosystem release | `git_release_create` on the `voyager` tracking repo |

## Auth failures — run `tawa login`

`tawa login` is how a machine gets its Forgejo credential. One call authenticates, mints a
PAT, and stores it for **both** the `tawa` CLI (`~/.tawa/forgejo-credentials.json`) and **git**
(the OS credential helper). With saved credentials present it runs non-interactively.

```bash
tawa login --save
git ls-remote origin HEAD     # verify, without touching the credential store
```

There is nothing to do afterwards. Do **not** hand-mint a PAT and store it yourself.

> **Superseded (2026-09-20).** This page used to say "do NOT reflexively re-login", and told
> you to mint a stable `git-cli-*` PAT through the Forgejo admin CLI and store it by hand so
> it would sit outside the `tawa-cli-` cull. **That guidance is stale. Do not follow it.**
> It read as a prohibition rather than a caveat: an agent avoided `tawa login`, worked around
> it, and then minted a redundant token nobody needed.
>
> What is actually true, verified against `iec-builder/src/routes/users.ts` on 2026-09-22:
> `deleteStaleTokens(username, machineId)` deletes only **this machine's** tokens, those named
> `tawa-cli-<machineId>-*`, and deletes nothing at all when the caller sends no machineId. A
> login on one machine never revokes another machine's token, so a laptop, a server and a
> cloud-runner session can all stay logged in as the same user at once. `tawa login` also
> rewrites the git credential in the same call, so this machine ends up holding a working
> credential. The separate stable PAT solved a problem that never existed.

**Scopes — the one real limit.** The token `tawa login` mints carries `write:repository`,
`write:organization` and `write:user`. That covers git and the Forgejo `/pulls` API. It does
**not** carry `write:issue`, so **creating an issue with it returns 403**, and logging in again
will not change that. Use the `git_issue_*` MCP tools for issues — they authenticate as the MCP
server rather than as your local token.

⚠️ Never test a token by putting it in a git URL (`https://user:$TOK@host/…`) — the
credential helper silently overwrites the stored credential with whatever the URL carried.

## Commits Are the Only Durable Save

Uncommitted edits live only in the working tree — a branch switch, rebase, or another
agent's operation can discard them with no recovery. **Commit as soon as a change is
coherent**, to your `claw/<task>-<shortid>` branch (never `main`), staging **explicit paths**
(`git add <paths>` — never `git add -u`/`-a`, which sweep up other agents' uncommitted edits
on a shared checkout). Small WIP commits are fine — they squash at merge; lost work cannot.

> There is **no** "Stop hook auto-commits `git add -u` and pushes to `main`" safety net —
> that older behavior is removed and superseded. Any automated commit must be branch-aware:
> refuse on `main`, stage explicit paths, and go through a self-merged PR.

## The One-Liner

> No work without an issue → plan → tests first → branch → commit referencing `#N` → PR →
> rebase + verify green → **agent self-merges** → cut a release per batch. Human is pulled
> in only on a major error. Issues live with the code; Villages aggregate cross-repo; Wikis
> hold the "why."

## Common Mistakes

- Starting work with no issue (only trivial one-liners are exempt).
- Ending at "PR is open, ready for you to merge" — a PR you opened is yours to self-merge.
- Asking "should I merge?" for a routine, green, rebased PR — merging is the assumed intent.
- Committing to `main` directly, or using `git add -u`/`-a` on a shared checkout.
- Merging without running the repo's tests first — the test pass is what replaces review.
- Committing without a `#N` reference when an issue exists.
- Creating `feature` / `status:*` labels on a repo because an issue create said they were
  missing — they live on the org. See [Labels live on the org](#labels-live-on-the-org-not-on-each-repo).
- Switching a remote to SSH to dodge an auth failure.
- Looking for `forgejo-protect-main` — it does not exist. Use `tawa git protect` (0.27.0+).
- Running `tawa git protect --all --apply` without first reading the dry run.
- Working around a refused release tag instead of checking the rule with a dry run. There is
  no admin bypass; only the accounts on the allow-list can tag.
- Trusting the sweep summary's "unchanged" count: it currently counts a repository with a
  `DIFFERS` rule as unchanged ([tawa-cli#128](https://git.insureco.io/insureco/tawa-cli/issues/128)).
  Read the per-repository `DIFFERS` lines.
- Hand-minting a Forgejo PAT, or avoiding `tawa login` when a push 401s — `tawa login`
  is the supported fix and rewrites the git credential itself. See below.
- Using GitHub / `mcp__github__*` tools — everything is Forgejo at `git.tawa.pro`.
- Tracking cross-repo work as issues in a "meta" repo — issues live where the code lives;
  aggregate them with a Village Project instead.

Install

Copy the skill content and save it to:

~/.claude/rules/tawa-agile-workflow.md
Download .md

Coming soon via CLI:

tawa chaac install tawa-agile-workflow

Details

Format
Rule
Category
platform
Version
1.0.44633
Tokens
~4,266
Updated
2026-10-13
platformagilegitforgejoissuespull-requestsmergereleasesvillagesprocess