@ulysses-ai/create-workspace 0.13.0-beta.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.
Files changed (86) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +108 -0
  3. package/bin/create.mjs +79 -0
  4. package/lib/git.mjs +26 -0
  5. package/lib/init.mjs +129 -0
  6. package/lib/payload.mjs +44 -0
  7. package/lib/prompts.mjs +113 -0
  8. package/lib/scaffold.mjs +84 -0
  9. package/lib/upgrade.mjs +42 -0
  10. package/package.json +43 -0
  11. package/template/.claude/agents/aside-researcher.md +48 -0
  12. package/template/.claude/agents/implementer.md +39 -0
  13. package/template/.claude/agents/researcher.md +40 -0
  14. package/template/.claude/agents/reviewer.md +47 -0
  15. package/template/.claude/hooks/_utils.mjs +196 -0
  16. package/template/.claude/hooks/_utils.test.mjs +99 -0
  17. package/template/.claude/hooks/post-compact.mjs +7 -0
  18. package/template/.claude/hooks/pre-compact.mjs +34 -0
  19. package/template/.claude/hooks/repo-write-detection.mjs +107 -0
  20. package/template/.claude/hooks/session-end.mjs +91 -0
  21. package/template/.claude/hooks/session-start.mjs +150 -0
  22. package/template/.claude/hooks/subagent-start.mjs +44 -0
  23. package/template/.claude/hooks/workspace-update-check.mjs +42 -0
  24. package/template/.claude/hooks/worktree-create.mjs +53 -0
  25. package/template/.claude/lib/session-frontmatter.mjs +265 -0
  26. package/template/.claude/lib/session-frontmatter.test.mjs +242 -0
  27. package/template/.claude/recipes/migrate-from-notion.md +120 -0
  28. package/template/.claude/rules/agent-rules.md.skip +32 -0
  29. package/template/.claude/rules/cloud-infrastructure.md.skip +15 -0
  30. package/template/.claude/rules/coherent-revisions.md +24 -0
  31. package/template/.claude/rules/documentation.md.skip +13 -0
  32. package/template/.claude/rules/git-conventions.md +34 -0
  33. package/template/.claude/rules/honest-pushback.md +56 -0
  34. package/template/.claude/rules/local-dev-environment.md.skip +60 -0
  35. package/template/.claude/rules/memory-guidance.md +26 -0
  36. package/template/.claude/rules/product-integrity.md.skip +24 -0
  37. package/template/.claude/rules/scope-guard.md.skip +22 -0
  38. package/template/.claude/rules/superpowers-workflow.md.skip +22 -0
  39. package/template/.claude/rules/token-economics.md.skip +31 -0
  40. package/template/.claude/rules/work-item-tracking.md +90 -0
  41. package/template/.claude/rules/workspace-structure.md +69 -0
  42. package/template/.claude/scripts/add-repo-to-session.mjs +78 -0
  43. package/template/.claude/scripts/cleanup-work-session.mjs +108 -0
  44. package/template/.claude/scripts/create-work-session.mjs +124 -0
  45. package/template/.claude/scripts/migrate-open-work.mjs +91 -0
  46. package/template/.claude/scripts/migrate-session-layout.mjs +236 -0
  47. package/template/.claude/scripts/migrate-session-layout.test.mjs +144 -0
  48. package/template/.claude/scripts/trackers/github-issues.mjs +170 -0
  49. package/template/.claude/scripts/trackers/github-issues.test.mjs +190 -0
  50. package/template/.claude/scripts/trackers/interface.mjs +25 -0
  51. package/template/.claude/scripts/trackers/interface.test.mjs +40 -0
  52. package/template/.claude/settings.json +107 -0
  53. package/template/.claude/skills/aside/SKILL.md +125 -0
  54. package/template/.claude/skills/braindump/SKILL.md +96 -0
  55. package/template/.claude/skills/build-docs-site/SKILL.md +323 -0
  56. package/template/.claude/skills/build-docs-site/checklists/framing.md +221 -0
  57. package/template/.claude/skills/build-docs-site/checklists/pitfalls.md +228 -0
  58. package/template/.claude/skills/build-docs-site/checklists/review.md +130 -0
  59. package/template/.claude/skills/build-docs-site/scripts/bulk-fill-migration.py +393 -0
  60. package/template/.claude/skills/build-docs-site/scripts/forbidden-word-grep.mjs +159 -0
  61. package/template/.claude/skills/build-docs-site/scripts/leak-grep.mjs +328 -0
  62. package/template/.claude/skills/build-docs-site/templates/custom.css.tmpl +212 -0
  63. package/template/.claude/skills/build-docs-site/templates/docusaurus.config.ts.tmpl +95 -0
  64. package/template/.claude/skills/build-docs-site/templates/primitives/Arrow.tsx +87 -0
  65. package/template/.claude/skills/build-docs-site/templates/primitives/Box.tsx +90 -0
  66. package/template/.claude/skills/build-docs-site/templates/primitives/DiagramContainer.tsx +46 -0
  67. package/template/.claude/skills/build-docs-site/templates/primitives/Region.tsx +68 -0
  68. package/template/.claude/skills/build-docs-site/templates/primitives/SectionTitle.tsx +42 -0
  69. package/template/.claude/skills/build-docs-site/templates/primitives/tokens.ts +67 -0
  70. package/template/.claude/skills/build-docs-site/templates/sidebars.ts.tmpl +89 -0
  71. package/template/.claude/skills/build-docs-site/templates/spec.md.tmpl +119 -0
  72. package/template/.claude/skills/complete-work/SKILL.md +369 -0
  73. package/template/.claude/skills/handoff/SKILL.md +98 -0
  74. package/template/.claude/skills/maintenance/SKILL.md +116 -0
  75. package/template/.claude/skills/pause-work/SKILL.md +98 -0
  76. package/template/.claude/skills/promote/SKILL.md +77 -0
  77. package/template/.claude/skills/release/SKILL.md +126 -0
  78. package/template/.claude/skills/setup-tracker/SKILL.md +117 -0
  79. package/template/.claude/skills/start-work/SKILL.md +234 -0
  80. package/template/.claude/skills/sync-work/SKILL.md +73 -0
  81. package/template/.claude/skills/workspace-init/SKILL.md +420 -0
  82. package/template/.claude/skills/workspace-update/SKILL.md +108 -0
  83. package/template/.mcp.json +12 -0
  84. package/template/CLAUDE.md.tmpl +32 -0
  85. package/template/_gitignore +28 -0
  86. package/template/workspace.json.tmpl +15 -0
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: promote
3
+ description: Move personal auto-memory or local-only files into shared context. Use when you've discovered something valuable that the team should know.
4
+ ---
5
+
6
+ # Promote
7
+
8
+ Promote personal knowledge into shared context. Assess all candidates, recommend actions, let the user decide with coded references.
9
+
10
+ ## Sources
11
+
12
+ This skill can promote from three sources:
13
+ 1. **Auto-memory (AM)** — files in `~/.claude/projects/*/memory/`
14
+ 2. **Local-only context (LOC)** — `shared-context/local-only-*.md`
15
+ 3. **Local-only rules (LOR)** — `.claude/rules/local-only-*.md`
16
+
17
+ ## Flow
18
+
19
+ **Step 1: List all candidates**
20
+
21
+ Show ALL candidates from all sources in a single coded table. The user should see everything at once to make informed decisions.
22
+
23
+ ```
24
+ | Code | File | Assessment | Recommendation |
25
+ |------|-------------------------------|-----------------------------------------|-------------------|
26
+ | AM1 | feedback_no_injection_rev... | Redundant — coherent-revisions rule | Drop from memory |
27
+ | AM2 | project_create_claude_work... | Stale — references deleted spec | Drop or update |
28
+ | AM3 | feedback_subagent_perms... | Personal setup quirk | Keep as memory |
29
+ | LOC1 | local-only-naming-ideas.md | Team should see naming options | Promote to alice/ |
30
+ | LOC2 | local-only-release-checkli... | Personal task tracker | Keep local |
31
+ | LOR1 | local-only-dogfood-sync.md | Dogfood-specific, not for template | Keep local |
32
+ ```
33
+
34
+ For each candidate, assess:
35
+ - Is it redundant with an existing rule or context file? → recommend drop
36
+ - Is it stale or outdated? → recommend drop or update
37
+ - Is it personal/setup-specific? → recommend keep as-is
38
+ - Would the team benefit from seeing it? → recommend promote
39
+
40
+ **Step 2: User decides**
41
+
42
+ The user responds using codes:
43
+ - "Promote: LOC1, LOC2. Drop: AM1, AM2. Keep the rest."
44
+ - "Promote all LOC. Drop AM1-AM3."
45
+ - Or any combination.
46
+
47
+ **Step 3: Execute decisions**
48
+
49
+ For each **promote** action:
50
+ - Ask: "Team-visible, user-scoped (default), or locked?"
51
+ - Copy to destination, set `type: promoted` in frontmatter
52
+ - Remove the local-only original
53
+ - Commit individually: `git commit -m "promote: {name}"`
54
+
55
+ For each **drop** action:
56
+ - Delete the file (auto-memory from `~/.claude/projects/*/memory/`, local-only from workspace)
57
+ - Update MEMORY.md index if auto-memory was removed
58
+
59
+ For each **keep** action:
60
+ - No changes
61
+
62
+ **Step 4: Report**
63
+
64
+ "Promoted {N} files. Dropped {M} files. {K} files unchanged."
65
+
66
+ ## Rewrite on Promote
67
+
68
+ Auto-memory files are terse notes written for Claude's internal use. When promoting to shared context, rewrite into proper format with:
69
+ - Frontmatter (state, lifecycle, type: promoted, topic, author, updated)
70
+ - Sections with enough context to be useful to someone who wasn't in the original session
71
+ - Local-only files may already be well-formatted — copy as-is if so, just update frontmatter
72
+
73
+ ## Notes
74
+ - Promotion is one-way: shared context should not be demoted back to local-only
75
+ - Use this when you discover a pattern, convention, or decision that would benefit the team
76
+ - The coded table makes bulk decisions fast — no need to type full filenames
77
+ - Assess everything upfront so the user sees the full picture before deciding
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: release
3
+ description: Combine unreleased branch notes into a versioned release document. Targets project repos, not the workspace. Synthesizes ephemeral shared context into locked entries. Use at release time.
4
+ ---
5
+
6
+ # Release
7
+
8
+ Combine unreleased branch-release-notes into a versioned document per project repo. Synthesize ephemeral workspace context into locked team knowledge.
9
+
10
+ ## Parameters
11
+ - `/release {version}` — create release notes for a specific version
12
+ - `/release` — ask for the version
13
+
14
+ ## Flow
15
+
16
+ **Step 1: Determine version and repo**
17
+ If no version parameter: ask "What version is this release? (e.g., 1.2.0)"
18
+
19
+ Check `workspace.json` for `releaseMode`:
20
+ - **per-repo** (default): ask which repo to release
21
+ - **workspace**: process all repos together
22
+ - **ask**: "Process all repos together or individually?"
23
+
24
+ **Step 2: Read unreleased notes**
25
+ For each target repo:
26
+ ```bash
27
+ ls repos/{repo}/release-notes/unreleased/
28
+ ```
29
+ Read all `branch-release-notes-*.md` and `branch-release-questions-*.md` files.
30
+
31
+ If no unreleased files exist: "No unreleased notes found for {repo}. Nothing to release."
32
+
33
+ **Step 3: Group and organize**
34
+ Group notes by type using `type:` frontmatter (feature, fix, chore):
35
+ - Features first, then fixes, then chores
36
+ - Within each group, order chronologically by date
37
+
38
+ **Step 4: Handle questions**
39
+ Present all open questions from `branch-release-questions-*.md` files:
40
+ "These questions are still open from development. For each one:"
41
+ - **Answer** — provide the answer, remove from questions
42
+ - **Defer** — keep in a "Known Issues" section of the release notes
43
+ - **Discard** — no longer relevant
44
+
45
+ **Step 5: Synthesize release document**
46
+ Write `repos/{repo}/release-notes/v{version}.md`:
47
+ ```markdown
48
+ # v{version} Release Notes
49
+
50
+ **Date:** {YYYY-MM-DD}
51
+
52
+ ## Features
53
+ {Coherent narrative combining all feature branch-release-notes.
54
+ Deduplicate related items. Credit authors.
55
+ Write from scratch — don't concatenate. Coherent-revisions rule applies.}
56
+
57
+ ## Fixes
58
+ {Same treatment for bugfix branches.}
59
+
60
+ ## Maintenance
61
+ {Same for chore branches.}
62
+
63
+ ## Known Issues
64
+ {Deferred questions from Step 4, if any.}
65
+
66
+ ## Contributors
67
+ {List of unique authors from all branch notes.}
68
+ ```
69
+
70
+ **Step 6: Archive unreleased files**
71
+ ```bash
72
+ mkdir -p repos/{repo}/release-notes/archive/v{version}
73
+ mv repos/{repo}/release-notes/unreleased/branch-release-* repos/{repo}/release-notes/archive/v{version}/
74
+ ```
75
+
76
+ **Step 7: Commit release notes to project repo**
77
+ ```bash
78
+ cd repos/{repo}
79
+ git add release-notes/
80
+ git commit -m "docs: v{version} release notes"
81
+ ```
82
+
83
+ **Step 7b: Bump package.json version**
84
+ If the project repo has a `package.json` with a `version` field (as in the scaffolder repo), update it to match the release version:
85
+ ```bash
86
+ cd repos/{repo}
87
+ # Update "version": "..." in package.json to the release version
88
+ git add package.json
89
+ git commit -m "chore: bump version to v{version}"
90
+ ```
91
+ Skip this step if the repo has no package.json or no version field.
92
+
93
+ **Step 8: Consume project-scoped specs**
94
+ Project-scoped specs and plans in `shared-context/{user}/` (ongoing) that are fully covered by this release:
95
+ - Consume into the release notes (their content is now captured in the versioned doc)
96
+ - Remove the source files
97
+ - If partially covered: rewrite the spec to reflect only what remains unimplemented
98
+
99
+ **Step 9: Synthesize workspace shared context**
100
+ Process ephemeral shared-context entries:
101
+
102
+ 1. List all ephemeral entries with `lifecycle: resolved`
103
+ 2. For each, determine:
104
+ - Does an existing locked entry cover this topic? → Merge into it (enrich)
105
+ - Are there related resolved entries? → Combine into a new locked entry
106
+ - Is it stale/fully consumed by release notes? → Archive or delete
107
+ - Is it unresolvable but still valuable? → Move to `{user}/` ongoing or keep as root ephemeral
108
+ 3. For merged/new locked entries:
109
+ - Set `state: locked`, `type: synthesized`
110
+ - Move to `shared-context/locked/`
111
+ - Write concise, focused content — team truths, not session history
112
+ 4. Commit:
113
+ ```bash
114
+ git add shared-context/
115
+ git commit -m "release: synthesize shared context for v{version}"
116
+ ```
117
+
118
+ **Step 10: Report**
119
+ "Release v{version} complete for {repo}. {N} branch notes combined. {M} context entries synthesized into {K} locked entries."
120
+
121
+ ## Notes
122
+ - Release notes live in the PROJECT repo — the workspace never gets versioned
123
+ - Context synthesis happens in the WORKSPACE repo — both get separate commits
124
+ - The archive directory preserves raw branch notes for audit
125
+ - Per-repo is the default — each repo has its own release cadence
126
+ - The coherent-revisions rule applies: write the release narrative from scratch, don't concatenate branch notes
@@ -0,0 +1,117 @@
1
+ ---
2
+ name: setup-tracker
3
+ description: Configure an issue tracker for this workspace — writes workspace.json → tracker block and initializes labels. GitHub Issues is the only backend shipped; others can be added by dropping an adapter at .claude/scripts/trackers/{type}.mjs. Runnable during /workspace-init or standalone.
4
+ ---
5
+
6
+ # Setup Tracker
7
+
8
+ Wire this workspace up to an external issue tracker. The tracker becomes the source of truth for all work items; the workspace does not maintain a local mirror.
9
+
10
+ ## Prerequisites
11
+
12
+ - `.claude/rules/work-item-tracking.md` should be active. If missing, warn but continue.
13
+ - The adapter for the chosen backend must exist at `.claude/scripts/trackers/{type}.mjs`. The template ships `github-issues.mjs`.
14
+
15
+ ## Flow
16
+
17
+ ### Step 1: Check current state
18
+
19
+ Read `workspace.json` → `workspace.tracker`. If already configured: "Tracker is {type} on {repo}. Reconfigure? [y/N]." If declined, exit.
20
+
21
+ ### Step 2: Pick a backend
22
+
23
+ Ask: "Which issue tracker?"
24
+ 1. GitHub Issues (shipped)
25
+ 2. Linear — not yet supported
26
+ 3. Jira — not yet supported
27
+ 4. None — skip
28
+
29
+ For (2) and (3): tell the user the adapter isn't shipped and exit. To add one, write a module at `.claude/scripts/trackers/{type}.mjs` that implements the contract in `.claude/scripts/trackers/interface.mjs`.
30
+
31
+ For (4): exit — no changes.
32
+
33
+ ### Step 3: GitHub Issues configuration
34
+
35
+ 1. **Verify `gh` auth.** Run `gh auth status`. If not authenticated, walk the user through `gh auth login`. Do not proceed until authenticated.
36
+
37
+ 2. **Resolve the target repo.** Default to the workspace's own git remote:
38
+ ```bash
39
+ git -C {workspace-root} remote get-url origin
40
+ ```
41
+ Parse the GitHub slug. Ask: "Use `{slug}` for issues, or a different repo?" If the user wants a different repo, accept any `owner/name` slug.
42
+
43
+ 3. **Verify issues are enabled:**
44
+ ```bash
45
+ gh repo view {slug} --json hasIssuesEnabled
46
+ ```
47
+ If `hasIssuesEnabled` is `false`, offer: "Issues are disabled on `{slug}`. Enable? [Y/n]" → `gh api repos/{slug} -X PATCH -f has_issues=true`.
48
+
49
+ 4. **Write `workspace.json`:**
50
+ ```json
51
+ {
52
+ "workspace": {
53
+ "tracker": {
54
+ "type": "github-issues",
55
+ "repo": "{slug}"
56
+ }
57
+ }
58
+ }
59
+ ```
60
+ Preserve all other fields. Commit:
61
+ ```bash
62
+ git add workspace.json
63
+ git commit -m "chore: configure github-issues tracker on {slug}"
64
+ ```
65
+
66
+ 5. **Initialize labels** by calling the adapter's `ensureLabels()` from a shell one-liner:
67
+ ```bash
68
+ node --input-type=module -e "
69
+ import { createTracker } from './.claude/scripts/trackers/interface.mjs';
70
+ import { readFileSync } from 'node:fs';
71
+ const ws = JSON.parse(readFileSync('workspace.json', 'utf-8'));
72
+ const t = createTracker(ws.workspace.tracker);
73
+ await t.ensureLabels();
74
+ console.log('Labels initialized.');
75
+ "
76
+ ```
77
+ Creates the six standard labels: `bug`, `feat`, `chore`, `P1`, `P2`, `P3`.
78
+
79
+ 6. **Optional: create milestones.** Ask if the user wants a starter milestone list (e.g., `Backlog`, `v0.1 — Alpha`, `v1.0 — Launch`). If yes, call the adapter for each — idempotent, so re-running setup won't duplicate:
80
+ ```bash
81
+ node --input-type=module -e "
82
+ import { createTracker } from './.claude/scripts/trackers/interface.mjs';
83
+ import { readFileSync } from 'node:fs';
84
+ const ws = JSON.parse(readFileSync('workspace.json', 'utf-8'));
85
+ const t = createTracker(ws.workspace.tracker);
86
+ await t.ensureMilestone({ title: 'Backlog', description: 'Triage later' });
87
+ await t.ensureMilestone({ title: 'v0.1 — Alpha' });
88
+ await t.ensureMilestone({ title: 'v1.0 — Launch' });
89
+ "
90
+ ```
91
+ Skip if the user declines — milestones can be added anytime by calling `tracker.ensureMilestone(...)` or via the GitHub UI.
92
+
93
+ 7. **Verify:**
94
+ ```bash
95
+ gh issue list --repo {slug} --limit 5
96
+ ```
97
+ Expected: empty list (no tickets yet) or the existing ones if the repo already had issues.
98
+
99
+ ### Step 4: Report
100
+
101
+ ```
102
+ Tracker configured:
103
+ Type: github-issues
104
+ Repo: {slug}
105
+ Labels: bug, feat, chore, P1, P2, P3
106
+ Milestones: {list or "(none — add via GitHub UI or gh api)"}
107
+
108
+ Next: run /start-work to pick or create an issue and begin.
109
+ ```
110
+
111
+ ## Notes
112
+
113
+ - The workspace repo is the default target — no separate `workspace-{project}` repo needed.
114
+ - Issues track everything across all project repos in the workspace. Cross-repo work items live in one place.
115
+ - One-way integration: the tracker is the source of truth. Skills read and write via the adapter; nothing else reflects tracker state locally.
116
+ - If `gh auth login` later expires, skill flows will surface `gh` errors — re-run `gh auth login` and try again.
117
+ - Adding a new backend: write an adapter module at `.claude/scripts/trackers/{type}.mjs` implementing the interface in `interface.mjs`, then add a case in the `createTracker` switch statement.
@@ -0,0 +1,234 @@
1
+ ---
2
+ name: start-work
3
+ description: Begin or resume a work session. Creates a self-contained work-sessions/{name}/ folder containing the workspace worktree and nested project worktrees. Accepts optional parameter "handoff" or "blank".
4
+ ---
5
+
6
+ # Start Work
7
+
8
+ Begin or resume a persistent work session. Each session lives in its own `work-sessions/{name}/` folder containing one workspace worktree, nested project worktrees, and a unified `session.md` tracker. Sessions can run in parallel from separate terminals.
9
+
10
+ ## Parameters
11
+ - `/start-work` (no param) — list your active sessions, then resume or start new
12
+ - `/start-work blank` — start new work from scratch
13
+ - `/start-work handoff` — list shared context to resume from
14
+ - `/start-work all` — list active sessions across all users (for shared debugging or multi-user workspaces)
15
+
16
+ ## Flow: No Parameter
17
+
18
+ 1. Read the current user from `.claude/settings.local.json` → `workspace.user`. If unset, behave as `/start-work all` (no user filter). If the user invoked `/start-work all`, also skip filtering.
19
+ 2. Walk `work-sessions/` — each `work-sessions/{name}/workspace/session.md` is one session. Read frontmatter for `status`, `description`, `branch`, `repos`, and `user`.
20
+ 3. Filter to sessions whose `status` is `active` or `paused`. When a current user is known and the user did not pass `all`, additionally filter to sessions whose `user` field matches the current user (or is missing — unscoped legacy sessions stay visible to everyone).
21
+ 4. If matching sessions exist, present them:
22
+ ```
23
+ Your active work sessions:
24
+ 1. migrate-tool (active, last chat ended 2h ago)
25
+ "Rewriting the migration module"
26
+ Branch: bugfix/migrate-rewrite | Repos: my-app
27
+
28
+ [N] Start something new
29
+
30
+ Which one?
31
+ ```
32
+ 5. User picks one → resume flow
33
+ 6. User picks "new" → blank flow
34
+ 7. If no matching sessions exist but other users have active/paused sessions, note it briefly before falling through to `blank`: "No active sessions for you. {N} session(s) belong to other users — run `/start-work all` to see them." If no sessions exist at all, proceed silently as `blank`.
35
+
36
+ ## Flow: Resume
37
+
38
+ 1. Read the selected session tracker at `work-sessions/{name}/workspace/session.md`
39
+ 2. Verify worktrees exist:
40
+ - Workspace: `work-sessions/{name}/workspace/`
41
+ - For each repo in `repos:` frontmatter: `work-sessions/{name}/workspace/repos/{repo}/`
42
+ - If any are missing, recreate from the branch
43
+ 3. The session-start hook automatically registers each chat in the session tracker's `chatSessions` frontmatter when Claude opens in a worktree. Verify the current chat is registered — if not (e.g., the hook didn't fire), add an entry manually via the session-frontmatter helper.
44
+
45
+ Each `chatSessions` entry has this shape:
46
+ ```yaml
47
+ - id: {uuid}
48
+ names: [{name-if-any}]
49
+ started: {iso-timestamp}
50
+ ended: null
51
+ ```
52
+ - `id` is the authoritative identifier — the UUID from Claude Code's session. The session-start hook gets it from `input.session_id`.
53
+ - `names` is a list of all names the chat has had (users can rename). Append, never replace.
54
+ - `ended` is set by the session-end hook when the chat closes.
55
+ 4. Update the tracker `status:` to `active` if it was `paused`
56
+ 5. Run history reconstruction (see below)
57
+ 6. Tell user: "Resuming {name}. Work from `work-sessions/{name}/workspace/`."
58
+
59
+ ### History Reconstruction
60
+
61
+ On resume, check for uncaptured work from previous chats:
62
+
63
+ 1. Read the session tracker's `chatSessions` list
64
+ 2. For the most recent ended chat, use its `id` field (UUID) to locate the conversation log at `~/.claude/projects/{project-path}/{id}.jsonl`
65
+ 3. Check if the session.md body was updated after that chat ended
66
+ 4. If there's a gap (conversation log has content newer than the body's last update): scan the log and generate a summary of decisions, progress, and context
67
+ 5. Append the summary to the session.md body's `## Progress` section (or create one if it doesn't exist)
68
+ 6. Tell user: "Found uncaptured work from your last chat. Updated the session tracker."
69
+
70
+ If no gap is found, skip silently.
71
+
72
+ ## Flow: Blank (new session)
73
+
74
+ 1. **Check for a configured tracker.** Read `workspace.tracker` from `workspace.json`.
75
+
76
+ 2. **If no tracker is configured:** Ask: "No tracker configured. Want to run `/setup-tracker` first, or start a blank session (no issue linkage)?" If setup-tracker: invoke that skill, then re-enter this flow. If blank: proceed to the description-only path (step 6 below) with no `workItem:` linkage.
77
+
78
+ 3. **Fetch the candidate list via the adapter.** Build the adapter and pull two lists — issues assigned to the current user first, falling back to all unassigned issues if the assigned list is empty:
79
+ ```javascript
80
+ import { createTracker } from './.claude/scripts/trackers/interface.mjs';
81
+ import { readFileSync } from 'node:fs';
82
+ const ws = JSON.parse(readFileSync('workspace.json', 'utf-8'));
83
+ const tracker = createTracker(ws.workspace.tracker);
84
+ const assigned = await tracker.listAssignedToMe();
85
+ const candidates = assigned.length > 0 ? assigned : await tracker.listUnassigned();
86
+ const fallbackNote = assigned.length === 0 ? '(fallback — no issues assigned to you; showing unassigned)' : '';
87
+ ```
88
+
89
+ 4. **Present the list.** Group by milestone when the adapter provides one; sort by priority label (P1 before P2 before P3) within each group:
90
+ ```
91
+ {fallbackNote}
92
+ Backlog:
93
+ 1. [P1 bug] Auth timeout on mobile (gh:3)
94
+ 2. [P1 feat] JWT refresh logic (gh:8)
95
+
96
+ v0.1:
97
+ 3. [P2 feat] Full-text search (gh:5)
98
+
99
+ [N] Something new
100
+
101
+ Which one, or describe something new?
102
+ ```
103
+ Accept a number or "N".
104
+
105
+ 5. **User picked an existing issue.**
106
+ - If it came from the unassigned fallback list, atomically claim it:
107
+ ```javascript
108
+ try {
109
+ await tracker.claim(issue.id);
110
+ } catch (e) {
111
+ if (e.code === 'ALREADY_ASSIGNED') {
112
+ console.log(`${issue.id} was just claimed by ${e.assignees.join(', ')}. Refreshing list.`);
113
+ // Re-enter step 3 — someone else grabbed the ticket between fetch and claim.
114
+ return restart();
115
+ }
116
+ throw e;
117
+ }
118
+ ```
119
+ - If it came from the assigned-to-me list, skip the claim call (already mine).
120
+ - Generate the session name from the issue title (kebab-case slug, max ~40 chars).
121
+ - Remember `workItem: {issue.id}` for the session tracker.
122
+
123
+ 6. **User picked "Something new" (or fell through from step 2 with no tracker).**
124
+ - Ask for a description, type (`bug` / `feat` / `chore`), priority (`P1` / `P2` / `P3`), optional milestone.
125
+ - If a tracker is configured, create the issue and self-assign:
126
+ ```javascript
127
+ const newIssue = await tracker.createIssue({
128
+ title: description,
129
+ body: `Created at /start-work by ${user}.`,
130
+ labels: [type, priority],
131
+ milestone: milestone || null,
132
+ });
133
+ await tracker.claim(newIssue.id);
134
+ ```
135
+ Remember `workItem: {newIssue.id}` for the session tracker.
136
+ - If no tracker: proceed without a `workItem:` linkage — the session is a pure blank.
137
+
138
+ 7. **Pick repo(s)** — present numbered list from workspace.json, allow multi-select (e.g., `1,3` or `all`).
139
+
140
+ 8. **Propose branch:** `{prefix}/{session-name}` where prefix comes from type (`feature/` for feat, `bugfix/` for bug, `chore/` for chore). Wait for confirmation.
141
+
142
+ ### Create work session
143
+
144
+ Run the helper script:
145
+ ```bash
146
+ node .claude/scripts/create-work-session.mjs \
147
+ --session-name "{session-name}" \
148
+ --branch "{branch}" \
149
+ --repo "{repo1},{repo2}" \
150
+ --user "{user}" \
151
+ --description "{description}"
152
+ ```
153
+
154
+ The script creates:
155
+ - Session folder at `work-sessions/{session-name}/`
156
+ - Workspace worktree at `work-sessions/{session-name}/workspace/` with a real `repos/` directory inside
157
+ - Project worktree per repo nested at `work-sessions/{session-name}/workspace/repos/{repo}/`
158
+ - Unified session tracker at `work-sessions/{session-name}/workspace/session.md` (frontmatter + body)
159
+ - Active-session pointer at `work-sessions/{session-name}/workspace/.claude/.active-session.json`
160
+ - Copies `settings.local.json` into the worktree if it exists at the workspace root
161
+
162
+ If a `workItem:` was set in step 5 or 6, write it into the tracker's frontmatter via the session-frontmatter helper after creation. This is what `/pause-work` and `/complete-work` use to locate the linked issue.
163
+
164
+ Register this chat in the tracker's `chatSessions` frontmatter. For new sessions, the session-start hook has already fired (before /start-work was invoked) but the session folder didn't exist yet. Find the current chat's UUID from the most recently modified `.jsonl` file in `~/.claude/projects/{project-path}/` and add the entry manually via the session-frontmatter helper. Subsequent chats on this session will be registered automatically by the hook.
165
+
166
+ The tracker already reflects the correct state — assignment happened in step 5 or 6 via `adapter.claim()`. Do not write to any local file mirror. There is no `open-work.md`.
167
+
168
+ ### Capture prior conversation context
169
+
170
+ If brainstorming, spec writing, or design discussion happened in this conversation before `/start-work` was called, that reasoning needs to be captured into the session tracker body. Otherwise it will be lost when the conversation ends and `/complete-work` will produce thin release notes.
171
+
172
+ Check: has the current conversation included substantive discussion (design decisions, requirements exploration, approach selection) before this point?
173
+
174
+ If yes:
175
+ 1. Summarize the prior discussion — key decisions, requirements established, approaches chosen/rejected, constraints identified
176
+ 2. Write the summary into `work-sessions/{session-name}/workspace/session.md`'s body, in a `## Pre-session context` or `## Progress` section
177
+ 3. Auto-commit from inside the worktree so the capture lands on the session branch:
178
+ ```bash
179
+ cd work-sessions/{session-name}/workspace
180
+ git add session.md
181
+ git commit -m "chore: capture pre-session discussion for {session-name}"
182
+ ```
183
+
184
+ If no prior discussion: skip silently.
185
+
186
+ Tell user: "Work session started. Work from `work-sessions/{session-name}/workspace/`."
187
+
188
+ ### Add repo to active session
189
+
190
+ If there's an active session and the user wants to add a repo (explicitly or prompted by repo-write-detection):
191
+
192
+ 1. Confirm: "Add {repo} to the current session '{session-name}'?"
193
+ 2. Run the helper script:
194
+ ```bash
195
+ node .claude/scripts/add-repo-to-session.mjs \
196
+ --session-name "{session-name}" \
197
+ --repo "{repo}"
198
+ ```
199
+ 3. Tell user: "Added {repo}. Worktree at `work-sessions/{session-name}/workspace/repos/{repo}/`."
200
+
201
+ ### Stale worktree check
202
+
203
+ Before creating a new session, scan for existing sessions:
204
+ ```bash
205
+ ls work-sessions/ 2>/dev/null
206
+ ```
207
+ If stale sessions exist (no recent commits on the branch, no open PR, tracker `status` is `active` but worktrees are gone):
208
+ - "You have existing sessions for {names}. Clean up? [y/N]"
209
+ - If yes: run cleanup script for each
210
+
211
+ ### Next steps
212
+
213
+ If superpowers-workflow rule is active: run mandatory research phase, then invoke brainstorming skill.
214
+ If not: ask "Ready to start implementing, or want to brainstorm first?"
215
+
216
+ ## Flow: Retroactive (called mid-session)
217
+
218
+ When /start-work is called after work has already begun:
219
+
220
+ 1. Detect uncommitted changes in `repos/` or `shared-context/`
221
+ 2. "It looks like you've already been working. Let me formalize this."
222
+ 3. If changes are on a default branch: stash → create session → pop stash
223
+ 4. If changes are already on a feature branch: create workspace worktree and nest the existing project worktree(s) under it, or create a fresh session if the work is small enough to re-apply
224
+ 5. Summarize: "Formalized as work session: {name}. Work from `work-sessions/{name}/workspace/`."
225
+
226
+ ## Notes
227
+ - All repos (workspace + project repos) get the same branch name for traceability
228
+ - Each session lives in a single self-contained folder at `work-sessions/{name}/`
229
+ - The workspace worktree contains a real `repos/` directory with nested project worktrees — no symlink
230
+ - `session.md` is the single source of truth for session state: frontmatter is machine state (status, branch, chatSessions, workItem), body is human content (decisions, progress)
231
+ - The `workItem:` field in session frontmatter holds the adapter-prefixed issue ID (e.g., `gh:42`) — the tracker itself is authoritative for status, assignment, and labels
232
+ - Session trackers, specs, and plans live at the top of the session worktree and are tracked on the session branch. Pushing the branch carries durable session thinking across machines. `/complete-work` removes them from the branch before the final PR so main's top level stays free of session artifacts
233
+ - Worktrees and local artifacts are gitignored — recreate them on first resume on each machine
234
+ - Auto-committing session state is a workflow artifact — this intentionally bypasses normal commit conventions
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: sync-work
3
+ description: Push branches without ceremony — all project and workspace repos. No PR, no status change, no forced capture. Use for backing up work in progress.
4
+ ---
5
+
6
+ # Sync
7
+
8
+ Push current branches to remote for all project repos and the workspace repo. Lightest-touch backup — no PRs, no lifecycle changes, no forced context capture.
9
+
10
+ ## Flow
11
+
12
+ **Step 1: Detect active branches**
13
+ ```bash
14
+ # Workspace worktree
15
+ cd work-sessions/{session-name}/workspace
16
+ git branch --show-current
17
+
18
+ # Project worktree(s) — for each repo in the session tracker's repos:
19
+ git -C work-sessions/{session-name}/workspace/repos/{repo} branch --show-current
20
+ ```
21
+
22
+ **Step 2: Check for uncommitted changes**
23
+ For each repo in the session tracker's `repos:` list plus the workspace:
24
+ ```bash
25
+ cd work-sessions/{session-name}/workspace/repos/{repo}
26
+ git status --short
27
+ ```
28
+ If uncommitted changes exist: "You have uncommitted changes in {repo}. Commit before syncing? [Y/n]"
29
+ If yes: ask for a commit message or suggest one based on the changes.
30
+ If no: skip that repo (can't push uncommitted work).
31
+
32
+ **Step 3: Check for remotes**
33
+ For each repo in the session tracker's `repos:`:
34
+ ```bash
35
+ cd work-sessions/{session-name}/workspace/repos/{repo}
36
+ git remote -v
37
+ ```
38
+ If no remote: "No remote configured for {repo}. Want me to create one on GitHub, or provide a URL?"
39
+ Create via `gh repo create` or add the provided URL. Never silently skip.
40
+
41
+ **Step 4: Push**
42
+ For each repo with committed changes and a remote:
43
+ ```bash
44
+ cd work-sessions/{session-name}/workspace/repos/{repo}
45
+ git push -u origin {branch-name}
46
+ ```
47
+
48
+ Then push the workspace repo from the workspace worktree:
49
+ ```bash
50
+ cd work-sessions/{session-name}/workspace
51
+ git push -u origin {branch-name}
52
+ ```
53
+
54
+ The session-branch top-level files (`session.md`, `design-*.md`, `plan-*.md`) ride along with the workspace push — they live on the session branch, not on main, so pushing the branch is how durable session thinking reaches another machine.
55
+ Report per repo: "Synced: {repo} ({branch-name}) pushed to origin."
56
+
57
+ **Step 5: Optionally offer capture**
58
+ "Want to /braindump or /handoff while syncing? [n/Y]"
59
+ Default is no — /sync-work is about backing up, not capturing. But the offer is there.
60
+
61
+ ## Three Intents, Three Skills
62
+
63
+ | Skill | Intent | What happens |
64
+ |---|---|---|
65
+ | /pause-work | Stopping, someone else might pick up | Capture + push + draft PR + mark paused |
66
+ | /complete-work | Done with this branch | Synthesize + push + real PR + resolve context |
67
+ | /sync-work | Still working, just backing up | Push + no PR + no status change |
68
+
69
+ ## Notes
70
+ - No PRs created — this is a checkpoint, not a milestone
71
+ - No lifecycle changes — context stays `active`
72
+ - All repos pushed if they have branches with changes
73
+ - Safe to run repeatedly — just pushes latest commits