Skip to content

Add label-driven release automation - #8

Merged
klauern merged 17 commits into
mainfrom
codex/release-process
May 25, 2026
Merged

Add label-driven release automation#8
klauern merged 17 commits into
mainfrom
codex/release-process

Conversation

@klauern

@klauern klauern commented May 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • add PR label normalization for patch/minor/major release labels
  • add merged-PR release workflow that bumps pyproject/uv.lock, tags, creates GitHub releases, and publishes to PyPI via trusted publishing
  • expose runtime package version via version and mcp-ynab --version
  • tighten Hatch build includes so sdists do not ship local/dev files
  • document the release process

Verification

  • task test
  • task lint
  • uv build
  • node -c .github/scripts/release_labeler.cjs
  • node -c .github/scripts/release_level.cjs
  • uv run mcp-ynab --version

Summary by CodeRabbit

  • New Features

    • Label-driven release flow with automated version bumping, tagging, and optional publish.
    • CLI --version output.
    • Create scheduled (recurring) transactions; richer transaction/category/payee resources and interactive category selection for moves.
    • Per-budget payees caching and improved confirmation flows.
  • Documentation

    • Added release process docs describing labels and workflow behavior.
  • Tests

    • Expanded tests for release bumping, scheduled transactions, interactive flows, resources, and sandbox builtins.
  • Chores

    • Packaging/build config updates.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@klauern, we couldn't start this review because you've used your available PR reviews for now.

Your plan includes 1 review of capacity. Refill in 6 minutes and 23 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: db170736-cfd9-4e05-aee3-03b4fa7af610

📥 Commits

Reviewing files that changed from the base of the PR and between 3fd5481 and 6bd9d51.

📒 Files selected for processing (6)
  • .github/workflows/release.yml
  • src/mcp_ynab/code_mode/examples.md
  • src/mcp_ynab/resources.py
  • src/mcp_ynab/tools/budgeting.py
  • tests/test_budgeting_core.py
  • tests/test_tools.py
📝 Walkthrough

Walkthrough

This PR adds a label-driven automated release pipeline (label detection, release-level resolution, version bumping, workflows, docs, and tracking) and a new MCP tool to create scheduled YNAB transactions with accompanying tests and a server re-export.

Changes

Automated Release Workflow

Layer / File(s) Summary
PR label automation
.github/scripts/release_labeler.cjs, .github/workflows/release-labels.yml
Ensures patch/minor/major labels exist, detects release-relevant changed files, and applies/removes patch per rules.
Release level determination
.github/scripts/release_level.cjs
Reads merged PR labels and emits should_release and level outputs, selecting highest-priority label when multiple exist.
Release workflows and orchestration
.github/workflows/release.yml
Release job bumps version and lockfile, runs CI gates, builds artifacts, tags and creates a GitHub Release; publish job uploads distributions to PyPI when should_release is true.
Version bump script and tests
.github/scripts/bump_version.py, tests/test_release_version.py
Regex-based CLI to bump semantic versions in pyproject.toml, CLI wiring for GitHub Actions outputs, and tests for level transitions and file updates.
Packaging and runtime version
pyproject.toml, src/mcp_ynab/__init__.py
Hatch build targets configure sdist/wheel contents; module-level __version__ exposed with --version flag.
Release docs and tracking metadata
docs/release-process.md, .beads/issues.jsonl, .beads/interactions.jsonl
Documents release contract and records issue/interaction updates for release automation and several task closures.

MCP tools, resources, state, and tests

Layer / File(s) Summary
Scheduled transaction tool & delete confirmation
src/mcp_ynab/tools/transactions.py
Adds _FREQUENCY_VALUES, create_scheduled_transaction (milliunit conversion, start_date handling, SDK submission), and makes delete_transaction optionally elicit user confirmation via ctx.
Server exports and tool tests
src/mcp_ynab/server.py, tests/test_tools.py
Re-exports new tool(s) and adds tests for scheduled transactions, delete confirmation paths, confirmation-preference bypass, and resource behaviors.
Payees/categories resources and caching
src/mcp_ynab/resources.py, src/mcp_ynab/state.py
Adds ynab://categories/{budget_id}/current and ynab://payees/{budget_id} resources, introduces PAYEES_CACHE_FILENAME, in-memory payees cache load, get_cached_payee_records and cache_payees.
Interactive move_money and docs
src/mcp_ynab/tools/budgeting.py, tests
Makes from/to/amount optional, adds ctx for elicitation using cached categories (fetch+cache when empty), handles cancellation/validation, and clarifies docstrings.
Code Mode safe builtins and examples
src/mcp_ynab/code_mode/runner.py, src/mcp_ynab/code_mode/examples.md
Expands SAFE_BUILTINS to include hasattr and adds multiple Code Mode example snippets.
Tests and fixtures
tests/*, tests/conftest.py
Widespread tests added/updated for tools, resources, state, code-mode, server behaviors; mock_ynab_apis patched to include PayeesApi.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer
  participant PR as PullRequest
  participant Labeler as release_labeler
  participant Level as release_level
  participant Workflow as release.yml
  participant GitHub as GitHub Release
  participant PyPI as PyPI

  Dev->>PR: open / label / change files
  PR->>Labeler: run on PR events (detect files, ensure/remove `patch`)
  PR->>Level: on merged PR, label set passed to release_level
  Level->>Workflow: sets should_release & level
  Workflow->>Workflow: bump pyproject.toml and uv.lock
  Workflow->>Workflow: run CI checks, build dists
  Workflow->>GitHub: create tag and GitHub Release
  Workflow->>PyPI: publish artifact when should_release == true
Loading

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs:

  • klauern/mcp-ynab#7: Also touches Code Mode runner safe builtins changes (related test/sandbox behavior).

"🐰 I hopped through labels, bumped versions with care,
I cached payees and scheduled transactions to share.
Examples and tests sprouted up all through the night,
Now releases and tools are lined up just right.
Hooray — the pipeline's ready to hare!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add label-driven release automation' directly corresponds to the main changes: PR label normalization, merged-PR release workflows, and release process documentation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/release-process

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
tests/test_release_version.py (1)

9-9: ⚡ Quick win

Add explicit type hints on test helpers/functions to match repo standards.

Please annotate the helper return type and test function signatures (-> None), including the tmp_path fixture type.

Suggested fix
 import importlib.util
 from pathlib import Path
+from types import ModuleType
 
 
-def load_bump_version_module():
+def load_bump_version_module() -> ModuleType:
@@
-def test_bump_version_levels():
+def test_bump_version_levels() -> None:
@@
-def test_bump_pyproject_updates_static_project_version(tmp_path):
+def test_bump_pyproject_updates_static_project_version(tmp_path: Path) -> None:

As per coding guidelines, **/*.py: Use type hints consistently with modern Python typing.

Also applies to: 19-19, 27-27

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_release_version.py` at line 9, Add explicit type hints: annotate
the helper load_bump_version_module to return types.ModuleType (or typing.Any if
you prefer) and update the test function signatures to include return type ->
None and type the tmp_path fixture as pathlib.Path; specifically modify
load_bump_version_module(), and the test functions named in the file (eg.
test_bump_version_from_pyproject and test_bump_version_from_setup_py) to accept
tmp_path: Path and return None. Also add the necessary imports (from types
import ModuleType and from pathlib import Path) if not already present.
src/mcp_ynab/__init__.py (1)

17-20: 💤 Low value

Consider adding a type hint for __version__.

For consistency with the coding guideline "Use type hints consistently with modern Python typing," consider adding an explicit type annotation.

📝 Proposed enhancement
 try:
-    __version__ = version("mcp-ynab")
+    __version__: str = version("mcp-ynab")
 except PackageNotFoundError:
     __version__ = "0+unknown"

As per coding guidelines: "Use type hints consistently with modern Python typing" for files matching **/*.py.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mcp_ynab/__init__.py` around lines 17 - 20, Add an explicit type
annotation for the module-level variable __version__: declare __version__ as a
str and keep the existing try/except that sets it via version("mcp-ynab") and
PackageNotFoundError fallback; update the __version__ assignment site (the
try/except block using version and PackageNotFoundError) to use the annotated
variable so the module consistently follows modern Python typing.
.github/workflows/release-labels.yml (1)

17-28: 💤 Low value

Security pattern for pull_request_target is correctly implemented.

The static analysis tool flagged pull_request_target as dangerous, but this implementation follows the secure pattern:

  1. Line 20 checks out code from default_branch, NOT from the PR branch
  2. The script executed comes from the trusted default branch
  3. PR content is only read via GitHub API, never executed

This pattern is necessary to write labels on PRs (including those from forks) while maintaining security.

Optional: Consider pinning actions to commit SHAs.

For additional supply chain security, you could pin actions to specific commit hashes instead of version tags:

  • actions/checkout@v4actions/checkout@<commit-sha>
  • actions/github-script@v7actions/github-script@<commit-sha>

This prevents tag-moving attacks, though the risk is low for official GitHub actions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-labels.yml around lines 17 - 28, The workflow
currently uses actions referenced by tags (actions/checkout@v4 and
actions/github-script@v7); to harden supply-chain security, replace those tagged
references with specific commit SHAs for each action (e.g.,
actions/checkout@<commit-sha> and actions/github-script@<commit-sha>) while
keeping the existing pattern that checks out the default branch and requires the
release_labeler.cjs script; update the two "uses" entries that mention
actions/checkout and actions/github-script accordingly and verify the checkout
ref: ${{ github.event.repository.default_branch }} and the labeler import remain
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/scripts/bump_version.py:
- Line 11: The long single-line regex assigned to VERSION_RE exceeds the
100-character limit; split it across lines by using a multi-line string or
re.VERBOSE and combine flags so the pattern stays readable and under 100 chars
per line (e.g., build the pattern with implicit string concatenation or use
re.VERBOSE and pass re.MULTILINE | re.VERBOSE to re.compile) while preserving
the named groups (?P<version>, ?P<minor>, ?P<patch>) and the raw string prefix.

In @.github/workflows/release.yml:
- Line 27: Pin every uses: entry to an immutable commit SHA instead of tag names
for actions referenced (e.g., replace actions/checkout@v4,
actions/github-script@v7, astral-sh/setup-uv@v3, actions/upload-artifact@v4,
actions/download-artifact@v4, pypa/gh-action-pypi-publish@release/v1 with their
corresponding full commit SHAs) and for the second checkout step (the "Checkout
main" checkout action) add with: persist-credentials: false so the GITHUB_TOKEN
is not retained; then enable authentication only on the specific step(s) that
perform git push/tag (configure that push/tag step to use a short-lived token or
set persist-credentials: true just for that step via a separate checkout if
needed).
- Around line 40-45: The "Checkout main" step currently uses actions/checkout@v4
without disabling credential persistence; update that step (named "Checkout
main", referencing uses: actions/checkout@v4 and ref: main) to add
persist-credentials: false so the default GITHUB_TOKEN is not left configured
for subsequent steps, and ensure you explicitly set up an authenticated remote
only for the push step (e.g., by adding a dedicated git remote or using an
authenticated action/step) before "Push version commit and tag".

In `@docs/release-process.md`:
- Line 34: Replace the all-caps platform name "GITHUB" with the proper
capitalization "GitHub" in the document; search for the token "GITHUB"
(including the occurrence in the phrase "PyPI publishing requires a trusted
publisher configured for this repository and the") and update every occurrence
to "GitHub" to ensure consistent, user-facing platform naming.

---

Nitpick comments:
In @.github/workflows/release-labels.yml:
- Around line 17-28: The workflow currently uses actions referenced by tags
(actions/checkout@v4 and actions/github-script@v7); to harden supply-chain
security, replace those tagged references with specific commit SHAs for each
action (e.g., actions/checkout@<commit-sha> and
actions/github-script@<commit-sha>) while keeping the existing pattern that
checks out the default branch and requires the release_labeler.cjs script;
update the two "uses" entries that mention actions/checkout and
actions/github-script accordingly and verify the checkout ref: ${{
github.event.repository.default_branch }} and the labeler import remain
unchanged.

In `@src/mcp_ynab/__init__.py`:
- Around line 17-20: Add an explicit type annotation for the module-level
variable __version__: declare __version__ as a str and keep the existing
try/except that sets it via version("mcp-ynab") and PackageNotFoundError
fallback; update the __version__ assignment site (the try/except block using
version and PackageNotFoundError) to use the annotated variable so the module
consistently follows modern Python typing.

In `@tests/test_release_version.py`:
- Line 9: Add explicit type hints: annotate the helper load_bump_version_module
to return types.ModuleType (or typing.Any if you prefer) and update the test
function signatures to include return type -> None and type the tmp_path fixture
as pathlib.Path; specifically modify load_bump_version_module(), and the test
functions named in the file (eg. test_bump_version_from_pyproject and
test_bump_version_from_setup_py) to accept tmp_path: Path and return None. Also
add the necessary imports (from types import ModuleType and from pathlib import
Path) if not already present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d3c3c1cd-cf9a-4eda-911f-8c0542b43e4c

📥 Commits

Reviewing files that changed from the base of the PR and between fe09b81 and fbf1017.

📒 Files selected for processing (11)
  • .beads/interactions.jsonl
  • .beads/issues.jsonl
  • .github/scripts/bump_version.py
  • .github/scripts/release_labeler.cjs
  • .github/scripts/release_level.cjs
  • .github/workflows/release-labels.yml
  • .github/workflows/release.yml
  • docs/release-process.md
  • pyproject.toml
  • src/mcp_ynab/__init__.py
  • tests/test_release_version.py

Comment thread .github/scripts/bump_version.py Outdated
Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml
Comment thread docs/release-process.md
8. Creates a GitHub release with the built distributions attached.
9. Publishes to PyPI with trusted publishing.

PyPI publishing requires a trusted publisher configured for this repository and the

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the official GitHub capitalization.

Line 34 uses GITHUB; update it to GitHub for correct platform naming in user-facing docs.

✏️ Suggested fix
-PyPI publishing requires a trusted publisher configured for this repository and the
+PyPI publishing requires a trusted publisher configured for this repository and the
 `.github/workflows/release.yml` workflow.

And ensure any GITHUB occurrences are changed to GitHub.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~34-~34: The official name of this software platform is spelled with a capital “H”.
Context: ... configured for this repository and the .github/workflows/release.yml workflow.

(GITHUB)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/release-process.md` at line 34, Replace the all-caps platform name
"GITHUB" with the proper capitalization "GitHub" in the document; search for the
token "GITHUB" (including the occurrence in the phrase "PyPI publishing requires
a trusted publisher configured for this repository and the") and update every
occurrence to "GitHub" to ensure consistent, user-facing platform naming.

…sactions

Wraps ScheduledTransactionsApi.create_scheduled_transaction() to expose
scheduled transaction creation via MCP. Accepts amount in dollars (converted
to milliunits), ISO start date (defaults to today), and a Literal-typed
frequency with all 13 valid YNAB values. Supports all SaveScheduledTransaction
fields: payee_id/payee_name, category_id, memo, flag_color.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mcp_ynab/tools/transactions.py`:
- Around line 1099-1135: The create_scheduled_transaction implementation
violates the declared contract by allowing both payee_id and payee_name to be
sent and truncates amounts; update create_scheduled_transaction to validate
exclusivity (raise ValueError if both payee_id and payee_name are provided) and
ensure milliunit conversion matches the rest of the module by using rounding
(use int(round(amount * 1000))) before passing the value into
SaveScheduledTransaction (reference SaveScheduledTransaction, txn/txn_date, and
the function create_scheduled_transaction for locating the changes).

In `@tests/test_tools.py`:
- Around line 1922-1926: The current assertion checks for "$15.99" in result but
doesn't ensure the negative sign is present; update the test in
tests/test_tools.py to assert the negative sign is included (e.g., require
"-$15.99" in result) or use a regex match against result (for example matching a
leading minus or Unicode minus before $15.99) so the test fails if the negative
sign is dropped; locate the assertion referring to result and replace the final
assert that checks "$15.99" with the stricter check for the negative formatted
amount.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8c4e866e-f2e5-4704-a415-a85b951a888b

📥 Commits

Reviewing files that changed from the base of the PR and between fbf1017 and 4bfaa17.

📒 Files selected for processing (4)
  • .beads/issues.jsonl
  • src/mcp_ynab/server.py
  • src/mcp_ynab/tools/transactions.py
  • tests/test_tools.py

Comment thread src/mcp_ynab/tools/transactions.py
Comment thread tests/test_tools.py
klauern added 13 commits May 23, 2026 21:02
…ution

- set_preference: 6 tests for code_mode_enabled, code_mode_replace_tools,
  code_mode_timeout_s (float coercion + gt=0/le=60 bounds), and
  code_mode_max_output_chars (int ge=0 including zero)
- _resolve_config_dir: 2 tests for XDG_CONFIG_HOME override and ~/.config
  fallback via Path.home() monkeypatch
- 268 total tests pass (up from 260)
Add any, all, abs, round, hasattr, and isinstance to the Code Mode
builtin allow-list. These were missing and causing failures in
read-only analysis snippets (e.g. hasattr on YNAB API response dicts,
any/all for list-filtering patterns).

hasattr is safe here: the existing dunder-string-literal AST audit
blocks hasattr(obj, "__class__") style probes at parse time, so the
expanded surface doesn't widen the escape-hatch surface.

12 new tests cover each new builtin, the dunder-string guard, and a
realistic isinstance-based type-filter pattern.
Field description now reads: "Amount in dollars. Negative for outflows
(expenses, e.g. -42.50), positive for inflows (deposits, e.g. 1500.00)."

Docstring adds a one-line example sentence so the sign convention is
visible to both MCP clients reading the schema and developers reading
the source.
Add notes to get_categories, update_category, and
get_scheduled_transactions describing what the YNAB API cannot do:
- No POST /categories endpoint — categories must be created in the app
- SaveCategory write model exposes no goal fields — goals are read-only
- No update/delete endpoint for scheduled transactions — only create+list
Fetch the transaction summary (date, payee, amount, category) and show
a confirmation prompt via ctx.elicit before issuing the destructive
DELETE. Returns "cancelled" string without deleting if the user declines
or dismisses the prompt.

No ctx (batch/automation flows) skips the prompt and deletes directly,
preserving backward compatibility.

Three new tests cover the confirm, decline, and dismiss paths.
…is fixture

Replace inline DummyApi/DummyCtx boilerplate in 4 categorize_transaction
tests with the shared mock_ynab_apis fixture. Each test shrinks by ~15
lines. Behavioral assertions preserved: no-GET guarantee, PATCH-only
semantics, 404 not-found path, and 500 re-raise path all still verified.
Exposes all non-deleted payees for a budget as a markdown table
(name, ID, transfer_account_id) via the MCP resource protocol —
avoids burning a tool call for payee lookup.

- YNABResources gains cache_payees() + get_cached_payee_records()
  backed by payees_cache.json (same envelope pattern as category cache)
- list_payees_resource fetches live, filters deleted, caches, returns markdown
- conftest mock_ynab_apis now patches server.PayeesApi so resource
  tests can control the mock the same way tool tests do
- 4 tests covering markdown render, empty list, deleted-filter, caching
…=True

Adds test_code_mode_replace_tools_filters_instance_list_tools to verify
the instance-attribute patch (mcp.list_tools = _list_tools_with_code_mode_filter)
returns exactly {search, execute} + bootstrap tools when replace_tools is
enabled — closing the regression gap alongside the existing protocol-handler
and escape-hatch tests.

Closes mcp-ynab-fsv.2
Adds bulk approve, spending-by-category, triage-uncategorized-by-payee,
and spending-by-payee examples to ynab://code-mode/examples. File stays
at 4.9KB, well under the 8KB cap. Namespace regression test updated.

Closes mcp-ynab-fsv.4
Both create_transaction and delete_transaction now check
ynab_resources.preferences.confirm_before_post before triggering
ctx.elicit(). When the preference is False, the confirmation prompt
is skipped regardless of the per-call confirm= param — giving users
a global escape hatch to disable confirmation dialogs.

Design: should_confirm = confirm AND confirm_before_post (both must be
True; per-call can opt-out, preference is the global gate).

Closes mcp-ynab-6ha.6
…esource

Live-fetches all category groups for a budget and renders a per-group
markdown table with budgeted, activity, and balance columns — allowing
the model to answer 'what's left in Groceries?' from a resource read
without spending a tool call.

- Uses getattr() throughout to work correctly with both SDK models and mocks
- Filters deleted categories; empty budgets return a clear message
- Registered in server.py re-export block

Closes mcp-ynab-g9z.10
Makes from_category_id, to_category_id, and amount all Optional in the
move_money tool signature. When either category ID is missing and an MCP
context is available, the user is prompted to choose from the cached
category list (which is refreshed from the API if empty).

The amount parameter remains required (infer-from-overspend deferred).
Existing positional callers are unaffected by the signature change.

Closes mcp-ynab-qlh.5

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Around line 26-30: The checkout steps currently pin `with: ref: main` which
can cause the release job to operate on a moved main tip; update both checkout
steps (the "Checkout workflow scripts" step and the other actions/checkout at
lines referenced around 40-46) to use the PR merge commit SHA via
`github.event.pull_request.merge_commit_sha` for the release flow (fallback to
`github.sha` or fail fast if the merge SHA is not set), so the release
builds/tags/pushes the exact PR merge commit rather than a moving `main` tip;
alternatively add a guard that compares `main` head with the expected merge SHA
and fails/retries before `git tag`/`git push` if they differ.

In `@src/mcp_ynab/code_mode/examples.md`:
- Around line 119-121: The example calls ynab.write.approve_transactions using
budget_id in the else branch before it’s defined; fix by computing an
effective_budget_id first (e.g., set effective_budget_id =
transactions[0].budget_id if hasattr(transactions[0], "budget_id") else
provided_budget_id or a default) and then pass effective_budget_id to
ynab.write.approve_transactions (reference symbols: transactions, budget_id,
ynab.write.approve_transactions).

In `@src/mcp_ynab/resources.py`:
- Around line 186-190: The loop over groups should skip YNAB groups that are
marked deleted so stale categories aren't rendered; before deriving
group_name/categories/active (in the for group in groups loop in
src/mcp_ynab/resources.py) add a guard that continues if getattr(group,
"deleted", False) is True (or equivalently check group.deleted), and keep the
existing check that continues when there are no non-deleted categories (the
active list) so only non-deleted groups with active categories are processed.

In `@src/mcp_ynab/tools/budgeting.py`:
- Around line 310-317: In move_money, add an early check after resolving
from_category_id and to_category_id to detect if they refer to the same category
(compare the resolved IDs or Category objects) and short-circuit as a no-op
(return immediately) to avoid performing the two-step update that would
incorrectly change the budget; place this check before computing delta
(int(amount * 1000)) and before calling _resolve_month so the function exits
cleanly when from_category_id == to_category_id (or their resolved equivalents).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 910065a5-4303-4dc9-9917-444c5332bd77

📥 Commits

Reviewing files that changed from the base of the PR and between 4bfaa17 and 3fd5481.

📒 Files selected for processing (20)
  • .beads/interactions.jsonl
  • .beads/issues.jsonl
  • .github/scripts/bump_version.py
  • .github/workflows/release-labels.yml
  • .github/workflows/release.yml
  • src/mcp_ynab/__init__.py
  • src/mcp_ynab/code_mode/examples.md
  • src/mcp_ynab/code_mode/runner.py
  • src/mcp_ynab/resources.py
  • src/mcp_ynab/server.py
  • src/mcp_ynab/state.py
  • src/mcp_ynab/tools/budgeting.py
  • src/mcp_ynab/tools/transactions.py
  • tests/conftest.py
  • tests/test_budgeting_core.py
  • tests/test_code_mode.py
  • tests/test_release_version.py
  • tests/test_server.py
  • tests/test_state.py
  • tests/test_tools.py
✅ Files skipped from review due to trivial changes (1)
  • .beads/issues.jsonl

Comment thread .github/workflows/release.yml
Comment thread src/mcp_ynab/code_mode/examples.md
Comment thread src/mcp_ynab/resources.py
Comment thread src/mcp_ynab/tools/budgeting.py
@klauern

klauern commented May 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai help

@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai rate limit to show your current review rate limit status.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai emit path instructions to emit generated path-specific review instructions for this repository.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@klauern

klauern commented May 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@klauern
klauern merged commit d0fb4b1 into main May 25, 2026
2 checks passed
@klauern
klauern deleted the codex/release-process branch May 25, 2026 15:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant