devcrew 0.1.0__py3-none-any.whl
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.
- devcrew/__init__.py +3 -0
- devcrew/agents.py +80 -0
- devcrew/cli.py +71 -0
- devcrew/crew.py +33 -0
- devcrew/schemas.py +66 -0
- devcrew/tasks.py +74 -0
- devcrew-0.1.0.dist-info/METADATA +143 -0
- devcrew-0.1.0.dist-info/RECORD +11 -0
- devcrew-0.1.0.dist-info/WHEEL +4 -0
- devcrew-0.1.0.dist-info/entry_points.txt +2 -0
- devcrew-0.1.0.dist-info/licenses/LICENSE +21 -0
devcrew/__init__.py
ADDED
devcrew/agents.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""The four specialised agents.
|
|
2
|
+
|
|
3
|
+
Each agent gets a narrow role, goal and backstory ("role-scoped context").
|
|
4
|
+
This is deliberate: a focused prompt hallucinates less than one giant
|
|
5
|
+
prompt asking a single LLM to plan, code, test and review all at once.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
from crewai import LLM, Agent
|
|
11
|
+
|
|
12
|
+
DEFAULT_MODEL = "gpt-4o-mini"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_llm(model: str | None = None) -> LLM:
|
|
16
|
+
"""One shared LLM config. Model comes from the argument, then the MODEL env var."""
|
|
17
|
+
return LLM(
|
|
18
|
+
model=model or os.getenv("MODEL", DEFAULT_MODEL),
|
|
19
|
+
temperature=0.3, # low temp = more deterministic, parseable output
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def project_manager(llm: LLM) -> Agent:
|
|
24
|
+
return Agent(
|
|
25
|
+
role="Project Manager",
|
|
26
|
+
goal="Break the user's idea into a small, concrete development plan.",
|
|
27
|
+
backstory=(
|
|
28
|
+
"You are a pragmatic software project manager. You take vague "
|
|
29
|
+
"one-line ideas and turn them into 3-6 unambiguous tasks a "
|
|
30
|
+
"developer can implement in a single Python file. You never "
|
|
31
|
+
"invent features the user did not ask for."
|
|
32
|
+
),
|
|
33
|
+
llm=llm,
|
|
34
|
+
verbose=True,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def developer(llm: LLM) -> Agent:
|
|
39
|
+
return Agent(
|
|
40
|
+
role="Python Developer",
|
|
41
|
+
goal="Implement the project plan as clean, working Python code.",
|
|
42
|
+
backstory=(
|
|
43
|
+
"You are a senior Python developer. You write a single, "
|
|
44
|
+
"self-contained, runnable Python file with functions, docstrings "
|
|
45
|
+
"and a __main__ demo block. You implement exactly the tasks in "
|
|
46
|
+
"the plan — nothing more. You only use the standard library."
|
|
47
|
+
),
|
|
48
|
+
llm=llm,
|
|
49
|
+
verbose=True,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def qa_tester(llm: LLM) -> Agent:
|
|
54
|
+
return Agent(
|
|
55
|
+
role="QA Tester",
|
|
56
|
+
goal="Find bugs and untested edge cases in the developer's code.",
|
|
57
|
+
backstory=(
|
|
58
|
+
"You are a sceptical QA engineer. You read code line by line "
|
|
59
|
+
"looking for edge cases: empty inputs, wrong types, negative "
|
|
60
|
+
"numbers, duplicates. You design test cases and honestly mark "
|
|
61
|
+
"which ones the current code would fail."
|
|
62
|
+
),
|
|
63
|
+
llm=llm,
|
|
64
|
+
verbose=True,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def code_reviewer(llm: LLM) -> Agent:
|
|
69
|
+
return Agent(
|
|
70
|
+
role="Code Reviewer",
|
|
71
|
+
goal="Judge the code on readability and correctness, using the QA report.",
|
|
72
|
+
backstory=(
|
|
73
|
+
"You are a strict but fair code reviewer. You consider both the "
|
|
74
|
+
"code and the QA report, score readability and correctness out "
|
|
75
|
+
"of 10, and give a final verdict: approved or changes_requested. "
|
|
76
|
+
"You point at specific functions, never vague advice."
|
|
77
|
+
),
|
|
78
|
+
llm=llm,
|
|
79
|
+
verbose=True,
|
|
80
|
+
)
|
devcrew/cli.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Command-line entry point: `devcrew "your project idea"`."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from dotenv import load_dotenv
|
|
8
|
+
|
|
9
|
+
from . import __version__
|
|
10
|
+
from .agents import DEFAULT_MODEL
|
|
11
|
+
|
|
12
|
+
OUTPUT_FILES = (
|
|
13
|
+
("01_plan.json", "Project Manager's plan"),
|
|
14
|
+
("02_code.py", "Developer's code"),
|
|
15
|
+
("03_test_report.json", "QA Tester's report"),
|
|
16
|
+
("04_review.json", "Code Reviewer's verdict"),
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
21
|
+
parser = argparse.ArgumentParser(
|
|
22
|
+
prog="devcrew",
|
|
23
|
+
description="Run an AI software team (plan -> code -> test -> review) on a one-line idea.",
|
|
24
|
+
)
|
|
25
|
+
parser.add_argument("idea", help='what to build, e.g. "a CLI expense tracker"')
|
|
26
|
+
parser.add_argument(
|
|
27
|
+
"-o",
|
|
28
|
+
"--output-dir",
|
|
29
|
+
default="output",
|
|
30
|
+
help="folder for results, relative to the current directory (default: output)",
|
|
31
|
+
)
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"-m", "--model", default=None, help=f"LLM to use (default: $MODEL or {DEFAULT_MODEL})"
|
|
34
|
+
)
|
|
35
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
36
|
+
return parser
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main(argv: list[str] | None = None) -> int:
|
|
40
|
+
parser = build_parser()
|
|
41
|
+
args = parser.parse_args(argv)
|
|
42
|
+
|
|
43
|
+
# CrewAI only writes task output to relative paths: it rejects ".." and "~",
|
|
44
|
+
# and silently drops the leading "/" of an absolute path.
|
|
45
|
+
if (
|
|
46
|
+
os.path.isabs(args.output_dir)
|
|
47
|
+
or ".." in args.output_dir.split(os.sep)
|
|
48
|
+
or (args.output_dir.startswith(("~", "$")))
|
|
49
|
+
):
|
|
50
|
+
parser.error("--output-dir must be a relative path inside the current directory")
|
|
51
|
+
|
|
52
|
+
load_dotenv()
|
|
53
|
+
|
|
54
|
+
if not os.getenv("OPENAI_API_KEY"):
|
|
55
|
+
sys.exit("Missing OPENAI_API_KEY. Copy .env.example to .env and add your key.")
|
|
56
|
+
|
|
57
|
+
os.makedirs(args.output_dir, exist_ok=True)
|
|
58
|
+
|
|
59
|
+
# Imported here so `--help` and `--version` stay fast.
|
|
60
|
+
from .crew import run
|
|
61
|
+
|
|
62
|
+
print(f"\n🚀 DevCrew starting on: {args.idea}\n")
|
|
63
|
+
run(args.idea, output_dir=args.output_dir, model=args.model)
|
|
64
|
+
print(f"\n✅ Done. Check the {args.output_dir}/ folder:")
|
|
65
|
+
for name, what in OUTPUT_FILES:
|
|
66
|
+
print(f" {name:<20}— {what}")
|
|
67
|
+
return 0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
if __name__ == "__main__":
|
|
71
|
+
sys.exit(main())
|
devcrew/crew.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Assemble the crew and run the pipeline end-to-end."""
|
|
2
|
+
|
|
3
|
+
from crewai import Crew, Process
|
|
4
|
+
|
|
5
|
+
from . import agents, tasks
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def build_crew(output_dir: str = "output", model: str | None = None) -> Crew:
|
|
9
|
+
llm = agents.get_llm(model)
|
|
10
|
+
|
|
11
|
+
pm = agents.project_manager(llm)
|
|
12
|
+
dev = agents.developer(llm)
|
|
13
|
+
qa = agents.qa_tester(llm)
|
|
14
|
+
reviewer = agents.code_reviewer(llm)
|
|
15
|
+
|
|
16
|
+
t_plan = tasks.plan_task(pm, output_dir=output_dir)
|
|
17
|
+
t_code = tasks.code_task(dev, plan=t_plan, output_dir=output_dir)
|
|
18
|
+
t_test = tasks.test_task(qa, code=t_code, output_dir=output_dir)
|
|
19
|
+
t_review = tasks.review_task(reviewer, code=t_code, tests=t_test, output_dir=output_dir)
|
|
20
|
+
|
|
21
|
+
return Crew(
|
|
22
|
+
agents=[pm, dev, qa, reviewer],
|
|
23
|
+
tasks=[t_plan, t_code, t_test, t_review],
|
|
24
|
+
process=Process.sequential, # strict order: plan -> code -> test -> review
|
|
25
|
+
verbose=True,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def run(idea: str, output_dir: str = "output", model: str | None = None) -> str:
|
|
30
|
+
"""Run the full pipeline for a one-line project idea."""
|
|
31
|
+
crew = build_crew(output_dir=output_dir, model=model)
|
|
32
|
+
result = crew.kickoff(inputs={"idea": idea})
|
|
33
|
+
return str(result)
|
devcrew/schemas.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Pydantic schemas that force each agent to return structured JSON.
|
|
2
|
+
|
|
3
|
+
Why this matters: LLM agents tend to ramble. By binding each task to a
|
|
4
|
+
schema, the output of one agent becomes machine-parseable input for the
|
|
5
|
+
next agent in the pipeline — no regex, no guessing.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Literal
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
|
|
12
|
+
# ---------- Project Manager output ----------
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PlanItem(BaseModel):
|
|
16
|
+
id: int = Field(description="Sequential task id, starting at 1")
|
|
17
|
+
title: str = Field(description="Short task title")
|
|
18
|
+
description: str = Field(description="What exactly needs to be built")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ProjectPlan(BaseModel):
|
|
22
|
+
project_name: str
|
|
23
|
+
summary: str = Field(description="One-paragraph summary of the project")
|
|
24
|
+
tasks: list[PlanItem] = Field(description="3-6 concrete development tasks")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# ---------- QA Tester output ----------
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestCase(BaseModel):
|
|
31
|
+
name: str
|
|
32
|
+
scenario: str = Field(description="What is being tested")
|
|
33
|
+
expected: str = Field(description="Expected behaviour")
|
|
34
|
+
verdict: Literal["pass", "fail"] = Field(
|
|
35
|
+
description="'pass' or 'fail' based on reading the code"
|
|
36
|
+
)
|
|
37
|
+
notes: str = Field(default="", description="Why it passes/fails")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TestReport(BaseModel):
|
|
41
|
+
total_cases: int
|
|
42
|
+
passed: int
|
|
43
|
+
failed: int
|
|
44
|
+
test_cases: list[TestCase]
|
|
45
|
+
bugs_found: list[str] = Field(description="Concrete bugs or edge cases the code misses")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# ---------- Code Reviewer output ----------
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ReviewComment(BaseModel):
|
|
52
|
+
severity: Literal["critical", "major", "minor"] = Field(
|
|
53
|
+
description="'critical', 'major' or 'minor'"
|
|
54
|
+
)
|
|
55
|
+
location: str = Field(description="Function or section of code")
|
|
56
|
+
comment: str
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ReviewReport(BaseModel):
|
|
60
|
+
verdict: Literal["approved", "changes_requested"] = Field(
|
|
61
|
+
description="'approved' or 'changes_requested'"
|
|
62
|
+
)
|
|
63
|
+
readability_score: int = Field(ge=1, le=10, description="1-10")
|
|
64
|
+
correctness_score: int = Field(ge=1, le=10, description="1-10")
|
|
65
|
+
comments: list[ReviewComment]
|
|
66
|
+
summary: str = Field(description="Final review summary in 2-3 sentences")
|
devcrew/tasks.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""The pipeline: Plan -> Code -> Test -> Review.
|
|
2
|
+
|
|
3
|
+
The hand-off between agents happens through CrewAI's `context` parameter:
|
|
4
|
+
each task receives the *output* of the previous task(s) as input. That is
|
|
5
|
+
the "orchestrated hand-off" — no agent sees the whole conversation, only
|
|
6
|
+
what it needs.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
from crewai import Agent, Task
|
|
12
|
+
|
|
13
|
+
from .schemas import ProjectPlan, ReviewReport, TestReport
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def plan_task(agent: Agent, output_dir: str = "output") -> Task:
|
|
17
|
+
return Task(
|
|
18
|
+
description=(
|
|
19
|
+
"The user wants to build: '{idea}'.\n"
|
|
20
|
+
"Create a development plan with 3-6 concrete tasks. The whole "
|
|
21
|
+
"project must fit in ONE Python file using only the standard "
|
|
22
|
+
"library."
|
|
23
|
+
),
|
|
24
|
+
expected_output="A structured project plan as JSON.",
|
|
25
|
+
agent=agent,
|
|
26
|
+
output_json=ProjectPlan,
|
|
27
|
+
output_file=os.path.join(output_dir, "01_plan.json"),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def code_task(agent: Agent, plan: Task, output_dir: str = "output") -> Task:
|
|
32
|
+
return Task(
|
|
33
|
+
description=(
|
|
34
|
+
"Implement the project plan you received as ONE self-contained "
|
|
35
|
+
"Python file. Include docstrings and a small demo under "
|
|
36
|
+
"`if __name__ == '__main__':`. Output ONLY the raw Python code, "
|
|
37
|
+
"no markdown fences, no explanations."
|
|
38
|
+
),
|
|
39
|
+
expected_output="A single runnable Python file.",
|
|
40
|
+
agent=agent,
|
|
41
|
+
context=[plan], # hand-off: developer only sees the plan
|
|
42
|
+
output_file=os.path.join(output_dir, "02_code.py"),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_task(agent: Agent, code: Task, output_dir: str = "output") -> Task:
|
|
47
|
+
return Task(
|
|
48
|
+
description=(
|
|
49
|
+
"Read the Python code you received and design 5-8 test cases "
|
|
50
|
+
"covering normal use and edge cases (empty input, invalid input, "
|
|
51
|
+
"duplicates, boundaries). For each, decide honestly whether the "
|
|
52
|
+
"CURRENT code would pass or fail, and list concrete bugs."
|
|
53
|
+
),
|
|
54
|
+
expected_output="A structured QA test report as JSON.",
|
|
55
|
+
agent=agent,
|
|
56
|
+
context=[code], # hand-off: tester only sees the code
|
|
57
|
+
output_json=TestReport,
|
|
58
|
+
output_file=os.path.join(output_dir, "03_test_report.json"),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def review_task(agent: Agent, code: Task, tests: Task, output_dir: str = "output") -> Task:
|
|
63
|
+
return Task(
|
|
64
|
+
description=(
|
|
65
|
+
"Review the code, taking the QA report into account. Score "
|
|
66
|
+
"readability and correctness out of 10, leave specific comments "
|
|
67
|
+
"with severity levels, and give a final verdict."
|
|
68
|
+
),
|
|
69
|
+
expected_output="A structured code review as JSON.",
|
|
70
|
+
agent=agent,
|
|
71
|
+
context=[code, tests], # hand-off: reviewer sees code + QA report
|
|
72
|
+
output_json=ReviewReport,
|
|
73
|
+
output_file=os.path.join(output_dir, "04_review.json"),
|
|
74
|
+
)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: devcrew
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An AI software team in a pipeline: four agents plan, code, test and review a project from a one-line idea.
|
|
5
|
+
Project-URL: Homepage, https://github.com/agrvasu05/DevCrew
|
|
6
|
+
Project-URL: Issues, https://github.com/agrvasu05/DevCrew/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/agrvasu05/DevCrew/blob/main/CHANGELOG.md
|
|
8
|
+
Author: Vasu Agrawal
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,ai,code-generation,code-review,crewai,llm,multi-agent
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
22
|
+
Requires-Python: <3.14,>=3.10
|
|
23
|
+
Requires-Dist: crewai>=1.0.0
|
|
24
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# DevCrew — Multi-Agent AI Orchestration System
|
|
31
|
+
|
|
32
|
+
[](https://github.com/agrvasu05/DevCrew/actions/workflows/ci.yml)
|
|
33
|
+
[](LICENSE)
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
An AI software team in a pipeline. You give it a one-line project idea; four specialised LLM agents plan it, code it, test it, and review it — each handing structured output to the next.
|
|
37
|
+
|
|
38
|
+
Built with **CrewAI** on the OpenAI API.
|
|
39
|
+
|
|
40
|
+
## How it works
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
idea ─→ ┌─────────────────┐ ┌─────────────────┐
|
|
44
|
+
│ Project Manager │ ───→ │ Developer │
|
|
45
|
+
│ plan.json │ │ code.py │
|
|
46
|
+
└─────────────────┘ └───────┬─────────┘
|
|
47
|
+
│
|
|
48
|
+
▼
|
|
49
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
50
|
+
│ Code Reviewer │ ←─── │ QA Tester │
|
|
51
|
+
│ review.json │ │ test_report.json│
|
|
52
|
+
└─────────────────┘ └─────────────────┘
|
|
53
|
+
(sees code + QA report)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
1. **Project Manager** turns the idea into a 3–6 task plan (JSON).
|
|
57
|
+
2. **Developer** implements the plan as one runnable Python file.
|
|
58
|
+
3. **QA Tester** designs edge-case tests against the code and honestly marks which would fail (JSON).
|
|
59
|
+
4. **Code Reviewer** reads the code *and* the QA report, scores it, and gives a verdict (JSON).
|
|
60
|
+
|
|
61
|
+
## Design decisions
|
|
62
|
+
|
|
63
|
+
- **Role-scoped context, not one giant prompt.** Each agent only receives what it needs (the developer sees the plan, not the user's raw message). Narrow prompts hallucinate less and stay on task.
|
|
64
|
+
- **Structured JSON outputs via Pydantic.** Every non-code output is bound to a schema (`devcrew/schemas.py`), so one agent's output is machine-parseable input for the next — no regex, no parsing failures.
|
|
65
|
+
- **Sequential process.** A software pipeline has a natural order; sequential orchestration keeps the run deterministic and debuggable. Every stage is written to `output/` so you can inspect exactly where a run went wrong.
|
|
66
|
+
- **Adversarial QA.** The tester is prompted to be sceptical and mark failures honestly, and the reviewer sees the QA report — so the review verdict is grounded in found bugs, not vibes.
|
|
67
|
+
|
|
68
|
+
## Run it
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
git clone https://github.com/agrvasu05/DevCrew && cd DevCrew
|
|
72
|
+
pip install -e .
|
|
73
|
+
cp .env.example .env # add your OPENAI_API_KEY
|
|
74
|
+
|
|
75
|
+
devcrew "Build a CLI expense tracker with categories and monthly totals"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`python main.py "..."` still works if you'd rather not install the package.
|
|
79
|
+
|
|
80
|
+
| Option | Default | What it does |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `-o`, `--output-dir` | `output` | Where results go (a path relative to the current directory) |
|
|
83
|
+
| `-m`, `--model` | `$MODEL` or `gpt-4o-mini` | Which LLM the agents use |
|
|
84
|
+
| `--version` | | Print the version |
|
|
85
|
+
|
|
86
|
+
Outputs land in the output directory:
|
|
87
|
+
|
|
88
|
+
| File | Agent | Contents |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| `01_plan.json` | Project Manager | Task breakdown |
|
|
91
|
+
| `02_code.py` | Developer | Runnable Python file |
|
|
92
|
+
| `03_test_report.json` | QA Tester | Test cases + bugs found |
|
|
93
|
+
| `04_review.json` | Code Reviewer | Scores, comments, verdict |
|
|
94
|
+
|
|
95
|
+
A full example run is committed in [`sample_output/`](sample_output/).
|
|
96
|
+
|
|
97
|
+
> DevCrew never runs the code it generates. Read `02_code.py` before you execute it.
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pip install -e ".[dev]"
|
|
103
|
+
pytest # no API key or network needed
|
|
104
|
+
ruff check .
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The tests check how the pipeline is wired (which agent sees which output) and validate
|
|
108
|
+
`sample_output/` against the schemas, without calling an LLM. CI runs them on Python 3.10–3.13.
|
|
109
|
+
|
|
110
|
+
## Roadmap
|
|
111
|
+
|
|
112
|
+
- Feed the reviewer's verdict back to the Developer for a fix-up round when changes are requested
|
|
113
|
+
- Actually run the generated code against the QA test cases in a sandbox
|
|
114
|
+
- Support projects that span more than one file
|
|
115
|
+
- A small eval set of project ideas to catch prompt regressions in CI
|
|
116
|
+
|
|
117
|
+
Ideas and PRs are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
118
|
+
|
|
119
|
+
## Stack
|
|
120
|
+
|
|
121
|
+
Python · CrewAI · OpenAI API · Pydantic
|
|
122
|
+
|
|
123
|
+
## Project structure
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
devcrew/
|
|
127
|
+
├── main.py # thin wrapper around devcrew.cli
|
|
128
|
+
├── devcrew/
|
|
129
|
+
│ ├── cli.py # `devcrew` command-line entry point
|
|
130
|
+
│ ├── agents.py # 4 agents with role-scoped prompts
|
|
131
|
+
│ ├── tasks.py # pipeline tasks + context hand-offs
|
|
132
|
+
│ ├── schemas.py # Pydantic schemas for structured JSON
|
|
133
|
+
│ └── crew.py # crew assembly (sequential process)
|
|
134
|
+
├── sample_output/ # committed example run
|
|
135
|
+
├── tests/ # offline unit tests
|
|
136
|
+
├── pyproject.toml
|
|
137
|
+
├── requirements.txt
|
|
138
|
+
└── .env.example
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
[MIT](LICENSE) © Vasu Agrawal
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
devcrew/__init__.py,sha256=b5HYA_4lnPE-WrarBBTVBvw-VRH8lQ3U36JyUA87zM4,108
|
|
2
|
+
devcrew/agents.py,sha256=EHXo2Lxdnv9DgLZrUpnE1-DerJeiRqrcUhuTnm16_3o,2743
|
|
3
|
+
devcrew/cli.py,sha256=AuMCy-UEkMxu80XM5WD06hM3clpZovnOw5GH-ubRPDY,2234
|
|
4
|
+
devcrew/crew.py,sha256=jb3mGyne-7yC0ZWeNRwTtt_741tND4QRAl-IjV_P5DY,1157
|
|
5
|
+
devcrew/schemas.py,sha256=_XvI_wEi0vO6CJoeD24Lg9s8kxO1nLu-AiRAtSrQ8b4,2121
|
|
6
|
+
devcrew/tasks.py,sha256=dJQh1C-P9ZtDdEGM3dnDEsfqEaBLiVMgcqe7yl0BcGE,2842
|
|
7
|
+
devcrew-0.1.0.dist-info/METADATA,sha256=xbjFeofvbbxYeOh906hggmbDofhGZqOKDdTx2GDpMys,6429
|
|
8
|
+
devcrew-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
9
|
+
devcrew-0.1.0.dist-info/entry_points.txt,sha256=ViCXHUuWsN5mGfaDO7sRvYnD_nOH3faEAHNlg-k8-ko,45
|
|
10
|
+
devcrew-0.1.0.dist-info/licenses/LICENSE,sha256=fc3Um9yZj96IwCbnwNCmkWs6ZvlGDqz3YUfacpaxios,1069
|
|
11
|
+
devcrew-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vasu Agrawal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|