Fixed the auto sync file watcher and updated setup script to make agent-os default install false

This commit is contained in:
Bob Roberts 2025-12-12 14:37:45 -06:00
parent 212dda1ce1
commit c45c2e87a5
7 changed files with 383 additions and 4 deletions

View file

@ -178,6 +178,9 @@ class GlobalFileWatcher:
watcher = ProjectWatcher(project_id) watcher = ProjectWatcher(project_id)
watcher.start() watcher.start()
self.watchers[project_id] = watcher self.watchers[project_id] = watcher
# Enable if we have active watchers
if self.watchers:
self.enabled = True
def stop_project(self, project_id: int): def stop_project(self, project_id: int):
"""Stop watching a project.""" """Stop watching a project."""
@ -187,6 +190,9 @@ class GlobalFileWatcher:
watcher = self.watchers.pop(project_id) watcher = self.watchers.pop(project_id)
watcher.stop() watcher.stop()
# Disable if no more watchers
if not self.watchers:
self.enabled = False
def restart_project(self, project_id: int): def restart_project(self, project_id: int):
"""Restart watcher for a project.""" """Restart watcher for a project."""

BIN
docs/assets/og-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

View file

@ -5,6 +5,26 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Claude OS - The AI Operating System That Never Forgets</title> <title>Claude OS - The AI Operating System That Never Forgets</title>
<!-- Open Graph / Social Media Meta Tags -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://thebob.dev/claude-os/">
<meta property="og:title" content="Claude OS - The AI Operating System That Never Forgets">
<meta property="og:description" content="Persistent memory for Claude Code. Index 10,000 files in 3 seconds. 36+ community skills. Never start from zero again.">
<meta property="og:image" content="https://thebob.dev/claude-os/assets/og-image.png">
<meta property="og:site_name" content="Claude OS">
<!-- Twitter Card Meta Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="https://thebob.dev/claude-os/">
<meta name="twitter:title" content="Claude OS - The AI Operating System That Never Forgets">
<meta name="twitter:description" content="Persistent memory for Claude Code. Index 10,000 files in 3 seconds. 36+ community skills. Never start from zero again.">
<meta name="twitter:image" content="https://thebob.dev/claude-os/assets/og-image.png">
<!-- General Meta Tags -->
<meta name="description" content="Claude OS gives Claude Code persistent memory across sessions. Index 10,000 files in 3 seconds with hybrid indexing. 36+ community skills available.">
<meta name="keywords" content="Claude, Claude Code, AI, memory, coding assistant, developer tools, open source">
<meta name="author" content="Bob Roberts">
<!-- Bootstrap 5 --> <!-- Bootstrap 5 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">

View file

@ -3324,6 +3324,35 @@ async def startup_event():
except Exception as e: except Exception as e:
logger.error(f"❌ Failed to start spec watchers: {e}") logger.error(f"❌ Failed to start spec watchers: {e}")
# Auto-start file watchers for all projects with hooks enabled
try:
from app.core.hooks import ProjectHook
db_manager = get_sqlite_manager()
projects = db_manager.list_projects()
file_watcher = get_global_watcher()
started_count = 0
for project in projects:
try:
# Check if project has any enabled hooks
hook = ProjectHook(project['id'])
hook_status = hook.get_hook_status()
if hook_status.get('enabled_hooks', 0) > 0:
file_watcher.start_project(project['id'])
started_count += 1
logger.info(f"📂 File watcher started for project {project['name']}")
except Exception as e:
logger.warning(f"Could not start file watcher for project {project['id']}: {e}")
if started_count > 0:
logger.info(f"✅ File watchers started for {started_count} project(s)")
else:
logger.info("ℹ️ No projects with hooks enabled - file watchers will start when hooks are configured")
except Exception as e:
logger.error(f"❌ Failed to start file watchers: {e}")
@app.on_event("shutdown") @app.on_event("shutdown")
async def shutdown_event(): async def shutdown_event():
@ -3340,6 +3369,14 @@ async def shutdown_event():
except Exception as e: except Exception as e:
logger.error(f"❌ Failed to stop spec watchers: {e}") logger.error(f"❌ Failed to stop spec watchers: {e}")
# Stop all file watchers
try:
file_watcher = get_global_watcher()
file_watcher.stop_all()
logger.info("✅ File watchers stopped")
except Exception as e:
logger.error(f"❌ Failed to stop file watchers: {e}")
def main(): def main():
"""Start the MCP server.""" """Start the MCP server."""

View file

@ -154,7 +154,7 @@ echo ""
# ===== 5. Start RQ Workers (Real-Time Learning System) ===== # ===== 5. Start RQ Workers (Real-Time Learning System) =====
echo -e "${YELLOW}5. Starting RQ Workers (Real-Time Learning)...${NC}" echo -e "${YELLOW}5. Starting RQ Workers (Real-Time Learning)...${NC}"
if check_port 6379; then if check_port 6379; then
nohup "$PROJECT_DIR/venv/bin/python3" -m rq worker claude-os:learning claude-os:prompts claude-os:ingest --with-scheduler > "$PROJECT_DIR/logs/rq_workers.log" 2>&1 & nohup "$PROJECT_DIR/venv/bin/rq" worker claude-os:learning claude-os:prompts claude-os:ingest --with-scheduler > "$PROJECT_DIR/logs/rq_workers.log" 2>&1 &
RQ_PID=$! RQ_PID=$!
echo " RQ Workers PID: $RQ_PID (logging to logs/rq_workers.log)" echo " RQ Workers PID: $RQ_PID (logging to logs/rq_workers.log)"
echo -e " ${GREEN}✓ RQ workers started${NC}" echo -e " ${GREEN}✓ RQ workers started${NC}"

View file

@ -73,8 +73,8 @@ Let's get your project configured for AI-powered development.
- Default: `http://localhost:8051` - Default: `http://localhost:8051`
- Ask: `Claude OS server URL? [default: http://localhost:8051]` - Ask: `Claude OS server URL? [default: http://localhost:8051]`
9. **Agent-OS Setup** (Optional): 9. **Agent-OS Setup** (Optional - for advanced users):
- Ask: `Enable Agent-OS for spec-driven development? [Y/n]` - Ask: `Enable Agent-OS for spec-driven development? [y/N]`
- Explain: - Explain:
``` ```
Agent-OS provides 8 specialized agents for structured feature development: Agent-OS provides 8 specialized agents for structured feature development:
@ -83,13 +83,14 @@ Let's get your project configured for AI-powered development.
- Generate task breakdowns - Generate task breakdowns
- Implement and verify features - Implement and verify features
This is recommended for complex projects with formal spec workflows.
Note: Requires Ollama (local) or OpenAI API key for advanced features. Note: Requires Ollama (local) or OpenAI API key for advanced features.
``` ```
- If YES: - If YES:
- Set `ENABLE_AGENT_OS=true` - Set `ENABLE_AGENT_OS=true`
- Will create `agent-os/` directory structure - Will create `agent-os/` directory structure
- Will symlink agents to `.claude/agents/agent-os/` - Will symlink agents to `.claude/agents/agent-os/`
- If NO: - If NO (default):
- Set `ENABLE_AGENT_OS=false` - Set `ENABLE_AGENT_OS=false`
- Can enable later by manually copying templates - Can enable later by manually copying templates
@ -184,6 +185,18 @@ mkdir -p .claude-os
- Copy from: `{claude_os_dir}/templates/project-files/.claude-os/.gitignore` - Copy from: `{claude_os_dir}/templates/project-files/.claude-os/.gitignore`
- Write to: `./.claude-os/.gitignore` - Write to: `./.claude-os/.gitignore`
**Install TDD Skill (always - best practice for all projects):**
- Create directory: `mkdir -p ./.claude/skills/test-driven-development`
- Copy from: `{claude_os_dir}/templates/skills/test-driven-development/SKILL.md`
- Write to: `./.claude/skills/test-driven-development/SKILL.md`
- Show:
```
✅ Installed TDD skill (test-driven-development)
- Guides RED-GREEN-REFACTOR workflow
- Ensures tests fail first, then pass
- Use: "I'm using the TDD skill to implement this feature"
```
**If Agent-OS is enabled (`ENABLE_AGENT_OS=true`):** **If Agent-OS is enabled (`ENABLE_AGENT_OS=true`):**
1. **Create agent-os/ directory structure:** 1. **Create agent-os/ directory structure:**
@ -450,6 +463,11 @@ Your project is now connected to Claude OS.
/claude-os-session - Manage development sessions /claude-os-session - Manage development sessions
/claude-os-remember - Quick save to memories /claude-os-remember - Quick save to memories
🧪 TDD Skill Installed:
- RED-GREEN-REFACTOR workflow built-in
- Say "I'm using the TDD skill" to activate
- Write tests first, watch them fail, then implement
📂 Project Structure: 📂 Project Structure:
./CLAUDE.md - Project context (auto-loaded every session) ./CLAUDE.md - Project context (auto-loaded every session)
./.claude/ - Commands, skills, agents ./.claude/ - Commands, skills, agents

View file

@ -0,0 +1,298 @@
---
name: test-driven-development
description: Use when implementing any feature or bugfix, before writing implementation code - write the test first, watch it fail, write minimal code to pass; ensures tests actually verify behavior by requiring failure first
---
# Test-Driven Development (TDD)
## Overview
Write the test first. Watch it fail. Write minimal code to pass.
**Core principle:** If you didn't watch the test fail, you don't know if it tests the right thing.
**Violating the letter of the rules is violating the spirit of the rules.**
## When to Use
**Always:**
- New features
- Bug fixes
- Refactoring
- Behavior changes
**Exceptions (ask your human partner):**
- Throwaway prototypes
- Generated code
- Configuration files
Thinking "skip TDD just this once"? Stop. That's rationalization.
## The Iron Law
```
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
```
Write code before the test? Delete it. Start over.
**No exceptions:**
- Don't keep it as "reference"
- Don't "adapt" it while writing tests
- Don't look at it
- Delete means delete
Implement fresh from tests. Period.
## Red-Green-Refactor
### RED - Write Failing Test
Write one minimal test showing what should happen.
**Good:**
```typescript
test('retries failed operations 3 times', async () => {
let attempts = 0;
const operation = () => {
attempts++;
if (attempts < 3) throw new Error('fail');
return 'success';
};
const result = await retryOperation(operation);
expect(result).toBe('success');
expect(attempts).toBe(3);
});
```
Clear name, tests real behavior, one thing
**Bad:**
```typescript
test('retry works', async () => {
const mock = jest.fn()
.mockRejectedValueOnce(new Error())
.mockRejectedValueOnce(new Error())
.mockResolvedValueOnce('success');
await retryOperation(mock);
expect(mock).toHaveBeenCalledTimes(3);
});
```
Vague name, tests mock not code
**Requirements:**
- One behavior
- Clear name
- Real code (no mocks unless unavoidable)
### Verify RED - Watch It Fail
**MANDATORY. Never skip.**
```bash
npm test path/to/test.test.ts
```
Confirm:
- Test fails (not errors)
- Failure message is expected
- Fails because feature missing (not typos)
**Test passes?** You're testing existing behavior. Fix test.
**Test errors?** Fix error, re-run until it fails correctly.
### GREEN - Minimal Code
Write simplest code to pass the test.
**Good:**
```typescript
async function retryOperation<T>(fn: () => Promise<T>): Promise<T> {
for (let i = 0; i < 3; i++) {
try {
return await fn();
} catch (e) {
if (i === 2) throw e;
}
}
throw new Error('unreachable');
}
```
Just enough to pass
**Bad:**
```typescript
async function retryOperation<T>(
fn: () => Promise<T>,
options?: {
maxRetries?: number;
backoff?: 'linear' | 'exponential';
onRetry?: (attempt: number) => void;
}
): Promise<T> {
// YAGNI
}
```
Over-engineered
Don't add features, refactor other code, or "improve" beyond the test.
### Verify GREEN - Watch It Pass
**MANDATORY.**
```bash
npm test path/to/test.test.ts
```
Confirm:
- Test passes
- Other tests still pass
- Output pristine (no errors, warnings)
**Test fails?** Fix code, not test.
**Other tests fail?** Fix now.
### REFACTOR - Clean Up
After green only:
- Remove duplication
- Improve names
- Extract helpers
Keep tests green. Don't add behavior.
### Repeat
Next failing test for next feature.
## Good Tests
| Quality | Good | Bad |
|---------|------|-----|
| **Minimal** | One thing. "and" in name? Split it. | `test('validates email and domain and whitespace')` |
| **Clear** | Name describes behavior | `test('test1')` |
| **Shows intent** | Demonstrates desired API | Obscures what code should do |
## Why Order Matters
**"I'll write tests after to verify it works"**
Tests written after code pass immediately. Passing immediately proves nothing:
- Might test wrong thing
- Might test implementation, not behavior
- Might miss edge cases you forgot
- You never saw it catch the bug
Test-first forces you to see the test fail, proving it actually tests something.
**"I already manually tested all the edge cases"**
Manual testing is ad-hoc. You think you tested everything but:
- No record of what you tested
- Can't re-run when code changes
- Easy to forget cases under pressure
- "It worked when I tried it" ≠ comprehensive
Automated tests are systematic. They run the same way every time.
## Common Rationalizations
| Excuse | Reality |
|--------|---------|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after" | Tests passing immediately prove nothing. |
| "Already manually tested" | Ad-hoc ≠ systematic. No record, can't re-run. |
| "Need to explore first" | Fine. Throw away exploration, start with TDD. |
| "Test hard = design unclear" | Listen to test. Hard to test = hard to use. |
| "TDD will slow me down" | TDD faster than debugging. Pragmatic = test-first. |
## Red Flags - STOP and Start Over
- Code before test
- Test after implementation
- Test passes immediately
- Can't explain why test failed
- Tests added "later"
- Rationalizing "just this once"
**All of these mean: Delete code. Start over with TDD.**
## Example: Bug Fix
**Bug:** Empty email accepted
**RED**
```typescript
test('rejects empty email', async () => {
const result = await submitForm({ email: '' });
expect(result.error).toBe('Email required');
});
```
**Verify RED**
```bash
$ npm test
FAIL: expected 'Email required', got undefined
```
**GREEN**
```typescript
function submitForm(data: FormData) {
if (!data.email?.trim()) {
return { error: 'Email required' };
}
// ...
}
```
**Verify GREEN**
```bash
$ npm test
PASS
```
**REFACTOR**
Extract validation for multiple fields if needed.
## Verification Checklist
Before marking work complete:
- [ ] Every new function/method has a test
- [ ] Watched each test fail before implementing
- [ ] Each test failed for expected reason (feature missing, not typo)
- [ ] Wrote minimal code to pass each test
- [ ] All tests pass
- [ ] Output pristine (no errors, warnings)
- [ ] Tests use real code (mocks only if unavoidable)
- [ ] Edge cases and errors covered
Can't check all boxes? You skipped TDD. Start over.
## When Stuck
| Problem | Solution |
|---------|----------|
| Don't know how to test | Write wished-for API. Write assertion first. Ask your human partner. |
| Test too complicated | Design too complicated. Simplify interface. |
| Must mock everything | Code too coupled. Use dependency injection. |
| Test setup huge | Extract helpers. Still complex? Simplify design. |
## Debugging Integration
Bug found? Write failing test reproducing it. Follow TDD cycle. Test proves fix and prevents regression.
Never fix bugs without a test.
## Final Rule
```
Production code → test exists and failed first
Otherwise → not TDD
```
No exceptions without your human partner's permission.