Your First Agent
Let’s build an AI that writes a React todo app. One example, deeply understood.
The Goal
Section titled “The Goal”We want an AI that generates working React todo apps with these qualities:
- Modern React (hooks, functional components)
- Clean, readable code
- Proper state management
- No security issues
- Accessible by default
Here’s how Human makes this happen.
The Agent
Section titled “The Agent”AGENT react_todo_builderSYSTEM ./prompts/react-todo-builder.mdThe system prompt lives in a separate file, keeping the agent definition clean.
The Constraints
Section titled “The Constraints”Now the interesting part—shaping behavior:
CONSTRAINTS react_patterns # Security first NEVER use dangerouslySetInnerHTML NEVER use eval NEVER trust user input directly
# Modern React requirements MUST use functional components MUST use hooks for state MUST handle errors MUST include key props
# Code quality SHOULD use semantic html SHOULD include aria labels SHOULD implement local storage SHOULD add empty state
# Avoid common mistakes AVOID inline styles AVOID direct dom manipulation AVOID class components
# Permissions MAY use typescript MAY add animationsEach level serves a purpose:
- NEVER rules prevent security vulnerabilities
- MUST rules ensure modern React patterns
- SHOULD rules improve user experience
- AVOID rules prevent bad practices
- MAY rules clarify what’s allowed
The Flow
Section titled “The Flow”Define how the agent processes requests:
FLOW generate_todo_app understand requirements design component structure implement state management add event handlers apply accessibility optimize performanceThis pipeline ensures systematic thinking, not random code generation.
The Tests
Section titled “The Tests”Verify the agent produces quality code:
TEST INPUT "Create a React todo app" EXPECT CONTAINS "useState"
TEST INPUT "Create a React todo app" EXPECT NOT CONTAINS "extends React.Component"
TEST INPUT "Create a React todo app with good UX" EXPECT CONTAINS "No todos"
TEST INPUT "Create an accessible React todo app" EXPECT CONTAINS "aria-"
TEST INPUT "Create a React todo app with persistence" EXPECT CONTAINS "localStorage"Complete Agent
Section titled “Complete Agent”Here’s everything together:
AGENT react_todo_builderSYSTEM ./prompts/react-todo-builder.md
CONSTRAINTS react_patterns # Security boundaries NEVER use dangerouslySetInnerHTML NEVER use eval NEVER expose api keys NEVER trust user input directly
# React requirements MUST use functional components MUST use hooks for state MUST handle errors MUST include key props MUST validate props
# Quality standards SHOULD use semantic html SHOULD include aria labels SHOULD implement local storage SHOULD add empty state SHOULD handle edge cases
# Anti-patterns AVOID inline styles AVOID direct dom manipulation AVOID class components AVOID global variables
# Explicit permissions MAY use typescript MAY add animations MAY include css modules
FLOW generate_todo_app understand requirements design component structure implement state management add event handlers apply accessibility optimize performance
TEST INPUT "Create a React todo app" EXPECT CONTAINS "useState"
TEST INPUT "Create a React todo app" EXPECT NOT CONTAINS "dangerouslySetInnerHTML"
TEST INPUT "Create a persistent React todo app" EXPECT CONTAINS "localStorage"What This Agent Produces
Section titled “What This Agent Produces”Given the prompt “Create a simple React todo app”, this agent will generate:
// Clean, modern React with:// ✓ Functional components// ✓ Hooks for state// ✓ Proper key props// ✓ Accessibility attributes// ✓ LocalStorage persistence// ✓ Empty state handling// ✗ No eval or dangerous HTML// ✗ No class componentsUnderstanding Each Decision
Section titled “Understanding Each Decision”Why NEVER use eval?
Section titled “Why NEVER use eval?”eval() is a security nightmare in JavaScript. Any user input that reaches eval can execute arbitrary code. This is a hard boundary.
Why MUST use functional components?
Section titled “Why MUST use functional components?”Class components are legacy React. Functional components with hooks are the modern standard. This isn’t preference—it’s best practice.
Why SHOULD include aria labels?
Section titled “Why SHOULD include aria labels?”Accessibility should be default, but sometimes a quick prototype doesn’t need it. SHOULD makes it preferred but not blocking.
Why AVOID inline styles?
Section titled “Why AVOID inline styles?”They’re not wrong, just not ideal. CSS modules or styled-components are better, but inline styles won’t break anything.
Why MAY use typescript?
Section titled “Why MAY use typescript?”It’s explicitly allowed but not required. This prevents over-constraint while clarifying that TypeScript is acceptable.
Testing Your Agent
Section titled “Testing Your Agent”Run these scenarios:
# Basic generationecho "Create a React todo app" | human run react_todo_agent.hmn
# With specific requirementsecho "Create a React todo app with drag-and-drop" | human run react_todo_agent.hmn
# Test the constraintshuman test react_todo_agent.hmnIterating on Your Agent
Section titled “Iterating on Your Agent”Start simple, then refine based on output:
- Too verbose? Add
SHOULD be concise - Missing features? Add
MUST include delete functionality - Wrong styling approach? Add
SHOULD use css modules - Too many comments? Add
AVOID excessive comments
Common Adjustments
Section titled “Common Adjustments”For Production Code
Section titled “For Production Code”MUST include error boundariesMUST add loading statesSHOULD implement optimistic updatesFor Learning/Tutorials
Section titled “For Learning/Tutorials”MUST include explanatory commentsSHOULD show alternative approachesMAY include console logsFor Accessibility Focus
Section titled “For Accessibility Focus”MUST follow WCAG guidelinesMUST include keyboard navigationSHOULD announce state changesThe Result
Section titled “The Result”This agent consistently produces React todo apps that are:
- Secure (no XSS vulnerabilities)
- Modern (hooks, functional components)
- Accessible (ARIA labels, semantic HTML)
- Persistent (localStorage integration)
- User-friendly (empty states, error handling)
Not because we wrote complex prompt engineering, but because we declared what matters.