curupira 0.1.0.dev1__tar.gz → 0.3.0.dev0__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 (148) hide show
  1. curupira-0.3.0.dev0/PKG-INFO +361 -0
  2. curupira-0.3.0.dev0/README.md +326 -0
  3. curupira-0.3.0.dev0/curupira-core/Cargo.lock +2441 -0
  4. curupira-0.3.0.dev0/curupira-core/Cargo.toml +51 -0
  5. curupira-0.3.0.dev0/curupira-core/PROTOCOL.md +81 -0
  6. curupira-0.3.0.dev0/curupira-core/curupira.example.toml +201 -0
  7. curupira-0.3.0.dev0/curupira-core/rust-toolchain.toml +3 -0
  8. curupira-0.3.0.dev0/curupira-core/src/agents/claude.rs +72 -0
  9. curupira-0.3.0.dev0/curupira-core/src/agents/codex.rs +92 -0
  10. curupira-0.3.0.dev0/curupira-core/src/agents/copilot.rs +95 -0
  11. curupira-0.3.0.dev0/curupira-core/src/agents/cursor.rs +80 -0
  12. curupira-0.3.0.dev0/curupira-core/src/agents/gemini.rs +83 -0
  13. curupira-0.3.0.dev0/curupira-core/src/agents/kilo.rs +75 -0
  14. curupira-0.3.0.dev0/curupira-core/src/agents/mod.rs +398 -0
  15. curupira-0.3.0.dev0/curupira-core/src/agents/opencode.rs +128 -0
  16. curupira-0.3.0.dev0/curupira-core/src/agents/pi.rs +106 -0
  17. curupira-0.3.0.dev0/curupira-core/src/agents/profile.rs +111 -0
  18. curupira-0.3.0.dev0/curupira-core/src/agents/qwen.rs +69 -0
  19. curupira-0.3.0.dev0/curupira-core/src/bin/curu.rs +4 -0
  20. curupira-0.3.0.dev0/curupira-core/src/bin/curupira.rs +4 -0
  21. curupira-0.3.0.dev0/curupira-core/src/cli.rs +300 -0
  22. curupira-0.3.0.dev0/curupira-core/src/config.rs +692 -0
  23. curupira-0.3.0.dev0/curupira-core/src/cron.rs +221 -0
  24. curupira-0.3.0.dev0/curupira-core/src/dispatch.rs +432 -0
  25. curupira-0.3.0.dev0/curupira-core/src/error.rs +29 -0
  26. curupira-0.3.0.dev0/curupira-core/src/extensions/bundled.rs +37 -0
  27. curupira-0.3.0.dev0/curupira-core/src/extensions/host.rs +339 -0
  28. curupira-0.3.0.dev0/curupira-core/src/extensions/manager.rs +266 -0
  29. curupira-0.3.0.dev0/curupira-core/src/extensions/mod.rs +8 -0
  30. curupira-0.3.0.dev0/curupira-core/src/extensions/namespace.rs +109 -0
  31. curupira-0.3.0.dev0/curupira-core/src/extensions/registry.rs +220 -0
  32. curupira-0.3.0.dev0/curupira-core/src/extensions/tools.rs +127 -0
  33. curupira-0.3.0.dev0/curupira-core/src/lib.rs +33 -0
  34. curupira-0.3.0.dev0/curupira-core/src/process.rs +165 -0
  35. curupira-0.3.0.dev0/curupira-core/src/protocol/error.rs +62 -0
  36. curupira-0.3.0.dev0/curupira-core/src/protocol/framing.rs +82 -0
  37. curupira-0.3.0.dev0/curupira-core/src/protocol/manifest.rs +172 -0
  38. curupira-0.3.0.dev0/curupira-core/src/protocol/methods.rs +181 -0
  39. curupira-0.3.0.dev0/curupira-core/src/protocol/mod.rs +21 -0
  40. curupira-0.3.0.dev0/curupira-core/src/protocol/version.rs +50 -0
  41. curupira-0.3.0.dev0/curupira-core/src/runtime.rs +121 -0
  42. curupira-0.3.0.dev0/curupira-core/src/storage.rs +276 -0
  43. curupira-0.3.0.dev0/curupira-core/src/vcs.rs +497 -0
  44. curupira-0.3.0.dev0/curupira-core/src/version.rs +4 -0
  45. curupira-0.3.0.dev0/curupira-core/tests/agent_worktree_isolation.rs +67 -0
  46. curupira-0.3.0.dev0/curupira-core/tests/cli_smoke.rs +118 -0
  47. curupira-0.3.0.dev0/curupira-core/tests/fixtures/node-ext/curupira-extension.toml +12 -0
  48. curupira-0.3.0.dev0/curupira-core/tests/fixtures/node-ext/plugin.js +58 -0
  49. curupira-0.3.0.dev0/curupira-core/tests/fixtures/python-ext/curupira-extension.toml +12 -0
  50. curupira-0.3.0.dev0/curupira-core/tests/fixtures/python-ext/plugin.py +67 -0
  51. curupira-0.3.0.dev0/curupira-core/tests/fixtures/ts-ext/curupira-extension.toml +12 -0
  52. curupira-0.3.0.dev0/curupira-core/tests/fixtures/ts-ext/plugin.ts +70 -0
  53. curupira-0.3.0.dev0/curupira-core/tests/protocol_extensions.rs +49 -0
  54. curupira-0.3.0.dev0/pyproject.toml +51 -0
  55. curupira-0.3.0.dev0/src/curupira/__init__.py +12 -0
  56. curupira-0.3.0.dev0/src/curupira/__main__.py +23 -0
  57. curupira-0.1.0.dev1/.gitignore +0 -190
  58. curupira-0.1.0.dev1/CHANGELOG.md +0 -43
  59. curupira-0.1.0.dev1/CONTRIBUTING.md +0 -221
  60. curupira-0.1.0.dev1/LICENSE +0 -21
  61. curupira-0.1.0.dev1/PKG-INFO +0 -324
  62. curupira-0.1.0.dev1/README.md +0 -290
  63. curupira-0.1.0.dev1/SECURITY.md +0 -27
  64. curupira-0.1.0.dev1/crates/curupira-core/Cargo.lock +0 -132
  65. curupira-0.1.0.dev1/crates/curupira-core/Cargo.toml +0 -14
  66. curupira-0.1.0.dev1/crates/curupira-core/src/lib.rs +0 -15
  67. curupira-0.1.0.dev1/curupira.example.toml +0 -92
  68. curupira-0.1.0.dev1/hatch_build.py +0 -100
  69. curupira-0.1.0.dev1/pyproject.toml +0 -142
  70. curupira-0.1.0.dev1/src/curupira/__init__.py +0 -5
  71. curupira-0.1.0.dev1/src/curupira/__main__.py +0 -5
  72. curupira-0.1.0.dev1/src/curupira/_native.pyi +0 -4
  73. curupira-0.1.0.dev1/src/curupira/_version.py +0 -3
  74. curupira-0.1.0.dev1/src/curupira/agents/__init__.py +0 -34
  75. curupira-0.1.0.dev1/src/curupira/agents/base.py +0 -112
  76. curupira-0.1.0.dev1/src/curupira/agents/claude.py +0 -30
  77. curupira-0.1.0.dev1/src/curupira/agents/codex.py +0 -40
  78. curupira-0.1.0.dev1/src/curupira/agents/cursor.py +0 -29
  79. curupira-0.1.0.dev1/src/curupira/agents/opencode.py +0 -30
  80. curupira-0.1.0.dev1/src/curupira/cli.py +0 -260
  81. curupira-0.1.0.dev1/src/curupira/clients/__init__.py +0 -1
  82. curupira-0.1.0.dev1/src/curupira/clients/gh.py +0 -198
  83. curupira-0.1.0.dev1/src/curupira/clients/process.py +0 -133
  84. curupira-0.1.0.dev1/src/curupira/config.py +0 -114
  85. curupira-0.1.0.dev1/src/curupira/dispatcher.py +0 -69
  86. curupira-0.1.0.dev1/src/curupira/errors.py +0 -68
  87. curupira-0.1.0.dev1/src/curupira/executor.py +0 -181
  88. curupira-0.1.0.dev1/src/curupira/models/__init__.py +0 -71
  89. curupira-0.1.0.dev1/src/curupira/models/base.py +0 -15
  90. curupira-0.1.0.dev1/src/curupira/models/configuration.py +0 -285
  91. curupira-0.1.0.dev1/src/curupira/models/github.py +0 -47
  92. curupira-0.1.0.dev1/src/curupira/models/process.py +0 -47
  93. curupira-0.1.0.dev1/src/curupira/models/profiles.py +0 -107
  94. curupira-0.1.0.dev1/src/curupira/models/tasks.py +0 -87
  95. curupira-0.1.0.dev1/src/curupira/native.py +0 -15
  96. curupira-0.1.0.dev1/src/curupira/py.typed +0 -0
  97. curupira-0.1.0.dev1/src/curupira/runtime.py +0 -117
  98. curupira-0.1.0.dev1/src/curupira/scheduler.py +0 -156
  99. curupira-0.1.0.dev1/src/curupira/status.py +0 -53
  100. curupira-0.1.0.dev1/src/curupira/storage/__init__.py +0 -6
  101. curupira-0.1.0.dev1/src/curupira/storage/cron.py +0 -119
  102. curupira-0.1.0.dev1/src/curupira/storage/key_value.py +0 -203
  103. curupira-0.1.0.dev1/src/curupira/storage/sessions.py +0 -29
  104. curupira-0.1.0.dev1/src/curupira/tasks/__init__.py +0 -5
  105. curupira-0.1.0.dev1/src/curupira/tasks/base.py +0 -62
  106. curupira-0.1.0.dev1/src/curupira/tasks/cron.py +0 -144
  107. curupira-0.1.0.dev1/src/curupira/tasks/feed.py +0 -103
  108. curupira-0.1.0.dev1/src/curupira/tasks/github_issues.py +0 -79
  109. curupira-0.1.0.dev1/src/curupira/tasks/github_pull_requests.py +0 -100
  110. curupira-0.1.0.dev1/src/curupira/tasks/registry.py +0 -33
  111. curupira-0.1.0.dev1/src/curupira/telemetry.py +0 -83
  112. curupira-0.1.0.dev1/src/curupira/vcs/__init__.py +0 -5
  113. curupira-0.1.0.dev1/src/curupira/vcs/base.py +0 -200
  114. curupira-0.1.0.dev1/src/curupira/vcs/github_cli.py +0 -19
  115. curupira-0.1.0.dev1/src/gh_dispatch/tasks/__init__.py +0 -1
  116. curupira-0.1.0.dev1/tests/__init__.py +0 -1
  117. curupira-0.1.0.dev1/tests/agents/__init__.py +0 -1
  118. curupira-0.1.0.dev1/tests/agents/test_base.py +0 -95
  119. curupira-0.1.0.dev1/tests/agents/test_claude.py +0 -70
  120. curupira-0.1.0.dev1/tests/agents/test_codex.py +0 -60
  121. curupira-0.1.0.dev1/tests/agents/test_cursor.py +0 -93
  122. curupira-0.1.0.dev1/tests/agents/test_opencode.py +0 -46
  123. curupira-0.1.0.dev1/tests/fakes.py +0 -137
  124. curupira-0.1.0.dev1/tests/helpers.py +0 -55
  125. curupira-0.1.0.dev1/tests/tasks/__init__.py +0 -1
  126. curupira-0.1.0.dev1/tests/tasks/test_base.py +0 -66
  127. curupira-0.1.0.dev1/tests/tasks/test_cron.py +0 -91
  128. curupira-0.1.0.dev1/tests/tasks/test_cron_trigger.py +0 -34
  129. curupira-0.1.0.dev1/tests/tasks/test_feed.py +0 -122
  130. curupira-0.1.0.dev1/tests/tasks/test_github_issues.py +0 -87
  131. curupira-0.1.0.dev1/tests/tasks/test_github_pull_requests.py +0 -106
  132. curupira-0.1.0.dev1/tests/tasks/test_registry.py +0 -79
  133. curupira-0.1.0.dev1/tests/test_cli.py +0 -157
  134. curupira-0.1.0.dev1/tests/test_clients.py +0 -303
  135. curupira-0.1.0.dev1/tests/test_config.py +0 -277
  136. curupira-0.1.0.dev1/tests/test_dispatcher.py +0 -299
  137. curupira-0.1.0.dev1/tests/test_native.py +0 -17
  138. curupira-0.1.0.dev1/tests/test_process.py +0 -123
  139. curupira-0.1.0.dev1/tests/test_runtime.py +0 -76
  140. curupira-0.1.0.dev1/tests/test_scheduler.py +0 -118
  141. curupira-0.1.0.dev1/tests/test_session_repository.py +0 -61
  142. curupira-0.1.0.dev1/tests/test_status.py +0 -57
  143. curupira-0.1.0.dev1/tests/test_tasks.py +0 -69
  144. curupira-0.1.0.dev1/tests/test_telemetry.py +0 -179
  145. curupira-0.1.0.dev1/tests/test_verify_dist_version.py +0 -112
  146. curupira-0.1.0.dev1/tests/vcs/__init__.py +0 -1
  147. curupira-0.1.0.dev1/tests/vcs/test_base.py +0 -150
  148. curupira-0.1.0.dev1/uv.lock +0 -2243
@@ -0,0 +1,361 @@
1
+ Metadata-Version: 2.4
2
+ Name: curupira
3
+ Version: 0.3.0.dev0
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: Environment :: Console
6
+ Classifier: Intended Audience :: Developers
7
+ Classifier: Operating System :: OS Independent
8
+ Classifier: Programming Language :: Python :: 3.11
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Programming Language :: Python :: 3.14
12
+ Classifier: Programming Language :: Rust
13
+ Classifier: Typing :: Typed
14
+ Requires-Dist: curupira-plugins>=0.1.0.dev0 ; extra == 'azure'
15
+ Requires-Dist: curupira-plugins>=0.1.0.dev0 ; extra == 'extensions'
16
+ Requires-Dist: curupira-plugins>=0.1.0.dev0 ; extra == 'github'
17
+ Requires-Dist: curupira-plugins>=0.1.0.dev0 ; extra == 'monday'
18
+ Requires-Dist: curupira-plugins>=0.1.0.dev0 ; extra == 'trello'
19
+ Provides-Extra: azure
20
+ Provides-Extra: extensions
21
+ Provides-Extra: github
22
+ Provides-Extra: monday
23
+ Provides-Extra: trello
24
+ Summary: Dispatch GitHub and cron tasks to local AI coding agents
25
+ Keywords: github,automation,coding-agents,cli,cron
26
+ Author: Mario Taddeucci
27
+ License-Expression: MIT
28
+ Requires-Python: >=3.11
29
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
30
+ Project-URL: Changelog, https://github.com/caipora-labs/curupira/blob/main/CHANGELOG.md
31
+ Project-URL: Homepage, https://github.com/caipora-labs/curupira
32
+ Project-URL: Issues, https://github.com/caipora-labs/curupira/issues
33
+ Project-URL: Repository, https://github.com/caipora-labs/curupira
34
+
35
+ # Curupira
36
+
37
+ **Curupira** (by Caipora Labs) is the product name. The PyPI project, primary console script, and Python import are `curupira`. The short command `curu` is the same entry point.
38
+
39
+ Curupira runs automations on your machine. It takes a GitHub issue or pull request, a Trello card, a monday.com item, or a local cron occurrence, and hands it to a coding-agent CLI you already have.
40
+
41
+ Each automation in the settings TOML watches one source (issues, pull requests, Trello
42
+ cards, monday.com items, or a cron schedule) and carries its own prompt. All automations share one discovery,
43
+ scheduling, and execution pipeline: `run` drains currently available tasks, while
44
+ `run --watch` polls every automation continuously.
45
+
46
+ ## Requirements
47
+
48
+ - A supported platform wheel from PyPI (the CLI is a Rust binary; Python 3.11+ is
49
+ used for packaging and optional official trigger extras)
50
+ - [`gh`](https://cli.github.com/) installed and authenticated (`gh auth login`) when
51
+ using GitHub automations
52
+ - Only the CLIs used by the configured profiles need to be installed:
53
+ [`claude`](https://code.claude.com/docs/en/cli-reference),
54
+ [`codex`](https://developers.openai.com/codex/cli/), the Cursor CLI (`agent`),
55
+ [`gemini`](https://github.com/google-gemini/gemini-cli),
56
+ [GitHub Copilot CLI (`copilot`)](https://docs.github.com/en/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli),
57
+ [`kilo`](https://kilo.ai/docs/code-with-ai/platforms/cli),
58
+ [`opencode`](https://opencode.ai/), [`pi`](https://pi.dev/docs/latest), or
59
+ [`qwen`](https://github.com/QwenLM/qwen-code)
60
+ - For Trello automations, install and authenticate the
61
+ [Scale-Flow `trello-cli`](https://github.com/Scale-Flow/trello-cli).
62
+ - For monday.com automations, set a personal API token in `MONDAY_API_TOKEN` (or the
63
+ environment variable named by `token_env`); see the
64
+ [monday.com task source guide](https://caipora-labs.github.io/curupira/monday/).
65
+
66
+ ## Installation
67
+
68
+ Install the published package from PyPI (ships the Rust CLI only):
69
+
70
+ ```bash
71
+ uv tool install curupira
72
+ # or
73
+ pip install curupira
74
+ ```
75
+
76
+ Official triggers (`curupira-plugins`) and `curupira-sdk` are optional. Install them when
77
+ you need forge task sources:
78
+
79
+ ```bash
80
+ pip install 'curupira[extensions]' # installs curupira-plugins (+ curupira-sdk)
81
+ pip install 'curupira[github]' # same package; forge-named extras are aliases
82
+ ```
83
+
84
+ To pin a specific version, use `uv tool install "curupira==X.Y.Z"`.
85
+
86
+ The project is [caipora-labs/curupira](https://github.com/caipora-labs/curupira).
87
+ `curupira --version` and the short alias `curu --version` report the installed version.
88
+ Task-source extensions (except built-in cron) are separate processes; coding agents are
89
+ built into the Rust CLI. See
90
+ [Process extensions](https://caipora-labs.github.io/curupira/extensions/).
91
+
92
+ ## Documentation
93
+
94
+ See the [full guide in Portuguese](https://caipora-labs.github.io/curupira/) for
95
+ installation, automation configuration, providers, and operational commands. Newcomers
96
+ can start with the
97
+ [automations reference](https://caipora-labs.github.io/curupira/automations/)
98
+ (triggers, minimal TOML examples, first-run commands, and common errors).
99
+
100
+ ## Configuration
101
+
102
+ The default settings file is `~/.curupira/settings.toml`. Download the example
103
+ configuration directly to that location, then adjust repositories, paths, queries, and
104
+ prompts:
105
+
106
+ ```bash
107
+ mkdir -p ~/.curupira
108
+ curl -fsSL https://raw.githubusercontent.com/caipora-labs/curupira/main/packages/curupira-core/curupira.example.toml \
109
+ -o ~/.curupira/settings.toml
110
+ ```
111
+
112
+ The `~/.curupira` directory is created automatically when the default file is first
113
+ loaded. Pass `--config path/to/settings.toml` to use a different file; relative workspace,
114
+ state, and automation paths are resolved from that file's directory.
115
+
116
+ ```toml
117
+ [settings]
118
+ max_active_tasks = 1
119
+ workspace_dir = "~/.curupira/workspaces"
120
+ state_db_path = "~/.curupira/state.sqlite3"
121
+ log_level = "INFO"
122
+ # Optional OTLP/HTTP trace endpoint; omit it to disable telemetry.
123
+ # otlp_endpoint = "http://localhost:4318/v1/traces"
124
+
125
+ [settings.polling]
126
+ poll_interval_seconds = 30
127
+ batch_size = 100
128
+ cron_poll_interval_seconds = 1
129
+
130
+ [repositories.api]
131
+ remote = "https://github.com/acme/api.git"
132
+ # setup_script = "scripts/bootstrap.sh"
133
+
134
+ [agents.defaults]
135
+ profile = "opencode-default"
136
+ timezone = "UTC"
137
+
138
+ [agents.profiles.opencode-default]
139
+ provider = "opencode"
140
+
141
+ [automations.resolve-ready-issues]
142
+ trigger_type = "plugins-py/github-issues"
143
+ repository = "api"
144
+ repo = "acme/api"
145
+ labels = ["agent-ready"]
146
+ linked_pull_request = false
147
+ prompt = "Resolve issue ${issue_number}: ${issue_title}\n\n${issue_body}"
148
+ ```
149
+
150
+ ### Automations
151
+
152
+ For a newcomer-oriented map of every built-in trigger (minimal TOML, placeholders, and
153
+ first-run commands), see the
154
+ [automations reference](https://caipora-labs.github.io/curupira/automations/).
155
+
156
+ `[automations.<name>]` is a keyed map; the map key is the automation ID and is carried
157
+ into every task identity. `repository` selects a `[repositories.<alias>]` checkout with a
158
+ full Git `remote` URL (and optional `path` / `setup_script`). `trigger_type` selects the
159
+ source:
160
+
161
+ - `"plugins-py/github-issues"` / `"plugins-py/github-pull-requests"` — discover matching GitHub issues and pull
162
+ requests; see the
163
+ [GitHub task source guide](https://caipora-labs.github.io/curupira/github/)
164
+ - `"azure_cli_pull_requests"` — lists Azure DevOps pull requests with `az repos pr list`
165
+ - `"trello_cli_cards"` — discovers cards from a configured board with Scale-Flow's `trello-cli`
166
+ - `"monday_items"` — discovers board items through the monday.com GraphQL API; see the
167
+ [monday.com task source guide](https://caipora-labs.github.io/curupira/monday/)
168
+ - `"cron"` — produces occurrences from `schedule` instead of querying a forge
169
+
170
+ Every automation requires `repository` and `prompt`. GitHub/Azure triggers also require
171
+ forge `repo` identity; cron requires `schedule`. Trello automations require `board_id` and
172
+ optionally accept `list_ids`; see the
173
+ [Trello task source guide](https://caipora-labs.github.io/curupira/trello/).
174
+ monday.com automations require `board_id` and a token in `token_env` (default
175
+ `MONDAY_API_TOKEN`), and optionally accept `group_ids`.
176
+ For Azure DevOps, forge `repo` uses `organization/project/repository` (organization name,
177
+ not a full URL). Optional `status` (`active` by default), `source_branch`, and
178
+ `target_branch` filter the Azure list. Optional `profile` selects a named CLI profile;
179
+ otherwise the default profile applies. Relative paths resolve from the TOML directory.
180
+ Different repository aliases cannot share one workspace path. Automations keep file order,
181
+ and one-shot selection follows that order.
182
+
183
+ ### Providers and native options
184
+
185
+ Curupira supports these coding-agent CLIs, selected with `provider` in a profile:
186
+
187
+ - Claude Code (`claude`)
188
+ - Codex (`codex`)
189
+ - Cursor (`cursor`)
190
+ - Kilo CLI (`kilo`)
191
+ - Gemini CLI (`gemini`)
192
+ - GitHub Copilot CLI (`copilot`)
193
+ - OpenCode (`opencode`)
194
+ - [pi (`pi`)](https://caipora-labs.github.io/curupira/providers/pi/)
195
+ - [Qwen Code (`qwen`)](https://caipora-labs.github.io/curupira/providers/qwen/)
196
+
197
+ How `model`, `effort`, `agent`, and permission options map to each CLI's native
198
+ arguments is documented on the
199
+ [Providers page](https://caipora-labs.github.io/curupira/providers/).
200
+
201
+ ### Prompts and placeholders
202
+
203
+ Placeholders use `${name}` syntax and are validated when the configuration loads.
204
+ Common fields: `${repo}`, `${repository}`, `${automation_id}`, `${task_type}`,
205
+ `${task_number}`, `${task_title}`, `${task_body}`, `${task_url}`. Trello cards add `${card_id}`,
206
+ `${card_title}`, `${card_body}`, `${card_url}`, `${card_list_id}`. monday.com items add
207
+ `${item_id}`, `${item_name}`, `${item_url}`, and related fields listed in the
208
+ [monday.com task source guide](https://caipora-labs.github.io/curupira/monday/).
209
+ GitHub issue and pull-request placeholders are listed in the
210
+ [GitHub task source guide](https://caipora-labs.github.io/curupira/github/).
211
+ For cron tasks, `${task_number}` is the occurrence timestamp.
212
+
213
+ ### Discovery, concurrency, and cron semantics
214
+
215
+ GitHub discovery compiles typed filters into Search queries and runs them through GraphQL
216
+ with a token from `gh auth token`; see the
217
+ [GitHub task source guide](https://caipora-labs.github.io/curupira/github/) for filters,
218
+ deduplication, scopes, and prompt fields. Polls fetch up to `batch_size` items (default 100,
219
+ up to 1000). When a full cycle finds nothing, the shared poller waits
220
+ `poll_interval_seconds` (default 30s); consecutive empty cycles double the wait up to
221
+ 5 minutes, and any discovery resets it. Each automation deduplicates its own items, so
222
+ two automations may process the same forge item with different prompts.
223
+
224
+ Other task sources can be added as trigger plugins registered under the
225
+ `curupira.triggers` entry-point group; see the
226
+ [plugins guide](https://github.com/caipora-labs/curupira/blob/main/docs/en/plugins.md).
227
+
228
+ `max_active_tasks` bounds concurrently running coding agents (default 1). By default,
229
+ each task runs in a new worktree beside its base checkout, so tasks for the same repository
230
+ can run concurrently without sharing edits. The worktree branch is created from the
231
+ fetched remote default branch and is not pushed. Set `checkout = "main"` to use the
232
+ shared checkout instead (this means the shared checkout, not a branch named `main`, and
233
+ restores the previous exclusive behavior). `path` continues to select the base checkout.
234
+ With `checkout = "main"`, the agent runs on the shared checkout exactly as it is: Curupira does not fetch, pull, or switch branches there.
235
+ Checkouts are created on demand with `git clone <remote>` under
236
+ `workspace_dir/<repository-alias>` (or the alias `path`).
237
+
238
+ An optional `setup_script` on the repository alias is a repository-relative executable
239
+ path (no absolute paths or `..`). It runs directly, with the checkout root as its working
240
+ directory, only when the base checkout has just been cloned. It does not run for an
241
+ existing checkout or in the task worktree. Use `checkout = "main"` when the agent must run
242
+ where setup wrote files. A nonzero setup exit prevents the agent from starting; the newly
243
+ cloned checkout is removed, while an existing checkout is preserved. `validate` checks the
244
+ path syntax but does not require the script to exist. `run --dry-run` does not fetch, clone,
245
+ create a worktree, or run setup.
246
+
247
+ Each cron automation coalesces overdue ticks into a single pending occurrence; the same
248
+ automation never runs concurrently with itself. `schedule` is a five-field cron
249
+ expression, `timezone` is IANA (defaulting to `agents.defaults.timezone`), and
250
+ `start_date`/`end_date` form an optional inclusive window interpreted in that timezone.
251
+ Without `start_date`, the window starts when the automation is first recorded.
252
+
253
+ ### OpenTelemetry
254
+
255
+ Set `settings.otlp_endpoint` to an OTLP/HTTP trace endpoint (for example,
256
+ `http://localhost:4318/v1/traces`) to export one span for each dispatched issue, pull
257
+ request, or cron occurrence. Each span includes the repository, type, identifier, and
258
+ result (success or failure); failures also include `error.message`. The endpoint must
259
+ accept OTLP over HTTP/protobuf. If the field is omitted, no telemetry is exported.
260
+
261
+ ### State files
262
+
263
+ Running sessions and cron schedule state live in `state_db_path` (default
264
+ `~/.curupira/state.sqlite3`). The per-user dispatch lock is stored in
265
+ `~/.curupira/dispatch.lock`, and the dedicated log directory is
266
+ `~/.curupira/logs`. Only one `run` or `tui` process can dispatch at a time; a second
267
+ process exits with an error rather than running tasks in parallel. Session records are
268
+ removed when the agent process ends; `run` and `run --watch` resume saved sessions after
269
+ a restart. If the file exists but is not a compatible database, the application exits with
270
+ an error instead of deleting it — delete or move the file yourself to start fresh.
271
+
272
+ ### Log file
273
+
274
+ The `run` and `run --watch` commands append records to
275
+ `~/.curupira/logs/curupira.log`; restarting the process does not erase existing
276
+ content. Each task records its start and completion time, repository, type, and
277
+ identifier. If a task fails, the record includes the error. Set
278
+ `[settings].log_level` (or pass `--log-level`) to `DEBUG` for more internal detail.
279
+ Uncaught crashes write separate reports under `~/.curupira/logs/crashes/`.
280
+
281
+ ## Usage
282
+
283
+ Validate configuration without calling external CLIs or writing state:
284
+
285
+ ```bash
286
+ curupira validate
287
+ ```
288
+
289
+ Drain currently available tasks through the shared scheduler:
290
+
291
+ ```bash
292
+ curupira run
293
+ curupira run --size 5
294
+ ```
295
+
296
+ Preview one selected task without reserving, persisting, cloning, or executing:
297
+
298
+ ```bash
299
+ curupira run --dry-run
300
+ ```
301
+
302
+ Poll all automations with the shared bounded scheduler until interrupted:
303
+
304
+ ```bash
305
+ curupira run --watch
306
+ ```
307
+
308
+ Run the same continuous scheduler inside an interactive Textual dashboard:
309
+
310
+ ```bash
311
+ curupira tui
312
+ ```
313
+
314
+ The short alias `curu` accepts the same subcommands (`curu validate`, `curu run`,
315
+ `curu run --watch`, `curu tui`).
316
+
317
+ `validate` exits `0` when the configuration is valid and `2` on configuration errors.
318
+ `run`, `run --watch`, and `tui` exit `1` when any executed task failed, otherwise `0`.
319
+ `run --dry-run` never reserves or persists cron occurrences and does not perform checkout,
320
+ worktree, or setup operations.
321
+
322
+ `run --watch` runs every CLI non-interactively so concurrent workers never contend for the
323
+ terminal UI. `tui` is the interactive alternative. Editing the configuration file while
324
+ either is running hot-reloads settings after in-flight tasks finish. Transient `gh`
325
+ failures are retried with backoff; authentication, configuration, output-format, and
326
+ agent-task failures are not retried automatically.
327
+
328
+ ## Public interface
329
+
330
+ Curupira is CLI-first. The only supported programmatic surface is
331
+ `curupira.__version__`; all other modules are internal implementation details that
332
+ may change without notice.
333
+
334
+ ## Development and validation
335
+
336
+ ```bash
337
+ uv sync --dev
338
+ uv run --no-sync prek install
339
+ uv run --no-sync pytest
340
+ uv run --no-sync ruff check .
341
+ uv run --no-sync ruff format --check .
342
+ uv run --no-sync pyrefly check
343
+ uv build
344
+ uv run --no-sync twine check dist/*
345
+ ```
346
+
347
+ `uv sync` installs the pure-Python package. `uv run --no-sync prek install` registers
348
+ Git pre-commit hooks; Ruff and Pyrefly run through `uv` so they use the locked project
349
+ environment. `uv build` produces a `py3-none-any` wheel and sdist with no compiler
350
+ toolchain required.
351
+
352
+ To inspect branch coverage locally, run `uv run --no-sync pytest --cov --cov-report=term-missing`;
353
+ the configured minimum is 85%.
354
+
355
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for environment setup and the exact verification
356
+ commands, and [CHANGELOG.md](CHANGELOG.md) for release notes.
357
+
358
+ ## License
359
+
360
+ MIT — see [LICENSE](LICENSE).
361
+
@@ -0,0 +1,326 @@
1
+ # Curupira
2
+
3
+ **Curupira** (by Caipora Labs) is the product name. The PyPI project, primary console script, and Python import are `curupira`. The short command `curu` is the same entry point.
4
+
5
+ Curupira runs automations on your machine. It takes a GitHub issue or pull request, a Trello card, a monday.com item, or a local cron occurrence, and hands it to a coding-agent CLI you already have.
6
+
7
+ Each automation in the settings TOML watches one source (issues, pull requests, Trello
8
+ cards, monday.com items, or a cron schedule) and carries its own prompt. All automations share one discovery,
9
+ scheduling, and execution pipeline: `run` drains currently available tasks, while
10
+ `run --watch` polls every automation continuously.
11
+
12
+ ## Requirements
13
+
14
+ - A supported platform wheel from PyPI (the CLI is a Rust binary; Python 3.11+ is
15
+ used for packaging and optional official trigger extras)
16
+ - [`gh`](https://cli.github.com/) installed and authenticated (`gh auth login`) when
17
+ using GitHub automations
18
+ - Only the CLIs used by the configured profiles need to be installed:
19
+ [`claude`](https://code.claude.com/docs/en/cli-reference),
20
+ [`codex`](https://developers.openai.com/codex/cli/), the Cursor CLI (`agent`),
21
+ [`gemini`](https://github.com/google-gemini/gemini-cli),
22
+ [GitHub Copilot CLI (`copilot`)](https://docs.github.com/en/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli),
23
+ [`kilo`](https://kilo.ai/docs/code-with-ai/platforms/cli),
24
+ [`opencode`](https://opencode.ai/), [`pi`](https://pi.dev/docs/latest), or
25
+ [`qwen`](https://github.com/QwenLM/qwen-code)
26
+ - For Trello automations, install and authenticate the
27
+ [Scale-Flow `trello-cli`](https://github.com/Scale-Flow/trello-cli).
28
+ - For monday.com automations, set a personal API token in `MONDAY_API_TOKEN` (or the
29
+ environment variable named by `token_env`); see the
30
+ [monday.com task source guide](https://caipora-labs.github.io/curupira/monday/).
31
+
32
+ ## Installation
33
+
34
+ Install the published package from PyPI (ships the Rust CLI only):
35
+
36
+ ```bash
37
+ uv tool install curupira
38
+ # or
39
+ pip install curupira
40
+ ```
41
+
42
+ Official triggers (`curupira-plugins`) and `curupira-sdk` are optional. Install them when
43
+ you need forge task sources:
44
+
45
+ ```bash
46
+ pip install 'curupira[extensions]' # installs curupira-plugins (+ curupira-sdk)
47
+ pip install 'curupira[github]' # same package; forge-named extras are aliases
48
+ ```
49
+
50
+ To pin a specific version, use `uv tool install "curupira==X.Y.Z"`.
51
+
52
+ The project is [caipora-labs/curupira](https://github.com/caipora-labs/curupira).
53
+ `curupira --version` and the short alias `curu --version` report the installed version.
54
+ Task-source extensions (except built-in cron) are separate processes; coding agents are
55
+ built into the Rust CLI. See
56
+ [Process extensions](https://caipora-labs.github.io/curupira/extensions/).
57
+
58
+ ## Documentation
59
+
60
+ See the [full guide in Portuguese](https://caipora-labs.github.io/curupira/) for
61
+ installation, automation configuration, providers, and operational commands. Newcomers
62
+ can start with the
63
+ [automations reference](https://caipora-labs.github.io/curupira/automations/)
64
+ (triggers, minimal TOML examples, first-run commands, and common errors).
65
+
66
+ ## Configuration
67
+
68
+ The default settings file is `~/.curupira/settings.toml`. Download the example
69
+ configuration directly to that location, then adjust repositories, paths, queries, and
70
+ prompts:
71
+
72
+ ```bash
73
+ mkdir -p ~/.curupira
74
+ curl -fsSL https://raw.githubusercontent.com/caipora-labs/curupira/main/packages/curupira-core/curupira.example.toml \
75
+ -o ~/.curupira/settings.toml
76
+ ```
77
+
78
+ The `~/.curupira` directory is created automatically when the default file is first
79
+ loaded. Pass `--config path/to/settings.toml` to use a different file; relative workspace,
80
+ state, and automation paths are resolved from that file's directory.
81
+
82
+ ```toml
83
+ [settings]
84
+ max_active_tasks = 1
85
+ workspace_dir = "~/.curupira/workspaces"
86
+ state_db_path = "~/.curupira/state.sqlite3"
87
+ log_level = "INFO"
88
+ # Optional OTLP/HTTP trace endpoint; omit it to disable telemetry.
89
+ # otlp_endpoint = "http://localhost:4318/v1/traces"
90
+
91
+ [settings.polling]
92
+ poll_interval_seconds = 30
93
+ batch_size = 100
94
+ cron_poll_interval_seconds = 1
95
+
96
+ [repositories.api]
97
+ remote = "https://github.com/acme/api.git"
98
+ # setup_script = "scripts/bootstrap.sh"
99
+
100
+ [agents.defaults]
101
+ profile = "opencode-default"
102
+ timezone = "UTC"
103
+
104
+ [agents.profiles.opencode-default]
105
+ provider = "opencode"
106
+
107
+ [automations.resolve-ready-issues]
108
+ trigger_type = "plugins-py/github-issues"
109
+ repository = "api"
110
+ repo = "acme/api"
111
+ labels = ["agent-ready"]
112
+ linked_pull_request = false
113
+ prompt = "Resolve issue ${issue_number}: ${issue_title}\n\n${issue_body}"
114
+ ```
115
+
116
+ ### Automations
117
+
118
+ For a newcomer-oriented map of every built-in trigger (minimal TOML, placeholders, and
119
+ first-run commands), see the
120
+ [automations reference](https://caipora-labs.github.io/curupira/automations/).
121
+
122
+ `[automations.<name>]` is a keyed map; the map key is the automation ID and is carried
123
+ into every task identity. `repository` selects a `[repositories.<alias>]` checkout with a
124
+ full Git `remote` URL (and optional `path` / `setup_script`). `trigger_type` selects the
125
+ source:
126
+
127
+ - `"plugins-py/github-issues"` / `"plugins-py/github-pull-requests"` — discover matching GitHub issues and pull
128
+ requests; see the
129
+ [GitHub task source guide](https://caipora-labs.github.io/curupira/github/)
130
+ - `"azure_cli_pull_requests"` — lists Azure DevOps pull requests with `az repos pr list`
131
+ - `"trello_cli_cards"` — discovers cards from a configured board with Scale-Flow's `trello-cli`
132
+ - `"monday_items"` — discovers board items through the monday.com GraphQL API; see the
133
+ [monday.com task source guide](https://caipora-labs.github.io/curupira/monday/)
134
+ - `"cron"` — produces occurrences from `schedule` instead of querying a forge
135
+
136
+ Every automation requires `repository` and `prompt`. GitHub/Azure triggers also require
137
+ forge `repo` identity; cron requires `schedule`. Trello automations require `board_id` and
138
+ optionally accept `list_ids`; see the
139
+ [Trello task source guide](https://caipora-labs.github.io/curupira/trello/).
140
+ monday.com automations require `board_id` and a token in `token_env` (default
141
+ `MONDAY_API_TOKEN`), and optionally accept `group_ids`.
142
+ For Azure DevOps, forge `repo` uses `organization/project/repository` (organization name,
143
+ not a full URL). Optional `status` (`active` by default), `source_branch`, and
144
+ `target_branch` filter the Azure list. Optional `profile` selects a named CLI profile;
145
+ otherwise the default profile applies. Relative paths resolve from the TOML directory.
146
+ Different repository aliases cannot share one workspace path. Automations keep file order,
147
+ and one-shot selection follows that order.
148
+
149
+ ### Providers and native options
150
+
151
+ Curupira supports these coding-agent CLIs, selected with `provider` in a profile:
152
+
153
+ - Claude Code (`claude`)
154
+ - Codex (`codex`)
155
+ - Cursor (`cursor`)
156
+ - Kilo CLI (`kilo`)
157
+ - Gemini CLI (`gemini`)
158
+ - GitHub Copilot CLI (`copilot`)
159
+ - OpenCode (`opencode`)
160
+ - [pi (`pi`)](https://caipora-labs.github.io/curupira/providers/pi/)
161
+ - [Qwen Code (`qwen`)](https://caipora-labs.github.io/curupira/providers/qwen/)
162
+
163
+ How `model`, `effort`, `agent`, and permission options map to each CLI's native
164
+ arguments is documented on the
165
+ [Providers page](https://caipora-labs.github.io/curupira/providers/).
166
+
167
+ ### Prompts and placeholders
168
+
169
+ Placeholders use `${name}` syntax and are validated when the configuration loads.
170
+ Common fields: `${repo}`, `${repository}`, `${automation_id}`, `${task_type}`,
171
+ `${task_number}`, `${task_title}`, `${task_body}`, `${task_url}`. Trello cards add `${card_id}`,
172
+ `${card_title}`, `${card_body}`, `${card_url}`, `${card_list_id}`. monday.com items add
173
+ `${item_id}`, `${item_name}`, `${item_url}`, and related fields listed in the
174
+ [monday.com task source guide](https://caipora-labs.github.io/curupira/monday/).
175
+ GitHub issue and pull-request placeholders are listed in the
176
+ [GitHub task source guide](https://caipora-labs.github.io/curupira/github/).
177
+ For cron tasks, `${task_number}` is the occurrence timestamp.
178
+
179
+ ### Discovery, concurrency, and cron semantics
180
+
181
+ GitHub discovery compiles typed filters into Search queries and runs them through GraphQL
182
+ with a token from `gh auth token`; see the
183
+ [GitHub task source guide](https://caipora-labs.github.io/curupira/github/) for filters,
184
+ deduplication, scopes, and prompt fields. Polls fetch up to `batch_size` items (default 100,
185
+ up to 1000). When a full cycle finds nothing, the shared poller waits
186
+ `poll_interval_seconds` (default 30s); consecutive empty cycles double the wait up to
187
+ 5 minutes, and any discovery resets it. Each automation deduplicates its own items, so
188
+ two automations may process the same forge item with different prompts.
189
+
190
+ Other task sources can be added as trigger plugins registered under the
191
+ `curupira.triggers` entry-point group; see the
192
+ [plugins guide](https://github.com/caipora-labs/curupira/blob/main/docs/en/plugins.md).
193
+
194
+ `max_active_tasks` bounds concurrently running coding agents (default 1). By default,
195
+ each task runs in a new worktree beside its base checkout, so tasks for the same repository
196
+ can run concurrently without sharing edits. The worktree branch is created from the
197
+ fetched remote default branch and is not pushed. Set `checkout = "main"` to use the
198
+ shared checkout instead (this means the shared checkout, not a branch named `main`, and
199
+ restores the previous exclusive behavior). `path` continues to select the base checkout.
200
+ With `checkout = "main"`, the agent runs on the shared checkout exactly as it is: Curupira does not fetch, pull, or switch branches there.
201
+ Checkouts are created on demand with `git clone <remote>` under
202
+ `workspace_dir/<repository-alias>` (or the alias `path`).
203
+
204
+ An optional `setup_script` on the repository alias is a repository-relative executable
205
+ path (no absolute paths or `..`). It runs directly, with the checkout root as its working
206
+ directory, only when the base checkout has just been cloned. It does not run for an
207
+ existing checkout or in the task worktree. Use `checkout = "main"` when the agent must run
208
+ where setup wrote files. A nonzero setup exit prevents the agent from starting; the newly
209
+ cloned checkout is removed, while an existing checkout is preserved. `validate` checks the
210
+ path syntax but does not require the script to exist. `run --dry-run` does not fetch, clone,
211
+ create a worktree, or run setup.
212
+
213
+ Each cron automation coalesces overdue ticks into a single pending occurrence; the same
214
+ automation never runs concurrently with itself. `schedule` is a five-field cron
215
+ expression, `timezone` is IANA (defaulting to `agents.defaults.timezone`), and
216
+ `start_date`/`end_date` form an optional inclusive window interpreted in that timezone.
217
+ Without `start_date`, the window starts when the automation is first recorded.
218
+
219
+ ### OpenTelemetry
220
+
221
+ Set `settings.otlp_endpoint` to an OTLP/HTTP trace endpoint (for example,
222
+ `http://localhost:4318/v1/traces`) to export one span for each dispatched issue, pull
223
+ request, or cron occurrence. Each span includes the repository, type, identifier, and
224
+ result (success or failure); failures also include `error.message`. The endpoint must
225
+ accept OTLP over HTTP/protobuf. If the field is omitted, no telemetry is exported.
226
+
227
+ ### State files
228
+
229
+ Running sessions and cron schedule state live in `state_db_path` (default
230
+ `~/.curupira/state.sqlite3`). The per-user dispatch lock is stored in
231
+ `~/.curupira/dispatch.lock`, and the dedicated log directory is
232
+ `~/.curupira/logs`. Only one `run` or `tui` process can dispatch at a time; a second
233
+ process exits with an error rather than running tasks in parallel. Session records are
234
+ removed when the agent process ends; `run` and `run --watch` resume saved sessions after
235
+ a restart. If the file exists but is not a compatible database, the application exits with
236
+ an error instead of deleting it — delete or move the file yourself to start fresh.
237
+
238
+ ### Log file
239
+
240
+ The `run` and `run --watch` commands append records to
241
+ `~/.curupira/logs/curupira.log`; restarting the process does not erase existing
242
+ content. Each task records its start and completion time, repository, type, and
243
+ identifier. If a task fails, the record includes the error. Set
244
+ `[settings].log_level` (or pass `--log-level`) to `DEBUG` for more internal detail.
245
+ Uncaught crashes write separate reports under `~/.curupira/logs/crashes/`.
246
+
247
+ ## Usage
248
+
249
+ Validate configuration without calling external CLIs or writing state:
250
+
251
+ ```bash
252
+ curupira validate
253
+ ```
254
+
255
+ Drain currently available tasks through the shared scheduler:
256
+
257
+ ```bash
258
+ curupira run
259
+ curupira run --size 5
260
+ ```
261
+
262
+ Preview one selected task without reserving, persisting, cloning, or executing:
263
+
264
+ ```bash
265
+ curupira run --dry-run
266
+ ```
267
+
268
+ Poll all automations with the shared bounded scheduler until interrupted:
269
+
270
+ ```bash
271
+ curupira run --watch
272
+ ```
273
+
274
+ Run the same continuous scheduler inside an interactive Textual dashboard:
275
+
276
+ ```bash
277
+ curupira tui
278
+ ```
279
+
280
+ The short alias `curu` accepts the same subcommands (`curu validate`, `curu run`,
281
+ `curu run --watch`, `curu tui`).
282
+
283
+ `validate` exits `0` when the configuration is valid and `2` on configuration errors.
284
+ `run`, `run --watch`, and `tui` exit `1` when any executed task failed, otherwise `0`.
285
+ `run --dry-run` never reserves or persists cron occurrences and does not perform checkout,
286
+ worktree, or setup operations.
287
+
288
+ `run --watch` runs every CLI non-interactively so concurrent workers never contend for the
289
+ terminal UI. `tui` is the interactive alternative. Editing the configuration file while
290
+ either is running hot-reloads settings after in-flight tasks finish. Transient `gh`
291
+ failures are retried with backoff; authentication, configuration, output-format, and
292
+ agent-task failures are not retried automatically.
293
+
294
+ ## Public interface
295
+
296
+ Curupira is CLI-first. The only supported programmatic surface is
297
+ `curupira.__version__`; all other modules are internal implementation details that
298
+ may change without notice.
299
+
300
+ ## Development and validation
301
+
302
+ ```bash
303
+ uv sync --dev
304
+ uv run --no-sync prek install
305
+ uv run --no-sync pytest
306
+ uv run --no-sync ruff check .
307
+ uv run --no-sync ruff format --check .
308
+ uv run --no-sync pyrefly check
309
+ uv build
310
+ uv run --no-sync twine check dist/*
311
+ ```
312
+
313
+ `uv sync` installs the pure-Python package. `uv run --no-sync prek install` registers
314
+ Git pre-commit hooks; Ruff and Pyrefly run through `uv` so they use the locked project
315
+ environment. `uv build` produces a `py3-none-any` wheel and sdist with no compiler
316
+ toolchain required.
317
+
318
+ To inspect branch coverage locally, run `uv run --no-sync pytest --cov --cov-report=term-missing`;
319
+ the configured minimum is 85%.
320
+
321
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for environment setup and the exact verification
322
+ commands, and [CHANGELOG.md](CHANGELOG.md) for release notes.
323
+
324
+ ## License
325
+
326
+ MIT — see [LICENSE](LICENSE).