fplkit 1.0.0__tar.gz → 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/TOOLS.md +6 -6
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/skills/squad-builder/SKILL.md +17 -17
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/skills/squad-builder/references/rules.md +3 -3
- {fplkit-1.0.0 → fplkit-1.2.0}/.claude/output-styles/fpl-mate.md +1 -1
- {fplkit-1.0.0 → fplkit-1.2.0}/.github/workflows/release.yml +2 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.gitignore +18 -9
- fplkit-1.2.0/AGENTS.md +67 -0
- fplkit-1.2.0/CHANGELOG.md +33 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/CLAUDE.md +3 -1
- fplkit-1.2.0/PKG-INFO +204 -0
- fplkit-1.2.0/README.md +172 -0
- fplkit-1.2.0/config/fixture_predictions.yaml +41 -0
- fplkit-1.2.0/config/team_managers.yaml +21 -0
- fplkit-1.2.0/config/team_ratings.yaml +119 -0
- fplkit-1.2.0/config/team_ratings_overrides.yaml +8 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/docs/architecture.md +56 -99
- {fplkit-1.0.0 → fplkit-1.2.0}/docs/command-reference.md +102 -157
- fplkit-1.2.0/docs/custom-analysis.md +425 -0
- fplkit-1.2.0/docs/images/fpl-player-demo-v1-0.png +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/_version.py +2 -2
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/action/waiver.py +29 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/analysis/bench_order.py +16 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/analysis/captain.py +14 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/analysis/squad_analyzer.py +30 -1
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/analysis/starting_xi.py +16 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/analysis/stats.py +46 -3
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/analysis/transfer_eval.py +63 -11
- fplkit-1.2.0/fpl_cli/api/core_insights.py +532 -0
- fplkit-1.2.0/fpl_cli/api/dataset_fetcher.py +141 -0
- fplkit-1.2.0/fpl_cli/api/historical.py +106 -0
- fplkit-1.2.0/fpl_cli/api/historical_types.py +179 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/understat.py +16 -32
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/vaastav.py +59 -131
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_context.py +1 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_helpers.py +3 -1
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_plan_grid.py +3 -3
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_review_analysis.py +4 -4
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_review_classic.py +5 -5
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_review_draft.py +2 -2
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_review_summarisation.py +2 -2
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/captain.py +7 -1
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/chips.py +4 -4
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/credentials.py +2 -2
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/differentials.py +8 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/fdr.py +18 -4
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/history.py +5 -5
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/league.py +4 -4
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/league_recap.py +5 -5
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/player.py +157 -44
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/preview.py +8 -7
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/price_history.py +15 -8
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/ratings.py +3 -3
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/review.py +17 -7
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/sell_prices.py +7 -5
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/squad.py +2 -2
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/stats.py +112 -24
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/targets.py +9 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/transfer_eval.py +30 -3
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/waivers.py +14 -4
- {fplkit-1.0.0 → fplkit-1.2.0/fpl_cli}/config/defaults.yaml +1 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/models/player.py +6 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/models/types.py +8 -0
- fplkit-1.2.0/fpl_cli/paths.py +131 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/season.py +21 -9
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/services/player_prior.py +10 -4
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/services/player_scoring.py +926 -59
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/services/squad_allocator.py +2 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/templates/gw_league_recap.md.j2 +1 -1
- fplkit-1.2.0/fpl_cli/utils/text.py +26 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/conftest.py +14 -1
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_agents_action.py +29 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_agents_analysis_squad.py +107 -0
- fplkit-1.2.0/tests/test_api_core_insights.py +785 -0
- fplkit-1.2.0/tests/test_api_dataset_fetcher.py +397 -0
- fplkit-1.2.0/tests/test_api_historical.py +291 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_api_understat.py +59 -4
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_api_vaastav.py +122 -70
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_differentials.py +14 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_format_suppression.py +5 -1
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_history.py +33 -80
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_player.py +323 -30
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_price_history.py +20 -20
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_stats.py +169 -27
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_targets.py +14 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_transfer_eval.py +54 -20
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_waivers.py +18 -0
- fplkit-1.2.0/tests/test_cli_warnings_stderr.py +120 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_common_scoring.py +95 -1
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_data_prep_harmonisation.py +11 -11
- fplkit-1.2.0/tests/test_paths.py +182 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_player_prior.py +76 -6
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_player_scoring.py +1603 -122
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_review.py +2 -3
- fplkit-1.2.0/tests/test_rolling_pts_per_m.py +126 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_stats.py +75 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_transfer_eval_agent.py +57 -9
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_utils_text.py +4 -0
- fplkit-1.0.0/AGENTS.md +0 -1
- fplkit-1.0.0/CHANGELOG.md +0 -5
- fplkit-1.0.0/PKG-INFO +0 -312
- fplkit-1.0.0/README.md +0 -280
- fplkit-1.0.0/config/credentials.yaml.example +0 -11
- fplkit-1.0.0/fpl_cli/config/defaults.yaml +0 -51
- fplkit-1.0.0/fpl_cli/paths.py +0 -104
- fplkit-1.0.0/fpl_cli/utils/text.py +0 -10
- fplkit-1.0.0/templates/gw_league_recap.md.j2 +0 -67
- fplkit-1.0.0/templates/gw_preview.md.j2 +0 -128
- fplkit-1.0.0/templates/gw_review.md.j2 +0 -206
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/README.md +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/skills/gw-prep/SKILL.md +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/skills/gw-prep/references/output-template.md +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/skills/gw-prep/references/rules.md +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/skills/gw-prep/scripts/bench_order.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/skills/gw-prep/scripts/starting_xi.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/skills/gw-prep/scripts/transfer_eval.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/skills/squad-builder/references/output-template.md +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.agents/skills/update-gw-prep/SKILL.md +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.claude/settings.json +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.env.example +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/.github/workflows/ci.yml +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/LICENSE +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/cliff.toml +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/docs/fpl-rules.md +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/action/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/analysis/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/base.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/common.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/data/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/data/fixture.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/data/price.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/data/scout.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/orchestration/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/agents/orchestration/report.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/football_data.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/fpl.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/fpl_draft.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/providers/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/providers/_models.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/providers/anthropic.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/providers/openai_compat.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/api/providers/perplexity.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_banner.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_fines.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_fines_config.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_json.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_league_recap_data.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/_league_recap_types.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/allocate.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/fixtures.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/init.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/price_changes.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/status.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/cli/xg.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/constants.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/models/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/models/chip_plan.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/models/fixture.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/models/team.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/parsers/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/parsers/recommendations.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/prompts/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/prompts/league_recap.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/prompts/review.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/prompts/scout.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/scraper/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/scraper/fpl_prices.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/services/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/services/fixture_predictions.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/services/matchup.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/services/team_form.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/services/team_ratings.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/services/team_ratings_prior.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/templates/gw_preview.md.j2 +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/templates/gw_review.md.j2 +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/fpl_cli/utils/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/pyproject.toml +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/pyrightconfig.json +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/requirements.lock +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/__init__.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_agents_analysis.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_agents_base.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_agents_data.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_agents_data_price.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_agents_orchestration.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_allocate.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_api_client.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_api_draft.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_api_football_data.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_bench_order_script.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_allocate.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_banner.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_captain.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_chips.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_credentials.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_custom_analysis.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_fdr.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_fdr_blanks.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_fixtures.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_format.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_init.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_json.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_plan_grid.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_preview.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_review.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_sell_prices.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_squad.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_status.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_cli_xg.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_common.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_fines.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_fines_config.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_fixture_predictions.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_fpl_prices.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_init.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_init_fines.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_league_recap.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_matchup_service.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_models.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_player_resolution.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_providers.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_recommendations_parser.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_report_agent.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_scraper.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_season.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_sell_prices.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_squad_allocator.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_starting_xi_agent.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_team_ratings.py +0 -0
- {fplkit-1.0.0 → fplkit-1.2.0}/tests/test_team_ratings_prior.py +0 -0
|
@@ -27,8 +27,8 @@ Errors use `emit_json_error()` with `{"command", "error"}` shape.
|
|
|
27
27
|
| `init` | Set up fpl-cli with your FPL IDs and optional features | No | General | No | direct-api |
|
|
28
28
|
| `status` | Show FPL gameweek status and upcoming deadlines | Yes | General | No | direct-api |
|
|
29
29
|
| `fixtures` | Show fixtures for a gameweek | Yes | General | No | direct-api |
|
|
30
|
-
| `player` | Look up a player's stats, xG, ownership and fixture run | Yes | General | No | direct-api |
|
|
31
|
-
| `stats` | List players with filtering and sorting | Yes | General | No | direct-api |
|
|
30
|
+
| `player` | Look up a player's stats, xG, ownership and fixture run. JSON includes `ep_next` (predicted pts next GW) and `ep_this` (current GW); panel shows `xPts` (ep_next). `--detail` (`-d`) shows GW-by-GW performance and, for FWD/MID with sufficient history, xGI sustainability (per-match GI-xGI divergence -> form modifier). With `custom_analysis`: JSON adds `info.adjusted_npxg_per_90` (fixture-adjusted) and `info.raw_npxg_per_90` (Understat season avg); panel shows `adj. npxG/90: X.XXX (raw: Y.YYY)` | Yes | General | No | direct-api |
|
|
31
|
+
| `stats` | List players with filtering and sorting. `--value` adds quality/value per £m columns; `--window N` sets rolling lookback (3-10) for `rolling_pts_per_m`. Sortable by `ep_next`/`ep_this` (FPL predicted points); both in JSON output | Yes | General | No | direct-api |
|
|
32
32
|
| `history` | Show historical player performance across seasons | Yes | General | No | direct-api |
|
|
33
33
|
| `league` | Show live league standings for Classic and Draft leagues | No | General | No | direct-api |
|
|
34
34
|
| `fdr` | Analyse fixture difficulty - easy runs, blanks, doubles | Yes | General | No | via-agent |
|
|
@@ -38,10 +38,10 @@ Errors use `emit_json_error()` with `{"command", "error"}` shape.
|
|
|
38
38
|
| `preview` | Run full pre-gameweek analysis and generate report | No | General | No | via-agent |
|
|
39
39
|
| `review` | Review a completed gameweek - squad performance and standings | No | General | No | via-agent |
|
|
40
40
|
| `league-recap` | Recap a completed gameweek - awards, standings, and banter | No | General | No | via-agent |
|
|
41
|
-
| `captain` | Analyse and rank captain options for next gameweek | Yes | Classic | Yes | via-agent |
|
|
42
|
-
| `differentials` | Find differential picks - high potential, low ownership | Yes | Classic | Yes | via-agent |
|
|
43
|
-
| `targets` | Find transfer targets - high performers across all ownership | Yes | Classic | Yes | via-agent |
|
|
44
|
-
| `transfer-eval` | Compare transfer OUT player against IN candidates | Yes | General | Yes | via-agent |
|
|
41
|
+
| `captain` | Analyse and rank captain options for next gameweek. JSON candidates include `adjusted_npxg_per_90` and `raw_npxg_per_90` when fixture adjustment is active. Consistency tiebreaker (CV-xGI percentile) phased in GW6-10 | Yes | Classic | Yes | via-agent |
|
|
42
|
+
| `differentials` | Find differential picks - high potential, low ownership. Inverted consistency bonus (volatile players score higher, phased in GW6-10) | Yes | Classic | Yes | via-agent |
|
|
43
|
+
| `targets` | Find transfer targets - high performers across all ownership. Consistency bonus (CV-xGI percentile, phased in GW6-10) | Yes | Classic | Yes | via-agent |
|
|
44
|
+
| `transfer-eval` | Compare transfer OUT player against IN candidates. JSON includes `adjusted_npxg_per_90` and `raw_npxg_per_90` per player when fixture adjustment is active | Yes | General | Yes | via-agent |
|
|
45
45
|
| `allocate` | Select mathematically optimal 15-player squad within budget | Yes | Classic | Yes | direct-api |
|
|
46
46
|
| `waivers` | Show waiver recommendations for your draft league | Yes | Draft | Yes | via-agent |
|
|
47
47
|
| `squad` | Analyse your FPL squad health and fixtures | Yes | General | No | via-agent |
|
|
@@ -119,10 +119,10 @@ Issue all reads and CLI commands in a **single parallel tool-call block**:
|
|
|
119
119
|
- `fpl stats -p FWD -s form --min-minutes 450 -n 15 --available-only --format json`
|
|
120
120
|
- `fpl stats -p DEF -s total_points --min-minutes 450 -n 15 --available-only --format json`
|
|
121
121
|
- `fpl stats -p GK -s points_per_game --min-minutes 450 -n 8 --available-only --format json`
|
|
122
|
-
- `fpl stats --value -p MID -s
|
|
123
|
-
- `fpl stats --value -p FWD -s
|
|
124
|
-
- `fpl stats --value -p DEF -s
|
|
125
|
-
- `fpl stats --value -p GK -s
|
|
122
|
+
- `fpl stats --value -p MID -s quality_per_m --min-minutes 450 -n 15 --available-only --format json` (underpriced mids by underlying performance per £m)
|
|
123
|
+
- `fpl stats --value -p FWD -s quality_per_m --min-minutes 450 -n 15 --available-only --format json`
|
|
124
|
+
- `fpl stats --value -p DEF -s quality_per_m --min-minutes 450 -n 15 --available-only --format json`
|
|
125
|
+
- `fpl stats --value -p GK -s quality_per_m --min-minutes 450 -n 8 --available-only --format json`
|
|
126
126
|
- `fpl stats -s now_cost -r --min-minutes 450 -n 15 --available-only --format json` (cheapest playing options)
|
|
127
127
|
- `fpl stats -s form --min-minutes 315 -n 20 --available-only --format json` (in-form across positions)
|
|
128
128
|
- `fpl stats -s transfers_in_event -n 15 --format json` (transfer momentum)
|
|
@@ -144,7 +144,7 @@ Skip missing optional sources gracefully. Store all results for Phase B2.
|
|
|
144
144
|
## Phase B2: Candidate Shortlisting (orchestrator, inline)
|
|
145
145
|
No sub-agent needed. The orchestrator already has all Phase B JSON. Extract candidate lists per position:
|
|
146
146
|
|
|
147
|
-
1. Parse the 4 positional `fpl stats` outputs (MID/FWD/DEF/GK) + 4 `
|
|
147
|
+
1. Parse the 4 positional `fpl stats` outputs (MID/FWD/DEF/GK) + 4 `quality_per_m` outputs + form + cheapest
|
|
148
148
|
2. Deduplicate players appearing in multiple lists
|
|
149
149
|
3. Add any player names from scout reports / previews not already in stats
|
|
150
150
|
4. Note which players appear in the `fpl allocate` solver output (JSON field is `web_name`, not `name`)
|
|
@@ -152,10 +152,10 @@ No sub-agent needed. The orchestrator already has all Phase B JSON. Extract cand
|
|
|
152
152
|
|
|
153
153
|
| Position | Target candidates | Primary stats sources |
|
|
154
154
|
|----------|------------------|-----------------------|
|
|
155
|
-
| GK | 4-6 | GK ppg, GK
|
|
156
|
-
| DEF | 8-10 | DEF total_points, DEF
|
|
157
|
-
| MID | 8-10 | MID xGI, MID
|
|
158
|
-
| FWD | 6-8 | FWD form, FWD
|
|
155
|
+
| GK | 4-6 | GK ppg, GK quality_per_m |
|
|
156
|
+
| DEF | 8-10 | DEF total_points, DEF quality_per_m, cheapest |
|
|
157
|
+
| MID | 8-10 | MID xGI, MID quality_per_m, form, transfers_in |
|
|
158
|
+
| FWD | 6-8 | FWD form, FWD quality_per_m, cheapest |
|
|
159
159
|
|
|
160
160
|
Each candidate entry: `{name, team, position, in_allocator_squad: bool}`.
|
|
161
161
|
|
|
@@ -177,10 +177,10 @@ Agent tool parameters (per agent):
|
|
|
177
177
|
|
|
178
178
|
| Agent | Stats sources | pFDR column | Allocator picks |
|
|
179
179
|
|-------|--------------|------------|-----------------|
|
|
180
|
-
| GK | GK ppg, GK
|
|
181
|
-
| DEF | DEF total_points, DEF
|
|
182
|
-
| MID | MID xGI, MID
|
|
183
|
-
| FWD | FWD form, FWD
|
|
180
|
+
| GK | GK ppg, GK quality_per_m | DEF | GK entries from allocator |
|
|
181
|
+
| DEF | DEF total_points, DEF quality_per_m | DEF | DEF entries from allocator |
|
|
182
|
+
| MID | MID xGI, MID quality_per_m | ATK | MID entries from allocator |
|
|
183
|
+
| FWD | FWD form, FWD quality_per_m | ATK | FWD entries from allocator |
|
|
184
184
|
|
|
185
185
|
Cross-positional data (form, cheapest, transfers_in, price-history, captain) goes to Phase D assembler, not position agents.
|
|
186
186
|
|
|
@@ -207,8 +207,8 @@ Include all of this in the prompt field, populated with position-specific data:
|
|
|
207
207
|
{this position's primary stat output}
|
|
208
208
|
|
|
209
209
|
=== fpl stats: {POSITION} value score ===
|
|
210
|
-
{this position's
|
|
211
|
-
Players ranked by underlying performance (Understat xG/xA) per GBPm. High
|
|
210
|
+
{this position's quality_per_m output}
|
|
211
|
+
Players ranked by underlying performance (Understat xG/xA) per GBPm. High quality_per_m = outperforming price tag.
|
|
212
212
|
|
|
213
213
|
=== fpl allocate: {POSITION} picks ===
|
|
214
214
|
{only this position's entries from allocator output, including effective_price}
|
|
@@ -244,13 +244,13 @@ Include all of this in the prompt field, populated with position-specific data:
|
|
|
244
244
|
Run `fpl player "{name}" -f -H` **in parallel** for all candidates in your list.
|
|
245
245
|
For season-start modes with no current-season data, also use `fpl history` data passed in context.
|
|
246
246
|
|
|
247
|
-
7. **Scoring:** Score each candidate against the mode-specific criteria from rules. Use quality_score and
|
|
247
|
+
7. **Scoring:** Score each candidate against the mode-specific criteria from rules. Use quality_score and quality_per_m when available (null for players without Understat data - don't penalise).
|
|
248
248
|
|
|
249
249
|
8. **Return format:** Return a structured ranked list. Per candidate:
|
|
250
250
|
```
|
|
251
251
|
{rank}. {name} ({team}) - GBP{effective_price}m
|
|
252
252
|
Form: {form} | PPG: {ppg} | Minutes: {minutes}
|
|
253
|
-
Quality: {quality_score}/100 | Value: {
|
|
253
|
+
Quality: {quality_score}/100 | Value: {quality_per_m}
|
|
254
254
|
Fixtures (next {horizon}): {condensed fixture run}
|
|
255
255
|
Flags: {injury/suspension/rotation risk, if any}
|
|
256
256
|
Allocator pick: {yes/no}
|
|
@@ -33,9 +33,9 @@ After building, note how many of the user's current players (if known) appear in
|
|
|
33
33
|
## Value-for-Money
|
|
34
34
|
Available in `fpl player --format json` output when Understat data exists for the player:
|
|
35
35
|
- **quality_score** (0-100): Player output quality normalised against positional ceiling. Form and PPG weighted heavily - measures "current FPL points production rate."
|
|
36
|
-
- **
|
|
37
|
-
- When choosing between similarly-ranked candidates at the same position, prefer higher `
|
|
38
|
-
- `
|
|
36
|
+
- **quality_per_m** (quality_score / price per GBPm): Within-position budget efficiency. Higher = more output per pound.
|
|
37
|
+
- When choosing between similarly-ranked candidates at the same position, prefer higher `quality_per_m` to free budget for other slots.
|
|
38
|
+
- `quality_per_m` is not meaningful for cross-position comparison (positional ceilings differ).
|
|
39
39
|
- Both fields are `null` for players without Understat data - do not penalise or exclude these players, use other signals instead.
|
|
40
40
|
- **Free Hit note:** Free Hit uses `fpl allocate --horizon 1 --bench-discount 0.01` for a fixture-adjusted, single-GW optimal squad. The solver output is the primary starting point.
|
|
41
41
|
|
|
@@ -41,7 +41,7 @@ When pulling data for comparison or field extraction, use `--format json` on com
|
|
|
41
41
|
- `-d` GW-by-GW match performance (FPL API, always fresh)
|
|
42
42
|
- `-u` Understat analysis (shot analysis + situation profile) - use with `-d` for MID/FWD
|
|
43
43
|
- `-H` historical career arc - pts/90, xGI/90, cost trajectory across last 3 seasons
|
|
44
|
-
- `fpl stats` - ranked player list; `-p MID` position filter, `-t ARS` team filter, `-s xGI` sort field (form, ICT, cost, transfers_in_event...), `--min-minutes` appearances filter, `--draft` adds ownership column, `-v` adds quality and
|
|
44
|
+
- `fpl stats` - ranked player list; `-p MID` position filter, `-t ARS` team filter, `-s xGI` sort field (form, ICT, cost, transfers_in_event...), `--min-minutes` appearances filter, `--draft` adds ownership column, `-v` adds quality, quality/£m, and rolling pts/£m columns (sorts by quality/£m by default - use with position filter for best results), `-w N` rolling fixture window (3-10)
|
|
45
45
|
- `fpl fixtures <gw>` - who plays who, difficulty
|
|
46
46
|
- `fpl league` - standings context for risk calibration
|
|
47
47
|
|
|
@@ -75,4 +75,6 @@ jobs:
|
|
|
75
75
|
git add CHANGELOG.md
|
|
76
76
|
git diff --cached --quiet && exit 0
|
|
77
77
|
git commit -m "docs: update CHANGELOG.md [skip ci]"
|
|
78
|
+
# Non-fast-forward risk: if main advances in the ~30s between tag push and here,
|
|
79
|
+
# this push fails. Acceptable for a solo project - re-run the job manually if needed.
|
|
78
80
|
git push origin HEAD:main
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Local Claude Code instructions (personal, not committed)
|
|
2
|
+
CLAUDE.local.md
|
|
3
|
+
|
|
4
|
+
# Runtime caches and user secrets (never commit)
|
|
2
5
|
config/*.yaml
|
|
3
|
-
!config/
|
|
6
|
+
!config/fixture_predictions.yaml
|
|
7
|
+
!config/team_managers.yaml
|
|
8
|
+
!config/team_ratings.yaml
|
|
9
|
+
!config/team_ratings_overrides.yaml
|
|
4
10
|
.env
|
|
5
11
|
|
|
6
12
|
# Generated version file (hatch-vcs)
|
|
@@ -63,9 +69,9 @@ docs/plans/
|
|
|
63
69
|
docs/brainstorms/
|
|
64
70
|
docs/solutions/
|
|
65
71
|
docs/ideas/
|
|
72
|
+
docs/discarded/
|
|
66
73
|
docs/positioning.md
|
|
67
|
-
docs/
|
|
68
|
-
docs/2026-03-23-security-review-pre-open-source.md
|
|
74
|
+
docs/releasing.md
|
|
69
75
|
|
|
70
76
|
# Local todos
|
|
71
77
|
todos/
|
|
@@ -75,11 +81,14 @@ todos/
|
|
|
75
81
|
.claude/hooks/
|
|
76
82
|
.claude/worktrees/
|
|
77
83
|
.claude/handoffs/
|
|
78
|
-
.agents/skills/legal-risk-assessment/
|
|
79
|
-
.agents/skills/update-fixture-schedule/
|
|
80
|
-
|
|
81
|
-
# Agentic session logs
|
|
82
|
-
agentic_logs/
|
|
83
84
|
|
|
85
|
+
# Untracked skills
|
|
86
|
+
.agents/skills/create-readme/
|
|
87
|
+
.agents/skills/documentation-writer/
|
|
88
|
+
.agents/skills/release-notes/
|
|
89
|
+
.agents/skills/release/
|
|
90
|
+
.agents/skills/senior-data-scientist/
|
|
91
|
+
.agents/skills/data-scientist/
|
|
92
|
+
.agents/skills/fpl-data-scientist/
|
|
84
93
|
# OS
|
|
85
94
|
.DS_Store
|
fplkit-1.2.0/AGENTS.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
## Project Overview
|
|
2
|
+
fpl-cli - CLI tool for Fantasy Premier League analysis (classic + draft).
|
|
3
|
+
|
|
4
|
+
## Setup & Dev
|
|
5
|
+
```bash
|
|
6
|
+
source .venv/bin/activate && pip install -e ".[dev]"
|
|
7
|
+
ruff check fpl_cli/ # Lint
|
|
8
|
+
pyright fpl_cli/ # Type check
|
|
9
|
+
pytest tests/ # Tests
|
|
10
|
+
```
|
|
11
|
+
Entry point: `fpl_cli/cli/__init__.py:main` (Click). Config: `config/defaults.yaml` (committed) + `~/Library/Application Support/fpl-cli/settings.yaml` (user overrides, deep-merged via `platformdirs`). Override config dir with `FPL_CLI_CONFIG_DIR` env var.
|
|
12
|
+
|
|
13
|
+
## Architecture
|
|
14
|
+
Agents inherit `fpl_cli/agents/base.py:Agent`, implement `async run(context: dict | None) -> AgentResult`. Organised in `agents/{data,analysis,action,orchestration}/`. AgentResult statuses: SUCCESS, PARTIAL, FAILED, PENDING_APPROVAL.
|
|
15
|
+
|
|
16
|
+
External consumers: `BenchOrderAgent`, `StartingXIAgent`, and `TransferEvalAgent` are imported directly by the gw-prep skill (Obsidian vault) via standalone scripts (`bench_order.py`, `starting_xi.py`, `transfer_eval.py`) that run in fpl-cli's venv. Changes to any agent's interface or import path will break those scripts.
|
|
17
|
+
|
|
18
|
+
API clients in `fpl_cli/api/`: FPLClient (main API, caches `bootstrap-static/`), fpl_draft, perplexity (needs `PERPLEXITY_API_KEY`), understat (scrapes understat.com for npxG/xGChain/xGBuildup), historical data via dual-source architecture: VaastavClient (3 historical seasons 2022-25, keyed on `element_code`) + CoreInsightsClient (current season 2025-26+), composed by `HistoricalDataProvider` (`make_historical_provider()`). Shared types in `historical_types.py` (SeasonHistory, PlayerProfile, GwTrendProfile). Season helper: `season_label()` (alias `vaastav_season()`). Scraper in `fpl_cli/scraper/` (needs `FPL_EMAIL`, `FPL_PASSWORD`). Jinja2 templates in `templates/`.
|
|
19
|
+
|
|
20
|
+
### Models (non-obvious aliases)
|
|
21
|
+
- `Player`: `element_type` = position, `team` = team_id, `code` = stable cross-season ID (element_code). Prices in £0.1m units (100 = £10.0m)
|
|
22
|
+
- `Fixture`: `gameweek` (alias "event"), `home_team_id`/`away_team_id`
|
|
23
|
+
|
|
24
|
+
For a complete inventory of CLI commands, analysis agents, and skills with JSON support and format awareness, see `.agents/TOOLS.md`.
|
|
25
|
+
|
|
26
|
+
## Conventions
|
|
27
|
+
### CLI Patterns
|
|
28
|
+
- Read-only data display commands -> direct API client usage (comment `# Pattern: direct-api`)
|
|
29
|
+
- Analytical commands -> via agent (comment `# Pattern: via-agent`)
|
|
30
|
+
- Help text: describe what the user sees, never reference internal components ("agent", "client")
|
|
31
|
+
- Inner async function: always name `_run`
|
|
32
|
+
- **Format awareness:** New commands classified in `CLASSIC_ONLY`/`DRAFT_ONLY` frozensets in `_context.py` (omit for General). Shared commands use `@click.pass_context` and `fmt = get_format(ctx)` to gate irrelevant sections (see `league.py` for pattern).
|
|
33
|
+
|
|
34
|
+
### Agent Patterns
|
|
35
|
+
- Primary API client: `self.client` in `__init__` (FPLClient for classic agents, FPLDraftClient for draft agents)
|
|
36
|
+
- Secondary clients: qualified name (e.g. `self.perplexity_client`)
|
|
37
|
+
- Position map: import `POSITION_MAP` from `fpl_cli/models/player.py`, never redefine locally
|
|
38
|
+
- Understat enrichment: import `match_fpl_to_understat` from `fpl_cli/api/understat`
|
|
39
|
+
|
|
40
|
+
### API Method Naming
|
|
41
|
+
- Use `get_` prefix for all data-fetching methods
|
|
42
|
+
- Use domain language (gameweek, player, team), never FPL jargon (event, element, bootstrap-static)
|
|
43
|
+
- FPL jargon translation happens at the model boundary via Pydantic aliases
|
|
44
|
+
- xG, xA, xGI, npxG, FDR, BPS - stats abbreviations acceptable as-is
|
|
45
|
+
|
|
46
|
+
### Exception Handling
|
|
47
|
+
- Never use bare `except Exception`. Use specific types for narrow try blocks; use `# noqa: BLE001 — <justification>` for intentional broad handlers (agent top-level, scraper resilience, graceful degradation)
|
|
48
|
+
|
|
49
|
+
## FPL Domain Knowledge
|
|
50
|
+
- Chips (each available **twice** per season, split at GW19 deadline): Wildcard, Free Hit, Bench Boost, Triple Captain
|
|
51
|
+
- Scoring: GK/DEF clean sheet = 4pts, MID = 1pt; goals: DEF=6, MID=5, FWD=4; assist = 3pts; yellow = -1; red = -3
|
|
52
|
+
- Transfers: 1 free/GW, max 5 banked; extra transfers cost 4pts each; Wildcard/Free Hit preserve banked transfers
|
|
53
|
+
- Draft format has no captains, no budget, no transfers, no chips - uses waivers for player acquisition
|
|
54
|
+
|
|
55
|
+
## Rules
|
|
56
|
+
- Verify before asserting: don't state that a command, file, function, or data point exists without checking first (read the file, run the command, grep for the name)
|
|
57
|
+
- Find-and-replace: review each replacement in context - don't blindly replace substrings in unrelated identifiers
|
|
58
|
+
- Removing/replacing X: new implementation must have zero dependencies on X
|
|
59
|
+
- Repeated convention violations: suggest a ruff lint rule to enforce automatically
|
|
60
|
+
- README must stay in sync: any CLI command added/changed/removed requires updating the relevant job section in "What You Can Do" and, if the command has detailed flags or formulas, `docs/command-reference.md`
|
|
61
|
+
- Architecture doc must stay in sync: adding a new agent, service, API client, or CLI command requires updating `docs/architecture.md`
|
|
62
|
+
- TOOLS.md must stay in sync: adding, removing, or changing a CLI command, analysis agent, or skill requires updating `.agents/TOOLS.md`
|
|
63
|
+
- AGENTS.md must stay in sync: any change to project instructions in CLAUDE.md requires the same change in AGENTS.md
|
|
64
|
+
- CLI changes require corresponding unit tests
|
|
65
|
+
- Changing a function's return format: update existing tests to match and confirm pytest passes
|
|
66
|
+
- Tests: `pytest-asyncio` with `asyncio_mode = "auto"`, factories in `tests/conftest.py` (`make_player()`, `make_team()`, `make_fixture()`)
|
|
67
|
+
- After any task touching Python files, run `pyright fpl_cli/` as a final check alongside ruff and pytest
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
## [1.1.0] - 2026-04-07
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
- wrap migration in try/except, update architecture.md paths
|
|
9
|
+
- CLI hygiene batch (P10-P13) (#4)
|
|
10
|
+
- Understat name matching for abbreviated/punctuated web_names
|
|
11
|
+
- PR #4 code review follow-ups (#5)
|
|
12
|
+
- review fixes - gather resilience, CSV field protection, test gaps
|
|
13
|
+
- correct README data source count and Core-Insights repo URL
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
- add cached dataset fetcher with ETag conditional requests (#6)
|
|
18
|
+
- add rolling pts/£m metric and rename value fields (#7)
|
|
19
|
+
- expose ep_next/ep_this (FPL predicted points) (#8)
|
|
20
|
+
- implement CoreInsightsClient for 2025-26 season data
|
|
21
|
+
- add HistoricalDataProvider composition layer, update call sites
|
|
22
|
+
|
|
23
|
+
### Refactoring
|
|
24
|
+
|
|
25
|
+
- extract shared types, rename season helpers, separate cache dirs
|
|
26
|
+
|
|
27
|
+
## [1.0.0] - 2026-04-03
|
|
28
|
+
|
|
29
|
+
### Features
|
|
30
|
+
|
|
31
|
+
- CI pipeline and PyPI publish for v1.0.0 (#1)
|
|
32
|
+
|
|
33
|
+
|
|
@@ -15,7 +15,7 @@ Agents inherit `fpl_cli/agents/base.py:Agent`, implement `async run(context: dic
|
|
|
15
15
|
|
|
16
16
|
External consumers: `BenchOrderAgent`, `StartingXIAgent`, and `TransferEvalAgent` are imported directly by the gw-prep skill (Obsidian vault) via standalone scripts (`bench_order.py`, `starting_xi.py`, `transfer_eval.py`) that run in fpl-cli's venv. Changes to any agent's interface or import path will break those scripts.
|
|
17
17
|
|
|
18
|
-
API clients in `fpl_cli/api/`: FPLClient (main API, caches `bootstrap-static/`), fpl_draft, perplexity (needs `PERPLEXITY_API_KEY`), understat (scrapes understat.com for npxG/xGChain/xGBuildup),
|
|
18
|
+
API clients in `fpl_cli/api/`: FPLClient (main API, caches `bootstrap-static/`), fpl_draft, perplexity (needs `PERPLEXITY_API_KEY`), understat (scrapes understat.com for npxG/xGChain/xGBuildup), historical data via dual-source architecture: VaastavClient (3 historical seasons 2022-25, keyed on `element_code`) + CoreInsightsClient (current season 2025-26+), composed by `HistoricalDataProvider` (`make_historical_provider()`). Shared types in `historical_types.py` (SeasonHistory, PlayerProfile, GwTrendProfile). Season helper: `season_label()` (alias `vaastav_season()`). Scraper in `fpl_cli/scraper/` (needs `FPL_EMAIL`, `FPL_PASSWORD`). Jinja2 templates in `templates/`.
|
|
19
19
|
|
|
20
20
|
### Models (non-obvious aliases)
|
|
21
21
|
- `Player`: `element_type` = position, `team` = team_id, `code` = stable cross-season ID (element_code). Prices in £0.1m units (100 = £10.0m)
|
|
@@ -53,12 +53,14 @@ For a complete inventory of CLI commands, analysis agents, and skills with JSON
|
|
|
53
53
|
- Draft format has no captains, no budget, no transfers, no chips - uses waivers for player acquisition
|
|
54
54
|
|
|
55
55
|
## Rules
|
|
56
|
+
- Verify before asserting: don't state that a command, file, function, or data point exists without checking first (read the file, run the command, grep for the name)
|
|
56
57
|
- Find-and-replace: review each replacement in context - don't blindly replace substrings in unrelated identifiers
|
|
57
58
|
- Removing/replacing X: new implementation must have zero dependencies on X
|
|
58
59
|
- Repeated convention violations: suggest a ruff lint rule to enforce automatically
|
|
59
60
|
- README must stay in sync: any CLI command added/changed/removed requires updating the relevant job section in "What You Can Do" and, if the command has detailed flags or formulas, `docs/command-reference.md`
|
|
60
61
|
- Architecture doc must stay in sync: adding a new agent, service, API client, or CLI command requires updating `docs/architecture.md`
|
|
61
62
|
- TOOLS.md must stay in sync: adding, removing, or changing a CLI command, analysis agent, or skill requires updating `.agents/TOOLS.md`
|
|
63
|
+
- AGENTS.md must stay in sync: any change to project instructions in CLAUDE.md requires the same change in AGENTS.md
|
|
62
64
|
- CLI changes require corresponding unit tests
|
|
63
65
|
- Changing a function's return format: update existing tests to match and confirm pytest passes
|
|
64
66
|
- Tests: `pytest-asyncio` with `asyncio_mode = "auto"`, factories in `tests/conftest.py` (`make_player()`, `make_team()`, `make_fixture()`)
|
fplkit-1.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fplkit
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: CLI tool for Fantasy Premier League analysis - classic and draft formats
|
|
5
|
+
Project-URL: Homepage, https://github.com/rossgroomio/fpl-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/rossgroomio/fpl-cli
|
|
7
|
+
Author-email: Ross Groom <rossgroom1+tech@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Requires-Dist: click>=8.1.0
|
|
12
|
+
Requires-Dist: httpx>=0.27.0
|
|
13
|
+
Requires-Dist: jinja2>=3.1.0
|
|
14
|
+
Requires-Dist: keyring>=24.0.0
|
|
15
|
+
Requires-Dist: platformdirs<5,>=4.3
|
|
16
|
+
Requires-Dist: pulp>=2.7
|
|
17
|
+
Requires-Dist: pydantic>=2.5.0
|
|
18
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
19
|
+
Requires-Dist: pyyaml>=6.0.0
|
|
20
|
+
Requires-Dist: rich>=13.7.0
|
|
21
|
+
Requires-Dist: ruamel-yaml>=0.18.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pyright>=1.1.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=7.4.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: respx>=0.21.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
29
|
+
Provides-Extra: scraper
|
|
30
|
+
Requires-Dist: playwright>=1.40.0; extra == 'scraper'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# fpl-cli
|
|
34
|
+
|
|
35
|
+
Fantasy Premier League analysis from the terminal. Classic and Draft formats. Six data sources, one interface.
|
|
36
|
+
|
|
37
|
+
[](https://pypi.org/project/fplkit/)
|
|
38
|
+
[](https://www.python.org/downloads/)
|
|
39
|
+
[](LICENSE)
|
|
40
|
+
|
|
41
|
+
<img src="docs/images/fpl-player-demo-v1-0.png"
|
|
42
|
+
alt="FPL player scouting table in fpl-cli showing form, xGI, expected goals, availability flags and Fantasy Premier League data"
|
|
43
|
+
width="600"
|
|
44
|
+
style="max-width: 100%; height: auto;">
|
|
45
|
+
|
|
46
|
+
*Example output from `fpl player` — real-time player analysis with form, xGI and availability flags.*
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
- **Multi-source data** - FPL API, Draft API, Understat (npxG/xGChain), historical data (vaastav 2022-25 + Core-Insights 2025-26), and football-data.org in one place.
|
|
51
|
+
- **Player scouting** - Filter by any stat, track xG trends, spot underperformers, check fixture runs.
|
|
52
|
+
- **Fixture intelligence** - Bayesian difficulty ratings from actual match results, blank/double GW detection, squad exposure analysis.
|
|
53
|
+
- **Custom analysis** - Captain picks, transfer targets, differentials, waivers, and ILP-optimal squad allocation. Opt-in, off by default.
|
|
54
|
+
- **Gameweek reports** - Post-GW reviews and league recaps with optional LLM narrative.
|
|
55
|
+
- **Draft parity** - Most commands work for both Classic and Draft. Waivers cover the free-agent wire.
|
|
56
|
+
- **Agent-friendly** - `--format json` with a consistent envelope on key commands. Ready-made agent skills in `.agents/skills/`.
|
|
57
|
+
|
|
58
|
+
## Quickstart
|
|
59
|
+
|
|
60
|
+
```console
|
|
61
|
+
$ pipx install fplkit
|
|
62
|
+
$ fpl init
|
|
63
|
+
$ fpl status
|
|
64
|
+
$ fpl stats -p MID -s form --available-only
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`fpl init` configures your FPL IDs and optional features. With just an entry ID you get the full data toolkit.
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
Requires **Python 3.11+**.
|
|
72
|
+
|
|
73
|
+
```console
|
|
74
|
+
$ pipx install fplkit
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Alternatives: `uv pip install fplkit` or `pip install fplkit`.
|
|
78
|
+
|
|
79
|
+
> [!NOTE]
|
|
80
|
+
> Browser scraping (`fpl squad sell-prices --refresh`) requires the scraper extra and Playwright:
|
|
81
|
+
> ```console
|
|
82
|
+
> $ pipx install 'fplkit[scraper]'
|
|
83
|
+
> $ playwright install chromium
|
|
84
|
+
> ```
|
|
85
|
+
|
|
86
|
+
## Usage
|
|
87
|
+
|
|
88
|
+
### After the Gameweek
|
|
89
|
+
|
|
90
|
+
```console
|
|
91
|
+
$ fpl status # GW result, deadline, rank movement, flagged players
|
|
92
|
+
$ fpl review --save --summarise # Full review with LLM narrative
|
|
93
|
+
$ fpl league # Live league standings
|
|
94
|
+
$ fpl league-recap --summarise # Awards and editorial for the group chat
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Scouting Players
|
|
98
|
+
|
|
99
|
+
```console
|
|
100
|
+
$ fpl stats -p FWD -s form -a # Forwards by form, excluding unavailable
|
|
101
|
+
$ fpl player Rice -f -u # Deep dive: fixtures + Understat analysis
|
|
102
|
+
$ fpl xg # xG/xA analysis, over/underperformers
|
|
103
|
+
$ fpl history # Career arc across 3 seasons
|
|
104
|
+
$ fpl price-history -n 4 -s price_slope # Bandwagon detection
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Before the Deadline
|
|
108
|
+
|
|
109
|
+
```console
|
|
110
|
+
$ fpl squad # Squad health: form, injuries, recommendations
|
|
111
|
+
$ fpl squad grid -n 8 -w Mbeumo # 8-GW fixture difficulty grid with a watchlist player
|
|
112
|
+
$ fpl fdr --my-squad # Your squad's blank/double GW exposure
|
|
113
|
+
$ fpl preview --save --scout # Full analysis + BUY/SELL research via LLM
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Strategic Planning
|
|
117
|
+
|
|
118
|
+
```console
|
|
119
|
+
$ fpl fdr --blanks # Confirmed + predicted blank/double GWs
|
|
120
|
+
$ fpl chips timing # Rule-based Free Hit / Bench Boost / Triple Captain signals
|
|
121
|
+
$ fpl fixtures # Next GW fixtures with FDR
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Custom Analysis
|
|
125
|
+
|
|
126
|
+
Off by default. Enable via `fpl init` or `custom_analysis: true` in settings.yaml.
|
|
127
|
+
|
|
128
|
+
```console
|
|
129
|
+
$ fpl captain # Ranked captain picks (0-100 matchup scoring)
|
|
130
|
+
$ fpl targets --min-own 30 # Transfer targets, template tier
|
|
131
|
+
$ fpl differentials -t 3 # Ultra-differentials (<3% owned)
|
|
132
|
+
$ fpl waivers # Free-agent waiver picks with drop suggestions (draft)
|
|
133
|
+
$ fpl transfer-eval --out Palmer --in "Salah,Mbeumo" # Side-by-side comparison
|
|
134
|
+
$ fpl allocate --horizon 1 # Free Hit: optimal squad for a single GW
|
|
135
|
+
$ fpl ratings # Bayesian team strength ratings from match results
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Enabling custom analysis also enriches other commands: `fpl stats` gains `--value` columns, `fpl xg` adds Value Picks, `fpl fdr` upgrades to Bayesian FDR with ATK/DEF split.
|
|
139
|
+
|
|
140
|
+
### JSON Output
|
|
141
|
+
|
|
142
|
+
Commands with `--format json` emit a consistent envelope:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"command": "stats",
|
|
147
|
+
"metadata": {"gameweek": null, "format": "classic", "custom_analysis": true},
|
|
148
|
+
"data": [...]
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```console
|
|
153
|
+
$ fpl stats --format json -p MID -s expected_goal_involvements
|
|
154
|
+
$ fpl status --format json
|
|
155
|
+
$ fpl fdr --blanks --format json
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Configuration
|
|
159
|
+
|
|
160
|
+
Run `fpl init` to configure interactively. Settings stored in your platform's config directory (override with `FPL_CLI_CONFIG_DIR`).
|
|
161
|
+
|
|
162
|
+
**Required:** FPL classic entry ID or draft league + entry IDs.
|
|
163
|
+
|
|
164
|
+
| Feature | What it enables |
|
|
165
|
+
|---------|----------------|
|
|
166
|
+
| Custom Analysis | Captain, targets, differentials, waivers, allocate, ratings, value scores, Bayesian FDR |
|
|
167
|
+
| League ID | Standings, fines, league recaps |
|
|
168
|
+
| LLM providers | `--summarise` and `--scout` flags (Perplexity, Anthropic, OpenAI, or any compatible API) |
|
|
169
|
+
| FPL credentials | `fpl squad sell-prices` (browser scraping) |
|
|
170
|
+
| `FOOTBALL_DATA_API_KEY` | League table in `fpl review` |
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# LLM providers (for --summarise and --scout)
|
|
174
|
+
export PERPLEXITY_API_KEY="your-key" # Research role
|
|
175
|
+
export ANTHROPIC_API_KEY="your-key" # Synthesis role
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
See [Command Reference](docs/command-reference.md#configuration-reference) for the full settings.yaml schema and LLM provider setup.
|
|
179
|
+
|
|
180
|
+
## Development
|
|
181
|
+
|
|
182
|
+
```console
|
|
183
|
+
$ git clone https://github.com/rossgroomio/fpl-cli.git
|
|
184
|
+
$ cd fpl-cli
|
|
185
|
+
$ python3 -m venv .venv && source .venv/bin/activate
|
|
186
|
+
$ pip install -e ".[dev]"
|
|
187
|
+
$ fpl init
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```console
|
|
191
|
+
$ ruff check fpl_cli/ # Lint
|
|
192
|
+
$ pyright fpl_cli/ # Type check
|
|
193
|
+
$ pytest tests/ # Tests
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
> [!NOTE]
|
|
197
|
+
> Football data provided by the [Football-Data.org API](https://www.football-data.org/). Player and fixture data is property of the Premier League. Expected goals data is property of [Understat](https://understat.com). Historical data from [vaastav/Fantasy-Premier-League](https://github.com/vaastav/Fantasy-Premier-League) (MIT, 2022-25) and [olbauday/FPL-Core-Insights](https://github.com/olbauday/FPL-Core-Insights) (2025-26+). This tool fetches data at runtime and does not redistribute third-party data.
|
|
198
|
+
|
|
199
|
+
> [!WARNING]
|
|
200
|
+
> Browser scraping (`fpl squad sell-prices`) uses your FPL login to read sell prices. Automated access may violate FPL website terms - use at your own risk.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
[Command Reference](docs/command-reference.md) | [Custom Analysis Guide](docs/custom-analysis.md) | [Architecture](docs/architecture.md) | [Agent Tools & Skills](.agents/TOOLS.md)
|