| title | AI Sprint Manager | ||||||
|---|---|---|---|---|---|---|---|
| emoji | 🤖 | ||||||
| colorFrom | blue | ||||||
| colorTo | purple | ||||||
| sdk | docker | ||||||
| pinned | false | ||||||
| tags |
|
A reinforcement learning environment where an AI agent acts as a Tech Lead managing agile software sprints — from a single 10-day sprint (Round 1) to a full 60-day, 6-sprint project (Round 2).
Modern software teams spend enormous time on sprint planning decisions:
- Which developer gets which task?
- What do you do when someone goes sick mid-sprint?
- How do you handle a stakeholder instruction that arrives on day 23 and invalidates your whole plan?
This environment simulates these real-world decisions so an AI agent can learn optimal sprint management strategies through reinforcement learning.
The agent plays the role of a Tech Lead. Each step it observes the full sprint state (tasks, developers, workloads, deadlines, active instructions) and takes an action. The environment responds with a reward signal that guides learning.
┌─────────────────────────────────────────┐
│ RL Agent / LLM / Training Loop │
│ inference.py (R1) / inference_r2.py │
└──────────────────┬──────────────────────┘
│ HTTP reset / step / state
▼
┌─────────────────────────────────────────┐
│ FastAPI Server (port 7860) │
│ /reset /step /state /health │
│ /project/reset /project/step (R2) │
└──────────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Sprint Environment (core logic) │
│ • Task/developer simulation │
│ • Reward calculation (3-layer for R2) │
│ • Random events (bugs, absences) │
│ • 3 graders: easy / medium / hard │
│ • Tech debt & instruction following │
└──────────────────┬──────────────────────┘
│ data loaded from
▼
┌─────────────────────────────────────────┐
│ data/sprint_data.json │
│ (customizable — bring your own data!) │
└─────────────────────────────────────────┘
- Select a sprint scenario (easy / medium / hard)
- Click 🔄 Reset Sprint
- Use the Skill → Dev Guide to assign tasks correctly
- Or click 🤖 Auto-Assign All to let the system decide
- Watch the reward history and task status update in real time
| Field | Type | Values |
|---|---|---|
action_type |
string | assign, reassign, reprioritize, unblock, skip |
task_id |
string | Task ID e.g. "T1", "T6" |
dev_id |
string | Developer ID e.g. "dev1", "dev3" |
new_priority |
int | 1–5 (1=highest, for reprioritize only) |
| Field | Type | Description |
|---|---|---|
current_day |
int | Day in sprint (1–10) or project (1–60) |
current_sprint |
int | Active sprint number (R2 only) |
sprint_length |
int | Total sprint length |
developers |
list | Each dev's skill, capacity, load, tasks, availability |
tasks |
list | Each task's type, priority, effort, deadline, status, progress, deps |
reward |
float | Step reward |
cumulative_reward |
float | Total reward this episode |
tasks_completed/missed/in_progress/backlog |
int | Status counts |
workload_balance_score |
float | 0=unbalanced, 1=perfect |
instruction_following_score |
float | Running avg: 1.0=all instructions followed (R2) |
tech_debt |
list | Tasks that missed sprint deadlines (R2) |
active_instructions |
list | Current stakeholder instructions (R2) |
events |
list | Events that just happened (completions, misses, absences) |
done |
bool | Whether episode is complete |
| ID | Difficulty | Devs | Tasks | Random Events |
|---|---|---|---|---|
easy_sprint |
🟢 Easy | 3 | 5 | None |
medium_sprint |
🟡 Medium | 4 | 8 | Dev absences, bugs expire |
hard_sprint |
🔴 Hard | 5 | 12 | Urgent bugs mid-sprint, cascading failures |
| ID | Difficulty | Devs | Tasks | Features |
|---|---|---|---|---|
project_easy |
🟢 Easy | 4 | 25 | Cross-sprint deps, time-released instructions |
project_medium |
🟡 Medium | 5 | 30 | Absences, burnout, tech debt |
project_hard |
🔴 Hard | 6 | 40 | All of the above + cascading failures |
⚠️ Important context: All three models share the same Guard/Loop/Stall inference wrapper — when the wrapper overrides an invalid model action, the rule-based fallback agent executes that step instead. Fallback rates differ by model and scenario and affect how much of each score is attributable to the LLM vs. the fallback. See the fallback rate tables below.
| Model | easy_sprint | medium_sprint | hard_sprint | Average |
|---|---|---|---|---|
| Rule-Based | 0.9900 | 0.6667 | 0.3716 | 0.6761 |
| Llama-3.1-8B (baseline) | 0.9900 | 0.5000 | 0.2858 | 0.5919 |
| Trained Qwen2.5-1.5B | 0.9900 | 0.6667 | 0.2858 | 0.6475 |
R1 Fallback Rates (% of steps where Guard/Loop overrode the model):
| Model | easy_sprint | medium_sprint | hard_sprint | Average |
|---|---|---|---|---|
| Rule-Based | — | — | — | — (is the fallback) |
| Llama-3.1-8B | 0% | 40% | 20% | 20% |
| Trained Qwen2.5-1.5B | 71% | 80% | 90% | 80% |
The trained model's R1 scores should be interpreted carefully: with 80% fallback rate, these scores primarily reflect the rule-based agent running, not the trained model. The model's training gap in R1 is T01-fixation — it re-proposes already-assigned tasks on nearly every step.
| Model | project_easy | project_medium | project_hard | Average |
|---|---|---|---|---|
| Rule-Based | 0.2308 | 0.1693 | 0.1049 | 0.1683 |
| Llama-3.1-8B (baseline) | 0.2567 | 0.1647 | 0.0870 | 0.1694 |
| Trained Qwen2.5-1.5B | 0.2567 | 0.2027 | 0.0750 | 0.1781 |
R2 Fallback Rates:
| Model | project_easy | project_medium | project_hard | Average |
|---|---|---|---|---|
| Rule-Based | — | — | — | — |
| Llama-3.1-8B | 33% | 42% | 23% | 33% |
| Trained Qwen2.5-1.5B | 43% | 38% | 32% | 38% |
The trained model achieves the highest R2 average with ~62% model autonomy on average. The project_medium improvement (+20% over rule-based, +23% over Llama) is the most credible result: genuine model-driven improvement with STALL-rescued reassignments contributing in sprint 2. The project_hard underperformance (0.0750 vs 0.1049 rule-based) at 68% model autonomy is genuinely attributable to model decisions.
| Event | Reward |
|---|---|
| Assign task (skill match) | +0.8 to +1.3 |
| Assign task (skill mismatch penalty) | +0.1 to +0.6 |
| Wrong skill / over capacity | -0.15 |
| Task completed on time | +0.5 to +2.5 |
| Task completed late | +0.1 |
| Task missed deadline | -0.3 to -1.5 |
| Urgent bug missed | -0.25 extra |
| Skip (no action) | -0.05 |
| Final score bonus | score × 10.0 |
| Layer | Trigger | Signal |
|---|---|---|
| Step reward | Every action | Same as R1 + instruction weight |
| Sprint boundary | Every 10 days | ±delivery rate, burnout penalty, miss penalty |
| Final score | Day 60 | delivery_rate×0.55 + inst_score×0.30 + team_health×0.15 |
GRPO training signal: combined = step_norm × 0.6 + inst_score × 0.4
The inference layer has three defence mechanisms to handle invalid or degenerate model outputs:
GUARD — validates every action before executing it. Checks: task not already assigned this episode, dependency tasks are complete, task is in backlog, developer has capacity. Fires fallback on any violation.
LOOP — detects repetition. If the model emits the same (action_type, task_id) pair twice consecutively, overrides with rule-based fallback. Prevents the greedy-decoding lock-on failure mode.
STALL — detects long-running tasks. If a task has been in_progress for more than max(5, effort×1.5) days, reassigns to a higher-productivity developer. Unblocks frozen dependency chains before they cascade.
Fallback rates in practice: The trained model triggers fallback on ~80% of R1 steps (primarily
already_assignedviolations — the model re-proposes already-allocated tasks) and ~38% of R2 steps. Llama triggers fallback on ~20% of R1 steps and ~33% of R2 steps. When fallback fires, the rule-based agent makes that decision. Scores should be interpreted in light of these rates.
# Health check
GET /health → {"status": "ok", "env": "ai-sprint-manager"}
# Round 1
POST /reset Body: {"task_name": "easy_sprint", "seed": 42}
POST /step Body: {"action": {"action_type": "assign", "task_id": "T1", "dev_id": "dev1"}}
GET /state
GET /tasks
# Round 2 (multi-sprint project)
POST /project/reset Body: {"task_name": "project_easy", "seed": 42}
POST /project/step Body: {"action": {"action_type": "assign", "task_id": "T01", "dev_id": "dev1"}}
GET /project/statefrom client import SprintEnvClient
from sprint_env.models import SprintAction
# Connect to live Space
with SprintEnvClient(base_url="https://sejal-k-ai-sprint-manager.hf.space") as env:
obs = env.reset(task_name="medium_sprint", seed=42)
while not obs["done"]:
action = SprintAction(
action_type="assign",
task_id="T1",
dev_id="dev1",
)
result = env.step(action)
print(result) # StepResult(reward=+1.20, done=False, day=2, completed=0)
obs = result.observationai-sprint-manager-openenv/
├── openenv.yaml # OpenEnv spec metadata
├── pyproject.toml # Project dependencies
├── Dockerfile # Container definition
├── requirements.txt # Python dependencies
├── inference.py # R1 LLM agent (trained model + guard/loop)
├── inference_r2.py # R2 LLM agent (60-day + guard/loop/stall)
├── train_llm.py # SFT + GRPO training pipeline
├── client.py # Typed Python client
├── project_client.py # R2 Typed Python client (for RL training)
├── ui.py # Gradio UI + FastAPI combined server
├── start.sh # Container startup script
│
├── data/
│ └── sprint_data.json # All scenario data (customizable!)
│
├── sprint_env/
│ ├── __init__.py
│ ├── models.py # Pydantic Action/Observation/State
│ ├── tasks.py # Task & Developer dataclasses
│ ├── environment.py # Core RL environment logic (R1)
│ ├── project_graders.py # R2 Scoring functions (easy/medium/hard)
│ ├── project_models.py # R2 Pydantic Action/Observation/State
│ ├── project_environment.py # Extended environment (R2, 60-day)
│ ├── project_data_loader.py # R2 JSON data loader with caching
│ └── data_loader.py # JSON data loader with caching
│
└── server/
├── __init__.py
├── app.py # OpenEnv-compliant FastAPI server entry
└── project_app.py # R2 OpenEnv-compliant FastAPI server entry
# Example training loop skeleton (TRL/GRPO compatible)
from client import SprintEnvClient
from sprint_env.models import SprintAction
env = SprintEnvClient(base_url="http://localhost:7860")
for episode in range(1000):
obs = env.reset(task_name="medium_sprint")
trajectory = []
while not obs["done"]:
action = policy.sample(obs) # your policy here
result = env.step(action)
trajectory.append((obs, action, result.reward))
obs = result.observation
policy.update(trajectory) # GRPO/PPO updateFull training pipeline (SFT warm-up → GRPO curriculum):
# Smoke test first (no GPU needed)
python train_llm.py --smoke-test
# Full training (T4 GPU)
python train_llm.py --phase both --episodes 300 \
--sft-epochs 2 --gpu-tier t4 \
--output results/trained_model --push📓 Kaggle Notebook: AI Sprint Manager — OpenEnv Hackathon '26
Edit data/sprint_data.json:
{
"scenarios": {
"my_custom_sprint": {
"description": "My team's actual sprint",
"difficulty": "medium",
"developers": [
{"id": "dev1", "name": "Your Name", "skill": "backend", "capacity": 5, "productivity": 1.0}
],
"tasks": [
{"id": "T1", "name": "Your Task", "task_type": "feature", "priority": 1,
"effort": 3, "deadline": 5, "required_skill": "backend"}
]
}
}
}Or point to your own file:
export SPRINT_DATA_PATH=/path/to/your/data.json
python ui.py# Clone
git clone https://github.com/sejalsksagar/ai-sprint-manager-openenv.git
cd ai-sprint-manager-openenv
# Install
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
# Configure
cp .env.example .env
# Edit .env with your HF_TOKEN
# Run locally
python ui.py
# Open http://localhost:7860
# Docker
docker build -t ai-sprint-manager .
docker run -p 7860:7860 ai-sprint-manager
# Run inference (R1)
python inference.py
# Run inference (R2 — full 60-day project)
python inference_r2.pyBuilt for the Meta PyTorch OpenEnv Hackathon × SST | India AI Hackathon '26