@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,242 @@
1
+ #!/usr/bin/env node
2
+ // Unit tests for session-frontmatter.mjs
3
+ // Run: node template/.claude/lib/session-frontmatter.test.mjs
4
+ import {
5
+ parseSessionContent,
6
+ updateSessionContent,
7
+ } from './session-frontmatter.mjs';
8
+
9
+ let failed = 0;
10
+ let passed = 0;
11
+
12
+ function assert(cond, msg) {
13
+ if (cond) {
14
+ passed++;
15
+ } else {
16
+ failed++;
17
+ console.error(` FAIL: ${msg}`);
18
+ }
19
+ }
20
+
21
+ function assertEq(actual, expected, msg) {
22
+ const a = JSON.stringify(actual);
23
+ const e = JSON.stringify(expected);
24
+ if (a === e) {
25
+ passed++;
26
+ } else {
27
+ failed++;
28
+ console.error(` FAIL: ${msg}\n expected: ${e}\n actual: ${a}`);
29
+ }
30
+ }
31
+
32
+ const SAMPLE = `---
33
+ type: session-tracker
34
+ name: fix-auth
35
+ description: Fix the auth timeout on mobile
36
+ status: active
37
+ branch: bugfix/fix-auth
38
+ created: 2026-04-13T05:33:50.000Z
39
+ user: alice
40
+ repos:
41
+ - my-app
42
+ - my-api
43
+ workItem: 3
44
+ chatSessions:
45
+ - id: aa3c952e-dbff-4055-8bcc-e5f217618d57
46
+ names: [pickup-from-braindump]
47
+ started: 2026-04-13T05:33:50.000Z
48
+ ended: 2026-04-13T07:12:00.000Z
49
+ - id: bb4d063e-ec00-4166-cc71-cd3d3d4628a1
50
+ names: []
51
+ started: 2026-04-13T08:00:00.000Z
52
+ ended: null
53
+ author: alice
54
+ updated: 2026-04-13
55
+ ---
56
+
57
+ # Work Session: fix-auth
58
+
59
+ Brief one-liner.
60
+
61
+ ## Progress
62
+
63
+ Some prose.
64
+ `;
65
+
66
+ // === Test 1: parse all field types ===
67
+ console.log('Test 1: parse all field types');
68
+ {
69
+ const parsed = parseSessionContent(SAMPLE);
70
+ assertEq(parsed.fields.type, 'session-tracker', 'type');
71
+ assertEq(parsed.fields.name, 'fix-auth', 'name');
72
+ assertEq(parsed.fields.description, 'Fix the auth timeout on mobile', 'description');
73
+ assertEq(parsed.fields.status, 'active', 'status');
74
+ assertEq(parsed.fields.branch, 'bugfix/fix-auth', 'branch');
75
+ assertEq(parsed.fields.created, '2026-04-13T05:33:50.000Z', 'created (ISO timestamp unquoted)');
76
+ assertEq(parsed.fields.workItem, 3, 'workItem (integer)');
77
+ assertEq(parsed.fields.repos, ['my-app', 'my-api'], 'repos (flat list)');
78
+ assertEq(parsed.fields.chatSessions.length, 2, 'chatSessions length');
79
+ assertEq(parsed.fields.chatSessions[0].id, 'aa3c952e-dbff-4055-8bcc-e5f217618d57', 'chat 0 id');
80
+ assertEq(parsed.fields.chatSessions[0].names, ['pickup-from-braindump'], 'chat 0 names');
81
+ assertEq(parsed.fields.chatSessions[0].started, '2026-04-13T05:33:50.000Z', 'chat 0 started');
82
+ assertEq(parsed.fields.chatSessions[0].ended, '2026-04-13T07:12:00.000Z', 'chat 0 ended');
83
+ assertEq(parsed.fields.chatSessions[1].id, 'bb4d063e-ec00-4166-cc71-cd3d3d4628a1', 'chat 1 id');
84
+ assertEq(parsed.fields.chatSessions[1].names, [], 'chat 1 names (empty inline list)');
85
+ assertEq(parsed.fields.chatSessions[1].ended, null, 'chat 1 ended (null)');
86
+ assert(parsed.body.startsWith('\n# Work Session'), 'body starts with blank line + H1');
87
+ assert(parsed.body.endsWith('Some prose.\n'), 'body ends with trailing newline');
88
+ }
89
+
90
+ // === Test 2: lossless byte-identity on no-op update ===
91
+ console.log('Test 2: lossless byte-identity on no-op update');
92
+ {
93
+ const unchanged = updateSessionContent(SAMPLE, {});
94
+ assertEq(unchanged, SAMPLE, 'no-op update preserves content byte-identical');
95
+ }
96
+
97
+ // === Test 3: update single scalar field ===
98
+ console.log('Test 3: update single scalar field');
99
+ {
100
+ const updated = updateSessionContent(SAMPLE, { status: 'paused' });
101
+ const parsed = parseSessionContent(updated);
102
+ assertEq(parsed.fields.status, 'paused', 'status changed');
103
+ assertEq(parsed.fields.name, 'fix-auth', 'name preserved');
104
+ assertEq(parsed.fields.repos, ['my-app', 'my-api'], 'repos preserved');
105
+ assertEq(parsed.fields.chatSessions.length, 2, 'chatSessions preserved');
106
+ // Verify every other line is byte-identical
107
+ const origLines = SAMPLE.split('\n');
108
+ const newLines = updated.split('\n');
109
+ assertEq(newLines.length, origLines.length, 'same number of lines');
110
+ for (let i = 0; i < origLines.length; i++) {
111
+ if (origLines[i].startsWith('status:')) {
112
+ assertEq(newLines[i], 'status: paused', `line ${i} is new status`);
113
+ } else {
114
+ assertEq(newLines[i], origLines[i], `line ${i} preserved`);
115
+ }
116
+ }
117
+ }
118
+
119
+ // === Test 4: update chatSessions array (append a chat) ===
120
+ console.log('Test 4: update chatSessions array');
121
+ {
122
+ const parsed = parseSessionContent(SAMPLE);
123
+ const newChats = [...parsed.fields.chatSessions, {
124
+ id: 'cc5e174f-fd11-5277-dd82-de4e4e5739b2',
125
+ names: [],
126
+ started: '2026-04-13T09:00:00.000Z',
127
+ ended: null,
128
+ }];
129
+ const updated = updateSessionContent(SAMPLE, { chatSessions: newChats });
130
+ const reparsed = parseSessionContent(updated);
131
+ assertEq(reparsed.fields.chatSessions.length, 3, 'chatSessions now has 3 entries');
132
+ assertEq(reparsed.fields.chatSessions[2].id, 'cc5e174f-fd11-5277-dd82-de4e4e5739b2', 'new chat id');
133
+ assertEq(reparsed.fields.name, 'fix-auth', 'other fields preserved');
134
+ assertEq(reparsed.body, parsed.body, 'body preserved byte-identical');
135
+ }
136
+
137
+ // === Test 5: append a new field ===
138
+ console.log('Test 5: append a new field');
139
+ {
140
+ const updated = updateSessionContent(SAMPLE, { newField: 'hello' });
141
+ const parsed = parseSessionContent(updated);
142
+ assertEq(parsed.fields.newField, 'hello', 'newField present');
143
+ assertEq(parsed.fields.name, 'fix-auth', 'existing field preserved');
144
+ }
145
+
146
+ // === Test 6: remove a field ===
147
+ console.log('Test 6: remove a field');
148
+ {
149
+ const updated = updateSessionContent(SAMPLE, { workItem: undefined });
150
+ const parsed = parseSessionContent(updated);
151
+ assertEq(parsed.fields.workItem, undefined, 'workItem removed');
152
+ assertEq(parsed.fields.user, 'alice', 'user preserved');
153
+ }
154
+
155
+ // === Test 7: update repos (flat list) ===
156
+ console.log('Test 7: update repos flat list');
157
+ {
158
+ const updated = updateSessionContent(SAMPLE, { repos: ['my-app', 'my-api', 'my-web'] });
159
+ const parsed = parseSessionContent(updated);
160
+ assertEq(parsed.fields.repos, ['my-app', 'my-api', 'my-web'], 'repos has 3 items');
161
+ assertEq(parsed.fields.chatSessions.length, 2, 'chatSessions preserved after repos update');
162
+ }
163
+
164
+ // === Test 8: empty repos ===
165
+ console.log('Test 8: empty repos');
166
+ {
167
+ const updated = updateSessionContent(SAMPLE, { repos: [] });
168
+ const parsed = parseSessionContent(updated);
169
+ assertEq(parsed.fields.repos, [], 'repos is empty');
170
+ }
171
+
172
+ // === Test 9: scalar with special chars (colon in branch name) ===
173
+ console.log('Test 9: scalar with special chars');
174
+ {
175
+ // Branch names with slashes should NOT be quoted
176
+ const sample = `---
177
+ branch: feature/worksessions-refactor
178
+ ---
179
+ body
180
+ `;
181
+ const parsed = parseSessionContent(sample);
182
+ assertEq(parsed.fields.branch, 'feature/worksessions-refactor', 'branch unquoted');
183
+ const noop = updateSessionContent(sample, {});
184
+ assertEq(noop, sample, 'no-op preserves unquoted slash');
185
+ }
186
+
187
+ // === Test 10: ISO timestamp round-trip ===
188
+ console.log('Test 10: ISO timestamp round-trip');
189
+ {
190
+ const sample = `---
191
+ created: 2026-04-13T05:33:50.000Z
192
+ ---
193
+ body
194
+ `;
195
+ const parsed = parseSessionContent(sample);
196
+ assertEq(parsed.fields.created, '2026-04-13T05:33:50.000Z', 'ISO timestamp parsed');
197
+ const updated = updateSessionContent(sample, { created: '2026-05-01T12:00:00.000Z' });
198
+ const reparsed = parseSessionContent(updated);
199
+ assertEq(reparsed.fields.created, '2026-05-01T12:00:00.000Z', 'ISO timestamp round-trip');
200
+ // Must not be quoted
201
+ assert(!updated.includes('"2026-05-01'), 'ISO timestamp not quoted on write');
202
+ }
203
+
204
+ // === Test 11: string that truly needs quoting ===
205
+ console.log('Test 11: string that truly needs quoting');
206
+ {
207
+ const sample = `---
208
+ title: hello
209
+ ---
210
+ body
211
+ `;
212
+ const updated = updateSessionContent(sample, { title: 'hello: world' });
213
+ assert(updated.includes('title: "hello: world"'), 'colon-space triggers quoting');
214
+ const reparsed = parseSessionContent(updated);
215
+ assertEq(reparsed.fields.title, 'hello: world', 'quoted value round-trips');
216
+ }
217
+
218
+ // === Test 12: body preservation with multiline content ===
219
+ console.log('Test 12: body preservation with multiline content');
220
+ {
221
+ const sample = `---
222
+ name: test
223
+ ---
224
+
225
+ # Heading
226
+
227
+ Paragraph with multiple lines.
228
+ And more lines.
229
+
230
+ - bullet 1
231
+ - bullet 2
232
+ `;
233
+ const noop = updateSessionContent(sample, {});
234
+ assertEq(noop, sample, 'multiline body preserved byte-identical');
235
+ const updated = updateSessionContent(sample, { name: 'changed' });
236
+ const parsed = parseSessionContent(updated);
237
+ assertEq(parsed.body.trim(), '# Heading\n\nParagraph with multiple lines.\nAnd more lines.\n\n- bullet 1\n- bullet 2', 'body intact after update');
238
+ }
239
+
240
+ // === Summary ===
241
+ console.log(`\n${passed} passed, ${failed} failed`);
242
+ if (failed > 0) process.exit(1);
@@ -0,0 +1,120 @@
1
+ # Recipe: Migrate from Notion
2
+
3
+ Migrate rules, memory, and handoffs from Notion pages into the claude-workspace template structure.
4
+
5
+ ## Prerequisites
6
+
7
+ - The workspace must have a working Notion MCP server configured in `.mcp.json`
8
+ - Run this recipe BEFORE removing the MCP server
9
+ - The scaffolder (`npx @ulysses-ai/create-workspace --init`) should have already been run to install the template structure
10
+
11
+ ## Detection
12
+
13
+ This recipe applies when:
14
+ - `.mcp.json` contains a Notion MCP server configuration
15
+ - `CLAUDE.md` (or `.bak`) references Notion page IDs for rules, memory, or handoffs
16
+
17
+ ## Steps
18
+
19
+ ### 1. Identify Notion pages
20
+
21
+ Read `CLAUDE.md.bak` (the pre-migration backup) to find Notion page references:
22
+ - Look for page IDs (32-character hex strings)
23
+ - Note the purpose of each page (rules, memory/context, handoffs)
24
+
25
+ ### 2. Extract rules
26
+
27
+ For each Notion page that contains rules/conventions:
28
+
29
+ ```
30
+ Fetch the page content using the Notion MCP server.
31
+ For each rule or convention section:
32
+ - Create a .claude/rules/{rule-name}.md file
33
+ - Use the section heading as the filename (kebab-case)
34
+ - If the rule is project-specific, make it mandatory (.md)
35
+ - If the rule is optional, use .md.skip
36
+ - Write the content as a coherent rule following the template format:
37
+ # Rule Name
38
+ {What the rule says}
39
+ ## Why
40
+ {Rationale if provided}
41
+ ```
42
+
43
+ ### 3. Extract memory and context
44
+
45
+ For each Notion page that contains project memory, context, or key decisions:
46
+
47
+ ```
48
+ Fetch the page content using the Notion MCP server.
49
+ Determine scope:
50
+ - Architecture decisions, tech stack, stable conventions → shared-context/locked/
51
+ - Active project state, current priorities → shared-context/{user}/
52
+ - Historical context no longer relevant → skip
53
+
54
+ For each section:
55
+ - Create a shared-context file with proper frontmatter:
56
+ ---
57
+ state: locked (or ephemeral)
58
+ lifecycle: active
59
+ type: promoted
60
+ topic: {section-topic}
61
+ author: {user}
62
+ updated: {today}
63
+ ---
64
+ - Write content adapted for the template format
65
+ - One topic per file — split large Notion pages into multiple files
66
+ ```
67
+
68
+ ### 4. Extract handoffs
69
+
70
+ For each Notion page that contains session handoffs or context transfers:
71
+
72
+ ```
73
+ Fetch the page content using the Notion MCP server.
74
+ For recent/active handoffs only (skip stale ones):
75
+ - Create shared-context/{user}/{handoff-name}.md
76
+ - Use handoff frontmatter format with type: handoff
77
+ - Extract: status, key decisions, next steps, open questions
78
+ - Set lifecycle: active (or paused if the work is suspended)
79
+ ```
80
+
81
+ ### 5. Preserve local preferences
82
+
83
+ Check `CLAUDE.md.bak` for local preferences that aren't Notion-dependent:
84
+ - Repo paths, coding conventions, project-specific notes
85
+ - Add these to appropriate places:
86
+ - Coding conventions → `.claude/rules/` (new rule file)
87
+ - Project notes → `shared-context/locked/` or `shared-context/{user}/`
88
+ - Repo paths → already in `workspace.json`
89
+
90
+ ### 6. Remove Notion dependency
91
+
92
+ After all content is extracted and verified:
93
+
94
+ ```bash
95
+ # Back up and remove MCP config
96
+ mv .mcp.json .mcp.json.bak
97
+
98
+ # Remove CLAUDE.md backup (original Notion-fetching version)
99
+ rm CLAUDE.md.bak
100
+ ```
101
+
102
+ Verify the workspace works without Notion:
103
+ - Start a new Claude Code session
104
+ - Confirm SessionStart hook surfaces the migrated context
105
+ - Confirm rules are loaded (check /context)
106
+ - Confirm skills work
107
+
108
+ ### 7. Commit
109
+
110
+ ```bash
111
+ git add .claude/rules/ shared-context/
112
+ git commit -m "chore: migrate Notion content to local files"
113
+ ```
114
+
115
+ ## Notes
116
+
117
+ - Don't try to migrate everything — only active, relevant content
118
+ - Stale Notion handoffs can be skipped. If it's more than a few weeks old and not referenced, it's dead.
119
+ - Large Notion pages should be split into multiple focused files (one topic per file)
120
+ - The migration is one-way — once verified, the Notion pages become the archive, not the source of truth
@@ -0,0 +1,32 @@
1
+ # Agent Rules
2
+
3
+ Activate this rule to enforce conventions specifically for subagent behavior.
4
+
5
+ ## All Agents
6
+
7
+ - Follow the coherent-revisions rule — rewrite sections from scratch, never inject
8
+ - Report status using the standard protocol: DONE / DONE_WITH_CONCERNS / BLOCKED / NEEDS_CONTEXT
9
+ - If anything is ambiguous, ask before proceeding — don't guess
10
+ - Stay within the scope of the task description — don't explore beyond what was asked
11
+
12
+ ## Implementer Agents
13
+
14
+ - Receive full task text in the prompt — never read plan files directly
15
+ - Keep changes minimal and focused on the assigned task
16
+ - Don't restructure code outside the task scope
17
+ - Commit frequently with conventional commit messages
18
+ - It is always OK to say "this is too complex for a single task"
19
+
20
+ ## Reviewer Agents
21
+
22
+ - Review only what changed — don't comment on pre-existing code
23
+ - Don't suggest improvements outside the diff scope
24
+ - Be specific: file, line, what's wrong, what to do instead
25
+ - Style preferences defer to linters/formatters — don't enforce personal taste
26
+
27
+ ## Researcher Agents
28
+
29
+ - Never modify files — read-only operations only
30
+ - Search thoroughly before reporting "not found"
31
+ - Report with exact file paths and line numbers
32
+ - Flag contradictions between code and documentation
@@ -0,0 +1,15 @@
1
+ # Cloud Infrastructure
2
+
3
+ Activate this rule if the project uses cloud resources (AWS, GCP, Azure, etc.).
4
+
5
+ ## Code-First Rule
6
+
7
+ - All changes to cloud resources go through code and CI/CD
8
+ - Never recommend or execute direct cloud provider changes — no console edits, no CLI commands against live resources
9
+ - If the user asks to do something directly in the cloud provider, warn about drift and recommend the code-first path
10
+
11
+ ## Environment Portability
12
+
13
+ - Never hardcode account IDs, resource ARNs/URIs, bucket names, distribution IDs, or environment-specific values
14
+ - All environment-specific values come from environment config files or runtime CI/CD variables
15
+ - This applies to infrastructure code, configuration files, workflow files, and function code
@@ -0,0 +1,24 @@
1
+ # Coherent Revisions
2
+
3
+ When revising any document or code, rewrite the affected section from start to finish so the result reads as a single coherent piece. Never patch, inject, or insert new content between existing paragraphs/blocks in a way that creates a stitched-together feel.
4
+
5
+ This applies to all written output:
6
+ - Project documentation
7
+ - Specs and design docs
8
+ - Code and logic changes including comments
9
+ - Shared context documents (handoffs, braindumps, locked context)
10
+ - Release notes
11
+ - Open questions
12
+ - Commit messages
13
+
14
+ ## Why
15
+
16
+ Injected revisions create fragmented, hard-to-follow output where the seams between old and new content are visible. Rewriting from start to finish produces output that flows naturally and reads as if written in one pass.
17
+
18
+ ## In Practice
19
+
20
+ - When updating a section of a document, rewrite the entire section — not just the changed sentences
21
+ - When updating a shared-context file, rewrite it as a fresh snapshot of current understanding
22
+ - When synthesizing multiple sources into release notes, write the narrative from scratch — don't concatenate
23
+ - When revising code with comments, ensure the comments tell a coherent story, not a changelog
24
+ - Small, isolated edits (fixing a typo, updating a single value) are fine — this rule targets substantive revisions
@@ -0,0 +1,13 @@
1
+ # Documentation
2
+
3
+ Activate this rule if the project maintains documentation that must stay in sync with code.
4
+
5
+ ## Doc-Code Consistency
6
+
7
+ - When a code change fixes a bug, corrects an API, or replaces a deprecated pattern, check whether any documentation references the old behavior
8
+ - If it does, update the documentation in the same session — code and docs must never contradict each other
9
+
10
+ ## No Unsolicited Docs
11
+
12
+ - Do not create documentation files (README.md, CONTRIBUTING.md, etc.) unless explicitly asked
13
+ - Never create documentation files (*.md) unless the user requests it
@@ -0,0 +1,34 @@
1
+ # Git Conventions
2
+
3
+ ## Branching
4
+
5
+ - Prefixes: `feature/`, `bugfix/`, `chore/`
6
+ - Names: kebab-case after prefix, no grouping/nesting
7
+ - Examples: `feature/ble-provisioning`, `bugfix/mqtt-reconnect`
8
+ - All branches merge to the repo's default branch
9
+ - Branch names should be unique — if revisiting previous work, distinguish the new branch name
10
+
11
+ ## Worktrees
12
+
13
+ - Work sessions get N+1 worktrees: one for the workspace, plus one per project repo
14
+ - Each session lives in a self-contained folder at `work-sessions/{session-name}/`
15
+ - The workspace worktree is at `work-sessions/{session-name}/workspace/`
16
+ - Project worktrees are nested inside the workspace worktree at `work-sessions/{session-name}/workspace/repos/{repo-name}/`
17
+ - Example: for a session `fix-auth` on branch `bugfix/fix-auth` touching repos `my-app` and `my-api`:
18
+ - `work-sessions/fix-auth/workspace/` — workspace worktree
19
+ - `work-sessions/fix-auth/workspace/repos/my-app/` — project worktree
20
+ - `work-sessions/fix-auth/workspace/repos/my-api/` — project worktree
21
+ - The workspace repo's `.gitignore` pattern `repos` (no trailing slash) covers both the workspace root's `repos/` and the nested `repos/` inside every worktree
22
+ - Source clones at `repos/{repo-name}/` (at the workspace root) stay on their default branch at all times
23
+ - Remove worktrees when the work session is completed — use the cleanup helper to enforce the mandatory teardown order (project worktrees first, then workspace worktree, then prune)
24
+
25
+ ## Branch Maintenance
26
+
27
+ - Before creating a PR, fetch and rebase onto the latest parent branch
28
+ - If conflicts arise during rebase, stop and present them to the user — do not auto-resolve
29
+
30
+ ## Commits
31
+
32
+ - Conventional commit format: `feat:`, `fix:`, `refactor:`, `chore:`, `docs:`
33
+ - Never amend commits unless explicitly asked
34
+ - Never force push unless explicitly asked
@@ -0,0 +1,56 @@
1
+ # Honest Pushback
2
+
3
+ Do not agree with the user just to be agreeable. Do not keep trying things that aren't working. Do not assume when you can verify. Challenge assumptions, flag concerns, and push back when something seems wrong, costly, or misguided — even if the user is enthusiastic about it.
4
+
5
+ ## What This Means
6
+
7
+ - If an approach has obvious downsides, say so before implementing
8
+ - If a design decision contradicts an earlier one, flag the contradiction
9
+ - If scope is creeping, name it: "This started as X but is becoming Y. Split?"
10
+ - If you don't know something, say so — don't fabricate confidence
11
+ - If the user's idea is good, a simple "that works" is enough — don't embellish with praise
12
+ - If you made a mistake, own it plainly — don't bury it in hedging language
13
+
14
+ ## No Retry Loops
15
+
16
+ When a fix attempt fails, do not immediately try a variation of the same approach. If you have tried a solution and it produced the same error or unexpected result twice, stop and:
17
+
18
+ 1. **State what you expected vs what happened.** Be specific — not "it didn't work" but "expected 200, got 403 with message X."
19
+ 2. **Identify what you don't understand.** What assumption is failing? Why is the result surprising?
20
+ 3. **Research the specific issue.** Read documentation, search for the error message, check source code. Use web search if local sources don't explain it.
21
+ 4. **Present your findings.** Tell the user what you learned and what you now think the actual cause is. Propose a solution based on understanding, not guessing.
22
+
23
+ This prevents cycling through variations of the same broken approach, wasting tokens on trial-and-error when reading the docs would take one turn, and the user having to say "stop and actually research this."
24
+
25
+ ## Verify, Don't Assume
26
+
27
+ When evidence is available to confirm or deny an assumption, check it before proceeding. Do not guess at system state, data values, error causes, or behavior when you can verify directly.
28
+
29
+ Sources to check before assuming:
30
+ - **Logs** — application logs, server logs, build output. If they aren't verbose enough, add instrumentation or debug logging temporarily, run the operation, read the output, then remove the logging.
31
+ - **Database** — query the actual data instead of assuming what's there.
32
+ - **UI/browser** — test the actual behavior instead of predicting what the user will see. Use browser tools, take screenshots, inspect network requests.
33
+ - **Runtime state** — add a console.log, print statement, or debugger breakpoint. Run it. Read the output.
34
+ - **API responses** — make the actual call instead of assuming the response shape.
35
+
36
+ **Before checking, ask the user:** "I want to verify {what} by {how}. Should I go ahead, or do you want me to just check without asking each time?"
37
+
38
+ If the user says to just check: remember this preference and verify proactively for the rest of the session without asking. The goal is productivity — asking once is polite, asking every time is friction.
39
+
40
+ **When this applies:**
41
+ - You're about to say "I think the issue is..." when you could check
42
+ - You're reasoning about what a function returns when you could call it
43
+ - You're guessing at database state when you could query it
44
+ - You're predicting UI behavior when you could test it
45
+ - You catch yourself writing "probably" or "likely" about something verifiable
46
+
47
+ ## What This Does NOT Mean
48
+
49
+ - Don't be contrarian for the sake of it — push back when there's substance, not as a personality trait
50
+ - Don't refuse to execute — voice the concern, then follow the user's decision
51
+ - Don't lecture — state the issue once, clearly, and move on
52
+ - Don't over-verify trivial things — use judgment about what's worth checking
53
+
54
+ ## Why
55
+
56
+ Sycophantic AI wastes time, erodes trust, and lets bad decisions through unchallenged. Retry loops burn tokens and frustrate everyone. Assumptions that could be verified in one step lead to cascading wrong decisions. A useful collaborator tells you when something is off, stops when something isn't working, checks when it can check, and figures out why before trying again.
@@ -0,0 +1,60 @@
1
+ # Local Dev Environment
2
+
3
+ Maintain a local-only document at `shared-context/locked/local-only-dev-environment.md` that captures machine-specific development context. This file is gitignored (local-only prefix) but positioned in locked for maximum visibility — Claude sees it every turn.
4
+
5
+ ## What to Record
6
+
7
+ When you discover any of the following during work, add it to the local dev environment doc:
8
+
9
+ - **Services & ports** — dev server URLs, database ports, API base URLs, queue endpoints
10
+ - **Credentials** — local dev passwords, API keys for dev/staging, test user accounts, tokens
11
+ - **CLI commands** — project-specific build/run/test commands, Docker invocations, migration commands
12
+ - **Environment variables** — required env vars and their local values, .env file locations
13
+ - **Paths** — local SDK paths, tool installations, config file locations, certificate paths
14
+ - **Infrastructure** — local Docker containers, dev database names, S3 bucket names for dev
15
+
16
+ ## How to Record
17
+
18
+ When you encounter a local development detail worth preserving:
19
+
20
+ 1. Check if `shared-context/locked/local-only-dev-environment.md` exists
21
+ 2. If not, create it with this structure:
22
+ ```markdown
23
+ ---
24
+ state: locked
25
+ type: reference
26
+ topic: local-dev-environment
27
+ updated: {today}
28
+ ---
29
+
30
+ # Local Dev Environment
31
+
32
+ Machine-specific development context. This file is gitignored — never shared.
33
+
34
+ ## Services & Ports
35
+
36
+ ## Credentials
37
+
38
+ ## CLI Commands
39
+
40
+ ## Environment Variables
41
+
42
+ ## Paths
43
+
44
+ ## Infrastructure
45
+ ```
46
+ 3. Add the new detail under the appropriate section
47
+ 4. Update the `updated:` date in frontmatter
48
+
49
+ ## When to Ask
50
+
51
+ - **Credentials:** Always ask before recording: "Save this credential to your local dev doc? (gitignored, never shared)" — even though it's local-only, confirm the user wants it persisted.
52
+ - **Everything else:** Record proactively when discovered. No need to ask — if you see the dev server is on port 3000, just add it.
53
+
54
+ ## When This Applies
55
+
56
+ - You run a command and see a port or URL in the output
57
+ - The user mentions "my API key is..." or "the database is at..."
58
+ - You read a .env file or docker-compose.yml and learn the local setup
59
+ - You troubleshoot a connection issue and discover the correct endpoint
60
+ - The user provides credentials for a dev service
@@ -0,0 +1,26 @@
1
+ # Memory Guidance
2
+
3
+ Guide Claude's auto-memory system for this workspace.
4
+
5
+ ## What to Auto-Remember
6
+
7
+ When working in this workspace, pay attention to and save memories about:
8
+ - Architecture decisions and their rationale
9
+ - Patterns that caused bugs or confusion
10
+ - User corrections about project conventions
11
+ - External system URLs, credentials locations, API quirks
12
+ - Workarounds for tooling issues
13
+
14
+ ## What NOT to Auto-Remember
15
+
16
+ - Temporary debugging state
17
+ - File contents (re-read them instead)
18
+ - Anything already captured in a shared-context file
19
+ - Anything documented in .claude/rules/
20
+
21
+ ## Session-Scoped vs Cross-Session
22
+
23
+ When a work session is active:
24
+ - Decisions and progress from this session → update the session tracker body at `work-sessions/{name}/workspace/session.md` (consumed by /complete-work)
25
+ - Patterns, corrections, and insights that apply beyond this session → auto-memory (persists across all sessions)
26
+ - Don't duplicate: if something is already in the session tracker, don't also save it to auto-memory
@@ -0,0 +1,24 @@
1
+ # Product Integrity
2
+
3
+ Guard against personal biases, habits, and compensating mechanisms being encoded into product decisions. The tool should serve its users, not just its author.
4
+
5
+ ## The Test
6
+
7
+ Before promoting any convention, feature, or rule: **would this help someone who doesn't share your specific problem?** If the answer is unclear, keep it local-only or user-scoped until external feedback confirms the value.
8
+
9
+ ## Detection
10
+
11
+ - When a proposed feature directly mirrors a personal struggle, flag it: "This solves your specific problem. Is it general enough to ship?"
12
+ - When a convention assumes a particular working style, name it: "This assumes {style}. Does it help or constrain someone with a different approach?"
13
+ - When "I need this" is the primary justification, push for a second reason that isn't personal
14
+
15
+ ## Response
16
+
17
+ - State the concern once
18
+ - Suggest keeping it local-only or user-scoped as a default
19
+ - If the user confirms it's general-purpose, proceed
20
+ - Don't block work — flag, then follow the decision
21
+
22
+ ## Why
23
+
24
+ Tools built by their own users are especially vulnerable to this. A feature that compensates for one person's weakness becomes a rigid process that frustrates everyone else. The antidote is separating "this helps me" from "this helps users" — and defaulting to personal until proven general.