Timmy can now delegate coding tasks to Kimi CLI (262K context).
Includes timeout handling, workdir validation, output truncation.
Sovereign division of labor — Timmy plans, Kimi codes.
Timmy can now run his own test suite via the run_self_tests() tool.
Supports 'fast' (unit only), 'full', or specific path scopes.
Returns structured results with pass/fail counts.
Sovereign self-verification — a fundamental capability.
- Replace flat file list with layered architecture map (config→agent→prompt→tool→memory→interface)
- Add SELF-MODIFICATION section: Timmy knows he can edit his own config and code
- Remove false limitation 'cannot modify own source code'
- Update tests to match new section headers, add self-modification tests
Closes#81 (reasoning depth)
Closes#86 (self-modification awareness)
[loop-cycle-11]
_maybe_consolidate() now checks get_memories(subject=agent_id)
before storing. Skips if a memory of the same type (pattern/anomaly)
was created within the last hour. Prevents duplicate consolidation
entries on repeated task completion/failure events.
Also restructured branching: neutral success rates (0.3-0.8) now
return early instead of falling through.
9 new tests. 1465 total passing.
Adds SELF-KNOWLEDGE section to both SYSTEM_PROMPT_LITE and
SYSTEM_PROMPT_FULL with:
- Codebase map (all src/timmy/ modules with descriptions)
- Current capabilities list (grounded, not generic)
- Known limitations (real gaps, not LLM platitudes)
Lite prompt gets condensed version; full prompt gets detailed.
Timmy can now answer 'what does tool_safety.py do?' and give
grounded answers about his actual limitations.
10 new tests. 1456 total passing.
Changed message param from str to list[str] in chat() and route() commands.
Words are joined with spaces, so 'timmy chat hello how are you' works without
quoting. Single-word messages still work as before.
- chat(): message: list[str], joined to full_message
- route(): message: list[str], joined to full_message
- 7 new tests in test_cli_multiword.py
Closes#26
Timmy can now introspect which session he's running in (cli, dashboard, loop).
- Add {session_id} placeholder to both lite and full system prompts
- get_system_prompt() accepts session_id param (default: 'unknown')
- create_timmy() accepts session_id param, forwards to prompt
- CLI chat/think/status pass their session_id to create_timmy()
- session.py passes _DEFAULT_SESSION_ID to create_timmy()
- 7 new tests in test_session_identity.py
- Updated 2 existing CLI test mocks
Closes#64
- Use sys.executable instead of hardcoded "python" in tests
- Fixes test_run_python_expression and test_run_nonzero_exit
- Passes allowed_prefixes for both python and python3
- Replace substring matching with word-boundary regex in route_request()
- "fix the bug" now correctly routes to coder
- Multi-word patterns match if all words appear (any order)
- Add "timmy route" CLI command for debugging routing
- Add route_request_with_match() for pattern visibility
- Expand routing keywords in agents.yaml
- 22 new routing tests, all passing
Comprehensive test coverage for the semantic memory module:
- _simple_hash_embedding determinism and normalization
- cosine_similarity including zero vectors
- SemanticMemory: init, index_file, index_vault, search, stats
- _split_into_chunks with various sizes
- memory_search, memory_read, memory_write, memory_forget tools
- MemorySearcher class
- Edge cases: empty DB, unicode, very long text, special chars
- All tests use tmp_path for isolation, no sentence-transformers needed
86 tests, all passing. 1393 total tests passing.
All `except Exception:` now catch as `except Exception as exc:` with
appropriate logging (warning for critical paths, debug for graceful degradation).
Added logger setup to 4 files that lacked it:
- src/timmy/memory/vector_store.py
- src/dashboard/middleware/csrf.py
- src/dashboard/middleware/security_headers.py
- src/spark/memory.py
31 files changed across timmy core, dashboard, infrastructure, integrations.
Zero bare excepts remain. 1340 tests passing.
- Add ollama_num_ctx setting (default 4096) to config.py
- Pass num_ctx option to Ollama in agent.py and agents/base.py
- Add OLLAMA_NUM_CTX to .env.example with usage docs
- Add context_window note in providers.yaml
- Fix mock_settings in test_agent.py for new attribute
- qwen3:30b with 4096 ctx uses ~19GB vs 45GB default
- BaseAgent.run(): catch httpx.ConnectError/ReadError/ConnectionError,
log 'Ollama disconnected: <error>' at ERROR level, then re-raise
- session.py: distinguish Ollama disconnects from other errors in
chat(), chat_with_tools(), continue_chat() — return specific message
'Ollama appears to be disconnected' instead of generic error
- 11 new tests covering all disconnect paths
Wrap numpy and voice_loop imports in try/except with pytestmark skipif.
Tests skip cleanly instead of ImportError when numpy not in dev deps.
Closes#48
Add _warmup_model() that sends a minimal generation request (1 token)
before returning the Agent. 60s timeout handles cold VRAM loads.
Warns but does not abort if warmup fails.
Closes#82
Remove DuckDuckGoTools import, all web_search registrations across 4 toolkit
factories, catalog entry, safety classification, prompt references, and
session regex. Total: -41 lines of dead code.
consult_grok is functional (grok_enabled=True, API key set) and opt-in,
so it stays — but Timmy never calls it autonomously, which is correct
sovereign behavior (no cloud calls unless user permits).
Closes#87
_get_ollama_model() used prefix match (startswith) on /api/tags,
causing qwen3:30b to match qwen3.5:latest. Now:
1. Queries /api/ps (loaded models) first — most accurate
2. Falls back to /api/tags with exact name match
3. Reports actual running model, not just configured one
Updated test_get_system_info_contains_model to not assume model==config.
Fixes#77. 5 regression tests added.
Add config/allowlist.yaml — YAML-driven gate that auto-approves bounded
tool calls when no human is present.
When Timmy runs with --autonomous or stdin is not a terminal, tool calls
are checked against allowlist: matched → auto-approved, else → rejected.
Changes:
- config/allowlist.yaml: shell prefixes, deny patterns, path rules
- tool_safety.py: is_allowlisted() checks tools against YAML rules
- cli.py: --autonomous flag, _is_interactive() detection
- 44 new allowlist tests, 8 updated CLI tests
Closes#69