Replace in-memory MessageLog with SQLite-backed implementation.
Same API surface (append/all/clear/len) so zero caller changes needed.
- data/chat.db stores messages with role, content, timestamp, source
- Lazy DB connection (opened on first use, not at import time)
- Retention policy: oldest messages pruned when count > 500
- New .recent(limit) method for efficient last-N queries
- Thread-safe with explicit locking
- WAL mode for concurrent read performance
- Test isolation: conftest redirects DB to tmp_path per test
- 8 new tests: persistence, retention, concurrency, source field
Closes#46
Agno's MCPTools has an undocumented executable whitelist that blocks
gitea-mcp (Go binary). Switch to server_params=StdioServerParameters()
which bypasses this restriction. Also fixes:
- Use tools.session.call_tool() for standalone invocation (MCPTools
doesn't expose call_tool() directly)
- Use close() instead of disconnect() for cleanup
- Resolve gitea-mcp path via ~/go/bin fallback when not on PATH
- Stub mcp.client.stdio in test conftest
Smoke-tested end-to-end against real Gitea: connect, list_issues,
create issue, close issue, create_gitea_issue_via_mcp — all pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consolidates 3 separate memory databases (semantic_memory.db, swarm.db
memory_entries, brain.db) into a single data/memory.db with facts,
chunks, and episodes tables.
Key changes:
- Add unified schema (timmy/memory/unified.py) with 3 core tables
- Redirect vector_store.py and semantic_memory.py to memory.db
- Add thought distillation: every Nth thought extracts lasting facts
- Enrich agent context with known facts in system prompt
- Add memory_forget tool for removing outdated memories
- Unify embeddings: vector_store delegates to semantic_memory.embed_text
- Bridge spark events to unified event log
- Add pruning for thoughts and events with configurable retention
- Add data migration script (timmy/memory_migrate.py)
- Deprecate brain.memory in favor of unified system
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Test data was bleeding into production tasks.db because
swarm.task_queue.models.DB_PATH (relative path) was never patched in
conftest.clean_database. Fixed by switching to absolute paths via
settings.repo_root and adding the missing module to the patching list.
Discord bot could leak orphaned clients on retry after ERROR state.
Added _cleanup_stale() to close stale client/task before each start()
attempt, with improved logging in the token watcher.
Rewrote test_paperclip_client.py to use httpx.MockTransport instead of
patching _get/_post/_delete — tests now exercise real HTTP status codes,
error handling, and JSON parsing. Added end-to-end test for
capture_error → create_task DB isolation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* polish: streamline nav, extract inline styles, improve tablet UX
- Restructure desktop nav from 8+ flat links + overflow dropdown into
5 grouped dropdowns (Core, Agents, Intel, System, More) matching
the mobile menu structure to reduce decision fatigue
- Extract all inline styles from mission_control.html and base.html
notification elements into mission-control.css with semantic classes
- Replace JS-built innerHTML with secure DOM construction in
notification loader and chat history
- Add CONNECTING state to connection indicator (amber) instead of
showing OFFLINE before WebSocket connects
- Add tablet breakpoint (1024px) with larger touch targets for
Apple Pencil / stylus use and safe-area padding for iPad toolbar
- Add active-link highlighting in desktop dropdown menus
- Rename "Mission Control" page title to "System Overview" to
disambiguate from the chat home page
- Add "Home — Timmy Time" page title to index.html
https://claude.ai/code/session_015uPUoKyYa8M2UAcyk5Gt6h
* fix(security): move auth-gate credentials to environment variables
Hardcoded username, password, and HMAC secret in auth-gate.py replaced
with os.environ lookups. Startup now refuses to run if any variable is
unset. Added AUTH_GATE_SECRET/USER/PASS to .env.example.
https://claude.ai/code/session_015uPUoKyYa8M2UAcyk5Gt6h
* refactor(tooling): migrate from black+isort+bandit to ruff
Replace three separate linting/formatting tools with a single ruff
invocation. Updates tox.ini (lint, format, pre-push, pre-commit envs),
.pre-commit-config.yaml, and CI workflow. Fixes all ruff errors
including unused imports, missing raise-from, and undefined names.
Ruff config maps existing bandit skips to equivalent S-rules.
https://claude.ai/code/session_015uPUoKyYa8M2UAcyk5Gt6h
---------
Co-authored-by: Claude <noreply@anthropic.com>
Replace the homebrew regex-based tool extraction and manual dispatch
(tool_executor.py) with Agno's built-in Human-In-The-Loop confirmation:
- Toolkit(requires_confirmation_tools=...) marks dangerous tools
- agent.run() returns RunOutput with status=paused when confirmation needed
- RunRequirement.confirm()/reject() + agent.continue_run() resumes execution
Dashboard and Discord vendor both use the native flow. DuckDuckGo import
isolated so its absence doesn't kill all tools. Test stubs cleaned up
(agno is a real dependency, only truly optional packages stubbed).
1384 tests pass in parallel (~14s).
Co-authored-by: Trip T <trip@local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Round 2+3 bug fix batch:
1. Ollama timeout: Add request_timeout=300 to prevent socket read errors
on complex 30-60s prompts (production crash fix)
2. Memory API: Create missing HTMX partial templates (memory_facts.html,
memory_results.html) so Save/Search buttons work
3. CALM page: Add create_tables() call so SQLAlchemy tables exist on
first request (was returning HTTP 500)
4. Task Queue: Full SQLite-backed rebuild with CRUD endpoints, HTMX
partials, and action buttons (approve/veto/pause/cancel/retry)
5. Work Orders: Full SQLite-backed rebuild with submit/approve/reject/
execute pipeline and HTMX polling partials
6. Memory READ tool: Add memory_read function so Timmy stops calling
read_file when trying to recall stored facts
Also: Close GitHub issues #115, #114, #112, #110 as won't-fix.
Comment on #107 confirming prune_memories() already wired to startup.
Tests: 33 new tests across 4 test files, all passing.
Full suite: 1155 passed, 2 pre-existing failures (hands_shell).
Co-authored-by: Trip T <trip@local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* CI/CD Optimization: Guard Rails, Black Linting, and Pre-commit Hooks
- Fixed all test collection errors (Selenium imports, fixture paths, syntax)
- Implemented pre-commit hooks with Black formatting and isort
- Created comprehensive Makefile with test targets (unit, integration, functional, e2e)
- Added pytest.ini with marker definitions for test categorization
- Established guard rails to prevent future collection errors
- Wrapped optional dependencies (Selenium, MoviePy) in try-except blocks
- Added conftest_markers for automatic test categorization
This ensures a smooth development stream with:
- Fast feedback loops (pre-commit checks before push)
- Consistent code formatting (Black)
- Reliable CI/CD (no collection errors, proper test isolation)
- Clear test organization (unit, integration, functional, E2E)
* Fix CI/CD test failures:
- Export templates from dashboard.app
- Fix model name assertion in test_agent.py
- Fix platform-agnostic path resolution in test_path_resolution.py
- Skip Docker tests in test_docker_deployment.py if docker not available
- Fix test_model_fallback_chain logic in test_ollama_integration.py
* Add preventative pre-commit checks and Docker test skipif decorators:
- Create pre_commit_checks.py script for common CI failures
- Add skipif decorators to Docker tests
- Improve test robustness for CI environments
## Summary
Complete refactoring of Timmy Time from monolithic architecture to microservices
using Test-Driven Development (TDD) and optimized Docker builds.
## Changes
### Core Improvements
- Optimized dashboard startup: moved blocking tasks to async background processes
- Fixed model fallback logic in agent configuration
- Enhanced test fixtures with comprehensive conftest.py
### Microservices Architecture
- Created separate Dockerfiles for dashboard, Ollama, and agent services
- Implemented docker-compose.microservices.yml for service orchestration
- Added health checks and non-root user execution for security
- Multi-stage Docker builds for lean, fast images
### Testing
- Added E2E tests for dashboard responsiveness
- Added E2E tests for Ollama integration
- Added E2E tests for microservices architecture validation
- All 36 tests passing, 8 skipped (environment-specific)
### Documentation
- Created comprehensive final report
- Generated issue resolution plan
- Added interview transcript demonstrating core agent functionality
### New Modules
- skill_absorption.py: Dynamic skill loading and integration system for Timmy
## Test Results
✅ 36 passed, 8 skipped, 6 warnings
✅ All microservices tests passing
✅ Dashboard responsiveness verified
✅ Ollama integration validated
## Files Added/Modified
- docker/: Multi-stage Dockerfiles for all services
- tests/e2e/: Comprehensive E2E test suite
- src/timmy/skill_absorption.py: Skill absorption system
- src/dashboard/app.py: Optimized startup logic
- tests/conftest.py: Enhanced test fixtures
- docker-compose.microservices.yml: Service orchestration
## Breaking Changes
None - all changes are backward compatible
## Next Steps
- Integrate skill absorption system into agent workflow
- Test with microservices-tdd-refactor skill
- Deploy to production with docker-compose orchestration
- Add `requests` to conftest.py module stubs so patch("requests.post") works
in reward scoring tests without the package installed
- Use sys.executable instead of bare "python" in git safety tests so the
subprocess finds pytest from the venv rather than system python
https://claude.ai/code/session_012Ye9nyFEiw2QQfx4bZeDmn
Introduces a vendor-agnostic chat platform architecture:
- chat_bridge/base.py: ChatPlatform ABC, ChatMessage, ChatThread
- chat_bridge/registry.py: PlatformRegistry singleton
- chat_bridge/invite_parser.py: QR + Ollama vision invite extraction
- chat_bridge/vendors/discord.py: DiscordVendor with native threads
Workflow: paste a screenshot of a Discord invite or QR code at
POST /discord/join → Timmy extracts the invite automatically.
Every Discord conversation gets its own thread, keeping channels clean.
Bot responds to @mentions and DMs, routes through Timmy agent.
43 new tests (base classes, registry, invite parser, vendor, routes).
https://claude.ai/code/session_01WU4h3cQQiouMwmgYmAgkMM
Add infrastructure for running swarm agents as isolated Docker
containers with HTTP-based coordination, startup recovery, and
enhanced dashboard UI for agent management.
- Dockerfile and docker-compose.yml for multi-service orchestration
- DockerAgentRunner for programmatic container lifecycle management
- Internal HTTP API for container agents to poll tasks and submit bids
- Startup recovery system to reconcile orphaned tasks and stale agents
- Enhanced UI partials for agent panels, chat, and task assignment
- Timmy docker entry point with heartbeat and task polling
- New Makefile targets for Docker workflows
- Tests for swarm recovery
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bridges Telegram messages to Timmy via python-telegram-bot (optional
dependency). The bot token can be supplied through the TELEGRAM_TOKEN
env var or at runtime via the new POST /telegram/setup dashboard
endpoint, which (re)starts the bot without a restart.
Changes:
- src/telegram_bot/bot.py — TelegramBot singleton: token persistence
(telegram_state.json), lifecycle (start/stop), /start command and
message handler that forwards to Timmy
- src/dashboard/routes/telegram.py — /telegram/setup and /telegram/status
FastAPI routes
- src/dashboard/app.py — register telegram router; auto-start/stop bot
in lifespan hook
- src/config.py — TELEGRAM_TOKEN setting (pydantic-settings)
- pyproject.toml — [telegram] optional extra (python-telegram-bot>=21),
telegram_bot wheel include
- .env.example — TELEGRAM_TOKEN section
- .gitignore — exclude telegram_state.json (contains token)
- tests/conftest.py — stub telegram/telegram.ext for offline test runs
- tests/test_telegram_bot.py — 16 tests covering token helpers,
lifecycle, and all dashboard routes (370 total, all passing)
https://claude.ai/code/session_01CNBm3ZLobtx3Z1YogHq8ZS
- Add dashboard/store.py: MessageLog dataclass singleton tracking
user/agent/error messages for the lifetime of the server process
- agents.py: write each chat turn to MessageLog; add GET and DELETE
/agents/timmy/history routes returning the history.html partial
- partials/history.html: render stored messages by role (YOU / TIMMY /
SYSTEM); falls back to the Mission Control init message when empty
- index.html: chat-log loads history via hx-get on page start; new
CLEAR button in panel header sends hx-delete to reset the log
- style.css: add .mc-btn-clear (muted, red-on-hover for the header)
- tests: autouse reset_message_log fixture in conftest; 5 new history
tests covering empty state, recording, offline errors, clear, and
post-clear state → 32 tests total, all passing
https://claude.ai/code/session_01KZMfwBpLuiv6x9GbzTqbys