- Document tea CLI TTY errors and YES="" workaround - Record wrong parameter names (--body vs --description) - Add Gitea API hostname corrections - Include Git configuration errors - Document Python/pytest common issues Each failure includes: - ❌ Failing command - 💡 Failure reason - ✅ Working solution - 📝 Additional notes Closes #11 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
7.3 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Git Workflow Policy
CRITICAL: All code changes MUST follow this workflow. Direct pushes to main are ABSOLUTELY PROHIBITED.
- Create Gitea Issue First — All features, bug fixes, and policy changes require a Gitea issue before any code is written
- Create Feature Branch — Branch from
mainusing formatfeature/issue-{N}-{short-description} - Implement Changes — Write code, tests, and documentation on the feature branch
- Create Pull Request — Submit PR to
mainbranch referencing the issue number - Review & Merge — After approval, merge via PR (squash or merge commit)
Never commit directly to main. This policy applies to all changes, no exceptions.
Common Command Failures
Critical: Learn from failures. Never repeat the same failed command without modification.
tea CLI (Gitea Command Line Tool)
❌ TTY Error - Interactive Confirmation Fails
~/bin/tea issues create --repo X --title "Y" --description "Z"
# Error: huh: could not open a new TTY: open /dev/tty: no such device or address
💡 Reason: tea tries to open /dev/tty for interactive confirmation prompts, which is unavailable in non-interactive environments.
✅ Solution: Use YES="" environment variable to bypass confirmation
YES="" ~/bin/tea issues create --repo jihoson/The-Ouroboros --title "Title" --description "Body"
YES="" ~/bin/tea issues edit <number> --repo jihoson/The-Ouroboros --description "Updated body"
YES="" ~/bin/tea pulls create --repo jihoson/The-Ouroboros --head feature-branch --base main --title "Title" --description "Body"
📝 Notes:
- Always set default login:
~/bin/tea login default local - Use
--repo jihoson/The-Ouroboroswhen outside repo directory - tea is preferred over direct Gitea API calls for consistency
❌ Wrong Parameter Name
tea issues create --body "text"
# Error: flag provided but not defined: -body
💡 Reason: Parameter is --description, not --body.
✅ Solution: Use correct parameter name
YES="" ~/bin/tea issues create --description "text"
Gitea API (Direct HTTP Calls)
❌ Wrong Hostname
curl http://gitea.local:3000/api/v1/...
# Error: Could not resolve host: gitea.local
💡 Reason: Gitea instance runs on localhost:3000, not gitea.local.
✅ Solution: Use correct hostname (but prefer tea CLI)
curl http://localhost:3000/api/v1/repos/jihoson/The-Ouroboros/issues \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"...", "body":"..."}'
📝 Notes:
- Prefer
teaCLI over direct API calls - Only use curl for operations tea doesn't support
Git Commands
❌ User Not Configured
git commit -m "message"
# Error: Author identity unknown
💡 Reason: Git user.name and user.email not set.
✅ Solution: Configure git user
git config user.name "agentson"
git config user.email "agentson@localhost"
❌ Permission Denied on Push
git push origin branch
# Error: User permission denied for writing
💡 Reason: Repository access token lacks write permissions or user lacks repo write access.
✅ Solution:
- Verify user has write access to repository (admin grants this)
- Ensure git credential has correct token with
write:repositoryscope - Check remote URL uses correct authentication
Python/Pytest
❌ Module Import Error
pytest tests/test_foo.py
# ModuleNotFoundError: No module named 'src'
💡 Reason: Package not installed in development mode.
✅ Solution: Install package with dev dependencies
pip install -e ".[dev]"
❌ Async Test Hangs
async def test_something(): # Hangs forever
result = await async_function()
💡 Reason: Missing pytest-asyncio or wrong configuration.
✅ Solution: Already configured in pyproject.toml
[tool.pytest.ini_options]
asyncio_mode = "auto"
No decorator needed for async tests.
Build & Test Commands
# Install all dependencies (production + dev)
pip install ".[dev]"
# Run full test suite with coverage
pytest -v --cov=src --cov-report=term-missing
# Run a single test file
pytest tests/test_risk.py -v
# Run a single test by name
pytest tests/test_brain.py -k "test_parse_valid_json" -v
# Lint
ruff check src/ tests/
# Type check (strict mode, non-blocking in CI)
mypy src/ --strict
# Run the trading agent
python -m src.main --mode=paper
# Docker
docker compose up -d ouroboros # Run agent
docker compose --profile test up test # Run tests in container
Architecture
Self-evolving AI trading agent for Korean stock markets (KIS API). The main loop in src/main.py orchestrates four components in a 60-second cycle per stock:
-
Broker (
src/broker/kis_api.py) — Async KIS API client with automatic OAuth token refresh, leaky-bucket rate limiter (10 RPS), and POST body hash-key signing. Uses a custom SSL context with disabled hostname verification for the VTS (virtual trading) endpoint due to a known certificate mismatch. -
Brain (
src/brain/gemini_client.py) — Sends structured prompts to Google Gemini, parses JSON responses intoTradeDecisionobjects. Forces HOLD when confidence < threshold (default 80). Falls back to safe HOLD on any parse/API error. -
Risk Manager (
src/core/risk_manager.py) — READ-ONLY by policy (seedocs/agents.md). Circuit breaker halts all trading viaSystemExitwhen daily P&L drops below -3.0%. Fat-finger check rejects orders exceeding 30% of available cash. -
Evolution (
src/evolution/optimizer.py) — Analyzes high-confidence losing trades from SQLite, asks Gemini to generate newBaseStrategysubclasses, validates them by running the full pytest suite, and simulates PR creation.
Data flow per cycle: Fetch orderbook + balance → calculate P&L → get Gemini decision → validate with risk manager → execute order → log to SQLite (src/db.py).
Key Constraints (from docs/agents.md)
core/risk_manager.pyis READ-ONLY. Changes require human approval.- Circuit breaker threshold (-3.0%) may only be made stricter, never relaxed.
- Fat-finger protection (30% max order size) must always be enforced.
- Confidence < 80 must force HOLD — this rule cannot be weakened.
- All code changes require corresponding tests. Coverage must stay >= 80%.
- Generated strategies must pass the full test suite before activation.
Configuration
Pydantic Settings loaded from .env (see .env.example). Required vars: KIS_APP_KEY, KIS_APP_SECRET, KIS_ACCOUNT_NO (format XXXXXXXX-XX), GEMINI_API_KEY. Tests use in-memory SQLite (DB_PATH=":memory:") and dummy credentials via tests/conftest.py.
Test Structure
35 tests across three files. asyncio_mode = "auto" in pyproject.toml — async tests need no special decorator. The settings fixture in conftest.py provides safe defaults with test credentials and in-memory DB.
test_risk.py(11) — Circuit breaker boundaries, fat-finger edge casestest_broker.py(6) — Token lifecycle, rate limiting, hash keys, network errorstest_brain.py(18) — JSON parsing, confidence threshold, malformed responses, prompt construction