Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions .cursor/rules/python-poetry.mdc

This file was deleted.

35 changes: 35 additions & 0 deletions .cursor/rules/python-uv.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
description: Python 3.11 and uv workspace conventions
globs: **/*.py
alwaysApply: false
---

# Python and uv

- Runtime: **Python 3.11+** via uv (`pyproject.toml` workspace + `uv.lock`).
- Install: `uv sync --group dev` or `make install`.
- Run scripts: `uv run <script>` or `uv run python ...`
- Add dependencies on the owning member (`credit/pyproject.toml` or `investing/pyproject.toml`), then `uv lock` / `uv sync`. Do not pip-install into the global env.

## Style

- Prefer type hints on public functions.
- Short English docstrings for non-obvious business logic.
- Match existing module style when extending code.

## Libraries

Use dependencies declared in the relevant member `pyproject.toml` (pandas, yfinance, etc.) as directed by the **feature spec**, not by default habit.

## Financial domain

- **No look-ahead bias:** only data available on or before the decision `as_of_date`.
- Document `as_of_date`, data sources, and formula versions in the feature spec when adding metrics.

## Tooling

No project-wide tests or linter unless configured in root `pyproject.toml`. Do not add heavy CI scaffolding unless requested.

## Network

`yfinance` and external APIs require network access; handle failures explicitly in implementation specs.
2 changes: 1 addition & 1 deletion .cursor/skills/commit-split/CONVENTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ feat(universe): filter banks via SIC codes

fix(scores): exclude rows with EV <= 0 from EY rank

build: bump pandas in poetry lockfile
build: bump pandas in uv lockfile
```

## Merge / revert (do not rewrite)
Expand Down
12 changes: 6 additions & 6 deletions .cursor/skills/commit-split/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,13 @@ make lint # ruff check + format --check (must exit 0)
make test # pytest with coverage (must exit 0)
```

If `make` is unavailable, use the equivalent Poetry targets from the repo `Makefile`:
If `make` is unavailable, use the equivalent uv targets from the repo `Makefile`:

```bash
poetry run ruff format .
poetry run ruff check .
poetry run ruff format --check .
poetry run pytest --cov=smartwealthai --cov-report=term-missing
uv run ruff format .
uv run ruff check .
uv run ruff format --check .
uv run pytest --cov=investing --cov=credit --cov-report=term-missing
```

### When format changes the working tree
Expand Down Expand Up @@ -165,7 +165,7 @@ git status

## Dependency files

`pyproject.toml` and `poetry.lock` are **tracked** (not in `.gitignore`). When they change, prefer a dedicated `build:` or `chore:` commit unless the user folds them into another approved row.
`pyproject.toml` and `uv.lock` are **tracked** (not in `.gitignore`). When they change, prefer a dedicated `build:` or `chore:` commit unless the user folds them into another approved row.

## Safety

Expand Down
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
}
}
},
"postCreateCommand": "pipx install poetry && poetry config virtualenvs.in-project true && poetry install && bash .devcontainer/install-env-hook.sh",
"postCreateCommand": "curl -LsSf https://astral.sh/uv/install.sh | sh && export PATH=\"$HOME/.local/bin:$PATH\" && uv sync --group dev && bash .devcontainer/install-env-hook.sh",
"remoteEnv": {
"SIMFIN_API_KEY": "${localEnv:SIMFIN_API_KEY}"
}
Expand Down
11 changes: 3 additions & 8 deletions .github/workflows/pr-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,11 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
python-version: "3.11"

- name: Install Poetry
uses: snok/install-poetry@76e04a911780d5b312d89783f7b1cd627778900a
with:
virtualenvs-in-project: true

- name: Install dependencies
run: make install

Expand All @@ -40,7 +35,7 @@ jobs:
- name: Test with coverage
# Match [tool.coverage.run]: both packages + branch=true (mixing CLI
# statement-only --cov with pyproject branch data fails combine).
run: poetry run pytest --cov=investing --cov=credit --cov-branch --cov-report=term-missing --cov-report=xml
run: uv run pytest --cov=investing --cov=credit --cov-branch --cov-report=term-missing --cov-report=xml

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI sync does not freeze lock

Low Severity

PR CI installs and runs via uv sync / uv run without --frozen or --locked, while credit Docker images use uv sync --frozen. If uv.lock drifts from the member pyproject.toml files, CI can re-resolve and stay green while Docker builds fail, or tests can run a different graph than the images.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0c75e56. Configure here.


- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
Expand Down
23 changes: 12 additions & 11 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,25 +51,26 @@ Write all code, comments, docstrings, documentation, commits, and PR text in **E

## Runtime

- **Python:** 3.11+ (`requires-python = "^3.11"` in `pyproject.toml`)
- **Dependencies:** Poetry
- **Python:** 3.11+ (`requires-python = ">=3.11,<4.0"` in root `pyproject.toml`)
- **Dependencies:** uv workspace (`uv sync --frozen --group dev` / `make install`); members `credit` + `investing` ([ADR-0005](docs/adr/0005-poetry-to-uv-workspace.md)). CI and `make install` use `--frozen` so installs match `uv.lock`.

```bash
poetry env use python3.11
poetry install
poetry run pytest
uv sync --frozen --group dev
uv run pytest
```

### MLflow (demo pipeline runs)

`mlflow-skinny` is a Poetry dependency (`poetry install` is enough for logging). No local MLflow UI server is required for #61.
`mlflow-skinny` is a uv dependency (`uv sync` is enough for logging). No local MLflow UI server is required for #61.

```bash
export MLFLOW_TRACKING_URI="file://$(pwd)/mlruns" # default if unset
export MLFLOW_ALLOW_FILE_STORE=true # required for file:// with MLflow 3.14+ (set automatically by score-universe)
# Usually do NOT export — code defaults to file://$(pwd)/mlruns.
# When you do export, expand pwd on the current machine (never hardcode /workspaces/...):
export MLFLOW_TRACKING_URI="file://$(pwd)/mlruns"
export MLFLOW_ALLOW_FILE_STORE=true # required for file:// with MLflow 3.14+ (set automatically by score-universe)
```

Logged by `score-universe` after ranking/portfolio construction ([#61](https://github.com/JLaborda/SmartWealthAI/issues/61)).
Logged by `score-universe` after ranking/portfolio construction ([#61](https://github.com/JLaborda/SmartWealthAI/issues/61)). After switching Dev Container ↔ Mac host, if MLflow hits a read-only `/workspaces` path: first `unset MLFLOW_TRACKING_URI` (or set it to `file://$(pwd)/mlruns`), and confirm the tracking URI points at a writable path under the repo (or your intended store). Prefer correcting the URI over deleting. Only if local `mlruns/` is clearly corrupted or still points at an unusable absolute `/workspaces` artifact location — and you accept losing those local runs — then remove or recreate that directory.

To view runs on a remote tracking server (e.g. EC2 Docker), set `MLFLOW_TRACKING_URI` to that server **before** `score-universe` and use a shared artifact store (e.g. S3). Local `mlruns/` are not visible to a remote server unless you log there at run time.

Expand All @@ -83,7 +84,7 @@ Active pipeline for the June 30 demo slice. Requires `SIMFIN_API_KEY` (never com

```bash
export SIMFIN_API_KEY="<from user secrets>"
poetry run download-simfin
uv run download-simfin
```

Spec: [`investing/docs/features/etl-data-lake.md`](investing/docs/features/etl-data-lake.md). Operator guide: [`investing/docs/guides/download-simfin.md`](investing/docs/guides/download-simfin.md). Delivery target: [`investing/docs/demo-slice.md`](investing/docs/demo-slice.md).
Expand All @@ -92,7 +93,7 @@ Spec: [`investing/docs/features/etl-data-lake.md`](investing/docs/features/etl-d

```bash
export SEC_IDENTITY="Your Name your@email.com"
poetry run download-fundamentals --universe dow30
uv run download-fundamentals --universe dow30
```

Guide: [`investing/docs/guides/download-fundamentals.md`](investing/docs/guides/download-fundamentals.md).
Expand Down
8 changes: 4 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ First public release: the **June 30 demo slice** — a runnable Greenblatt-style

### Requirements

- Python 3.11+, Poetry.
- Python 3.11+, uv.
- `SIMFIN_API_KEY` for live data download (see [download-simfin guide](docs/mvp/guides/download-simfin.md)).

### Quickstart

```bash
poetry install
uv sync
export SIMFIN_API_KEY="<your key>"
poetry run run-demo-pipeline --run-date 2026-06-18
poetry run run-dashboard --data-dir data --run-date 2026-06-18
uv run run-demo-pipeline --run-date 2026-06-18
uv run run-dashboard --data-dir data --run-date 2026-06-18
```

### Known gaps (phase 2)
Expand Down
2 changes: 1 addition & 1 deletion CONTEXT-MAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Top-level folders are **products/domains**, not technical layers:
| `fraud/` | Fraud detection (future — create when that module starts) |
| `platform/` | Shared infra (Terraform, AWS, shared API) — **only after** domain demos work locally |

**Packaging:** one Poetry project / one `poetry install`. Register `investing` and `credit` as packages (`investing/src`, `credit/src`) with PEP 621 scripts. Poetry→uv is a later isolated tooling PR (#182). Do not put a second `pyproject.toml` under domain folders in this phase.
**Packaging:** root uv workspace (`uv sync`); members `credit` + `investing` with PEP 621 scripts under `credit/src` and `investing/src` ([ADR-0005](docs/adr/0005-poetry-to-uv-workspace.md), #182). Lean per-domain deps: #183.

Do **not** put shared `ingest/`, `benchmarks/`, or `serving/` at the repo root as peers of domains.

Expand Down
14 changes: 7 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
.PHONY: install lint test download-fundamentals format platform-tf-check

install:
poetry install --with dev
uv sync --frozen --group dev

lint:
poetry run ruff check .
poetry run ruff format --check .
uv run ruff check .
uv run ruff format --check .

test:
poetry run pytest --cov=investing --cov=credit --cov-branch --cov-report=term-missing
uv run pytest --cov=investing --cov=credit --cov-branch --cov-report=term-missing

# Requires SEC_IDENTITY in the environment. See investing/docs/guides/download-fundamentals.md
download-fundamentals:
poetry run download-fundamentals --universe dow30
uv run download-fundamentals --universe dow30

# formatting command
format:
poetry run ruff format .
uv run ruff format .

# Terraform fmt + validate for credit CSS serve demo (no apply; no AWS creds required).
platform-tf-check:
cd platform/terraform/credit-css-serve-demo && terraform fmt -check -recursive && terraform init -backend=false -input=false && terraform validate
cd platform/terraform/credit-css-serve-demo && terraform fmt -check -recursive && terraform init -backend=false -input=false && terraform validate
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ Greenblatt-style ranking on US equities: SimFin → PIT lake → ROC + EY → to
### Quickstart (investing demo)

```bash
poetry install
uv sync
export SIMFIN_API_KEY="<from user secrets>"
poetry run run-demo-pipeline --run-date 2026-06-18
poetry run run-dashboard --data-dir data --run-date 2026-06-18
uv run run-demo-pipeline --run-date 2026-06-18
uv run run-dashboard --data-dir data --run-date 2026-06-18
```

See [`investing/README.md`](investing/) and [`investing/docs/demo-slice.md`](investing/docs/demo-slice.md).

### Tech stack (investing)

* **Language:** Python 3.11+ · **Deps:** Poetry (uv migration — #182)
* **Language:** Python 3.11+ · **Deps:** uv workspace ([ADR-0005](docs/adr/0005-poetry-to-uv-workspace.md))
* **Data:** SimFin bulk · **Libs:** pandas, simfin, yfinance, streamlit, mlflow-skinny

---
Expand All @@ -49,7 +49,7 @@ Application **CSS**: public demo data → application mart → scoring → rank
## Roadmap (portfolio)

1. **Credit** — chapter 6 OptBinning scorecard, monitoring, explainability (as scheduled).
2. **Tooling** — Poetry → uv workspace (#182) + domain deps / CI matrix (#183).
2. **Tooling** — Domain deps / CI matrix (#183) after uv workspace ([#182](https://github.com/JLaborda/SmartWealthAI/issues/182), [ADR-0005](docs/adr/0005-poetry-to-uv-workspace.md)).
3. **`platform/`** — Terraform / AWS; orchestrator choice open (Airflow vs EventBridge/ECS vs Prefect).
4. Optional: Spec Kit (#178); fraud module.

Expand Down
17 changes: 12 additions & 5 deletions credit/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,27 @@

FROM python:3.11-slim-bookworm

COPY --from=ghcr.io/astral-sh/uv:0.13.1 /uv /uvx /bin/

WORKDIR /app

# System deps for xgboost / scipy wheels when needed.
RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential \
&& rm -rf /var/lib/apt/lists/*

COPY pyproject.toml poetry.lock README.md ./
COPY src ./src
ENV UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy \
UV_NO_DEV=1

COPY pyproject.toml uv.lock README.md ./
COPY credit ./credit
# Workspace lockfile needs sibling member metadata present.
COPY investing/pyproject.toml investing/pyproject.toml

RUN uv sync --frozen --no-dev --package credit --no-editable

RUN pip install --no-cache-dir poetry \
&& poetry config virtualenvs.create false \
&& poetry install --only main --no-ansi --no-interaction
ENV PATH="/app/.venv/bin:$PATH"

# Default: batch score. Mount mart + artifact + output dir at runtime.
# See credit/README.md for a one-liner docker run.
Expand Down
17 changes: 11 additions & 6 deletions credit/Dockerfile.serve
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,26 @@

FROM python:3.11-slim-bookworm

COPY --from=ghcr.io/astral-sh/uv:0.13.1 /uv /uvx /bin/

WORKDIR /app

RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential \
&& rm -rf /var/lib/apt/lists/*

COPY pyproject.toml poetry.lock README.md ./
COPY src ./src
ENV UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy \
UV_NO_DEV=1

COPY pyproject.toml uv.lock README.md ./
COPY credit ./credit
COPY investing/pyproject.toml investing/pyproject.toml

RUN pip install --no-cache-dir poetry \
&& poetry config virtualenvs.create false \
&& poetry install --only main --no-ansi --no-interaction
RUN uv sync --frozen --no-dev --package credit --no-editable

ENV CREDIT_PIPELINE_ARTIFACT=/artifact/pipeline.joblib
ENV PATH="/app/.venv/bin:$PATH" \
CREDIT_PIPELINE_ARTIFACT=/artifact/pipeline.joblib
EXPOSE 8000

# Factory loads artifact from CREDIT_PIPELINE_ARTIFACT at startup.
Expand Down
17 changes: 11 additions & 6 deletions credit/Dockerfile.serve.demo
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,28 @@

FROM python:3.11-slim-bookworm

COPY --from=ghcr.io/astral-sh/uv:0.13.1 /uv /uvx /bin/

WORKDIR /app

RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential \
&& rm -rf /var/lib/apt/lists/*

COPY pyproject.toml poetry.lock README.md ./
COPY src ./src
ENV UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy \
UV_NO_DEV=1

COPY pyproject.toml uv.lock README.md ./
COPY credit ./credit
COPY investing/pyproject.toml investing/pyproject.toml

RUN pip install --no-cache-dir poetry \
&& poetry config virtualenvs.create false \
&& poetry install --only main --no-ansi --no-interaction
RUN uv sync --frozen --no-dev --package credit --no-editable

# Baked hermetic fit output (gitignored under credit/demo_artifact/).
COPY credit/demo_artifact/pipeline.joblib /artifact/pipeline.joblib
ENV CREDIT_PIPELINE_ARTIFACT=/artifact/pipeline.joblib
ENV PATH="/app/.venv/bin:$PATH" \
CREDIT_PIPELINE_ARTIFACT=/artifact/pipeline.joblib
EXPOSE 8000

CMD ["uvicorn", "credit.api:create_app", "--factory", "--host", "0.0.0.0", "--port", "8000"]
Loading
Loading