Skip to main content
The quality of your instructions directly impacts the quality of OpenHands’ output. This guide shows concrete examples of good and bad prompts, explains why some work better than others, and provides principles for writing effective instructions.

Concrete Examples of Good/Bad Prompts

Bug Fixing Examples

Bad Example

Fix the bug in my code.
Why it’s bad:
  • No information about what the bug is
  • No indication of where to look
  • No description of expected vs. actual behavior
  • OpenHands would have to guess what’s wrong

Good Example

Fix the TypeError in src/api/users.py line 45.

Error message:
TypeError: 'NoneType' object has no attribute 'get'

Expected behavior: The get_user_preferences() function should return 
default preferences when the user has no saved preferences.

Actual behavior: It crashes with the error above when user.preferences is None.

The fix should handle the None case gracefully and return DEFAULT_PREFERENCES.
Why it works:
  • Specific file and line number
  • Exact error message
  • Clear expected vs. actual behavior
  • Suggested approach for the fix

Feature Development Examples

Bad Example

Add user authentication to my app.
Why it’s bad:
  • Scope is too large and undefined
  • No details about authentication requirements
  • No mention of existing code or patterns
  • Could mean many different things

Good Example

Add email/password login to our Express.js API.

Requirements:
1. POST /api/auth/login endpoint
2. Accept email and password in request body
3. Validate against users in PostgreSQL database
4. Return JWT token on success, 401 on failure
5. Use bcrypt for password comparison (already in dependencies)

Follow the existing patterns in src/api/routes.js for route structure.
Use the existing db.query() helper in src/db/index.js for database access.

Success criteria: I can call the endpoint with valid credentials 
and receive a JWT token that works with our existing auth middleware.
Why it works:
  • Specific, scoped feature
  • Clear technical requirements
  • Points to existing patterns to follow
  • Defines what “done” looks like

Code Review Examples

Bad Example

Review my code.
Why it’s bad:
  • No code provided or referenced
  • No indication of what to look for
  • No context about the code’s purpose
  • No criteria for the review

Good Example

Review this pull request for our payment processing module:

Focus areas:
1. Security - we're handling credit card data
2. Error handling - payments must never silently fail
3. Idempotency - duplicate requests should be safe

Context:
- This integrates with Stripe API
- It's called from our checkout flow
- We have ~10,000 transactions/day

Please flag any issues as Critical/Major/Minor with explanations.
Why it works:
  • Clear scope and focus areas
  • Important context provided
  • Business implications explained
  • Requested output format specified

Refactoring Examples

Bad Example

Make the code better.
Why it’s bad:
  • “Better” is subjective and undefined
  • No specific problems identified
  • No goals for the refactoring
  • No constraints or requirements

Good Example

Refactor the UserService class in src/services/user.js:

Problems to address:
1. The class is 500+ lines - split into smaller, focused services
2. Database queries are mixed with business logic - separate them
3. There's code duplication in the validation methods

Constraints:
- Keep the public API unchanged (other code depends on it)
- Maintain test coverage (run npm test after changes)
- Follow our existing service patterns in src/services/

Goal: Improve maintainability while keeping the same functionality.
Why it works:
  • Specific problems identified
  • Clear constraints and requirements
  • Points to patterns to follow
  • Measurable success criteria

Key Principles for Effective Instructions

Be Specific

Vague instructions produce vague results. Be concrete about:
Instead of…Say…
”Fix the error""Fix the TypeError on line 45 of api.py"
"Add tests""Add unit tests for the calculateTotal function covering edge cases"
"Improve performance""Reduce the database queries from N+1 to a single join query"
"Clean up the code""Extract the validation logic into a separate ValidatorService class”

Provide Context

Help OpenHands understand the bigger picture:
Context to include:
- What does this code do? (purpose)
- Who uses it? (users/systems)
- Why does this matter? (business impact)
- What constraints exist? (performance, compatibility)
- What patterns should be followed? (existing conventions)
Example with context:
Add rate limiting to our public API endpoints.

Context:
- This is a REST API serving mobile apps and third-party integrations
- We've been seeing abuse from web scrapers hitting us 1000+ times/minute
- Our infrastructure can handle 100 req/sec per client sustainably
- We use Redis (already available in the project)
- Our API follows the controller pattern in src/controllers/

Requirement: Limit each API key to 100 requests per minute with 
appropriate 429 responses and Retry-After headers.

Set Clear Goals

Define what success looks like:
Success criteria checklist:
✓ What specific outcome do you want?
✓ How will you verify it worked?
✓ What tests should pass?
✓ What should the user experience be?
Example with clear goals:
Implement password reset functionality.

Success criteria:
1. User can request reset via POST /api/auth/forgot-password
2. System sends email with secure reset link
3. Link expires after 1 hour
4. User can set new password via POST /api/auth/reset-password
5. Old sessions are invalidated after password change
6. All edge cases return appropriate error messages
7. Existing tests still pass, new tests cover the feature

Include Constraints

Specify what you can’t or won’t change:
Constraints to specify:
- API compatibility (can't break existing clients)
- Technology restrictions (must use existing stack)
- Performance requirements (must respond in <100ms)
- Security requirements (must not log PII)
- Time/scope limits (just this one file)

Common Pitfalls to Avoid

Vague Requirements

Make the dashboard faster.

Missing Context

Add caching to the API.

Unrealistic Expectations

Rewrite our entire backend from PHP to Go.

Incomplete Information

The login is broken, fix it.

Best Practices

Structure Your Instructions

Use clear structure for complex requests:
## Task
[One sentence describing what you want]

## Background
[Context and why this matters]

## Requirements
1. [Specific requirement]
2. [Specific requirement]
3. [Specific requirement]

## Constraints
- [What you can't change]
- [What must be preserved]

## Success Criteria
- [How to verify it works]

Provide Examples

Show what you want through examples:
Add input validation to the user registration endpoint.

Example of what validation errors should look like:

{
  "error": "validation_failed",
  "details": [
    {"field": "email", "message": "Invalid email format"},
    {"field": "password", "message": "Must be at least 8 characters"}
  ]
}

Validate:
- email: valid format, not already registered
- password: min 8 chars, at least 1 number
- username: 3-20 chars, alphanumeric only

Define Success Criteria

Be explicit about what “done” means:
This task is complete when:
1. All existing tests pass (npm test)
2. New tests cover the added functionality
3. The feature works as described in the acceptance criteria
4. Code follows our style guide (npm run lint passes)
5. Documentation is updated if needed

Iterate and Refine

Build on previous work:
In our last session, you added the login endpoint. 

Now add the logout functionality:
1. POST /api/auth/logout endpoint
2. Invalidate the current session token
3. Clear any server-side session data
4. Follow the same patterns used in login

The login implementation is in src/api/auth/login.js for reference.

Quick Reference

ElementBadGood
Location”in the code""in src/api/users.py line 45”
Problem”it’s broken""TypeError when user.preferences is None”
Scope”add authentication""add JWT-based login endpoint”
Behavior”make it work""return 200 with user data on success”
Patterns(none)“follow patterns in src/services/“
Success(none)“all tests pass, endpoint returns correct data”
The investment you make in writing clear instructions pays off in fewer iterations, better results, and less time debugging miscommunication. Take the extra minute to be specific.