# Decisions Log

<!-- Append-only. Each decision includes rationale and date. -->
<!-- Format: ### D-NNN: <decision title> -->

### D-001: Typer over Click for CLI
- **Date**: 2026-02-27
- **Decision**: Use Typer as the CLI framework instead of Click.
- **Rationale**: Typer builds on Click but provides type-hint-driven commands, auto-generated help, and cleaner syntax. Better developer ergonomics for a project with many commands.
- **Alternatives considered**: Click (too verbose), argparse (too low-level), Fire (too magic)

### D-002: Textual for TUI dashboard
- **Date**: 2026-02-27
- **Decision**: Use Textual for the interactive TUI dashboard (must-have feature).
- **Rationale**: Native Python, Rich-compatible, supports reactive widgets, CSS-like styling. The TUI is the primary interface — not an afterthought.
- **Alternatives considered**: urwid (dated API), blessed (less maintained), pure Rich (no widgets)

### D-003: Docker sandbox for agent execution
- **Date**: 2026-02-27
- **Decision**: Agents run inside Docker containers (`ievoai/sandbox:latest`), not directly on host.
- **Rationale**: Isolation, reproducibility, consistent environment. Prevents agents from accessing host system outside project scope.
- **Limitations**: Docker must be installed, slight startup overhead.

### D-004: OAuth token over API key
- **Date**: 2026-02-28
- **Decision**: Use `CLAUDE_CODE_OAUTH_TOKEN` (subscription-based) instead of `ANTHROPIC_API_KEY` (pay-per-use).
- **Rationale**: Subscription model = free per-token usage. API key = direct cost per call. For an agent framework that makes many calls, subscription is critical.

### D-005: uv as package manager
- **Date**: 2026-02-27
- **Decision**: Use uv for dependency management and virtual environments.
- **Rationale**: 10-100x faster than pip, built-in lockfile support, drop-in pip replacement. Maintained by Astral (ruff team).

### D-006: Marketplace as separate repo
- **Date**: 2026-02-27
- **Decision**: Agent marketplace lives in `ievo-ai/marketplace`, not embedded in CLI.
- **Rationale**: Agents evolve independently of CLI. Marketplace has its own versioning, registry.yaml, and evolution cycle. CLI fetches agents via registry.

### D-008: TUI-first model — CLI commands deprecated
- **Date**: 2026-03-03
- **Decision**: All CLI commands except `ievo config` are deprecated. `ievo` (no args) is now the primary entry point.
- **Rationale**: Agent composition, lifecycle, and orchestration are managed autonomously by the HR agent and TUI. Exposing these as user-facing CLI commands creates friction and leaks implementation details.
- **Alternatives considered**: Keep all commands active (rejected — confusing dual surface), remove commands immediately (rejected — breaks existing scripts).
- **Affects**: REQ-001, REQ-002, REQ-003

### D-009: Deprecation via warning, not removal
- **Date**: 2026-03-03
- **Decision**: Deprecated commands print a warning but continue to function.
- **Rationale**: Immediate removal would break users who scripted these commands. Warning gives a migration window.
- **Pattern**: `deprecated_command(name, alternative)` utility in `src/ievo/utils/deprecation.py`.

### D-010: Internal vs CLI surface split for `add`
- **Date**: 2026-03-03
- **Decision**: `add_agents(list[str])` is the internal API (no deprecation warning), `add(Argument)` is the CLI wrapper (with warning).
- **Rationale**: HR agent calls `add_agents()` programmatically — it should not see CLI deprecation noise. The warning belongs only on the human-facing surface.

### D-012: Git flow — trunk-based development
- **Date**: 2026-03-03
- **Decision**: This project uses trunk-based development. Feature branches are short-lived and branch off `main`. PRs target `main`.
- **Branch naming**: `<type>/<ticket>-<description>` — e.g., `feat/REQ-001-auto-init-confirmation`, `fix/REQ-002-docker-build`
- **Rationale**: Discovered after a coordination failure where the Coder committed directly to `test/full-cycle-v3` without asking. Git flow was not in memory and the agent made an assumption.
- **Rule**: Coder and Architect agents MUST check DECISIONS.md for a D-xxx entry about git flow before the first commit of any requirement. If no entry exists, ASK the user before committing.
- **Evolution signal**: see `.ievo/evolution/LOG.md` E-002

### D-007: Native Claude Code sub-agents
- **Date**: 2026-03-02
- **Decision**: Agents are native Claude Code `.md` files with YAML frontmatter, deployed to `.claude/agents/`.
- **Rationale**: Claude Code natively auto-delegates to sub-agents based on `description` field. No custom orchestration needed. Each agent has `memory: user` for cross-project learning.

### D-011: Spec-writer is a mandatory pipeline gate, not optional
- **Date**: 2026-03-03
- **Decision**: No feature may enter the Architect or Coder stage without a corresponding `REQ-xxx.md` file with status `ready` in `.ievo/spec/requirements/`. This applies even when user phrasing makes the request feel like a direct coding ask.
- **Rationale**: A session where REQ-001 through REQ-003 were implemented without prior REQ files demonstrated that: (1) acceptance criteria were retroactively created, (2) scope was not formally frozen before implementation began, (3) pipeline integrity was broken.
- **Rule**: When a user describes a new feature, the first response is always delegation to spec-writer. Never planning or coding without a ready REQ.
- **Evolution signal**: https://github.com/ievo-ai/curator/issues/1

### D-014: External communications must be sanitized to pattern-level abstraction
- **Date**: 2026-03-03
- **Decision**: Any content posted to an external or public repository (issues, comments, PRs) must contain ONLY abstract pattern descriptions. It must NOT contain: config key names, file paths, module names, code snippets, agent instruction text, naming conventions, or any detail that reveals internal architecture.
- **Rationale**: The evolution agent posted three curator issues containing internal implementation details (key names, code snippets, file structure). The user had to manually redact all three. Public issues are readable by anyone — the audience is not the project team. The sanitization rule that existed previously covered only credentials, not structural details.
- **Rule**: Before posting to any external repo, apply an audience check: "Could this be published as a blog post with no context, without revealing how this project is implemented?" If no, strip further. Describe the error class and proposed fix in terms of agent behaviour patterns, not project specifics.
- **Scope**: Evolution agent and any other agent that files external issues (e.g., curator signals, marketplace reports).
- **Evolution signal**: see `.ievo/evolution/LOG.md` E-004

### D-015: PR health check must collect all blocking signals before acting on any one
- **Date**: 2026-03-03
- **Decision**: When asked to diagnose why a PR is blocked, collect all blocking signals before beginning any fix. Do not treat the first signal found as the complete answer.
- **Checklist**: (1) CI status — `gh pr checks`, (2) merge state and review decisions — `gh pr view --json mergeStateStatus,mergeable,reviewDecision`, (3) branch freshness — `git fetch origin main && git log origin/main --not HEAD`, (4) review comments — `gh pr view --json reviews`.
- **Rationale**: A session where the agent fixed only CI failures and missed a branch-behind-base condition and reviewer change requests required the user to prompt the agent twice to surface the remaining blockers. The agent mapped "PR blocked" to "CI failed" and stopped — a one-dimensional diagnosis.
- **Rule**: After running the full checklist, report ALL blockers in a single summary before starting any fix. A PR is clear only when all four checks return green.
- **Evolution signal**: see `.ievo/evolution/LOG.md` E-005

### D-016: Evolution lessons must be propagated to working docs, not only logged
- **Date**: 2026-03-03
- **Decision**: An evolution lesson is not complete until it appears in the document agents actually load. For project-wide rules, that document is CLAUDE.md. For agent-specific rules, it is the agent's ROLE.md.
- **Rationale**: E-001 through E-005 were logged in `.ievo/evolution/LOG.md` and DECISIONS.md but none reached CLAUDE.md. A grep confirmed zero matches for any of the five new rules. Lessons that exist only in reference files produce no behavior change in future sessions.
- **Rule**: After filing a curator issue for any evolution finding, update the governing working document with a concise rule. Evolution is not complete until the rule is in the document agents read.
- **Evolution signal**: see `.ievo/evolution/LOG.md` E-006

### D-017: ievo update repurposed as CLI self-update
- **Date**: 2026-03-03
- **Decision**: `ievo update` is repurposed from a deprecated agent-update command (pointing users to the HR agent) into a first-class CLI self-update command that fetches the latest version from PyPI and upgrades via the detected installer (`uvx`, `uv tool`, or `pip`).
- **Rationale**: The agent-update behavior is obsolete (HR agent owns that). `ievo update` is a natural, memorable entry point for users wanting to upgrade the tool itself.
- **Installer detection order**: (1) script path contains `.cache/uv/` or `uvx` → uvx, (2) script path under `~/.local/share/uv/tools/ievo/` → uv tool, (3) fallback → pip.
- **PyPI API**: `https://pypi.org/pypi/ievo/json`, fetched via httpx, timeout 10s.
- **Affects**: REQ-004, CR-001 (against REQ-002)

### D-013: Tests must satisfy guard conditions with real state, not mock internal functions
- **Date**: 2026-03-03
- **Decision**: When a test fails in CI because a code path calls `input()` or any interactive prompt, the fix is to satisfy the guard condition that determines whether that path is taken — using real config files, real directories, real state. Function-level mocking of application logic is prohibited.
- **Rationale**: `prompt_github_auth()` is guarded by `if get_config(home, "github_auth") is None`. The correct test setup writes `config.json` with `{"github_auth": "gh_cli"}` so the guard evaluates to False and the function is never reached. This exercises the same code path that real users with a configured `~/.ievo/config.json` experience. Mocking the function itself bypasses the guard entirely and silently passes even if the guard logic is broken or the function is renamed.
- **Rule**: When a CI failure is caused by a function reading stdin: (1) trace the call upward to find its guard condition, (2) write real state that satisfies the guard, (3) verify the function is no longer reached. Mocks are only permitted for true external boundaries (Docker daemon, network, OS subprocess).
- **Affects**: `tests/test_cli_app.py::test_auto_init_creates_project`, `src/ievo/commands/init.py`
- **Evolution signal**: https://github.com/ievo-ai/curator/issues/3

### D-018: TUI integration tests use Textual Pilot in separate file
- **Date**: 2026-03-03
- **Decision**: TUI integration tests (Pilot-based, async) live in `tests/test_tui_integration.py`, separate from existing `tests/test_tui.py` (unit-level, mock-based). Both files coexist.
- **Rationale**: Pilot tests exercise the full Textual lifecycle with real widgets and event routing. Mock-based tests provide fast, targeted coverage for internal methods. Mixing them in one file creates confusion about what each test actually verifies.
- **Testing pattern**: `pytest-asyncio` with `asyncio_mode = "auto"`. Each test creates its own `app.run_test()` context with `tmp_path`-based project. `await pilot.pause()` after every action. `notifications=True` when testing toasts.
- **Affects**: REQ-007

### D-020: Template version tracking via single cli_version field (not per-template)
- **Date**: 2026-03-03
- **Decision**: Track template staleness with a single `cli_version: str` field in `ProjectManifest`, not a per-template version map or content hashes.
- **Rationale**: Templates only change when the CLI package version changes. Per-template tracking is unnecessary complexity. Content hashing was rejected as overkill — version strings are already available.
- **Behaviour on old projects**: `cli_version = ""` (absent from manifest) → no staleness notification. Silent grace period for projects that predate this feature.
- **User control**: No auto-refresh. TUI shows a toast; user presses `t` to refresh. Single warning notification before overwrite — no second confirmation prompt.
- **Affects**: REQ-009

### D-021: New project conventions must be documented atomically with creation

- **Date**: 2026-03-04
- **Decision**: Whenever any agent establishes a new `.ievo/` directory, file type, or naming convention, the pipeline reference document (`src/ievo/marketplace/templates/iEVO.md`) MUST be updated in the same session before ending. Creating a structure and documenting the convention are one atomic action — they are never two separate steps.
- **Rationale**: A new `.ievo/research/` directory and naming convention (`YYYY-MM-DD-<topic>.md`) were created without updating `iEVO.md`. The user had to explicitly point this out in a later session. The pattern repeats a known failure mode: rules that fire only reactively (after feedback) produce documentation gaps. A proactive rule at the moment of creation closes the gap permanently.
- **Rule**: Session end checklist for any agent: "Did I create or establish any new directory structure, file type, or naming convention? If yes, is it documented in `src/ievo/marketplace/templates/iEVO.md`?"
- **Evolution signal**: see `.ievo/evolution/KERNEL.md`, `.ievo/evolution/LOG.md` E-010

### D-022: Context-loaded files must not contain visual artifacts

- **Date**: 2026-03-04
- **Decision**: Files that agents auto-load as context at session start (iEVO.md, CLAUDE.md, agent overlays) must contain only machine-actionable rules and state. Visual artifacts — ASCII diagrams, illustrative flowcharts, large orientation tables — must not be added to these files.
- **Rationale**: An ASCII diagram was added to a context-critical file. The user rejected immediately: visual content inflates context token budget with no benefit to agent reasoning. ASCII diagrams are human communication artifacts — they communicate structure visually to a human reader but add noise to a machine consumer.
- **Rule**: Before editing a context-loaded file, classify the content being added. If it is a human-only artifact, route it to README, docs/, or deliver as chat output. Do not add it to agent context files.
- **Placement for visual content**: README, docs/, or inline in chat.
- **Evolution signal**: https://github.com/ievo-ai/curator/issues/11

### D-019: IevoApp AUTO_FOCUS targets SelectionList
- **Date**: 2026-03-03
- **Decision**: `IevoApp.AUTO_FOCUS = "#agents-list"` instead of the default `"*"`.
- **Rationale**: The default `"*"` selector focuses the first focusable widget in DOM order, which is `ContentTabs` (TabbedContent's internal tab strip), not the `SelectionList` that users need to interact with. This made the TUI appear non-interactive -- users had to press Tab first to reach the agent list.
- **Affects**: REQ-007, `src/ievo/tui/app.py`
