Skip to content

AI Agents - Best Practices

NOTE

Documentation updated: November 28, 2025

Learn how to write effective agent prompts, avoid common mistakes, and optimize your agents for production use.

1. Writing Effective Instructions

Your agent's behavior is determined by three core components: description, goals, and rules. Here's how to write each one effectively.

Description (What)

The description is a 1-2 sentence summary that defines the agent's domain and purpose.

Good Examples:

json
"AI tutor for 5th grade math focusing on fractions and decimals"
"Educational assistant that checks grammar in student essays"
"Workshop moderator for design thinking sessions"

Bad Examples:

json
"Helper"                          // Too vague
"AI that does everything"         // No focus
"Super smart assistant bot"       // Meaningless buzzwords

Tips:

  • Be specific about the domain (math, language, design)
  • Include the level or context (5th grade, beginner, professional)
  • Focus on ONE core function
  • Keep it under 100 characters

Goals (Why)

Goals are 2-4 objectives ordered by priority. They define what success looks like.

Good Examples:

json
{
  "goals": [
    "Help students understand concepts without giving direct answers",
    "Build confidence through encouragement",
    "Adapt difficulty based on student performance"
  ]
}

Bad Examples:

json
{
  "goals": [
    "Be helpful",                 // Too vague
    "Answer questions"            // No strategy
  ]
}

Tips:

  • Order by priority (most important first)
  • Make them measurable ("help students understand" vs "be helpful")
  • Include HOW, not just WHAT ("without giving answers")
  • Limit to 4 goals maximum

Rules (Boundaries)

Rules define constraints - what the agent should NEVER do and ALWAYS do.

Good Examples:

json
{
  "rules": [
    "Never reveal the full answer",
    "Always encourage effort before offering hints",
    "Respond in the student's language",
    "If student is stuck for 3+ minutes, offer a hint"
  ]
}

Bad Examples:

json
{
  "rules": [
    "Be nice",                    // Too subjective
    "Help students"               // Not a constraint
  ]
}

Tips:

  • Use "Never" and "Always" to set hard boundaries
  • Include timing conditions ("after 3 minutes", "before answering")
  • Address edge cases ("if student is stuck", "when timer expires")
  • Be specific about behavior, not feelings

2. Prompt Templates by Persona

Use these templates as starting points for different agent types.

Tutor Template

For educational assistants that guide learning without giving answers.

json
{
  "name": "Math Tutor",
  "persona": "tutor",
  "instructions": {
    "description": "Educational assistant for [SUBJECT] at [LEVEL]",
    "goals": [
      "Guide students to discover answers themselves",
      "Identify misconceptions and address them",
      "Build confidence through encouragement"
    ],
    "rules": [
      "Never give direct answers",
      "Use Socratic method (ask guiding questions)",
      "Match complexity to student level",
      "Celebrate small wins and progress"
    ],
    "triggers": [
      {
        "event": "object:created",
        "condition": "object.type === 'answer-card'",
        "action": "evaluate_answer"
      },
      {
        "event": "participant:idle",
        "condition": "idleSeconds > 180",
        "action": "generate_hint"
      }
    ]
  }
}

Use for: Language learning, homework help, tutoring platforms

Moderator Template

For session management and room monitoring.

json
{
  "name": "Session Moderator",
  "persona": "moderator",
  "instructions": {
    "description": "Session moderator for [TYPE] meetings",
    "goals": [
      "Keep discussion on track",
      "Ensure equal participation",
      "Flag inappropriate content"
    ],
    "rules": [
      "Don't interrupt active discussion",
      "Be neutral, don't take sides",
      "Escalate serious issues to host",
      "Send time warnings 2 minutes before transitions"
    ],
    "triggers": [
      {
        "event": "timer:tick",
        "condition": "minutesRemaining === 2",
        "action": "send_notification",
        "params": { "message": "2 minutes remaining" }
      },
      {
        "event": "participant:idle",
        "condition": "idleSeconds > 300",
        "action": "notify_teacher",
        "params": { "message": "Room silent for 5+ minutes" }
      }
    ]
  }
}

Use for: Workshops, breakout sessions, classroom management

Facilitator Template

For guiding participants through structured activities.

json
{
  "name": "Workshop Facilitator",
  "persona": "facilitator",
  "instructions": {
    "description": "Workshop facilitator for [ACTIVITY]",
    "goals": [
      "Guide participants through activities",
      "Manage time effectively",
      "Summarize key insights at the end"
    ],
    "rules": [
      "Announce transitions 2 minutes before",
      "Don't rush creative phases",
      "Keep energy positive and encouraging",
      "Summarize each phase before moving on"
    ],
    "triggers": [
      {
        "event": "timer:tick",
        "action": "send_notification"
      }
    ],
    "schedule": [
      {
        "at": "every:10min",
        "action": "send_notification",
        "params": { "message": "Time check - how's everyone doing?" }
      }
    ]
  }
}

Use for: Design sprints, brainstorming, ideation workshops

Timer Template

For simple time-based notifications without AI.

json
{
  "name": "Pomodoro Timer",
  "persona": "timer",
  "instructions": {
    "description": "Productivity timer for focus sessions",
    "goals": [
      "Keep sessions on schedule",
      "Signal breaks and transitions"
    ],
    "rules": [
      "Trigger every 25 minutes for breaks",
      "5 minute warning before session end"
    ],
    "schedule": [
      {
        "at": "every:25min",
        "action": "send_notification",
        "params": { "message": "Time for a break!" }
      }
    ]
  },
  "maxActionsPerMinute": 2
}

Use for: Pomodoro sessions, timed exercises, sprint planning

3. Trigger Design Patterns

Pattern: Delayed Response

Avoid spam by waiting before acting.

json
{
  "event": "participant:idle",
  "condition": "idleSeconds > 180",
  "action": "generate_hint"
}

Why: Prevents agent from firing immediately when user pauses. Gives time to think.

Pattern: Zone-Based

React only in specific areas of the board.

json
{
  "event": "object:created",
  "condition": "frameId === 'answer-zone'",
  "action": "evaluate_answer"
}

Why: Prevents agent from processing every object. Focuses on relevant areas.

Pattern: Cascade Prevention

Avoid agent reacting to its own actions.

json
{
  "event": "object:created",
  "allowSelfEvents": false,
  "action": "evaluate_answer"
}

Why: Without this, agent could trigger itself in an infinite loop.

Pattern: Conditional Filtering

Process only specific object types or properties.

json
{
  "event": "object:created",
  "condition": "object.type === 'sticky-note' && object.color === 'red'",
  "action": "flag_for_review"
}

Why: Reduces unnecessary processing. Agent only acts when criteria match.

Pattern: Rate-Limited AI Calls

Use scheduled actions for expensive operations instead of event-based triggers.

json
{
  "schedule": [
    {
      "at": "every:5min",
      "action": "summarize",
      "params": { "scope": "all-frames" }
    }
  ]
}

Why: Prevents token explosion. Summarizes periodically instead of on every change.

4. Common Mistakes

MistakeProblemFix
Too vague goalsAgent does random thingsBe specific: "Help students understand fractions" not "be helpful"
No rulesAgent over-helps or gives answersAdd "never" constraints: "Never give full answer"
Too many triggersToken explosion, high costsStart with 1-2 triggers, add more gradually
No scope limitsAgent monitors everythingLimit to specific frames/object types
Missing budgetRunaway costsSet budgetTokens for AI-powered agents
Forgetting allowSelfEvents: falseInfinite loopsPrevent agent from reacting to itself
Single-assertion testsNot validating behaviorUse multiple assertions per test
Conditional assertionsTests pass but don't validateAvoid if (x) expect(y) - always assert

Example: Too Vague

Bad:

json
{
  "description": "Helper",
  "goals": ["Be helpful"],
  "rules": ["Be nice"]
}

Good:

json
{
  "description": "Math homework assistant for grades 6-8",
  "goals": [
    "Help students identify mistakes in calculations",
    "Teach problem-solving strategies"
  ],
  "rules": [
    "Never solve the problem for them",
    "Ask what step they're stuck on",
    "Provide examples of similar problems"
  ]
}

Example: Token Explosion

Bad:

json
{
  "triggers": [
    {
      "event": "object:created",
      "action": "evaluate_answer"  // Fires on EVERY object!
    }
  ]
}

Good:

json
{
  "triggers": [
    {
      "event": "object:created",
      "condition": "object.type === 'answer-card' && frameId === 'quiz-frame'",
      "action": "evaluate_answer",
      "allowSelfEvents": false
    }
  ],
  "scope": {
    "frames": ["quiz-frame"],
    "objectTypes": ["answer-card"]
  },
  "budgetTokens": 10000
}

5. Testing Your Agent

1. Start Simple

Begin with one trigger and one action:

json
{
  "triggers": [
    {
      "event": "object:created",
      "action": "send_notification",
      "params": { "message": "New object created" }
    }
  ]
}

Test that it works before adding complexity.

2. Test Edge Cases

Edge CaseHow to Test
Empty inputCreate object with no text
Long textCreate object with 1000+ characters
Special charsCreate object with emojis, unicode
Rapid eventsCreate 10 objects in 10 seconds
Agent's own objectsVerify allowSelfEvents: false works

3. Monitor Action Log

Check what the agent is actually doing:

bash
curl -X GET https://app.boardapi.io/api/v1/boards/{board_uuid}/agents/{agent_id}/actions \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Response:

json
[
  {
    "id": "action-uuid",
    "action": "evaluate_answer",
    "reasoning": "Student submitted answer in red zone",
    "output": "Hint: Check your calculation in step 2",
    "tokens_used": 150,
    "created_at": "2025-11-28T10:30:00Z"
  }
]

Look for:

  • Is reasoning logical?
  • Is output appropriate?
  • Are tokens_used within budget?

4. Adjust Gradually

Don't change everything at once. Make one change, test, repeat.

1. Add one trigger → Test
2. Add condition → Test
3. Add scope limitation → Test
4. Add second trigger → Test

6. Performance Tips

Set Rate Limits

Protect against runaway agents:

json
{
  "maxActionsPerMinute": 5,  // Max 5 actions per minute
  "budgetTokens": 10000       // Max 10K tokens total
}

Default is 10 actions/minute. Lower for expensive AI calls.

Use Token Budgets

For AI-powered agents, always set a budget:

json
{
  "persona": "tutor",
  "budgetTokens": 5000  // Stops at 5K tokens
}

Agent will pause when budget is exhausted.

Scope to Specific Frames

Don't monitor the entire board if you only need one area:

json
{
  "scope": {
    "frames": ["quiz-frame", "answer-frame"],
    "objectTypes": ["sticky-note", "text"]
  }
}

Performance impact:

  • No scope: Agent processes ALL events
  • With scope: Agent ignores events outside scope

Use Stealth Mode for Background Agents

If agent doesn't need to be visible:

json
{
  "visibility": "stealth"
}

Benefits:

  • Doesn't clutter participant list
  • Doesn't create agent object on canvas
  • Still processes events normally

Batch with Scheduled Actions

Instead of reacting to every event, batch process periodically:

Bad (fires on every change):

json
{
  "triggers": [
    {
      "event": "object:updated",
      "action": "summarize"
    }
  ]
}

Good (batches every 5 minutes):

json
{
  "schedule": [
    {
      "at": "every:5min",
      "action": "summarize",
      "params": { "scope": "changed-since-last-run" }
    }
  ]
}

7. Production Checklist

Before deploying agents to production:

□ Description is specific and clear
□ Goals are prioritized (2-4 items)
□ Rules include "never" and "always" boundaries
□ Triggers have conditions (not monitoring everything)
□ allowSelfEvents: false for triggers that create objects
□ scope limits set (frames, objectTypes)
□ maxActionsPerMinute is set (lower for AI calls)
□ budgetTokens is set for AI-powered agents
□ Tested edge cases (empty input, long text, rapid events)
□ Monitored action log for reasoning quality
□ Verified no infinite loops
□ Confirmed costs are within budget

8. Advanced Patterns

Multi-Stage Assistance

Provide progressive hints instead of one-time help:

json
{
  "goals": [
    "Give hints in stages: gentle → specific → detailed"
  ],
  "rules": [
    "First hint: ask what they've tried",
    "Second hint: point to relevant concept",
    "Third hint: show similar example",
    "Never give full answer even after 3 hints"
  ]
}

Context-Aware Responses

Tailor agent behavior based on user state:

json
{
  "rules": [
    "If student answered 3+ correctly: increase difficulty",
    "If student struggled on 2+ in a row: simplify",
    "Track progress across session for adaptive hints"
  ]
}

Escalation Pattern

Agent escalates to human when it can't help:

json
{
  "triggers": [
    {
      "event": "participant:idle",
      "condition": "idleSeconds > 600 && hintsGiven > 2",
      "action": "notify_teacher",
      "params": { "message": "Student may need human help" }
    }
  ]
}

Next Steps

Need Help?