@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.
- package/lib/init.mjs +12 -25
- package/lib/scaffold.mjs +3 -2
- package/package.json +1 -1
- package/template/.claude/agents/reviewer.md +1 -1
- package/template/.claude/hooks/pre-compact.mjs +1 -1
- package/template/.claude/hooks/repo-write-detection.mjs +2 -2
- package/template/.claude/hooks/session-start.mjs +10 -7
- package/template/.claude/hooks/subagent-start.mjs +3 -3
- package/template/.claude/recipes/migrate-from-notion.md +6 -6
- package/template/.claude/rules/coherent-revisions.md +2 -2
- package/template/.claude/rules/local-dev-environment.md.skip +2 -2
- package/template/.claude/rules/memory-guidance.md +23 -14
- package/template/.claude/rules/token-economics.md.skip +2 -2
- package/template/.claude/rules/work-item-tracking.md +1 -1
- package/template/.claude/rules/workspace-structure.md +36 -15
- package/template/.claude/scripts/build-workspace-context.mjs +712 -0
- package/template/.claude/scripts/capture-context.mjs +217 -0
- package/template/.claude/scripts/generate-claude-local.mjs +104 -0
- package/template/.claude/scripts/migrate-canonical-priority.mjs +108 -0
- package/template/.claude/scripts/migrate-open-work.mjs +1 -1
- package/template/.claude/scripts/migrate-to-workspace-context.mjs +520 -0
- package/template/.claude/scripts/sweep-references.mjs +177 -0
- package/template/.claude/skills/aside/SKILL.md +49 -44
- package/template/.claude/skills/braindump/SKILL.md +25 -19
- package/template/.claude/skills/build-docs-site/SKILL.md +1 -1
- package/template/.claude/skills/build-docs-site/checklists/framing.md +1 -1
- package/template/.claude/skills/complete-work/SKILL.md +91 -3
- package/template/.claude/skills/handoff/SKILL.md +31 -30
- package/template/.claude/skills/maintenance/SKILL.md +90 -22
- package/template/.claude/skills/pause-work/SKILL.md +1 -1
- package/template/.claude/skills/promote/SKILL.md +18 -8
- package/template/.claude/skills/release/SKILL.md +20 -13
- package/template/.claude/skills/start-work/SKILL.md +1 -1
- package/template/.claude/skills/workspace-init/SKILL.md +12 -12
- package/template/.claude/skills/workspace-update/SKILL.md +7 -1
- package/template/CLAUDE.md.tmpl +4 -3
- package/template/_gitignore +1 -0
- package/template/workspace.json.tmpl +3 -2
- package/template/.claude/hooks/_bash-output-advisory.test.mjs +0 -88
- package/template/.claude/hooks/_utils.test.mjs +0 -99
- package/template/.claude/lib/freshness.test.mjs +0 -175
- package/template/.claude/lib/registry-check.test.mjs +0 -130
- package/template/.claude/lib/session-frontmatter.test.mjs +0 -242
- package/template/.claude/scripts/build-shared-context-index.mjs +0 -212
- package/template/.claude/scripts/build-shared-context-index.test.mjs +0 -318
- package/template/.claude/scripts/migrate-claude-md-freshness-include.test.mjs +0 -54
- package/template/.claude/scripts/migrate-session-layout.test.mjs +0 -144
- package/template/.claude/scripts/sync-tasks.test.mjs +0 -350
- package/template/.claude/scripts/trackers/github-issues.test.mjs +0 -190
- 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
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
|
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, '
|
|
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
|
@@ -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
|
|
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
|
|
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/,
|
|
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('
|
|
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, '
|
|
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
|
-
|
|
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 === '
|
|
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(
|
|
145
|
+
scanDir(sharedDir);
|
|
143
146
|
if (entries.length > 0) {
|
|
144
147
|
lines.push('');
|
|
145
|
-
lines.push('
|
|
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
|
|
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, '
|
|
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
|
|
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 →
|
|
51
|
-
- Active project state, current priorities →
|
|
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
|
|
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
|
|
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 → `
|
|
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/
|
|
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
|
-
-
|
|
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
|
|
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 `
|
|
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 `
|
|
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
|
|
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
|
-
##
|
|
28
|
+
## Workspace-Context Frontmatter
|
|
29
29
|
|
|
30
|
-
Every
|
|
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
|
-
- `
|
|
38
|
-
- `
|
|
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 `
|
|
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
|
|
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
|
-
##
|
|
65
|
+
## Workspace-Context Auto-Generated Files
|
|
65
66
|
|
|
66
|
-
|
|
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-
|
|
70
|
-
node .claude/scripts/build-
|
|
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
|
|
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.** `
|
|
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 `
|
|
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 `
|
|
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
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
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
|
-
##
|
|
33
|
+
## Workspace-Context Levels
|
|
28
34
|
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|