lgtmaybe 0.0.1__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.
Files changed (52) hide show
  1. lgtmaybe-0.0.1/.claude/settings.local.json +26 -0
  2. lgtmaybe-0.0.1/.env.development +0 -0
  3. lgtmaybe-0.0.1/.env.development.local +0 -0
  4. lgtmaybe-0.0.1/.env.local +0 -0
  5. lgtmaybe-0.0.1/.env.production +0 -0
  6. lgtmaybe-0.0.1/.env.production.local +0 -0
  7. lgtmaybe-0.0.1/.env.test +0 -0
  8. lgtmaybe-0.0.1/.env.test.local +0 -0
  9. lgtmaybe-0.0.1/.github/workflows/ci.yml +33 -0
  10. lgtmaybe-0.0.1/.gitignore +218 -0
  11. lgtmaybe-0.0.1/.gitmodules +0 -0
  12. lgtmaybe-0.0.1/.npmrc +0 -0
  13. lgtmaybe-0.0.1/.yarnrc +0 -0
  14. lgtmaybe-0.0.1/.yarnrc.yml +0 -0
  15. lgtmaybe-0.0.1/CLAUDE.md +100 -0
  16. lgtmaybe-0.0.1/Dockerfile +13 -0
  17. lgtmaybe-0.0.1/LICENSE +21 -0
  18. lgtmaybe-0.0.1/PKG-INFO +33 -0
  19. lgtmaybe-0.0.1/README.md +21 -0
  20. lgtmaybe-0.0.1/bunfig.toml +0 -0
  21. lgtmaybe-0.0.1/manual-steps.md +53 -0
  22. lgtmaybe-0.0.1/package-lock.json +0 -0
  23. lgtmaybe-0.0.1/package.json +0 -0
  24. lgtmaybe-0.0.1/pnpm-lock.yaml +0 -0
  25. lgtmaybe-0.0.1/pyproject.toml +46 -0
  26. lgtmaybe-0.0.1/src/lgtmaybe/__init__.py +3 -0
  27. lgtmaybe-0.0.1/src/lgtmaybe/__main__.py +20 -0
  28. lgtmaybe-0.0.1/src/lgtmaybe/cli/__init__.py +1 -0
  29. lgtmaybe-0.0.1/src/lgtmaybe/config/__init__.py +1 -0
  30. lgtmaybe-0.0.1/src/lgtmaybe/core/__init__.py +1 -0
  31. lgtmaybe-0.0.1/src/lgtmaybe/core/logging.py +88 -0
  32. lgtmaybe-0.0.1/src/lgtmaybe/core/models.py +104 -0
  33. lgtmaybe-0.0.1/src/lgtmaybe/core/ports.py +49 -0
  34. lgtmaybe-0.0.1/src/lgtmaybe/engine/__init__.py +1 -0
  35. lgtmaybe-0.0.1/src/lgtmaybe/github/__init__.py +1 -0
  36. lgtmaybe-0.0.1/src/lgtmaybe/providers/__init__.py +1 -0
  37. lgtmaybe-0.0.1/src/lgtmaybe/py.typed +0 -0
  38. lgtmaybe-0.0.1/tests/__init__.py +0 -0
  39. lgtmaybe-0.0.1/tests/fakes/__init__.py +7 -0
  40. lgtmaybe-0.0.1/tests/fakes/engine.py +28 -0
  41. lgtmaybe-0.0.1/tests/fakes/github.py +29 -0
  42. lgtmaybe-0.0.1/tests/fakes/provider.py +39 -0
  43. lgtmaybe-0.0.1/tests/snapshots/PRContext.json +43 -0
  44. lgtmaybe-0.0.1/tests/snapshots/ProviderResult.json +30 -0
  45. lgtmaybe-0.0.1/tests/snapshots/ReviewConfig.json +79 -0
  46. lgtmaybe-0.0.1/tests/snapshots/ReviewFinding.json +69 -0
  47. lgtmaybe-0.0.1/tests/test_fakes_wiring.py +29 -0
  48. lgtmaybe-0.0.1/tests/test_logging.py +53 -0
  49. lgtmaybe-0.0.1/tests/test_models.py +80 -0
  50. lgtmaybe-0.0.1/tests/test_ports.py +18 -0
  51. lgtmaybe-0.0.1/uv.lock +400 -0
  52. lgtmaybe-0.0.1/yarn.lock +0 -0
@@ -0,0 +1,26 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(uv --version)",
5
+ "Bash(uv sync *)",
6
+ "Bash(uv run *)",
7
+ "Bash(git check-ignore *)",
8
+ "Bash(gh auth *)",
9
+ "Bash(git ls-remote *)",
10
+ "Bash(gh repo *)",
11
+ "Bash(git ls-tree *)",
12
+ "Bash(git checkout *)",
13
+ "Bash(git add *)",
14
+ "Bash(git commit *)",
15
+ "Bash(git push *)",
16
+ "Bash(gh pr create --base main --head foundation --title 'foundation: freeze contracts, fakes, structured logging, CI' --body ' *)",
17
+ "Bash(gh pr *)",
18
+ "Bash(echo \"--- exit: $? ---\")",
19
+ "Bash(git pull *)",
20
+ "Bash(env)",
21
+ "Bash(curl -s -o /dev/null -w \"%{http_code}\" https://pypi.org/pypi/lgtmaybe/json)",
22
+ "Bash(uv build *)",
23
+ "Bash(uvx twine *)"
24
+ ]
25
+ }
26
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,33 @@
1
+ name: ci
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ jobs:
9
+ check:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Install uv
15
+ uses: astral-sh/setup-uv@v5
16
+ with:
17
+ python-version: "3.12"
18
+ enable-cache: true
19
+
20
+ - name: Sync (with dev deps)
21
+ run: uv sync --dev
22
+
23
+ - name: Lint
24
+ run: uv run ruff check .
25
+
26
+ - name: Format check
27
+ run: uv run ruff format --check .
28
+
29
+ - name: Types
30
+ run: uv run mypy
31
+
32
+ - name: Tests
33
+ run: uv run pytest -q
@@ -0,0 +1,218 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
File without changes
lgtmaybe-0.0.1/.npmrc ADDED
File without changes
lgtmaybe-0.0.1/.yarnrc ADDED
File without changes
File without changes
@@ -0,0 +1,100 @@
1
+ # CLAUDE.md
2
+
3
+ Guidance for agents working in **lgtmaybe** — a provider-agnostic PR reviewer.
4
+ Read this before writing code. It encodes decisions that are **made, not options**.
5
+
6
+ ## What this is
7
+
8
+ A PR reviewer that posts inline review comments + a summary. The user picks the
9
+ LLM backend with a `--provider` flag, drops a key into GitHub secrets (or wires
10
+ OIDC/WIF for cloud providers), and gets a review. One core, two distribution
11
+ variants:
12
+
13
+ - **PyPI CLI** — `pip install lgtmaybe`
14
+ - **GitHub Action** — Docker container action pulling a GHCR image
15
+
16
+ **The wedge:** first-class **Bedrock + Vertex with keyless OIDC/WIF**. Five
17
+ providers, one flag, no keys in secrets for cloud. We do not try to out-feature
18
+ pr-agent; we win on auth + simplicity. Reuse its proven mechanics, don't clone
19
+ its surface.
20
+
21
+ ## Non-negotiables
22
+
23
+ - **TDD, always: red → green → refactor.** Write the acceptance test from a
24
+ task's stated in/out *first*, watch it fail, write the minimum code to pass,
25
+ then refactor. CI rejects a PR whose diff adds code without a test.
26
+ - **Structured output only.** The model returns JSON (`severity`, `file`,
27
+ `line`, `body`, `suggestion`). Never parse prose.
28
+ - **Fork safety.** Trigger on `pull_request_target` so the review has secrets,
29
+ but **never check out or execute PR code** — fetch the diff via API only.
30
+ Treat all diff content as untrusted input.
31
+ - **No static cloud keys.** Bedrock uses ambient AWS creds; Vertex uses ambient
32
+ GCP creds. Never accept or require a service-account JSON or static AWS key.
33
+
34
+ ## Key decisions (do not relitigate)
35
+
36
+ - **Language:** Python.
37
+ - **Provider spine:** [litellm] — normalises openai, openrouter, anthropic,
38
+ bedrock, vertex, ollama to one `completion()` call. A thin wrapper on top adds
39
+ retries / fallback / cost.
40
+ - **License:** MIT (already in `LICENSE`).
41
+ - **Posting:** REST review API — batched inline comments + one summary.
42
+ Idempotent updates via a hidden marker comment.
43
+
44
+ ### Auth model — resolved by provider (chain of responsibility)
45
+
46
+ | Provider | Auth |
47
+ |------------------------|------------------------------------------------------------------|
48
+ | openai / openrouter / anthropic | API key from `secrets.*` / env / `--api-key` |
49
+ | bedrock | ambient AWS creds (GitHub OIDC role, or local `~/.aws`); IAM `bedrock:InvokeModel*` only |
50
+ | vertex | ambient GCP creds (WIF, or local ADC) |
51
+ | ollama | none — just an `api_base` (localhost, host.docker.internal, tailscale host); fully local, zero cost |
52
+
53
+ Resolver order: chosen provider → try ambient cloud creds if that's its native
54
+ mode → else API key → ollama needs neither → else **fail with a clear "how to
55
+ auth this provider" message**.
56
+
57
+ ## Architecture — ports & adapters (hexagonal)
58
+
59
+ This is what lets tracks build in parallel against frozen contracts.
60
+
61
+ - `core/ports.py` — the ports (interfaces). **Frozen in the foundation step.**
62
+ - litellm / github classes — the adapters.
63
+ - **Engine is a pipeline:** `fetch → compress → prompt → parse → post`, as
64
+ composable stages.
65
+ - **Provider choice:** strategy + factory. The `--provider` flag selects a
66
+ strategy; a small factory builds the `ProviderClient` (litellm keeps it tiny).
67
+ - **Credential resolution:** chain of responsibility (see auth table).
68
+ - **Dependency injection:** inject ports into the engine — this is what makes
69
+ fakes + dry-run drop in.
70
+
71
+ **Deliberately skipped** (don't add without a written reason): repository
72
+ pattern, event bus, plugin framework.
73
+
74
+ ## Parallel build structure
75
+
76
+ 1. **Foundation (sequential, first):** freeze the contracts in `core/ports.py`,
77
+ plus structured logging for CI debugging. Everything downstream codes against
78
+ these frozen ports.
79
+ 2. **Parallel tracks**, each against frozen contracts:
80
+ - **Track A** — provider/litellm wrapper: retries, fallback, **cost reporting**.
81
+ - **Track B** — github adapter + diff handling; **skip generated/binary files**
82
+ (lockfiles, minified, vendored).
83
+ - **Track C** — hardening: **prompt-injection defense** (PR text trying to
84
+ steer the reviewer), **secret redaction in diffs before they leave for the
85
+ LLM**, fork-PR exposure (already handled by `pull_request_target` + no checkout).
86
+ - **CLI track** — PyPI packaging, `--dry-run` for local dev.
87
+ 3. **Integration (sequential, last):** wire stages; surface errors (**a failed
88
+ review posts a comment, never fails silently**); fold cost into the summary.
89
+
90
+ Every task carries its inputs/outputs and an acceptance test so an agent can
91
+ self-verify without asking. The acceptance test *is* the red step — start there.
92
+
93
+ ## Conventions
94
+
95
+ - **Docs:** `manual-steps.md` holds the human-only setup (cloud roles,
96
+ registries, marketplace).
97
+ - Treat diff content as untrusted everywhere it flows.
98
+ - Errors surface to the user; never swallow them.
99
+
100
+ [litellm]: https://github.com/BerriAI/litellm
@@ -0,0 +1,13 @@
1
+ # Container action image (published to GHCR). The CLI track wires the real
2
+ # entrypoint; this builds the skeleton into a runnable image today.
3
+ FROM python:3.12-slim
4
+
5
+ COPY --from=ghcr.io/astral-sh/uv:0.10.6 /uv /uvx /bin/
6
+
7
+ WORKDIR /app
8
+ COPY pyproject.toml README.md ./
9
+ COPY src ./src
10
+
11
+ RUN uv sync --no-dev
12
+
13
+ ENTRYPOINT ["uv", "run", "python", "-m", "lgtmaybe"]
lgtmaybe-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Matt Coles
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,33 @@
1
+ Metadata-Version: 2.4
2
+ Name: lgtmaybe
3
+ Version: 0.0.1
4
+ Summary: Provider-agnostic PR reviewer — five providers, one flag, no keys in secrets for cloud.
5
+ Project-URL: Homepage, https://github.com/lgtmaybe/lgtmaybe
6
+ Author: Matt Coles
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Requires-Python: >=3.12
10
+ Requires-Dist: pydantic>=2.7
11
+ Description-Content-Type: text/markdown
12
+
13
+ # lgtmaybe
14
+
15
+ Provider-agnostic PR reviewer. Five providers, one flag, no keys in secrets for
16
+ cloud. Posts inline review comments + a summary.
17
+
18
+ > Status: under construction. See `CLAUDE.md` for the build plan and
19
+ > `manual-steps.md` for the human-only setup.
20
+
21
+ ## Providers
22
+
23
+ `openai` · `openrouter` · `anthropic` · `bedrock` (keyless OIDC) ·
24
+ `vertex` (keyless WIF) · `ollama` (local, zero cost)
25
+
26
+ ## Distribution
27
+
28
+ - **CLI** — `pip install lgtmaybe`
29
+ - **GitHub Action** — Docker container action from GHCR
30
+
31
+ ## License
32
+
33
+ MIT — see `LICENSE`.
@@ -0,0 +1,21 @@
1
+ # lgtmaybe
2
+
3
+ Provider-agnostic PR reviewer. Five providers, one flag, no keys in secrets for
4
+ cloud. Posts inline review comments + a summary.
5
+
6
+ > Status: under construction. See `CLAUDE.md` for the build plan and
7
+ > `manual-steps.md` for the human-only setup.
8
+
9
+ ## Providers
10
+
11
+ `openai` · `openrouter` · `anthropic` · `bedrock` (keyless OIDC) ·
12
+ `vertex` (keyless WIF) · `ollama` (local, zero cost)
13
+
14
+ ## Distribution
15
+
16
+ - **CLI** — `pip install lgtmaybe`
17
+ - **GitHub Action** — Docker container action from GHCR
18
+
19
+ ## License
20
+
21
+ MIT — see `LICENSE`.
File without changes
@@ -0,0 +1,53 @@
1
+ # lgtmaybe — manual steps
2
+
3
+ things an agent cant do for you. work top to bottom; each block says *when* in the build it's needed.
4
+
5
+ ---
6
+
7
+ ## A. before any code (day one)
8
+ - [ ] create github org/repo `lgtmaybe` (confirm `lgtm-ai` isnt yours — it's a different project).
9
+ - [ ] `pip install build twine` and push a `0.0.1` placeholder to pypi to hold the name. real release comes later.
10
+ - [ ] enable branch protection on `main`: require CI green, require a PR.
11
+
12
+ ## B. provider credentials (needed to run a real review)
13
+ pick whichever providers you'll actually demo. you do **not** need all five.
14
+
15
+ ### key-based (openai / openrouter / anthropic)
16
+ - [ ] generate an api key in that provider's console.
17
+ - [ ] add it as a github **repo secret** (e.g. `OPENAI_KEY`, `ANTHROPIC_KEY`, `OPENROUTER_KEY`).
18
+
19
+ ### bedrock (keyless, via OIDC) — the wedge, worth doing
20
+ - [ ] in AWS, create an IAM **OIDC identity provider** for `token.actions.githubusercontent.com`.
21
+ - [ ] create an IAM **role** with a trust policy scoped to your repo (`repo:<org>/lgtmaybe:*`).
22
+ - [ ] attach a least-privilege policy: `bedrock:InvokeModel` + `bedrock:InvokeModelWithResponseStream` on the specific model ARNs only.
23
+ - [ ] note the **role ARN** — it becomes the `aws_role_arn` action input. no static key is ever stored.
24
+ - [ ] confirm the models you want are enabled in the target region (model access request in the Bedrock console).
25
+
26
+ ### vertex (keyless, via workload identity federation)
27
+ - [ ] create a GCP **workload identity pool** + a github provider in it.
28
+ - [ ] create a service account with `roles/aiplatform.user` (or narrower).
29
+ - [ ] grant the github principal permission to impersonate that SA, scoped to your repo.
30
+ - [ ] note the **WIF provider resource name** — it becomes `gcp_wif_provider`.
31
+
32
+ ## C. repo permissions for the action
33
+ - [ ] the workflow needs `permissions: id-token: write` (for OIDC) and `pull-requests: write` (to post comments).
34
+ - [ ] decide the trigger: `pull_request_target` (so secrets are available) — and confirm the action never checks out PR code, only reads the diff.
35
+
36
+ ## D. publishing (step 4 of the plan)
37
+
38
+ ### pypi CLI via trusted publishing (no token in secrets)
39
+ - [ ] on pypi, add a **trusted publisher** for the repo + the release workflow name + environment.
40
+ - [ ] no `PYPI_TOKEN` secret needed — the release workflow authenticates via OIDC.
41
+
42
+ ### GHCR image
43
+ - [ ] confirm `packages: write` permission in the release workflow; GHCR uses the built-in `GITHUB_TOKEN`, nothing manual beyond that.
44
+
45
+ ### marketplace listing
46
+ - [ ] add an `action.yml` with `name`, `description`, `branding` (icon + colour).
47
+ - [ ] tag a release (`v1.0.0`) and a floating `v1`.
48
+ - [ ] from the release page, tick **"Publish this Action to the GitHub Marketplace"**, accept terms, pick categories (`code-review`, `continuous-integration`).
49
+
50
+ ## E. before you announce / blog it
51
+ - [ ] run lgtmaybe on its own repo (dogfood) so the README screenshot is real.
52
+ - [ ] write the data/privacy statement: which provider sees the diff, and that cloud variants send no static keys.
53
+ - [ ] sanity-check the least-privilege IAM/WIF scopes one more time before the repo goes public.
File without changes
File without changes
File without changes
@@ -0,0 +1,46 @@
1
+ [project]
2
+ name = "lgtmaybe"
3
+ version = "0.0.1"
4
+ description = "Provider-agnostic PR reviewer — five providers, one flag, no keys in secrets for cloud."
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ requires-python = ">=3.12"
8
+ authors = [{ name = "Matt Coles" }]
9
+ dependencies = [
10
+ "pydantic>=2.7",
11
+ ]
12
+
13
+ [project.urls]
14
+ Homepage = "https://github.com/lgtmaybe/lgtmaybe"
15
+
16
+ [dependency-groups]
17
+ dev = [
18
+ "pytest>=8",
19
+ "ruff>=0.5",
20
+ "mypy>=1.10",
21
+ ]
22
+
23
+ [build-system]
24
+ requires = ["hatchling"]
25
+ build-backend = "hatchling.build"
26
+
27
+ [tool.hatch.build.targets.wheel]
28
+ packages = ["src/lgtmaybe"]
29
+
30
+ [tool.ruff]
31
+ line-length = 100
32
+ target-version = "py312"
33
+ src = ["src", "tests"]
34
+
35
+ [tool.ruff.lint]
36
+ select = ["E", "F", "I", "UP", "B"]
37
+
38
+ [tool.pytest.ini_options]
39
+ testpaths = ["tests"]
40
+ pythonpath = ["src"]
41
+
42
+ [tool.mypy]
43
+ python_version = "3.12"
44
+ packages = ["lgtmaybe"]
45
+ mypy_path = "src"
46
+ strict = true
@@ -0,0 +1,3 @@
1
+ """lgtmaybe — provider-agnostic PR reviewer."""
2
+
3
+ __version__ = "0.0.1"
@@ -0,0 +1,20 @@
1
+ """Module entrypoint placeholder.
2
+
3
+ The real CLI is wired in the CLI track. For now this keeps `python -m lgtmaybe`
4
+ (and the Docker ENTRYPOINT) runnable on the skeleton.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import sys
10
+
11
+ from . import __version__
12
+
13
+
14
+ def main(argv: list[str] | None = None) -> int:
15
+ print(f"lgtmaybe {__version__} — CLI not wired yet (see CLAUDE.md)")
16
+ return 0
17
+
18
+
19
+ if __name__ == "__main__":
20
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1 @@
1
+ """cli — populated by its track (see CLAUDE.md)."""
@@ -0,0 +1 @@
1
+ """config — populated by its track (see CLAUDE.md)."""
@@ -0,0 +1 @@
1
+ """Core: frozen data contracts and boundary interfaces (ports)."""