arcane-cli 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +253 -253
- package/dist/assets/.arcane/agents/agent-policies-template.md +414 -414
- package/dist/assets/.arcane/governance/agent-policies.md +414 -414
- package/dist/assets/.arcane/governance/agent-work-queue-model.md +61 -61
- package/dist/assets/.arcane/governance/cicd-standards.md +227 -227
- package/dist/assets/.arcane/governance/development-methodology.md +384 -384
- package/dist/assets/.arcane/governance/git-conventions.md +759 -759
- package/dist/assets/.arcane/governance/naming-conventions.md +142 -142
- package/dist/assets/.arcane/governance/new-business-setup.md +182 -182
- package/dist/assets/.arcane/governance/portable-bootstrap.md +101 -101
- package/dist/assets/.arcane/governance/product-excellence-standards.md +211 -211
- package/dist/assets/.arcane/governance/testing-standards.md +158 -158
- package/dist/assets/.arcane/governance/universal-agent-rules.md +108 -108
- package/dist/assets/.arcane/image-prompts/adelaide-image-prompt.md +140 -140
- package/dist/assets/.arcane/image-prompts/alexander-image-prompt.md +138 -138
- package/dist/assets/.arcane/image-prompts/bess-image-prompt.md +139 -139
- package/dist/assets/.arcane/image-prompts/circe-image-prompt.md +143 -143
- package/dist/assets/.arcane/image-prompts/custodio-image-prompt.md +140 -140
- package/dist/assets/.arcane/image-prompts/iris-image-prompt.md +139 -139
- package/dist/assets/.arcane/image-prompts/kellar-image-prompt.md +141 -141
- package/dist/assets/.arcane/image-prompts/lafayette-image-prompt.md +140 -140
- package/dist/assets/.arcane/image-prompts/lince-image-prompt.md +142 -142
- package/dist/assets/.arcane/image-prompts/mercurio-image-prompt.md +140 -140
- package/dist/assets/.arcane/image-prompts/merlin-image-prompt.md +139 -139
- package/dist/assets/.arcane/image-prompts/prospero-image-prompt.md +141 -141
- package/dist/assets/.claude/commands/spell-enchant.md +9 -9
- package/dist/assets/.github/agents/adelaide.agent.md +44 -44
- package/dist/assets/.github/agents/alexander.agent.md +43 -43
- package/dist/assets/.github/agents/bess.agent.md +42 -42
- package/dist/assets/.github/agents/circe.agent.md +43 -43
- package/dist/assets/.github/agents/custodio.agent.md +44 -44
- package/dist/assets/.github/agents/iris.agent.md +43 -43
- package/dist/assets/.github/agents/kellar.agent.md +43 -43
- package/dist/assets/.github/agents/lafayette.agent.md +42 -42
- package/dist/assets/.github/agents/lince.agent.md +43 -43
- package/dist/assets/.github/agents/mercurio.agent.md +43 -43
- package/dist/assets/.github/agents/merlin.agent.md +44 -44
- package/dist/assets/.github/agents/prospero.agent.md +43 -43
- package/dist/assets/.github/prompts/spell-close-session.prompt.md +17 -5
- package/dist/assets/.github/prompts/spell-commit-work.prompt.md +24 -6
- package/dist/assets/.github/prompts/spell-create-pull-request.prompt.md +12 -3
- package/dist/assets/.github/prompts/spell-enchant.prompt.md +385 -385
- package/dist/assets/.github/prompts/spell-feedback.prompt.md +113 -113
- package/dist/assets/.github/prompts/spell-full-cycle.prompt.md +202 -201
- package/dist/assets/.github/prompts/spell-implement.prompt.md +101 -101
- package/dist/assets/.github/prompts/spell-open-session.prompt.md +20 -5
- package/dist/assets/.github/prompts/spell-scope.prompt.md +263 -263
- package/dist/assets/agents/architecture-lead.yaml +61 -61
- package/dist/assets/agents/collaborator.yaml +59 -59
- package/dist/assets/agents/devops.yaml +60 -60
- package/dist/assets/agents/frontend-dev.yaml +60 -60
- package/dist/assets/agents/fullstack-dev.yaml +59 -59
- package/dist/assets/agents/marketing-strategist.yaml +60 -60
- package/dist/assets/agents/mobile-dev.yaml +59 -59
- package/dist/assets/agents/operations-comms.yaml +58 -58
- package/dist/assets/agents/orchestrator.yaml +60 -60
- package/dist/assets/agents/qa-lead.yaml +60 -60
- package/dist/assets/agents/research-analyst.yaml +59 -59
- package/dist/assets/agents/security-ops.yaml +61 -61
- package/dist/index.js +323 -7
- package/dist/index.js.map +1 -1
- package/package.json +72 -72
- package/dist/assets/.claude/commands/spell-eas-ios-deploy.md +0 -9
- package/dist/assets/.github/prompts/spell-eas-ios-deploy.prompt.md +0 -183
|
@@ -1,759 +1,759 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Git Conventions — Commit Format and Branching Model
|
|
3
|
-
audience: both
|
|
4
|
-
status: active
|
|
5
|
-
distributable: true
|
|
6
|
-
last_updated: 2026-07-05
|
|
7
|
-
tags: [git, conventional-commits, workflow, standards, attribution]
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# Git Conventions
|
|
11
|
-
|
|
12
|
-
How to structure commits, branches, and pull requests for this repository.
|
|
13
|
-
|
|
14
|
-
## Executive Summary
|
|
15
|
-
|
|
16
|
-
- This repo uses Conventional Commits format for all commit messages — industry standard, tool-portable, human-readable.
|
|
17
|
-
- Trunk-based development with short-lived feature branches keeps history clean and reduces merge conflicts.
|
|
18
|
-
- No custom git hooks — conventions work on any machine without setup, no fragile tooling dependencies.
|
|
19
|
-
- Use `spell-commit-work` prompt during sessions to automate commit message generation in the correct format.
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Conventional Commits Format
|
|
24
|
-
|
|
25
|
-
All commit messages follow the [Conventional Commits](https://www.conventionalcommits.org/) standard.
|
|
26
|
-
|
|
27
|
-
### Basic Structure
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
type(scope): short description
|
|
31
|
-
|
|
32
|
-
[optional body with details]
|
|
33
|
-
|
|
34
|
-
[optional footer with breaking changes or issue references]
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### Commit Types
|
|
38
|
-
|
|
39
|
-
| Type | When to Use | Example |
|
|
40
|
-
| ---------- | ----------------------------------------------- | -------------------------------------------------------------- |
|
|
41
|
-
| `feat` | New feature or capability | `feat(prompts): add spell-commit-work for checkpointing` |
|
|
42
|
-
| `fix` | Bug fix | `fix(auth): restore token validation after refactor` |
|
|
43
|
-
| `docs` | Documentation only | `docs(decisions): add table of contents to DECISIONS.md` |
|
|
44
|
-
| `refactor` | Code/structure change, no behavior change | `refactor(playbooks): reorganize setup steps` |
|
|
45
|
-
| `chore` | Maintenance, deps, tooling, cleanup | `chore(deps): bump <dependency> to <version>` |
|
|
46
|
-
| `test` | Adding or fixing tests | `test(security): add token-expiry test` |
|
|
47
|
-
| `perf` | Performance improvements | `perf(api): reduce cold-start latency` |
|
|
48
|
-
| `ci` | CI/CD pipeline changes | `ci(azure): add DevOps pipeline for repo sync` |
|
|
49
|
-
| `style` | Code formatting, whitespace (rare in this repo) | `style(markdown): fix inconsistent heading levels` |
|
|
50
|
-
| `revert` | Revert a previous commit | `revert: undo feat(prompts): add spell-commit-work` |
|
|
51
|
-
|
|
52
|
-
### Scopes
|
|
53
|
-
|
|
54
|
-
Scope indicates what part of the repo changed. Use singular, lowercase.
|
|
55
|
-
|
|
56
|
-
| Scope | Area |
|
|
57
|
-
| ---------------- | ------------------------------------------------- |
|
|
58
|
-
| `prompts` | `.github/prompts/*.prompt.md` |
|
|
59
|
-
| `agents` | `agents/` directory, agent config, policies |
|
|
60
|
-
| `security` | `security/` directory, threat model, hardening |
|
|
61
|
-
| `infrastructure` | `infrastructure/` directory, hardware, OS setup |
|
|
62
|
-
| `decisions` | `DECISIONS.md` updates |
|
|
63
|
-
| `journal` | `journal/` entries |
|
|
64
|
-
| `governance` | `governance/` directory, process docs |
|
|
65
|
-
| `playbooks` | `playbooks/` directory |
|
|
66
|
-
| `business` | `ventures/` directory |
|
|
67
|
-
| `ai-context` | `ai-context/` directory |
|
|
68
|
-
| `repo` | Root-level files (README, TODO, .gitignore, etc.) |
|
|
69
|
-
| `naming` | `naming-conventions.md` |
|
|
70
|
-
|
|
71
|
-
Multiple scopes? Pick the primary one. If everything changed, use `repo` or omit the scope.
|
|
72
|
-
|
|
73
|
-
### Short Description Rules
|
|
74
|
-
|
|
75
|
-
- **Imperative mood:** "add", "fix", "update", "remove" (not "added", "fixes", "updating")
|
|
76
|
-
- **Lowercase:** start with lowercase letter
|
|
77
|
-
- **No period:** don't end with `.`
|
|
78
|
-
- **72 characters max:** keeps `git log --oneline` readable
|
|
79
|
-
|
|
80
|
-
**Good examples:**
|
|
81
|
-
|
|
82
|
-
- `add spell-commit-work prompt`
|
|
83
|
-
- `fix gateway auth regression after onboarding`
|
|
84
|
-
- `update table of contents in DECISIONS.md`
|
|
85
|
-
|
|
86
|
-
**Bad examples:**
|
|
87
|
-
|
|
88
|
-
- `Added spell-commit-work prompt.` (past tense, period)
|
|
89
|
-
- `Fix gateway authentication regression that occurred after running the onboarding wizard` (too long, 84 chars)
|
|
90
|
-
|
|
91
|
-
### Optional Body
|
|
92
|
-
|
|
93
|
-
Include a body when:
|
|
94
|
-
|
|
95
|
-
- The short description doesn't explain _why_
|
|
96
|
-
- Multiple related changes need enumeration
|
|
97
|
-
- ADR or file references add value
|
|
98
|
-
- Future readers need context
|
|
99
|
-
|
|
100
|
-
**Format:**
|
|
101
|
-
|
|
102
|
-
- Blank line after the short description
|
|
103
|
-
- Bullet list or paragraphs
|
|
104
|
-
- Wrap at 72 characters per line
|
|
105
|
-
- Reference ADRs, files, or issues
|
|
106
|
-
|
|
107
|
-
**Example:**
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
feat(prompts): add spell-commit-work for session checkpoints
|
|
111
|
-
|
|
112
|
-
Enables committing work-in-progress during active sessions without
|
|
113
|
-
waiting for spell-close-session. Generates Conventional Commits format
|
|
114
|
-
messages with proper type and scope.
|
|
115
|
-
|
|
116
|
-
Implements ADR-019 spell- naming convention.
|
|
117
|
-
|
|
118
|
-
Changes:
|
|
119
|
-
- Created .github/prompts/spell-commit-work.prompt.md
|
|
120
|
-
- Created governance/git-conventions.md as reference doc
|
|
121
|
-
- Updated TODO.md to mark git conventions doc complete
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Optional Footer
|
|
125
|
-
|
|
126
|
-
Use for:
|
|
127
|
-
|
|
128
|
-
- **Breaking changes:** `BREAKING CHANGE: removed support for plaintext token auth`
|
|
129
|
-
- **Issue/ticket references:** `Closes #535` or `Fixes #127`
|
|
130
|
-
|
|
131
|
-
Most commits in this repo won't need footers.
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## Atomic Commits
|
|
136
|
-
|
|
137
|
-
Each commit should be a **single logical change** — one coherent unit that can be understood, reviewed, reverted, or cherry-picked on its own.
|
|
138
|
-
|
|
139
|
-
### The Rule
|
|
140
|
-
|
|
141
|
-
> **One commit = one purpose.** If you can't describe the commit in a single short description without "and", it's probably two commits.
|
|
142
|
-
|
|
143
|
-
### When to Split
|
|
144
|
-
|
|
145
|
-
| Situation | Action |
|
|
146
|
-
| -------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
147
|
-
| New governance doc + updates to 3 referencing docs | One commit — the doc and its cross-references form one logical unit |
|
|
148
|
-
| New feature + unrelated typo fix | Two commits — the typo fix is a separate `fix` or `docs` commit |
|
|
149
|
-
| Refactor + behavior change | Two commits — refactor first (`refactor`), then behavior change (`feat` or `fix`) |
|
|
150
|
-
| Multiple ADRs decided independently | One commit per ADR, each with its related doc updates |
|
|
151
|
-
| Config change + documentation of that change | One commit — the config and its docs are one logical unit |
|
|
152
|
-
|
|
153
|
-
### When to Combine
|
|
154
|
-
|
|
155
|
-
Not every file change needs its own commit. **Group changes that only make sense together:**
|
|
156
|
-
|
|
157
|
-
- A new spell prompt + updates to the methodology doc, CLAUDE.md, copilot-instructions.md, and DECISIONS.md that reference it = **one commit** (the spell and its integration are one feature)
|
|
158
|
-
- A playbook + its template files = **one commit**
|
|
159
|
-
- A security fix + its threat model update = **one commit**
|
|
160
|
-
|
|
161
|
-
The test: if you reverted just one of the commits, would the repo be in an inconsistent state? If yes, they belong together.
|
|
162
|
-
|
|
163
|
-
### Staging Strategy
|
|
164
|
-
|
|
165
|
-
Use `git add -p` or selective staging to separate unrelated changes that were edited in the same session:
|
|
166
|
-
|
|
167
|
-
```bash
|
|
168
|
-
# Stage only the files related to one logical change
|
|
169
|
-
git add governance/new-standard.md DECISIONS.md CLAUDE.md
|
|
170
|
-
git commit -m "docs(governance): add new-standard with ADR-053"
|
|
171
|
-
|
|
172
|
-
# Then stage the unrelated fix
|
|
173
|
-
git add README.md
|
|
174
|
-
git commit -m "fix(repo): correct broken link in README"
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
---
|
|
178
|
-
|
|
179
|
-
## Branch Discipline
|
|
180
|
-
|
|
181
|
-
**Trunk-based development** with mandatory topic branches for all actors. No one — human or agent — commits directly to main.
|
|
182
|
-
|
|
183
|
-
### The Rule
|
|
184
|
-
|
|
185
|
-
> **Main is an integration-only branch.** It receives merges, never direct commits. All work happens on topic branches.
|
|
186
|
-
|
|
187
|
-
This applies to:
|
|
188
|
-
|
|
189
|
-
- Humans editing on any machine
|
|
190
|
-
- Autonomous agents working independently
|
|
191
|
-
- Interactive AI tools (Copilot, Claude Code, Codex, or any other client)
|
|
192
|
-
|
|
193
|
-
### Branch Naming
|
|
194
|
-
|
|
195
|
-
**Humans:**
|
|
196
|
-
|
|
197
|
-
```
|
|
198
|
-
type/short-description
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
**Session branches (interactive tools — Copilot, Claude Code, etc.):**
|
|
202
|
-
|
|
203
|
-
```
|
|
204
|
-
sessions/YYYY-MM-DD-topic-slug
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
Create the session branch as the **first action** of any session, before any file edits or commits. All session commits land on this branch. At close, push and open a PR. After merge, return to `main`.
|
|
208
|
-
|
|
209
|
-
**Examples:**
|
|
210
|
-
|
|
211
|
-
- `sessions/2025-11-04-widget-app-implementation` (interactive session)
|
|
212
|
-
- `sessions/2025-11-12-payment-webhook-fix` (interactive session)
|
|
213
|
-
|
|
214
|
-
**Session branch policy (required):**
|
|
215
|
-
|
|
216
|
-
- Session branches must be deterministic, human-readable, and derived from the active task title.
|
|
217
|
-
- Default format for new interactive sessions: `sessions/YYYY-MM-DD-<topic-slug>`.
|
|
218
|
-
- Random adjective-noun branches (for example, `ideal-disco`) are non-compliant and must be renamed.
|
|
219
|
-
- If a non-compliant branch was already pushed, migrate it safely:
|
|
220
|
-
1. `git branch -m <old> <new>`
|
|
221
|
-
2. `git push -u origin <new>`
|
|
222
|
-
3. `git push origin --delete <old>` (skip this if an active PR still depends on `<old>`).
|
|
223
|
-
|
|
224
|
-
**Agents:**
|
|
225
|
-
|
|
226
|
-
```
|
|
227
|
-
{agent-slug}/type/short-description
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
The agent slug prefix makes branch ownership obvious in `git branch -r` output and prevents naming collisions between agents.
|
|
231
|
-
|
|
232
|
-
**Examples:**
|
|
233
|
-
|
|
234
|
-
- `docs/readme-update` (human)
|
|
235
|
-
- `feat/spell-commit-work` (human)
|
|
236
|
-
- `fix/auth-token-regression` (human)
|
|
237
|
-
- `lafayette/feat/api-endpoint` (agent — Lafayette)
|
|
238
|
-
- `merlin/docs/architecture-update` (agent — Merlin)
|
|
239
|
-
- `lince/fix/test-regression` (agent — Lince)
|
|
240
|
-
|
|
241
|
-
### Human Workflow
|
|
242
|
-
|
|
243
|
-
1. **Start a topic branch** before any work:
|
|
244
|
-
```bash
|
|
245
|
-
git fetch origin
|
|
246
|
-
git checkout -b docs/my-topic origin/main
|
|
247
|
-
```
|
|
248
|
-
2. **Commit often** using Conventional Commits format.
|
|
249
|
-
3. **Push your branch** (especially important for multi-machine work):
|
|
250
|
-
```bash
|
|
251
|
-
git push origin docs/my-topic
|
|
252
|
-
```
|
|
253
|
-
4. **Merge to main via fast-forward** when done:
|
|
254
|
-
```bash
|
|
255
|
-
git checkout main
|
|
256
|
-
git pull origin main
|
|
257
|
-
git merge --ff-only docs/my-topic
|
|
258
|
-
git push origin main
|
|
259
|
-
git branch -d docs/my-topic
|
|
260
|
-
git push origin --delete docs/my-topic
|
|
261
|
-
```
|
|
262
|
-
5. **If ff-only fails** (someone else merged first), rebase and retry:
|
|
263
|
-
```bash
|
|
264
|
-
git checkout docs/my-topic
|
|
265
|
-
git rebase main
|
|
266
|
-
git checkout main
|
|
267
|
-
git merge --ff-only docs/my-topic
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
### Agent Workflow
|
|
271
|
-
|
|
272
|
-
1. **Create a prefixed topic branch:**
|
|
273
|
-
```bash
|
|
274
|
-
git checkout -b lafayette/feat/api-endpoint origin/main
|
|
275
|
-
```
|
|
276
|
-
2. **Commit with proper attribution** (author identity + required trailers).
|
|
277
|
-
3. **Sync with main before opening a PR** — always rebase on the latest origin/main before pushing
|
|
278
|
-
or creating a PR, regardless of whether conflicts are expected. **This is mandatory for every
|
|
279
|
-
agent-initiated PR — see the [🛑 Agent-mandatory pre-PR guard](#-agent-mandatory-pre-pr-guard)
|
|
280
|
-
callout below. It applies even when using raw `az repos pr create` / `gh pr create` / MCP tools
|
|
281
|
-
instead of the `spell-create-pull-request` spell.**
|
|
282
|
-
```bash
|
|
283
|
-
git fetch origin
|
|
284
|
-
git rebase origin/main
|
|
285
|
-
# If conflicts arise: resolve → git add → git rebase --continue
|
|
286
|
-
```
|
|
287
|
-
This ensures the PR diff is clean, the CI runs against current main, and reviewers see no
|
|
288
|
-
stale divergence. Resolve conflicts locally — never push a branch with known merge conflicts.
|
|
289
|
-
4. **Push the branch to origin** (after rebase).
|
|
290
|
-
5. **Merge or queue for review** based on power level:
|
|
291
|
-
- **Magus+ agents:** self-merge via `git merge --ff-only`, then push main
|
|
292
|
-
- **Below Magus:** push the branch, report branch name, and queue for human merge
|
|
293
|
-
6. **Delete the branch** after merge.
|
|
294
|
-
|
|
295
|
-
### Multi-Machine Workflow
|
|
296
|
-
|
|
297
|
-
When working across machines, topic branches are the coordination mechanism:
|
|
298
|
-
|
|
299
|
-
- **Starting work on any machine:** `git fetch && git checkout -b type/topic origin/main`
|
|
300
|
-
- **Continuing work started on another machine:** `git fetch && git checkout type/topic && git pull`
|
|
301
|
-
- **Push branches frequently** so work is available across machines
|
|
302
|
-
- Main stays clean — only receives merges from completed branches
|
|
303
|
-
|
|
304
|
-
### Merge Strategy by Repo Risk
|
|
305
|
-
|
|
306
|
-
| Repo Type | Examples | Merge Method | PR Required? |
|
|
307
|
-
| -------------- | ------------------------------------------- | ------------ | ------------ |
|
|
308
|
-
| **Docs repos** | docs hub, prototypes | PR | Yes |
|
|
309
|
-
| **Code repos** | application, API, storefront repos | PR | Yes |
|
|
310
|
-
|
|
311
|
-
- **All repos have main branch protection.** Direct pushes to main are rejected. All changes must go through a PR.
|
|
312
|
-
|
|
313
|
-
#### Azure DevOps PR Merge Type
|
|
314
|
-
|
|
315
|
-
When completing a PR in Azure DevOps, allow only these merge strategies by default:
|
|
316
|
-
|
|
317
|
-
- **Merge (no fast forward)**, or
|
|
318
|
-
- **Rebase and fast-forward**
|
|
319
|
-
|
|
320
|
-
Do **not** use Squash commit.
|
|
321
|
-
|
|
322
|
-
| Merge Type | Use? | Why |
|
|
323
|
-
| --------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
324
|
-
| **Rebase and fast-forward** | **Yes** | Preserves linear history while keeping individual commits and attribution trailers intact. |
|
|
325
|
-
| **Merge (no fast forward)** | **Yes** | Preserves full branch context and review traceability where explicit merge commits are preferred. |
|
|
326
|
-
| Squash commit | **No** | Collapses commit history and breaks per-commit attribution/analytics and granular rollback. |
|
|
327
|
-
| Semi-linear merge | No | Adds unnecessary merge commits on top of rebased commits; avoid by default. |
|
|
328
|
-
|
|
329
|
-
### Commit Governance
|
|
330
|
-
|
|
331
|
-
Commit execution rights depend on the interaction context:
|
|
332
|
-
|
|
333
|
-
| Context | Commit Behavior | Rationale |
|
|
334
|
-
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
335
|
-
| **Interactive session** (Copilot, Claude in VS Code, Claude Code) | **Must ask human** before committing. Stage changes, present proposed message, wait for approval. | Human is actively collaborating; commits are a shared decision. |
|
|
336
|
-
| **Autonomous agent** at Magus+ power level | May self-commit and self-merge within approved scope (per your power-level policy). Must use proper author/trailers. | Agent is operating independently with delegated authority. |
|
|
337
|
-
| **Autonomous agent** below Magus | Must commit to topic branch and queue merge for human review. | Insufficient autonomy level for unsupervised merges to main. |
|
|
338
|
-
|
|
339
|
-
**Interactive session rule applies to ALL interactive tools, regardless of agent identity.** Even a high-power-level agent cannot auto-commit when operating through an interactive editor session — the human is present and must approve.
|
|
340
|
-
|
|
341
|
-
### Post-Merge Cleanup
|
|
342
|
-
|
|
343
|
-
After every PR merge or local fast-forward merge, **always return to main and prune the branch**. Failing to do this leaves you on a stale branch where new work gets committed to the wrong place or stays unpushed.
|
|
344
|
-
|
|
345
|
-
```bash
|
|
346
|
-
# After PR merges on remote:
|
|
347
|
-
git checkout main
|
|
348
|
-
git pull origin main
|
|
349
|
-
git branch -d type/old-topic # delete local branch
|
|
350
|
-
git push origin --delete type/old-topic # delete remote branch (safety net; ignore 'does not exist' errors if already auto-deleted)
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
This applies to all actors — humans, interactive tools (Copilot, Claude), and autonomous agents. The `spell-commit-work` and `spell-close-session` prompts enforce this check.
|
|
354
|
-
|
|
355
|
-
### ADO PR Lifecycle — Complete Command Reference
|
|
356
|
-
|
|
357
|
-
When working in an Azure DevOps repo with branch protection (direct push to `main` rejected), use this exact sequence. Several shortcut tools have known reliability issues on Windows — use the commands below instead.
|
|
358
|
-
|
|
359
|
-
```powershell
|
|
360
|
-
# 1. Push your topic branch
|
|
361
|
-
git push origin <branch>
|
|
362
|
-
|
|
363
|
-
# 2. Create the PR
|
|
364
|
-
az repos pr create `
|
|
365
|
-
--repository <repo> `
|
|
366
|
-
--org https://dev.azure.com/<org> `
|
|
367
|
-
--source-branch <branch> `
|
|
368
|
-
--target-branch main `
|
|
369
|
-
--title "type(scope): description" `
|
|
370
|
-
--description "Body..."
|
|
371
|
-
# Capture pullRequestId from the JSON output
|
|
372
|
-
|
|
373
|
-
# 3. Assign reviewer (default to operator identity; idempotent)
|
|
374
|
-
# Resolve reviewer (example: git config user.email), then:
|
|
375
|
-
az repos pr reviewer list --id <PR_ID> --org https://dev.azure.com/<org>
|
|
376
|
-
# If reviewer is missing, add:
|
|
377
|
-
az repos pr reviewer add --id <PR_ID> --org https://dev.azure.com/<org> --reviewer "<email>"
|
|
378
|
-
|
|
379
|
-
# 4. Approve via CLI first (self-approve only when policy allows)
|
|
380
|
-
az repos pr set-vote --id <PR_ID> --org https://dev.azure.com/<org> --vote approve
|
|
381
|
-
# If policy blocks self-approval, record and require second human approval.
|
|
382
|
-
|
|
383
|
-
# 5. REST fallback only if CLI vote command fails
|
|
384
|
-
$bearer = az account get-access-token --resource "499b84ac-1321-427f-aa17-267ca6975798" --query accessToken -o tsv
|
|
385
|
-
$headers = @{ Authorization = "Bearer $bearer"; "Content-Type" = "application/json" }
|
|
386
|
-
Invoke-RestMethod -Method PUT `
|
|
387
|
-
-Uri "https://dev.azure.com/<org>/<project>/_apis/git/repositories/<repo>/pullRequests/<PR_ID>/reviewers/<AAD-id>?api-version=7.1" `
|
|
388
|
-
-Headers $headers -Body '{"vote": 10}'
|
|
389
|
-
|
|
390
|
-
# 6. Verify vote registered (expect vote: 10 unless policy blocks self-approval)
|
|
391
|
-
az repos pr reviewer list --id <PR_ID> --org https://dev.azure.com/<org>
|
|
392
|
-
|
|
393
|
-
# 7. Complete (merge) the PR with source-branch deletion and squash disabled
|
|
394
|
-
# Allowed merge strategies: Merge (no fast forward) or Rebase+fast-forward
|
|
395
|
-
az repos pr update --id <PR_ID> --org https://dev.azure.com/<org> --status completed --delete-source-branch true --squash false
|
|
396
|
-
|
|
397
|
-
# 8. Pull merge commit and clean up (worktree-safe)
|
|
398
|
-
git checkout main
|
|
399
|
-
git pull origin main
|
|
400
|
-
git branch -d <branch> # delete local branch (skip if branch is attached to an active worktree)
|
|
401
|
-
git push origin --delete <branch> # delete remote branch (safety net — --delete-source-branch true usually handles this; ignore 'does not exist' errors)
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
**Known issues:**
|
|
405
|
-
|
|
406
|
-
| Issue | Symptom | Fix |
|
|
407
|
-
| --------------------------------------------------------------- | ----------------------------------- | ------------------------------------------ |
|
|
408
|
-
| Reviewer already assigned | `reviewer add` returns already exists | Treat as idempotent success and continue |
|
|
409
|
-
| `az repos pr set-vote` succeeds but approval still blocked | Policy requires additional approver | Confirm vote state, then request second human approval |
|
|
410
|
-
| MCP `vote_pull_request` returns "Success" but vote stays 0 | `reviewer list` shows `vote: 0` | Use `Invoke-RestMethod` step 5 above |
|
|
411
|
-
| `az rest --body '{"vote":10}'` fails | Shell parsing error on Windows | Use `Invoke-RestMethod` |
|
|
412
|
-
| `az repos pr update --status completed` fails with policy error | "Needs 1 approval" | Verify `vote: 10` first, then retry |
|
|
413
|
-
| MCP `create_pull_request` returns no data | No PR ID/URL in response | Fall back to `az repos pr create` |
|
|
414
|
-
| `gh pr create` not found | `gh` CLI not installed | Use `az repos pr create` |
|
|
415
|
-
| `creatorVoteCounts` is false on branch policy | Vote registers but PR still blocked | A second human must approve via ADO web UI |
|
|
416
|
-
| `az repos pr update --status completed` returns `status: active` without error | PR silently not merged | Add `--squash false` to the command; the flag triggers the merge path correctly |
|
|
417
|
-
| `git branch -d <branch>` fails after merge | Branch is attached to a worktree | Skip local delete; run remote delete + prune |
|
|
418
|
-
| `git push origin --delete <branch>` fails with missing ref | Branch already deleted remotely | Treat as non-fatal and continue |
|
|
419
|
-
|
|
420
|
-
### Branch Lifecycle
|
|
421
|
-
|
|
422
|
-
- **Short-lived:** hours to a few days, not weeks
|
|
423
|
-
- **Delete after merge:** don't let branches pile up — delete local and remote
|
|
424
|
-
- **No long-running feature branches:** they create merge hell
|
|
425
|
-
- **Stale branch cleanup:** branches older than 7 days or already merged should be pruned
|
|
426
|
-
- **Scheduled hygiene:** any scheduled auto-pull job should also run `git fetch --prune` to remove stale remote-tracking branches. Locally merged branches are pruned on the next session or scheduled cycle.
|
|
427
|
-
- **Workspace isolation:** agents must never create, switch, or modify branches in a human's primary workspace. All agent work happens in their own isolated clones.
|
|
428
|
-
|
|
429
|
-
---
|
|
430
|
-
|
|
431
|
-
## Ticket Tagging
|
|
432
|
-
|
|
433
|
-
If your tracker links commits to work items by ID (Azure Boards, GitHub Issues, Jira, etc.), tag commits so the linkage happens automatically.
|
|
434
|
-
|
|
435
|
-
**Recommended for Spell Loop PRs:**
|
|
436
|
-
|
|
437
|
-
- Create or identify a work item **before** starting spell-plan
|
|
438
|
-
- Include the work item ID in the PR description and link it before merging
|
|
439
|
-
- If your branch policy requires a linked work item, PRs without one will be blocked
|
|
440
|
-
|
|
441
|
-
**Commit prefix format:**
|
|
442
|
-
|
|
443
|
-
```
|
|
444
|
-
#506 test(api): add xUnit test project
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
- Prefix commits with `#WORKITEM` to enable automatic commit → work item linking
|
|
448
|
-
- The orchestrating agent should include the work item ID in the initial spell-plan message and carry it through to ship
|
|
449
|
-
|
|
450
|
-
**Agent responsibility:** When a Spell Loop run is triggered, the work item ID should be provided upfront. The agent stores it in `stories.json` top-level as `"workItemId"` and includes it in every commit and the PR description.
|
|
451
|
-
|
|
452
|
-
---
|
|
453
|
-
|
|
454
|
-
## PR Standards
|
|
455
|
-
|
|
456
|
-
All pull requests — whether created by humans or agents — must meet these requirements.
|
|
457
|
-
|
|
458
|
-
### 🛑 Agent-mandatory pre-PR guard
|
|
459
|
-
|
|
460
|
-
> **AGENTS: BEFORE running any PR-creation tool (`az repos pr create`, `gh pr create`, the `create_pull_request` MCP tool, or any equivalent), you MUST run `git fetch origin && git rebase origin/<target-branch>` and resolve any conflicts. This is not optional. Skipping this step is a governance violation.**
|
|
461
|
-
|
|
462
|
-
This rule applies **every single time**, regardless of:
|
|
463
|
-
|
|
464
|
-
- Which tool or CLI is used to open the PR (spell, raw `az`/`gh`, MCP tool, REST call, web UI-triggered automation).
|
|
465
|
-
- Whether the branch was recently created off `main` or has been open for hours.
|
|
466
|
-
- Whether the agent "thinks" no conflicts are likely — assumptions do not substitute for a rebase.
|
|
467
|
-
|
|
468
|
-
**Correct sequence for every agent-initiated PR:**
|
|
469
|
-
|
|
470
|
-
```bash
|
|
471
|
-
git fetch origin
|
|
472
|
-
git rebase origin/<target-branch> # resolve conflicts locally, never push a conflicted branch
|
|
473
|
-
git push --force-with-lease # only if the branch existed remotely before the rebase
|
|
474
|
-
# ...only THEN run the PR-creation tool of your choice
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
If a rebase produces conflicts the agent cannot confidently resolve, **STOP** and hand off to the human — do **not** open the PR and hope reviewers will sort it out. Pushing a branch that will produce a merge conflict on the target is a governance violation and wastes reviewer time.
|
|
478
|
-
|
|
479
|
-
The `spell-create-pull-request` spell encodes this check in Step 0, but the guard is on **the agent**, not on the spell. Bypassing the spell (by calling `az repos pr create` / `gh pr create` directly) does **not** bypass this rule.
|
|
480
|
-
|
|
481
|
-
See also: [Agent Workflow — Sync with main before opening a PR](#agent-workflow) below.
|
|
482
|
-
|
|
483
|
-
### PR Requirements
|
|
484
|
-
|
|
485
|
-
| Requirement | Details |
|
|
486
|
-
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
487
|
-
| **Work item link** | Optional. Linking is encouraged for traceability but enforce it only if your branch policy requires it. |
|
|
488
|
-
| **Title format** | Conventional Commits format: `type(scope): description` |
|
|
489
|
-
| **Description** | Must include: summary of changes, rationale, verification steps, and a linked work item ID if applicable |
|
|
490
|
-
| **Pre-PR sync** | **Mandatory rebase on latest `origin/<target>` before pushing.** See [🛑 Agent-mandatory pre-PR guard](#-agent-mandatory-pre-pr-guard) above — this applies even when opening PRs via raw `az repos pr create` / `gh pr create` / MCP tools. |
|
|
491
|
-
| **Branch cleanup** | After merge, delete the source branch (local and remote). |
|
|
492
|
-
| **PR link format** | All PR references in agent output should be clickable markdown links to the PR, not a bare `PR #NNN`. |
|
|
493
|
-
|
|
494
|
-
### Agent PR Workflow
|
|
495
|
-
|
|
496
|
-
1. **Create a work item** (if one doesn't exist) using `spell-suggest-feature` or `spell-bug`.
|
|
497
|
-
2. **Open PR** with proper title, description, and work-item link.
|
|
498
|
-
3. **Notify the human** through your configured channel with: `[PR #{number}] {repo} — {title} (#{workItemId})`.
|
|
499
|
-
4. **Address review feedback** if a reviewer requests changes.
|
|
500
|
-
5. **After merge**, delete the branch (local + remote) and confirm cleanup.
|
|
501
|
-
|
|
502
|
-
### PR Hygiene
|
|
503
|
-
|
|
504
|
-
- `spell-open-session` checks for open PRs across all repos and reports them.
|
|
505
|
-
- PRs open >3 days are flagged as **stale** — the human is prompted to review or close.
|
|
506
|
-
- PRs open >7 days without activity are flagged for **closure** — the human decides.
|
|
507
|
-
- Abandoned PRs should be closed with a comment explaining why (e.g., "superseded by #{newPR}", "scope changed").
|
|
508
|
-
|
|
509
|
-
---
|
|
510
|
-
|
|
511
|
-
## Agent Attribution Model
|
|
512
|
-
|
|
513
|
-
Every commit must clearly identify **who produced the content** and **who approved/pushed it**.
|
|
514
|
-
|
|
515
|
-
### Author vs. Committer
|
|
516
|
-
|
|
517
|
-
| Field | Represents | Examples |
|
|
518
|
-
| -------------------------- | -------------------------------- | -------------------------------------------------------------------- |
|
|
519
|
-
| **Author** (`--author`) | Entity that produced the content | `{AGENT_NAME} <{AGENT_EMAIL}>`, `{OPERATOR_NAME} <{OPERATOR_EMAIL}>` |
|
|
520
|
-
| **Committer** (Git config) | Human who approved and pushed | Always the operator: `{OPERATOR_NAME} <{OPERATOR_EMAIL}>` |
|
|
521
|
-
|
|
522
|
-
- If **you** wrote the content: don't override author. Your global Git config is used.
|
|
523
|
-
- If an **agent** produced the content: use `--author` to set the agent's identity.
|
|
524
|
-
- If an **interactive AI tool** (Copilot, Claude in VS Code) produced the content: use the tool-level identity.
|
|
525
|
-
|
|
526
|
-
### Agent Email Convention
|
|
527
|
-
|
|
528
|
-
Give every agent/tool a stable email under a domain you control. Most hosts treat author email as metadata only — authentication uses the push credential (SSH key / PAT), not the author email.
|
|
529
|
-
|
|
530
|
-
**Format:** `[Persona Name] <[lowercase-persona]@{OPERATOR_DOMAIN}>`
|
|
531
|
-
|
|
532
|
-
Maintain a registry of the identities you use, for example:
|
|
533
|
-
|
|
534
|
-
| Identity | Email | Type | Role |
|
|
535
|
-
| --------------- | --------------------------- | ------------------------------- | -------------------------- |
|
|
536
|
-
| {OPERATOR_NAME} | `{OPERATOR_EMAIL}` | Human (owner) | — |
|
|
537
|
-
| {AGENT_NAME} | `{AGENT_EMAIL}` | Autonomous agent | Product Operations Manager |
|
|
538
|
-
| Merlin | `merlin@{OPERATOR_DOMAIN}` | Autonomous agent | CTO / Architecture Lead |
|
|
539
|
-
| Lafayette | `lafayette@{OPERATOR_DOMAIN}` | Autonomous agent | Full-Stack Developer |
|
|
540
|
-
| Copilot | `copilot@{OPERATOR_DOMAIN}` | GitHub Copilot | Tool |
|
|
541
|
-
| Claude | `claude@{OPERATOR_DOMAIN}` | Claude Code | Tool |
|
|
542
|
-
|
|
543
|
-
New agents are registered during onboarding.
|
|
544
|
-
|
|
545
|
-
### Required Commit Trailers (Agent Commits)
|
|
546
|
-
|
|
547
|
-
Agent-authored commits MUST include trailers in the commit message footer. Human commits MAY include them.
|
|
548
|
-
|
|
549
|
-
| Trailer | Required | Example |
|
|
550
|
-
| -------------- | ----------- | --------------------------------------------- |
|
|
551
|
-
| `Agent` | Yes | `kellar`, `copilot`, `claude` |
|
|
552
|
-
| `Model` | Yes | `claude-opus-4-20250918`, `gpt-4o` |
|
|
553
|
-
| `Provider` | Yes | `anthropic`, `openai` |
|
|
554
|
-
| `Role` | Recommended | `product-ops`, `developer`, `cto` |
|
|
555
|
-
| `Task-Type` | Optional | `docs`, `code`, `review`, `marketing` |
|
|
556
|
-
| `Approval` | Optional | `interactive`, `batch`, `post-review` |
|
|
557
|
-
| `Channel` | Optional | `chat`, `cli`, `editor` |
|
|
558
|
-
| `Risk-Class` | Optional | `low`, `medium`, `high` |
|
|
559
|
-
| `Request-ID` | Optional | `req-001` |
|
|
560
|
-
| `Session` | Optional | `session-01` |
|
|
561
|
-
| `Rollback-Ref` | Optional | path or commit to the pre-change state |
|
|
562
|
-
|
|
563
|
-
### Complete Examples
|
|
564
|
-
|
|
565
|
-
**Agent-authored commit ({AGENT_NAME}):**
|
|
566
|
-
|
|
567
|
-
```bash
|
|
568
|
-
git commit --author="{AGENT_NAME} <{AGENT_EMAIL}>" \
|
|
569
|
-
--trailer="Agent=kellar" \
|
|
570
|
-
--trailer="Model=<model-id>" \
|
|
571
|
-
--trailer="Provider=<provider>" \
|
|
572
|
-
--trailer="Role=product-ops" \
|
|
573
|
-
--trailer="Channel=chat" \
|
|
574
|
-
-m "feat(inventory): generate initial product catalog
|
|
575
|
-
|
|
576
|
-
Created 47 SKUs from the inventory spreadsheet."
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
**Copilot-assisted commit (Copilot in editor):**
|
|
580
|
-
|
|
581
|
-
```bash
|
|
582
|
-
git commit --author="Copilot <copilot@{OPERATOR_DOMAIN}>" \
|
|
583
|
-
--trailer="Agent=copilot" \
|
|
584
|
-
--trailer="Model=<model-id>" \
|
|
585
|
-
--trailer="Provider=<provider>" \
|
|
586
|
-
--trailer="Channel=editor" \
|
|
587
|
-
-m "docs(governance): add attribution model to git conventions"
|
|
588
|
-
```
|
|
589
|
-
|
|
590
|
-
**Human-authored commit (no overrides):**
|
|
591
|
-
|
|
592
|
-
```bash
|
|
593
|
-
git commit -m "docs(decisions): add ADR-028 agent attribution model"
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
### Querying Attribution
|
|
597
|
-
|
|
598
|
-
```bash
|
|
599
|
-
# All commits by {AGENT_NAME}
|
|
600
|
-
git log --author="{AGENT_NAME}" --oneline
|
|
601
|
-
|
|
602
|
-
# All commits by any agent (non-human)
|
|
603
|
-
git log --author="@{OPERATOR_DOMAIN}" --oneline
|
|
604
|
-
|
|
605
|
-
# All human-only commits
|
|
606
|
-
git log --author="{OPERATOR_EMAIL}" --oneline
|
|
607
|
-
|
|
608
|
-
# Extract trailers
|
|
609
|
-
git log -10 --format='%H %s%n%(trailers:key=Agent,key=Model,key=Provider)%n'
|
|
610
|
-
|
|
611
|
-
# Count commits per agent
|
|
612
|
-
git log --all --format='%(trailers:key=Agent,valueonly)' | sort | uniq -c | sort -rn
|
|
613
|
-
```
|
|
614
|
-
|
|
615
|
-
---
|
|
616
|
-
|
|
617
|
-
## Tools to Help
|
|
618
|
-
|
|
619
|
-
### Automated Commit Generation
|
|
620
|
-
|
|
621
|
-
Use `spell-commit-work` prompt during sessions:
|
|
622
|
-
|
|
623
|
-
1. Type `@spell-commit-work` in chat
|
|
624
|
-
2. Prompt analyzes `git status` and conversation context
|
|
625
|
-
3. Generates Conventional Commits message
|
|
626
|
-
4. Shows for approval
|
|
627
|
-
5. Executes `git add -A && git commit` if approved
|
|
628
|
-
|
|
629
|
-
### Manual Commit Template
|
|
630
|
-
|
|
631
|
-
If committing manually, use this mental checklist:
|
|
632
|
-
|
|
633
|
-
```
|
|
634
|
-
[ ] Type correct? (feat, fix, docs, chore, refactor, etc.)
|
|
635
|
-
[ ] Scope correct? (prompts, agents, security, etc.)
|
|
636
|
-
[ ] Imperative mood? ("add" not "added")
|
|
637
|
-
[ ] Lowercase start, no period?
|
|
638
|
-
[ ] Under 72 chars?
|
|
639
|
-
[ ] Body needed for context?
|
|
640
|
-
```
|
|
641
|
-
|
|
642
|
-
### Validating Format
|
|
643
|
-
|
|
644
|
-
Quick regex to check format (optional — not enforced by hooks):
|
|
645
|
-
|
|
646
|
-
```bash
|
|
647
|
-
# Valid: type(scope): description
|
|
648
|
-
^(feat|fix|docs|refactor|chore|test|perf|ci|style|revert)(\([a-z-]+\))?:\s.{1,72}$
|
|
649
|
-
```
|
|
650
|
-
|
|
651
|
-
---
|
|
652
|
-
|
|
653
|
-
## Examples from This Repo
|
|
654
|
-
|
|
655
|
-
**Feature addition:**
|
|
656
|
-
|
|
657
|
-
```
|
|
658
|
-
feat(prompts): add spell-commit-work for checkpointing
|
|
659
|
-
|
|
660
|
-
Enables mid-session commits without waiting for spell-close-session.
|
|
661
|
-
Generates Conventional Commits messages with approval workflow.
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
**Documentation update:**
|
|
665
|
-
|
|
666
|
-
```
|
|
667
|
-
docs(decisions): add table of contents to DECISIONS.md
|
|
668
|
-
```
|
|
669
|
-
|
|
670
|
-
**Bug fix:**
|
|
671
|
-
|
|
672
|
-
```
|
|
673
|
-
fix(auth): restore token SecretRef after onboarding
|
|
674
|
-
|
|
675
|
-
Onboarding wizard overwrote auth config with a plaintext token.
|
|
676
|
-
Restored the SecretRef and restarted the service.
|
|
677
|
-
```
|
|
678
|
-
|
|
679
|
-
**Refactor:**
|
|
680
|
-
|
|
681
|
-
```
|
|
682
|
-
refactor(prompts): rename to spell- prefix
|
|
683
|
-
|
|
684
|
-
- continue-arcane.prompt.md → spell-open-session.prompt.md
|
|
685
|
-
- session-close.prompt.md → spell-close-session.prompt.md
|
|
686
|
-
- doc-drift-check.prompt.md → spell-check-drift.prompt.md
|
|
687
|
-
- new-business-bootstrap.prompt.md → spell-bootstrap-business.prompt.md
|
|
688
|
-
|
|
689
|
-
Implements ADR-019 spell- naming convention.
|
|
690
|
-
```
|
|
691
|
-
|
|
692
|
-
**Chore:**
|
|
693
|
-
|
|
694
|
-
```
|
|
695
|
-
chore(repo): add root .gitignore
|
|
696
|
-
|
|
697
|
-
Excludes .env, *.log, node_modules/, .obsidian/, OS artifacts.
|
|
698
|
-
```
|
|
699
|
-
|
|
700
|
-
---
|
|
701
|
-
|
|
702
|
-
## What NOT to Commit
|
|
703
|
-
|
|
704
|
-
Enforced by root `.gitignore`:
|
|
705
|
-
|
|
706
|
-
- Secrets (`.env`, `*.pem`, `*.key`)
|
|
707
|
-
- Logs (`*.log`)
|
|
708
|
-
- Dependencies (`node_modules/`, `vendor/`)
|
|
709
|
-
- Build artifacts (`dist/`, `build/`, `*.pyc`)
|
|
710
|
-
- OS artifacts (`.DS_Store`, `Thumbs.db`, `desktop.ini`)
|
|
711
|
-
- Editor state (`.vscode/settings.json`, `.idea/`)
|
|
712
|
-
- Obsidian vault state (`.obsidian/`)
|
|
713
|
-
|
|
714
|
-
See [.gitignore](../.gitignore) for full list.
|
|
715
|
-
|
|
716
|
-
---
|
|
717
|
-
|
|
718
|
-
## When to Commit
|
|
719
|
-
|
|
720
|
-
**During active work (use `spell-commit-work`):**
|
|
721
|
-
|
|
722
|
-
- Completed a discrete task (added ADR, renamed files, fixed bug)
|
|
723
|
-
- About to switch context to a different task
|
|
724
|
-
- Reached a checkpoint before taking a break
|
|
725
|
-
|
|
726
|
-
**At session close (use `spell-close-session`):**
|
|
727
|
-
|
|
728
|
-
- Generated journal entry, updated TODO.md
|
|
729
|
-
- Finalized session documentation
|
|
730
|
-
- Ready to hand off or resume later
|
|
731
|
-
|
|
732
|
-
**Commit early, commit often.** Small commits with clear messages are easier to review, revert, and understand than giant "end of day" dumps.
|
|
733
|
-
|
|
734
|
-
---
|
|
735
|
-
|
|
736
|
-
## Troubleshooting Notes
|
|
737
|
-
|
|
738
|
-
### Git command unavailable in interactive PowerShell terminal
|
|
739
|
-
|
|
740
|
-
**Symptom:** Running `git` returns "The term 'git' is not recognized" even though recent command output still includes Git diff content.
|
|
741
|
-
|
|
742
|
-
**Cause:** Terminal PATH resolution can differ between integrated shell contexts, especially when commands are piped or executed in chained command blocks.
|
|
743
|
-
|
|
744
|
-
**Fix:** Use the explicit executable path:
|
|
745
|
-
|
|
746
|
-
```powershell
|
|
747
|
-
& "C:\Program Files\Git\cmd\git.exe" <subcommand>
|
|
748
|
-
```
|
|
749
|
-
|
|
750
|
-
**Verify:** Run:
|
|
751
|
-
|
|
752
|
-
```powershell
|
|
753
|
-
& "C:\Program Files\Git\cmd\git.exe" --version
|
|
754
|
-
& "C:\Program Files\Git\cmd\git.exe" status --short
|
|
755
|
-
```
|
|
756
|
-
|
|
757
|
-
Both commands should return successfully.
|
|
758
|
-
|
|
759
|
-
**Prevention:** Prefer explicit git path in scripted close-session and commit workflows when shell behavior is inconsistent.
|
|
1
|
+
---
|
|
2
|
+
title: Git Conventions — Commit Format and Branching Model
|
|
3
|
+
audience: both
|
|
4
|
+
status: active
|
|
5
|
+
distributable: true
|
|
6
|
+
last_updated: 2026-07-05
|
|
7
|
+
tags: [git, conventional-commits, workflow, standards, attribution]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Git Conventions
|
|
11
|
+
|
|
12
|
+
How to structure commits, branches, and pull requests for this repository.
|
|
13
|
+
|
|
14
|
+
## Executive Summary
|
|
15
|
+
|
|
16
|
+
- This repo uses Conventional Commits format for all commit messages — industry standard, tool-portable, human-readable.
|
|
17
|
+
- Trunk-based development with short-lived feature branches keeps history clean and reduces merge conflicts.
|
|
18
|
+
- No custom git hooks — conventions work on any machine without setup, no fragile tooling dependencies.
|
|
19
|
+
- Use `spell-commit-work` prompt during sessions to automate commit message generation in the correct format.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Conventional Commits Format
|
|
24
|
+
|
|
25
|
+
All commit messages follow the [Conventional Commits](https://www.conventionalcommits.org/) standard.
|
|
26
|
+
|
|
27
|
+
### Basic Structure
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
type(scope): short description
|
|
31
|
+
|
|
32
|
+
[optional body with details]
|
|
33
|
+
|
|
34
|
+
[optional footer with breaking changes or issue references]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Commit Types
|
|
38
|
+
|
|
39
|
+
| Type | When to Use | Example |
|
|
40
|
+
| ---------- | ----------------------------------------------- | -------------------------------------------------------------- |
|
|
41
|
+
| `feat` | New feature or capability | `feat(prompts): add spell-commit-work for checkpointing` |
|
|
42
|
+
| `fix` | Bug fix | `fix(auth): restore token validation after refactor` |
|
|
43
|
+
| `docs` | Documentation only | `docs(decisions): add table of contents to DECISIONS.md` |
|
|
44
|
+
| `refactor` | Code/structure change, no behavior change | `refactor(playbooks): reorganize setup steps` |
|
|
45
|
+
| `chore` | Maintenance, deps, tooling, cleanup | `chore(deps): bump <dependency> to <version>` |
|
|
46
|
+
| `test` | Adding or fixing tests | `test(security): add token-expiry test` |
|
|
47
|
+
| `perf` | Performance improvements | `perf(api): reduce cold-start latency` |
|
|
48
|
+
| `ci` | CI/CD pipeline changes | `ci(azure): add DevOps pipeline for repo sync` |
|
|
49
|
+
| `style` | Code formatting, whitespace (rare in this repo) | `style(markdown): fix inconsistent heading levels` |
|
|
50
|
+
| `revert` | Revert a previous commit | `revert: undo feat(prompts): add spell-commit-work` |
|
|
51
|
+
|
|
52
|
+
### Scopes
|
|
53
|
+
|
|
54
|
+
Scope indicates what part of the repo changed. Use singular, lowercase.
|
|
55
|
+
|
|
56
|
+
| Scope | Area |
|
|
57
|
+
| ---------------- | ------------------------------------------------- |
|
|
58
|
+
| `prompts` | `.github/prompts/*.prompt.md` |
|
|
59
|
+
| `agents` | `agents/` directory, agent config, policies |
|
|
60
|
+
| `security` | `security/` directory, threat model, hardening |
|
|
61
|
+
| `infrastructure` | `infrastructure/` directory, hardware, OS setup |
|
|
62
|
+
| `decisions` | `DECISIONS.md` updates |
|
|
63
|
+
| `journal` | `journal/` entries |
|
|
64
|
+
| `governance` | `governance/` directory, process docs |
|
|
65
|
+
| `playbooks` | `playbooks/` directory |
|
|
66
|
+
| `business` | `ventures/` directory |
|
|
67
|
+
| `ai-context` | `ai-context/` directory |
|
|
68
|
+
| `repo` | Root-level files (README, TODO, .gitignore, etc.) |
|
|
69
|
+
| `naming` | `naming-conventions.md` |
|
|
70
|
+
|
|
71
|
+
Multiple scopes? Pick the primary one. If everything changed, use `repo` or omit the scope.
|
|
72
|
+
|
|
73
|
+
### Short Description Rules
|
|
74
|
+
|
|
75
|
+
- **Imperative mood:** "add", "fix", "update", "remove" (not "added", "fixes", "updating")
|
|
76
|
+
- **Lowercase:** start with lowercase letter
|
|
77
|
+
- **No period:** don't end with `.`
|
|
78
|
+
- **72 characters max:** keeps `git log --oneline` readable
|
|
79
|
+
|
|
80
|
+
**Good examples:**
|
|
81
|
+
|
|
82
|
+
- `add spell-commit-work prompt`
|
|
83
|
+
- `fix gateway auth regression after onboarding`
|
|
84
|
+
- `update table of contents in DECISIONS.md`
|
|
85
|
+
|
|
86
|
+
**Bad examples:**
|
|
87
|
+
|
|
88
|
+
- `Added spell-commit-work prompt.` (past tense, period)
|
|
89
|
+
- `Fix gateway authentication regression that occurred after running the onboarding wizard` (too long, 84 chars)
|
|
90
|
+
|
|
91
|
+
### Optional Body
|
|
92
|
+
|
|
93
|
+
Include a body when:
|
|
94
|
+
|
|
95
|
+
- The short description doesn't explain _why_
|
|
96
|
+
- Multiple related changes need enumeration
|
|
97
|
+
- ADR or file references add value
|
|
98
|
+
- Future readers need context
|
|
99
|
+
|
|
100
|
+
**Format:**
|
|
101
|
+
|
|
102
|
+
- Blank line after the short description
|
|
103
|
+
- Bullet list or paragraphs
|
|
104
|
+
- Wrap at 72 characters per line
|
|
105
|
+
- Reference ADRs, files, or issues
|
|
106
|
+
|
|
107
|
+
**Example:**
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
feat(prompts): add spell-commit-work for session checkpoints
|
|
111
|
+
|
|
112
|
+
Enables committing work-in-progress during active sessions without
|
|
113
|
+
waiting for spell-close-session. Generates Conventional Commits format
|
|
114
|
+
messages with proper type and scope.
|
|
115
|
+
|
|
116
|
+
Implements ADR-019 spell- naming convention.
|
|
117
|
+
|
|
118
|
+
Changes:
|
|
119
|
+
- Created .github/prompts/spell-commit-work.prompt.md
|
|
120
|
+
- Created governance/git-conventions.md as reference doc
|
|
121
|
+
- Updated TODO.md to mark git conventions doc complete
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Optional Footer
|
|
125
|
+
|
|
126
|
+
Use for:
|
|
127
|
+
|
|
128
|
+
- **Breaking changes:** `BREAKING CHANGE: removed support for plaintext token auth`
|
|
129
|
+
- **Issue/ticket references:** `Closes #535` or `Fixes #127`
|
|
130
|
+
|
|
131
|
+
Most commits in this repo won't need footers.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Atomic Commits
|
|
136
|
+
|
|
137
|
+
Each commit should be a **single logical change** — one coherent unit that can be understood, reviewed, reverted, or cherry-picked on its own.
|
|
138
|
+
|
|
139
|
+
### The Rule
|
|
140
|
+
|
|
141
|
+
> **One commit = one purpose.** If you can't describe the commit in a single short description without "and", it's probably two commits.
|
|
142
|
+
|
|
143
|
+
### When to Split
|
|
144
|
+
|
|
145
|
+
| Situation | Action |
|
|
146
|
+
| -------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
147
|
+
| New governance doc + updates to 3 referencing docs | One commit — the doc and its cross-references form one logical unit |
|
|
148
|
+
| New feature + unrelated typo fix | Two commits — the typo fix is a separate `fix` or `docs` commit |
|
|
149
|
+
| Refactor + behavior change | Two commits — refactor first (`refactor`), then behavior change (`feat` or `fix`) |
|
|
150
|
+
| Multiple ADRs decided independently | One commit per ADR, each with its related doc updates |
|
|
151
|
+
| Config change + documentation of that change | One commit — the config and its docs are one logical unit |
|
|
152
|
+
|
|
153
|
+
### When to Combine
|
|
154
|
+
|
|
155
|
+
Not every file change needs its own commit. **Group changes that only make sense together:**
|
|
156
|
+
|
|
157
|
+
- A new spell prompt + updates to the methodology doc, CLAUDE.md, copilot-instructions.md, and DECISIONS.md that reference it = **one commit** (the spell and its integration are one feature)
|
|
158
|
+
- A playbook + its template files = **one commit**
|
|
159
|
+
- A security fix + its threat model update = **one commit**
|
|
160
|
+
|
|
161
|
+
The test: if you reverted just one of the commits, would the repo be in an inconsistent state? If yes, they belong together.
|
|
162
|
+
|
|
163
|
+
### Staging Strategy
|
|
164
|
+
|
|
165
|
+
Use `git add -p` or selective staging to separate unrelated changes that were edited in the same session:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Stage only the files related to one logical change
|
|
169
|
+
git add governance/new-standard.md DECISIONS.md CLAUDE.md
|
|
170
|
+
git commit -m "docs(governance): add new-standard with ADR-053"
|
|
171
|
+
|
|
172
|
+
# Then stage the unrelated fix
|
|
173
|
+
git add README.md
|
|
174
|
+
git commit -m "fix(repo): correct broken link in README"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Branch Discipline
|
|
180
|
+
|
|
181
|
+
**Trunk-based development** with mandatory topic branches for all actors. No one — human or agent — commits directly to main.
|
|
182
|
+
|
|
183
|
+
### The Rule
|
|
184
|
+
|
|
185
|
+
> **Main is an integration-only branch.** It receives merges, never direct commits. All work happens on topic branches.
|
|
186
|
+
|
|
187
|
+
This applies to:
|
|
188
|
+
|
|
189
|
+
- Humans editing on any machine
|
|
190
|
+
- Autonomous agents working independently
|
|
191
|
+
- Interactive AI tools (Copilot, Claude Code, Codex, or any other client)
|
|
192
|
+
|
|
193
|
+
### Branch Naming
|
|
194
|
+
|
|
195
|
+
**Humans:**
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
type/short-description
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Session branches (interactive tools — Copilot, Claude Code, etc.):**
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
sessions/YYYY-MM-DD-topic-slug
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Create the session branch as the **first action** of any session, before any file edits or commits. All session commits land on this branch. At close, push and open a PR. After merge, return to `main`.
|
|
208
|
+
|
|
209
|
+
**Examples:**
|
|
210
|
+
|
|
211
|
+
- `sessions/2025-11-04-widget-app-implementation` (interactive session)
|
|
212
|
+
- `sessions/2025-11-12-payment-webhook-fix` (interactive session)
|
|
213
|
+
|
|
214
|
+
**Session branch policy (required):**
|
|
215
|
+
|
|
216
|
+
- Session branches must be deterministic, human-readable, and derived from the active task title.
|
|
217
|
+
- Default format for new interactive sessions: `sessions/YYYY-MM-DD-<topic-slug>`.
|
|
218
|
+
- Random adjective-noun branches (for example, `ideal-disco`) are non-compliant and must be renamed.
|
|
219
|
+
- If a non-compliant branch was already pushed, migrate it safely:
|
|
220
|
+
1. `git branch -m <old> <new>`
|
|
221
|
+
2. `git push -u origin <new>`
|
|
222
|
+
3. `git push origin --delete <old>` (skip this if an active PR still depends on `<old>`).
|
|
223
|
+
|
|
224
|
+
**Agents:**
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
{agent-slug}/type/short-description
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
The agent slug prefix makes branch ownership obvious in `git branch -r` output and prevents naming collisions between agents.
|
|
231
|
+
|
|
232
|
+
**Examples:**
|
|
233
|
+
|
|
234
|
+
- `docs/readme-update` (human)
|
|
235
|
+
- `feat/spell-commit-work` (human)
|
|
236
|
+
- `fix/auth-token-regression` (human)
|
|
237
|
+
- `lafayette/feat/api-endpoint` (agent — Lafayette)
|
|
238
|
+
- `merlin/docs/architecture-update` (agent — Merlin)
|
|
239
|
+
- `lince/fix/test-regression` (agent — Lince)
|
|
240
|
+
|
|
241
|
+
### Human Workflow
|
|
242
|
+
|
|
243
|
+
1. **Start a topic branch** before any work:
|
|
244
|
+
```bash
|
|
245
|
+
git fetch origin
|
|
246
|
+
git checkout -b docs/my-topic origin/main
|
|
247
|
+
```
|
|
248
|
+
2. **Commit often** using Conventional Commits format.
|
|
249
|
+
3. **Push your branch** (especially important for multi-machine work):
|
|
250
|
+
```bash
|
|
251
|
+
git push origin docs/my-topic
|
|
252
|
+
```
|
|
253
|
+
4. **Merge to main via fast-forward** when done:
|
|
254
|
+
```bash
|
|
255
|
+
git checkout main
|
|
256
|
+
git pull origin main
|
|
257
|
+
git merge --ff-only docs/my-topic
|
|
258
|
+
git push origin main
|
|
259
|
+
git branch -d docs/my-topic
|
|
260
|
+
git push origin --delete docs/my-topic
|
|
261
|
+
```
|
|
262
|
+
5. **If ff-only fails** (someone else merged first), rebase and retry:
|
|
263
|
+
```bash
|
|
264
|
+
git checkout docs/my-topic
|
|
265
|
+
git rebase main
|
|
266
|
+
git checkout main
|
|
267
|
+
git merge --ff-only docs/my-topic
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Agent Workflow
|
|
271
|
+
|
|
272
|
+
1. **Create a prefixed topic branch:**
|
|
273
|
+
```bash
|
|
274
|
+
git checkout -b lafayette/feat/api-endpoint origin/main
|
|
275
|
+
```
|
|
276
|
+
2. **Commit with proper attribution** (author identity + required trailers).
|
|
277
|
+
3. **Sync with main before opening a PR** — always rebase on the latest origin/main before pushing
|
|
278
|
+
or creating a PR, regardless of whether conflicts are expected. **This is mandatory for every
|
|
279
|
+
agent-initiated PR — see the [🛑 Agent-mandatory pre-PR guard](#-agent-mandatory-pre-pr-guard)
|
|
280
|
+
callout below. It applies even when using raw `az repos pr create` / `gh pr create` / MCP tools
|
|
281
|
+
instead of the `spell-create-pull-request` spell.**
|
|
282
|
+
```bash
|
|
283
|
+
git fetch origin
|
|
284
|
+
git rebase origin/main
|
|
285
|
+
# If conflicts arise: resolve → git add → git rebase --continue
|
|
286
|
+
```
|
|
287
|
+
This ensures the PR diff is clean, the CI runs against current main, and reviewers see no
|
|
288
|
+
stale divergence. Resolve conflicts locally — never push a branch with known merge conflicts.
|
|
289
|
+
4. **Push the branch to origin** (after rebase).
|
|
290
|
+
5. **Merge or queue for review** based on power level:
|
|
291
|
+
- **Magus+ agents:** self-merge via `git merge --ff-only`, then push main
|
|
292
|
+
- **Below Magus:** push the branch, report branch name, and queue for human merge
|
|
293
|
+
6. **Delete the branch** after merge.
|
|
294
|
+
|
|
295
|
+
### Multi-Machine Workflow
|
|
296
|
+
|
|
297
|
+
When working across machines, topic branches are the coordination mechanism:
|
|
298
|
+
|
|
299
|
+
- **Starting work on any machine:** `git fetch && git checkout -b type/topic origin/main`
|
|
300
|
+
- **Continuing work started on another machine:** `git fetch && git checkout type/topic && git pull`
|
|
301
|
+
- **Push branches frequently** so work is available across machines
|
|
302
|
+
- Main stays clean — only receives merges from completed branches
|
|
303
|
+
|
|
304
|
+
### Merge Strategy by Repo Risk
|
|
305
|
+
|
|
306
|
+
| Repo Type | Examples | Merge Method | PR Required? |
|
|
307
|
+
| -------------- | ------------------------------------------- | ------------ | ------------ |
|
|
308
|
+
| **Docs repos** | docs hub, prototypes | PR | Yes |
|
|
309
|
+
| **Code repos** | application, API, storefront repos | PR | Yes |
|
|
310
|
+
|
|
311
|
+
- **All repos have main branch protection.** Direct pushes to main are rejected. All changes must go through a PR.
|
|
312
|
+
|
|
313
|
+
#### Azure DevOps PR Merge Type
|
|
314
|
+
|
|
315
|
+
When completing a PR in Azure DevOps, allow only these merge strategies by default:
|
|
316
|
+
|
|
317
|
+
- **Merge (no fast forward)**, or
|
|
318
|
+
- **Rebase and fast-forward**
|
|
319
|
+
|
|
320
|
+
Do **not** use Squash commit.
|
|
321
|
+
|
|
322
|
+
| Merge Type | Use? | Why |
|
|
323
|
+
| --------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
324
|
+
| **Rebase and fast-forward** | **Yes** | Preserves linear history while keeping individual commits and attribution trailers intact. |
|
|
325
|
+
| **Merge (no fast forward)** | **Yes** | Preserves full branch context and review traceability where explicit merge commits are preferred. |
|
|
326
|
+
| Squash commit | **No** | Collapses commit history and breaks per-commit attribution/analytics and granular rollback. |
|
|
327
|
+
| Semi-linear merge | No | Adds unnecessary merge commits on top of rebased commits; avoid by default. |
|
|
328
|
+
|
|
329
|
+
### Commit Governance
|
|
330
|
+
|
|
331
|
+
Commit execution rights depend on the interaction context:
|
|
332
|
+
|
|
333
|
+
| Context | Commit Behavior | Rationale |
|
|
334
|
+
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
335
|
+
| **Interactive session** (Copilot, Claude in VS Code, Claude Code) | **Must ask human** before committing. Stage changes, present proposed message, wait for approval. | Human is actively collaborating; commits are a shared decision. |
|
|
336
|
+
| **Autonomous agent** at Magus+ power level | May self-commit and self-merge within approved scope (per your power-level policy). Must use proper author/trailers. | Agent is operating independently with delegated authority. |
|
|
337
|
+
| **Autonomous agent** below Magus | Must commit to topic branch and queue merge for human review. | Insufficient autonomy level for unsupervised merges to main. |
|
|
338
|
+
|
|
339
|
+
**Interactive session rule applies to ALL interactive tools, regardless of agent identity.** Even a high-power-level agent cannot auto-commit when operating through an interactive editor session — the human is present and must approve.
|
|
340
|
+
|
|
341
|
+
### Post-Merge Cleanup
|
|
342
|
+
|
|
343
|
+
After every PR merge or local fast-forward merge, **always return to main and prune the branch**. Failing to do this leaves you on a stale branch where new work gets committed to the wrong place or stays unpushed.
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
# After PR merges on remote:
|
|
347
|
+
git checkout main
|
|
348
|
+
git pull origin main
|
|
349
|
+
git branch -d type/old-topic # delete local branch
|
|
350
|
+
git push origin --delete type/old-topic # delete remote branch (safety net; ignore 'does not exist' errors if already auto-deleted)
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
This applies to all actors — humans, interactive tools (Copilot, Claude), and autonomous agents. The `spell-commit-work` and `spell-close-session` prompts enforce this check.
|
|
354
|
+
|
|
355
|
+
### ADO PR Lifecycle — Complete Command Reference
|
|
356
|
+
|
|
357
|
+
When working in an Azure DevOps repo with branch protection (direct push to `main` rejected), use this exact sequence. Several shortcut tools have known reliability issues on Windows — use the commands below instead.
|
|
358
|
+
|
|
359
|
+
```powershell
|
|
360
|
+
# 1. Push your topic branch
|
|
361
|
+
git push origin <branch>
|
|
362
|
+
|
|
363
|
+
# 2. Create the PR
|
|
364
|
+
az repos pr create `
|
|
365
|
+
--repository <repo> `
|
|
366
|
+
--org https://dev.azure.com/<org> `
|
|
367
|
+
--source-branch <branch> `
|
|
368
|
+
--target-branch main `
|
|
369
|
+
--title "type(scope): description" `
|
|
370
|
+
--description "Body..."
|
|
371
|
+
# Capture pullRequestId from the JSON output
|
|
372
|
+
|
|
373
|
+
# 3. Assign reviewer (default to operator identity; idempotent)
|
|
374
|
+
# Resolve reviewer (example: git config user.email), then:
|
|
375
|
+
az repos pr reviewer list --id <PR_ID> --org https://dev.azure.com/<org>
|
|
376
|
+
# If reviewer is missing, add:
|
|
377
|
+
az repos pr reviewer add --id <PR_ID> --org https://dev.azure.com/<org> --reviewer "<email>"
|
|
378
|
+
|
|
379
|
+
# 4. Approve via CLI first (self-approve only when policy allows)
|
|
380
|
+
az repos pr set-vote --id <PR_ID> --org https://dev.azure.com/<org> --vote approve
|
|
381
|
+
# If policy blocks self-approval, record and require second human approval.
|
|
382
|
+
|
|
383
|
+
# 5. REST fallback only if CLI vote command fails
|
|
384
|
+
$bearer = az account get-access-token --resource "499b84ac-1321-427f-aa17-267ca6975798" --query accessToken -o tsv
|
|
385
|
+
$headers = @{ Authorization = "Bearer $bearer"; "Content-Type" = "application/json" }
|
|
386
|
+
Invoke-RestMethod -Method PUT `
|
|
387
|
+
-Uri "https://dev.azure.com/<org>/<project>/_apis/git/repositories/<repo>/pullRequests/<PR_ID>/reviewers/<AAD-id>?api-version=7.1" `
|
|
388
|
+
-Headers $headers -Body '{"vote": 10}'
|
|
389
|
+
|
|
390
|
+
# 6. Verify vote registered (expect vote: 10 unless policy blocks self-approval)
|
|
391
|
+
az repos pr reviewer list --id <PR_ID> --org https://dev.azure.com/<org>
|
|
392
|
+
|
|
393
|
+
# 7. Complete (merge) the PR with source-branch deletion and squash disabled
|
|
394
|
+
# Allowed merge strategies: Merge (no fast forward) or Rebase+fast-forward
|
|
395
|
+
az repos pr update --id <PR_ID> --org https://dev.azure.com/<org> --status completed --delete-source-branch true --squash false
|
|
396
|
+
|
|
397
|
+
# 8. Pull merge commit and clean up (worktree-safe)
|
|
398
|
+
git checkout main
|
|
399
|
+
git pull origin main
|
|
400
|
+
git branch -d <branch> # delete local branch (skip if branch is attached to an active worktree)
|
|
401
|
+
git push origin --delete <branch> # delete remote branch (safety net — --delete-source-branch true usually handles this; ignore 'does not exist' errors)
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
**Known issues:**
|
|
405
|
+
|
|
406
|
+
| Issue | Symptom | Fix |
|
|
407
|
+
| --------------------------------------------------------------- | ----------------------------------- | ------------------------------------------ |
|
|
408
|
+
| Reviewer already assigned | `reviewer add` returns already exists | Treat as idempotent success and continue |
|
|
409
|
+
| `az repos pr set-vote` succeeds but approval still blocked | Policy requires additional approver | Confirm vote state, then request second human approval |
|
|
410
|
+
| MCP `vote_pull_request` returns "Success" but vote stays 0 | `reviewer list` shows `vote: 0` | Use `Invoke-RestMethod` step 5 above |
|
|
411
|
+
| `az rest --body '{"vote":10}'` fails | Shell parsing error on Windows | Use `Invoke-RestMethod` |
|
|
412
|
+
| `az repos pr update --status completed` fails with policy error | "Needs 1 approval" | Verify `vote: 10` first, then retry |
|
|
413
|
+
| MCP `create_pull_request` returns no data | No PR ID/URL in response | Fall back to `az repos pr create` |
|
|
414
|
+
| `gh pr create` not found | `gh` CLI not installed | Use `az repos pr create` |
|
|
415
|
+
| `creatorVoteCounts` is false on branch policy | Vote registers but PR still blocked | A second human must approve via ADO web UI |
|
|
416
|
+
| `az repos pr update --status completed` returns `status: active` without error | PR silently not merged | Add `--squash false` to the command; the flag triggers the merge path correctly |
|
|
417
|
+
| `git branch -d <branch>` fails after merge | Branch is attached to a worktree | Skip local delete; run remote delete + prune |
|
|
418
|
+
| `git push origin --delete <branch>` fails with missing ref | Branch already deleted remotely | Treat as non-fatal and continue |
|
|
419
|
+
|
|
420
|
+
### Branch Lifecycle
|
|
421
|
+
|
|
422
|
+
- **Short-lived:** hours to a few days, not weeks
|
|
423
|
+
- **Delete after merge:** don't let branches pile up — delete local and remote
|
|
424
|
+
- **No long-running feature branches:** they create merge hell
|
|
425
|
+
- **Stale branch cleanup:** branches older than 7 days or already merged should be pruned
|
|
426
|
+
- **Scheduled hygiene:** any scheduled auto-pull job should also run `git fetch --prune` to remove stale remote-tracking branches. Locally merged branches are pruned on the next session or scheduled cycle.
|
|
427
|
+
- **Workspace isolation:** agents must never create, switch, or modify branches in a human's primary workspace. All agent work happens in their own isolated clones.
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Ticket Tagging
|
|
432
|
+
|
|
433
|
+
If your tracker links commits to work items by ID (Azure Boards, GitHub Issues, Jira, etc.), tag commits so the linkage happens automatically.
|
|
434
|
+
|
|
435
|
+
**Recommended for Spell Loop PRs:**
|
|
436
|
+
|
|
437
|
+
- Create or identify a work item **before** starting spell-plan
|
|
438
|
+
- Include the work item ID in the PR description and link it before merging
|
|
439
|
+
- If your branch policy requires a linked work item, PRs without one will be blocked
|
|
440
|
+
|
|
441
|
+
**Commit prefix format:**
|
|
442
|
+
|
|
443
|
+
```
|
|
444
|
+
#506 test(api): add xUnit test project
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
- Prefix commits with `#WORKITEM` to enable automatic commit → work item linking
|
|
448
|
+
- The orchestrating agent should include the work item ID in the initial spell-plan message and carry it through to ship
|
|
449
|
+
|
|
450
|
+
**Agent responsibility:** When a Spell Loop run is triggered, the work item ID should be provided upfront. The agent stores it in `stories.json` top-level as `"workItemId"` and includes it in every commit and the PR description.
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## PR Standards
|
|
455
|
+
|
|
456
|
+
All pull requests — whether created by humans or agents — must meet these requirements.
|
|
457
|
+
|
|
458
|
+
### 🛑 Agent-mandatory pre-PR guard
|
|
459
|
+
|
|
460
|
+
> **AGENTS: BEFORE running any PR-creation tool (`az repos pr create`, `gh pr create`, the `create_pull_request` MCP tool, or any equivalent), you MUST run `git fetch origin && git rebase origin/<target-branch>` and resolve any conflicts. This is not optional. Skipping this step is a governance violation.**
|
|
461
|
+
|
|
462
|
+
This rule applies **every single time**, regardless of:
|
|
463
|
+
|
|
464
|
+
- Which tool or CLI is used to open the PR (spell, raw `az`/`gh`, MCP tool, REST call, web UI-triggered automation).
|
|
465
|
+
- Whether the branch was recently created off `main` or has been open for hours.
|
|
466
|
+
- Whether the agent "thinks" no conflicts are likely — assumptions do not substitute for a rebase.
|
|
467
|
+
|
|
468
|
+
**Correct sequence for every agent-initiated PR:**
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
git fetch origin
|
|
472
|
+
git rebase origin/<target-branch> # resolve conflicts locally, never push a conflicted branch
|
|
473
|
+
git push --force-with-lease # only if the branch existed remotely before the rebase
|
|
474
|
+
# ...only THEN run the PR-creation tool of your choice
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
If a rebase produces conflicts the agent cannot confidently resolve, **STOP** and hand off to the human — do **not** open the PR and hope reviewers will sort it out. Pushing a branch that will produce a merge conflict on the target is a governance violation and wastes reviewer time.
|
|
478
|
+
|
|
479
|
+
The `spell-create-pull-request` spell encodes this check in Step 0, but the guard is on **the agent**, not on the spell. Bypassing the spell (by calling `az repos pr create` / `gh pr create` directly) does **not** bypass this rule.
|
|
480
|
+
|
|
481
|
+
See also: [Agent Workflow — Sync with main before opening a PR](#agent-workflow) below.
|
|
482
|
+
|
|
483
|
+
### PR Requirements
|
|
484
|
+
|
|
485
|
+
| Requirement | Details |
|
|
486
|
+
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
487
|
+
| **Work item link** | Optional. Linking is encouraged for traceability but enforce it only if your branch policy requires it. |
|
|
488
|
+
| **Title format** | Conventional Commits format: `type(scope): description` |
|
|
489
|
+
| **Description** | Must include: summary of changes, rationale, verification steps, and a linked work item ID if applicable |
|
|
490
|
+
| **Pre-PR sync** | **Mandatory rebase on latest `origin/<target>` before pushing.** See [🛑 Agent-mandatory pre-PR guard](#-agent-mandatory-pre-pr-guard) above — this applies even when opening PRs via raw `az repos pr create` / `gh pr create` / MCP tools. |
|
|
491
|
+
| **Branch cleanup** | After merge, delete the source branch (local and remote). |
|
|
492
|
+
| **PR link format** | All PR references in agent output should be clickable markdown links to the PR, not a bare `PR #NNN`. |
|
|
493
|
+
|
|
494
|
+
### Agent PR Workflow
|
|
495
|
+
|
|
496
|
+
1. **Create a work item** (if one doesn't exist) using `spell-suggest-feature` or `spell-bug`.
|
|
497
|
+
2. **Open PR** with proper title, description, and work-item link.
|
|
498
|
+
3. **Notify the human** through your configured channel with: `[PR #{number}] {repo} — {title} (#{workItemId})`.
|
|
499
|
+
4. **Address review feedback** if a reviewer requests changes.
|
|
500
|
+
5. **After merge**, delete the branch (local + remote) and confirm cleanup.
|
|
501
|
+
|
|
502
|
+
### PR Hygiene
|
|
503
|
+
|
|
504
|
+
- `spell-open-session` checks for open PRs across all repos and reports them.
|
|
505
|
+
- PRs open >3 days are flagged as **stale** — the human is prompted to review or close.
|
|
506
|
+
- PRs open >7 days without activity are flagged for **closure** — the human decides.
|
|
507
|
+
- Abandoned PRs should be closed with a comment explaining why (e.g., "superseded by #{newPR}", "scope changed").
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Agent Attribution Model
|
|
512
|
+
|
|
513
|
+
Every commit must clearly identify **who produced the content** and **who approved/pushed it**.
|
|
514
|
+
|
|
515
|
+
### Author vs. Committer
|
|
516
|
+
|
|
517
|
+
| Field | Represents | Examples |
|
|
518
|
+
| -------------------------- | -------------------------------- | -------------------------------------------------------------------- |
|
|
519
|
+
| **Author** (`--author`) | Entity that produced the content | `{AGENT_NAME} <{AGENT_EMAIL}>`, `{OPERATOR_NAME} <{OPERATOR_EMAIL}>` |
|
|
520
|
+
| **Committer** (Git config) | Human who approved and pushed | Always the operator: `{OPERATOR_NAME} <{OPERATOR_EMAIL}>` |
|
|
521
|
+
|
|
522
|
+
- If **you** wrote the content: don't override author. Your global Git config is used.
|
|
523
|
+
- If an **agent** produced the content: use `--author` to set the agent's identity.
|
|
524
|
+
- If an **interactive AI tool** (Copilot, Claude in VS Code) produced the content: use the tool-level identity.
|
|
525
|
+
|
|
526
|
+
### Agent Email Convention
|
|
527
|
+
|
|
528
|
+
Give every agent/tool a stable email under a domain you control. Most hosts treat author email as metadata only — authentication uses the push credential (SSH key / PAT), not the author email.
|
|
529
|
+
|
|
530
|
+
**Format:** `[Persona Name] <[lowercase-persona]@{OPERATOR_DOMAIN}>`
|
|
531
|
+
|
|
532
|
+
Maintain a registry of the identities you use, for example:
|
|
533
|
+
|
|
534
|
+
| Identity | Email | Type | Role |
|
|
535
|
+
| --------------- | --------------------------- | ------------------------------- | -------------------------- |
|
|
536
|
+
| {OPERATOR_NAME} | `{OPERATOR_EMAIL}` | Human (owner) | — |
|
|
537
|
+
| {AGENT_NAME} | `{AGENT_EMAIL}` | Autonomous agent | Product Operations Manager |
|
|
538
|
+
| Merlin | `merlin@{OPERATOR_DOMAIN}` | Autonomous agent | CTO / Architecture Lead |
|
|
539
|
+
| Lafayette | `lafayette@{OPERATOR_DOMAIN}` | Autonomous agent | Full-Stack Developer |
|
|
540
|
+
| Copilot | `copilot@{OPERATOR_DOMAIN}` | GitHub Copilot | Tool |
|
|
541
|
+
| Claude | `claude@{OPERATOR_DOMAIN}` | Claude Code | Tool |
|
|
542
|
+
|
|
543
|
+
New agents are registered during onboarding.
|
|
544
|
+
|
|
545
|
+
### Required Commit Trailers (Agent Commits)
|
|
546
|
+
|
|
547
|
+
Agent-authored commits MUST include trailers in the commit message footer. Human commits MAY include them.
|
|
548
|
+
|
|
549
|
+
| Trailer | Required | Example |
|
|
550
|
+
| -------------- | ----------- | --------------------------------------------- |
|
|
551
|
+
| `Agent` | Yes | `kellar`, `copilot`, `claude` |
|
|
552
|
+
| `Model` | Yes | `claude-opus-4-20250918`, `gpt-4o` |
|
|
553
|
+
| `Provider` | Yes | `anthropic`, `openai` |
|
|
554
|
+
| `Role` | Recommended | `product-ops`, `developer`, `cto` |
|
|
555
|
+
| `Task-Type` | Optional | `docs`, `code`, `review`, `marketing` |
|
|
556
|
+
| `Approval` | Optional | `interactive`, `batch`, `post-review` |
|
|
557
|
+
| `Channel` | Optional | `chat`, `cli`, `editor` |
|
|
558
|
+
| `Risk-Class` | Optional | `low`, `medium`, `high` |
|
|
559
|
+
| `Request-ID` | Optional | `req-001` |
|
|
560
|
+
| `Session` | Optional | `session-01` |
|
|
561
|
+
| `Rollback-Ref` | Optional | path or commit to the pre-change state |
|
|
562
|
+
|
|
563
|
+
### Complete Examples
|
|
564
|
+
|
|
565
|
+
**Agent-authored commit ({AGENT_NAME}):**
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
git commit --author="{AGENT_NAME} <{AGENT_EMAIL}>" \
|
|
569
|
+
--trailer="Agent=kellar" \
|
|
570
|
+
--trailer="Model=<model-id>" \
|
|
571
|
+
--trailer="Provider=<provider>" \
|
|
572
|
+
--trailer="Role=product-ops" \
|
|
573
|
+
--trailer="Channel=chat" \
|
|
574
|
+
-m "feat(inventory): generate initial product catalog
|
|
575
|
+
|
|
576
|
+
Created 47 SKUs from the inventory spreadsheet."
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
**Copilot-assisted commit (Copilot in editor):**
|
|
580
|
+
|
|
581
|
+
```bash
|
|
582
|
+
git commit --author="Copilot <copilot@{OPERATOR_DOMAIN}>" \
|
|
583
|
+
--trailer="Agent=copilot" \
|
|
584
|
+
--trailer="Model=<model-id>" \
|
|
585
|
+
--trailer="Provider=<provider>" \
|
|
586
|
+
--trailer="Channel=editor" \
|
|
587
|
+
-m "docs(governance): add attribution model to git conventions"
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
**Human-authored commit (no overrides):**
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
git commit -m "docs(decisions): add ADR-028 agent attribution model"
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Querying Attribution
|
|
597
|
+
|
|
598
|
+
```bash
|
|
599
|
+
# All commits by {AGENT_NAME}
|
|
600
|
+
git log --author="{AGENT_NAME}" --oneline
|
|
601
|
+
|
|
602
|
+
# All commits by any agent (non-human)
|
|
603
|
+
git log --author="@{OPERATOR_DOMAIN}" --oneline
|
|
604
|
+
|
|
605
|
+
# All human-only commits
|
|
606
|
+
git log --author="{OPERATOR_EMAIL}" --oneline
|
|
607
|
+
|
|
608
|
+
# Extract trailers
|
|
609
|
+
git log -10 --format='%H %s%n%(trailers:key=Agent,key=Model,key=Provider)%n'
|
|
610
|
+
|
|
611
|
+
# Count commits per agent
|
|
612
|
+
git log --all --format='%(trailers:key=Agent,valueonly)' | sort | uniq -c | sort -rn
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
---
|
|
616
|
+
|
|
617
|
+
## Tools to Help
|
|
618
|
+
|
|
619
|
+
### Automated Commit Generation
|
|
620
|
+
|
|
621
|
+
Use `spell-commit-work` prompt during sessions:
|
|
622
|
+
|
|
623
|
+
1. Type `@spell-commit-work` in chat
|
|
624
|
+
2. Prompt analyzes `git status` and conversation context
|
|
625
|
+
3. Generates Conventional Commits message
|
|
626
|
+
4. Shows for approval
|
|
627
|
+
5. Executes `git add -A && git commit` if approved
|
|
628
|
+
|
|
629
|
+
### Manual Commit Template
|
|
630
|
+
|
|
631
|
+
If committing manually, use this mental checklist:
|
|
632
|
+
|
|
633
|
+
```
|
|
634
|
+
[ ] Type correct? (feat, fix, docs, chore, refactor, etc.)
|
|
635
|
+
[ ] Scope correct? (prompts, agents, security, etc.)
|
|
636
|
+
[ ] Imperative mood? ("add" not "added")
|
|
637
|
+
[ ] Lowercase start, no period?
|
|
638
|
+
[ ] Under 72 chars?
|
|
639
|
+
[ ] Body needed for context?
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### Validating Format
|
|
643
|
+
|
|
644
|
+
Quick regex to check format (optional — not enforced by hooks):
|
|
645
|
+
|
|
646
|
+
```bash
|
|
647
|
+
# Valid: type(scope): description
|
|
648
|
+
^(feat|fix|docs|refactor|chore|test|perf|ci|style|revert)(\([a-z-]+\))?:\s.{1,72}$
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Examples from This Repo
|
|
654
|
+
|
|
655
|
+
**Feature addition:**
|
|
656
|
+
|
|
657
|
+
```
|
|
658
|
+
feat(prompts): add spell-commit-work for checkpointing
|
|
659
|
+
|
|
660
|
+
Enables mid-session commits without waiting for spell-close-session.
|
|
661
|
+
Generates Conventional Commits messages with approval workflow.
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
**Documentation update:**
|
|
665
|
+
|
|
666
|
+
```
|
|
667
|
+
docs(decisions): add table of contents to DECISIONS.md
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
**Bug fix:**
|
|
671
|
+
|
|
672
|
+
```
|
|
673
|
+
fix(auth): restore token SecretRef after onboarding
|
|
674
|
+
|
|
675
|
+
Onboarding wizard overwrote auth config with a plaintext token.
|
|
676
|
+
Restored the SecretRef and restarted the service.
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
**Refactor:**
|
|
680
|
+
|
|
681
|
+
```
|
|
682
|
+
refactor(prompts): rename to spell- prefix
|
|
683
|
+
|
|
684
|
+
- continue-arcane.prompt.md → spell-open-session.prompt.md
|
|
685
|
+
- session-close.prompt.md → spell-close-session.prompt.md
|
|
686
|
+
- doc-drift-check.prompt.md → spell-check-drift.prompt.md
|
|
687
|
+
- new-business-bootstrap.prompt.md → spell-bootstrap-business.prompt.md
|
|
688
|
+
|
|
689
|
+
Implements ADR-019 spell- naming convention.
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
**Chore:**
|
|
693
|
+
|
|
694
|
+
```
|
|
695
|
+
chore(repo): add root .gitignore
|
|
696
|
+
|
|
697
|
+
Excludes .env, *.log, node_modules/, .obsidian/, OS artifacts.
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
---
|
|
701
|
+
|
|
702
|
+
## What NOT to Commit
|
|
703
|
+
|
|
704
|
+
Enforced by root `.gitignore`:
|
|
705
|
+
|
|
706
|
+
- Secrets (`.env`, `*.pem`, `*.key`)
|
|
707
|
+
- Logs (`*.log`)
|
|
708
|
+
- Dependencies (`node_modules/`, `vendor/`)
|
|
709
|
+
- Build artifacts (`dist/`, `build/`, `*.pyc`)
|
|
710
|
+
- OS artifacts (`.DS_Store`, `Thumbs.db`, `desktop.ini`)
|
|
711
|
+
- Editor state (`.vscode/settings.json`, `.idea/`)
|
|
712
|
+
- Obsidian vault state (`.obsidian/`)
|
|
713
|
+
|
|
714
|
+
See [.gitignore](../.gitignore) for full list.
|
|
715
|
+
|
|
716
|
+
---
|
|
717
|
+
|
|
718
|
+
## When to Commit
|
|
719
|
+
|
|
720
|
+
**During active work (use `spell-commit-work`):**
|
|
721
|
+
|
|
722
|
+
- Completed a discrete task (added ADR, renamed files, fixed bug)
|
|
723
|
+
- About to switch context to a different task
|
|
724
|
+
- Reached a checkpoint before taking a break
|
|
725
|
+
|
|
726
|
+
**At session close (use `spell-close-session`):**
|
|
727
|
+
|
|
728
|
+
- Generated journal entry, updated TODO.md
|
|
729
|
+
- Finalized session documentation
|
|
730
|
+
- Ready to hand off or resume later
|
|
731
|
+
|
|
732
|
+
**Commit early, commit often.** Small commits with clear messages are easier to review, revert, and understand than giant "end of day" dumps.
|
|
733
|
+
|
|
734
|
+
---
|
|
735
|
+
|
|
736
|
+
## Troubleshooting Notes
|
|
737
|
+
|
|
738
|
+
### Git command unavailable in interactive PowerShell terminal
|
|
739
|
+
|
|
740
|
+
**Symptom:** Running `git` returns "The term 'git' is not recognized" even though recent command output still includes Git diff content.
|
|
741
|
+
|
|
742
|
+
**Cause:** Terminal PATH resolution can differ between integrated shell contexts, especially when commands are piped or executed in chained command blocks.
|
|
743
|
+
|
|
744
|
+
**Fix:** Use the explicit executable path:
|
|
745
|
+
|
|
746
|
+
```powershell
|
|
747
|
+
& "C:\Program Files\Git\cmd\git.exe" <subcommand>
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**Verify:** Run:
|
|
751
|
+
|
|
752
|
+
```powershell
|
|
753
|
+
& "C:\Program Files\Git\cmd\git.exe" --version
|
|
754
|
+
& "C:\Program Files\Git\cmd\git.exe" status --short
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
Both commands should return successfully.
|
|
758
|
+
|
|
759
|
+
**Prevention:** Prefer explicit git path in scripted close-session and commit workflows when shell behavior is inconsistent.
|