HomeBlog › Rovo Agent for HR

Building an HR AI Agent with Atlassian Rovo

Atlassian Rovo is an AI layer that sits across Jira, Confluence, and other Atlassian products. It can search, summarize, and take actions on behalf of users. For Forge app developers, Rovo opens a new interaction model: instead of users navigating to your app's UI, they can ask questions in natural language and the agent retrieves data from your app's backend.

TeamOps uses Rovo to create an HR agent that can answer questions like "How many vacation days do I have left?", "Who is out of office this week?", and "What is the status of the new hire's onboarding?" This post walks through the architecture and the decisions we made building it.

Why an HR agent makes sense

HR data is frequently queried but infrequently changed. An employee checks their leave balance a few times per year. A manager checks team availability weekly during sprint planning. An HR admin checks onboarding progress whenever a new hire starts.

These are read-heavy, context-light queries. The user wants a single piece of information and does not need to navigate a full UI to get it. That is the exact pattern where AI agents add value: reducing a "open the app, find the right tab, look up the data" workflow to a single question.

Compare the two experiences:

For power users who live in the TeamOps UI, the agent is not essential. For casual users who check their balance twice a year, the agent removes all friction.

Architecture: Forge resolvers as agent actions

Rovo agents are defined in your Forge app's manifest.yml. An agent is a collection of "actions" that the AI can invoke based on the user's query. Each action maps to a Forge resolver function.

The manifest entry looks roughly like this:

rovo:agent:
  - key: teamops-hr-agent
    name: TeamOps HR Agent
    description: Answers questions about leave balances, team availability, and onboarding status.
    actions:
      - key: get-leave-balance
        function: getLeaveBalance
        description: Returns the requesting user's remaining leave balance by type.
        inputs:
          userId:
            type: string
            description: The Atlassian account ID of the user.
      - key: get-team-availability
        function: getTeamAvailability
        description: Returns who is out of office for a given date range.
        inputs:
          startDate:
            type: string
          endDate:
            type: string
      - key: get-onboarding-status
        function: getOnboardingStatus
        description: Returns progress of active onboardings.

Each action's function references a Forge resolver. These are the same resolvers that power the TeamOps UI. The agent reuses existing backend logic rather than duplicating it.

Key design decision: We did not build separate endpoints for the agent. The Rovo actions call the same resolver functions that the UI calls. This means the agent always returns the same data as the UI, and any bug fix or improvement to the resolver benefits both interfaces simultaneously.

Handling permissions

HR data is sensitive. An employee should see their own leave balance but not a colleague's. A manager should see their team's availability but not another team's. An HR admin should see everything.

Rovo passes the requesting user's Atlassian account ID to the agent action. TeamOps already implements role-based access control (RBAC) in every resolver. When the agent calls getLeaveBalance, the resolver checks whether the requesting user has permission to view the requested data. If someone asks "What is Jane's leave balance?" and they are not Jane's manager or an HR admin, the resolver returns an access-denied response.

This is important because Rovo's natural language interface makes it easy for users to ask for data they should not have access to. The permission check must happen at the resolver level, not at the agent level. The agent does not know your org chart. The resolver does.

Structuring agent responses

Rovo agents return structured data that the AI formats into natural language. The balance resolver returns something like:

{
  "balances": [
    { "type": "Vacation", "total": 20, "used": 8, "pending": 3, "available": 9 },
    { "type": "Sick Leave", "total": 10, "used": 2, "pending": 0, "available": 8 }
  ],
  "asOfDate": "2026-04-06"
}

Rovo's AI takes this structured response and formats it into a readable answer: "You have 9 vacation days and 8 sick days remaining as of April 6, 2026. You have 3 vacation days pending approval."

The key is returning structured data, not pre-formatted text. If you return a formatted string, the AI has nothing to work with for follow-up questions. If you return structured data, the user can ask "How many of those vacation days are pending?" and the AI can answer from the same response.

What the agent can do today

The TeamOps Rovo agent currently supports five query types:

What we intentionally kept out

Write operations. The agent can read data, but it cannot submit a leave request, approve a request, or modify an onboarding template. This is a deliberate constraint.

HR actions have consequences. Approving a leave request affects team capacity. Submitting a request on behalf of someone else raises consent questions. These actions should require explicit user intent in a UI with confirmation steps, not a casual message in a chat window where a typo could approve the wrong request.

Read operations are low-risk. Write operations are high-risk. The agent handles reads. The UI handles writes. This boundary is unlikely to change.

Building your own Rovo agent on Forge

If you are building a Forge app and want to add a Rovo agent, the pattern is straightforward:

  1. Identify your read-heavy queries. What do users look up frequently? Those are your agent actions.
  2. Reuse your existing resolvers. Do not build a parallel API for the agent. Call the same functions your UI calls.
  3. Enforce permissions in the resolver, not the agent. The agent's job is to understand the query and route it. The resolver's job is to check access and return data.
  4. Return structured data. Let Rovo's AI handle the formatting. Your job is to return accurate, well-typed data.
  5. Keep write operations out of the agent. If an action has side effects, it belongs in a UI with confirmation dialogs.

The Forge documentation covers the manifest schema and resolver integration in detail. The TeamOps roadmap includes planned Rovo agent expansions if you want to follow our progress.

TeamOps handles this inside Jira. Free for up to 10 users.