fplkit 2.0.0__tar.gz → 2.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-2.2.0/.agents/TOOLS.md +116 -0
- fplkit-2.2.0/.agents/skills/create-pr/SKILL.md +189 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/gw-prep/SKILL.md +157 -18
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/gw-prep/references/output-template.md +32 -4
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/gw-prep/references/rules.md +5 -2
- fplkit-2.2.0/.agents/skills/gw-prep/scripts/_bootstrap.py +25 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/gw-prep/scripts/bench_order.py +3 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/gw-prep/scripts/extract_classic_squad.py +126 -118
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/gw-prep/scripts/starting_xi.py +3 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/gw-prep/scripts/transfer_eval.py +3 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/gw-prep/scripts/validate_draft_waivers.py +71 -38
- fplkit-2.2.0/.agents/skills/preview-ingest/SKILL.md +162 -0
- fplkit-2.2.0/.agents/skills/release/SKILL.md +172 -0
- fplkit-2.2.0/.agents/skills/release-notes/SKILL.md +98 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/squad-builder/SKILL.md +96 -14
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/squad-builder/references/output-template.md +11 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/squad-builder/references/rules.md +24 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/skills/update-gw-prep/SKILL.md +25 -8
- fplkit-2.2.0/.github/workflows/ci.yml +64 -0
- fplkit-2.2.0/.github/workflows/pr-title.yml +30 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.github/workflows/release.yml +8 -3
- {fplkit-2.0.0 → fplkit-2.2.0}/.gitignore +0 -3
- fplkit-2.2.0/AGENTS.md +94 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/CHANGELOG.md +55 -1
- fplkit-2.2.0/CLAUDE.md +94 -0
- fplkit-2.2.0/CONTRIBUTING.md +109 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/PKG-INFO +44 -7
- {fplkit-2.0.0 → fplkit-2.2.0}/README.md +40 -4
- {fplkit-2.0.0 → fplkit-2.2.0}/cliff.toml +14 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/docs/architecture.md +103 -38
- fplkit-2.2.0/docs/command-reference.md +952 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/docs/custom-analysis.md +60 -15
- {fplkit-2.0.0 → fplkit-2.2.0}/docs/fpl-rules.md +5 -5
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/_version.py +2 -2
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/action/waiver.py +30 -4
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/analysis/bench_order.py +8 -3
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/analysis/captain.py +8 -3
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/analysis/squad_analyzer.py +1 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/analysis/starting_xi.py +26 -3
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/analysis/stats.py +10 -3
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/analysis/transfer_eval.py +15 -4
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/common.py +6 -3
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/data/fixture.py +9 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/orchestration/report.py +62 -12
- fplkit-2.2.0/fpl_cli/api/contract.py +77 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/core_insights.py +83 -23
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/dataset_fetcher.py +3 -21
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/football_data.py +18 -2
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/fpl_draft.py +7 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/providers/anthropic.py +1 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/understat.py +35 -4
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/vaastav.py +45 -5
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/__init__.py +17 -4
- fplkit-2.2.0/fpl_cli/cli/_context.py +321 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_fines.py +15 -7
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_helpers.py +21 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_league_recap_data.py +674 -67
- fplkit-2.2.0/fpl_cli/cli/_league_recap_history.py +1076 -0
- fplkit-2.2.0/fpl_cli/cli/_league_recap_types.py +198 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_review_analysis.py +2 -2
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_review_classic.py +23 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_review_summarisation.py +163 -20
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/allocate.py +45 -25
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/captain.py +2 -5
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/chips.py +1 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/differentials.py +2 -5
- fplkit-2.2.0/fpl_cli/cli/doctor.py +694 -0
- fplkit-2.2.0/fpl_cli/cli/doctor_providers.py +710 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/fdr.py +7 -7
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/init.py +18 -21
- fplkit-2.2.0/fpl_cli/cli/intel.py +534 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/league.py +9 -2
- fplkit-2.2.0/fpl_cli/cli/league_recap.py +547 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/player.py +32 -23
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/preview.py +6 -3
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/price_changes.py +2 -5
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/ratings.py +120 -10
- fplkit-2.2.0/fpl_cli/cli/returnees.py +798 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/review.py +36 -9
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/sell_prices.py +22 -3
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/squad.py +39 -10
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/stats.py +11 -7
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/status.py +117 -32
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/targets.py +2 -5
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/waivers.py +2 -5
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/xg.py +2 -5
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/config/defaults.yaml +19 -1
- fplkit-2.2.0/fpl_cli/config/fixture_predictions.yaml +5 -0
- fplkit-2.2.0/fpl_cli/config/previews/EXAMPLE.yaml +97 -0
- {fplkit-2.0.0 → fplkit-2.2.0/fpl_cli}/config/team_managers.yaml +10 -10
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/models/chip_plan.py +7 -4
- fplkit-2.2.0/fpl_cli/models/league_history.py +415 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/models/player.py +8 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/models/team.py +18 -8
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/models/types.py +16 -0
- fplkit-2.2.0/fpl_cli/paths.py +244 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/prompts/league_recap.py +68 -4
- fplkit-2.2.0/fpl_cli/prompts/returnees.py +104 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/prompts/review.py +59 -16
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/scraper/fpl_prices.py +63 -17
- fplkit-2.2.0/fpl_cli/season.py +162 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/services/fixture_predictions.py +124 -20
- fplkit-2.2.0/fpl_cli/services/league_history.py +343 -0
- fplkit-2.2.0/fpl_cli/services/league_history_counters.py +679 -0
- fplkit-2.2.0/fpl_cli/services/league_history_notes.py +648 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/services/player_prior.py +20 -21
- fplkit-2.2.0/fpl_cli/services/returnee_radar.py +1655 -0
- fplkit-2.2.0/fpl_cli/services/scoring/__init__.py +252 -0
- fplkit-2.2.0/fpl_cli/services/scoring/constants.py +493 -0
- fplkit-2.2.0/fpl_cli/services/scoring/data_prep.py +498 -0
- fplkit-2.2.0/fpl_cli/services/scoring/display.py +57 -0
- fplkit-2.2.0/fpl_cli/services/scoring/evaluation.py +333 -0
- fplkit-2.2.0/fpl_cli/services/scoring/ownership.py +241 -0
- fplkit-2.2.0/fpl_cli/services/scoring/shrinkage.py +213 -0
- fplkit-2.2.0/fpl_cli/services/scoring/signals.py +708 -0
- fplkit-2.2.0/fpl_cli/services/scoring/single_gw.py +550 -0
- fplkit-2.2.0/fpl_cli/services/scoring/value_quality.py +217 -0
- fplkit-2.2.0/fpl_cli/services/season_previews.py +953 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/services/squad_allocator.py +12 -4
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/services/team_ratings.py +323 -68
- fplkit-2.2.0/fpl_cli/services/team_ratings_prior.py +651 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/templates/gw_league_recap.md.j2 +23 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/templates/gw_review.md.j2 +9 -1
- fplkit-2.2.0/fpl_cli/utils/files.py +37 -0
- fplkit-2.2.0/fpl_cli/utils/gameweek.py +10 -0
- fplkit-2.2.0/fpl_cli/utils/markdown.py +292 -0
- fplkit-2.2.0/fpl_cli/utils/teams.py +51 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/pyproject.toml +14 -1
- fplkit-2.2.0/scripts/calibrate_promoted_prior.py +283 -0
- fplkit-2.2.0/scripts/calibrate_quality_ceilings.py +669 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/conftest.py +116 -4
- fplkit-2.2.0/tests/fixtures/validate_draft_waivers/recs_clean.md +28 -0
- fplkit-2.2.0/tests/fixtures/validate_draft_waivers/waivers.json +19 -0
- fplkit-2.2.0/tests/fixtures/waiver_ranked_golden.json +1053 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_agents_action.py +344 -5
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_agents_analysis.py +21 -3
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_agents_analysis_squad.py +9 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_agents_data.py +21 -4
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_allocate.py +73 -27
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_api_core_insights.py +74 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_api_draft.py +33 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_api_football_data.py +14 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_api_understat.py +73 -3
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_api_vaastav.py +84 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_bench_order_script.py +17 -6
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_classic_squad_extraction.py +633 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_allocate.py +4 -4
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_captain.py +7 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_chips.py +17 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_custom_analysis.py +73 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_differentials.py +7 -0
- fplkit-2.2.0/tests/test_cli_doctor.py +485 -0
- fplkit-2.2.0/tests/test_cli_doctor_providers.py +359 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_fdr.py +54 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_fdr_blanks.py +43 -7
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_init.py +5 -1
- fplkit-2.2.0/tests/test_cli_intel.py +344 -0
- fplkit-2.2.0/tests/test_cli_league.py +67 -0
- fplkit-2.2.0/tests/test_cli_league_recap.py +1941 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_player.py +140 -2
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_preview.py +67 -0
- fplkit-2.2.0/tests/test_cli_price_changes.py +57 -0
- fplkit-2.2.0/tests/test_cli_returnees.py +868 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_review.py +208 -2
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_sell_prices.py +91 -1
- fplkit-2.2.0/tests/test_cli_settings_warning.py +99 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_squad.py +109 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_stats.py +8 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_status.py +332 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_targets.py +7 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_waivers.py +7 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_warnings_stderr.py +2 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_xg.py +7 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_common.py +37 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_common_scoring.py +4 -4
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_data_prep_harmonisation.py +17 -9
- fplkit-2.2.0/tests/test_doc_consistency.py +89 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_fines.py +16 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_fixture_predictions.py +183 -7
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_init.py +51 -0
- fplkit-2.2.0/tests/test_league_history_counters.py +935 -0
- fplkit-2.2.0/tests/test_league_history_notes.py +701 -0
- fplkit-2.2.0/tests/test_league_history_store.py +588 -0
- fplkit-2.2.0/tests/test_league_recap.py +2876 -0
- fplkit-2.2.0/tests/test_paths.py +454 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_player_prior.py +14 -14
- fplkit-2.2.0/tests/test_preseason.py +542 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_providers.py +5 -5
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_report_agent.py +50 -0
- fplkit-2.2.0/tests/test_report_paths.py +212 -0
- fplkit-2.2.0/tests/test_returnee_radar.py +1467 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_review.py +257 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_rolling_pts_per_m.py +1 -1
- fplkit-2.0.0/tests/test_player_scoring.py → fplkit-2.2.0/tests/test_scoring.py +655 -93
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_scraper.py +187 -25
- fplkit-2.2.0/tests/test_season.py +219 -0
- fplkit-2.2.0/tests/test_season_awareness.py +382 -0
- fplkit-2.2.0/tests/test_season_previews.py +763 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_squad_allocator.py +63 -2
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_starting_xi_agent.py +53 -1
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_stats.py +60 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_team_ratings.py +564 -17
- fplkit-2.2.0/tests/test_team_ratings_prior.py +1048 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_transfer_eval_agent.py +1 -1
- fplkit-2.2.0/tests/test_utils_gameweek.py +18 -0
- fplkit-2.2.0/tests/test_utils_markdown.py +238 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_validate_draft_waivers.py +363 -0
- fplkit-2.0.0/.agents/TOOLS.md +0 -97
- fplkit-2.0.0/.github/workflows/ci.yml +0 -35
- fplkit-2.0.0/AGENTS.md +0 -70
- fplkit-2.0.0/CLAUDE.md +0 -70
- fplkit-2.0.0/config/team_ratings.yaml +0 -119
- fplkit-2.0.0/docs/command-reference.md +0 -588
- fplkit-2.0.0/fpl_cli/cli/_context.py +0 -171
- fplkit-2.0.0/fpl_cli/cli/_league_recap_types.py +0 -120
- fplkit-2.0.0/fpl_cli/cli/league_recap.py +0 -297
- fplkit-2.0.0/fpl_cli/config/fixture_predictions.yaml +0 -10
- fplkit-2.0.0/fpl_cli/paths.py +0 -130
- fplkit-2.0.0/fpl_cli/season.py +0 -88
- fplkit-2.0.0/fpl_cli/services/player_scoring.py +0 -2784
- fplkit-2.0.0/fpl_cli/services/team_ratings_prior.py +0 -291
- fplkit-2.0.0/tests/fixtures/validate_draft_waivers/recs_clean.md +0 -20
- fplkit-2.0.0/tests/fixtures/validate_draft_waivers/waivers.json +0 -12
- fplkit-2.0.0/tests/test_league_recap.py +0 -1425
- fplkit-2.0.0/tests/test_paths.py +0 -182
- fplkit-2.0.0/tests/test_season.py +0 -95
- fplkit-2.0.0/tests/test_team_ratings_prior.py +0 -194
- {fplkit-2.0.0 → fplkit-2.2.0}/.agents/README.md +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.claude/output-styles/fpl-mate.md +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.claude/settings.json +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/.env.example +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/LICENSE +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/config/team_ratings_overrides.yaml +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/docs/images/fpl-player-demo-v1-0.png +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/action/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/analysis/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/base.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/data/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/data/price.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/data/scout.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/agents/orchestration/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/fpl.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/historical.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/historical_types.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/providers/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/providers/_models.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/providers/openai_compat.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/api/providers/perplexity.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_banner.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_fines_config.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_json.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_plan_grid.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/_review_draft.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/credentials.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/fixtures.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/history.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/price_history.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/cli/transfer_eval.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/constants.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/models/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/models/fixture.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/parsers/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/parsers/recommendations.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/prompts/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/prompts/scout.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/scraper/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/services/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/services/matchup.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/services/team_form.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/templates/gw_preview.md.j2 +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/utils/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/utils/text.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/fpl_cli/utils/time.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/pyrightconfig.json +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/requirements.lock +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/__init__.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/fixtures/classic_squad_fixture.md +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/fixtures/recommendations_fixture.md +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/fixtures/validate_draft_waivers/squad_grid.json +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_agents_base.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_agents_data_price.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_agents_orchestration.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_api_client.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_api_dataset_fetcher.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_api_historical.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_banner.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_credentials.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_fixtures.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_format.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_format_suppression.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_history.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_json.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_plan_grid.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_price_history.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_cli_transfer_eval.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_fines_config.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_fpl_prices.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_init_fines.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_matchup_service.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_models.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_player_resolution.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_recommendations_parser.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_sell_prices.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_utils_text.py +0 -0
- {fplkit-2.0.0 → fplkit-2.2.0}/tests/test_utils_time.py +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Tools & Capabilities
|
|
2
|
+
|
|
3
|
+
Complete inventory of fpl-cli's composable surface. For architectural diagrams and data flow, see [docs/architecture.md](../docs/architecture.md). For FPL-context usage guidance, see [.claude/output-styles/fpl-mate.md](../.claude/output-styles/fpl-mate.md).
|
|
4
|
+
|
|
5
|
+
## JSON Envelope
|
|
6
|
+
|
|
7
|
+
All `--format json` commands emit a standard envelope via `emit_json()` in `fpl_cli/cli/_json.py`:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"command": "<command-name>",
|
|
12
|
+
"metadata": { ... },
|
|
13
|
+
"data": [ ... ]
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- `command` - the CLI command name (e.g. `"captain"`, `"chips-timing"`)
|
|
18
|
+
- `metadata` - command-specific context (typically includes `gameweek`)
|
|
19
|
+
- `data` - the payload (list or dict, varies per command)
|
|
20
|
+
|
|
21
|
+
Errors use `emit_json_error()` with `{"command", "error"}` shape.
|
|
22
|
+
|
|
23
|
+
## CLI Commands
|
|
24
|
+
|
|
25
|
+
| Command | Description | JSON | Format | Experimental | Pattern |
|
|
26
|
+
|---------|-------------|------|--------|-------------|---------|
|
|
27
|
+
| `init` | Set up fpl-cli with your FPL IDs and optional features | No | General | No | direct-api |
|
|
28
|
+
| `status` | Show FPL gameweek status and upcoming deadlines. JSON `metadata` carries `gameweek`, `format` and `season` (hyphenated label, e.g. `2026-27`) - `season` is the directory segment skills must use when writing alongside fpl-cli's own reports | Yes | General | No | direct-api |
|
|
29
|
+
| `doctor` | Check the setup for dead IDs, stale data, and config problems: resolves each configured ID against the live API (reporting the team/league name back so a wrong-but-valid ID is visible), verifies per-team data files (team ratings, managers, season preview intel, finances, player prior) describe the current season's clubs, and reports which config/data/cache directories are in use. With `--providers`, probes the external data sources instead: live shape-and-volume checks against the FPL and Draft APIs, the vaastav and Core-Insights datasets, Understat, and football-data.org, including that every club resolves across sources (the drift that otherwise surfaces as plausible but wrong output). Distinguishes broken (needs a fix today) from stale (self-corrects). Exits non-zero when something is broken | Yes | General | No | direct-api |
|
|
30
|
+
| `fixtures` | Show fixtures for a gameweek | Yes | General | No | direct-api |
|
|
31
|
+
| `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), emitting `null` when FPL has no projection; panel shows `xPts` (ep_next) when available, omits the segment when FPL has no projection. `--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 |
|
|
32
|
+
| `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; `ep_this` is only meaningful before the gameweek's first kickoff — FPL rolls it forward to `ep_next` as each player's match finishes); both in JSON output (emit `null` when FPL has no projection; table renders `—`). Players with no projection sort to the bottom in either direction | Yes | General | No | direct-api |
|
|
33
|
+
| `history` | Show historical player performance across seasons | Yes | General | No | direct-api |
|
|
34
|
+
| `league` | Show live league standings for Classic and Draft leagues | No | General | No | direct-api |
|
|
35
|
+
| `fdr` | Analyse fixture difficulty - easy runs, blanks, doubles | Yes | General | No | via-agent |
|
|
36
|
+
| `xg` | Analyse underlying stats: xG, xA, overperformers | Yes | General | No | via-agent |
|
|
37
|
+
| `price-changes` | Show price changes and transfer activity | No | General | No | via-agent |
|
|
38
|
+
| `price-history` | Show price trajectory and transfer momentum | Yes | General | No | direct-api |
|
|
39
|
+
| `returnees` | Track injured and suspended players due back soon, so a returnee can be claimed in draft before they are fit or planned around in classic. Reads the FPL availability news, filters to returns inside a window (`--window N`, 1-38) and through a source-aware quality bar, and diffs against the stored watchlist for week-over-week changes. Most flagged players carry no parseable return date, so date-unknown entries are the norm rather than the exception; `--enrich` searches the web for fresher timing on those and on stale-news entries (needs a Perplexity key; skips with a note without one) and shows it beside the FPL news, never over it. `--all` bypasses the quality bar and deliberately does not persist the snapshot. JSON `metadata` carries `window`, `escalation_window`, `stash_upgrade_margin`, `transitions_available`, `quality_bar_available`, `quality_bar_applied` and `enrichment_requested`/`_available`/`_note`/`_count`; `data` is `{entries, departures}`, each entry carrying `quality.basis`/`quality.meets_stash`, `expected_return`/`return_gameweek`/`return_source`, `escalation_eligible`/`escalation_basis`, `transition`, and `enrichment` (null unless enriched) | Yes | General | No | direct-api |
|
|
40
|
+
| `preview` | Run full pre-gameweek analysis and generate report. `--save` writes to `<output dir>/<season>/gw{N}-preview.md`; `--scout` writes to `<research dir>/ai-scout-reports/<season>/gw{N}-scout-preview[-referenced].md` | No | General | No | via-agent |
|
|
41
|
+
| `review` | Review a completed gameweek - squad performance and standings. `--save` writes to `<output dir>/<season>/gw{N}-review.md`; `--compare-recs` reads `gw{N}-recommendations.md` from the same season directory | No | General | No | via-agent |
|
|
42
|
+
| `league-recap` | Recap a completed gameweek - awards, standings, and banter. Saves to `<output dir>/<season>/gw{N}-league-recap[-draft].md`. Records every run into the league history ledger (`<data dir>/league_history/`) as a side effect, backfilling classic gaps at a coarse tier automatically; `--backfill-detail` rebuilds earlier gameweeks in full (one request per manager per gameweek). Coverage gaps and capture warnings go to stderr; the command exits 0 even when the store is unreadable. `--format json` emits one row per manager (the captured ledger row shape) plus `metadata.coverage`, `season_phase`, `notes_pack`, `synthesis_summary`, `warnings` (always present, each entry a stable `code` plus rewritable `message` - codes listed in [Command Reference](../docs/command-reference.md#league-history)) and `first_capture_store_path` | Yes | General | No | via-agent |
|
|
43
|
+
| `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. Players ruled out of the gameweek (0% chance, or no minutes from GW6) are held out of the GW1-9 shrinkage rather than pulled toward the position mean | Yes | Classic | Yes | via-agent |
|
|
44
|
+
| `differentials` | Find differential picks - high potential, low ownership. Inverted consistency bonus (volatile players score higher, phased in GW6-10). Players ruled out of the gameweek (0% chance, or no minutes from GW6) are held out of the GW1-9 shrinkage rather than pulled toward the position mean | Yes | Classic | Yes | via-agent |
|
|
45
|
+
| `targets` | Find transfer targets - high performers across all ownership. Consistency bonus (CV-xGI percentile, phased in GW6-10). Players ruled out of the gameweek (0% chance, or no minutes from GW6) are held out of the GW1-9 shrinkage rather than pulled toward the position mean | Yes | Classic | Yes | via-agent |
|
|
46
|
+
| `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. Players ruled out of the gameweek (0% chance, or no minutes from GW6) are held out of the GW1-9 shrinkage rather than pulled toward the position mean | Yes | General | Yes | via-agent |
|
|
47
|
+
| `allocate` | Select mathematically optimal 15-player squad within budget. Players ruled out of the gameweek (0% chance, or no minutes from GW6) are held out of the GW1-9 shrinkage rather than pulled toward the position mean; they stay in the solver pool | Yes | Classic | Yes | direct-api |
|
|
48
|
+
| `waivers` | Show waiver recommendations for your draft league. JSON `data` carries `top_targets` and `targets_by_position` (ranked claims) plus `pool` — the full unowned roster, one `{id, player_name, position, team_short}` row each, unranked and untruncated, so a consumer can answer "is this player claimable at all" without inferring it from the ranked lists. Players ruled out of the gameweek (0% chance, or no minutes from GW6) are held out of the GW1-9 shrinkage rather than pulled toward the position mean | Yes | Draft | Yes | via-agent |
|
|
49
|
+
| `squad` | Analyse your FPL squad health and fixtures | Yes | General | No | via-agent |
|
|
50
|
+
| `squad grid` | Show squad fixture difficulty grid | Yes | General | No | via-agent |
|
|
51
|
+
| `squad sell-prices` | Show squad sell prices and financial breakdown | Yes | Classic | No | direct-api |
|
|
52
|
+
| `chips` | View and plan FPL chip usage | Yes | Classic | No | direct-api |
|
|
53
|
+
| `chips timing` | Recommend chip timing based on blank/double GW exposure | Yes | Classic | No | via-agent |
|
|
54
|
+
| `chips add` | Plan a chip for a gameweek | No | Classic | No | direct-api |
|
|
55
|
+
| `chips remove` | Remove a planned chip from a gameweek | No | Classic | No | direct-api |
|
|
56
|
+
| `chips sync` | Sync chip usage from FPL API | No | Classic | No | direct-api |
|
|
57
|
+
| `ratings` | Display team ratings | No | General | Yes | direct-api |
|
|
58
|
+
| `ratings update` | Recalculate ratings from fixture results (shrunk toward the previous-season prior before GW12; seeds from the prior when no results exist yet) | No | General | Yes | direct-api |
|
|
59
|
+
| `intel` | Show season preview intel collected per team, with coverage and per-gameweek decay. JSON `metadata` carries `coverage.usable_as` (`full` / `negative_filter_only` / `none`), `section_confidence`, `sections_live`/`sections_expired`, `decay_schedule`, `team_set_warning` and `warnings`. `-g/--gameweek` ages the payload to any gameweek; `--show-decay` prints the expiry schedule | Yes | General | No | direct-api |
|
|
60
|
+
| `intel schema` | Print the preview file format with every field explained | No | General | No | direct-api |
|
|
61
|
+
| `intel init` | Scaffold an empty preview file per Premier League team (`--force` overwrites). Stubs never count toward coverage | No | General | No | direct-api |
|
|
62
|
+
| `intel show` | Show one team's preview, aged to the current gameweek | Yes | General | No | direct-api |
|
|
63
|
+
| `intel resolve` | Match preview player names to FPL `element_code`s; `--write` saves them back with comments preserved (never touching an existing code), `--all` re-resolves coded players and with `--write` saves corrections over them. Ambiguity is reported, never guessed | Yes | General | No | direct-api |
|
|
64
|
+
| `credentials set` | Store FPL email and password in system keyring | No | Classic | No | direct-api |
|
|
65
|
+
| `credentials clear` | Remove FPL credentials from system keyring | No | Classic | No | direct-api |
|
|
66
|
+
|
|
67
|
+
**Column key:**
|
|
68
|
+
- **JSON** - supports `--format json` output
|
|
69
|
+
- **Format** - Classic (classic league only), Draft (draft league only), General (both)
|
|
70
|
+
- **Experimental** - requires `custom_analysis: true` in settings; hidden from `--help` by default, and invoking one while it is off reports the toggle and the settings.yaml being read
|
|
71
|
+
- **Pattern** - `direct-api` (API client only), `via-agent` (uses analysis agent), `mixed` (both patterns in subcommands)
|
|
72
|
+
|
|
73
|
+
**Report paths are season-partitioned.** Every command that saves a report writes to `<dir>/<season>/gw{N}-*.md`, where `<season>` is the hyphenated label (`2026-27`). Report filenames carry a gameweek but no season, so a flat directory lets one season's GW21 file overwrite the previous season's. This applies to an explicit `--output` too. Any skill or script writing alongside these reports must use the same season directory, and must take the label from `fpl status --format json` (`metadata.season`) rather than hardcoding it — a hardcoded label silently rots at the July rollover.
|
|
74
|
+
|
|
75
|
+
## Skills
|
|
76
|
+
|
|
77
|
+
Agent playbooks in `.agents/skills/`. Each has a `SKILL.md` entry point. Claude Code discovers them via the `.claude/skills/` symlink.
|
|
78
|
+
|
|
79
|
+
Skills write their own outputs (`gw{N}-recommendations.md`, `gw{N}-squad-builder.md`, `season-start-squad.md`) into the same `<output dir>/<season>/` directory, for the same reason.
|
|
80
|
+
|
|
81
|
+
| Skill | Path | Purpose | Compatibility |
|
|
82
|
+
|-------|------|---------|--------------|
|
|
83
|
+
| gw-prep | `skills/gw-prep/` | Gameweek preparation recommendations for classic and draft (embed / rederive / transfer branches; Phase B9 preview intel; Phase B10 injury returnee radar; Phase E post-write validation) | Full: Claude Code. Partial: Codex, Cursor, Copilot |
|
|
84
|
+
| update-gw-prep | `skills/update-gw-prep/` | Append GW update to existing recommendations | Full: Claude Code, Codex, Cursor, Copilot |
|
|
85
|
+
| squad-builder | `skills/squad-builder/` | Build optimal 15-player squad (wildcard, free hit, season start; Phase B3 preview intel gate) | Full: Claude Code, Codex, Cursor, Copilot |
|
|
86
|
+
| preview-ingest | `skills/preview-ingest/` | Convert season preview prose into structured per-team intel files, resolve player codes, verify coverage | Full: Claude Code (parallel per team), Codex, Cursor, Copilot |
|
|
87
|
+
| release-notes | `skills/release-notes/` | Draft release notes and suggest the next semver (read-only preview; never tags or publishes) | Full: Claude Code, Codex, Cursor, Copilot |
|
|
88
|
+
| release | `skills/release/` | Cut a release end-to-end: preflight, notes via release-notes, approval gate, publish GitHub release (tag drives PyPI publish + changelog automation) | Full: Claude Code (local), Codex, Cursor, Copilot. Partial: Claude Code web (publish step handed to user) |
|
|
89
|
+
| create-pr | `skills/create-pr/` | Open a PR for the current branch: conventional-commit title (the changelog line) + why-first prose body in the fpl-cli PR description style | Full: Claude Code, Codex, Cursor, Copilot |
|
|
90
|
+
|
|
91
|
+
## Analysis Agents
|
|
92
|
+
|
|
93
|
+
Python classes in `fpl_cli/agents/` that implement `async run(context) -> AgentResult`.
|
|
94
|
+
|
|
95
|
+
| Agent | Module | Category | CLI Commands | External Consumers |
|
|
96
|
+
|-------|--------|----------|-------------|-------------------|
|
|
97
|
+
| FixtureAgent | `agents/data/fixture.py` | Data | `fdr`, `player -f`, `chips timing`, `preview` | - |
|
|
98
|
+
| PriceAgent | `agents/data/price.py` | Data | `price-changes`, `preview` | - |
|
|
99
|
+
| ScoutAgent | `agents/data/scout.py` | Data | `preview` | - |
|
|
100
|
+
| StatsAgent | `agents/analysis/stats.py` | Analysis | `xg`, `targets`, `differentials`, `preview` | - |
|
|
101
|
+
| CaptainAgent | `agents/analysis/captain.py` | Analysis | `captain`, `differentials` | - |
|
|
102
|
+
| SquadAnalyzerAgent | `agents/analysis/squad_analyzer.py` | Analysis | `squad` | - |
|
|
103
|
+
| BenchOrderAgent | `agents/analysis/bench_order.py` | Analysis | - | gw-prep skill |
|
|
104
|
+
| StartingXIAgent | `agents/analysis/starting_xi.py` | Analysis | - | gw-prep skill |
|
|
105
|
+
| TransferEvalAgent | `agents/analysis/transfer_eval.py` | Analysis | `transfer-eval` | gw-prep skill |
|
|
106
|
+
| WaiverAgent | `agents/action/waiver.py` | Action | `waivers` | - |
|
|
107
|
+
| ReportAgent | `agents/orchestration/report.py` | Orchestration | `preview`, `review`, `league-recap` | - |
|
|
108
|
+
|
|
109
|
+
**Notes:**
|
|
110
|
+
- BenchOrderAgent and StartingXIAgent have no CLI command - they are invoked by gw-prep skill wrapper scripts in `.agents/skills/gw-prep/scripts/`
|
|
111
|
+
- Every scoring family holds players known not to be playing out of the GW1-9 shrinkage; bench and lineup order on raw scores, so for those two it changes the displayed score only
|
|
112
|
+
- TransferEvalAgent is used by both `transfer-eval` CLI command and gw-prep skill
|
|
113
|
+
- `extract_classic_squad.py` (`.agents/skills/gw-prep/scripts/`) — deterministic Classic Squad block extractor used by gw-prep Phase A3 + Phase E. JSON stdout; read-only; emits TypedDict-annotated payloads.
|
|
114
|
+
- gw-prep Phase B10 runs `fpl returnees --enrich --format json` and inlines the payload into both Phase C prompts, rendering a Returning Soon section in the classic and draft output templates. In draft a row can escalate into a stash claim; in classic the watchlist is informational and transfer recommendations may not name a tracked returnee (`references/rules.md`)
|
|
115
|
+
- `validate_draft_waivers.py` (`.agents/skills/gw-prep/scripts/`) — cross-checks the Draft waiver table against the live waiver pool and squad grid (gw-prep Phase D1). JSON stdout; read-only; always exits 0.
|
|
116
|
+
- Both scripts locate markdown sections via `fpl_cli.utils.markdown` (`HeadingMatcher`, `find_section`, `section_body`, `leaf_body`, `fence_flags`), tolerating LLM heading drift (qualifiers, case, leading annotations, opt-in aliases) without matching a different heading that shares a prefix. Also used by `fpl_cli/prompts/review.py` for the GW Narrative section boundary.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-pr
|
|
3
|
+
description: >
|
|
4
|
+
Use when the user asks to create a pull request or PR for the current
|
|
5
|
+
branch — "create a PR", "open a PR", "raise a PR", "push and create a
|
|
6
|
+
PR", "ship this branch". Writes the title as the changelog line
|
|
7
|
+
(conventional commits) and the body in the fpl-cli PR description style:
|
|
8
|
+
first-person prose, why-first, no boilerplate sections. Also the style
|
|
9
|
+
reference whenever a session writes a PR title or body outside the skill.
|
|
10
|
+
model: sonnet
|
|
11
|
+
compatibility:
|
|
12
|
+
claude-code: full (gh locally, GitHub MCP tools on the web)
|
|
13
|
+
codex: full (gh)
|
|
14
|
+
cursor: full (gh)
|
|
15
|
+
copilot: full (gh)
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Create Pull Request
|
|
19
|
+
|
|
20
|
+
Opens a PR for the current branch against main: pushes the branch, writes
|
|
21
|
+
a conventional-commit title, and a prose description in the fpl-cli PR
|
|
22
|
+
description style. Solo repo — there are no reviewers, squads, or labels
|
|
23
|
+
to assign, and the PR is created ready (not draft) unless asked otherwise.
|
|
24
|
+
|
|
25
|
+
## Title: the changelog line
|
|
26
|
+
|
|
27
|
+
PRs squash-merge with the title as the commit subject on main, and
|
|
28
|
+
git-cliff publishes `feat:`/`fix:`/`refactor:`/`perf:` subjects verbatim in
|
|
29
|
+
CHANGELOG.md and the GitHub release notes. The `PR Title` CI check rejects
|
|
30
|
+
anything non-conventional. So:
|
|
31
|
+
|
|
32
|
+
- Format `type(scope)?!?: subject` — types as in `cliff.toml` (`feat`,
|
|
33
|
+
`fix`, `refactor`, `perf` are changelog-visible; `chore`, `docs`, `ci`,
|
|
34
|
+
`test`, `style` are skipped). `!` marks a breaking CLI change and drives
|
|
35
|
+
a major bump.
|
|
36
|
+
- A changelog-visible title must read as the standalone user-facing change
|
|
37
|
+
("fix: pin PuLP below 4.0 so squad allocation keeps working"), never the
|
|
38
|
+
implementation ("fix: address review feedback").
|
|
39
|
+
- Keep it ≤ 72 characters — GitHub appends ` (#N)` on squash.
|
|
40
|
+
- No issue references in the title; `Closes #N` lives in the body, so the
|
|
41
|
+
changelog line stays clean.
|
|
42
|
+
- One purpose per PR, so one title can describe it. If no single
|
|
43
|
+
conventional subject covers the diff, the branch wants splitting, not a
|
|
44
|
+
vaguer title.
|
|
45
|
+
|
|
46
|
+
## Description: the fpl-cli PR description style
|
|
47
|
+
|
|
48
|
+
The body is **flowing first-person prose**, as if explaining the change to
|
|
49
|
+
a colleague. No `## Summary`/`## Changes`/`## Testing` headings, no
|
|
50
|
+
file-by-file changelog, no checklists.
|
|
51
|
+
|
|
52
|
+
### Tone
|
|
53
|
+
|
|
54
|
+
First person, conversational, proper sentence casing. Reads like an
|
|
55
|
+
explanation, not a filled-in template.
|
|
56
|
+
|
|
57
|
+
Good: "The changelog job pushes straight to main, which the new ruleset
|
|
58
|
+
would block — so it now authenticates as the repo admin, who is a bypass
|
|
59
|
+
actor."
|
|
60
|
+
Bad: "## Summary\nThis PR updates the changelog job's authentication."
|
|
61
|
+
|
|
62
|
+
### Content
|
|
63
|
+
|
|
64
|
+
- **Open with why, not what.** Start with the problem or context that
|
|
65
|
+
motivated the change. The diff already shows what changed.
|
|
66
|
+
- **Explain the approach when it is non-obvious.** Natural phrasing ("the
|
|
67
|
+
general strategy is"), not a formal section.
|
|
68
|
+
- **`Closes #N`** inline when the PR resolves an issue — GitHub closes it
|
|
69
|
+
on merge. The branch name often carries the number (`claude/issue-46-…`).
|
|
70
|
+
- **Use italics for caveats, scope notes, and verification gaps.**
|
|
71
|
+
Deliberate omissions, known limitations, and anything you could not
|
|
72
|
+
verify — and why — go in `_italics_`. In this repo that is usually
|
|
73
|
+
behaviour needing live FPL API data, LLM provider keys, or the scraper's
|
|
74
|
+
FPL credentials, none of which a web session has.
|
|
75
|
+
- **Include stats when relevant.** Test counts, performance numbers,
|
|
76
|
+
migration sizes — plainly stated, at the end.
|
|
77
|
+
|
|
78
|
+
### Structure and length
|
|
79
|
+
|
|
80
|
+
No fixed sections. Bullets only where you are genuinely listing items
|
|
81
|
+
(rules, scenarios, per-command effects) — never as the default shape.
|
|
82
|
+
|
|
83
|
+
Pick the budget before writing, and stay inside it:
|
|
84
|
+
|
|
85
|
+
| Change | Body |
|
|
86
|
+
|---|---|
|
|
87
|
+
| Dependency bump, config/data refresh, docs, cleanup, test-only | 1–2 sentences |
|
|
88
|
+
| Bug fix, small feature, new flag, refactor | 2–3 sentences |
|
|
89
|
+
| New agent, new data source, scoring change, or a strategy the diff cannot show | up to 3 short paragraphs |
|
|
90
|
+
|
|
91
|
+
Break the body up at every length: at 2–3 sentences, one sentence per
|
|
92
|
+
line; beyond that, paragraphs of two-three sentences with blank lines
|
|
93
|
+
between. Then one editing pass — delete every sentence that only tells the
|
|
94
|
+
reviewer something the diff or the title already tells them.
|
|
95
|
+
|
|
96
|
+
### What to leave out
|
|
97
|
+
|
|
98
|
+
- No "Test Plan"/"How to verify"/"Acceptance Criteria" sections
|
|
99
|
+
- No "Changes" lists that duplicate the diff
|
|
100
|
+
- No empty validation ("great improvement to the codebase")
|
|
101
|
+
- No restating the title or narrating commits
|
|
102
|
+
- No extra AI-attribution lines — remote Claude Code sessions append a
|
|
103
|
+
"Generated with Claude Code" footer automatically; that platform footer
|
|
104
|
+
stays, and nothing more gets added
|
|
105
|
+
|
|
106
|
+
## Workflow
|
|
107
|
+
|
|
108
|
+
### Step 1: Branch and push
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
BRANCH=$(git branch --show-current) # never main
|
|
112
|
+
git push -u origin "$BRANCH"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Target is always `main`. If the branch's previous PR was already merged,
|
|
116
|
+
restart the branch from `origin/main` first and carry only unmerged
|
|
117
|
+
commits.
|
|
118
|
+
|
|
119
|
+
### Step 2: Gather the why
|
|
120
|
+
|
|
121
|
+
If the branch or session references an issue, read it (`gh issue view N`,
|
|
122
|
+
or the GitHub MCP `issue_read` tool) for motivation. `git log
|
|
123
|
+
origin/main..HEAD --oneline` shows scope — use it to understand intent,
|
|
124
|
+
never to write a commit list into the body.
|
|
125
|
+
|
|
126
|
+
### Step 3: Write title and body
|
|
127
|
+
|
|
128
|
+
Title per the rules above; body inside the length budget. Sanity-check the
|
|
129
|
+
title against the lint regex:
|
|
130
|
+
`^(feat|fix|refactor|perf|chore|docs|ci|test|style)(\([a-zA-Z0-9._/ -]+\))?!?: .+`
|
|
131
|
+
|
|
132
|
+
### Step 4: Create the PR
|
|
133
|
+
|
|
134
|
+
Local session:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
gh pr create --title "<title>" --base main --body "$(cat <<'EOF'
|
|
138
|
+
<body prose>
|
|
139
|
+
EOF
|
|
140
|
+
)"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Web/remote session: the GitHub MCP `create_pull_request` tool (load via
|
|
144
|
+
ToolSearch) with the same title/body, `base: main`.
|
|
145
|
+
|
|
146
|
+
Pass `--draft` (or `draft: true`) only if the user asked to open it as a
|
|
147
|
+
draft to keep working on the branch.
|
|
148
|
+
|
|
149
|
+
### Step 5: Report
|
|
150
|
+
|
|
151
|
+
Print the PR URL. If the user asked for auto-merge, arm it (`gh pr merge
|
|
152
|
+
--auto --squash`, or the MCP `enable_pr_auto_merge` tool) — it merges once
|
|
153
|
+
the required `check` and `lint` checks pass.
|
|
154
|
+
|
|
155
|
+
## Stacked PRs
|
|
156
|
+
|
|
157
|
+
When this branch builds on another open PR, target that PR's branch
|
|
158
|
+
instead of main and end the body with `Stacked on #N.` Sanity-check with
|
|
159
|
+
`git log origin/<target>..HEAD --oneline` — only this PR's commits should
|
|
160
|
+
appear. When the base PR squash-merges and its branch auto-deletes, GitHub
|
|
161
|
+
retargets this PR to main and the diff inherits the base PR's commits:
|
|
162
|
+
rebase onto main before review continues.
|
|
163
|
+
|
|
164
|
+
## Common Mistakes
|
|
165
|
+
|
|
166
|
+
- Issue number in the title (belongs in the body as `Closes #N`)
|
|
167
|
+
- A changelog-visible title describing the implementation or the review
|
|
168
|
+
process instead of the user-facing change
|
|
169
|
+
- Narrating the diff or padding the body to look thorough
|
|
170
|
+
- Describing only what changed and never why — even a two-sentence body
|
|
171
|
+
carries the motivation
|
|
172
|
+
- Bundling unrelated changes so no single title can describe the PR
|
|
173
|
+
- Forgetting to push before creating the PR
|
|
174
|
+
- Adding attribution lines beyond the automatic platform footer
|
|
175
|
+
|
|
176
|
+
## Validation
|
|
177
|
+
|
|
178
|
+
- The branch is pushed and the PR targets `main` (or a stacked base per
|
|
179
|
+
the rules above), created ready unless the user asked for a draft.
|
|
180
|
+
- The title matches the lint regex, is ≤ 72 characters, carries no issue
|
|
181
|
+
ref, and — if changelog-visible — reads as the standalone user-facing
|
|
182
|
+
change.
|
|
183
|
+
- The body is why-first first-person prose within its length budget: no
|
|
184
|
+
boilerplate headings, no diff narration, no empty validation, and no
|
|
185
|
+
sentence restating the title or the diff.
|
|
186
|
+
- `Closes #N` appears when the PR resolves an issue; caveats and
|
|
187
|
+
verification gaps are in italics; any stats are plainly stated at the
|
|
188
|
+
end.
|
|
189
|
+
- The PR URL was reported to the user.
|
|
@@ -13,7 +13,7 @@ compatibility:
|
|
|
13
13
|
copilot: fallback (sequential execution)
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<!-- CLI commands composed: status, chips, chips sync, chips timing, fdr, captain, waivers, squad grid, squad sell-prices, price-history, player, stats -->
|
|
16
|
+
<!-- CLI commands composed: status, chips, chips sync, chips timing, fdr, captain, waivers, squad grid, squad sell-prices, price-history, player, stats, intel, returnees -->
|
|
17
17
|
|
|
18
18
|
# Gameweek Preparation
|
|
19
19
|
|
|
@@ -48,6 +48,9 @@ Extract:
|
|
|
48
48
|
- `deadline` -- the transfer deadline timestamp
|
|
49
49
|
- `phase` -- current status (e.g. "Fixture day 1 of 2", "Between gameweeks")
|
|
50
50
|
- `metadata.format` -- `"classic"`, `"draft"`, or `"both"`. This determines which sub-agents to dispatch and which Phase B commands to run. If format is not present (no entry IDs configured), ask the user.
|
|
51
|
+
- `metadata.season` -- the hyphenated season label (e.g. `"2026-27"`). Referred to below as `{season}`.
|
|
52
|
+
|
|
53
|
+
**Every file this skill reads or writes lives under `[YOUR_OUTPUT_DIR]/{season}/`.** Report filenames carry the gameweek but no season, so a flat output directory lets 2026-27's GW21 file overwrite 2025-26's. Take `{season}` from this command rather than hardcoding it -- a hardcoded label silently rots at the July rollover, which is the failure this partition exists to prevent. `fpl` writes its own reports to the same season directory.
|
|
51
54
|
|
|
52
55
|
### A1.5 -- Chip Status
|
|
53
56
|
|
|
@@ -82,7 +85,7 @@ _Skip unless `mode == "squad-builder"` AND `active_chip ∈ {wildcard, freehit}`
|
|
|
82
85
|
|
|
83
86
|
Locate a matching squad-builder output file and extract the Classic Squad block for embedding. Sets `squad_builder_result = "embed"` on success, or `"rederive"` with a `squad_builder_reason` code on failure. Resolving mode in Phase A (before Phase B) lets sub-agents know up-front which Phase B outputs will actually feed them, and prints the rederive warning banner before any data-gather commands run. All steps are synchronous and must complete before Phase B begins.
|
|
84
87
|
|
|
85
|
-
1. Look for `[YOUR_OUTPUT_DIR]/gw{N}-squad-builder.md`.
|
|
88
|
+
1. Look for `[YOUR_OUTPUT_DIR]/{season}/gw{N}-squad-builder.md`.
|
|
86
89
|
- Not found → `squad_builder_result = "rederive"`, `squad_builder_reason = "file-missing"`. Done.
|
|
87
90
|
2. Parse the file's YAML frontmatter. Required fields: `mode`, `gameweek`.
|
|
88
91
|
- Missing or malformed → `squad_builder_result = "rederive"`, `squad_builder_reason = "frontmatter-malformed"`. Done.
|
|
@@ -103,7 +106,7 @@ Locate a matching squad-builder output file and extract the Classic Squad block
|
|
|
103
106
|
5. Call the extraction helper:
|
|
104
107
|
|
|
105
108
|
```bash
|
|
106
|
-
python3 "${CLAUDE_SKILL_DIR}/scripts/extract_classic_squad.py" --file "[YOUR_OUTPUT_DIR]/gw{N}-squad-builder.md"
|
|
109
|
+
python3 "${CLAUDE_SKILL_DIR}/scripts/extract_classic_squad.py" --file "[YOUR_OUTPUT_DIR]/{season}/gw{N}-squad-builder.md"
|
|
107
110
|
```
|
|
108
111
|
|
|
109
112
|
Parse stdout as JSON regardless of exit code. If JSON parse fails, treat as extraction-failed with a generic error message.
|
|
@@ -200,7 +203,60 @@ fpl stats -p DEF -s clean_sheets --min-minutes 450 -n 10 --available-only --form
|
|
|
200
203
|
|
|
201
204
|
Store each result under a distinct key (e.g. `stats_form`, `stats_transfer_momentum`, `stats_mid_xgi`, `stats_fwd_xgi`, `stats_def_clean_sheets`) and inline them into Phase C prompts as labelled sections.
|
|
202
205
|
|
|
203
|
-
|
|
206
|
+
### B9 -- Season Preview Intel
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
fpl intel --format json
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Hand-curated pre-season notes on minutes, injuries, role and set-piece duty. Optional: most setups
|
|
213
|
+
have none, and every downstream step is unchanged when there is nothing to read.
|
|
214
|
+
|
|
215
|
+
**This is an early-season source by design.** Each section expires at the point real data
|
|
216
|
+
supersedes it -- projected XIs once actual minutes exist, everything eventually. Do not assume the
|
|
217
|
+
schedule: the response's `metadata.decay_schedule` carries the live expiry table and
|
|
218
|
+
`metadata.sections_live` what still counts at this gameweek. Once `sections_live` is empty, expect
|
|
219
|
+
an empty payload -- that is the decay working, not a failure. Its value is concentrated in the
|
|
220
|
+
opening gameweeks, when `starting_xi.py` and `bench_order.py` are ranking players who have not
|
|
221
|
+
played yet.
|
|
222
|
+
|
|
223
|
+
Read `metadata.coverage.usable_as` and store it as `intel_gate`:
|
|
224
|
+
|
|
225
|
+
| `intel_gate` | What sub-agents may do with intel |
|
|
226
|
+
|---|---|
|
|
227
|
+
| `full` | Support **or** oppose a pick |
|
|
228
|
+
| `negative_filter_only` | Only downgrade: injuries, rotation risk, "not nailed on". Never promote. |
|
|
229
|
+
| `none` | Ignore entirely; omit the intel block from every Phase C prompt |
|
|
230
|
+
|
|
231
|
+
With partial coverage the written-up teams carry annotations and the rest carry nothing, so absence
|
|
232
|
+
of a flag would read as absence of merit. Store the payload as `intel` for Phase C.
|
|
233
|
+
|
|
234
|
+
### B10 -- Injury Returnee Radar
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
fpl returnees --enrich --format json
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Flagged players -- injured, suspended, unavailable, doubtful -- whose expected return lands inside
|
|
241
|
+
`metadata.window` gameweeks and who clear the radar's quality bar. Each entry in `data.entries`
|
|
242
|
+
carries the return estimate and where it came from (`expected_return`, `return_gameweek`,
|
|
243
|
+
`return_source`, `escalation_basis`), a quality verdict (`quality.passed`, `quality.meets_stash`)
|
|
244
|
+
and what moved since the previous run (`transition`). `data.departures` says who left the
|
|
245
|
+
watchlist and why.
|
|
246
|
+
|
|
247
|
+
`--enrich` searches the web for fresher return timing on the players FPL's own news field is silent
|
|
248
|
+
or stale about, which is what supplies a date for the injured majority. It needs a Perplexity API
|
|
249
|
+
key; without one the command skips enrichment, records why in `metadata.enrichment_note` and still
|
|
250
|
+
returns the FPL-sourced watchlist -- so this step is never a reason to abort the run.
|
|
251
|
+
|
|
252
|
+
Store the payload as `returnee_radar` and inline it into both Phase C prompts as a labelled
|
|
253
|
+
section. C1 renders it as an informational watchlist and is barred from naming its players in
|
|
254
|
+
transfer recommendations; C2 renders the subset still in the waiver pool and may escalate an entry
|
|
255
|
+
to a stash claim. The Returning Soon section quotes this payload, which is inlined into the prompt
|
|
256
|
+
like every other cited source -- so its numbers are grounded the same way every other cited number
|
|
257
|
+
is.
|
|
258
|
+
|
|
259
|
+
<!-- ADAPT: Add your own further supplementary data sources here. Examples:
|
|
204
260
|
- `fpl preview --save --scout` generates a GW preview with fixture analysis and scout insights.
|
|
205
261
|
Read the saved file and inject its content into Phase C sub-agents as additional context.
|
|
206
262
|
- Newsletter extracts (e.g. community tips, model projections) saved as markdown files
|
|
@@ -252,7 +308,19 @@ Branch on `squad_builder_result` (set in Phase A3; unset on transfer weeks):
|
|
|
252
308
|
> - Chip timing: {B6 output}
|
|
253
309
|
> - Stats: {stats_form}, {stats_transfer_momentum}, {stats_mid_xgi}, {stats_fwd_xgi}, {stats_def_clean_sheets} (from B8)
|
|
254
310
|
>
|
|
255
|
-
>
|
|
311
|
+
> - Preview intel: {intel} (from B9 - omit this line entirely when `intel_gate` is `none`)
|
|
312
|
+
> Gate: {intel_gate}. Governs **minutes and role only**, never how good a player is. Attribute it
|
|
313
|
+
> ("Transfer Flow projects him starting"), never assert it. Under `negative_filter_only` use it
|
|
314
|
+
> only to downgrade. A player with no intel is not a worse player.
|
|
315
|
+
>
|
|
316
|
+
> - Returning soon: {returnee_radar} (from B10)
|
|
317
|
+
> **Informational only.** Render it as the Returning Soon section of the Classic output template,
|
|
318
|
+
> one row per entry in `data.entries`, quoting only fields present in that payload. The
|
|
319
|
+
> injury/suspension rule in the analysis rules above governs what may be recommended while a
|
|
320
|
+
> player is flagged, and its classic branch is what bars transfer recommendations -- inline
|
|
321
|
+
> late-change swaps included -- from naming a tracked returnee. Do not restate or relax it here.
|
|
322
|
+
>
|
|
323
|
+
> <!-- ADAPT: Add your own further supplementary data sources here (newsletters, external reports) -->
|
|
256
324
|
>
|
|
257
325
|
> **Embedded Classic Squad (from squad-builder — insert this as the `### Classic Squad` section):**
|
|
258
326
|
>
|
|
@@ -262,11 +330,11 @@ Branch on `squad_builder_result` (set in Phase A3; unset on transfer weeks):
|
|
|
262
330
|
>
|
|
263
331
|
> Default: insert the embedded `### Classic Squad` block above **verbatim** as the Classic Squad section of the recommendations file. This is the expected path for nearly every embed-mode run.
|
|
264
332
|
>
|
|
265
|
-
> Late-changes path (use only when clearly warranted): if Phase B data reveals a material change squad-builder could not have seen (a starter ruled out after the file was written, an injury confirmed, a price move materially shifting affordability), you may apply a swap inline. To apply a swap: replace the relevant Starting XI or Bench row, update Captain/Vice if affected, adjust the Budget table (subtract OUT price, add IN price, update Total and Remaining) and Team Exposure table accordingly. Immediately after the block's `#### Alternatives` section, append a blockquote note: `> Late change: {OUT name} → {IN name} — {one-line reason, named source e.g. "ruled out per Thursday presser"}`. One note per swap. **Default is verbatim pass-through. Only deviate for a specific named reason. Never rewrite tables to "improve" formatting or fix perceived typos in squad-builder's output.**
|
|
333
|
+
> Late-changes path (use only when clearly warranted): if Phase B data reveals a material change squad-builder could not have seen (a starter ruled out after the file was written, an injury confirmed, a price move materially shifting affordability), you may apply a swap inline. To apply a swap: replace the relevant Starting XI or Bench row, update Captain/Vice if affected, adjust the Budget table (subtract OUT price, add IN price, update Total and Remaining) and Team Exposure table accordingly. Immediately after the block's `#### Alternatives` section, append a blockquote note: `> Late change: {OUT name} → {IN name} — {one-line reason, named source e.g. "ruled out per Thursday presser"}`. One note per swap. **Default is verbatim pass-through. Only deviate for a specific named reason. Never rewrite tables to "improve" formatting or fix perceived typos in squad-builder's output, and never fold an annotation (formation, notes) into a heading line — if squad-builder wrote `#### Starting XI`, keep the heading exactly as `#### Starting XI`; the formation belongs only on the `**Formation:**` line beneath it.**
|
|
266
334
|
>
|
|
267
335
|
> For Phase C2.5 (`transfer_eval.py`): on embed mode, the OUT-candidate pool is the 15 players in the Player column of the embedded Starting XI and Bench tables (not the current `fpl squad grid`). Use this to evaluate whether any late-breaking swaps are justified.
|
|
268
336
|
>
|
|
269
|
-
> **Sections to produce:** Chip Timing (from B6), Momentum Alerts (from B5/B8), pFDR Overview (from B1), and the `### Classic Squad` block (embedded verbatim or swap-edited with trailing note). **Suppress:** Captain Pick top-3 table (captain is inside the embedded block), standalone Bench Order section (bench order is inside the embedded block), and Transfer Recommendations section (any swaps are applied inline in the block).
|
|
337
|
+
> **Sections to produce:** Chip Timing (from B6), Momentum Alerts (from B5/B8), Returning Soon (from B10), pFDR Overview (from B1), and the `### Classic Squad` block (embedded verbatim or swap-edited with trailing note). **Suppress:** Captain Pick top-3 table (captain is inside the embedded block), standalone Bench Order section (bench order is inside the embedded block), and Transfer Recommendations section (any swaps are applied inline in the block).
|
|
270
338
|
>
|
|
271
339
|
> **User workflow note:** The `### Classic Squad` block is the final 15-player squad the user should enter into FPL. If a trailing `> Late change:` note is present, it explains the swap — the user can revert it in the FPL site before saving if they disagree.
|
|
272
340
|
>
|
|
@@ -284,7 +352,7 @@ Branch on `squad_builder_result` (set in Phase A3; unset on transfer weeks):
|
|
|
284
352
|
Before dispatching, print the in-chat warning (variant by `squad_builder_reason`):
|
|
285
353
|
|
|
286
354
|
**Variant A** (`squad_builder_reason == "file-missing"`):
|
|
287
|
-
> ⚠️ **Wildcard/Free Hit detected for GW{N}, but no squad-builder file was found.** Expected `gw{N}-squad-builder.md` in `[YOUR_OUTPUT_DIR]`. Re-derivation will run (weaker squad selection). To use squad-builder output, run `/squad-builder --{wildcard|freehit}` first, then re-run `/gw-prep`.
|
|
355
|
+
> ⚠️ **Wildcard/Free Hit detected for GW{N}, but no squad-builder file was found.** Expected `gw{N}-squad-builder.md` in `[YOUR_OUTPUT_DIR]/{season}`. Re-derivation will run (weaker squad selection). To use squad-builder output, run `/squad-builder --{wildcard|freehit}` first, then re-run `/gw-prep`.
|
|
288
356
|
|
|
289
357
|
**Variant B** (`squad_builder_reason ∈ {"gameweek-mismatch", "mode-mismatch"}`):
|
|
290
358
|
> ⚠️ **Squad-builder file found but does not match this run.** Found `gw{N}-squad-builder.md` with `mode: {file.mode}` / `gameweek: {file.gameweek}`. Expected mode `{active_chip}` / gameweek `{N}`. Re-derivation will run. To use squad-builder output, run `/squad-builder --{wildcard|freehit}` for GW{N}, then re-run `/gw-prep`.
|
|
@@ -318,7 +386,19 @@ Proceed immediately (non-interactive).
|
|
|
318
386
|
> - Chip timing: {B6 output}
|
|
319
387
|
> - Stats: {stats_form}, {stats_transfer_momentum}, {stats_mid_xgi}, {stats_fwd_xgi}, {stats_def_clean_sheets} (from B8)
|
|
320
388
|
>
|
|
321
|
-
>
|
|
389
|
+
> - Preview intel: {intel} (from B9 - omit this line entirely when `intel_gate` is `none`)
|
|
390
|
+
> Gate: {intel_gate}. Governs **minutes and role only**, never how good a player is. Attribute it
|
|
391
|
+
> ("Transfer Flow projects him starting"), never assert it. Under `negative_filter_only` use it
|
|
392
|
+
> only to downgrade. A player with no intel is not a worse player.
|
|
393
|
+
>
|
|
394
|
+
> - Returning soon: {returnee_radar} (from B10)
|
|
395
|
+
> **Informational only.** Render it as the Returning Soon section of the Classic output template,
|
|
396
|
+
> one row per entry in `data.entries`, quoting only fields present in that payload. The
|
|
397
|
+
> injury/suspension rule in the analysis rules above governs what may be recommended while a
|
|
398
|
+
> player is flagged, and its classic branch is what bars transfer recommendations -- inline
|
|
399
|
+
> late-change swaps included -- from naming a tracked returnee. Do not restate or relax it here.
|
|
400
|
+
>
|
|
401
|
+
> <!-- ADAPT: Add your own further supplementary data sources here (newsletters, external reports) -->
|
|
322
402
|
>
|
|
323
403
|
> Apply squad-builder rules from `references/rules.md` for full squad selection. Prepend the fallback banner (Variant A/B/C — see `references/output-template.md` for exact wording) on the line immediately before the Classic section heading in the output file. Do not include `squad_builder_mode` in the frontmatter — the squad was re-derived, not embedded from squad-builder.
|
|
324
404
|
>
|
|
@@ -350,7 +430,13 @@ Proceed immediately (non-interactive).
|
|
|
350
430
|
> - Squad: {B4 output}
|
|
351
431
|
> - Price movements: {B5 output}
|
|
352
432
|
> - Chip timing: {B6 output}
|
|
353
|
-
> - Stats: {stats_form}, {stats_transfer_momentum}, {stats_mid_xgi}, {stats_fwd_xgi}, {stats_def_clean_sheets} (from B8)
|
|
433
|
+
> - Stats: {stats_form}, {stats_transfer_momentum}, {stats_mid_xgi}, {stats_fwd_xgi}, {stats_def_clean_sheets} (from B8)>
|
|
434
|
+
> - Returning soon: {returnee_radar} (from B10)
|
|
435
|
+
> **Informational only.** Render it as the Returning Soon section of the Classic output template,
|
|
436
|
+
> one row per entry in `data.entries`, quoting only fields present in that payload. The
|
|
437
|
+
> injury/suspension rule in the analysis rules above governs what may be recommended while a
|
|
438
|
+
> player is flagged, and its classic branch is what bars transfer recommendations -- inline
|
|
439
|
+
> late-change swaps included -- from naming a tracked returnee. Do not restate or relax it here.
|
|
354
440
|
>
|
|
355
441
|
> **Bench Boost instructions:**
|
|
356
442
|
>
|
|
@@ -390,7 +476,19 @@ Proceed immediately (non-interactive).
|
|
|
390
476
|
> - Chip timing: {B6 output}
|
|
391
477
|
> - Stats: {stats_form}, {stats_transfer_momentum}, {stats_mid_xgi}, {stats_fwd_xgi}, {stats_def_clean_sheets} (from B8)
|
|
392
478
|
>
|
|
393
|
-
>
|
|
479
|
+
> - Preview intel: {intel} (from B9 - omit this line entirely when `intel_gate` is `none`)
|
|
480
|
+
> Gate: {intel_gate}. Governs **minutes and role only**, never how good a player is. Attribute it
|
|
481
|
+
> ("Transfer Flow projects him starting"), never assert it. Under `negative_filter_only` use it
|
|
482
|
+
> only to downgrade. A player with no intel is not a worse player.
|
|
483
|
+
>
|
|
484
|
+
> - Returning soon: {returnee_radar} (from B10)
|
|
485
|
+
> **Informational only.** Render it as the Returning Soon section of the Classic output template,
|
|
486
|
+
> one row per entry in `data.entries`, quoting only fields present in that payload. The
|
|
487
|
+
> injury/suspension rule in the analysis rules above governs what may be recommended while a
|
|
488
|
+
> player is flagged, and its classic branch is what bars transfer recommendations -- inline
|
|
489
|
+
> late-change swaps included -- from naming a tracked returnee. Do not restate or relax it here.
|
|
490
|
+
>
|
|
491
|
+
> <!-- ADAPT: Add your own further supplementary data sources here (newsletters, external reports) -->
|
|
394
492
|
>
|
|
395
493
|
> Produce the **Classic** section of the output template.
|
|
396
494
|
|
|
@@ -417,11 +515,50 @@ Proceed immediately (non-interactive).
|
|
|
417
515
|
>
|
|
418
516
|
> **WAIVER POOL IS AUTHORITATIVE:** `fpl waivers` output is the only source for available players. All other data (stats, form tables, squad context) is for analysis only. Never recommend a claim not present in the waivers output — Phase D1 will flag pool misses as a warning. Cross-position recommendations (e.g. dropping a MID to claim a DEF) are structurally illegal and will be blocked by Phase D1.
|
|
419
517
|
>
|
|
518
|
+
> **`data.pool` is an availability roster, not a shortlist.** It lists every unowned player in the league — one `{id, player_name, position, team_short}` row each, unranked and untruncated — so membership answers only "may this player be claimed at all". Ranked claims come from `data.top_targets` and `data.targets_by_position`; presence in `data.pool` is never on its own a reason to recommend someone. The single claim allowed to rest on pool membership alone is a stash claim for a tracked returnee, which the waiver scoring suppresses by design and which therefore cannot reach the ranked targets.
|
|
519
|
+
>
|
|
420
520
|
> - Waivers: {B3 output}
|
|
421
521
|
> - Squad: {B4 output}
|
|
422
522
|
> - Stats: {stats_form}, {stats_transfer_momentum}, {stats_mid_xgi}, {stats_fwd_xgi}, {stats_def_clean_sheets} (from B8)
|
|
423
523
|
>
|
|
424
|
-
>
|
|
524
|
+
> - Preview intel: {intel} (from B9 - omit this line entirely when `intel_gate` is `none`)
|
|
525
|
+
> Gate: {intel_gate}. Governs **minutes and role only**, never how good a player is. Attribute it
|
|
526
|
+
> ("Transfer Flow projects him starting"), never assert it. Under `negative_filter_only` use it
|
|
527
|
+
> only to downgrade. A player with no intel is not a worse player.
|
|
528
|
+
>
|
|
529
|
+
> - Returning soon: {returnee_radar} (from B10)
|
|
530
|
+
> Render the Returning Soon section of the Draft output template from this payload, restricted to
|
|
531
|
+
> tracked returnees whose `id` appears in the waivers `data.pool` list. A returnee missing from
|
|
532
|
+
> the pool is already owned by a rival and is not actionable — leave it out rather than listing it
|
|
533
|
+
> as unavailable. Quote only fields present in this payload.
|
|
534
|
+
>
|
|
535
|
+
> **STASH CLAIMS:** a Returning Soon row escalates into the Waiver Recommendations table only when
|
|
536
|
+
> **all four** gates below hold. Any one failing means watchlist only — no claim.
|
|
537
|
+
>
|
|
538
|
+
> 1. **Elite by prior:** `quality.meets_stash` is `true`.
|
|
539
|
+
> 2. **Returning soon enough:** `escalation_eligible` is `true`. The command has already applied
|
|
540
|
+
> `metadata.escalation_window` and the citation gate, so do not re-derive the timing yourself:
|
|
541
|
+
> an enrichment date counts here only when it arrived cited, and `escalation_basis` names which
|
|
542
|
+
> source the verdict rests on (`fpl-news` or `ai-search`).
|
|
543
|
+
> 3. **Claimable and position-for-position:** the returnee's `id` is in the waivers `data.pool`, and
|
|
544
|
+
> the player dropped for them plays the returnee's own position.
|
|
545
|
+
> 4. **Beats the incumbent by the configured margin:** take the drop candidate your squad analysis
|
|
546
|
+
> already ranks lowest at that position, run C2.5's `transfer_eval.py --out "{that player}"
|
|
547
|
+
> --in "{returnee}"`, and require `outlook_delta` to exceed the radar's
|
|
548
|
+
> `metadata.stash_upgrade_margin`, which already carries the effective configured value; both
|
|
549
|
+
> are quality points on the same 0-100 scale. If the script errors, or the margin is missing
|
|
550
|
+
> from the metadata, or the delta does not clear it, do not escalate. A drop-priority ordering
|
|
551
|
+
> always yields a lowest-ranked player and so can never answer "no" — the margin is what makes
|
|
552
|
+
> this gate refusable.
|
|
553
|
+
>
|
|
554
|
+
> Write every stash claim as a stash, never as a straight upgrade: it spends a roster slot until the
|
|
555
|
+
> player is fit again, and it is bought to lock the asset before a rival can claim them. Each stash
|
|
556
|
+
> row's Rationale must carry the expected return (`expected_return`, or `return_gameweek` where the
|
|
557
|
+
> date is unknown) and name the provenance of that date from `escalation_basis`. The
|
|
558
|
+
> injury/suspension rule in the analysis rules above is the single authority on what may be
|
|
559
|
+
> recommended while a player is flagged.
|
|
560
|
+
>
|
|
561
|
+
> <!-- ADAPT: Add your own further supplementary data sources here (newsletters, external reports) -->
|
|
425
562
|
>
|
|
426
563
|
> Additionally enforce: every waiver swap must be position-for-position (MID out → MID in, DEF out → DEF in, etc.). Cross-position swaps are illegal under FPL Draft rules.
|
|
427
564
|
>
|
|
@@ -435,7 +572,7 @@ After each sub-agent identifies OUT candidates and an IN shortlist (from squad a
|
|
|
435
572
|
python3 "${CLAUDE_SKILL_DIR}/scripts/transfer_eval.py" --out "{out_player_name}" --in "{comma-separated IN candidate names}"
|
|
436
573
|
```
|
|
437
574
|
|
|
438
|
-
The script outputs JSON with Outlook (multi-GW quality) and This GW (lineup impact) deltas for each IN candidate vs the OUT player. Use these scores as the quantitative baseline for transfer/waiver recommendations. Sub-agents may override with qualitative reasons (press conference intel, newsletter signals) using the same `⚡ Override: {reason}` pattern as starting XI overrides.
|
|
575
|
+
The script outputs JSON with Outlook (multi-GW quality) and This GW (lineup impact) deltas for each IN candidate vs the OUT player. Use these scores as the quantitative baseline for transfer/waiver recommendations. Sub-agents may override with qualitative reasons (press conference intel, newsletter signals, season preview intel from B9) using the same `⚡ Override: {reason}` pattern as starting XI overrides. Name the source in the reason.
|
|
439
576
|
|
|
440
577
|
If the script fails (exit 1), fall back to LLM-driven transfer reasoning and note the failure.
|
|
441
578
|
|
|
@@ -449,7 +586,9 @@ python3 "${CLAUDE_SKILL_DIR}/scripts/starting_xi.py" --squad "{comma-separated 1
|
|
|
449
586
|
|
|
450
587
|
<!-- ADAPT: Replace with your squad player names from the squad grid output -->
|
|
451
588
|
|
|
452
|
-
Use the script's recommended XI as the default lineup. Sub-agents may override specific picks with stated qualitative reasons (press conference intel, newsletter signals, rotation predictions). Mark any overrides with `⚡ Override: {reason}` in the output. If the script fails (exit 1), fall back to manual selection and note the failure.
|
|
589
|
+
Use the script's recommended XI as the default lineup. Sub-agents may override specific picks with stated qualitative reasons (press conference intel, newsletter signals, rotation predictions, season preview intel from B9). Mark any overrides with `⚡ Override: {reason}` in the output, naming the source. If the script fails (exit 1), fall back to manual selection and note the failure.
|
|
590
|
+
|
|
591
|
+
**Preview intel is at its most useful here in GW1-3**, when the lineup engine is ranking players with no minutes on the board and a projected XI is the only nailed-on signal available. It feeds this override channel deliberately rather than the scoring inside `starting_xi.py`: an override is visible and attributed in the output, whereas a scoring input would move picks invisibly. Respect `intel_gate` -- under `negative_filter_only`, intel may bench a player but never promote one into the XI.
|
|
453
592
|
|
|
454
593
|
### C4 -- Bench Ordering (skip if `squad_builder_result == "embed"` OR `mode == "benchboost"` — embed has bench order inside block, bench boost has no bench ordering)
|
|
455
594
|
|
|
@@ -467,8 +606,8 @@ Incorporate the bench ordering output into the relevant sections of each sub-age
|
|
|
467
606
|
|
|
468
607
|
Combine the outputs from whichever sub-agents were dispatched into a single recommendations file. If only one format is active, the file contains only that format's section.
|
|
469
608
|
|
|
470
|
-
<!-- ADAPT: Set your output directory -->
|
|
471
|
-
**Output path:** `[YOUR_OUTPUT_DIR]/gw{N}-recommendations.md`
|
|
609
|
+
<!-- ADAPT: Set your output directory. Keep the `/{season}/` segment -- it is what stops a new season overwriting the last one's reports. -->
|
|
610
|
+
**Output path:** `[YOUR_OUTPUT_DIR]/{season}/gw{N}-recommendations.md`
|
|
472
611
|
|
|
473
612
|
The file should follow the structure defined in `references/output-template.md`, with both Classic and Draft sections populated.
|
|
474
613
|
|
|
@@ -492,7 +631,7 @@ _Runs after Phase D file write, before Phase E. Not embed-gated._
|
|
|
492
631
|
|
|
493
632
|
```bash
|
|
494
633
|
cd "$FPL_CLI_DIR" && source .venv/bin/activate && python "$FPL_CLI_DIR/.agents/skills/gw-prep/scripts/validate_draft_waivers.py" \
|
|
495
|
-
--recommendations-file "[YOUR_OUTPUT_DIR]/gw{N}-recommendations.md" \
|
|
634
|
+
--recommendations-file "[YOUR_OUTPUT_DIR]/{season}/gw{N}-recommendations.md" \
|
|
496
635
|
--waivers-json /tmp/gw-prep-waivers-{N}.json \
|
|
497
636
|
--squad-grid-json /tmp/gw-prep-squad-grid-{N}.json
|
|
498
637
|
```
|
|
@@ -537,7 +676,7 @@ _Skip unless `squad_builder_result == "embed"`. Transfer and rederive runs do no
|
|
|
537
676
|
1. Run:
|
|
538
677
|
|
|
539
678
|
```bash
|
|
540
|
-
python3 "${CLAUDE_SKILL_DIR}/scripts/extract_classic_squad.py" --from-recommendations --file "[YOUR_OUTPUT_DIR]/gw{N}-recommendations.md"
|
|
679
|
+
python3 "${CLAUDE_SKILL_DIR}/scripts/extract_classic_squad.py" --from-recommendations --file "[YOUR_OUTPUT_DIR]/{season}/gw{N}-recommendations.md"
|
|
541
680
|
```
|
|
542
681
|
|
|
543
682
|
Parse stdout as JSON regardless of exit code. If exit is non-zero → emit warning and proceed:
|