Metadata-Version: 2.4
Name: planfile
Version: 0.1.8
Summary: SDLC automation platform - strategic project management with CI/CD integration and automated bug-fix loops
Author-email: Tom Sapletta <tom@sapletta.com>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/wronai/strategy
Project-URL: Repository, https://github.com/wronai/strategy
Project-URL: Documentation, https://strategy.readthedocs.io
Keywords: sdlc,strategy,sprint,pm,jira,github,gitlab,tickets,agile,cicd,automation
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Office/Business :: Scheduling
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: typer>=0.12
Requires-Dist: rich>=13.0
Requires-Dist: pydantic>=2.0
Requires-Dist: pydantic-settings>=2.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: requests>=2.31
Provides-Extra: github
Requires-Dist: PyGithub>=2.0; extra == "github"
Provides-Extra: jira
Requires-Dist: jira>=3.5; extra == "jira"
Provides-Extra: gitlab
Requires-Dist: python-gitlab>=4.0; extra == "gitlab"
Provides-Extra: all
Requires-Dist: PyGithub>=2.0; extra == "all"
Requires-Dist: jira>=3.5; extra == "all"
Requires-Dist: python-gitlab>=4.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: black>=23.0; extra == "dev"
Requires-Dist: isort>=5.12; extra == "dev"
Dynamic: license-file

# strategy

<img src="https://r2cdn.perplexity.ai/pplx-full-logo-primary-dark%402x.png" style="height:64px;margin-right:32px"/>

# gdyby to by była osobna biblitoeka, to mozna byc zrobić integracje z github, jira, gitlab  iiinnymi integracjami dla zewnatrznych systemow ticketow, bez wzgledu na LLM i tools, dlatego zaprpoonuj nazwe i strukuiture takiej paczki

Świetne rozszerzenie! Można zrobić **osobny pakiet** jako „strategiczny layer” nad ticket‑systemami, który:

- opisuje **sprinty, strategie, quality‑gates** w `strategy.yaml`,
- tworzy / aktualizuje **tikety w Jira, GitHub, GitLab, Linear, ClickUp, …**,
- jest **neutranle** względem LLM i narzędzi (tj. LLM to tylko „input generator”, nie zależność runtime).

Poniżej zaproponuję **nazwę**, **strukturę pakietu** i **ogólny interfejs**.

***

## 1. Propozycja nazwy paczki

**`strategy`** – skrót od **sprint + strategy**

- inny rytm niż `llm`, `llx`, `agent` – jasne: to **strategiczny/PM layer**.
- można myśleć: `strategy` + `sprint`.

Alternatywy:

- `agilestrat`
- `planstrat`
- `taskflow`

Ale **`strategy`** jest najbardziej intuicyjne dla IT‑PM.

***

## 2. `strategy` – wysoki poziom funkcjonalności

Pakiet ma:

- modelować **strategie** i **sprinty** w YAML (`strategy.yaml`),
- mieć **integrations** dla:
    - Jira
    - GitHub Issues
    - GitLab Issues
    - ClickUp / Linear (opcjonalnie)
- dostarczać CLI i API:
    - `strategy apply --strategy=... --project-path=.`
    - `strategy review --strategy=... --project-path=.` (po wykonaniu).

Difference vs `llx`:

- `llx` − **LLM + routing + tools**
- `strategy` − **strategia + sprinty + tickets** (może być wywoływane przez `llx`, ale nie zależy od LLM).

***

## 3. Struktura pakietu `strategy`

```bash
strategy/
├── __init__.py
├── models.py                 # Pydantic Strategy + Ticket schemas
├── runner.py                 # apply / review / execution logic
├── cli/                      # CLI `strategy ...`
│   ├── __main__.py
│   └── commands.py
├── integrations/             # PM integrations
│   ├── base.py               # Base PM interface
│   ├── jira.py
│   ├── github.py
│   ├── gitlab.py
│   └── generic.py           # generic HTTP webhook / API
├── loaders/                  # YAML / JSON loading + validation
│   ├── yaml_loader.py       # Strategy.model_validate_yaml(...)
│   └── cli_loader.py
├── utils/                   # helpers (priority mapping, etc.)
│   ├── priorities.py
│   └── metrics.py
└── examples/
    ├── strategies/
    │   └── onboarding.yaml
    └── tasks/
        └── tasks.yaml
```


***

## 4. `models.py` – jądro schematu (uproszczone)

```python
from enum import Enum
from typing import List, Dict, Optional
from pydantic import BaseModel


class TaskType(str, Enum):
    feature = "feature"
    tech_debt = "tech_debt"
    bug = "bug"


class ModelTier(str, Enum):
    local = "local"
    cheap = "cheap"
    balanced = "balanced"
    premium = "premium"


class ModelHints(BaseModel):
    design: Optional[ModelTier] = None
    implementation: Optional[ModelTier] = None
    review: Optional[ModelTier] = None
    triage: Optional[ModelTier] = None


class TaskPattern(BaseModel):
    id: str
    type: TaskType
    title: str
    description: str
    priority: Optional[str] = None
    estimate: Optional[str] = None
    model_hints: ModelHints = ModelHints()


class Sprint(BaseModel):
    id: int
    name: str
    length_days: int
    objectives: List[str]


class Strategy(BaseModel):
    name: str
    project_type: str
    domain: str
    goal: str
    sprints: List[Sprint]
    tasks: Dict[str, List[TaskPattern]]
```

Za pomocą `pydantic-yaml`:

```python
from pydantic_yaml import YamlModel

class Strategy(YamlModel, Strategy):
    pass
```


***

## 5. `integrations/base.py` – wspólny interfejs

```python
from typing import Protocol, Optional

class TicketRef(BaseModel):
    id: str
    url: Optional[str] = None


class PMBackend(Protocol):
    def create_ticket(
        self,
        title: str,
        body: str,
        labels: list[str],
        priority: str,
        metadata: dict,
    ) -> TicketRef:
        ...

    def update_ticket(
        self,
        ticket_id: str,
        title: Optional[str] = None,
        body: Optional[str] = None,
        status: Optional[str] = None,
        labels: Optional[list[str]] = None,
    ) -> None:
        ...
```

Każdy `jira.py`, `github.py`, `gitlab.py` implementuje ten protokół.

***

## 6. `runner.py` – apply / review

```python
from strategy.models import Strategy, TaskPattern, Sprint
from strategy.integrations.base import PMBackend, TicketRef
from strategy.utils.metrics import analyze_project_metrics


def apply_strategy(
    strategy: Strategy,
    project_path: str,
    backends: Dict[str, PMBackend],
) -> Dict[str, TicketRef]:
    refs = {}
    for sprint in strategy.sprints:
        for task_pattern in strategy.tasks.get("patterns", []):
            for _ in range(1):  # lub N zależnie od heurystyki
                title = task_pattern.title
                body = task_pattern.description
                labels = task_pattern.type.value + [task_pattern.id]
                priority = task_pattern.priority or "medium"

                ref = backends["github"].create_ticket(
                    title=title,
                    body=body,
                    labels=labels,
                    priority=priority,
                    metadata={
                        "sprint": sprint.id,
                        "pattern": task_pattern.id,
                        "model_hints": task_pattern.model_hints.model_dump(),
                    },
                )
                refs[f"{sprint.id}-{task_pattern.id}"] = ref
    return refs


def review_strategy(
    strategy: Strategy,
    project_path: str,
    backends: Dict[str, PMBackend],
) -> dict:
    metrics = analyze_project_metrics(project_path)
    result = {"strategy": [], "metrics": []}
    # ... porównaj z strategy.metrics
    # ... sprawdź status wszystkich tiketów z backends
    return result
```


***

## 7. `cli/commands.py` – CLI

```python
import typer
from strategy.models import Strategy
from strategy.runner import apply_strategy, review_strategy
from strategy.integrations.jira import JiraBackend
from strategy.integrations.github import GitHubBackend

app = typer.Typer()

@app.command("apply")
def apply_strategy_cli(
    strategy_path: Path,
    project_path: Path,
):
    strategy = Strategy.model_validate_yaml(strategy_path.read_text())
    backends = {
        "github": GitHubBackend(
            repo="company/backend",
            token=os.environ["GITHUB_TOKEN"],
        ),
        "jira": JiraBackend(
            base_url="https://company.atlassian.net",
            email=os.environ["JIRA_EMAIL"],
            token=os.environ["JIRA_TOKEN"],
        ),
    }
    apply_strategy(strategy, project_path, backends)


@app.command("review")
def review_strategy_cli(
    strategy_path: Path,
    project_bonus_path: Path,
):
    strategy = Strategy.model_validate_yaml(strategy_path.read_text())
    backends = { ... }
    review_strategy(strategy, project_path, backends)
```


***

## 8. Jak `llx` integruje się z `strategy`

- `llx`:
    - generuje `strategy.yaml` i `tasks.yaml` z LLM,
    - zapisuje do pliku.
- `strategy`:
    - wczytuje `strategy.yaml` i `tasks.yaml` z walidacją,
    - wywołuje `apply_strategy` / `review_strategy`,
    - wraca wynik do `llx` (np. jako JSON statusu).

Flow:

```text
llm
└─ generuje YAML → llx
      ↓
      llx zapisuje → strategy.yaml + tasks.yaml
      ↓
      llx wywołuje: strategy apply --strategy=... --project-path=.
      ↓
      strategy: tworzy tickets w Jira/GitHub/GitLab
      ↓
      llx odczytuje status i zwraca podsumowanie użytkownikowi
```


***

## 9. Przykładowa instalacja / integracja

```bash
pip install llx strategy[all]  # lub llx[sprint] + separatne strategy

# w projekcie
llx run-strategy ...             # generuje strategy.yaml + tasks.yaml
strategy apply --strategy ./strategies/main.yaml .
```

Jeśli chcesz, mogę:

- rozpisać gotowy `strategy/setup.py` z `strategy[jira,github,gitlab]`,
- albo napisać minimalną `strategy/integrations/github.py` z `PyGithub`.

## License

Apache License 2.0 - see [LICENSE](LICENSE) for details.

## Author

Created by **Tom Sapletta** - [tom@sapletta.com](mailto:tom@sapletta.com)
