Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .claude/skills/specsync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ specsync -change <slug> # push to GitHub
**Pull issues into specs:**
```bash
specsync pull -issue N [-change <slug>]
specsync pull -issue N -worktree # also creates/reuses a dedicated git worktree + branch
```
One issue, one branch, one worktree — don't stack unrelated changes on whatever branch is currently checked out. `-worktree` sets both up for the issue-first path; see `specsync agent-help` for the general convention (also applies spec-first, where you branch/worktree by hand: `git worktree add ../worktrees/<slug> -b feat/<n>-<slug>`).

**Bind an already-existing change to an already-existing issue:**
```bash
Expand Down
2 changes: 2 additions & 0 deletions cmd/specsync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ specsync -change <slug> # push to GitHub
**Pull issues into specs:**
```bash
specsync pull -issue N [-change <slug>]
specsync pull -issue N -worktree # also creates/reuses a dedicated git worktree + branch
```
One issue, one branch, one worktree — don't stack unrelated changes on whatever branch is currently checked out. `-worktree` sets both up for the issue-first path; see `specsync agent-help` for the general convention (also applies spec-first, where you branch/worktree by hand: `git worktree add ../worktrees/<slug> -b feat/<n>-<slug>`).

**Bind an already-existing change to an already-existing issue:**
```bash
Expand Down
31 changes: 30 additions & 1 deletion cmd/specsync/agent_help.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,25 @@ var commandMetadata = map[string]AgentCommandHelp{
Default: "auto-detect",
Description: "Target repo as owner/name",
},
{
Name: "worktree",
Type: "boolean",
Required: false,
Default: false,
Description: "Create (or reuse) a git worktree for this issue and run the pull inside it, instead of the current directory — one issue, one branch, one worktree",
},
{
Name: "worktree-dir",
Type: "string",
Required: false,
Default: "../worktrees (or $SPECSYNC_WORKTREE_DIR)",
Description: "Base directory for -worktree",
},
},
SafetyRules: []string{
"Use -dry-run to preview before pulling",
"Verify the issue number is correct",
"Work each issue in its own branch (feat/<n>-<slug>) and, ideally, its own worktree — pass -worktree to have pull set both up automatically, rather than accumulating unrelated changes on whatever branch happens to be checked out",
},
Examples: []string{
"specsync pull -issue 42 -dry-run",
Expand Down Expand Up @@ -935,6 +950,7 @@ func renderAgentHelpOverview(asJSON bool) {
"Use `specsync agent-help <command> -json` for machine-readable output",
"All output formats support -json for automation",
"Always use -dry-run before making changes",
"One issue, one branch, one worktree: before starting work on a change, create a branch named after its issue (e.g. feat/<n>-<slug>) — a dedicated worktree (`git worktree add ../worktrees/<slug> -b feat/<n>-<slug>`) keeps concurrent changes from colliding in the same working directory. `specsync pull -issue <n> -worktree` does this for you on the issue-first path.",
},
}
data, _ := json.MarshalIndent(overview, "", " ")
Expand Down Expand Up @@ -964,7 +980,20 @@ Available commands:`)
- Always use -dry-run before making changes
- Many commands support -json for machine-readable output
- See agent-help <command> for full details and flags
- Read AGENTS.md for workflow patterns
- If the project has an AGENTS.md, read it for local workflow patterns

## Branch & worktree per issue

Before starting work on a change, create a branch named after its issue
(e.g. feat/42-my-change) — do not commit directly to the main branch or mix
two issues' work in one branch. A dedicated worktree keeps concurrent
changes from colliding in the same working directory:

git worktree add ../worktrees/my-change -b feat/42-my-change

On the issue-first path, 'specsync pull -issue 42 -worktree' does this for
you (see 'specsync agent-help pull'). Clean up when merged:
'git worktree remove ../worktrees/my-change'.
`)
}
}
Expand Down
2 changes: 2 additions & 0 deletions npm/skills/specsync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ specsync -change <slug> # push to GitHub
**Pull issues into specs:**
```bash
specsync pull -issue N [-change <slug>]
specsync pull -issue N -worktree # also creates/reuses a dedicated git worktree + branch
```
One issue, one branch, one worktree — don't stack unrelated changes on whatever branch is currently checked out. `-worktree` sets both up for the issue-first path; see `specsync agent-help` for the general convention (also applies spec-first, where you branch/worktree by hand: `git worktree add ../worktrees/<slug> -b feat/<n>-<slug>`).

**Bind an already-existing change to an already-existing issue:**
```bash
Expand Down
40 changes: 40 additions & 0 deletions openspec/changes/guide-agents-on-branch-per-issue/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Guide agents toward one branch, one worktree per issue

## Why

Agents working with specsync-managed projects are often unclear on basic
git hygiene: which branch to work on, whether to reuse one across unrelated
issues, and when a worktree is warranted. specsync already has real support
for this — `pull -worktree` creates a dedicated branch and worktree per
issue — but nothing an agent actually reads mentions it.

The gap is specific: this repo's own `AGENTS.md` documents the convention in
detail, but `AGENTS.md` is a dogfooding doc for *this* repo — it is never
installed into a project that adopts specsync. `specsync install-skill` only
ever ships `SKILL.md`; `skills/specsync/docs/*.md` never leaves this repo
either. So an agent working in an arbitrary consuming project, or reading
`specsync agent-help` (the one thing guaranteed to be reachable everywhere,
since it ships with the binary), gets no guidance on this at all — and
`agent-help`'s own overview previously just said "read AGENTS.md," which is
silently false for most projects.

## What

- `specsync agent-help` (overview, both text and `-json`) now states the
one-issue/one-branch/one-worktree convention directly, and softens the
AGENTS.md pointer to "if the project has one."
- `specsync agent-help pull` documents the existing `-worktree`/
`-worktree-dir` flags (previously undocumented anywhere) and adds a safety
rule pointing at them.
- The skill (`SKILL.md`, `docs/reference.md`, `docs/workflow.md`) mentions
the same convention and the `-worktree` flag, including the honest caveat
that there's no equivalent automation for the spec-first path yet — branch
and worktree by hand there.

No new command or flag: `pull -worktree` already existed and did the right
thing. This only makes it discoverable.

## Release note

`specsync agent-help` now guides agents toward one branch and worktree per
issue, and documents `pull`'s existing `-worktree`/`-worktree-dir` flags.
6 changes: 6 additions & 0 deletions openspec/changes/guide-agents-on-branch-per-issue/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Tasks: Guide agents toward one branch, one worktree per issue

- [x] `agent-help` overview (text + JSON) states the branch/worktree-per-issue convention directly, not just "read AGENTS.md"
- [x] `agent-help pull` documents `-worktree`/`-worktree-dir` and adds a matching safety rule
- [x] Skill (`SKILL.md`, `docs/reference.md`, `docs/workflow.md`) mentions the convention and the flag, including the spec-first gap (no automation there yet)
- [x] `make sync-skill`; `go build`/`go vet`/`go test` clean
2 changes: 2 additions & 0 deletions skills/specsync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ specsync -change <slug> # push to GitHub
**Pull issues into specs:**
```bash
specsync pull -issue N [-change <slug>]
specsync pull -issue N -worktree # also creates/reuses a dedicated git worktree + branch
```
One issue, one branch, one worktree — don't stack unrelated changes on whatever branch is currently checked out. `-worktree` sets both up for the issue-first path; see `specsync agent-help` for the general convention (also applies spec-first, where you branch/worktree by hand: `git worktree add ../worktrees/<slug> -b feat/<n>-<slug>`).

**Bind an already-existing change to an already-existing issue:**
```bash
Expand Down
4 changes: 3 additions & 1 deletion skills/specsync/docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ specsync [-dry-run] [-change <slug>] [-reconcile] [-close-completed] [-repo owne
Pull an issue into a local OpenSpec change.

```
specsync pull -issue <N> [-change <slug>] [-dry-run] [-repo owner/name]
specsync pull -issue <N> [-change <slug>] [-dry-run] [-repo owner/name] [-worktree] [-worktree-dir <dir>]
```

**Flags:**
- `-issue <N>` (required) — Issue number to pull
- `-change <slug>` — Override auto-derived change name
- `-dry-run` — Preview without writing files
- `-repo owner/name` — Override auto-detected repo
- `-worktree` — Create (or reuse) a dedicated git worktree and branch (`feat/<N>-<slug>`) for this issue, and run the pull inside it, instead of pulling into whatever's currently checked out — one issue, one branch, one worktree
- `-worktree-dir <dir>` — Base directory for `-worktree` (default: `$SPECSYNC_WORKTREE_DIR` or `../worktrees`)

## adopt

Expand Down
19 changes: 19 additions & 0 deletions skills/specsync/docs/workflow.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Workflow Patterns

## One Issue, One Branch, One Worktree

Before starting *any* change below — spec-first or issue-first — put it on
its own branch, named after the issue once one exists (`feat/<n>-<slug>`; use
a working name and rename once `sync`/`pull` mints the issue if starting
spec-first). Don't commit two unrelated changes to the same branch, and don't
work directly on the main branch. A dedicated worktree avoids collisions when
more than one change is in flight at once:

```bash
git worktree add ../worktrees/my-change -b feat/42-my-change
# ... implement here ...
git worktree remove ../worktrees/my-change # once merged
```

On the issue-first path, `specsync pull -issue 42 -worktree` sets both up for
you in one step (see `pull` in [reference.md](reference.md)). There's no
equivalent flag for spec-first yet — branch/worktree by hand as above.

## Spec-First (Plan → Issue)

When starting from a spec idea:
Expand Down
Loading