Forge Rovo Agent Integration
Adds a Rovo AI agent to an Atlassian Forge app. The agent is declared in
manifest.yml and backed by Forge function handlers that call Confluence APIs.
Architecture Overview
User (Rovo chat) → Rovo runtime → manifest.yml (agent + actions) → Forge functions (src/index.ts) → Confluence REST APIs
- Declarative layer:
rovo:agent+actionmodules inmanifest.yml - Implementation layer: exported async functions using
@forge/api - No agent-specific frontend code -- Rovo handles the chat UI
When to Use
- Adding an AI agent to an existing Forge app
- Creating Rovo actions that query or mutate Confluence content
- Building CQL-based reporting/search agents
- Generating Confluence pages with embedded macros via Rovo
- Creating pages containing any of the app's Forge macros (generic pattern)
Step-by-Step Integration
1. Add dependencies
# @forge/api is required for backend Confluence calls
yarn add @forge/api@^4
# Upgrade @forge/bridge if needed for emitsReadyEvent support
yarn add @forge/bridge@^5
2. Configure manifest.yml
Add three module types under modules::
modules:
rovo:agent:
- key: your-agent-key
name: Your Agent Name
description: What the agent does (shown to users)
prompt: |
System prompt instructing the agent's behavior.
Include: what to extract from user input, which actions to call,
how to format responses, and fallback behavior.
conversationStarters:
- "Example prompt 1"
- "Example prompt 2"
actions:
- your-action-key
action:
- key: your-action-key
function: yourFunction # Must match function key below
actionVerb: GET # GET | CREATE | UPDATE | DELETE
description: What this action does (used by Rovo to decide when to call it)
inputs:
paramName:
title: Human-readable label
type: string # string | integer | boolean
required: true
description: "Description with examples"
function:
- key: yourFunction
handler: index.yourFunction # file.exportedFunctionName
3. Add required scopes
permissions:
scopes:
- read:chat:rovo # Always required for Rovo agents
# Add API-specific scopes:
- search:confluence # For CQL search
- read:page:confluence # For reading pages
- write:page:confluence # For creating/updating pages
- read:space:confluence # For space lookups
4. Implement function handlers
Create src/index.ts with exported async functions matching your function keys:
import api, { route } from '@forge/api';
export async function yourFunction(payload: YourPayload) {
// Validate inputs
if (!payload.requiredField) {
return { error: 'requiredField is required.' };
}
// Call Confluence API
const response = await api.asUser().requestConfluence(
route`/wiki/rest/api/your-endpoint?param=${payload.requiredField}`,
{ method: 'GET' }
);
const data = await response.json();
// Return structured data (Rovo renders this for the user)
return { results: data.results, count: data.results.length };
}
5. Frontend: emit ready event (if app has macros)
If your app has Custom UI macros, add emitsReadyEvent: true to the macro
module and call view.emitReadyEvent() after the macro loads. This is required
for Rovo-embedded macro previews.
Key Patterns
Context placeholder substitution
Replace currentSpace() / currentPage() in CQL with actual values from
payload.context.confluence:
function substituteContextPlaceholders(cql: string, context?: any): string {
let result = cql;
if (context?.confluence?.spaceKey) {
result = result.replace(/currentSpace\(\)/g, `"${context.confluence.spaceKey}"`);
}
if (context?.confluence?.contentId) {
result = result.replace(/currentPage\(\)/g, context.confluence.contentId);
}
return result;
}
Structured error responses
Always return { error: string } objects instead of throwing -- Rovo displays
these to the user gracefully.
Space ID resolution
Accept both numeric IDs and space keys, resolve keys via
GET /wiki/api/v2/spaces?keys=KEY.
ADF macro embedding (generic — works for any Forge macro)
Build Atlas Document Format with extension nodes to embed any of the
app's macros in created pages. The pattern accepts a dynamic macroKey
(matching the macro's key in manifest.yml) and a generic macroParams
map (matching the macro's config schema). This works whether the app has
1 macro or 100 — the Rovo action just passes the right key and params.
See handler-reference.md for the full
buildAdfWithForgeMacro pattern and the generic page creation handler.
Prompt Writing Tips
- Be explicit about which actions to call and when
- Include CQL examples in the prompt so the agent can construct queries
- Tell the agent how to format results (table columns, ordering)
- Include fallback behavior (no results, errors, refinement)
- Add a follow-up suggestion pattern (e.g., "offer to save as a page")
Checklist
-
@forge/apiadded to dependencies -
rovo:agentmodule defined with prompt + conversation starters -
actionmodules defined with typed inputs -
functionmodules mapped to handler exports -
read:chat:rovoscope added - API-specific scopes added (
write:page:confluenceif creating pages) - Backend handlers validate inputs and return structured data
- Error responses use
{ error: string }pattern - Macros have
emitsReadyEvent: trueif applicable - If page-creation action: uses generic
buildAdfWithForgeMacrowith dynamic macro key + params - If page-creation action: app ID in
manifest.ymlmatches theextensionTypeARI used in ADF
Additional Resources
- Full manifest patterns: manifest-reference.md
- Backend handler code: handler-reference.md