Hey everyone 👋
I've been building a Forge app called Pixie and wanted to share it with the community — both to show what it does and to get feedback on the approach.
The problem
When a JSM agent opens a ticket, the answer often already exists in a Confluence Knowledge Base article. But finding it means context-switching: leaving the issue, searching Confluence, guessing keywords. Atlassian's own research points to knowledge bases being able to deflect a large share of customer requests (they cite figures around 45%), but that only happens if the right article actually gets in front of the agent (or customer) at the right moment.
What Pixie does
Pixie is a Forge UI Kit app that lives in the JSM/Jira issue panel. When an agent opens a ticket, it:
- Reads the ticket context — summary, description, and recent comments via the Jira REST API.
- Extracts topics with an LLM — it sends the ticket text to an NVIDIA NIM model (Nemotron) and gets back a small set of search topics. This is closer to NLP intent-matching than plain keyword search.
- Searches the Confluence KB — builds a CQL query and calls the Confluence search API, respecting the current user's permissions (restricted pages the agent can't see are never surfaced).
- Ranks the results — a transparent, deterministic scoring formula (title matches weighted higher than body matches) produces a "Relevance %" and keeps the top 3–5.
- Shows suggestions in clean cards — each with the title, an excerpt, a Relevance lozenge, and actions.
- Lets the agent act — Open Article, or Send to Customer (posts a public reply on the JSM request with the article link, where the project supports it).
- Tracks feedback — opened / sent / not useful, stored as minimal aggregate counts in Forge KV storage, surfaced on an admin page. The idea is to actually measure which suggestions help.
A few things I was deliberate about
- Secrets stay backend-only. The AI API key lives in an encrypted Forge environment variable and is only ever read inside a resolver — it never touches the frontend.
- No chain-of-thought leaks. The model is a reasoning model, so I disable thinking (
enable_thinking: false) and defensively strip any <think> blocks. The UI only ever shows the final structured output. - Permissions are respected, never bypassed. All product calls useÂ
asUser(), so Jira and Confluence enforce what the agent is actually allowed to see and do. - Honest capability handling. "Send to Customer" uses the JSMÂ
servicedeskapi public-comment endpoint — but on non-JSM projects (no customer portal) it returns a clear message and falls back to "Open Article" instead of faking the action. - Minimal scopes. I only added a scope when a feature actually required it:Â
read:jira-work, search:confluence, write:servicedesk-request, storage:app. - Simple caching. Search results are cached in the KV store with a short TTL to avoid hammering Confluence for the same ticket.
Tech stack
- Forge UI Kit (@Forge /react) for the issue panel + an admin global page
- Forge resolvers (@Forge /resolver + @Forge /api) for all backend logic
- Jira REST API for ticket data, Confluence REST API (CQL search) for the KB
- NVIDIA NIM / Nemotron for topic extraction
- Forge KV Storage (@Forge /kvs) for feedback + caching
Questions for the community
- For KB matching, has anyone had better results combining CQL text search with the model actually re-ranking the returned pages, versus scoring locally? I kept ranking deterministic on purpose, but curious about tradeoffs.
- Send to Customer across project types is fiddly — any patterns you like for detecting portal-enabled requests before showing the action?
- Any gotchas withÂ
search:confluence + CQL at scale (rate limits, long-query 400/431 issues)? I'm already keeping queries compact.
Happy to share more detail on any part. Feedback very welcome — especially on the ranking approach and the JSM comment flow. 🙌