一键导入
ai-intelligence
Best practices for AI bots, prompts, and intel in scope_of_work
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Best practices for AI bots, prompts, and intel in scope_of_work
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Best practices for writing Django tests (updated template)
GlueFetchHelper patterns for making AJAX calls in templates
Advanced seeding patterns for linking specific foreign keys
Apply DjangoSpire app CSS variables in templates instead of inline styles
Django URL configuration patterns, namespaces, and nested structure conventions
Examples on how we build our form views.
基于 SOC 职业分类
| name | ai-intelligence |
| description | Best practices for AI bots, prompts, and intel in scope_of_work |
AI Intelligence in the scope_of_work module uses LLM-powered bots to automatically generate, process, and review project documentation. This system transforms raw project notes into structured deliverables, labor estimates, and client-ready documentation.
When to Use:
Key Principles:
Bots are the primary interface for LLM interactions. Each bot defines a persona, task, and output structure.
Three Critical Components:
role - Defines the bot's persona and expertise (50-150 words)guidelines - Structured instructions using Prompt() classintel_class - Typed output structure that enforces consistencyThe Prompt() class structures data for LLM consumption:
prompt = (
Prompt()
.heading('Scope of Work')
.sub_heading('Project Notes')
.text(scope_of_work.notes)
.line_break()
.sub_heading('Deliverables')
.list(['Deliverable 1', 'Deliverable 2'])
)
Intel classes define structured output from LLM responses:
class DeliverableIntel(BaseIntel):
name: str
summary: str
features: list[str]
life_cylce: ScopeOfWorkDeliverableLifeCycleChoices
labour_items: LabourLineItemsIntel | None
Key Methods:
to_prompt() - Convert intel back to prompt formatto_string() / __str__() - String representationEvery bot follows this pattern:
from __future__ import annotations
from typing import TYPE_CHECKING
from dandy import Bot, Prompt
from app.partner.scope_of_work.deliverable.intelligence import intel
if TYPE_CHECKING:
from app.partner.scope_of_work.models import ScopeOfWork
class DeliverableBot(Bot):
role = 'Scope of Work Architect: A detail-oriented and pragmatic project strategist...'
task = 'Define clear, concise deliverable that fully highlights features and items being delivered.'
guidelines = (
Prompt()
.list([
'Name should be in the format "App Name: Description".',
'The summary should be 3 - 4 sentences that focuses on benefits.',
'Features should be 12 words or less.',
'Avoid technical jargon.',
])
.text('Life Cycle Choices')
.list([
'Wireframe - Only select if specifically mentioned.',
'Alpha - Most of the time this is the option.',
'Beta - Select if we are improving what we have already built.',
])
)
intel_class = intel.DeliverableIntel
def process(self, description: str, scope_of_work: ScopeOfWork) -> intel.DeliverableIntel:
deliverables = scope_of_work.deliverables.active()
deliverable_description = ''
for deliverable in deliverables:
deliverable_description += f'{deliverable.name}: {deliverable.description}\n'
return self.llm.prompt_to_intel(
Prompt()
.heading('New Deliverable Description')
.text(description)
.heading('Scope Of Work')
.text(f'Name: {scope_of_work.name}, Notes: {scope_of_work.notes}')
.heading('Existing Deliverables')
.text(deliverable_description)
)
Guidelines Definition:
Role Length: 50-150 words describing expertise and communication style
Effective Roles:
# Client-Focused
role = 'Client-Friendly Project Translator: A clear-communicating, business-savvy project specialist who translates technical software development goals into simple, engaging, and outcome-focused language that resonates with non-technical stakeholders.'
# Technical Expert
role = 'Scope of Work Architect: A detail-oriented and pragmatic project strategist with expertise in translating client needs into clear, impactful deliverables that emphasize key features, measurable business value, and tangible improvements over legacy processes.'
# Estimator
role = 'Estimator - A project manager with a knowledge of software development. Equipped with the rare ability to distill complex tasks into clear, confident, and unambiguous descriptions.'
Role Guidelines:
Guidelines use Prompt() for structured instruction delivery:
guidelines = (
Prompt()
.list([
'The user will provide you with instructions or meeting notes where they are talking about a scope of work for a software project.',
'The name should be no longer than 6 words and be relatable to the client.',
'The description should be 2 clear paragraphs that focuses on the client's outcome—not technical details.',
'Keep each paragraph between 3-5 sentences—concise, warm, and confident.',
])
.heading('Life Cycle Choices')
.list([
'Wireframe - Only select if it specifically mentioned.',
'Prototype - Only select prototype if it specifically mentioned.',
'Alpha - Most of the time this is the option. Clients need a working version.',
'Beta - Select if we are improving what we have already built.',
'Stable - Only select if specifically mentioned. This is the final stage.',
])
)
Guidelines Best Practices:
.list() for multiple related instructions.heading() and .sub_heading() for organizationWhen working with LLM configurations:
Temperature Settings:
Model Selection:
dandy library configurationProcessing Methods:
self.llm.prompt_to_intel(prompt) - Standard intel extractionself.llm.prompt_to_intel(prompt, temperature=0.5) - Override temperature when neededSeparate functions for role definitions enable reuse:
def deliverable_role_prompt():
return 'Scope of Work Architect: A detail-oriented and pragmatic project strategist with expertise in translating client needs into clear, impactful deliverables that emphasize key features, measurable business value, and tangible improvements over legacy processes.'
Usage:
class DeliverableBot(Bot):
role = prompts.deliverable_role_prompt()
Reusable instruction sets maintain consistency:
def deliverable_guidelines_prompt():
return (
Prompt()
.list([
'Name should be in the format "App Name: Description". App name is 1-3 words and is main entity or feature. Description is 4 words or less.',
'The summary should be 3 - 4 sentences that focuses on what the client will receive and the benefits.',
'A feature is a tangible benefit or improvement that the client will receive from the deliverable.',
'List the features in bullet points.',
'Features should be 12 words or less.',
'Avoid technical jargon.',
])
.text('Life Cycle Choices')
.list([
'Wireframe - Only select if it specifically mentioned.',
'Prototype - Only select prototype if it specifically mentioned.',
'Alpha - Most of the time this is the option.',
'Beta - Select if we are improving what we have already built.',
'Stable - Only select if specifically mentioned.',
])
)
Format model data for LLM consumption:
def deliverable_prompt(deliverable: ScopeOfWorkDeliverable, show_line_items: bool = True):
prompt = Prompt()
prompt.sub_heading(deliverable.name)
prompt.line_break()
prompt.text(deliverable.description)
prompt.line_break()
line_items = deliverable.line_items.active()
if show_line_items and line_items.exists():
prompt.sub_heading('Line Items')
prompt.line_break()
for line_item in line_items:
prompt.prompt(line_item_prompt(line_item))
return prompt
Combine multiple sources for context:
def scope_of_work_prompt(scope_of_work: ScopeOfWork):
prompt = Prompt()
prompt.heading('Scope of Work')
prompt.line_break()
prompt.sub_heading('Project Notes')
prompt.line_break()
prompt.text(scope_of_work.notes)
if scope_of_work.overview:
prompt.line_break()
prompt.sub_heading('Project Overview')
prompt.text(scope_of_work.overview)
deliverables = scope_of_work.deliverables.active()
if deliverables.exists():
prompt.line_break()
prompt.heading('Deliverables')
for deliverable in deliverables:
prompt.line_break()
prompt.prompt(deliverable_prompt(deliverable))
return prompt
Composite Prompt Guidelines:
line_break() between major sectionsAll intel classes inherit from BaseIntel:
from __future__ import annotations
from typing import TYPE_CHECKING
from dandy import BaseIntel, BaseListIntel
from app.partner.scope_of_work.line_item.choices import ScopeOfWorkLineItemTypeChoices
from app.partner.scope_of_work.line_item.enums import ScopeOfWorkSkillEnum
from app.partner.scope_of_work.line_item.models import ScopeOfWorkLineItem
if TYPE_CHECKING:
from app.partner.scope_of_work.deliverable.models import ScopeOfWorkDeliverable
from app.partner.scope_of_work.models import ScopeOfWork
class LabourLineItemIntel(BaseIntel):
name: str
description: str
quantity: float
skill_level: ScopeOfWorkSkillEnum
@property
def skill_level_choice(self) -> str:
return self.skill_level.to_choice()
@property
def skill_level_rate_choice(self) -> Decimal:
return self.skill_level.to_rate_choice()
def to_model_obj(
self,
scope_of_work: ScopeOfWork,
deliverable: ScopeOfWorkDeliverable
) -> ScopeOfWorkLineItem:
return ScopeOfWorkLineItem(
scope_of_work=scope_of_work,
deliverable=deliverable,
type=ScopeOfWorkLineItemTypeChoices.LABOUR,
name=self.name,
description=self.description,
quantity=self.quantity,
skill_level=self.skill_level_choice,
)
Use BaseListIntel for collections:
class LabourLineItemsIntel(BaseListIntel[LabourLineItemIntel]):
labour_items: list[LabourLineItemIntel]
def to_model_objs(
self,
scope_of_work: ScopeOfWork,
deliverable: ScopeOfWorkDeliverable
):
return [l.to_model_obj(scope_of_work, deliverable) for l in self.labour_items]
Intel can contain other intel objects:
class DeliverableIntel(BaseIntel):
name: str
summary: str
features: list[str]
life_cylce: ScopeOfWorkDeliverableLifeCycleChoices
labour_items: LabourLineItemsIntel | None
def format_description(self) -> str:
return f'{self.summary}\n {self.format_features()}'
def format_features(self) -> str:
features = ''
for feature in self.features:
features += f'- {feature}\n'
return features
def to_prompt(self):
return (
Prompt()
.heading(self.name)
.text(self.summary)
.list(self.features)
)
def to_string(self) -> str:
return f'{self.name} \n {self.format_description()} \n {self.format_features()}'
def to_model_obj(self, scope_of_work: ScopeOfWork) -> ScopeOfWorkDeliverable:
return ScopeOfWorkDeliverable(
scope_of_work=scope_of_work,
name=self.name,
description=self.format_description(),
life_cycle=self.life_cylce
)
to_prompt() - Convert to Prompt:
def to_prompt(self) -> Prompt:
return (
Prompt()
.sub_heading('Title')
.text(self.title)
.line_break()
.sub_heading('Overview')
.text(self.overview)
.line_break()
.sub_heading('Discussed Items')
.list([d for d in self.discussed_items])
.line_break()
)
to_string() / __str__() - String Representation:
def __str__(self) -> str:
return self.html_content
to_model_obj() - Convert to Django Model:
def to_model_obj(self, scope_of_work: ScopeOfWork) -> ScopeOfWorkDeliverable:
return ScopeOfWorkDeliverable(
scope_of_work=scope_of_work,
name=self.name,
description=self.format_description(),
life_cycle=self.life_cylce
)
Simple one-step processing:
class ScopeOfWorkOverviewBot(Bot):
role = 'Client-Friendly Project Translator: A clear-communicating, business-savvy project specialist...'
task = 'Write an overview for a software scope of work.'
guidelines = Prompt().list([...])
intel_class = intel.ScopeOfWorkOverviewIntel
def process(self, description: str) -> intel.ScopeOfWorkOverviewIntel:
return self.llm.prompt_to_intel(prompt=description)
Usage:
overview_intel = ScopeOfWorkOverviewBot().process(project_notes)
Complex workflows use multiple bots in sequence:
class BulkDeliverablesBot(Bot):
role = prompts.deliverable_role_prompt()
task = 'Return a list of formatted deliverables.'
guidelines = (
Prompt()
.heading('Bulk Guidelines')
.list([
'The user will give you a list of deliverables to create along with the reference text.',
'Use the reference text to find information relating to each deliverable.',
'Keep the deliverables in order.',
'The deliverable features should not overlap.',
])
.heading('Individual Deliverable Guidelines')
.prompt(prompts.deliverable_guidelines_prompt())
)
intel_class = DeliverablesIntel
def process(self, deliverables: FoundIntel, instructions: Prompt) -> DeliverablesIntel:
deliverables_intel = []
for deliverable in deliverables.items:
deliverables_intel.append(SingleDeliverablesBot().process(
deliverable=deliverable,
instructions=str(instructions)
))
return intel.DeliverablesIntel(deliverables=deliverables_intel)
Complete Workflow:
# Step 1: Extract deliverable names
finder_intel = FinderBot().process(user_prompt, project_context)
# Step 2: Create bulk deliverables
bulk_intel = BulkDeliverablesBot().process(finder_intel, scope_prompt)
# Step 3: Add labor estimates
for deliverable in bulk_intel.deliverables:
deliverable.labour_items = DeliverableLaborLineItemBot().process(deliverable)
# Step 4: Review and refine
final_intel = DeliverablesReviewBot().process(bulk_intel)
# Step 5: Convert to models
deliverable_objs = final_intel.to_model_objs(scope_of_work)
Review bots refine AI-generated content:
class DeliverablesReviewBot(Bot):
role = prompts.deliverable_role_prompt()
task = 'Review the scope of work deliverables.'
guidelines = (
Prompt()
.heading('Review Guidelines')
.list([
'Do not make major changes to the deliverables.',
'The main goal is to improve how the deliverables are read together.',
'The deliverables should not repeat information between on another.',
'The descriptions should flow from one deliverable to the next without referencing each other.',
])
.heading('Deliverable Guidelines')
.prompt(prompts.deliverable_guidelines_prompt())
)
intel_class = DeliverablesIntel
def process(self, deliverables: DeliverablesIntel) -> DeliverablesIntel:
prompt = (
Prompt()
.heading('Deliverables')
.prompt(deliverables.to_prompt())
)
return self.llm.prompt_to_intel(prompt)
Bots that create related objects:
class DeliverableLaborLineItemBot(Bot):
role = 'Expert Software Project Manager'
task = 'You are breaking down a deliverable and estimating labour hours.'
guidelines = (
Prompt()
.heading('For each deliverable')
.list([
'Labour items: Tasks needed to complete it',
])
.line_break()
.heading('For each labour item')
.list([
'Name: Use "Software Architecture", "Logic & Programming", "User Interface", "Testing & QA", or "Documentation"',
'Description: Brief task description',
'Quantity: Estimated hours',
'Skill level: Junior, Intermediate, Senior, or Intelligence',
])
)
intel_class = LabourLineItemsIntel
def process(self, deliverable_intel: DeliverableIntel) -> DeliverableIntel:
labour_line_items_intel = self.llm.prompt_to_intel(
prompt=(
Prompt()
.heading('Deliverable')
.line_break()
.sub_heading('Name')
.text(deliverable_intel.name)
.line_break()
.sub_heading('Description')
.text(deliverable_intel.description)
)
)
deliverable_intel.labour_items = labour_line_items_intel
return deliverable_intel
DON'T: Generic role and minimal guidelines
class BadDeliverableBot(Bot):
role = 'Project Bot'
task = 'Make deliverables.'
guidelines = Prompt().list(['Do a good job.'])
intel_class = intel.DeliverableIntel
def process(self, description: str):
return self.llm.prompt_to_intel(description)
DO: Specific role and comprehensive guidelines
from __future__ import annotations
from typing import TYPE_CHECKING
from dandy import Bot, Prompt
from app.partner.scope_of_work.deliverable.intelligence import intel, prompts
if TYPE_CHECKING:
from app.partner.scope_of_work.models import ScopeOfWork
class DeliverableBot(Bot):
role = prompts.deliverable_role_prompt()
task = 'Define clear, concise deliverable that fully highlights features and items being delivered.'
guidelines = prompts.deliverable_guidelines_prompt()
intel_class = intel.DeliverableIntel
def process(self, description: str, scope_of_work: ScopeOfWork) -> intel.DeliverableIntel:
deliverables = scope_of_work.deliverables.active()
deliverable_description = ''
for deliverable in deliverables:
deliverable_description += f'{deliverable.name}: {deliverable.description}\n'
return self.llm.prompt_to_intel(
Prompt()
.heading('New Deliverable Description')
.text(description)
.heading('Scope Of Work')
.text(f'Name: {scope_of_work.name}, Notes: {scope_of_work.notes}')
.heading('Existing Deliverables')
.text(deliverable_description)
)
DON'T: Inline prompt construction
def process(self, description: str, scope_of_work: ScopeOfWork):
prompt = Prompt()
prompt.heading('New Deliverable Description')
prompt.text(description)
prompt.heading('Scope Of Work')
prompt.text(f'Name: {scope_of_work.name}')
# ... more inline construction
return self.llm.prompt_to_intel(prompt)
DO: Reusable prompt functions
# prompts.py
def deliverable_prompt(deliverable: ScopeOfWorkDeliverable, show_line_items: bool = True):
prompt = Prompt()
prompt.sub_heading(deliverable.name)
prompt.text(deliverable.description)
if show_line_items:
line_items = deliverable.line_items.active()
if line_items.exists():
prompt.sub_heading('Line Items')
for line_item in line_items:
prompt.prompt(line_item_prompt(line_item))
return prompt
# bots.py
def process(self, description: str, scope_of_work: ScopeOfWork):
prompt = (
Prompt()
.heading('New Deliverable Description')
.text(description)
.heading('Scope Of Work')
.text(f'Name: {scope_of_work.name}, Notes: {scope_of_work.notes}')
.heading('Existing Deliverables')
.text(self._format_existing_deliverables(scope_of_work))
)
return self.llm.prompt_to_intel(prompt)
DON'T: Manual model creation
def save_deliverables(intel: DeliverablesIntel, scope_of_work: ScopeOfWork):
for deliverable_data in intel.deliverables:
deliverable = ScopeOfWorkDeliverable(
scope_of_work=scope_of_work,
name=deliverable_data.name,
description=f'{deliverable_data.summary}\n{deliverable_data.format_features()}',
life_cycle=deliverable_data.life_cylce
)
deliverable.save()
DO: Use built-in conversion methods
def save_deliverables(intel: DeliverablesIntel, scope_of_work: ScopeOfWork):
deliverable_objs = intel.to_model_objs(scope_of_work)
for obj in deliverable_objs:
obj.save()
Real-world deliverable creation workflow:
from __future__ import annotations
from typing import TYPE_CHECKING
from dandy import Prompt
from app.ai.intelligence.bots import FinderBot
from app.partner.scope_of_work.deliverable.intelligence.bots import (
BulkDeliverablesBot,
DeliverablesReviewBot,
DeliverableLaborLineItemBot,
)
from app.partner.scope_of_work.intelligence.prompts import scope_of_work_prompt
if TYPE_CHECKING:
from app.partner.scope_of_work.models import ScopeOfWork
def create_deliverables_from_notes(
user_request: str,
project_context: str,
scope_of_work: ScopeOfWork
) -> list[ScopeOfWorkDeliverable]:
"""
Complete workflow: Extract deliverables, create descriptions, add estimates, review.
"""
# Step 1: Find deliverable names in project notes
finder_intel = FinderBot().process(
user_prompt=user_request,
reference_text=project_context
)
# Step 2: Create bulk deliverables with descriptions
scope_prompt = scope_of_work_prompt(scope_of_work)
bulk_intel = BulkDeliverablesBot().process(
deliverables=finder_intel,
instructions=scope_prompt
)
# Step 3: Add labor estimates to each deliverable
for deliverable in bulk_intel.deliverables:
deliverable.labour_items = DeliverableLaborLineItemBot().process(deliverable)
# Step 4: Review and refine for consistency
final_intel = DeliverablesReviewBot().process(bulk_intel)
# Step 5: Convert to Django models
return final_intel.to_model_objs(scope_of_work)
When reviewing AI intelligence code, verify the following:
to_prompt(), to_string(), and to_model_obj() as neededBaseListIntel with typed genericsto_model_obj() methods handle all required fieldsPrompt() class methods used consistently