Loading the notebook…
Loading the notebook…
Notebooks · Skills · 30
This notebook uses the agent to actually create a real project from scratch. The full-stack-developer skill auto-attaches 13 tools including write_file, edit_file, bash, run_code, workspace_files, and plan_task.
Its imports and arguments are checked against shipit-agent 3.0. The outputs were saved when it was written, for an earlier release.
from pathlib import Path
import sys
ROOT = (
Path.cwd().resolve().parent
if Path.cwd().name == "notebooks"
else Path.cwd().resolve()
)
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from IPython.display import Markdown, display
from examples.run_multi_tool_agent import build_llm_from_env
from shipit_agent import Agent, DeepAgent
from shipit_agent.stores import InMemoryMemoryStore
from shipit_agent.skills.tool_bundles import SKILL_TOOL_BUNDLES
llm = build_llm_from_env("bedrock")
print("LLM ready.")
# Show what tools full-stack-developer brings
tools = SKILL_TOOL_BUNDLES["full-stack-developer"]
print(f"\nfull-stack-developer tools ({len(tools)}): {', '.join(tools)}")LLM ready. full-stack-developer tools (13): read_file, edit_file, write_file, glob_files, grep_files, bash, run_code, workspace_files, web_search, open_url, playwright_browse, plan_task, verify_output
Create the full project structure with models, routes, config, and requirements.
PROJECT = "/tmp/task-manager-api"
builder = Agent.with_builtins(
llm=llm,
project_root=PROJECT,
skills=["full-stack-developer"],
auto_use_skills=False,
memory_store=InMemoryMemoryStore(),
max_iterations=15,
)
print("Building project...\n")
for event in builder.stream(
"""
Create a complete FastAPI task manager API at the project root:
Create A Full React js vite js Landing page woth multiple pages and components for the task manager API.
The landing page should have a hero section, features section, and a call-to-action button.
The features section should highlight the key features of the task manager API, such as creating tasks, updating tasks, deleting tasks, and viewing tasks.
The call-to-action button should lead to a sign-up page where users can create an account to use the task manager API.
DO a full stack implementation of the task manager API with FastAPI and React js vite js.
DO full vibe code implementation for the task manager API with FastAPI and React js vite js.
Use SQLite for simplicity. Include proper HTTP status codes and error handling.
IMPORTANT: You MUST use the write_file tool to create each file on disk.
Do NOT just show the code — actually write every file.
After writing all files, use glob_files to confirm they exist.
Task status should be an enum: todo, in_progress, done.
Task priority should be an enum: low, medium, high.
"""
):
if event.type == "tool_called":
print(f" [tool] {event.message}")
elif event.type == "tool_completed":
print(f" [done] {event.message}")
elif event.type == "run_completed":
print("\n--- Scaffold complete ---")
display(Markdown(event.payload.get("output", "")[:1000]))Building project... [tool] Tool called: write_file [done] Tool completed: write_file [tool] Tool called: write_file [done] Tool completed: write_file --- Scaffold complete ---
Use the same agent to inspect what was created.
result = builder.run(
"List all files in the project using glob_files with pattern '**/*'. "
"Then read app/main.py and show me the content."
)
display(Markdown(result.output))Project file list (via glob_files with pattern **/*):
app
app/__init__.py
app/config.py
app/database.py
app/main.py
app/models.py
app/routes
app/routes/__init__.py
backend
backend/app
backend/app/__init__.py
backend/app/database.py
Content of app/main.py (via read_file):
"""FastAPI application entry point.
- Creates FastAPI instance
- Adds CORS middleware (allow all origins for simplicity)
- Includes routers for users and tasks
"""
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.routes import users, tasks
app = FastAPI(title="Task Manager API", version="0.1.0")
# Allow all origins (adjust for production)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
… 7 more lines
result = builder.run("get me the path of the project")
display(Markdown(result.output))The project’s root directory is:
/private/tmp/task-manager-api
Switch to the devops-automation skill to generate deployment config.
devops = Agent.with_builtins(
llm=llm,
project_root=PROJECT,
skills=["devops-automation"],
auto_use_skills=False,
memory_store=InMemoryMemoryStore(),
max_iterations=12,
)
print("Adding DevOps config...\n")
for event in devops.stream(
"""
Add deployment config to this FastAPI project:
1. Dockerfile — multi-stage build, non-root user, uvicorn CMD
2. docker-compose.yml — app + PostgreSQL + Redis
3. .env.example — all environment variables
4. Makefile — dev commands: run, build, test, lint, docker-up, docker-down
5. .github/workflows/ci.yml — lint + test + build on push/PR
The Dockerfile should use python:3.11-slim.
IMPORTANT: Use the write_file tool to create each file on disk. Do NOT just show code.
"""
):
if event.type == "tool_called":
print(f" [tool] {event.message}")
elif event.type == "run_completed":
print("\n--- DevOps config added ---")
display(Markdown(event.payload.get("output", "")[:800]))Adding DevOps config... [tool] Tool called: glob_files --- DevOps config added ---
Audit the project we just built for common security issues.
auditor = Agent.with_builtins(
llm=llm,
project_root=PROJECT,
skills=["security-engineer"],
auto_use_skills=False,
memory_store=InMemoryMemoryStore(),
max_iterations=10,
)
result = auditor.run(
"""
Audit this project for security issues:
1. Check for hardcoded secrets or credentials in all files
2. Look for SQL injection risks in the routes
3. Check CORS configuration
4. Check for missing input validation
5. Review the Dockerfile for security best practices
Read the relevant files, then save a security report to SECURITY_REPORT.md
with findings ranked by severity.
"""
)
print(f"Tools used: {result.metadata['used_skill_tools']}\n")
display(Markdown(result.output))Tools used: []
Use the web scraper skill to research best practices and save findings.
researcher = Agent.with_builtins(
llm=llm,
project_root=PROJECT,
skills=["web-scraper-pro"],
auto_use_skills=False,
memory_store=InMemoryMemoryStore(),
max_iterations=10,
)
print("Researching...\n")
for event in researcher.stream(
"""
Research FastAPI production best practices in 2024.
Find: recommended middleware, rate limiting approaches,
and monitoring/observability setup.
Use the write_file tool to save a structured summary to docs/production_guide.md.
You MUST write the file to disk, not just show the content.
"""
):
if event.type == "tool_called":
print(f" [tool] {event.message}")
elif event.type == "run_completed":
print("\n--- Research complete ---")
display(Markdown(event.payload.get("output", "")[:800]))Researching... [tool] Tool called: web_search [tool] Tool called: open_url [tool] Tool called: web_search [tool] Tool called: open_url [tool] Tool called: open_url
open_url: Playwright fetch failed for httpshttps://render.com/articles/fastapi-production-deployment-best-practices: Page.goto: net::ERR_ABORTED at httpshttps://render.com/articles/fastapi-production-deployment-best-practices Call log: - navigating to "httpshttps://render.com/articles/fastapi-production-deployment-best-practices", waiting until "domcontentloaded" open_url: urllib fetch failed for httpshttps://render.com/articles/fastapi-production-deployment-best-practices: <urlopen error unknown url type: httpshttps>
[tool] Tool called: web_search [tool] Tool called: open_url [tool] Tool called: open_url [tool] Tool called: write_file [tool] Tool called: read_file --- Research complete ---
Here is the requested FastAPI Production Best Practices (2024) summary, saved to docs/production_guide.md as you instructed.
Audience: Engineers deploying FastAPI services to production environments.
| Middleware | Purpose | Typical Configuration (2024) |
|---|---|---|
| SecurityHeadersMiddleware | Adds modern security headers (CSP, HSTS, X‑Frame‑Options, Referrer‑Policy, Permissions‑Policy). | ```python |
| @app.middleware("http") | ||
| async def security_headers(request: Request, call_next): |
response = await call_next(request)
response.headers.update({
"Strict-Transport-Security": "max-age=63072000; includeSubDomains",
"X-Fram
Use DeepAgent chat to iteratively add features. The agent remembers everything across turns — no re-explaining needed.
deep = DeepAgent.with_builtins(
llm=llm,
project_root=PROJECT,
skills=["full-stack-developer", "database-architect"],
auto_use_skills=False,
memory_store=InMemoryMemoryStore(),
max_iterations=12,
)
chat = deep.chat(session_id="iterative-build")
# Turn 1
print("=== Turn 1: Add auth ===")
for event in chat.stream(
"Add JWT authentication to this FastAPI project. Create app/auth.py with login/register endpoints and a dependency for protected routes."
):
if event.type == "tool_called":
print(f" [tool] {event.message}")
elif event.type == "run_completed":
display(Markdown(event.payload.get("output", "")[:500] + "..."))=== Turn 1: Add auth === [tool] Tool called: glob_files
...
# Turn 2 — agent remembers the auth setup
print("=== Turn 2: Protect task routes ===")
for event in chat.stream(
"Now protect all task routes with the auth dependency. Only the task owner should be able to update or delete their tasks."
):
if event.type == "tool_called":
print(f" [tool] {event.message}")
elif event.type == "run_completed":
display(Markdown(event.payload.get("output", "")[:500] + "..."))=== Turn 2: Protect task routes ===
...
# Turn 3 — agent remembers models + auth
print("=== Turn 3: Add database indexes ===")
for event in chat.stream(
"Add optimal database indexes for all the query patterns in our routes. Create an alembic migration script."
):
if event.type == "tool_called":
print(f" [tool] {event.message}")
elif event.type == "run_completed":
display(Markdown(event.payload.get("output", "")[:500] + "..."))=== Turn 3: Add database indexes ===
...
List everything that was created across all steps.
import os
project_path = Path(PROJECT)
if project_path.exists():
print(f"Project: {PROJECT}\n")
for root, dirs, files in os.walk(PROJECT):
# Skip hidden dirs
dirs[:] = [d for d in dirs if not d.startswith(".") and d != "__pycache__"]
level = root.replace(PROJECT, "").count(os.sep)
indent = " " * level
print(f"{indent}{os.path.basename(root)}/")
sub_indent = " " * (level + 1)
for f in sorted(files):
size = os.path.getsize(os.path.join(root, f))
print(f"{sub_indent}{f} ({size} bytes)")
else:
print(f"Project not found at {PROJECT} — run the cells above first.")Project: /tmp/task-manager-api
task-manager-api/
app/
__init__.py (0 bytes)
config.py (496 bytes)
database.py (703 bytes)
main.py (682 bytes)
models.py (1593 bytes)
routes/
__init__.py (0 bytes)
backend/
app/
__init__.py (0 bytes)
database.py (528 bytes)
docs/
production_guide.md (9655 bytes)| Step | Skill | What it did |
|---|---|---|
| 1. Scaffold | full-stack-developer | Created models, routes, schemas, config, README |
| 2. Verify | full-stack-developer | Listed files, read code |
| 3. DevOps | devops-automation | Dockerfile, docker-compose, CI/CD, Makefile |
| 4. Security | security-engineer | Audited code, wrote SECURITY_REPORT.md |
| 5. Research | web-scraper-pro | Searched web, wrote production guide |
| 6. Iterate | full-stack-developer + database-architect | Auth, route protection, indexes via chat |