This guide documents known issues, best practices, and troubleshooting steps for coding agents working on this codebase.
.claude/commands and .claude/skills are Git symlinks that point into .agents/. On Linux and macOS this works automatically after cloning.
On Windows, do this once before cloning (or before your first git checkout):
- Enable Developer Mode: Settings → System → For developers → Developer Mode → On
git config --global core.symlinks true
Without Developer Mode, Git materialises symlinks as plain text stub files instead of real filesystem links.
Problem: Tests checking for specific strings in Typer command help output fail on Linux CI but pass on local Windows development.
Environment:
- Fails: Ubuntu 24.04 (GitHub Actions)
- Passes: Windows 11 with Python 3.12.13
Root Cause:
Typer's CliRunner help text formatting varies significantly by environment due to:
- Terminal width differences
- ANSI code handling variation
- Typer version behavior differences
- The
@app.callback(invoke_without_command=True)decorator doesn't reliably display options in all environments
Original Failing Test:
def test_check_help() -> None:
result = runner.invoke(check_app, ["--help"])
assert result.exit_code == 0
assert "--path" in result.stdout # FAILS in CI, passes locallySolution (Applied): Test the actual functionality of the option instead of the help text display:
def test_check_help() -> None:
result = runner.invoke(check_app, ["--help"])
assert result.exit_code == 0
# Verify that the command accepts --path by testing it
registry.register(_Pass())
result = runner.invoke(check_app, ["--path", "."])
assert result.exit_code == 0
assert "a-ok" in result.stdoutKey Lesson: Never assert on terminal output formatting. Test functionality instead.
- ✅ DO: Check that a command produces correct output results
- ❌ DON'T: Assert on specific strings in help output, spacing, colors, or alignment
- ✅ DO: Use
result.exit_codeand check for functional output - ❌ DON'T: Check for
--option-namein help text, ANSI codes, formatting
from typer.testing import CliRunner
runner = CliRunner()
result = runner.invoke(app, ["command", "--option", "value"])
# Check what matters
assert result.exit_code == 0 # Command succeeded
assert "expected-output" in result.stdout # Actual result, not formattingInstead of:
result = runner.invoke(app, ["--help"])
assert "--myoption" in result.stdout # Fragile, environment-dependentDo this:
# Test that the option actually works
result = runner.invoke(app, ["--myoption", "value"])
assert result.exit_code == 0
assert "expected-behavior" in result.stdout-
Identify Failure Type
- Code/test failure: Check
pytestoutput for specific assertion failures - Action failure: Check GitHub Actions logs for setup/environment issues
- Linting failure: Check
ruffoutput for specific violations
- Code/test failure: Check
-
Check for Environment-Specific Issues
- Note the OS and Python version from CI logs
- Check if test passes locally
- Look for terminal output assertions (likely culprit)
-
Search History
git log --oneline --all -- <affected-file> git show <commit>:<affected-file> # See what changed
-
Document Findings
- Add to this file if it's a new pattern
- Update related test comments with workaround details
Check the full CI logs:
gh run list --repo intent-book/iec-cli --limit 1
gh run view <run-id> --log --repo intent-book/iec-cliLook for:
- Python version running
- Specific assertion that failed
- Any error messages from dependencies
- Terminal/formatting-related output
main.py: Entry point, adds check_app and init command to main appcheck.py: Check command logic using@check_app.callback(invoke_without_command=True)check_appis added to main app as a sub-app:app.add_typer(check_app, name="check")
Important: The callback decorator is required because check_app is a sub-app. Don't change to @check_app.command() as it breaks the command invocation structure.
tests/integration/: End-to-end tests with real checkers and CLItests/: Unit tests for individual componentstests/integration/test_check.py: Tests for check command functionality (not help text)
Current: typer>=0.15
Note: This is a loose constraint. If environment-specific issues reoccur, consider pinning to a tested version:
typer>=0.15,<0.26 # Tested rangeMonitor: https://github.com/tiangolo/typer/releases
| Problem | Solution |
|---|---|
--help test fails on CI but passes locally |
Don't test help text. Test option functionality instead. |
| Tests pass locally, fail on CI | Check for environment assumptions (os, terminal, Python version) |
| New Typer version breaks tests | See if help text assertions are involved; use functionality tests instead. |
| Linting fails | Run uv run ruff check . and uv run ruff format . locally first |
| Tests fail on import | Run uv sync to ensure dependencies are installed |
# Run tests
uv run pytest # All tests
uv run pytest tests/integration/ # Only integration tests
uv run pytest tests/test_check.py -xvs # Single file, verbose, stop on first failure
# Linting
uv run ruff check . # Check for issues
uv run ruff format . # Auto-format
# Check actual CLI
uv run iec check --help
uv run iec init --help