aihawk 0.1.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.
Files changed (44) hide show
  1. aihawk-0.1.0/.github/CODE_OF_CONDUCT.md +33 -0
  2. aihawk-0.1.0/.github/CONTRIBUTING.md +106 -0
  3. aihawk-0.1.0/.github/FUNDING.yml +1 -0
  4. aihawk-0.1.0/.github/ISSUE_TEMPLATE/bug-issue.yml +90 -0
  5. aihawk-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  6. aihawk-0.1.0/.github/ISSUE_TEMPLATE/documentation-issue.yml +39 -0
  7. aihawk-0.1.0/.github/ISSUE_TEMPLATE/enhancement-issue.yml +46 -0
  8. aihawk-0.1.0/.github/workflows/ci.yml +69 -0
  9. aihawk-0.1.0/.github/workflows/publish.yml +109 -0
  10. aihawk-0.1.0/.github/workflows/stale.yml +42 -0
  11. aihawk-0.1.0/.gitignore +167 -0
  12. aihawk-0.1.0/LICENSE +21 -0
  13. aihawk-0.1.0/PKG-INFO +177 -0
  14. aihawk-0.1.0/README.md +159 -0
  15. aihawk-0.1.0/articles/README.md +45 -0
  16. aihawk-0.1.0/assets/AIHawk.png +0 -0
  17. aihawk-0.1.0/assets/aihawk-logo-dark.png +0 -0
  18. aihawk-0.1.0/assets/aihawk-logo-light.png +0 -0
  19. aihawk-0.1.0/assets/invisible-playwright-banner.png +0 -0
  20. aihawk-0.1.0/assets/laboro.png +0 -0
  21. aihawk-0.1.0/pyproject.toml +52 -0
  22. aihawk-0.1.0/scripts/check_english_only.py +365 -0
  23. aihawk-0.1.0/src/aihawk/__init__.py +2 -0
  24. aihawk-0.1.0/src/aihawk/__main__.py +4 -0
  25. aihawk-0.1.0/src/aihawk/actions_help.py +53 -0
  26. aihawk-0.1.0/src/aihawk/agent.py +156 -0
  27. aihawk-0.1.0/src/aihawk/brain.py +115 -0
  28. aihawk-0.1.0/src/aihawk/cli.py +120 -0
  29. aihawk-0.1.0/src/aihawk/link.py +131 -0
  30. aihawk-0.1.0/src/aihawk/llm.py +25 -0
  31. aihawk-0.1.0/src/aihawk/runner.py +57 -0
  32. aihawk-0.1.0/src/aihawk/web.py +801 -0
  33. aihawk-0.1.0/tests/test_agent.py +81 -0
  34. aihawk-0.1.0/tests/test_agent_loop.py +843 -0
  35. aihawk-0.1.0/tests/test_cli.py +24 -0
  36. aihawk-0.1.0/tests/test_cli_surface.py +517 -0
  37. aihawk-0.1.0/tests/test_import.py +3 -0
  38. aihawk-0.1.0/tests/test_key_isolation.py +385 -0
  39. aihawk-0.1.0/tests/test_llm.py +15 -0
  40. aihawk-0.1.0/tests/test_openrouter_only.py +392 -0
  41. aihawk-0.1.0/tests/test_real_cli.py +19 -0
  42. aihawk-0.1.0/tests/test_runner.py +27 -0
  43. aihawk-0.1.0/tests/test_ui_drive.py +874 -0
  44. aihawk-0.1.0/tests/test_web_service.py +302 -0
@@ -0,0 +1,33 @@
1
+ # Code of Conduct
2
+
3
+ This project follows the [Contributor Covenant, v2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
4
+
5
+ ## Our Pledge
6
+
7
+ We pledge to make participation in our community a harassment-free experience for everyone.
8
+
9
+ ## Standards
10
+
11
+ Examples of behavior that contributes to a positive environment:
12
+
13
+ - Using welcoming and inclusive language
14
+ - Being respectful of differing viewpoints and experiences
15
+ - Gracefully accepting constructive criticism
16
+ - Focusing on what is best for the community
17
+
18
+ Examples of unacceptable behavior:
19
+
20
+ - The use of sexualized language or imagery
21
+ - Trolling, insulting or derogatory comments, and personal or political attacks
22
+ - Public or private harassment
23
+ - Publishing others' private information without explicit permission
24
+
25
+ ## Enforcement
26
+
27
+ Instances of unacceptable behavior may be reported by contacting the maintainer at **federico.elia.majo@gmail.com**. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
28
+
29
+ The maintainer is obligated to maintain confidentiality with regard to the reporter of an incident.
30
+
31
+ ## Attribution
32
+
33
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
@@ -0,0 +1,106 @@
1
+ # Contributing to AIHawk
2
+
3
+ Thanks for being here. This page says what this repository is, so you can tell in
4
+ one minute whether your change belongs here or in one of the packages below.
5
+
6
+ ## What lives here
7
+
8
+ The `aihawk` package: the two-pane interface, the loop that turns a sentence into
9
+ browser actions, and the command line around both. If you are changing what a
10
+ person sees, or how the model decides what to do next, it is here.
11
+
12
+ What is NOT here is the browser. AIHawk does not drive Firefox directly - it
13
+ talks to an MCP server over MCP, using the same fourteen tools any other client
14
+ gets. That is deliberate and it is the thing to understand before changing
15
+ anything: this interface has no privileged path to the page, so a browser
16
+ capability it needs is a capability every client gets, or it does not exist.
17
+
18
+ This page said the opposite earlier on 2 September 2026, when the repository held
19
+ only documentation. The package moved in the same day.
20
+
21
+ ## Where the code is
22
+
23
+ | Repository | What it holds |
24
+ |---|---|
25
+ | **this one** | the interface, the agent loop, the CLI |
26
+ | [invisible-playwright-mcp](https://github.com/feder-cr/invisible-playwright-mcp) | the MCP server: the fourteen tools, and nothing with a face |
27
+ | [invisible_playwright](https://github.com/feder-cr/invisible_playwright) | the Python wrapper, the launcher, and the patched browser it pins |
28
+ | [invisible_core](https://github.com/feder-cr/invisible_core) | seed to fingerprint to preferences, proxy and geolocation |
29
+
30
+ Where things go:
31
+
32
+ - the page, the conversation, the step list, the model's behaviour: **here**
33
+ - a tool that returns the wrong thing, or a click that does not land: **the MCP server**
34
+ - the browser failing to start, a proxy not used, a timezone that does not match
35
+ the exit country: **the wrapper or the core**
36
+ - a detector spotting the browser: almost always the engine, not this repository
37
+
38
+ If you are not sure, open the issue here and it will be moved.
39
+
40
+ ## Development setup
41
+
42
+ ```bash
43
+ git clone https://github.com/feder-cr/AIHawk.git
44
+ cd AIHawk
45
+ python -m venv .venv
46
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
47
+ pip install -e ".[test]"
48
+ ```
49
+
50
+ Python 3.11 or newer, Windows or Linux. No key is needed to work on it: `aihawk
51
+ ui` without one runs the literal-command placeholder, which drives the real
52
+ browser through the real server and is how most of this was tested.
53
+
54
+ ## Running the tests
55
+
56
+ ```bash
57
+ pytest # the default selection, no browser, seconds
58
+ pytest -m ui # drives a REAL browser through a REAL server
59
+ ```
60
+
61
+ The `ui` tests are deselected by default because they are slow and they must run
62
+ serially: they launch a browser, and two browser benches on one machine produce
63
+ results that are noise with numbers on them. Run them one at a time, on a machine
64
+ that is not doing anything else.
65
+
66
+ They assert what happened INSIDE the page, never what a tool said about itself. A
67
+ tool that answers "clicked #go" while nothing moved is the failure they exist to
68
+ catch, so the tool's own success string is never the assertion.
69
+
70
+ ## Pull requests
71
+
72
+ Fork, branch, open the pull request against `main`. There is one branch and no
73
+ release train.
74
+
75
+ Keep a pull request to one change, and say in the description what a reader would
76
+ be able to do afterwards that they could not do before. If you change what the
77
+ interface shows, include a screenshot: this project has already had the case
78
+ where five green tests passed while the pane showed a black rectangle, and the
79
+ picture was the only thing that noticed.
80
+
81
+ ## Opening an issue
82
+
83
+ Use one of the [templates](https://github.com/feder-cr/AIHawk/issues/new/choose).
84
+ Before you do, search the open and closed issues.
85
+
86
+ For a bug, the two things that decide how fast it can be answered are the exact
87
+ commands you ran and what happened instead of what you expected. Include your OS
88
+ and Python version, and whether you were running `ui` or `do`.
89
+
90
+ Please do not report a security problem in a public issue. In particular, never
91
+ paste an OpenRouter key into one: if you have, rotate it before anything else.
92
+
93
+ ## Tone
94
+
95
+ Questions are welcome and beginners are welcome. If something in the README was
96
+ not clear enough for you, that is worth an issue on its own, because it was
97
+ probably not clear to somebody else either.
98
+
99
+ ## Licence
100
+
101
+ By contributing you agree that your contribution is licensed under the MIT
102
+ licence, which is the licence in [LICENSE](../LICENSE). Everything received
103
+ before 2 September 2026 was contributed under AGPL-3.0 and stays under it: a
104
+ licence already granted is not withdrawn by changing that file.
105
+
106
+ Participation is covered by the [Code of Conduct](CODE_OF_CONDUCT.md).
@@ -0,0 +1 @@
1
+ github: feder-cr
@@ -0,0 +1,90 @@
1
+ name: Bug report
2
+ description: Report a bug or an issue that isn't working as expected.
3
+ title: "[BUG]: <Provide a clear, descriptive title>"
4
+ labels: ["bug"]
5
+ assignees: []
6
+
7
+ body:
8
+ - type: markdown
9
+ attributes:
10
+ value: |
11
+ Please fill out the following information to help us resolve the issue.
12
+
13
+ - type: input
14
+ id: description
15
+ attributes:
16
+ label: Describe the bug
17
+ description: A clear and concise description of what the bug is.
18
+ placeholder: "Describe the bug in detail..."
19
+
20
+ - type: textarea
21
+ id: steps
22
+ attributes:
23
+ label: Steps to reproduce
24
+ description: |
25
+ Steps to reproduce the behavior:
26
+ 1. Use branch named '...'
27
+ 2. Go to file '...'
28
+ 3. Find property named '...'
29
+ 4. Change '...'
30
+ 5. Run program using command '...'
31
+ 6. See error
32
+ placeholder: "List the steps to reproduce the bug..."
33
+
34
+ - type: input
35
+ id: expected
36
+ attributes:
37
+ label: Expected behavior
38
+ description: What you expected to happen.
39
+ placeholder: "What was the expected result?"
40
+
41
+ - type: input
42
+ id: actual
43
+ attributes:
44
+ label: Actual behavior
45
+ description: What actually happened instead.
46
+ placeholder: "What happened instead?"
47
+
48
+ - type: dropdown
49
+ id: branch
50
+ attributes:
51
+ label: Branch
52
+ description: Specify the branch you were using when the bug occurred.
53
+ options:
54
+ - main
55
+ - other
56
+
57
+ - type: input
58
+ id: otherBranch
59
+ attributes:
60
+ label: Branch name
61
+ description: If you selected ```other``` branch for the previous question, what is the branch name?
62
+ placeholder: "what-is-the-name-of-the-branch-you-were-using"
63
+
64
+ - type: input
65
+ id: pythonVersion
66
+ attributes:
67
+ label: Python version
68
+ description: Specify the version of Python you were using when the bug occurred.
69
+ placeholder: "e.g., 3.12.5(64b)"
70
+
71
+ - type: input
72
+ id: llm
73
+ attributes:
74
+ label: LLM Used
75
+ description: Specify the LLM provider you were using when the bug occurred.
76
+ placeholder: "e.g., ChatGPT"
77
+
78
+ - type: input
79
+ id: model
80
+ attributes:
81
+ label: Model used
82
+ description: Specify the LLM model you were using when the bug occurred.
83
+ placeholder: "e.g., GPT-4o-mini"
84
+
85
+ - type: textarea
86
+ id: additional
87
+ attributes:
88
+ label: Additional context
89
+ description: Add any other context about the problem here.
90
+ placeholder: "Any additional information..."
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Questions
4
+ url: https://t.me/AIhawkCommunity
5
+ about: You can join the discussions on Telegram.
6
+ - name: Contributing guide
7
+ url: https://github.com/feder-cr/AIHawk/blob/main/.github/CONTRIBUTING.md
8
+ about: Which repository your issue belongs in, and what to include.
@@ -0,0 +1,39 @@
1
+ name: Documentation request
2
+ description: Suggest improvements or additions to the project's documentation.
3
+ title: "[DOCS]: <Provide a short title>"
4
+ labels: ["documentation"]
5
+ assignees: []
6
+
7
+ body:
8
+ - type: markdown
9
+ attributes:
10
+ value: |
11
+ Thanks for helping to improve the project's documentation! Please provide the following details to ensure your request is clear.
12
+
13
+ - type: input
14
+ id: doc_section
15
+ attributes:
16
+ label: Affected documentation section
17
+ description: Specify which part of the documentation needs improvement or addition.
18
+ placeholder: "e.g., Installation Guide, API Reference..."
19
+
20
+ - type: textarea
21
+ id: description
22
+ attributes:
23
+ label: Documentation improvement description
24
+ description: Describe the specific improvements or additions you suggest.
25
+ placeholder: "Explain what changes you propose and why..."
26
+
27
+ - type: input
28
+ id: reason
29
+ attributes:
30
+ label: Why is this change necessary?
31
+ description: Explain why the documentation needs to be updated or expanded.
32
+ placeholder: "Describe the issue or gap in the documentation..."
33
+
34
+ - type: input
35
+ id: additional
36
+ attributes:
37
+ label: Additional context
38
+ description: Add any other context, such as related documentation, external resources, or screenshots.
39
+ placeholder: "Add any other supporting information..."
@@ -0,0 +1,46 @@
1
+ name: Feature request
2
+ description: Suggest a new feature or improvement for the project.
3
+ title: "[FEATURE]: <Provide a descriptive title>"
4
+ labels: ["enhancement"]
5
+ assignees: []
6
+
7
+ body:
8
+ - type: markdown
9
+ attributes:
10
+ value: |
11
+ Thank you for suggesting a feature! Please fill out the form below to help us understand your idea.
12
+
13
+ - type: input
14
+ id: summary
15
+ attributes:
16
+ label: Feature summary
17
+ description: Provide a short summary of the feature you're requesting.
18
+ placeholder: "Summarize the feature in a few words..."
19
+
20
+ - type: textarea
21
+ id: description
22
+ attributes:
23
+ label: Feature description
24
+ description: A detailed description of the feature or improvement.
25
+ placeholder: "Describe the feature in detail..."
26
+
27
+ - type: input
28
+ id: motivation
29
+ attributes:
30
+ label: Motivation
31
+ description: Explain why this feature would be beneficial and how it solves a problem.
32
+ placeholder: "Why do you need this feature?"
33
+
34
+ - type: textarea
35
+ id: alternatives
36
+ attributes:
37
+ label: Alternatives considered
38
+ description: List any alternative solutions or features you've considered.
39
+ placeholder: "Are there any alternative features or solutions you’ve considered?"
40
+
41
+ - type: input
42
+ id: additional
43
+ attributes:
44
+ label: Additional context
45
+ description: Add any other context or screenshots to support your feature request.
46
+ placeholder: "Any additional information..."
@@ -0,0 +1,69 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ # This repository is public and everything in it is English by rule. The gate
13
+ # is a COPY and not a reference to the one in the sibling packages, on purpose:
14
+ # it scans the tree it is run from, and running a sibling's copy from here
15
+ # silently scans the wrong repository and reports clean. That happened once
16
+ # already, which is why each package carries its own.
17
+ english:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.12"
24
+ - name: the repository is English
25
+ run: |
26
+ python scripts/check_english_only.py --selftest
27
+ python scripts/check_english_only.py
28
+
29
+ test:
30
+ runs-on: ${{ matrix.os }}
31
+ strategy:
32
+ fail-fast: false
33
+ matrix:
34
+ os: [ubuntu-latest, windows-latest]
35
+ python-version: ["3.11", "3.12", "3.13"]
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: actions/setup-python@v5
39
+ with:
40
+ python-version: ${{ matrix.python-version }}
41
+ - name: install and test
42
+ # The default selection excludes `ui`, which drives a real browser: those
43
+ # need an engine download and a machine doing nothing else, and a runner
44
+ # is neither. They are run by hand, serially, before a release.
45
+ run: |
46
+ python -m pip install --upgrade pip
47
+ pip install -e ".[test]"
48
+ python -m pytest -q
49
+
50
+ # This package is published, so the thing that must work is the WHEEL, not the
51
+ # checkout. An editable install can pass every test while the built artifact is
52
+ # missing a module: the tests import from src/ either way, and only a clean
53
+ # install from the wheel can tell the difference.
54
+ build:
55
+ runs-on: ubuntu-latest
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+ - uses: actions/setup-python@v5
59
+ with:
60
+ python-version: "3.12"
61
+ - name: the wheel builds, installs clean, and answers
62
+ run: |
63
+ python -m pip install --upgrade pip
64
+ pip install build
65
+ python -m build --wheel
66
+ python -m venv /tmp/clean
67
+ /tmp/clean/bin/pip install dist/*.whl
68
+ /tmp/clean/bin/aihawk --help
69
+ /tmp/clean/bin/python -c "import aihawk.web, aihawk.brain, aihawk.link, aihawk.cli"
@@ -0,0 +1,109 @@
1
+ name: publish
2
+
3
+ # Publish `aihawk` from a tag via PyPI Trusted Publishing (OIDC), with no
4
+ # long-lived token anywhere. The trust lives in the `pypi` GitHub Environment,
5
+ # minted per run and valid for minutes. Only the `upload` job names that
6
+ # environment, and it declares `needs: gate`, so a red gate means the only job
7
+ # that can authenticate never starts.
8
+ #
9
+ # BEFORE THE FIRST RUN, on PyPI: the name is unregistered, so Your projects will
10
+ # not list it. Use Account -> Publishing -> Add a pending publisher with:
11
+ # PyPI Project Name: aihawk
12
+ # Owner: feder-cr
13
+ # Repository name: AIHawk
14
+ # Workflow name: publish.yml
15
+ # Environment name: pypi
16
+ # Until that exists the upload fails with `invalid-publisher`, which is the
17
+ # correct failure: nothing has said this workflow may speak for this project.
18
+
19
+ on:
20
+ push:
21
+ tags:
22
+ - "v*"
23
+ workflow_dispatch:
24
+
25
+ permissions:
26
+ contents: read
27
+
28
+ jobs:
29
+ already-published:
30
+ runs-on: ubuntu-latest
31
+ outputs:
32
+ present: ${{ steps.probe.outputs.present }}
33
+ version: ${{ steps.probe.outputs.version }}
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - id: probe
37
+ shell: bash
38
+ # Asks the INDEX, not the ledger and not the tag: a re-pushed tag or a
39
+ # backfill is then a logged no-op rather than a red run, and the only
40
+ # answer that stops everything is one that is neither yes nor no.
41
+ run: |
42
+ VERSION="$(grep -m1 '^version = ' pyproject.toml | cut -d'"' -f2)"
43
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
44
+ CODE=$(curl -s -o /dev/null -w '%{http_code}' "https://pypi.org/pypi/aihawk/$VERSION/json")
45
+ case "$CODE" in
46
+ 200) echo "present=yes" >> "$GITHUB_OUTPUT"
47
+ echo "::notice::aihawk $VERSION is already on the index. No-op, not a failure." ;;
48
+ 404) echo "present=no" >> "$GITHUB_OUTPUT" ;;
49
+ *) echo "the index answered $CODE for $VERSION, which is neither present nor absent. Refusing rather than guessing." >&2
50
+ exit 1 ;;
51
+ esac
52
+
53
+ gate:
54
+ needs: already-published
55
+ if: needs.already-published.outputs.present != 'yes'
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ - uses: actions/setup-python@v5
60
+ with:
61
+ python-version: "3.12"
62
+ - name: the tag names the version being built
63
+ if: github.event_name == 'push'
64
+ shell: bash
65
+ run: |
66
+ TAG="${GITHUB_REF_NAME#v}"
67
+ HAVE="${{ needs.already-published.outputs.version }}"
68
+ if [ "$TAG" != "$HAVE" ]; then
69
+ echo "tag v$TAG does not name the version in pyproject.toml ($HAVE)" >&2
70
+ exit 1
71
+ fi
72
+ - name: install and run the suite
73
+ # A tag push does not trigger the ordinary test workflow, which runs on
74
+ # branches and pull requests, so without this a tag could publish code
75
+ # that no job has ever run.
76
+ run: |
77
+ python -m pip install --upgrade pip
78
+ pip install -e ".[test]"
79
+ python -m pytest -q
80
+ - name: the wheel installs into an empty environment and answers
81
+ # The published artifact is a wheel, and the suite above imports from
82
+ # src/ either way. Only a clean install can tell you that the thing
83
+ # about to reach users actually starts.
84
+ run: |
85
+ pip install build
86
+ python -m build --wheel
87
+ python -m venv /tmp/clean
88
+ /tmp/clean/bin/pip install dist/*.whl
89
+ /tmp/clean/bin/aihawk --help
90
+
91
+ upload:
92
+ needs: [already-published, gate]
93
+ if: needs.already-published.outputs.present != 'yes'
94
+ runs-on: ubuntu-latest
95
+ environment: pypi # the OIDC trust relationship lives HERE, behind the gate
96
+ permissions:
97
+ id-token: write # trusted publishing; no token in a secret anywhere
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+ - uses: actions/setup-python@v5
101
+ with:
102
+ python-version: "3.12"
103
+ - run: python -m pip install --upgrade pip build
104
+ - run: python -m build
105
+ - name: twine check
106
+ run: |
107
+ pip install twine
108
+ twine check dist/*
109
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,42 @@
1
+ name: Mark and Close Stale Issues
2
+
3
+ on:
4
+ # Schedule the workflow to run periodically (e.g., daily at 1:30 AM UTC)
5
+ schedule:
6
+ - cron: "30 1 * * *"
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ stale:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ issues: write
14
+ pull-requests: write
15
+
16
+ steps:
17
+ - name: Run Stale Action
18
+ uses: actions/stale@v9
19
+ with:
20
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
21
+ days-before-issue-stale: 10 # Days of inactivity before marking an issue as stale
22
+ days-before-issue-close: 5 # Days after being marked stale before closing the issue
23
+ stale-issue-label: "stale" # Label to apply to stale issues
24
+ exempt-issue-labels: "pinned,important" # Labels to exclude from being marked as stale
25
+ exempt-issue-assignees: true # Exempt issues with assignees from being marked as stale
26
+ stale-issue-message: "This issue has been marked as stale due to inactivity. Please comment or update if this is still relevant."
27
+ close-issue-message: "This issue was closed due to prolonged inactivity."
28
+ days-before-pr-stale: 10 # Days of inactivity before marking a PR as stale
29
+ days-before-pr-close: 2 # Days after being marked stale before closing the PR
30
+ stale-pr-label: "stale" # Label to apply to stale PRs
31
+ exempt-pr-labels: "pinned,important" # Labels to exclude from being marked as stale
32
+ stale-pr-message: >
33
+ "This pull request has been marked as stale due to inactivity.
34
+ To keep it open, you can:
35
+ - Show progress by updating the PR with new commits.
36
+ - Continue the conversation by adding comments or requesting clarification on any blockers.
37
+ - Resolve pending feedback by replying to unresolved comments or implementing suggested changes.
38
+ - Indicate readiness for review by explicitly requesting a review from maintainers or reviewers.
39
+ If no action is taken within 7 days, this pull request will be closed."
40
+ close-pr-message: "This PR was closed due to prolonged inactivity."
41
+ remove-stale-when-updated: true # Remove the stale label if there is new activity
42
+ operations-per-run: 20 # Number of issues to process per run (default is 30)