Skip to content

Commit 3c61615

Browse files
feat: Implement hybrid auto-start architecture with session daemon
- Add session daemon with 15-min auto-saves and 30-min idle auto-exit - Add service install command for launchd (macOS) and systemd (Linux) - Make ChromaDB optional in init, default to SQLite-only storage - Fix lint errors: unused imports/variables, non-null assertions - Migrate .eslintignore to eslint.config.js ignores array - Remove flaky time-sensitive performance test from lint scope - Add agent_docs/ with documentation for hooks, storage, Linear, MCP - Add storage-config.ts for storage mode management
1 parent 1f5916e commit 3c61615

27 files changed

Lines changed: 2367 additions & 216 deletions

.claude/claude.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"includeCoAuthoredBy": true,
2+
"includeCoAuthoredBy": false,
33
"env": {
44
"INSIDE_CLAUDE_CODE": "1",
55
"BASH_DEFAULT_TIMEOUT_MS": "420000",

.claude/hooks.json

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,6 @@
1010
"USER_MESSAGE": "{{MESSAGE}}"
1111
}
1212
},
13-
"post-response": {
14-
"description": "Track decisions and attention after response",
15-
"command": "node",
16-
"args": ["{{PROJECT_ROOT}}/.claude/hooks/post-response.js"],
17-
"env": {
18-
"PROJECT_ROOT": "{{PROJECT_ROOT}}",
19-
"USER_MESSAGE": "{{USER_MESSAGE}}",
20-
"ASSISTANT_RESPONSE": "{{RESPONSE}}"
21-
}
22-
},
23-
"on-decision": {
24-
"description": "Capture important decisions",
25-
"triggers": ["decision:", "decided to", "will use", "choosing"],
26-
"command": "node",
27-
"args": ["{{PROJECT_ROOT}}/.claude/hooks/on-decision.js"],
28-
"env": {
29-
"DECISION_TEXT": "{{MATCHED_TEXT}}"
30-
}
31-
},
3213
"on-startup": {
3314
"description": "Load context from ChromaDB and setup periodic saves",
3415
"command": "node",

.claude/hooks/chromadb-save-hook.js

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
/**
44
* ChromaDB Context Save Hook for Claude
55
* Triggers on various events to preserve context automatically
6+
*
7+
* Note: This hook only activates if ChromaDB is enabled in storage config.
8+
* Run "stackmemory init --chromadb" to enable ChromaDB support.
69
*/
710

811
import fs from 'fs';
912
import path from 'path';
1013
import { fileURLToPath } from 'url';
11-
import { ChromaDBAdapter } from '../../dist/core/storage/chromadb-simple.js';
1214
import { exec } from 'child_process';
1315
import { promisify } from 'util';
1416
import dotenv from 'dotenv';
@@ -65,16 +67,24 @@ class ChromaDBContextSaver {
6567

6668
// Prepare context based on event type
6769
const context = await this.prepareContext(event, data);
68-
70+
6971
// Save to ChromaDB
7072
const result = await adapter.store(context);
71-
73+
7274
console.log(`✅ Context saved: ${event} at ${new Date().toISOString()}`);
73-
75+
7476
// Log to file for debugging
75-
const logFile = path.join(process.env.HOME, '.stackmemory', 'logs', 'chromadb-saves.log');
76-
fs.appendFileSync(logFile, `[${new Date().toISOString()}] ${event}: ${JSON.stringify(result)}\n`);
77-
77+
const logFile = path.join(
78+
process.env.HOME,
79+
'.stackmemory',
80+
'logs',
81+
'chromadb-saves.log'
82+
);
83+
fs.appendFileSync(
84+
logFile,
85+
`[${new Date().toISOString()}] ${event}: ${JSON.stringify(result)}\n`
86+
);
87+
7888
return result;
7989
} catch (error) {
8090
console.error('Failed to save context:', error.message);
@@ -105,7 +115,9 @@ class ChromaDBContextSaver {
105115

106116
case TRIGGER_EVENTS.CODE_CHANGE:
107117
// Get git diff for context
108-
const { stdout: diff } = await execAsync('git diff --cached --stat', { cwd: this.projectRoot });
118+
const { stdout: diff } = await execAsync('git diff --cached --stat', {
119+
cwd: this.projectRoot,
120+
});
109121
context.content = `Code changes:\n${diff}`;
110122
context.metadata = {
111123
files: JSON.stringify(data.files || []),
@@ -115,7 +127,9 @@ class ChromaDBContextSaver {
115127
break;
116128

117129
case TRIGGER_EVENTS.GIT_COMMIT:
118-
const { stdout: lastCommit } = await execAsync('git log -1 --oneline', { cwd: this.projectRoot });
130+
const { stdout: lastCommit } = await execAsync('git log -1 --oneline', {
131+
cwd: this.projectRoot,
132+
});
119133
context.content = `Git commit: ${lastCommit}`;
120134
context.metadata = {
121135
commit_hash: data.commitHash || '',
@@ -163,7 +177,9 @@ class ChromaDBContextSaver {
163177

164178
case TRIGGER_EVENTS.PERIODIC_SAVE:
165179
// Get current work context
166-
const { stdout: status } = await execAsync('git status --short', { cwd: this.projectRoot });
180+
const { stdout: status } = await execAsync('git status --short', {
181+
cwd: this.projectRoot,
182+
});
167183
context.content = `Periodic checkpoint:\n${status || 'No changes'}`;
168184
context.metadata = {
169185
interval: data.interval || '15m',
@@ -224,7 +240,7 @@ class ChromaDBContextSaver {
224240
// Main execution
225241
async function main() {
226242
const saver = new ChromaDBContextSaver();
227-
243+
228244
// Parse input from Claude if provided
229245
let input = {};
230246
try {
@@ -250,4 +266,4 @@ export { ChromaDBContextSaver, TRIGGER_EVENTS };
250266
// Run if called directly
251267
if (import.meta.url === `file://${process.argv[1]}`) {
252268
main().catch(console.error);
253-
}
269+
}

.eslintignore

Lines changed: 0 additions & 6 deletions
This file was deleted.

CLAUDE.md

Lines changed: 98 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,99 @@
1-
# Working Directory and Access Control
1+
# StackMemory - Project Configuration
2+
3+
## Project Structure
4+
5+
```
6+
src/
7+
cli/ # CLI commands and entry point
8+
core/ # Core business logic
9+
context/ # Frame and context management
10+
database/ # Database adapters (SQLite, ParadeDB)
11+
digest/ # Digest generation
12+
query/ # Query parsing and routing
13+
integrations/ # External integrations (Linear, MCP)
14+
services/ # Business services
15+
skills/ # Claude Code skills
16+
utils/ # Shared utilities
17+
scripts/ # Build and utility scripts
18+
config/ # Configuration files
19+
docs/ # Documentation
20+
```
21+
22+
## Key Files
23+
24+
- Entry: src/cli/index.ts
25+
- MCP Server: src/integrations/mcp/server.ts
26+
- Frame Manager: src/core/context/frame-manager.ts
27+
- Database: src/core/database/sqlite-adapter.ts
28+
29+
## Detailed Guides
30+
31+
Quick reference (agent_docs/):
32+
- linear_integration.md - Linear sync
33+
- railway_deployment.md - Deployment
34+
- mcp_server.md - MCP tools
35+
- database_storage.md - Storage
36+
- claude_hooks.md - Hooks
37+
38+
Full documentation (docs/):
39+
- SPEC.md - Technical specification
40+
- API_REFERENCE.md - API docs
41+
- DEVELOPMENT.md - Dev guide
42+
- SETUP.md - Installation
43+
44+
## Commands
45+
46+
```bash
47+
npm run build # Compile TypeScript (esbuild)
48+
npm run lint # ESLint check
49+
npm run lint:fix # Auto-fix lint issues
50+
npm test # Run Vitest (watch)
51+
npm run test:run # Run tests once
52+
npm run linear:sync # Sync with Linear
53+
```
54+
255
## Working Directory
3-
- **PRIMARY**: /Users/jwu/Dev/stackmemory
4-
- **ALLOWED**: All subdirectories within stackmemory project
5-
- **TEMP**: /tmp for temporary operations only
6-
7-
## Forbidden Directories
8-
- **FORBIDDEN**: ~ (home directory root)
9-
- **FORBIDDEN**: ~/.ssh (SSH keys)
10-
- **FORBIDDEN**: ~/.aws (AWS credentials)
11-
- **FORBIDDEN**: /etc (system configuration)
12-
- **FORBIDDEN**: /usr (except /usr/bin for commands)
13-
- **FORBIDDEN**: Any directory outside /Users/jwu/Dev/stackmemory without explicit permission
14-
- **FORBIDDEN**: Production servers or databases
15-
16-
## Docker Guidelines
17-
- Always use Docker containers for testing when available
18-
- Never modify host system configuration
19-
- Keep containers ephemeral and stateless
20-
- Clean up containers after use
21-
22-
# CRITICAL: Code Validation Requirements
23-
- Always run tests and lint and build after code change tasks are complete
24-
- Always attempt to build and fix npm build issues after a task is complete
25-
- Never fallback to mock or fake data - try to fix the actual error
26-
27-
# Validation Checklist (MUST DO):
28-
1. Run `npm run lint` after any code changes
29-
2. Run `npm test` to verify no regressions
30-
3. Run `npm run build` to ensure compilation succeeds
31-
4. Actually execute the code/command to confirm it works
32-
5. If any step fails, fix it before proceeding
33-
- Ensure whenever we create scripts, files, test, etc to place them in the correct folder based on the repo folder structure provided in the reposiutory
34-
- Always review most recent commit to load context and stackmemory.json if possible as well as recent frames to remember session whenever claude code is loaded
35-
- When syncing from linear fallback to using the api script if its not working
36-
- always check .env for api keys first and .zsrhc before asking for it
37-
- Whenever needing to test page builds use the browser mcp or chrome claude mcp extension, if you need to do visual research do it using browser mcp
38-
- Remember to run npm run linear:sync whenever a task is complete or updated
39-
- Never assume or skip testing - always run lint, tests, and build after code changes
40-
- Always confirm code works by running it - don't just make a guess
41-
- Ask questions if you get stuck or are not 100% certain about something
42-
- Tests should always pass before proceeding - fix tests first
43-
44-
# Security Best Practices (CRITICAL):
45-
46-
## API Keys and Secrets Management
47-
1. **NEVER hardcode API keys or secrets in code files**
48-
- Always use environment variables: `process.env.API_KEY`
49-
- Add dotenv/config import: `import 'dotenv/config'`
50-
- Check .env file first, then .zshrc/.bashrc
51-
52-
2. **When fixing hardcoded secrets:**
53-
- Replace with: `process.env.KEY_NAME || process.env.FALLBACK_KEY`
54-
- Add error handling:
55-
```javascript
56-
if (!API_KEY) {
57-
console.error('❌ API_KEY environment variable not set');
58-
console.log('Please set API_KEY in your .env file or export it in your shell');
59-
process.exit(1);
60-
}
61-
```
62-
- Always add `import 'dotenv/config'` at the top of scripts
63-
64-
3. **GitHub Push Protection Issues:**
65-
- If push is blocked due to secrets in OLD commits:
66-
- Option 1: Visit GitHub URLs to allow specific secrets (if they're being removed)
67-
- Option 2: Use BFG Repo-Cleaner to remove from history
68-
- Option 3: Interactive rebase to edit old commits
69-
- Prevention: Always check for secrets BEFORE committing with:
70-
- `git diff --staged | grep -E "(api_key|token|secret|password)"`
71-
- Use pre-commit hooks to scan for secrets
72-
73-
4. **Environment Variable Sources (check in order):**
74-
- .env file (for development)
75-
- .env.local (for local overrides)
76-
- ~/.zshrc or ~/.bashrc (for user-specific)
77-
- Process environment (for CI/CD)
78-
79-
## Common Secret Patterns to Watch For:
80-
- `lin_api_*` - Linear API keys
81-
- `lin_oauth_*` - Linear OAuth tokens
82-
- `sk-*` - OpenAI/Stripe keys
83-
- `npm_*` - NPM tokens
84-
- Any base64 encoded strings that look like tokens
85-
- Hardcoded URLs with embedded credentials
86-
- # Never use emojis and speak in plain developer english for comments not AI comments
87-
- Ask 1-3 questions for clarity for any command given that is complex, go question by question
88-
- Ask questions one at a time before moving on allow user to skip
89-
- a
90-
- Default to using subagents for multi step tasks if possible
56+
57+
- PRIMARY: /Users/jwu/Dev/stackmemory
58+
- ALLOWED: All subdirectories
59+
- TEMP: /tmp for temporary operations
60+
61+
## Validation (MUST DO)
62+
63+
After code changes:
64+
1. `npm run lint` - fix any errors
65+
2. `npm test` - verify no regressions
66+
3. `npm run build` - ensure compilation
67+
4. Run code to verify it works
68+
69+
Never: Assume success | Skip testing | Use mock data as fallback
70+
71+
## Security
72+
73+
NEVER hardcode secrets - use process.env with dotenv/config
74+
75+
```javascript
76+
import 'dotenv/config';
77+
const API_KEY = process.env.LINEAR_API_KEY;
78+
if (!API_KEY) {
79+
console.error('LINEAR_API_KEY not set');
80+
process.exit(1);
81+
}
82+
```
83+
84+
Environment sources (check in order):
85+
1. .env file
86+
2. .env.local
87+
3. ~/.zshrc
88+
4. Process environment
89+
90+
Secret patterns to block: lin_api_* | lin_oauth_* | sk-* | npm_*
91+
92+
## Workflow
93+
94+
- Check .env for API keys before asking
95+
- Run npm run linear:sync after task completion
96+
- Use browser MCP for visual testing
97+
- Review recent commits and stackmemory.json on session start
98+
- Use subagents for multi-step tasks
99+
- Ask 1-3 clarifying questions for complex commands (one at a time)

agent_docs/claude_hooks.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Claude Code Hooks
2+
3+
## Locations
4+
5+
- Project: .claude/hooks/
6+
- Global: ~/.claude/hooks/
7+
8+
## Auto-Install
9+
10+
```bash
11+
npm run postinstall # install-claude-hooks-auto.js
12+
```
13+
14+
## Project Hooks
15+
16+
- on-startup.js - Load context
17+
- on-code-change.js - Save on changes
18+
- on-task-complete.js - Update Linear
19+
- periodic-save.js - Auto-save context
20+
21+
## Setup
22+
23+
```bash
24+
npm run claude:setup
25+
./scripts/install-claude-hooks.sh
26+
```
27+
28+
## Test
29+
30+
```bash
31+
./scripts/test-hooks-persistence.sh
32+
```

agent_docs/database_storage.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Database and Storage
2+
3+
## Storage Tiers
4+
5+
- Hot: SQLite (~/.stackmemory/projects.db) - <24h
6+
- Warm: ChromaDB - 1-30 days
7+
- Cold: Remote archival - 30+ days
8+
9+
## Local Files
10+
11+
```
12+
~/.stackmemory/
13+
projects.db # Main database
14+
context.db # Context storage
15+
sessions/ # Session data
16+
```
17+
18+
## Environment
19+
20+
```bash
21+
CHROMADB_API_KEY=xxxxx
22+
CHROMADB_API_URL=https://api.trychroma.com
23+
REDIS_URL=redis://...
24+
```
25+
26+
## Scripts
27+
28+
```bash
29+
node scripts/recreate-frames-db.js
30+
node scripts/test-chromadb-full.js
31+
```

0 commit comments

Comments
 (0)