diff --git a/app/core/file_watcher.py b/app/core/file_watcher.py
index c7a6cf5..0a2e397 100644
--- a/app/core/file_watcher.py
+++ b/app/core/file_watcher.py
@@ -178,6 +178,9 @@ class GlobalFileWatcher:
watcher = ProjectWatcher(project_id)
watcher.start()
self.watchers[project_id] = watcher
+ # Enable if we have active watchers
+ if self.watchers:
+ self.enabled = True
def stop_project(self, project_id: int):
"""Stop watching a project."""
@@ -187,6 +190,9 @@ class GlobalFileWatcher:
watcher = self.watchers.pop(project_id)
watcher.stop()
+ # Disable if no more watchers
+ if not self.watchers:
+ self.enabled = False
def restart_project(self, project_id: int):
"""Restart watcher for a project."""
diff --git a/docs/assets/og-image.png b/docs/assets/og-image.png
new file mode 100644
index 0000000..c989d0b
Binary files /dev/null and b/docs/assets/og-image.png differ
diff --git a/docs/index.html b/docs/index.html
index 5399b7d..4e9ebef 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -5,6 +5,26 @@
Claude OS - The AI Operating System That Never Forgets
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mcp_server/server.py b/mcp_server/server.py
index c1d8405..9f64e8f 100644
--- a/mcp_server/server.py
+++ b/mcp_server/server.py
@@ -3324,6 +3324,35 @@ async def startup_event():
except Exception as 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")
async def shutdown_event():
@@ -3340,6 +3369,14 @@ async def shutdown_event():
except Exception as 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():
"""Start the MCP server."""
diff --git a/start_all_services.sh b/start_all_services.sh
index 6b836b8..68b6e84 100755
--- a/start_all_services.sh
+++ b/start_all_services.sh
@@ -154,7 +154,7 @@ echo ""
# ===== 5. Start RQ Workers (Real-Time Learning System) =====
echo -e "${YELLOW}5. Starting RQ Workers (Real-Time Learning)...${NC}"
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=$!
echo " RQ Workers PID: $RQ_PID (logging to logs/rq_workers.log)"
echo -e " ${GREEN}โ RQ workers started${NC}"
diff --git a/templates/commands/claude-os-init.md b/templates/commands/claude-os-init.md
index e1caf3d..f8747f9 100644
--- a/templates/commands/claude-os-init.md
+++ b/templates/commands/claude-os-init.md
@@ -73,8 +73,8 @@ Let's get your project configured for AI-powered development.
- Default: `http://localhost:8051`
- Ask: `Claude OS server URL? [default: http://localhost:8051]`
-9. **Agent-OS Setup** (Optional):
- - Ask: `Enable Agent-OS for spec-driven development? [Y/n]`
+9. **Agent-OS Setup** (Optional - for advanced users):
+ - Ask: `Enable Agent-OS for spec-driven development? [y/N]`
- Explain:
```
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
- 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.
```
- If YES:
- Set `ENABLE_AGENT_OS=true`
- Will create `agent-os/` directory structure
- Will symlink agents to `.claude/agents/agent-os/`
- - If NO:
+ - If NO (default):
- Set `ENABLE_AGENT_OS=false`
- 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`
- 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`):**
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-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:
./CLAUDE.md - Project context (auto-loaded every session)
./.claude/ - Commands, skills, agents
diff --git a/templates/skills/test-driven-development/SKILL.md b/templates/skills/test-driven-development/SKILL.md
new file mode 100644
index 0000000..bd8bbf6
--- /dev/null
+++ b/templates/skills/test-driven-development/SKILL.md
@@ -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(fn: () => Promise): Promise {
+ 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(
+ fn: () => Promise,
+ options?: {
+ maxRetries?: number;
+ backoff?: 'linear' | 'exponential';
+ onRetry?: (attempt: number) => void;
+ }
+): Promise {
+ // 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.