crewforge 0.2.1__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.1/src/crewforge.egg-info → crewforge-0.2.2}/PKG-INFO +70 -22
- {crewforge-0.2.1 → crewforge-0.2.2}/README.md +69 -21
- {crewforge-0.2.1 → crewforge-0.2.2}/pyproject.toml +1 -1
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/__init__.py +1 -1
- {crewforge-0.2.1 → crewforge-0.2.2/src/crewforge.egg-info}/PKG-INFO +70 -22
- {crewforge-0.2.1 → crewforge-0.2.2}/LICENSE +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/setup.cfg +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/__main__.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/cli.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/cli_support.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/core/__init__.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/core/agent.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/core/client.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/core/config.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/core/crew.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/core/errors.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/core/parsing.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/core/providers.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/core/usage.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/py.typed +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/__init__.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/__init__.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/agents.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/citations.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/cli.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/disclosure.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/language.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/locales/en.yaml +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/locales/ms.yaml +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/pipeline.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/report.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/academic/settings.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/__init__.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/agents.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/analytics.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/appcheck.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/cli.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/formatters.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/generator.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/pipeline.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/scaffold.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/docker-compose.j2 +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/dockerfile.j2 +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/env.example.j2 +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/fastapi_main.j2 +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/model.j2 +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/requirements.j2 +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/route.j2 +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/templates/test.j2 +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/api/utils.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/content/__init__.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/content/agents.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/content/cli.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/content/export.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/content/pipeline.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/content/settings.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/content/text.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/docs/__init__.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/docs/agents.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/docs/cli.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/docs/export.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/docs/index.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/docs/ingest.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/docs/pipeline.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/docs/retrieve.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/docs/settings.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/review/__init__.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/review/agents.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/review/cli.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/review/pipeline.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/review/report.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge/recipes/review/sources.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge.egg-info/SOURCES.txt +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge.egg-info/dependency_links.txt +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge.egg-info/entry_points.txt +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge.egg-info/requires.txt +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/src/crewforge.egg-info/top_level.txt +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/tests/test_honest_failure_e2e.py +0 -0
- {crewforge-0.2.1 → crewforge-0.2.2}/tests/test_readme.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
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
|
|
@@ -56,15 +56,21 @@ Requires-Dist: fastapi>=0.110; extra == "dev"
|
|
|
56
56
|
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
57
57
|
Dynamic: license-file
|
|
58
58
|
|
|
59
|
-
|
|
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
60
|
|
|
61
|
-
|
|
61
|
+
<h1 align="center">crewforge</h1>
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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>
|
|
64
|
+
|
|
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>
|
|
67
|
+
|
|
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)
|
|
68
74
|
|
|
69
75
|
```bash
|
|
70
76
|
crewforge review src/ # six reviewers + a summary
|
|
@@ -81,7 +87,7 @@ crewforge academic feedback draft.md --brief brief.md --language ms
|
|
|
81
87
|
|
|
82
88
|
## Why one crew, many recipes
|
|
83
89
|
|
|
84
|
-
crewforge started as four separate command-line tools
|
|
90
|
+
crewforge started as four separate command-line tools:
|
|
85
91
|
[codeguard](https://github.com/aimanmalib/codeguard),
|
|
86
92
|
[documind](https://github.com/aimanmalib/documind),
|
|
87
93
|
[apiforge](https://github.com/aimanmalib/apiforge) and
|
|
@@ -95,7 +101,7 @@ showed the copies had drifted and that each hid its failures differently:
|
|
|
95
101
|
- apiforge scored a spec with **no endpoints** 100/100;
|
|
96
102
|
- contentforge wrote the real API key into its YAML file, and sent `${OPENAI_API_KEY}` literally as the key.
|
|
97
103
|
|
|
98
|
-
crewforge keeps one core
|
|
104
|
+
crewforge keeps one core, so a fix lands once, and turns each tool into a
|
|
99
105
|
*recipe*: a set of agents plus the steps that connect them. The same core rules
|
|
100
106
|
apply to every recipe: non-streaming requests, bounded retries, usage numbers
|
|
101
107
|
taken only from the provider, keys only from the environment, and no run that
|
|
@@ -290,13 +296,13 @@ Saya menggunakan crewforge academic (versi 0.1.0), sebuah alat berbantukan AI, d
|
|
|
290
296
|
- 22 Oktober 2026: Perancangan: alat ini menukar taklimat tugasan (brief-ms.md) kepada 3 soalan kajian, rangka 5 bahagian dan peruntukan perkataan. ...
|
|
291
297
|
```
|
|
292
298
|
|
|
293
|
-
How sources are labelled
|
|
299
|
+
How sources are labelled: there is no "verified" status, because the tool
|
|
294
300
|
cannot check that a source exists:
|
|
295
301
|
|
|
296
302
|
| Source | Label |
|
|
297
303
|
|---|---|
|
|
298
304
|
| You supplied it | *supplied by you (not checked online)* |
|
|
299
|
-
| 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 |
|
|
300
306
|
| The model proposed it with none of those | **LIKELY FABRICATED** |
|
|
301
307
|
| The model added a DOI/URL/ISBN to a reference you supplied | **UNVERIFIED**, naming the added identifier |
|
|
302
308
|
|
|
@@ -335,16 +341,16 @@ An unknown provider name is a configuration error, not a silent fallback.
|
|
|
335
341
|
|
|
336
342
|
<sub>Source: [docs/architecture.mmd](https://github.com/aimanmalib/crewforge/blob/main/docs/architecture.mmd) (re-render with `scripts/render_architecture.py`).</sub>
|
|
337
343
|
|
|
338
|
-
- **`core/client.py
|
|
344
|
+
- **`core/client.py`**: one async client. It always sends `"stream": false`,
|
|
339
345
|
retries only HTTP 429, 5xx and network/timeout errors (with capped exponential
|
|
340
346
|
backoff that honours `Retry-After`), and fails on the first 401/403/4xx with a
|
|
341
347
|
message naming the variable to fix. The key is only ever a request header.
|
|
342
|
-
- **`core/agent.py
|
|
348
|
+
- **`core/agent.py`**: an agent is a role, a system prompt and per-agent
|
|
343
349
|
sampling defaults. `ask()` records usage and raises if the reply is blank;
|
|
344
350
|
`ask_json()` additionally requires parseable JSON (optionally a pydantic schema).
|
|
345
|
-
- **`core/crew.py
|
|
351
|
+
- **`core/crew.py`**: runs agents as sequential steps or parallel stages and
|
|
346
352
|
turns any failure into a `CrewFailedError` that lists every failed agent.
|
|
347
|
-
- **`core/usage.py
|
|
353
|
+
- **`core/usage.py`**: per-agent calls, tokens, retries and latency, taken from
|
|
348
354
|
the provider's `usage` object. Calls without usage are counted as "not reported",
|
|
349
355
|
never estimated.
|
|
350
356
|
|
|
@@ -409,10 +415,10 @@ watching them fail; see [docs/porting.md](https://github.com/aimanmalib/crewforg
|
|
|
409
415
|
|
|
410
416
|
crewforge was built with AI coding assistance (Claude Code) under the
|
|
411
417
|
direction of its author, Muhammad Aiman. It consolidates four earlier tools by
|
|
412
|
-
the same author
|
|
418
|
+
the same author ([codeguard](https://github.com/aimanmalib/codeguard),
|
|
413
419
|
[documind](https://github.com/aimanmalib/documind),
|
|
414
420
|
[apiforge](https://github.com/aimanmalib/apiforge) and
|
|
415
|
-
[contentforge](https://github.com/aimanmalib/contentforge)
|
|
421
|
+
[contentforge](https://github.com/aimanmalib/contentforge)), whose test suites
|
|
416
422
|
were carried over into this repository (see [docs/porting.md](https://github.com/aimanmalib/crewforge/blob/main/docs/porting.md)
|
|
417
423
|
for what was ported, re-targeted at the shared core, or dropped and why).
|
|
418
424
|
|
|
@@ -435,10 +441,52 @@ Please report vulnerabilities privately through
|
|
|
435
441
|
See [SECURITY.md](https://github.com/aimanmalib/crewforge/blob/main/SECURITY.md) for scope notes (what is sent to your provider,
|
|
436
442
|
and what `validate` executes).
|
|
437
443
|
|
|
438
|
-
##
|
|
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
|
|
439
487
|
|
|
440
|
-
[
|
|
488
|
+
[](https://sasateguh.com/book)
|
|
441
489
|
|
|
442
|
-
|
|
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.
|
|
443
491
|
|
|
444
|
-
|
|
492
|
+
[Book a call](https://sasateguh.com/book) · hello@sasateguh.com · [More from Sasa Teguh](https://github.com/sasateguh)
|
|
@@ -1,12 +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
|
-
|
|
9
|
-
|
|
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)
|
|
10
16
|
|
|
11
17
|
```bash
|
|
12
18
|
crewforge review src/ # six reviewers + a summary
|
|
@@ -23,7 +29,7 @@ crewforge academic feedback draft.md --brief brief.md --language ms
|
|
|
23
29
|
|
|
24
30
|
## Why one crew, many recipes
|
|
25
31
|
|
|
26
|
-
crewforge started as four separate command-line tools
|
|
32
|
+
crewforge started as four separate command-line tools:
|
|
27
33
|
[codeguard](https://github.com/aimanmalib/codeguard),
|
|
28
34
|
[documind](https://github.com/aimanmalib/documind),
|
|
29
35
|
[apiforge](https://github.com/aimanmalib/apiforge) and
|
|
@@ -37,7 +43,7 @@ showed the copies had drifted and that each hid its failures differently:
|
|
|
37
43
|
- apiforge scored a spec with **no endpoints** 100/100;
|
|
38
44
|
- contentforge wrote the real API key into its YAML file, and sent `${OPENAI_API_KEY}` literally as the key.
|
|
39
45
|
|
|
40
|
-
crewforge keeps one core
|
|
46
|
+
crewforge keeps one core, so a fix lands once, and turns each tool into a
|
|
41
47
|
*recipe*: a set of agents plus the steps that connect them. The same core rules
|
|
42
48
|
apply to every recipe: non-streaming requests, bounded retries, usage numbers
|
|
43
49
|
taken only from the provider, keys only from the environment, and no run that
|
|
@@ -232,13 +238,13 @@ Saya menggunakan crewforge academic (versi 0.1.0), sebuah alat berbantukan AI, d
|
|
|
232
238
|
- 22 Oktober 2026: Perancangan: alat ini menukar taklimat tugasan (brief-ms.md) kepada 3 soalan kajian, rangka 5 bahagian dan peruntukan perkataan. ...
|
|
233
239
|
```
|
|
234
240
|
|
|
235
|
-
How sources are labelled
|
|
241
|
+
How sources are labelled: there is no "verified" status, because the tool
|
|
236
242
|
cannot check that a source exists:
|
|
237
243
|
|
|
238
244
|
| Source | Label |
|
|
239
245
|
|---|---|
|
|
240
246
|
| You supplied it | *supplied by you (not checked online)* |
|
|
241
|
-
| 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 |
|
|
242
248
|
| The model proposed it with none of those | **LIKELY FABRICATED** |
|
|
243
249
|
| The model added a DOI/URL/ISBN to a reference you supplied | **UNVERIFIED**, naming the added identifier |
|
|
244
250
|
|
|
@@ -277,16 +283,16 @@ An unknown provider name is a configuration error, not a silent fallback.
|
|
|
277
283
|
|
|
278
284
|
<sub>Source: [docs/architecture.mmd](https://github.com/aimanmalib/crewforge/blob/main/docs/architecture.mmd) (re-render with `scripts/render_architecture.py`).</sub>
|
|
279
285
|
|
|
280
|
-
- **`core/client.py
|
|
286
|
+
- **`core/client.py`**: one async client. It always sends `"stream": false`,
|
|
281
287
|
retries only HTTP 429, 5xx and network/timeout errors (with capped exponential
|
|
282
288
|
backoff that honours `Retry-After`), and fails on the first 401/403/4xx with a
|
|
283
289
|
message naming the variable to fix. The key is only ever a request header.
|
|
284
|
-
- **`core/agent.py
|
|
290
|
+
- **`core/agent.py`**: an agent is a role, a system prompt and per-agent
|
|
285
291
|
sampling defaults. `ask()` records usage and raises if the reply is blank;
|
|
286
292
|
`ask_json()` additionally requires parseable JSON (optionally a pydantic schema).
|
|
287
|
-
- **`core/crew.py
|
|
293
|
+
- **`core/crew.py`**: runs agents as sequential steps or parallel stages and
|
|
288
294
|
turns any failure into a `CrewFailedError` that lists every failed agent.
|
|
289
|
-
- **`core/usage.py
|
|
295
|
+
- **`core/usage.py`**: per-agent calls, tokens, retries and latency, taken from
|
|
290
296
|
the provider's `usage` object. Calls without usage are counted as "not reported",
|
|
291
297
|
never estimated.
|
|
292
298
|
|
|
@@ -351,10 +357,10 @@ watching them fail; see [docs/porting.md](https://github.com/aimanmalib/crewforg
|
|
|
351
357
|
|
|
352
358
|
crewforge was built with AI coding assistance (Claude Code) under the
|
|
353
359
|
direction of its author, Muhammad Aiman. It consolidates four earlier tools by
|
|
354
|
-
the same author
|
|
360
|
+
the same author ([codeguard](https://github.com/aimanmalib/codeguard),
|
|
355
361
|
[documind](https://github.com/aimanmalib/documind),
|
|
356
362
|
[apiforge](https://github.com/aimanmalib/apiforge) and
|
|
357
|
-
[contentforge](https://github.com/aimanmalib/contentforge)
|
|
363
|
+
[contentforge](https://github.com/aimanmalib/contentforge)), whose test suites
|
|
358
364
|
were carried over into this repository (see [docs/porting.md](https://github.com/aimanmalib/crewforge/blob/main/docs/porting.md)
|
|
359
365
|
for what was ported, re-targeted at the shared core, or dropped and why).
|
|
360
366
|
|
|
@@ -377,10 +383,52 @@ Please report vulnerabilities privately through
|
|
|
377
383
|
See [SECURITY.md](https://github.com/aimanmalib/crewforge/blob/main/SECURITY.md) for scope notes (what is sent to your provider,
|
|
378
384
|
and what `validate` executes).
|
|
379
385
|
|
|
380
|
-
##
|
|
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
|
|
381
429
|
|
|
382
|
-
[
|
|
430
|
+
[](https://sasateguh.com/book)
|
|
383
431
|
|
|
384
|
-
|
|
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.
|
|
385
433
|
|
|
386
|
-
|
|
434
|
+
[Book a call](https://sasateguh.com/book) · hello@sasateguh.com · [More from Sasa Teguh](https://github.com/sasateguh)
|
|
@@ -4,7 +4,7 @@ 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"
|
|
@@ -1,6 +1,6 @@
|
|
|
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
|
|
@@ -56,15 +56,21 @@ Requires-Dist: fastapi>=0.110; extra == "dev"
|
|
|
56
56
|
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
57
57
|
Dynamic: license-file
|
|
58
58
|
|
|
59
|
-
|
|
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
60
|
|
|
61
|
-
|
|
61
|
+
<h1 align="center">crewforge</h1>
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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>
|
|
64
|
+
|
|
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>
|
|
67
|
+
|
|
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)
|
|
68
74
|
|
|
69
75
|
```bash
|
|
70
76
|
crewforge review src/ # six reviewers + a summary
|
|
@@ -81,7 +87,7 @@ crewforge academic feedback draft.md --brief brief.md --language ms
|
|
|
81
87
|
|
|
82
88
|
## Why one crew, many recipes
|
|
83
89
|
|
|
84
|
-
crewforge started as four separate command-line tools
|
|
90
|
+
crewforge started as four separate command-line tools:
|
|
85
91
|
[codeguard](https://github.com/aimanmalib/codeguard),
|
|
86
92
|
[documind](https://github.com/aimanmalib/documind),
|
|
87
93
|
[apiforge](https://github.com/aimanmalib/apiforge) and
|
|
@@ -95,7 +101,7 @@ showed the copies had drifted and that each hid its failures differently:
|
|
|
95
101
|
- apiforge scored a spec with **no endpoints** 100/100;
|
|
96
102
|
- contentforge wrote the real API key into its YAML file, and sent `${OPENAI_API_KEY}` literally as the key.
|
|
97
103
|
|
|
98
|
-
crewforge keeps one core
|
|
104
|
+
crewforge keeps one core, so a fix lands once, and turns each tool into a
|
|
99
105
|
*recipe*: a set of agents plus the steps that connect them. The same core rules
|
|
100
106
|
apply to every recipe: non-streaming requests, bounded retries, usage numbers
|
|
101
107
|
taken only from the provider, keys only from the environment, and no run that
|
|
@@ -290,13 +296,13 @@ Saya menggunakan crewforge academic (versi 0.1.0), sebuah alat berbantukan AI, d
|
|
|
290
296
|
- 22 Oktober 2026: Perancangan: alat ini menukar taklimat tugasan (brief-ms.md) kepada 3 soalan kajian, rangka 5 bahagian dan peruntukan perkataan. ...
|
|
291
297
|
```
|
|
292
298
|
|
|
293
|
-
How sources are labelled
|
|
299
|
+
How sources are labelled: there is no "verified" status, because the tool
|
|
294
300
|
cannot check that a source exists:
|
|
295
301
|
|
|
296
302
|
| Source | Label |
|
|
297
303
|
|---|---|
|
|
298
304
|
| You supplied it | *supplied by you (not checked online)* |
|
|
299
|
-
| 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 |
|
|
300
306
|
| The model proposed it with none of those | **LIKELY FABRICATED** |
|
|
301
307
|
| The model added a DOI/URL/ISBN to a reference you supplied | **UNVERIFIED**, naming the added identifier |
|
|
302
308
|
|
|
@@ -335,16 +341,16 @@ An unknown provider name is a configuration error, not a silent fallback.
|
|
|
335
341
|
|
|
336
342
|
<sub>Source: [docs/architecture.mmd](https://github.com/aimanmalib/crewforge/blob/main/docs/architecture.mmd) (re-render with `scripts/render_architecture.py`).</sub>
|
|
337
343
|
|
|
338
|
-
- **`core/client.py
|
|
344
|
+
- **`core/client.py`**: one async client. It always sends `"stream": false`,
|
|
339
345
|
retries only HTTP 429, 5xx and network/timeout errors (with capped exponential
|
|
340
346
|
backoff that honours `Retry-After`), and fails on the first 401/403/4xx with a
|
|
341
347
|
message naming the variable to fix. The key is only ever a request header.
|
|
342
|
-
- **`core/agent.py
|
|
348
|
+
- **`core/agent.py`**: an agent is a role, a system prompt and per-agent
|
|
343
349
|
sampling defaults. `ask()` records usage and raises if the reply is blank;
|
|
344
350
|
`ask_json()` additionally requires parseable JSON (optionally a pydantic schema).
|
|
345
|
-
- **`core/crew.py
|
|
351
|
+
- **`core/crew.py`**: runs agents as sequential steps or parallel stages and
|
|
346
352
|
turns any failure into a `CrewFailedError` that lists every failed agent.
|
|
347
|
-
- **`core/usage.py
|
|
353
|
+
- **`core/usage.py`**: per-agent calls, tokens, retries and latency, taken from
|
|
348
354
|
the provider's `usage` object. Calls without usage are counted as "not reported",
|
|
349
355
|
never estimated.
|
|
350
356
|
|
|
@@ -409,10 +415,10 @@ watching them fail; see [docs/porting.md](https://github.com/aimanmalib/crewforg
|
|
|
409
415
|
|
|
410
416
|
crewforge was built with AI coding assistance (Claude Code) under the
|
|
411
417
|
direction of its author, Muhammad Aiman. It consolidates four earlier tools by
|
|
412
|
-
the same author
|
|
418
|
+
the same author ([codeguard](https://github.com/aimanmalib/codeguard),
|
|
413
419
|
[documind](https://github.com/aimanmalib/documind),
|
|
414
420
|
[apiforge](https://github.com/aimanmalib/apiforge) and
|
|
415
|
-
[contentforge](https://github.com/aimanmalib/contentforge)
|
|
421
|
+
[contentforge](https://github.com/aimanmalib/contentforge)), whose test suites
|
|
416
422
|
were carried over into this repository (see [docs/porting.md](https://github.com/aimanmalib/crewforge/blob/main/docs/porting.md)
|
|
417
423
|
for what was ported, re-targeted at the shared core, or dropped and why).
|
|
418
424
|
|
|
@@ -435,10 +441,52 @@ Please report vulnerabilities privately through
|
|
|
435
441
|
See [SECURITY.md](https://github.com/aimanmalib/crewforge/blob/main/SECURITY.md) for scope notes (what is sent to your provider,
|
|
436
442
|
and what `validate` executes).
|
|
437
443
|
|
|
438
|
-
##
|
|
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
|
|
439
487
|
|
|
440
|
-
[
|
|
488
|
+
[](https://sasateguh.com/book)
|
|
441
489
|
|
|
442
|
-
|
|
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.
|
|
443
491
|
|
|
444
|
-
|
|
492
|
+
[Book a call](https://sasateguh.com/book) · hello@sasateguh.com · [More from Sasa Teguh](https://github.com/sasateguh)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|