Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .amplifier/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"project_id": "test_integration_project_20251007_121405",
"project_name": "Test Integration Project",
"has_planning": true,
"created_at": "2025-10-07T12:14:05.201566",
"updated_at": "2025-10-07T12:14:05.201569"
}
72 changes: 71 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ default: ## Show essential commands
@echo "AI Context:"
@echo " make ai-context-files Build AI context documentation"
@echo ""
@echo "Project Planning:"
@echo " make project-init Initialize project with AI planning"
@echo " make project-plan Generate and execute project plan"
@echo " make project-status Show project status and progress"
@echo " make project-execute Execute project tasks with orchestration"
@echo " make smart-decomposer Smart task decomposition CLI"
@echo ""
@echo "Blog Writing:"
@echo " make blog-write Create a blog post from your ideas"
@echo ""
Expand Down Expand Up @@ -180,7 +187,7 @@ check: ## Format, lint, and type-check all code
@echo "Type-checking code with pyright..."
@VIRTUAL_ENV= uv run pyright
@echo "Checking for stubs and placeholders..."
@python tools/check_stubs.py
@uv run python tools/check_stubs.py
@echo "All checks passed!"

test: ## Run all tests
Expand Down Expand Up @@ -484,6 +491,69 @@ ai-context-files: ## Build AI context files
uv run python tools/build_git_collector_files.py
@echo "AI context files generated"

# Project Planning
project-init: ## Initialize project with AI planning. Usage: make project-init PROJECT_NAME="My Project" [PROJECT_PATH=/path/to/project]
@if [ -z "$(PROJECT_NAME)" ]; then \
echo "Error: Please provide a project name. Usage: make project-init PROJECT_NAME=\"My Project\""; \
exit 1; \
fi
@echo "🚀 Initializing AI-driven project planning..."; \
echo " Project: $(PROJECT_NAME)"; \
if [ -n "$(PROJECT_PATH)" ]; then \
echo " Path: $(PROJECT_PATH)"; \
uv run python -m scenarios.project_planner init --name "$(PROJECT_NAME)" --path "$(PROJECT_PATH)"; \
else \
uv run python -m scenarios.project_planner init --name "$(PROJECT_NAME)"; \
fi

project-plan: ## Generate and execute project plan. Usage: make project-plan PROJECT_ID="proj-abc123" [GOAL="Custom goal"]
@if [ -z "$(PROJECT_ID)" ]; then \
echo "Error: Please provide a project ID. Usage: make project-plan PROJECT_ID=\"proj-abc123\""; \
exit 1; \
fi
@echo "📋 Generating project plan..."; \
if [ -n "$(GOAL)" ]; then \
echo " Goal: $(GOAL)"; \
uv run python -m scenarios.project_planner plan --project-id "$(PROJECT_ID)" --goal "$(GOAL)"; \
else \
uv run python -m scenarios.project_planner plan --project-id "$(PROJECT_ID)"; \
fi

project-status: ## Show project status and progress. Usage: make project-status PROJECT_ID="proj-abc123"
@if [ -z "$(PROJECT_ID)" ]; then \
echo "Error: Please provide a project ID. Usage: make project-status PROJECT_ID=\"proj-abc123\""; \
exit 1; \
fi
@echo "📊 Checking project status..."; \
uv run python -m scenarios.project_planner status --project-id "$(PROJECT_ID)"

project-execute: ## Execute project tasks with orchestration. Usage: make project-execute PROJECT_ID="proj-abc123" [MAX_PARALLEL=5]
@if [ -z "$(PROJECT_ID)" ]; then \
echo "Error: Please provide a project ID. Usage: make project-execute PROJECT_ID=\"proj-abc123\""; \
exit 1; \
fi
@echo "🚀 Executing project tasks..."; \
if [ -n "$(MAX_PARALLEL)" ]; then \
uv run python -m scenarios.project_planner execute --project-id "$(PROJECT_ID)" --max-parallel "$(MAX_PARALLEL)"; \
else \
uv run python -m scenarios.project_planner execute --project-id "$(PROJECT_ID)"; \
fi

smart-decomposer: ## Smart task decomposition CLI. Usage: make smart-decomposer COMMAND="decompose --goal 'Build feature X'"
@if [ -z "$(COMMAND)" ]; then \
echo "Usage: make smart-decomposer COMMAND=\"decompose --goal 'Build feature X'\""; \
echo ""; \
echo "Available commands:"; \
echo " decompose --goal 'Goal text' Decompose goal into tasks"; \
echo " assign --project-id ID Assign agents to tasks"; \
echo " execute --project-id ID Execute tasks with orchestration"; \
echo " status --project-id ID Show project status"; \
echo ""; \
exit 1; \
fi
@echo "🧠 Running smart decomposer..."; \
uv run python -m scenarios.smart_decomposer $(COMMAND)

# Blog Writing
blog-write: ## Create a blog post from your ideas. Usage: make blog-write IDEA=ideas.md WRITINGS=my_writings/ [INSTRUCTIONS="..."]
@if [ -z "$(IDEA)" ]; then \
Expand Down
11 changes: 11 additions & 0 deletions amplifier/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
Amplifier Core - Project context and session management.

Provides automatic project detection and persistent state management
for amplifier across multiple invocations.
"""

from .context import ProjectContext
from .context import detect_project_context

__all__ = ["ProjectContext", "detect_project_context"]
121 changes: 121 additions & 0 deletions amplifier/core/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"""
Project Context Detection and Management.

Automatically detects project planning context and provides persistent state
management across amplifier invocations.
"""

import json
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path

from amplifier.planner import Project
from amplifier.planner import load_project


@dataclass
class ProjectContext:
"""Amplifier project context with planning integration."""

project_root: Path
project_id: str
project_name: str
config_file: Path
planner_project: Project | None = None
has_planning: bool = False

@classmethod
def from_config(cls, config_path: Path) -> "ProjectContext":
"""Create context from .amplifier/project.json config."""
with open(config_path) as f:
config = json.load(f)

project_root = config_path.parent.parent
context = cls(
project_root=project_root,
project_id=config["project_id"],
project_name=config["project_name"],
config_file=config_path,
has_planning=config.get("has_planning", False),
)

# Load planner project if planning is enabled
if context.has_planning:
import contextlib

with contextlib.suppress(FileNotFoundError):
context.planner_project = load_project(context.project_id)

return context

def enable_planning(self) -> None:
"""Enable planning for this project."""
if not self.has_planning:
self.has_planning = True
self.save_config()

def save_config(self) -> None:
"""Save project configuration."""
config = {
"project_id": self.project_id,
"project_name": self.project_name,
"has_planning": self.has_planning,
"created_at": datetime.now().isoformat(),
"updated_at": datetime.now().isoformat(),
}

self.config_file.parent.mkdir(parents=True, exist_ok=True)
with open(self.config_file, "w") as f:
json.dump(config, f, indent=2)


def detect_project_context(start_dir: Path | None = None) -> ProjectContext | None:
"""
Detect amplifier project context by looking for .amplifier/project.json.

Walks up directory tree from start_dir (or cwd) looking for project config.
Returns None if no project context found.
"""
if start_dir is None:
start_dir = Path.cwd()

# Walk up directory tree looking for .amplifier/project.json
current = Path(start_dir).absolute()

while current != current.parent: # Not at filesystem root
config_file = current / ".amplifier" / "project.json"
if config_file.exists():
try:
return ProjectContext.from_config(config_file)
except (json.JSONDecodeError, KeyError, OSError):
# Invalid config, continue searching up
pass
current = current.parent

return None


def create_project_context(
project_name: str, project_root: Path | None = None, enable_planning: bool = True
) -> ProjectContext:
"""Create new amplifier project context."""
if project_root is None:
project_root = Path.cwd()

# Generate project ID from name and timestamp
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
project_id = f"{project_name.lower().replace(' ', '_')}_{timestamp}"

config_file = project_root / ".amplifier" / "project.json"

context = ProjectContext(
project_root=project_root,
project_id=project_id,
project_name=project_name,
config_file=config_file,
has_planning=enable_planning,
)

context.save_config()
return context
Loading