"""Deep focus mode — single-problem context for Timmy. Persists focus state to a JSON file so Timmy can maintain narrow, deep attention on one problem across session restarts. Usage: from timmy.focus import focus_manager focus_manager.set_topic("three-phase loop") topic = focus_manager.get_topic() # "three-phase loop" ctx = focus_manager.get_focus_context() # prompt injection string focus_manager.clear() """ import json import logging from pathlib import Path logger = logging.getLogger(__name__) _DEFAULT_STATE_DIR = Path.home() / ".timmy" _STATE_FILE = "focus.json" class FocusManager: """Manages deep-focus state with file-backed persistence.""" def __init__(self, state_dir: Path | None = None) -> None: self._state_dir = state_dir or _DEFAULT_STATE_DIR self._state_file = self._state_dir / _STATE_FILE self._topic: str | None = None self._mode: str = "broad" self._load() # ── Public API ──────────────────────────────────────────────── def get_topic(self) -> str | None: """Return the current focus topic, or None if unfocused.""" return self._topic def get_mode(self) -> str: """Return 'deep' or 'broad'.""" return self._mode def is_focused(self) -> bool: """True when deep-focus is active with a topic set.""" return self._mode == "deep" and self._topic is not None def set_topic(self, topic: str) -> None: """Activate deep focus on a specific topic.""" self._topic = topic.strip() self._mode = "deep" self._save() logger.info("Focus: deep-focus set → %r", self._topic) def clear(self) -> None: """Return to broad (unfocused) mode.""" old = self._topic self._topic = None self._mode = "broad" self._save() logger.info("Focus: cleared (was %r)", old) def get_focus_context(self) -> str: """Return a prompt-injection string for the current focus state. When focused, this tells the model to prioritize the topic. When broad, returns an empty string (no injection). """ if not self.is_focused(): return "" return ( f"[DEEP FOCUS MODE] You are currently in deep-focus mode on: " f'"{self._topic}". ' f"Prioritize this topic in your responses. Surface related memories " f"and prior conversation about this topic first. Deprioritize " f"unrelated context. Stay focused — depth over breadth." ) # ── Persistence ─────────────────────────────────────────────── def _load(self) -> None: """Load focus state from disk.""" if not self._state_file.exists(): return try: data = json.loads(self._state_file.read_text()) self._topic = data.get("topic") self._mode = data.get("mode", "broad") except Exception as exc: logger.warning("Focus: failed to load state: %s", exc) def _save(self) -> None: """Persist focus state to disk.""" try: self._state_dir.mkdir(parents=True, exist_ok=True) self._state_file.write_text( json.dumps({"topic": self._topic, "mode": self._mode}, indent=2) ) except Exception as exc: logger.warning("Focus: failed to save state: %s", exc) # Module-level singleton focus_manager = FocusManager()