@ulysses-ai/create-workspace 0.14.0-beta.3 → 0.15.0-beta.1

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 (50) hide show
  1. package/lib/init.mjs +12 -25
  2. package/lib/scaffold.mjs +3 -2
  3. package/package.json +1 -1
  4. package/template/.claude/agents/reviewer.md +1 -1
  5. package/template/.claude/hooks/pre-compact.mjs +1 -1
  6. package/template/.claude/hooks/repo-write-detection.mjs +2 -2
  7. package/template/.claude/hooks/session-start.mjs +10 -7
  8. package/template/.claude/hooks/subagent-start.mjs +3 -3
  9. package/template/.claude/recipes/migrate-from-notion.md +6 -6
  10. package/template/.claude/rules/coherent-revisions.md +2 -2
  11. package/template/.claude/rules/local-dev-environment.md.skip +2 -2
  12. package/template/.claude/rules/memory-guidance.md +23 -14
  13. package/template/.claude/rules/token-economics.md.skip +2 -2
  14. package/template/.claude/rules/work-item-tracking.md +1 -1
  15. package/template/.claude/rules/workspace-structure.md +36 -15
  16. package/template/.claude/scripts/build-workspace-context.mjs +712 -0
  17. package/template/.claude/scripts/capture-context.mjs +217 -0
  18. package/template/.claude/scripts/generate-claude-local.mjs +104 -0
  19. package/template/.claude/scripts/migrate-canonical-priority.mjs +108 -0
  20. package/template/.claude/scripts/migrate-open-work.mjs +1 -1
  21. package/template/.claude/scripts/migrate-to-workspace-context.mjs +520 -0
  22. package/template/.claude/scripts/sweep-references.mjs +177 -0
  23. package/template/.claude/skills/aside/SKILL.md +49 -44
  24. package/template/.claude/skills/braindump/SKILL.md +25 -19
  25. package/template/.claude/skills/build-docs-site/SKILL.md +1 -1
  26. package/template/.claude/skills/build-docs-site/checklists/framing.md +1 -1
  27. package/template/.claude/skills/complete-work/SKILL.md +91 -3
  28. package/template/.claude/skills/handoff/SKILL.md +31 -30
  29. package/template/.claude/skills/maintenance/SKILL.md +90 -22
  30. package/template/.claude/skills/pause-work/SKILL.md +1 -1
  31. package/template/.claude/skills/promote/SKILL.md +18 -8
  32. package/template/.claude/skills/release/SKILL.md +20 -13
  33. package/template/.claude/skills/start-work/SKILL.md +1 -1
  34. package/template/.claude/skills/workspace-init/SKILL.md +12 -12
  35. package/template/.claude/skills/workspace-update/SKILL.md +7 -1
  36. package/template/CLAUDE.md.tmpl +4 -3
  37. package/template/_gitignore +1 -0
  38. package/template/workspace.json.tmpl +3 -2
  39. package/template/.claude/hooks/_bash-output-advisory.test.mjs +0 -88
  40. package/template/.claude/hooks/_utils.test.mjs +0 -99
  41. package/template/.claude/lib/freshness.test.mjs +0 -175
  42. package/template/.claude/lib/registry-check.test.mjs +0 -130
  43. package/template/.claude/lib/session-frontmatter.test.mjs +0 -242
  44. package/template/.claude/scripts/build-shared-context-index.mjs +0 -212
  45. package/template/.claude/scripts/build-shared-context-index.test.mjs +0 -318
  46. package/template/.claude/scripts/migrate-claude-md-freshness-include.test.mjs +0 -54
  47. package/template/.claude/scripts/migrate-session-layout.test.mjs +0 -144
  48. package/template/.claude/scripts/sync-tasks.test.mjs +0 -350
  49. package/template/.claude/scripts/trackers/github-issues.test.mjs +0 -190
  50. package/template/.claude/scripts/trackers/interface.test.mjs +0 -40
package/lib/init.mjs CHANGED
@@ -50,37 +50,24 @@ export async function initWorkspace(targetDir) {
50
50
  console.log(` Installed ${dir}`);
51
51
  }
52
52
 
53
- // Create shared-context structure. We always want shared-context/ and
54
- // shared-context/locked/ to exist after init, even if the payload ships
55
- // no files for them yet locked/ is referenced by CLAUDE.md.tmpl via
56
- // the @shared-context/locked/ import directive.
57
- const payloadContext = join(payloadDir, 'shared-context');
58
- const targetContext = join(targetDir, 'shared-context');
59
- if (existsSync(payloadContext) && !existsSync(targetContext)) {
60
- cpSync(payloadContext, targetContext, { recursive: true });
61
- console.log(' Created shared-context/');
62
- }
63
- ensureDir(join(targetDir, 'shared-context', 'locked'));
53
+ // Ensure workspace-context/locked/ exists. canonical.md and index.md are
54
+ // generated later by /workspace-init via build-workspace-context.mjs;
55
+ // this just guarantees the destination directory is in place.
56
+ ensureDir(join(targetDir, 'workspace-context', 'locked'));
64
57
 
65
58
  // Everything else (repos/, work-sessions/, workspace-scratchpad/) is
66
59
  // lazy-created by scripts and hooks when they first need to write.
67
60
  // We intentionally do NOT pre-create these dirs — they get made on demand.
68
61
 
69
- // Create workspace.json if missing
62
+ // Create workspace.json from template if missing. Single source of truth
63
+ // for shape is template/workspace.json.tmpl — mirrors the CLAUDE.md.tmpl
64
+ // handling below.
70
65
  if (!existsSync(workspaceJsonPath)) {
71
- writeFileSync(workspaceJsonPath, JSON.stringify({
72
- workspace: {
73
- name,
74
- templateVersion: toVersion,
75
- scratchpadDir: 'workspace-scratchpad',
76
- workSessionsDir: 'work-sessions',
77
- sharedContextDir: 'shared-context',
78
- releaseNotesDir: 'release-notes',
79
- subagentContextMaxBytes: 10240,
80
- greeting: `Welcome back to ${name}.`,
81
- },
82
- repos: {},
83
- }, null, 2) + '\n');
66
+ const wsTmplPath = join(payloadDir, 'workspace.json.tmpl');
67
+ const wsTmpl = readFileSync(wsTmplPath, 'utf-8').replace(/\{\{project-name\}\}/g, name);
68
+ const workspaceConfig = JSON.parse(wsTmpl);
69
+ workspaceConfig.workspace.templateVersion = toVersion;
70
+ writeFileSync(workspaceJsonPath, JSON.stringify(workspaceConfig, null, 2) + '\n');
84
71
  console.log(' Created workspace.json');
85
72
  }
86
73
 
package/lib/scaffold.mjs CHANGED
@@ -20,10 +20,11 @@ export async function scaffold(answers) {
20
20
  },
21
21
  });
22
22
 
23
- // Ensure shared-context/locked/ exists so the CLAUDE.md import resolves.
23
+ // Ensure workspace-context/locked/ exists. canonical.md and index.md are
24
+ // generated later by /workspace-init via build-workspace-context.mjs;
24
25
  // repos/, work-sessions/, and workspace-scratchpad/ are lazy-created when
25
26
  // scripts and hooks first need them — we do NOT pre-create them here.
26
- mkdirSync(join(directory, 'shared-context', 'locked'), { recursive: true });
27
+ mkdirSync(join(directory, 'workspace-context', 'locked'), { recursive: true });
27
28
 
28
29
  // Rename _gitignore to .gitignore
29
30
  const gitignoreSrc = join(directory, '_gitignore');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ulysses-ai/create-workspace",
3
- "version": "0.14.0-beta.3",
3
+ "version": "0.15.0-beta.1",
4
4
  "description": "A workspace convention for Claude Code: sessions, handoffs, and shared context as files in git",
5
5
  "keywords": [
6
6
  "claude",
@@ -27,7 +27,7 @@ You are reviewing code changes. Your job is to find problems, not to fix them.
27
27
  3. **Edge cases** — are there scenarios not handled?
28
28
  4. **Test coverage** — are tests covering the right scenarios? Are they testing behavior, not implementation?
29
29
  5. **Security** — any injection, XSS, or auth issues?
30
- 6. **Consistency** — does it match existing patterns in shared-context/locked/?
30
+ 6. **Consistency** — does it match existing patterns in workspace-context/shared/locked/?
31
31
 
32
32
  ## What NOT to review
33
33
  - Style preferences (defer to linters/formatters)
@@ -30,5 +30,5 @@ if (pointer) {
30
30
  respond(`Context is about to be compacted. No session tracker found for "${pointer.name}". Use /handoff to capture progress before context is lost.`);
31
31
  }
32
32
  } else {
33
- respond(`Context is about to be compacted — earlier conversation details will be lost.\n\nIf this session produced decisions or progress worth keeping:\n /braindump [name] — capture discussion and reasoning\n /handoff [name] — capture workstream state and next steps\n\nFiles in shared-context/ will persist. Conversation details won't.`);
33
+ respond(`Context is about to be compacted — earlier conversation details will be lost.\n\nIf this session produced decisions or progress worth keeping:\n /braindump [name] — capture discussion and reasoning\n /handoff [name] — capture workstream state and next steps\n\nFiles in workspace-context/ will persist. Conversation details won't.`);
34
34
  }
@@ -94,9 +94,9 @@ if (toolName === 'Bash') {
94
94
  }
95
95
  }
96
96
 
97
- // Check if this write targets repos/, shared-context/, work-sessions/, or template files
97
+ // Check if this write targets repos/, workspace-context/, work-sessions/, or template files
98
98
  const isRepoWrite = /(?:^|[\s/])repos\//.test(paths) || paths.includes('work-sessions/');
99
- const isContextWrite = paths.includes('shared-context/') && !basename(filePathArg).startsWith('local-only-');
99
+ const isContextWrite = paths.includes('workspace-context/') && !basename(filePathArg).startsWith('local-only-');
100
100
  const isTemplateWrite = paths.includes('.claude/') && !paths.includes(scratchpadName);
101
101
 
102
102
  if (isRepoWrite || isContextWrite || isTemplateWrite) {
@@ -22,7 +22,8 @@ const input = await readStdin();
22
22
  const config = readJSON(join(root, 'workspace.json'));
23
23
 
24
24
  const chatId = input.session_id || null;
25
- const contextDir = join(root, 'shared-context');
25
+ const contextDir = join(root, 'workspace-context');
26
+ const sharedDir = join(contextDir, 'shared');
26
27
  const reposDir = join(root, 'repos');
27
28
  const lines = [];
28
29
 
@@ -113,8 +114,11 @@ if (trackers.length > 0) {
113
114
  lines.push('Use /start-work to resume a session or start new work.');
114
115
  }
115
116
 
116
- // Surface shared context (secondary)
117
- if (existsSync(contextDir)) {
117
+ // Surface team-shared workspace context (secondary)
118
+ // Only scan shared/ — locked/ is now a sub-dir of shared/ and is included
119
+ // naturally. team-member/ is per-user (loaded via CLAUDE.local.md).
120
+ // release-notes/ is operational, not knowledge.
121
+ if (existsSync(sharedDir)) {
118
122
  const entries = [];
119
123
 
120
124
  function scanDir(dir, depth = 0) {
@@ -123,11 +127,10 @@ if (existsSync(contextDir)) {
123
127
  const fullPath = join(dir, entry);
124
128
  const stat = statSync(fullPath);
125
129
  if (stat.isDirectory()) {
126
- if (entry === 'locked' || entry === '.keep') continue;
130
+ if (entry === '.keep') continue;
127
131
  scanDir(fullPath, depth + 1);
128
132
  } else if (entry.endsWith('.md') && entry !== '.keep' && !entry.startsWith('local-only-')) {
129
133
  const relPath = relative(contextDir, fullPath);
130
- if (relPath.startsWith('locked/')) continue;
131
134
  const content = readFileSync(fullPath, 'utf-8');
132
135
  const topicMatch = content.match(/^topic:\s*(.+)$/m);
133
136
  const lifecycleMatch = content.match(/^lifecycle:\s*(.+)$/m);
@@ -139,10 +142,10 @@ if (existsSync(contextDir)) {
139
142
  }
140
143
  }
141
144
 
142
- scanDir(contextDir);
145
+ scanDir(sharedDir);
143
146
  if (entries.length > 0) {
144
147
  lines.push('');
145
- lines.push('Shared context:');
148
+ lines.push('Workspace context:');
146
149
  lines.push(...entries);
147
150
  }
148
151
  }
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- // SubagentStart hook — inject shared-context/locked/ into subagent context
2
+ // SubagentStart hook — inject workspace-context/shared/locked/ into subagent context
3
3
  import { readdirSync, readFileSync, existsSync } from 'fs';
4
4
  import { join, basename } from 'path';
5
5
  import { getWorkspaceRoot, readJSON, respond } from './_utils.mjs';
6
6
 
7
7
  const root = getWorkspaceRoot(import.meta.url);
8
8
  const config = readJSON(join(root, 'workspace.json'));
9
- const lockedDir = join(root, 'shared-context', 'locked');
9
+ const lockedDir = join(root, 'workspace-context', 'shared', 'locked');
10
10
 
11
11
  const maxBytes = config?.workspace?.subagentContextMaxBytes || 10240;
12
12
 
@@ -38,7 +38,7 @@ if (Buffer.byteLength(context) > maxBytes) {
38
38
  return `- ${basename(f, '.md')}: ${firstLine}`;
39
39
  }).join('\n');
40
40
 
41
- context = `[Locked shared context exceeds ${maxBytes} byte limit (${Buffer.byteLength(context)} bytes). Summary of ${files.length} files:]\n${summary}\n[Read individual files from shared-context/locked/ if you need full content.]`;
41
+ context = `[Locked shared context exceeds ${maxBytes} byte limit (${Buffer.byteLength(context)} bytes). Summary of ${files.length} files:]\n${summary}\n[Read individual files from workspace-context/shared/locked/ if you need full content.]`;
42
42
  }
43
43
 
44
44
  respond(context);
@@ -47,12 +47,12 @@ For each Notion page that contains project memory, context, or key decisions:
47
47
  ```
48
48
  Fetch the page content using the Notion MCP server.
49
49
  Determine scope:
50
- - Architecture decisions, tech stack, stable conventions → shared-context/locked/
51
- - Active project state, current priorities → shared-context/{user}/
50
+ - Architecture decisions, tech stack, stable conventions → workspace-context/shared/locked/
51
+ - Active project state, current priorities → workspace-context/team-member/{user}/
52
52
  - Historical context no longer relevant → skip
53
53
 
54
54
  For each section:
55
- - Create a shared-context file with proper frontmatter:
55
+ - Create a workspace-context file with proper frontmatter:
56
56
  ---
57
57
  state: locked (or ephemeral)
58
58
  lifecycle: active
@@ -72,7 +72,7 @@ For each Notion page that contains session handoffs or context transfers:
72
72
  ```
73
73
  Fetch the page content using the Notion MCP server.
74
74
  For recent/active handoffs only (skip stale ones):
75
- - Create shared-context/{user}/{handoff-name}.md
75
+ - Create workspace-context/team-member/{user}/{handoff-name}.md
76
76
  - Use handoff frontmatter format with type: handoff
77
77
  - Extract: status, key decisions, next steps, open questions
78
78
  - Set lifecycle: active (or paused if the work is suspended)
@@ -84,7 +84,7 @@ Check `CLAUDE.md.bak` for local preferences that aren't Notion-dependent:
84
84
  - Repo paths, coding conventions, project-specific notes
85
85
  - Add these to appropriate places:
86
86
  - Coding conventions → `.claude/rules/` (new rule file)
87
- - Project notes → `shared-context/locked/` or `shared-context/{user}/`
87
+ - Project notes → `workspace-context/shared/locked/` or `workspace-context/team-member/{user}/`
88
88
  - Repo paths → already in `workspace.json`
89
89
 
90
90
  ### 6. Remove Notion dependency
@@ -108,7 +108,7 @@ Verify the workspace works without Notion:
108
108
  ### 7. Commit
109
109
 
110
110
  ```bash
111
- git add .claude/rules/ shared-context/
111
+ git add .claude/rules/ workspace-context/
112
112
  git commit -m "chore: migrate Notion content to local files"
113
113
  ```
114
114
 
@@ -6,7 +6,7 @@ This applies to all written output:
6
6
  - Project documentation
7
7
  - Specs and design docs
8
8
  - Code and logic changes including comments
9
- - Shared context documents (handoffs, braindumps, locked context)
9
+ - Workspace-context files (handoffs, braindumps, locked truths)
10
10
  - Release notes
11
11
  - Open questions
12
12
  - Commit messages
@@ -18,7 +18,7 @@ Injected revisions create fragmented, hard-to-follow output where the seams betw
18
18
  ## In Practice
19
19
 
20
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
21
+ - When updating a workspace-context file, rewrite it as a fresh snapshot of current understanding
22
22
  - When synthesizing multiple sources into release notes, write the narrative from scratch — don't concatenate
23
23
  - When revising code with comments, ensure the comments tell a coherent story, not a changelog
24
24
  - Small, isolated edits (fixing a typo, updating a single value) are fine — this rule targets substantive revisions
@@ -1,6 +1,6 @@
1
1
  # Local Dev Environment
2
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.
3
+ Maintain a local-only document at `workspace-context/shared/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
4
 
5
5
  ## What to Record
6
6
 
@@ -17,7 +17,7 @@ When you discover any of the following during work, add it to the local dev envi
17
17
 
18
18
  When you encounter a local development detail worth preserving:
19
19
 
20
- 1. Check if `shared-context/locked/local-only-dev-environment.md` exists
20
+ 1. Check if `workspace-context/shared/locked/local-only-dev-environment.md` exists
21
21
  2. If not, create it with this structure:
22
22
  ```markdown
23
23
  ---
@@ -15,7 +15,7 @@ When working in this workspace, pay attention to and save memories about:
15
15
 
16
16
  - Temporary debugging state
17
17
  - File contents (re-read them instead)
18
- - Anything already captured in a shared-context file
18
+ - Anything already captured in a workspace-context file
19
19
  - Anything documented in .claude/rules/
20
20
 
21
21
  ## Session-Scoped vs Cross-Session
@@ -25,22 +25,23 @@ When a work session is active:
25
25
  - Patterns, corrections, and insights that apply beyond this session → auto-memory (persists across all sessions)
26
26
  - Don't duplicate: if something is already in the session tracker, don't also save it to auto-memory
27
27
 
28
- ## Shared-Context Frontmatter
28
+ ## Workspace-Context Frontmatter
29
29
 
30
- Every shared-context file should have YAML frontmatter. The fields below are conventions, not all required.
30
+ Every workspace-context file should have YAML frontmatter. The fields below are conventions, not all required.
31
31
 
32
32
  **Standard fields:**
33
33
 
34
- - `state` — `locked` (team truth) or `ephemeral` (working context). Locked files live under `locked/`; ephemeral files live elsewhere.
34
+ - `state` — `locked` (team truth) or `ephemeral` (working context). Locked files live under `shared/locked/`; ephemeral files live elsewhere under `shared/` or `team-member/{user}/`.
35
35
  - `lifecycle` — for ephemeral files: `active` (still relevant) or `resolved` (handled, kept for record).
36
- - `type` — kind of content: `reference`, `braindump`, `handoff`, `research`, `design`, `index`, `promoted`.
37
- - `topic` — kebab-case slug matching the filename (without `.md`).
38
- - `author` — username scope owner. Required for `{user}/` files.
36
+ - `type` — kind of content: `reference`, `braindump`, `handoff`, `research`, `design`, `index`, `canonical`, `promoted`.
37
+ - `priority` — for locked files only: `critical` (always loaded into canonical) or `reference` (eligible for trim/stub under canonical budget pressure). Default when absent is `critical`. See `build-workspace-context.mjs` for selection semantics.
38
+ - `topic` — kebab-case slug matching the filename (after the type prefix, when one is present).
39
+ - `author` — username scope owner. Required for `team-member/{user}/` files.
39
40
  - `updated` — ISO date of last meaningful edit. `/maintenance` flags stale `lifecycle: active` files based on this.
40
41
 
41
42
  **Index-feeding field:**
42
43
 
43
- - `description` — one-line summary, used verbatim by `shared-context/index.md`. When omitted, the index falls back to the first sentence of the body, then the filename slug. Adding a `description:` to a file with a weak fallback is the cheapest way to improve the index.
44
+ - `description` — one-line summary, used verbatim by `workspace-context/index.md` and per-user team-member indexes. When omitted, the index falls back to the first sentence of the body, then the filename slug (with the `braindump_`/`handoff_`/`research_` prefix stripped). Adding a `description:` to a file with a weak fallback is the cheapest way to improve the index.
44
45
 
45
46
  **Optional confidence marker:**
46
47
 
@@ -54,20 +55,28 @@ state: ephemeral
54
55
  lifecycle: active
55
56
  type: research
56
57
  topic: vector-search-evaluation
57
- description: Evaluation of FAISS for shared-context — concluded NL index is sufficient at our scale.
58
+ description: Evaluation of FAISS for workspace-context — concluded NL index is sufficient at our scale.
58
59
  author: alex
59
60
  confidence: medium
60
61
  updated: 2026-04-25
61
62
  ---
62
63
  ```
63
64
 
64
- ## Shared-Context Index
65
+ ## Workspace-Context Auto-Generated Files
65
66
 
66
- `shared-context/index.md` is auto-generated by `.claude/scripts/build-shared-context-index.mjs`. It's a one-line catalog of every shared-context file (excluding paths in `shared-context/.indexignore`). The script regenerates from frontmatter on demand:
67
+ A single generator at `.claude/scripts/build-workspace-context.mjs` produces three artifacts in one pass:
68
+
69
+ - `workspace-context/index.md` — navigation catalog of everything under `shared/` (locked files first, then the rest). Imported by the workspace-level `CLAUDE.md`.
70
+ - `workspace-context/canonical.md` — verbatim concatenation of `shared/locked/*.md` so team truths are loaded into every session prompt. Also imported by `CLAUDE.md`.
71
+ - `workspace-context/team-member/{user}/index.md` — per-user navigation catalog, one per team member. Imported by each user's gitignored `CLAUDE.local.md`.
72
+
73
+ Gitignored files (e.g. anything matching `local-only-*`) are excluded automatically, and `workspace-context/.indexignore` adds path-prefix excludes for tracked files that shouldn't appear in the shared index (e.g. archived release notes).
74
+
75
+ When `workspace-context/canonical.md` exceeds `workspace.canonicalBudgetBytes` (default 40960), the builder honors per-file `priority` and section-level `<!-- canonical:trim --> ... <!-- canonical:end-trim -->` markers to fit: `priority: reference` files are trimmed first, then stubbed, while `priority: critical` files are always included in full. `/maintenance` audits the budget and offers a triage flow when over.
67
76
 
68
77
  ```bash
69
- node .claude/scripts/build-shared-context-index.mjs --check --root . # exits 1 if stale
70
- node .claude/scripts/build-shared-context-index.mjs --write --root . # regenerate
78
+ node .claude/scripts/build-workspace-context.mjs --check --root . # exits 1 if any artifact is stale or missing
79
+ node .claude/scripts/build-workspace-context.mjs --write --root . # regenerate all three
71
80
  ```
72
81
 
73
- `/maintenance` checks the index for staleness in audit mode and regenerates in cleanup mode. Hand edits to `index.md` are overwritten — update source files (or their `description:` frontmatter) instead.
82
+ `/maintenance` checks staleness in audit mode and regenerates in cleanup mode. Hand edits to `index.md`, `canonical.md`, or any `team-member/{user}/index.md` are overwritten — update source files (or their `description:` frontmatter) instead.
@@ -34,7 +34,7 @@ The single biggest source of session bloat is bash output you didn't bound. The
34
34
  "Ghost tokens" are context spend you can't see in any single tool result — structural bloat that accumulates across the session. Watch for:
35
35
 
36
36
  - **Unused skills.** A loaded skill that you never invoke costs input tokens every turn. If a workspace ships skills you don't use in the current task, that's silent overhead.
37
- - **Oversized locked context.** `shared-context/locked/` is injected into every session and every subagent. If it grows past 5% of the active model's context window, flag it (yellow); past 15%, treat as red. Absolute byte count is a weak proxy — duplicated coverage and stale references matter more.
37
+ - **Oversized locked context.** `workspace-context/shared/locked/` is injected into every session and every subagent. If it grows past 5% of the active model's context window, flag it (yellow); past 15%, treat as red. Absolute byte count is a weak proxy — duplicated coverage and stale references matter more.
38
38
  - **Unused MCP servers.** Each MCP server's tool list is in your prompt whether you call it or not. If a server is registered but never used in this workspace's flow, surface it for cleanup.
39
39
  - **Resolved discussions still in context.** If the conversation has worked through a long debate that's now settled, that text is still occupying the window. Suggest `/braindump` to offload it into a file.
40
40
  - **Subagent context bloat.** A subagent prompt that ships more context than the task requires wastes tokens twice — once for the subagent, once for the dispatching model that wrote the prompt.
@@ -42,5 +42,5 @@ The single biggest source of session bloat is bash output you didn't bound. The
42
42
  ## Compaction Awareness
43
43
 
44
44
  - When approaching the compaction threshold, prioritize capturing over continuing. A `/braindump` or `/handoff` *before* compaction preserves reasoning that gets summarized away.
45
- - After compaction, avoid re-reading files that were already discussed — check `shared-context/` and the session tracker first.
45
+ - After compaction, avoid re-reading files that were already discussed — check `workspace-context/` and the session tracker first.
46
46
  - The `PreCompact` hook will prompt for capture; treat that prompt as a real checkpoint, not a dismissable nag.
@@ -69,7 +69,7 @@ The value is the adapter-prefixed issue ID. This survives adapter swaps — repl
69
69
 
70
70
  ## When NOT to maintain local state
71
71
 
72
- - Do not create, write to, or read `shared-context/open-work.md`. That file is deprecated.
72
+ - Do not create, write to, or read `workspace-context/open-work.md`. That file is deprecated.
73
73
  - Do not write ticket state into `session.md` frontmatter beyond the `workItem:` pointer. Status, assignment, milestone, and labels live in the tracker.
74
74
  - Do not cache issue bodies locally. Always fetch via `tracker.getIssue(id)` when the content is needed.
75
75
 
@@ -14,27 +14,35 @@ This workspace follows the claude-workspace convention. All paths are relative t
14
14
  | `work-sessions/{name}/workspace/plan-*.md` | Plans for this session — consumed into release notes by /complete-work | Yes — on the session branch |
15
15
  | `work-sessions/{name}/workspace/repos/` | Real directory holding nested project worktrees for this session | No (gitignored) |
16
16
  | `work-sessions/{name}/workspace/repos/{repo}/` | Project worktree nested inside the workspace worktree | No (gitignored) |
17
- | `shared-context/` | Shared memory handoffs, braindumps, team knowledge | Yes |
18
- | `shared-context/index.md` | Auto-generated catalog of every shared-context file (one-line per file) | Yes |
19
- | `shared-context/.indexignore` | Path prefixes to exclude from `index.md` (e.g., archived release notes) | Yes |
20
- | `shared-context/locked/` | Team truthsloaded every session, injected into subagents | Yes |
21
- | `shared-context/{user}/` | User-scoped working context default for all captures | Yes |
17
+ | `workspace-context/` | Team knowledge and per-user context | Yes |
18
+ | `workspace-context/shared/` | Team-visible content handoffs, braindumps, research, references | Yes |
19
+ | `workspace-context/shared/locked/` | Canonical team truths auto-concatenated into `canonical.md` and loaded into every session | Yes |
20
+ | `workspace-context/team-member/{user}/` | Per-user working context default destination for personal captures | Yes |
21
+ | `workspace-context/index.md` | Auto-generated navigation catalog of `shared/` (locked first, then ephemerals) | Yes |
22
+ | `workspace-context/canonical.md` | Auto-generated verbatim concatenation of `shared/locked/*.md` | Yes |
23
+ | `workspace-context/team-member/{user}/index.md` | Auto-generated per-user navigation catalog | Yes |
24
+ | `workspace-context/.indexignore` | Path prefixes to exclude from `index.md` (e.g., archived release notes) | Yes |
25
+ | `workspace-context/release-notes/` | Per-branch release-note artifacts — `unreleased/` and `archive/` | Yes |
22
26
  | `workspace-scratchpad/` | Disposable workspace-scoped files — session log, hook debug output | No (gitignored, lazy) |
27
+ | `CLAUDE.md` | Workspace launcher prompt — imports `canonical.md` and `index.md` | Yes |
28
+ | `CLAUDE.local.md` | Per-user prompt — imports `team-member/{user}/index.md` | No (gitignored) |
23
29
  | `.claude/` | Claude Code configuration — rules, agents, skills, hooks, scripts, lib | Yes (except settings.local.json) |
24
30
 
25
31
  Session content (tracker, specs, plans) lives at the top of each session's workspace worktree. It is tracked on the session branch, not on main. Pushing the session branch carries durable session thinking across machines. When `/complete-work` finalizes the session, it synthesizes the content into release notes and removes the files from the branch before the final PR so main's top level stays free of session artifacts.
26
32
 
27
- ## Shared Context Levels
33
+ ## Workspace-Context Levels
28
34
 
29
- | Level | What lives there | Default? |
30
- |-------|-----------------|----------|
31
- | `locked/` | Team truths — always loaded, injected into subagents | Promoted by /release |
32
- | Root | Team-visible ephemerals — cross-team handoffs, post-release leftovers | Explicit choice |
33
- | `{user}/` | Ongoing personal context — persists across work sessions | Default for captures |
35
+ Three layers, in increasing trust order:
34
36
 
35
- Inflight session state lives inside the session worktree at `work-sessions/{name}/workspace/session.md`, not in `shared-context/`. Shared-context is for knowledge that outlives any individual session.
37
+ | Level | Path | What lives there | How it gets there |
38
+ |-------|------|-----------------|--------------------|
39
+ | Personal | `team-member/{user}/` | Per-user braindumps, handoffs, research notes | Default destination for `/braindump`, `/handoff`, `/aside` |
40
+ | Shared | `shared/` (root) | Team-visible ephemerals — cross-team handoffs, post-release leftovers, references | Explicit choice via `--scope shared` or `/promote` |
41
+ | Canonical | `shared/locked/` | Promoted truths — naming conventions, post-release discipline, project status | Promoted by `/release` (or `/promote` with explicit locked target) |
36
42
 
37
- User-scoped is the default for captures. Root is only for content deliberately made team-visible.
43
+ Canonical content is verbatim-loaded into every session via `CLAUDE.md` `@workspace-context/canonical.md`. Personal content is loaded only for the active user via the gitignored `CLAUDE.local.md`.
44
+
45
+ Inflight session state lives inside the session worktree at `work-sessions/{name}/workspace/session.md`, not in `workspace-context/`. Workspace-context is for knowledge that outlives any individual session.
38
46
 
39
47
  ## Spec and Plan Locations — MANDATORY OVERRIDE
40
48
 
@@ -51,7 +59,7 @@ If a spec/plan already exists for the current session, version it: `design-{topi
51
59
 
52
60
  `/complete-work` reads specs and plans from the worktree to synthesize release notes, then removes them in a dedicated commit before the final PR so main's tree stays pristine.
53
61
 
54
- ## Naming Conventions
62
+ ## File Naming Conventions
55
63
 
56
64
  - Session folders: `work-sessions/{session-name}/`
57
65
  - Workspace worktrees: `work-sessions/{session-name}/workspace/`
@@ -59,7 +67,19 @@ If a spec/plan already exists for the current session, version it: `design-{topi
59
67
  - Session trackers: `work-sessions/{session-name}/workspace/session.md`
60
68
  - Specs: `design-{topic}.md` (top of worktree)
61
69
  - Plans: `plan-{topic}.md` (top of worktree)
62
- - Handoffs and braindumps: named by topic (no date prefix — use frontmatter `updated:`)
70
+
71
+ For ephemeral content under `shared/` and `team-member/{user}/`, the filename prefix signals the type:
72
+
73
+ | Skill | Filename prefix |
74
+ |-------|-----------------|
75
+ | `/braindump` | `braindump_{topic}.md` |
76
+ | `/handoff` | `handoff_{topic}.md` |
77
+ | `/aside` (full mode, dispatches researcher) | `research_{topic}.md` |
78
+ | `/aside --quick` | `braindump_{topic}.md` (with `variant: aside` in frontmatter) |
79
+ | `/promote` | preserves source prefix |
80
+ | `/release` | strips prefix when locking — `shared/locked/` files use bare names since location signals the type |
81
+
82
+ Local-only personal drafts get an additional `local-only-` prefix (e.g., `local-only-braindump_x.md`) which keeps them gitignored until promoted.
63
83
 
64
84
  ## Rules
65
85
 
@@ -69,3 +89,4 @@ If a spec/plan already exists for the current session, version it: `design-{topi
69
89
  - Source clones at `repos/{repo-name}/` stay on their default branch — never checkout a feature branch there.
70
90
  - `workspace-scratchpad/` is for disposable files only — session log, hook debug output, temporary pointers.
71
91
  - Project worktrees are nested inside the workspace worktree's real `repos/` directory — no symlink.
92
+ - Hand edits to `index.md`, `canonical.md`, or any per-user `team-member/{user}/index.md` are overwritten by `build-workspace-context.mjs`. Update source files (or their `description:` frontmatter) instead.