crewforge 0.2.0__tar.gz → 0.2.2__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.
- {crewforge-0.2.0/src/crewforge.egg-info → crewforge-0.2.2}/PKG-INFO +101 -57
- {crewforge-0.2.0 → crewforge-0.2.2}/README.md +86 -53
- {crewforge-0.2.0 → crewforge-0.2.2}/pyproject.toml +46 -4
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/__init__.py +1 -1
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/citations.py +3 -2
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/cli.py +15 -6
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/language.py +3 -1
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/agents.py +3 -1
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/docs/agents.py +6 -4
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/docs/ingest.py +2 -2
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/docs/pipeline.py +13 -7
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/review/agents.py +2 -2
- {crewforge-0.2.0 → crewforge-0.2.2/src/crewforge.egg-info}/PKG-INFO +101 -57
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge.egg-info/requires.txt +2 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/LICENSE +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/setup.cfg +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/__main__.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/cli.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/cli_support.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/core/__init__.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/core/agent.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/core/client.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/core/config.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/core/crew.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/core/errors.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/core/parsing.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/core/providers.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/core/usage.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/py.typed +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/__init__.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/__init__.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/agents.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/disclosure.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/locales/en.yaml +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/locales/ms.yaml +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/pipeline.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/report.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/academic/settings.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/__init__.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/analytics.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/appcheck.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/cli.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/formatters.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/generator.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/pipeline.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/scaffold.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/docker-compose.j2 +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/dockerfile.j2 +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/env.example.j2 +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/fastapi_main.j2 +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/model.j2 +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/requirements.j2 +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/route.j2 +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/test.j2 +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/api/utils.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/content/__init__.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/content/agents.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/content/cli.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/content/export.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/content/pipeline.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/content/settings.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/content/text.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/docs/__init__.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/docs/cli.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/docs/export.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/docs/index.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/docs/retrieve.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/docs/settings.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/review/__init__.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/review/cli.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/review/pipeline.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/review/report.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge/recipes/review/sources.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge.egg-info/SOURCES.txt +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge.egg-info/dependency_links.txt +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge.egg-info/entry_points.txt +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/src/crewforge.egg-info/top_level.txt +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/tests/test_honest_failure_e2e.py +0 -0
- {crewforge-0.2.0 → crewforge-0.2.2}/tests/test_readme.py +0 -0
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crewforge
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: One crew of LLM agents, five recipes: code review, document Q&A, API scaffolding, content and honest academic-writing help — on any OpenAI-compatible provider.
|
|
5
5
|
Author: Muhammad Aiman
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/aimanmalib/crewforge
|
|
8
|
-
Project-URL:
|
|
9
|
-
Project-URL: Issues, https://github.com/aimanmalib/crewforge/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/aimanmalib/crewforge#readme
|
|
10
9
|
Project-URL: Changelog, https://github.com/aimanmalib/crewforge/blob/main/CHANGELOG.md
|
|
11
|
-
|
|
10
|
+
Project-URL: Issues, https://github.com/aimanmalib/crewforge/issues
|
|
11
|
+
Project-URL: Source, https://github.com/aimanmalib/crewforge
|
|
12
|
+
Project-URL: Security, https://github.com/aimanmalib/crewforge/security/policy
|
|
13
|
+
Keywords: llm,agents,multi-agent,ai-agents,openai,openai-compatible,code-review,rag,document-qa,fastapi,api-scaffolding,content-generation,academic-writing,cli
|
|
12
14
|
Classifier: Development Status :: 3 - Alpha
|
|
13
15
|
Classifier: Environment :: Console
|
|
14
16
|
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: Education
|
|
18
|
+
Classifier: Natural Language :: English
|
|
19
|
+
Classifier: Natural Language :: Malay
|
|
15
20
|
Classifier: Operating System :: OS Independent
|
|
16
21
|
Classifier: Programming Language :: Python :: 3
|
|
17
22
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -19,8 +24,12 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
19
24
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
25
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
26
|
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
28
|
+
Classifier: Topic :: Education
|
|
22
29
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
30
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
23
31
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
32
|
+
Classifier: Topic :: Text Processing :: General
|
|
24
33
|
Classifier: Typing :: Typed
|
|
25
34
|
Requires-Python: >=3.10
|
|
26
35
|
Description-Content-Type: text/markdown
|
|
@@ -41,18 +50,27 @@ Requires-Dist: pytest>=8.0; extra == "dev"
|
|
|
41
50
|
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
42
51
|
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
43
52
|
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
53
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
54
|
+
Requires-Dist: types-PyYAML>=6.0; extra == "dev"
|
|
44
55
|
Requires-Dist: fastapi>=0.110; extra == "dev"
|
|
45
56
|
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
46
57
|
Dynamic: license-file
|
|
47
58
|
|
|
48
|
-
|
|
59
|
+
<p align="center"><img src="https://raw.githubusercontent.com/aimanmalib/crewforge/main/brand/logo-512.png" width="112" height="112" alt="crewforge"></p>
|
|
60
|
+
|
|
61
|
+
<h1 align="center">crewforge</h1>
|
|
62
|
+
|
|
63
|
+
<p align="center"><a href="https://github.com/aimanmalib/crewforge/actions/workflows/ci.yml"><img src="https://github.com/aimanmalib/crewforge/actions/workflows/ci.yml/badge.svg" alt="CI"></a> <a href="https://pypi.org/project/crewforge/"><img src="https://img.shields.io/pypi/v/crewforge" alt="PyPI"></a> <a href="https://scorecard.dev/viewer/?uri=github.com/aimanmalib/crewforge"><img src="https://api.scorecard.dev/projects/github.com/aimanmalib/crewforge/badge" alt="OpenSSF Scorecard"></a> <img src="https://img.shields.io/badge/python-3.10%E2%80%933.14-blue" alt="Python 3.10–3.14"> <a href="https://github.com/aimanmalib/crewforge/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License: MIT"></a></p>
|
|
49
64
|
|
|
50
|
-
|
|
65
|
+
<p align="center"><b>One crew of LLM agents, five recipes, any OpenAI-compatible provider.</b> · <i>Satu kru ejen LLM, lima resipi, mana-mana penyedia serasi OpenAI.</i><br>
|
|
66
|
+
<a href="https://pypi.org/project/crewforge/">PyPI</a> · <a href="https://github.com/aimanmalib/crewforge/blob/main/CHANGELOG.md">changelog</a> · <a href="https://github.com/aimanmalib/crewforge/blob/main/docs/porting.md">porting notes</a> · Built in Malaysia by <a href="https://aimanmalib.com">Aiman Malib</a></p>
|
|
51
67
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
crewforge is a command-line tool and Python library that runs a crew of LLM agents through five recipes: code
|
|
69
|
+
review, document Q&A, API scaffolding, content writing and honest academic-writing help. It works with any
|
|
70
|
+
OpenAI-compatible provider, reads API keys only from the environment, and fails loudly instead of pretending: a run
|
|
71
|
+
in which an agent produced nothing exits with code 1 and names that agent.
|
|
72
|
+
|
|
73
|
+
[Bahasa Melayu ↓](#bahasa-melayu)
|
|
56
74
|
|
|
57
75
|
```bash
|
|
58
76
|
crewforge review src/ # six reviewers + a summary
|
|
@@ -69,7 +87,7 @@ crewforge academic feedback draft.md --brief brief.md --language ms
|
|
|
69
87
|
|
|
70
88
|
## Why one crew, many recipes
|
|
71
89
|
|
|
72
|
-
crewforge started as four separate command-line tools
|
|
90
|
+
crewforge started as four separate command-line tools:
|
|
73
91
|
[codeguard](https://github.com/aimanmalib/codeguard),
|
|
74
92
|
[documind](https://github.com/aimanmalib/documind),
|
|
75
93
|
[apiforge](https://github.com/aimanmalib/apiforge) and
|
|
@@ -83,7 +101,7 @@ showed the copies had drifted and that each hid its failures differently:
|
|
|
83
101
|
- apiforge scored a spec with **no endpoints** 100/100;
|
|
84
102
|
- contentforge wrote the real API key into its YAML file, and sent `${OPENAI_API_KEY}` literally as the key.
|
|
85
103
|
|
|
86
|
-
crewforge keeps one core
|
|
104
|
+
crewforge keeps one core, so a fix lands once, and turns each tool into a
|
|
87
105
|
*recipe*: a set of agents plus the steps that connect them. The same core rules
|
|
88
106
|
apply to every recipe: non-streaming requests, bounded retries, usage numbers
|
|
89
107
|
taken only from the provider, keys only from the environment, and no run that
|
|
@@ -161,6 +179,11 @@ total 7 calls 22,366 tokens (provider-reported)
|
|
|
161
179
|
|
|
162
180
|
### `ask` and `summarize`
|
|
163
181
|
|
|
182
|
+
<p align="center">
|
|
183
|
+
<img src="https://raw.githubusercontent.com/aimanmalib/crewforge/main/docs/demo/ask.gif" alt="Terminal demo: crewforge ask --verify answers two questions about a short project brief with [Source N] citations; the second answer says the document does not give the cost, and both answers are fact-checked claim by claim" width="900">
|
|
184
|
+
</p>
|
|
185
|
+
<p align="center"><sub>A real run of <code>crewforge ask --verify</code>: the answerer cites the passages it used as <code>[Source N]</code>, a second agent checks every claim against those passages, and the question the document does not answer is answered as such. Provider-reported tokens. Recorded with <a href="https://github.com/charmbracelet/vhs">VHS</a> from <a href="https://github.com/aimanmalib/crewforge/blob/main/docs/demo/ask.tape"><code>docs/demo/ask.tape</code></a> (the document is invented) using Gemini 3.8 Flash through an OpenAI-compatible gateway (the <code>custom</code> provider). The wait for the model is shown in full.</sub></p>
|
|
186
|
+
|
|
164
187
|
```text
|
|
165
188
|
$ crewforge ask kestrel.md -q "How many sensors does Project Kestrel use, and who leads it?" --verify --export session.md
|
|
166
189
|
✓ ingested kestrel.md (1 chunks)
|
|
@@ -232,6 +255,11 @@ Indonesian forms such as *karena* or *kualitas*). Every step is recorded
|
|
|
232
255
|
(file names and hashes, never content or keys) so `disclose` can write the
|
|
233
256
|
AI-use statement many universities now ask for.
|
|
234
257
|
|
|
258
|
+
<p align="center">
|
|
259
|
+
<img src="https://raw.githubusercontent.com/aimanmalib/crewforge/main/docs/demo/academic.gif" alt="Terminal demo: crewforge academic feedback --language ms comments in Malay on a student's essay draft, quoting the sentences it refers to, then a no-AI citation check lists (Lim, 2024) as cited in the text but missing from the reference list" width="900">
|
|
260
|
+
</p>
|
|
261
|
+
<p align="center"><sub>A real run of <code>crewforge academic feedback --language ms</code> on a short essay draft in Malay. Each comment quotes the student's own sentence and suggests a fix; nothing is rewritten. The citation check after it uses no AI: it finds <em>(Lim, 2024)</em> cited in the text but missing from the reference list. Only the <code>argument</code> reviewer is run so the result fits on one screen. Recorded with <a href="https://github.com/charmbracelet/vhs">VHS</a> from <a href="https://github.com/aimanmalib/crewforge/blob/main/docs/demo/academic.tape"><code>docs/demo/academic.tape</code></a> (draft, brief and reference are invented) using Gemini 3.8 Flash through an OpenAI-compatible gateway (the <code>custom</code> provider). The wait for the model is shown in full.</sub></p>
|
|
262
|
+
|
|
235
263
|
```text
|
|
236
264
|
$ crewforge academic plan brief.md -f markdown # a 1,200-word TSL3013 essay brief
|
|
237
265
|
# Assignment plan: Regulated Integration over Prohibition: ...
|
|
@@ -268,13 +296,13 @@ Saya menggunakan crewforge academic (versi 0.1.0), sebuah alat berbantukan AI, d
|
|
|
268
296
|
- 22 Oktober 2026: Perancangan: alat ini menukar taklimat tugasan (brief-ms.md) kepada 3 soalan kajian, rangka 5 bahagian dan peruntukan perkataan. ...
|
|
269
297
|
```
|
|
270
298
|
|
|
271
|
-
How sources are labelled
|
|
299
|
+
How sources are labelled: there is no "verified" status, because the tool
|
|
272
300
|
cannot check that a source exists:
|
|
273
301
|
|
|
274
302
|
| Source | Label |
|
|
275
303
|
|---|---|
|
|
276
304
|
| You supplied it | *supplied by you (not checked online)* |
|
|
277
|
-
| The model proposed it, with a DOI, URL or valid ISBN | **UNVERIFIED
|
|
305
|
+
| The model proposed it, with a DOI, URL or valid ISBN | **UNVERIFIED**: check it |
|
|
278
306
|
| The model proposed it with none of those | **LIKELY FABRICATED** |
|
|
279
307
|
| The model added a DOI/URL/ISBN to a reference you supplied | **UNVERIFIED**, naming the added identifier |
|
|
280
308
|
|
|
@@ -309,47 +337,20 @@ An unknown provider name is a configuration error, not a silent fallback.
|
|
|
309
337
|
|
|
310
338
|
## Architecture
|
|
311
339
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
subgraph R["Recipes (src/crewforge/recipes)"]
|
|
317
|
-
RV[review]
|
|
318
|
-
DC[docs]
|
|
319
|
-
AP[api]
|
|
320
|
-
CT[content]
|
|
321
|
-
AC[academic]
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
R --> CREW
|
|
325
|
-
|
|
326
|
-
subgraph CORE["Core (src/crewforge/core)"]
|
|
327
|
-
CREW["Crew<br/>step() · parallel()<br/>names failed agents"]
|
|
328
|
-
AG["Agent<br/>ask() · ask_json()<br/>rejects empty output"]
|
|
329
|
-
PA["parsing<br/>tolerant JSON + schema"]
|
|
330
|
-
CL["LLMClient<br/>stream=false · retries 429/5xx only"]
|
|
331
|
-
US["UsageTracker<br/>provider-reported tokens"]
|
|
332
|
-
CF["LLMConfig + provider presets<br/>keys from env only"]
|
|
333
|
-
CREW --> AG
|
|
334
|
-
AG --> PA
|
|
335
|
-
AG --> CL
|
|
336
|
-
AG --> US
|
|
337
|
-
CL --> CF
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
CL -->|"/chat/completions"| P[("Any OpenAI-compatible provider")]
|
|
341
|
-
```
|
|
340
|
+
<p align="center"><img src="https://raw.githubusercontent.com/aimanmalib/crewforge/main/docs/architecture.png" alt="Architecture: the CLI dispatches to five recipes; each recipe builds a Crew of Agents on the shared core (parsing, LLMClient, LLMConfig, UsageTracker), which talks to any OpenAI-compatible provider over /chat/completions" width="100%"></p>
|
|
341
|
+
|
|
342
|
+
<sub>Source: [docs/architecture.mmd](https://github.com/aimanmalib/crewforge/blob/main/docs/architecture.mmd) (re-render with `scripts/render_architecture.py`).</sub>
|
|
342
343
|
|
|
343
|
-
- **`core/client.py
|
|
344
|
+
- **`core/client.py`**: one async client. It always sends `"stream": false`,
|
|
344
345
|
retries only HTTP 429, 5xx and network/timeout errors (with capped exponential
|
|
345
346
|
backoff that honours `Retry-After`), and fails on the first 401/403/4xx with a
|
|
346
347
|
message naming the variable to fix. The key is only ever a request header.
|
|
347
|
-
- **`core/agent.py
|
|
348
|
+
- **`core/agent.py`**: an agent is a role, a system prompt and per-agent
|
|
348
349
|
sampling defaults. `ask()` records usage and raises if the reply is blank;
|
|
349
350
|
`ask_json()` additionally requires parseable JSON (optionally a pydantic schema).
|
|
350
|
-
- **`core/crew.py
|
|
351
|
+
- **`core/crew.py`**: runs agents as sequential steps or parallel stages and
|
|
351
352
|
turns any failure into a `CrewFailedError` that lists every failed agent.
|
|
352
|
-
- **`core/usage.py
|
|
353
|
+
- **`core/usage.py`**: per-agent calls, tokens, retries and latency, taken from
|
|
353
354
|
the provider's `usage` object. Calls without usage are counted as "not reported",
|
|
354
355
|
never estimated.
|
|
355
356
|
|
|
@@ -414,22 +415,23 @@ watching them fail; see [docs/porting.md](https://github.com/aimanmalib/crewforg
|
|
|
414
415
|
|
|
415
416
|
crewforge was built with AI coding assistance (Claude Code) under the
|
|
416
417
|
direction of its author, Muhammad Aiman. It consolidates four earlier tools by
|
|
417
|
-
the same author
|
|
418
|
+
the same author ([codeguard](https://github.com/aimanmalib/codeguard),
|
|
418
419
|
[documind](https://github.com/aimanmalib/documind),
|
|
419
420
|
[apiforge](https://github.com/aimanmalib/apiforge) and
|
|
420
|
-
[contentforge](https://github.com/aimanmalib/contentforge)
|
|
421
|
+
[contentforge](https://github.com/aimanmalib/contentforge)), whose test suites
|
|
421
422
|
were carried over into this repository (see [docs/porting.md](https://github.com/aimanmalib/crewforge/blob/main/docs/porting.md)
|
|
422
423
|
for what was ported, re-targeted at the shared core, or dropped and why).
|
|
423
424
|
|
|
424
425
|
The evidence that it works is meant to be checkable: the test suite (run
|
|
425
|
-
`pytest`; it needs no key and no network), CI on Python 3.10–3.
|
|
426
|
+
`pytest`; it needs no key and no network), CI on Python 3.10–3.14, and the
|
|
426
427
|
real-provider runs shown above, two of which found bugs that were fixed with
|
|
427
428
|
tests before the output was recorded.
|
|
428
429
|
|
|
429
430
|
## Contributing
|
|
430
431
|
|
|
431
|
-
See [CONTRIBUTING.md](https://github.com/aimanmalib/crewforge/blob/main/CONTRIBUTING.md). In short: `
|
|
432
|
-
|
|
432
|
+
See [CONTRIBUTING.md](https://github.com/aimanmalib/crewforge/blob/main/CONTRIBUTING.md). In short: `uv sync --extra dev --extra docs`
|
|
433
|
+
(versions from the committed `uv.lock`, as in CI), `uv run pytest`,
|
|
434
|
+
`uv run ruff check . && uv run ruff format --check .`, and every new failure path
|
|
433
435
|
needs a test that fails if the guard is removed.
|
|
434
436
|
|
|
435
437
|
## Security
|
|
@@ -439,10 +441,52 @@ Please report vulnerabilities privately through
|
|
|
439
441
|
See [SECURITY.md](https://github.com/aimanmalib/crewforge/blob/main/SECURITY.md) for scope notes (what is sent to your provider,
|
|
440
442
|
and what `validate` executes).
|
|
441
443
|
|
|
442
|
-
##
|
|
444
|
+
## Bahasa Melayu
|
|
445
|
+
|
|
446
|
+
crewforge ialah alat baris arahan dan pustaka Python yang menjalankan satu kru ejen LLM melalui lima resipi:
|
|
447
|
+
semakan kod (`review`), soal jawab dokumen (`ask`, `summarize`), penjanaan projek API FastAPI (`scaffold`,
|
|
448
|
+
`validate`), penulisan kandungan (`write`) dan bantuan penulisan akademik yang jujur (`academic`). Ia berfungsi
|
|
449
|
+
dengan mana-mana penyedia serasi OpenAI, termasuk model tempatan melalui Ollama atau llama.cpp. Kunci API hanya
|
|
450
|
+
dibaca dari pemboleh ubah persekitaran, tidak pernah ditulis ke fail.
|
|
451
|
+
|
|
452
|
+
**Mengapa satu kru.** crewforge menggabungkan empat alat lama (codeguard, documind, apiforge, contentforge) yang
|
|
453
|
+
masing-masing menyimpan salinan sendiri bagi rangka yang sama. Salinan itu sudah berbeza dan setiap satu
|
|
454
|
+
menyembunyikan kegagalan dengan cara sendiri. Kini teras dikongsi: pembaikan dibuat sekali, dan setiap alat menjadi
|
|
455
|
+
resipi di atas teras itu.
|
|
456
|
+
|
|
457
|
+
**Gagal dengan jelas.** Larian yang ejennya memulangkan jawapan kosong atau tidak boleh dihurai, atau pengesah
|
|
458
|
+
yang tidak menyemak apa-apa, keluar dengan kod 1 dan menamakan ejen itu. Kod keluar: `0` berjaya, `1` larian
|
|
459
|
+
gagal, `2` ralat penggunaan atau konfigurasi. Bilangan token diambil daripada laporan penyedia sahaja, tidak
|
|
460
|
+
dianggar.
|
|
461
|
+
|
|
462
|
+
**Resipi `academic`.** Membantu pelajar dan penyelidik dengan kerja mereka **sendiri**: merancang dari taklimat
|
|
463
|
+
tugasan, memberi ulasan atas draf tanpa menulis semula, memformat rujukan yang diberi pengguna (APA 7, IEEE,
|
|
464
|
+
Harvard) tanpa menambah rujukan baharu, dan menulis pernyataan penggunaan AI daripada rekod langkah yang
|
|
465
|
+
dijalankan. Output dalam bahasa Inggeris atau Bahasa Melayu (`--language ms`); output BM disemak untuk bentuk
|
|
466
|
+
Indonesia seperti *karena* atau *kualitas*. Sumber yang dicadangkan model dilabel UNVERIFIED, atau LIKELY
|
|
467
|
+
FABRICATED jika tiada DOI, URL atau ISBN. Tiada ciri "humanise" atau mengelak pengesan AI.
|
|
468
|
+
|
|
469
|
+
**Pasang dan guna.**
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
pip install crewforge # Python 3.10 hingga 3.14
|
|
473
|
+
pip install "crewforge[docs,api]" # pilihan: PDF/DOCX dan semakan aplikasi FastAPI
|
|
474
|
+
export OPENAI_API_KEY=sk-... # atau penyedia lain, lihat `crewforge providers`
|
|
475
|
+
crewforge review src/
|
|
476
|
+
crewforge academic feedback draf.md --brief taklimat.md --language ms
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Senarai penyedia, contoh setiap resipi dan seni bina ada dalam bahagian bahasa Inggeris di atas
|
|
480
|
+
([Providers](https://github.com/aimanmalib/crewforge#providers), [Recipes](https://github.com/aimanmalib/crewforge#recipes)).
|
|
481
|
+
|
|
482
|
+
## Licence
|
|
483
|
+
|
|
484
|
+
[MIT](https://github.com/aimanmalib/crewforge/blob/main/LICENSE) © Muhammad Aiman. Made by [Aiman Malib](https://aimanmalib.com), Malaysia.
|
|
485
|
+
|
|
486
|
+
## Work with Sasa Teguh
|
|
443
487
|
|
|
444
|
-
[
|
|
488
|
+
[](https://sasateguh.com/book)
|
|
445
489
|
|
|
446
|
-
|
|
490
|
+
I built this project. I run [Sasa Teguh](https://sasateguh.com), a studio in Malaysia that builds websites found on Google and in AI answers, and sets up systems like this one for businesses.
|
|
447
491
|
|
|
448
|
-
|
|
492
|
+
[Book a call](https://sasateguh.com/book) · hello@sasateguh.com · [More from Sasa Teguh](https://github.com/sasateguh)
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center"><img src="https://raw.githubusercontent.com/aimanmalib/crewforge/main/brand/logo-512.png" width="112" height="112" alt="crewforge"></p>
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<h1 align="center">crewforge</h1>
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
<p align="center"><a href="https://github.com/aimanmalib/crewforge/actions/workflows/ci.yml"><img src="https://github.com/aimanmalib/crewforge/actions/workflows/ci.yml/badge.svg" alt="CI"></a> <a href="https://pypi.org/project/crewforge/"><img src="https://img.shields.io/pypi/v/crewforge" alt="PyPI"></a> <a href="https://scorecard.dev/viewer/?uri=github.com/aimanmalib/crewforge"><img src="https://api.scorecard.dev/projects/github.com/aimanmalib/crewforge/badge" alt="OpenSSF Scorecard"></a> <img src="https://img.shields.io/badge/python-3.10%E2%80%933.14-blue" alt="Python 3.10–3.14"> <a href="https://github.com/aimanmalib/crewforge/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License: MIT"></a></p>
|
|
6
|
+
|
|
7
|
+
<p align="center"><b>One crew of LLM agents, five recipes, any OpenAI-compatible provider.</b> · <i>Satu kru ejen LLM, lima resipi, mana-mana penyedia serasi OpenAI.</i><br>
|
|
8
|
+
<a href="https://pypi.org/project/crewforge/">PyPI</a> · <a href="https://github.com/aimanmalib/crewforge/blob/main/CHANGELOG.md">changelog</a> · <a href="https://github.com/aimanmalib/crewforge/blob/main/docs/porting.md">porting notes</a> · Built in Malaysia by <a href="https://aimanmalib.com">Aiman Malib</a></p>
|
|
9
|
+
|
|
10
|
+
crewforge is a command-line tool and Python library that runs a crew of LLM agents through five recipes: code
|
|
11
|
+
review, document Q&A, API scaffolding, content writing and honest academic-writing help. It works with any
|
|
12
|
+
OpenAI-compatible provider, reads API keys only from the environment, and fails loudly instead of pretending: a run
|
|
13
|
+
in which an agent produced nothing exits with code 1 and names that agent.
|
|
14
|
+
|
|
15
|
+
[Bahasa Melayu ↓](#bahasa-melayu)
|
|
9
16
|
|
|
10
17
|
```bash
|
|
11
18
|
crewforge review src/ # six reviewers + a summary
|
|
@@ -22,7 +29,7 @@ crewforge academic feedback draft.md --brief brief.md --language ms
|
|
|
22
29
|
|
|
23
30
|
## Why one crew, many recipes
|
|
24
31
|
|
|
25
|
-
crewforge started as four separate command-line tools
|
|
32
|
+
crewforge started as four separate command-line tools:
|
|
26
33
|
[codeguard](https://github.com/aimanmalib/codeguard),
|
|
27
34
|
[documind](https://github.com/aimanmalib/documind),
|
|
28
35
|
[apiforge](https://github.com/aimanmalib/apiforge) and
|
|
@@ -36,7 +43,7 @@ showed the copies had drifted and that each hid its failures differently:
|
|
|
36
43
|
- apiforge scored a spec with **no endpoints** 100/100;
|
|
37
44
|
- contentforge wrote the real API key into its YAML file, and sent `${OPENAI_API_KEY}` literally as the key.
|
|
38
45
|
|
|
39
|
-
crewforge keeps one core
|
|
46
|
+
crewforge keeps one core, so a fix lands once, and turns each tool into a
|
|
40
47
|
*recipe*: a set of agents plus the steps that connect them. The same core rules
|
|
41
48
|
apply to every recipe: non-streaming requests, bounded retries, usage numbers
|
|
42
49
|
taken only from the provider, keys only from the environment, and no run that
|
|
@@ -114,6 +121,11 @@ total 7 calls 22,366 tokens (provider-reported)
|
|
|
114
121
|
|
|
115
122
|
### `ask` and `summarize`
|
|
116
123
|
|
|
124
|
+
<p align="center">
|
|
125
|
+
<img src="https://raw.githubusercontent.com/aimanmalib/crewforge/main/docs/demo/ask.gif" alt="Terminal demo: crewforge ask --verify answers two questions about a short project brief with [Source N] citations; the second answer says the document does not give the cost, and both answers are fact-checked claim by claim" width="900">
|
|
126
|
+
</p>
|
|
127
|
+
<p align="center"><sub>A real run of <code>crewforge ask --verify</code>: the answerer cites the passages it used as <code>[Source N]</code>, a second agent checks every claim against those passages, and the question the document does not answer is answered as such. Provider-reported tokens. Recorded with <a href="https://github.com/charmbracelet/vhs">VHS</a> from <a href="https://github.com/aimanmalib/crewforge/blob/main/docs/demo/ask.tape"><code>docs/demo/ask.tape</code></a> (the document is invented) using Gemini 3.8 Flash through an OpenAI-compatible gateway (the <code>custom</code> provider). The wait for the model is shown in full.</sub></p>
|
|
128
|
+
|
|
117
129
|
```text
|
|
118
130
|
$ crewforge ask kestrel.md -q "How many sensors does Project Kestrel use, and who leads it?" --verify --export session.md
|
|
119
131
|
✓ ingested kestrel.md (1 chunks)
|
|
@@ -185,6 +197,11 @@ Indonesian forms such as *karena* or *kualitas*). Every step is recorded
|
|
|
185
197
|
(file names and hashes, never content or keys) so `disclose` can write the
|
|
186
198
|
AI-use statement many universities now ask for.
|
|
187
199
|
|
|
200
|
+
<p align="center">
|
|
201
|
+
<img src="https://raw.githubusercontent.com/aimanmalib/crewforge/main/docs/demo/academic.gif" alt="Terminal demo: crewforge academic feedback --language ms comments in Malay on a student's essay draft, quoting the sentences it refers to, then a no-AI citation check lists (Lim, 2024) as cited in the text but missing from the reference list" width="900">
|
|
202
|
+
</p>
|
|
203
|
+
<p align="center"><sub>A real run of <code>crewforge academic feedback --language ms</code> on a short essay draft in Malay. Each comment quotes the student's own sentence and suggests a fix; nothing is rewritten. The citation check after it uses no AI: it finds <em>(Lim, 2024)</em> cited in the text but missing from the reference list. Only the <code>argument</code> reviewer is run so the result fits on one screen. Recorded with <a href="https://github.com/charmbracelet/vhs">VHS</a> from <a href="https://github.com/aimanmalib/crewforge/blob/main/docs/demo/academic.tape"><code>docs/demo/academic.tape</code></a> (draft, brief and reference are invented) using Gemini 3.8 Flash through an OpenAI-compatible gateway (the <code>custom</code> provider). The wait for the model is shown in full.</sub></p>
|
|
204
|
+
|
|
188
205
|
```text
|
|
189
206
|
$ crewforge academic plan brief.md -f markdown # a 1,200-word TSL3013 essay brief
|
|
190
207
|
# Assignment plan: Regulated Integration over Prohibition: ...
|
|
@@ -221,13 +238,13 @@ Saya menggunakan crewforge academic (versi 0.1.0), sebuah alat berbantukan AI, d
|
|
|
221
238
|
- 22 Oktober 2026: Perancangan: alat ini menukar taklimat tugasan (brief-ms.md) kepada 3 soalan kajian, rangka 5 bahagian dan peruntukan perkataan. ...
|
|
222
239
|
```
|
|
223
240
|
|
|
224
|
-
How sources are labelled
|
|
241
|
+
How sources are labelled: there is no "verified" status, because the tool
|
|
225
242
|
cannot check that a source exists:
|
|
226
243
|
|
|
227
244
|
| Source | Label |
|
|
228
245
|
|---|---|
|
|
229
246
|
| You supplied it | *supplied by you (not checked online)* |
|
|
230
|
-
| The model proposed it, with a DOI, URL or valid ISBN | **UNVERIFIED
|
|
247
|
+
| The model proposed it, with a DOI, URL or valid ISBN | **UNVERIFIED**: check it |
|
|
231
248
|
| The model proposed it with none of those | **LIKELY FABRICATED** |
|
|
232
249
|
| The model added a DOI/URL/ISBN to a reference you supplied | **UNVERIFIED**, naming the added identifier |
|
|
233
250
|
|
|
@@ -262,47 +279,20 @@ An unknown provider name is a configuration error, not a silent fallback.
|
|
|
262
279
|
|
|
263
280
|
## Architecture
|
|
264
281
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
subgraph R["Recipes (src/crewforge/recipes)"]
|
|
270
|
-
RV[review]
|
|
271
|
-
DC[docs]
|
|
272
|
-
AP[api]
|
|
273
|
-
CT[content]
|
|
274
|
-
AC[academic]
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
R --> CREW
|
|
278
|
-
|
|
279
|
-
subgraph CORE["Core (src/crewforge/core)"]
|
|
280
|
-
CREW["Crew<br/>step() · parallel()<br/>names failed agents"]
|
|
281
|
-
AG["Agent<br/>ask() · ask_json()<br/>rejects empty output"]
|
|
282
|
-
PA["parsing<br/>tolerant JSON + schema"]
|
|
283
|
-
CL["LLMClient<br/>stream=false · retries 429/5xx only"]
|
|
284
|
-
US["UsageTracker<br/>provider-reported tokens"]
|
|
285
|
-
CF["LLMConfig + provider presets<br/>keys from env only"]
|
|
286
|
-
CREW --> AG
|
|
287
|
-
AG --> PA
|
|
288
|
-
AG --> CL
|
|
289
|
-
AG --> US
|
|
290
|
-
CL --> CF
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
CL -->|"/chat/completions"| P[("Any OpenAI-compatible provider")]
|
|
294
|
-
```
|
|
282
|
+
<p align="center"><img src="https://raw.githubusercontent.com/aimanmalib/crewforge/main/docs/architecture.png" alt="Architecture: the CLI dispatches to five recipes; each recipe builds a Crew of Agents on the shared core (parsing, LLMClient, LLMConfig, UsageTracker), which talks to any OpenAI-compatible provider over /chat/completions" width="100%"></p>
|
|
283
|
+
|
|
284
|
+
<sub>Source: [docs/architecture.mmd](https://github.com/aimanmalib/crewforge/blob/main/docs/architecture.mmd) (re-render with `scripts/render_architecture.py`).</sub>
|
|
295
285
|
|
|
296
|
-
- **`core/client.py
|
|
286
|
+
- **`core/client.py`**: one async client. It always sends `"stream": false`,
|
|
297
287
|
retries only HTTP 429, 5xx and network/timeout errors (with capped exponential
|
|
298
288
|
backoff that honours `Retry-After`), and fails on the first 401/403/4xx with a
|
|
299
289
|
message naming the variable to fix. The key is only ever a request header.
|
|
300
|
-
- **`core/agent.py
|
|
290
|
+
- **`core/agent.py`**: an agent is a role, a system prompt and per-agent
|
|
301
291
|
sampling defaults. `ask()` records usage and raises if the reply is blank;
|
|
302
292
|
`ask_json()` additionally requires parseable JSON (optionally a pydantic schema).
|
|
303
|
-
- **`core/crew.py
|
|
293
|
+
- **`core/crew.py`**: runs agents as sequential steps or parallel stages and
|
|
304
294
|
turns any failure into a `CrewFailedError` that lists every failed agent.
|
|
305
|
-
- **`core/usage.py
|
|
295
|
+
- **`core/usage.py`**: per-agent calls, tokens, retries and latency, taken from
|
|
306
296
|
the provider's `usage` object. Calls without usage are counted as "not reported",
|
|
307
297
|
never estimated.
|
|
308
298
|
|
|
@@ -367,22 +357,23 @@ watching them fail; see [docs/porting.md](https://github.com/aimanmalib/crewforg
|
|
|
367
357
|
|
|
368
358
|
crewforge was built with AI coding assistance (Claude Code) under the
|
|
369
359
|
direction of its author, Muhammad Aiman. It consolidates four earlier tools by
|
|
370
|
-
the same author
|
|
360
|
+
the same author ([codeguard](https://github.com/aimanmalib/codeguard),
|
|
371
361
|
[documind](https://github.com/aimanmalib/documind),
|
|
372
362
|
[apiforge](https://github.com/aimanmalib/apiforge) and
|
|
373
|
-
[contentforge](https://github.com/aimanmalib/contentforge)
|
|
363
|
+
[contentforge](https://github.com/aimanmalib/contentforge)), whose test suites
|
|
374
364
|
were carried over into this repository (see [docs/porting.md](https://github.com/aimanmalib/crewforge/blob/main/docs/porting.md)
|
|
375
365
|
for what was ported, re-targeted at the shared core, or dropped and why).
|
|
376
366
|
|
|
377
367
|
The evidence that it works is meant to be checkable: the test suite (run
|
|
378
|
-
`pytest`; it needs no key and no network), CI on Python 3.10–3.
|
|
368
|
+
`pytest`; it needs no key and no network), CI on Python 3.10–3.14, and the
|
|
379
369
|
real-provider runs shown above, two of which found bugs that were fixed with
|
|
380
370
|
tests before the output was recorded.
|
|
381
371
|
|
|
382
372
|
## Contributing
|
|
383
373
|
|
|
384
|
-
See [CONTRIBUTING.md](https://github.com/aimanmalib/crewforge/blob/main/CONTRIBUTING.md). In short: `
|
|
385
|
-
|
|
374
|
+
See [CONTRIBUTING.md](https://github.com/aimanmalib/crewforge/blob/main/CONTRIBUTING.md). In short: `uv sync --extra dev --extra docs`
|
|
375
|
+
(versions from the committed `uv.lock`, as in CI), `uv run pytest`,
|
|
376
|
+
`uv run ruff check . && uv run ruff format --check .`, and every new failure path
|
|
386
377
|
needs a test that fails if the guard is removed.
|
|
387
378
|
|
|
388
379
|
## Security
|
|
@@ -392,10 +383,52 @@ Please report vulnerabilities privately through
|
|
|
392
383
|
See [SECURITY.md](https://github.com/aimanmalib/crewforge/blob/main/SECURITY.md) for scope notes (what is sent to your provider,
|
|
393
384
|
and what `validate` executes).
|
|
394
385
|
|
|
395
|
-
##
|
|
386
|
+
## Bahasa Melayu
|
|
387
|
+
|
|
388
|
+
crewforge ialah alat baris arahan dan pustaka Python yang menjalankan satu kru ejen LLM melalui lima resipi:
|
|
389
|
+
semakan kod (`review`), soal jawab dokumen (`ask`, `summarize`), penjanaan projek API FastAPI (`scaffold`,
|
|
390
|
+
`validate`), penulisan kandungan (`write`) dan bantuan penulisan akademik yang jujur (`academic`). Ia berfungsi
|
|
391
|
+
dengan mana-mana penyedia serasi OpenAI, termasuk model tempatan melalui Ollama atau llama.cpp. Kunci API hanya
|
|
392
|
+
dibaca dari pemboleh ubah persekitaran, tidak pernah ditulis ke fail.
|
|
393
|
+
|
|
394
|
+
**Mengapa satu kru.** crewforge menggabungkan empat alat lama (codeguard, documind, apiforge, contentforge) yang
|
|
395
|
+
masing-masing menyimpan salinan sendiri bagi rangka yang sama. Salinan itu sudah berbeza dan setiap satu
|
|
396
|
+
menyembunyikan kegagalan dengan cara sendiri. Kini teras dikongsi: pembaikan dibuat sekali, dan setiap alat menjadi
|
|
397
|
+
resipi di atas teras itu.
|
|
398
|
+
|
|
399
|
+
**Gagal dengan jelas.** Larian yang ejennya memulangkan jawapan kosong atau tidak boleh dihurai, atau pengesah
|
|
400
|
+
yang tidak menyemak apa-apa, keluar dengan kod 1 dan menamakan ejen itu. Kod keluar: `0` berjaya, `1` larian
|
|
401
|
+
gagal, `2` ralat penggunaan atau konfigurasi. Bilangan token diambil daripada laporan penyedia sahaja, tidak
|
|
402
|
+
dianggar.
|
|
403
|
+
|
|
404
|
+
**Resipi `academic`.** Membantu pelajar dan penyelidik dengan kerja mereka **sendiri**: merancang dari taklimat
|
|
405
|
+
tugasan, memberi ulasan atas draf tanpa menulis semula, memformat rujukan yang diberi pengguna (APA 7, IEEE,
|
|
406
|
+
Harvard) tanpa menambah rujukan baharu, dan menulis pernyataan penggunaan AI daripada rekod langkah yang
|
|
407
|
+
dijalankan. Output dalam bahasa Inggeris atau Bahasa Melayu (`--language ms`); output BM disemak untuk bentuk
|
|
408
|
+
Indonesia seperti *karena* atau *kualitas*. Sumber yang dicadangkan model dilabel UNVERIFIED, atau LIKELY
|
|
409
|
+
FABRICATED jika tiada DOI, URL atau ISBN. Tiada ciri "humanise" atau mengelak pengesan AI.
|
|
410
|
+
|
|
411
|
+
**Pasang dan guna.**
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
pip install crewforge # Python 3.10 hingga 3.14
|
|
415
|
+
pip install "crewforge[docs,api]" # pilihan: PDF/DOCX dan semakan aplikasi FastAPI
|
|
416
|
+
export OPENAI_API_KEY=sk-... # atau penyedia lain, lihat `crewforge providers`
|
|
417
|
+
crewforge review src/
|
|
418
|
+
crewforge academic feedback draf.md --brief taklimat.md --language ms
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Senarai penyedia, contoh setiap resipi dan seni bina ada dalam bahagian bahasa Inggeris di atas
|
|
422
|
+
([Providers](https://github.com/aimanmalib/crewforge#providers), [Recipes](https://github.com/aimanmalib/crewforge#recipes)).
|
|
423
|
+
|
|
424
|
+
## Licence
|
|
425
|
+
|
|
426
|
+
[MIT](https://github.com/aimanmalib/crewforge/blob/main/LICENSE) © Muhammad Aiman. Made by [Aiman Malib](https://aimanmalib.com), Malaysia.
|
|
427
|
+
|
|
428
|
+
## Work with Sasa Teguh
|
|
396
429
|
|
|
397
|
-
[
|
|
430
|
+
[](https://sasateguh.com/book)
|
|
398
431
|
|
|
399
|
-
|
|
432
|
+
I built this project. I run [Sasa Teguh](https://sasateguh.com), a studio in Malaysia that builds websites found on Google and in AI answers, and sets up systems like this one for businesses.
|
|
400
433
|
|
|
401
|
-
|
|
434
|
+
[Book a call](https://sasateguh.com/book) · hello@sasateguh.com · [More from Sasa Teguh](https://github.com/sasateguh)
|
|
@@ -4,18 +4,36 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "crewforge"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "One crew of LLM agents, five recipes: code review, document Q&A, API scaffolding, content and honest academic-writing help — on any OpenAI-compatible provider."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
11
11
|
license-files = ["LICENSE"]
|
|
12
12
|
requires-python = ">=3.10"
|
|
13
13
|
authors = [{ name = "Muhammad Aiman" }]
|
|
14
|
-
keywords = [
|
|
14
|
+
keywords = [
|
|
15
|
+
"llm",
|
|
16
|
+
"agents",
|
|
17
|
+
"multi-agent",
|
|
18
|
+
"ai-agents",
|
|
19
|
+
"openai",
|
|
20
|
+
"openai-compatible",
|
|
21
|
+
"code-review",
|
|
22
|
+
"rag",
|
|
23
|
+
"document-qa",
|
|
24
|
+
"fastapi",
|
|
25
|
+
"api-scaffolding",
|
|
26
|
+
"content-generation",
|
|
27
|
+
"academic-writing",
|
|
28
|
+
"cli",
|
|
29
|
+
]
|
|
15
30
|
classifiers = [
|
|
16
31
|
"Development Status :: 3 - Alpha",
|
|
17
32
|
"Environment :: Console",
|
|
18
33
|
"Intended Audience :: Developers",
|
|
34
|
+
"Intended Audience :: Education",
|
|
35
|
+
"Natural Language :: English",
|
|
36
|
+
"Natural Language :: Malay",
|
|
19
37
|
"Operating System :: OS Independent",
|
|
20
38
|
"Programming Language :: Python :: 3",
|
|
21
39
|
"Programming Language :: Python :: 3 :: Only",
|
|
@@ -23,8 +41,12 @@ classifiers = [
|
|
|
23
41
|
"Programming Language :: Python :: 3.11",
|
|
24
42
|
"Programming Language :: Python :: 3.12",
|
|
25
43
|
"Programming Language :: Python :: 3.13",
|
|
44
|
+
"Programming Language :: Python :: 3.14",
|
|
45
|
+
"Topic :: Education",
|
|
26
46
|
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
47
|
+
"Topic :: Software Development :: Code Generators",
|
|
27
48
|
"Topic :: Software Development :: Quality Assurance",
|
|
49
|
+
"Topic :: Text Processing :: General",
|
|
28
50
|
"Typing :: Typed",
|
|
29
51
|
]
|
|
30
52
|
dependencies = [
|
|
@@ -44,15 +66,19 @@ dev = [
|
|
|
44
66
|
"pytest-asyncio>=0.23",
|
|
45
67
|
"pytest-cov>=5.0",
|
|
46
68
|
"ruff>=0.6",
|
|
69
|
+
"mypy>=1.10",
|
|
70
|
+
"types-PyYAML>=6.0",
|
|
47
71
|
"fastapi>=0.110",
|
|
48
72
|
"httpx>=0.27",
|
|
49
73
|
]
|
|
50
74
|
|
|
51
75
|
[project.urls]
|
|
52
76
|
Homepage = "https://github.com/aimanmalib/crewforge"
|
|
53
|
-
|
|
54
|
-
Issues = "https://github.com/aimanmalib/crewforge/issues"
|
|
77
|
+
Documentation = "https://github.com/aimanmalib/crewforge#readme"
|
|
55
78
|
Changelog = "https://github.com/aimanmalib/crewforge/blob/main/CHANGELOG.md"
|
|
79
|
+
Issues = "https://github.com/aimanmalib/crewforge/issues"
|
|
80
|
+
Source = "https://github.com/aimanmalib/crewforge"
|
|
81
|
+
Security = "https://github.com/aimanmalib/crewforge/security/policy"
|
|
56
82
|
|
|
57
83
|
[project.scripts]
|
|
58
84
|
crewforge = "crewforge.cli:main"
|
|
@@ -80,6 +106,22 @@ select = ["E", "F", "W", "I", "UP", "B"]
|
|
|
80
106
|
[tool.ruff.lint.per-file-ignores]
|
|
81
107
|
"tests/**" = ["B011"]
|
|
82
108
|
|
|
109
|
+
[tool.mypy]
|
|
110
|
+
# CI runs `mypy` (lint job). Bodies of unannotated functions are checked too.
|
|
111
|
+
files = ["src/crewforge"]
|
|
112
|
+
python_version = "3.10"
|
|
113
|
+
plugins = ["pydantic.mypy"]
|
|
114
|
+
check_untyped_defs = true
|
|
115
|
+
strict_equality = true
|
|
116
|
+
warn_redundant_casts = true
|
|
117
|
+
warn_unused_ignores = true
|
|
118
|
+
warn_unused_configs = true
|
|
119
|
+
|
|
120
|
+
[[tool.mypy.overrides]]
|
|
121
|
+
# Pre-1.24 PyMuPDF import name, used only as a fallback; it ships no type information.
|
|
122
|
+
module = ["fitz"]
|
|
123
|
+
ignore_missing_imports = true
|
|
124
|
+
|
|
83
125
|
[tool.coverage.run]
|
|
84
126
|
source = ["crewforge"]
|
|
85
127
|
branch = true
|
|
@@ -66,12 +66,13 @@ class Identifiers:
|
|
|
66
66
|
def identifiers(text: str) -> Identifiers:
|
|
67
67
|
"""Find the identifiers in a reference. URLs pointing at doi.org count as the DOI."""
|
|
68
68
|
dois = {_strip_trailing(m.group(1)).lower() for m in _DOI.finditer(text)}
|
|
69
|
-
urls = set()
|
|
69
|
+
urls: set[str] = set()
|
|
70
70
|
for m in _URL.finditer(text):
|
|
71
71
|
url = _strip_trailing(m.group(0)).rstrip("/")
|
|
72
72
|
if not any(host in url.lower() for host in _DOI_HOSTS):
|
|
73
73
|
urls.add(url)
|
|
74
|
-
valid
|
|
74
|
+
valid: set[str] = set()
|
|
75
|
+
invalid: set[str] = set()
|
|
75
76
|
# Springer-style DOIs embed an ISBN ("10.1007/978-3-..."): search the rest only.
|
|
76
77
|
rest = _URL.sub(" ", _DOI.sub(" ", text))
|
|
77
78
|
raw_isbns = [m.group(1) for m in _ISBN_LABELLED.finditer(rest)]
|