wayfind 2.0.28 → 2.0.30
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/bin/connectors/github.js +37 -1
- package/bin/content-store.js +127 -38
- package/bin/digest.js +118 -37
- package/bin/distill.js +355 -0
- package/bin/memory-compare.js +171 -0
- package/bin/memory-report.sh +41 -0
- package/bin/slack-bot.js +2 -1
- package/bin/storage/sqlite-backend.js +44 -2
- package/bin/team-context.js +106 -39
- package/package.json +1 -1
- package/plugin/scripts/session-end.sh +1 -1
- package/plugin/skills/init-folder/SKILL.md +93 -0
- package/plugin/skills/init-team/SKILL.md +8 -0
- package/plugin/skills/session-protocol/SKILL.md +2 -0
- package/specializations/claude-code/CLAUDE.md-global-fragment.md +6 -2
- package/specializations/claude-code/CLAUDE.md-repo-fragment.md +2 -0
- package/specializations/claude-code/commands/init-folder.md +91 -0
- package/specializations/claude-code/commands/init-team.md +8 -0
- package/specializations/claude-code/hooks/session-end.sh +1 -1
package/bin/team-context.js
CHANGED
|
@@ -16,44 +16,7 @@ if (!HOME) {
|
|
|
16
16
|
|
|
17
17
|
const WAYFIND_DIR = process.env.WAYFIND_DIR || path.join(HOME, '.claude', 'team-context');
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
// Honor old MERIDIAN_* env vars with deprecation warning. Remove in v3.0.
|
|
21
|
-
const ENV_VAR_MIGRATION = {
|
|
22
|
-
MERIDIAN_TELEMETRY: 'TEAM_CONTEXT_TELEMETRY',
|
|
23
|
-
MERIDIAN_AUTHOR: 'TEAM_CONTEXT_AUTHOR',
|
|
24
|
-
MERIDIAN_TENANT_ID: 'TEAM_CONTEXT_TENANT_ID',
|
|
25
|
-
MERIDIAN_TEAM_CONTEXT_DIR: 'TEAM_CONTEXT_DIR',
|
|
26
|
-
MERIDIAN_JOURNALS_DIR: 'TEAM_CONTEXT_JOURNALS_DIR',
|
|
27
|
-
MERIDIAN_SIGNALS_DIR: 'TEAM_CONTEXT_SIGNALS_DIR',
|
|
28
|
-
MERIDIAN_SKIP_EXPORT: 'TEAM_CONTEXT_SKIP_EXPORT',
|
|
29
|
-
MERIDIAN_EXCLUDE_REPOS: 'TEAM_CONTEXT_EXCLUDE_REPOS',
|
|
30
|
-
MERIDIAN_SLACK_WEBHOOK: 'TEAM_CONTEXT_SLACK_WEBHOOK',
|
|
31
|
-
MERIDIAN_LLM_MODEL: 'TEAM_CONTEXT_LLM_MODEL',
|
|
32
|
-
MERIDIAN_DIGEST_SCHEDULE: 'TEAM_CONTEXT_DIGEST_SCHEDULE',
|
|
33
|
-
MERIDIAN_SIGNAL_SCHEDULE: 'TEAM_CONTEXT_SIGNAL_SCHEDULE',
|
|
34
|
-
MERIDIAN_STORAGE_BACKEND: 'TEAM_CONTEXT_STORAGE_BACKEND',
|
|
35
|
-
MERIDIAN_MODE: 'TEAM_CONTEXT_MODE',
|
|
36
|
-
MERIDIAN_REINDEX_SCHEDULE: 'TEAM_CONTEXT_REINDEX_SCHEDULE',
|
|
37
|
-
MERIDIAN_ENCRYPTION_KEY: 'TEAM_CONTEXT_ENCRYPTION_KEY',
|
|
38
|
-
MERIDIAN_SIMULATE: 'TEAM_CONTEXT_SIMULATE',
|
|
39
|
-
MERIDIAN_SIM_FIXTURES: 'TEAM_CONTEXT_SIM_FIXTURES',
|
|
40
|
-
MERIDIAN_VERSION: 'TEAM_CONTEXT_VERSION',
|
|
41
|
-
};
|
|
42
|
-
for (const [oldKey, newKey] of Object.entries(ENV_VAR_MIGRATION)) {
|
|
43
|
-
if (process.env[oldKey] && !process.env[newKey]) {
|
|
44
|
-
process.env[newKey] = process.env[oldKey];
|
|
45
|
-
if (!process.env.TEAM_CONTEXT_SKIP_EXPORT) {
|
|
46
|
-
console.warn(`⚠ ${oldKey} is deprecated — rename to ${newKey}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Also migrate config directory: if old ~/.claude/meridian/ exists but new doesn't, use old
|
|
52
|
-
const OLD_DIR = path.join(HOME, '.claude', 'meridian');
|
|
53
|
-
const EFFECTIVE_DIR = (fs.existsSync(WAYFIND_DIR) || !fs.existsSync(OLD_DIR)) ? WAYFIND_DIR : OLD_DIR;
|
|
54
|
-
if (EFFECTIVE_DIR === OLD_DIR) {
|
|
55
|
-
console.warn('⚠ ~/.claude/meridian/ detected — rename to ~/.claude/team-context/');
|
|
56
|
-
}
|
|
19
|
+
const EFFECTIVE_DIR = WAYFIND_DIR;
|
|
57
20
|
|
|
58
21
|
// Auto-load .env from config dir BEFORE requiring modules
|
|
59
22
|
// (modules like content-store read env vars at load time)
|
|
@@ -718,6 +681,14 @@ async function runPull(args) {
|
|
|
718
681
|
writeConnectorsConfig(freshConfig);
|
|
719
682
|
printPullResult(name, result);
|
|
720
683
|
}
|
|
684
|
+
// Auto-index signals into content store after pull
|
|
685
|
+
try {
|
|
686
|
+
console.log('\nIndexing signals...');
|
|
687
|
+
const signalStats = await contentStore.indexSignals({ embeddings: false });
|
|
688
|
+
console.log(` ${signalStats.newEntries} new, ${signalStats.updatedEntries} updated, ${signalStats.skippedEntries} unchanged`);
|
|
689
|
+
} catch (err) {
|
|
690
|
+
console.log(` Signal indexing skipped: ${err.message}`);
|
|
691
|
+
}
|
|
721
692
|
return;
|
|
722
693
|
}
|
|
723
694
|
|
|
@@ -827,6 +798,14 @@ async function runPull(args) {
|
|
|
827
798
|
writeConnectorsConfig(freshConfig);
|
|
828
799
|
|
|
829
800
|
printPullResult(channel, result);
|
|
801
|
+
|
|
802
|
+
// Auto-index signals into content store after pull
|
|
803
|
+
try {
|
|
804
|
+
const signalStats = await contentStore.indexSignals({ embeddings: false });
|
|
805
|
+
console.log(`\nSignals indexed: ${signalStats.newEntries} new, ${signalStats.updatedEntries} updated`);
|
|
806
|
+
} catch (err) {
|
|
807
|
+
console.log(`Signal indexing skipped: ${err.message}`);
|
|
808
|
+
}
|
|
830
809
|
}
|
|
831
810
|
|
|
832
811
|
function runSignals() {
|
|
@@ -928,6 +907,7 @@ async function runDigest(args) {
|
|
|
928
907
|
const personaIdx = args.indexOf('--persona');
|
|
929
908
|
const sinceIdx = args.indexOf('--since');
|
|
930
909
|
const deliver = args.includes('--deliver');
|
|
910
|
+
const preview = args.includes('--preview');
|
|
931
911
|
|
|
932
912
|
// Determine personas
|
|
933
913
|
let personaIds;
|
|
@@ -981,6 +961,32 @@ async function runDigest(args) {
|
|
|
981
961
|
});
|
|
982
962
|
|
|
983
963
|
console.log('');
|
|
964
|
+
|
|
965
|
+
if (preview) {
|
|
966
|
+
// Preview mode: print digest content and stats to stdout
|
|
967
|
+
console.log('=== DIGEST PREVIEW ===');
|
|
968
|
+
console.log('');
|
|
969
|
+
if (result.inputStats) {
|
|
970
|
+
const s = result.inputStats;
|
|
971
|
+
console.log(`Input: ${s.journalEntries || 0} journal, ${s.signalEntries || 0} signal entries`);
|
|
972
|
+
if (s.budgetStats) {
|
|
973
|
+
console.log(`Budget: ${s.budgetStats.kept || 0} kept, ${s.budgetStats.dropped || 0} dropped`);
|
|
974
|
+
}
|
|
975
|
+
console.log('');
|
|
976
|
+
}
|
|
977
|
+
for (const f of result.files) {
|
|
978
|
+
try {
|
|
979
|
+
const content = fs.readFileSync(f, 'utf8');
|
|
980
|
+
const personaId = path.basename(path.dirname(f)) || 'combined';
|
|
981
|
+
console.log(`--- ${personaId} ---`);
|
|
982
|
+
console.log(content);
|
|
983
|
+
console.log('');
|
|
984
|
+
} catch { /* skip unreadable */ }
|
|
985
|
+
}
|
|
986
|
+
console.log('=== END PREVIEW ===');
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
|
|
984
990
|
console.log('Digests generated:');
|
|
985
991
|
for (const f of result.files) {
|
|
986
992
|
console.log(` ${f}`);
|
|
@@ -1172,6 +1178,20 @@ async function runReindex(args) {
|
|
|
1172
1178
|
const signalsOnly = args.includes('--signals-only');
|
|
1173
1179
|
const doExport = args.includes('--export');
|
|
1174
1180
|
const detectShifts = args.includes('--detect-shifts');
|
|
1181
|
+
const force = args.includes('--force');
|
|
1182
|
+
|
|
1183
|
+
if (force) {
|
|
1184
|
+
console.log('Force mode: clearing content store for full reindex...');
|
|
1185
|
+
try {
|
|
1186
|
+
const backend = contentStore.getBackend();
|
|
1187
|
+
const emptyIndex = { version: contentStore.INDEX_VERSION, entries: {}, lastUpdated: Date.now(), entryCount: 0 };
|
|
1188
|
+
backend.saveIndex(emptyIndex);
|
|
1189
|
+
// Clear conversation fingerprint cache so all transcripts are re-extracted
|
|
1190
|
+
backend.saveConversationIndex({});
|
|
1191
|
+
} catch (err) {
|
|
1192
|
+
console.log(` Warning: could not clear store: ${err.message}`);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1175
1195
|
|
|
1176
1196
|
if (!conversationsOnly && !signalsOnly) {
|
|
1177
1197
|
console.log('=== Journals ===');
|
|
@@ -1192,6 +1212,44 @@ async function runReindex(args) {
|
|
|
1192
1212
|
console.log('=== Signals ===');
|
|
1193
1213
|
await indexSignalsIfAvailable();
|
|
1194
1214
|
}
|
|
1215
|
+
|
|
1216
|
+
// Optional: run distillation after reindex
|
|
1217
|
+
if (args.includes('--distill')) {
|
|
1218
|
+
console.log('');
|
|
1219
|
+
console.log('=== Distillation ===');
|
|
1220
|
+
await runDistill(['--tier', 'daily']);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
async function runDistill(args) {
|
|
1225
|
+
const distill = require('./distill');
|
|
1226
|
+
const dryRun = args.includes('--dry-run');
|
|
1227
|
+
const tierIdx = args.indexOf('--tier');
|
|
1228
|
+
const tier = (tierIdx !== -1 && args[tierIdx + 1]) ? args[tierIdx + 1] : 'daily';
|
|
1229
|
+
|
|
1230
|
+
console.log(`Distilling content (tier: ${tier}${dryRun ? ', dry run' : ''})...`);
|
|
1231
|
+
|
|
1232
|
+
// Build LLM config from connectors
|
|
1233
|
+
let llmConfig = null;
|
|
1234
|
+
if (!dryRun) {
|
|
1235
|
+
const config = readConnectorsConfig();
|
|
1236
|
+
if (config.digest && config.digest.llm) {
|
|
1237
|
+
llmConfig = {
|
|
1238
|
+
provider: config.digest.llm.provider,
|
|
1239
|
+
model: config.digest.llm.intelligence?.model || 'claude-haiku-4-5-20251001',
|
|
1240
|
+
api_key_env: config.digest.llm.api_key_env,
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
const stats = await distill.distillEntries({ tier, dryRun, llmConfig });
|
|
1246
|
+
|
|
1247
|
+
console.log('');
|
|
1248
|
+
console.log('Distillation results:');
|
|
1249
|
+
console.log(` Groups: ${stats.grouped}`);
|
|
1250
|
+
console.log(` Deduped: ${stats.deduped}`);
|
|
1251
|
+
console.log(` Merged: ${stats.merged}`);
|
|
1252
|
+
console.log(` LLM calls: ${stats.llmCalls}`);
|
|
1195
1253
|
}
|
|
1196
1254
|
|
|
1197
1255
|
/**
|
|
@@ -2789,7 +2847,7 @@ function runMigrateToPlugin(args) {
|
|
|
2789
2847
|
}
|
|
2790
2848
|
|
|
2791
2849
|
// Step 3: Remove old command files (plugin skills replace these)
|
|
2792
|
-
const oldCommandFiles = ['init-memory.md', 'init-team.md', 'doctor.md', 'journal.md', 'standup.md', 'review-prs.md'];
|
|
2850
|
+
const oldCommandFiles = ['init-memory.md', 'init-team.md', 'init-folder.md', 'doctor.md', 'journal.md', 'standup.md', 'review-prs.md'];
|
|
2793
2851
|
for (const file of oldCommandFiles) {
|
|
2794
2852
|
const cmdPath = path.join(commandsDir, file);
|
|
2795
2853
|
if (fs.existsSync(cmdPath)) {
|
|
@@ -4736,6 +4794,10 @@ const COMMANDS = {
|
|
|
4736
4794
|
desc: 'Index all signal sources (journals + conversations)',
|
|
4737
4795
|
run: (args) => runReindex(args),
|
|
4738
4796
|
},
|
|
4797
|
+
distill: {
|
|
4798
|
+
desc: 'Distill content store: dedup, merge, and compact entries',
|
|
4799
|
+
run: (args) => runDistill(args),
|
|
4800
|
+
},
|
|
4739
4801
|
'index-journals': {
|
|
4740
4802
|
desc: 'Index journal entries into the content store',
|
|
4741
4803
|
run: (args) => runIndexJournals(args),
|
|
@@ -4748,6 +4810,10 @@ const COMMANDS = {
|
|
|
4748
4810
|
desc: 'Search indexed entries (journals + conversations, semantic or full-text)',
|
|
4749
4811
|
run: (args) => runSearchJournals(args),
|
|
4750
4812
|
},
|
|
4813
|
+
'memory-compare': {
|
|
4814
|
+
desc: 'Compare Claude Code auto-memory vs Wayfind memory systems',
|
|
4815
|
+
run: () => require('./memory-compare').compare(),
|
|
4816
|
+
},
|
|
4751
4817
|
insights: {
|
|
4752
4818
|
desc: 'Show insights from indexed journal data',
|
|
4753
4819
|
run: (args) => runInsights(args),
|
|
@@ -4966,6 +5032,7 @@ function showHelp() {
|
|
|
4966
5032
|
console.log('');
|
|
4967
5033
|
console.log('In a Claude Code session:');
|
|
4968
5034
|
console.log(' /init-memory Set up memory for current repo');
|
|
5035
|
+
console.log(' /init-folder Set up memory for a non-repo folder');
|
|
4969
5036
|
console.log(' /init-team Set up team context (journals, digests, Notion)');
|
|
4970
5037
|
console.log(' /journal View your session journal digest');
|
|
4971
5038
|
console.log(' /doctor Check installation health');
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ set -euo pipefail
|
|
|
11
11
|
# Skip export for worker agents in multi-agent swarms.
|
|
12
12
|
# Set TEAM_CONTEXT_SKIP_EXPORT=1 when spawning worker agents so only the
|
|
13
13
|
# orchestrator's decisions flow into the journal.
|
|
14
|
-
if [ "${TEAM_CONTEXT_SKIP_EXPORT
|
|
14
|
+
if [ "${TEAM_CONTEXT_SKIP_EXPORT:-}" = "1" ]; then
|
|
15
15
|
exit 0
|
|
16
16
|
fi
|
|
17
17
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: init-folder
|
|
3
|
+
description: Initialize Wayfind for a non-repo folder (e.g., ~/admin, ~/). Creates .claude/personal-state.md, defensively updates .gitignore if one exists, and registers the folder in the global index. Safe to run multiple times (idempotent).
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Initialize Wayfind for a Non-Repo Folder
|
|
8
|
+
|
|
9
|
+
Run these steps in order. Skip any step that's already done (this command is idempotent).
|
|
10
|
+
|
|
11
|
+
This command is for **non-repo working directories** — your home directory, an admin folder,
|
|
12
|
+
a scratch workspace, etc. For git repos, use `/wayfind:init-memory` instead.
|
|
13
|
+
|
|
14
|
+
## Step 1: Detect Context
|
|
15
|
+
|
|
16
|
+
- Determine the current working directory (or ask the user which folder to initialize)
|
|
17
|
+
- Check if it's a git repo (`git rev-parse --show-toplevel 2>/dev/null`)
|
|
18
|
+
- If it IS a git repo, suggest: "This looks like a git repo. Did you mean to run `/wayfind:init-memory` instead? That sets up team-state.md for shared context too."
|
|
19
|
+
- If the user confirms they want init-folder anyway, proceed.
|
|
20
|
+
- Read `~/.claude/global-state.md` to check if this folder is already registered
|
|
21
|
+
|
|
22
|
+
## Step 2: Create personal state file (if missing)
|
|
23
|
+
|
|
24
|
+
Non-repo folders only get **one** state file — there's no team-state.md because there's
|
|
25
|
+
no git repo to commit it to.
|
|
26
|
+
|
|
27
|
+
If `.claude/personal-state.md` does not exist, create it:
|
|
28
|
+
|
|
29
|
+
```markdown
|
|
30
|
+
# [Folder Name] — Personal State
|
|
31
|
+
|
|
32
|
+
Last updated: [today's date]
|
|
33
|
+
|
|
34
|
+
(This file is local-only. It persists context across AI sessions in this folder.)
|
|
35
|
+
|
|
36
|
+
## My Current Focus
|
|
37
|
+
<!-- Your current tasks and next steps for work in this folder -->
|
|
38
|
+
|
|
39
|
+
## Personal Context
|
|
40
|
+
<!-- Working notes, decisions, things to remember -->
|
|
41
|
+
|
|
42
|
+
## What I'm Watching
|
|
43
|
+
<!-- Open questions, things to follow up on -->
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Create the `.claude/` directory first if it doesn't exist.
|
|
47
|
+
|
|
48
|
+
## Step 3: Defensive .gitignore update
|
|
49
|
+
|
|
50
|
+
Check if a `.gitignore` file exists in the folder root.
|
|
51
|
+
|
|
52
|
+
**If `.gitignore` exists:** Ensure `.claude/` is listed (the whole directory — unlike repos,
|
|
53
|
+
non-repo folders have no team-state.md to preserve). If it's missing, append it.
|
|
54
|
+
|
|
55
|
+
**If `.gitignore` does not exist:** Skip this step. Don't create one — this isn't a repo.
|
|
56
|
+
|
|
57
|
+
## Step 4: Check CLAUDE.md
|
|
58
|
+
|
|
59
|
+
Read the folder's `CLAUDE.md` (if it exists).
|
|
60
|
+
|
|
61
|
+
**If it exists and does NOT contain "Session State Protocol":** Note to the user:
|
|
62
|
+
"Your `~/CLAUDE.md` (or global instructions) should include the session protocol.
|
|
63
|
+
If you're using Wayfind's standard `~/CLAUDE.md`, you're already covered."
|
|
64
|
+
|
|
65
|
+
**If it exists and DOES contain "Session State Protocol":** Skip — already configured.
|
|
66
|
+
|
|
67
|
+
**If it does not exist:** Do NOT create one. Note: "No CLAUDE.md in this folder.
|
|
68
|
+
Your `~/CLAUDE.md` global instructions handle the session protocol."
|
|
69
|
+
|
|
70
|
+
## Step 5: Register in Global Index
|
|
71
|
+
|
|
72
|
+
Read `~/.claude/global-state.md`. Add the folder's state file to the State Files table
|
|
73
|
+
if missing:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
| `[full path]/.claude/personal-state.md` | Personal context for [folder name] (non-repo) |
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The Active Projects table is auto-generated by `wayfind status --write` — do NOT add
|
|
80
|
+
rows to it manually.
|
|
81
|
+
|
|
82
|
+
## Step 6: Report
|
|
83
|
+
|
|
84
|
+
Tell the user:
|
|
85
|
+
- `.claude/personal-state.md` — created or already existed (local only)
|
|
86
|
+
- `.gitignore` — updated or not applicable
|
|
87
|
+
- `global-state.md` — folder registered or already listed
|
|
88
|
+
|
|
89
|
+
Then print:
|
|
90
|
+
|
|
91
|
+
**"This folder is now tracked by Wayfind. Context saved here will be available in future
|
|
92
|
+
sessions. For cross-repo context that should be available everywhere, save to
|
|
93
|
+
`~/.claude/memory/` instead."**
|
|
@@ -87,6 +87,14 @@ Create them if missing. If `prompts/` is new, add the README from `templates/pro
|
|
|
87
87
|
|
|
88
88
|
Store the team context repo path for later steps.
|
|
89
89
|
|
|
90
|
+
## Step 1a: Non-Repo Folder Setup (Optional)
|
|
91
|
+
|
|
92
|
+
After the team context repo is set up, ask:
|
|
93
|
+
|
|
94
|
+
**"Do you have a non-repo folder you use for admin or cross-cutting work? (e.g., your home directory) We can set that up too so context from those sessions is preserved."**
|
|
95
|
+
|
|
96
|
+
If yes, run `/wayfind:init-folder` in that directory (or guide them to run it later).
|
|
97
|
+
|
|
90
98
|
## Step 2: Slack Integration
|
|
91
99
|
|
|
92
100
|
Ask: **"Do you want weekly digests posted to Slack? You'll need a Slack Incoming Webhook URL. If you have one, paste it. If not, I can walk you through creating one."**
|
|
@@ -35,4 +35,6 @@ the plugin's hooks. This skill tells you where state files live so you can load
|
|
|
35
35
|
- Keep `global-state.md` under 80 lines. Detail goes in `~/.claude/memory/` files.
|
|
36
36
|
- Per-repo state files stay focused on that repo only.
|
|
37
37
|
- New cross-repo topics get new files in `~/.claude/memory/`, not appended to global-state.md.
|
|
38
|
+
- **NEVER write secrets, API keys, tokens, or credentials into memory or state files.** Store pointers to where secrets live, not the secrets themselves.
|
|
39
|
+
- Do NOT write Wayfind files to `~/.claude/projects/<project>/memory/` root — that's Claude Code's native auto-memory space.
|
|
38
40
|
- Do NOT use external memory databases or CLI tools for state storage. Use plain markdown files only.
|
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
**Memory system:** Hierarchical plain-markdown files. No CLI tools, no databases.
|
|
5
5
|
|
|
6
|
+
**Important:** Claude Code has its own auto-memory system that writes to `~/.claude/projects/<project>/memory/MEMORY.md`. Wayfind's memory files live in a separate `wayfind/` subfolder to avoid conflicts. Do NOT write Wayfind state files to the root memory directory — that's Claude Code's native auto-memory space.
|
|
7
|
+
|
|
6
8
|
### File Hierarchy
|
|
7
9
|
|
|
8
10
|
```
|
|
9
11
|
~/.claude/
|
|
10
12
|
global-state.md # Thin index — ALWAYS load at session start
|
|
11
13
|
state.md # Admin/non-repo work
|
|
12
|
-
memory/ #
|
|
14
|
+
memory/ # Cross-repo topic files — load on demand
|
|
13
15
|
<topic>.md
|
|
14
|
-
journal/YYYY-MM-DD.md # Daily log
|
|
16
|
+
journal/YYYY-MM-DD.md # Daily work log
|
|
15
17
|
|
|
16
18
|
<repo>/.claude/
|
|
17
19
|
team-state.md # Shared team context — committed to git
|
|
@@ -47,7 +49,9 @@ If work drifts from the stated goal, flag it: *"Quick check — we set out to [g
|
|
|
47
49
|
|
|
48
50
|
### Rules
|
|
49
51
|
|
|
52
|
+
- **NEVER write secrets, API keys, tokens, passwords, or credentials into memory or state files.** Store a pointer to where the secret lives (e.g., "API key is in `~/.config/myapp/.env`"), not the secret itself. Memory files are plain text, may be synced to git, and are readable by any tool with filesystem access.
|
|
50
53
|
- Keep `global-state.md` under 80 lines. Detail goes in `~/.claude/memory/` files.
|
|
51
54
|
- Per-repo `state.md` stays focused on that repo only.
|
|
52
55
|
- New cross-repo topics get new files in `~/.claude/memory/`, not appended to global-state.md.
|
|
56
|
+
- Do NOT write Wayfind files to `~/.claude/projects/<project>/memory/` root — that's Claude Code's native auto-memory space.
|
|
53
57
|
- Do NOT use external memory databases or CLI tools for state storage. Use plain markdown files only.
|
|
@@ -13,4 +13,6 @@
|
|
|
13
13
|
3. Do NOT update `~/.claude/global-state.md` — its Active Projects table is rebuilt automatically by `wayfind status`.
|
|
14
14
|
4. If significant new cross-repo context was created (patterns, strategies, decisions), create or update a file in `~/.claude/memory/` and add it to the Memory Files manifest in global-state.md
|
|
15
15
|
|
|
16
|
+
**NEVER write secrets, API keys, tokens, or credentials into memory or state files.** Store pointers to where secrets live, not the secrets themselves.
|
|
17
|
+
**Do NOT write Wayfind files to `~/.claude/projects/<project>/memory/` root** — that's Claude Code's native auto-memory space.
|
|
16
18
|
**Do NOT use external memory databases or CLI tools for state storage.** Use plain markdown files only.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Initialize Wayfind for a non-repo folder (e.g., ~/admin, ~/). Creates .claude/personal-state.md, defensively updates .gitignore if one exists, and registers the folder in the global index. Safe to run multiple times (idempotent).
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Initialize Wayfind for a Non-Repo Folder
|
|
6
|
+
|
|
7
|
+
Run these steps in order. Skip any step that's already done (this command is idempotent).
|
|
8
|
+
|
|
9
|
+
This command is for **non-repo working directories** — your home directory, an admin folder,
|
|
10
|
+
a scratch workspace, etc. For git repos, use `/init-memory` instead.
|
|
11
|
+
|
|
12
|
+
## Step 1: Detect Context
|
|
13
|
+
|
|
14
|
+
- Determine the current working directory (or ask the user which folder to initialize)
|
|
15
|
+
- Check if it's a git repo (`git rev-parse --show-toplevel 2>/dev/null`)
|
|
16
|
+
- If it IS a git repo, suggest: "This looks like a git repo. Did you mean to run `/init-memory` instead? That sets up team-state.md for shared context too."
|
|
17
|
+
- If the user confirms they want init-folder anyway, proceed.
|
|
18
|
+
- Read `~/.claude/global-state.md` to check if this folder is already registered
|
|
19
|
+
|
|
20
|
+
## Step 2: Create personal state file (if missing)
|
|
21
|
+
|
|
22
|
+
Non-repo folders only get **one** state file — there's no team-state.md because there's
|
|
23
|
+
no git repo to commit it to.
|
|
24
|
+
|
|
25
|
+
If `.claude/personal-state.md` does not exist, create it:
|
|
26
|
+
|
|
27
|
+
```markdown
|
|
28
|
+
# [Folder Name] — Personal State
|
|
29
|
+
|
|
30
|
+
Last updated: [today's date]
|
|
31
|
+
|
|
32
|
+
(This file is local-only. It persists context across AI sessions in this folder.)
|
|
33
|
+
|
|
34
|
+
## My Current Focus
|
|
35
|
+
<!-- Your current tasks and next steps for work in this folder -->
|
|
36
|
+
|
|
37
|
+
## Personal Context
|
|
38
|
+
<!-- Working notes, decisions, things to remember -->
|
|
39
|
+
|
|
40
|
+
## What I'm Watching
|
|
41
|
+
<!-- Open questions, things to follow up on -->
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Create the `.claude/` directory first if it doesn't exist.
|
|
45
|
+
|
|
46
|
+
## Step 3: Defensive .gitignore update
|
|
47
|
+
|
|
48
|
+
Check if a `.gitignore` file exists in the folder root.
|
|
49
|
+
|
|
50
|
+
**If `.gitignore` exists:** Ensure `.claude/` is listed (the whole directory — unlike repos,
|
|
51
|
+
non-repo folders have no team-state.md to preserve). If it's missing, append it.
|
|
52
|
+
|
|
53
|
+
**If `.gitignore` does not exist:** Skip this step. Don't create one — this isn't a repo.
|
|
54
|
+
|
|
55
|
+
## Step 4: Check CLAUDE.md
|
|
56
|
+
|
|
57
|
+
Read the folder's `CLAUDE.md` (if it exists).
|
|
58
|
+
|
|
59
|
+
**If it exists and does NOT contain "Session State Protocol":** Note to the user:
|
|
60
|
+
"Your `~/CLAUDE.md` (or global instructions) should include the session protocol.
|
|
61
|
+
If you're using Wayfind's standard `~/CLAUDE.md`, you're already covered."
|
|
62
|
+
|
|
63
|
+
**If it exists and DOES contain "Session State Protocol":** Skip — already configured.
|
|
64
|
+
|
|
65
|
+
**If it does not exist:** Do NOT create one. Note: "No CLAUDE.md in this folder.
|
|
66
|
+
Your `~/CLAUDE.md` global instructions handle the session protocol."
|
|
67
|
+
|
|
68
|
+
## Step 5: Register in Global Index
|
|
69
|
+
|
|
70
|
+
Read `~/.claude/global-state.md`. Add the folder's state file to the State Files table
|
|
71
|
+
if missing:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
| `[full path]/.claude/personal-state.md` | Personal context for [folder name] (non-repo) |
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The Active Projects table is auto-generated by `wayfind status --write` — do NOT add
|
|
78
|
+
rows to it manually.
|
|
79
|
+
|
|
80
|
+
## Step 6: Report
|
|
81
|
+
|
|
82
|
+
Tell the user:
|
|
83
|
+
- `.claude/personal-state.md` — created or already existed (local only)
|
|
84
|
+
- `.gitignore` — updated or not applicable
|
|
85
|
+
- `global-state.md` — folder registered or already listed
|
|
86
|
+
|
|
87
|
+
Then print:
|
|
88
|
+
|
|
89
|
+
**"This folder is now tracked by Wayfind. Context saved here will be available in future
|
|
90
|
+
sessions. For cross-repo context that should be available everywhere, save to
|
|
91
|
+
`~/.claude/memory/` instead."**
|
|
@@ -142,6 +142,14 @@ Create `~/.claude/memory/wayfind-team-context.md` with:
|
|
|
142
142
|
- <list of usernames with journal directories>
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
+
## Step 1a: Non-Repo Folder Setup (Optional)
|
|
146
|
+
|
|
147
|
+
After the team context repo is set up, ask:
|
|
148
|
+
|
|
149
|
+
**"Do you have a non-repo folder you use for admin or cross-cutting work? (e.g., your home directory) We can set that up too so context from those sessions is preserved."**
|
|
150
|
+
|
|
151
|
+
If yes, run `/init-folder` in that directory (or guide them to run it later).
|
|
152
|
+
|
|
145
153
|
## Step 1b: Link and Distribute Context
|
|
146
154
|
|
|
147
155
|
Once the team context repo exists, link it so Wayfind knows where to find shared
|
|
@@ -11,7 +11,7 @@ set -euo pipefail
|
|
|
11
11
|
# Skip export for worker agents in multi-agent swarms.
|
|
12
12
|
# Set TEAM_CONTEXT_SKIP_EXPORT=1 when spawning worker agents so only the
|
|
13
13
|
# orchestrator's decisions flow into the journal.
|
|
14
|
-
if [ "${TEAM_CONTEXT_SKIP_EXPORT
|
|
14
|
+
if [ "${TEAM_CONTEXT_SKIP_EXPORT:-}" = "1" ]; then
|
|
15
15
|
exit 0
|
|
16
16
|
fi
|
|
17
17
|
|