Inspiration
On a building site, questions to the design team go in writing as RFIs (requests for information). Each answer becomes a decision that people build to. A 2013 Navigant study of 1,362 projects estimated that reviewing and answering an RFI costs about $1,080, at an average of 796 RFIs per project. The median time to an answer was 9.7 days (Navigant Construction Forum, "Impact & Control of RFIs on Construction Projects", 2013).
The costly case is not the slow answer. It is the old answer that is still being used. A decision made in an RFI in March can be replaced in a meeting in September. The minutes go into Confluence. Nobody goes back to the March RFI. The crew that ordered parts in March keeps building to it. A 2018 survey by PlanGrid and FMI (PlanGrid sold construction software at the time) found that 48% of rework on US jobs came from poor communication and poor project data.
The facts needed to catch this already exist in Atlassian. The RFI is a Jira issue. The minutes are a Confluence page. The minutes link to the issue. What was missing was something that reads those links before anyone answers the question again.
What it does
Plumbline adds three things to a Jira project.
- An issue panel on each RFI. It checks the question against the project's decisions by spec section, drawing, location, discipline and text. It shows the best match, why it matched, and the proof. If the project's links show that the answer was replaced, it says so: "Text match alone would say DEC-103 … The project's links show DEC-111", citing "OAC Meeting Minutes No. 27, 17 September 2026".
- Ripple. Under the answer, the panel lists the work still relying on the old decision. A person ticks which work to tell and presses "Tell the selected work". Plumbline then comments on each item with the new decision and its evidence. Nothing is sent without that press, and the same work is never told twice about the same decision.
- A Decision Ledger project page. It lists current and replaced decisions, open and overdue RFIs, and who holds each one ("ball in court"). Replacements found only through the graph are counted here too.
A Rovo agent, also named Plumbline, answers the same questions in chat. It has four read-only actions: checkRfi, checkQuestion, listDecisions and whoReliesOn. The same four tools are exposed to outside AI clients, such as Claude Code, through rovo:mcp.
Judges can try it in about three minutes. "Load demo project" on the Decision Ledger page creates a fictional hospital job: 44 Jira issues, 12 decisions, and 4 Confluence meeting-minute pages in a space named PLUMBLINE, with smart links to the issues.
How we built it
- Forge, Node.js 24 runtime, UI Kit (
render: native) for the issue panel and the project page, so both look and behave like Jira. - Teamwork Graph through a persisted Cypher query run with
customQuery. It reads the edge from a Confluence page to a Jira work item (content_entity_links_entity). A later decision with the same scope that cites a page linking to an older decision's RFI is read as its replacement. The decision record's own "supersedes" field is not used for this, because the point is to find what the record missed. - Rovo: one
rovo:agent, fouractionmodules (all GET), and onerovo:skillthat tells the agent when to call each tool and how to present the result. rovo:mcpwith four separate actions. They use only Plumbline's own stored decisions and never Teamwork Graph data, following Atlassian's guidance on graph data leaving the platform. Each MCP answer says this in a note.- Forge storage (KVS) for decisions and for the record of who has been told. RFI details sit in a Jira issue property.
- All Jira, Confluence and graph calls run as the user (
asUser), so people only see what they already have access to. The app declares no external egress. - The matching engine is plain TypeScript with no Forge imports, and has its own tests. The project has 786 passing unit tests (Vitest).
Challenges we ran into
- No curated graph query joins a Jira issue to a Confluence page. We had to write and register a persisted Cypher query, and learn that registration needs the full app ARI.
- The graph sometimes refuses. On a newly provisioned developer site, Teamwork Graph can briefly answer "User is not permitted to query this organization". The client retries, and if the graph still cannot be read, the app carries on with stored decisions and says so on screen.
- Telling people safely. A Forge invocation can stop part way. The Ripple step records each piece of work right after it is told, so pressing again never posts a second comment.
- Keeping the agent honest. The agent answers only from tool results, names what was not checked, and does not give engineering or code advice.
Accomplishments that we're proud of
- The answer changes because of the graph, and the panel shows both answers side by side, so the user can see why.
- A person stays in charge. The agent and the MCP tools only read. Changes happen in the panel, behind one confirmed press.
- The demo builds real Jira issues and real Confluence pages with real links, so the graph has something true to read.
What we learned
- Teamwork Graph is most useful for questions about relationships that no single record holds.
- Making the graph optional made the app better. Every screen has a clear answer when the graph is missing.
- Construction already has the words for this: RFI, ball in court, supersede, OAC meeting. Using them made the screens shorter.
What's next
- Read decisions from more places: submittals, ASIs and change orders.
- Let a team mark a replacement that Plumbline found as confirmed, so it is written back to the record.
- Publish on the Atlassian Marketplace and try it with a contractor's project team.
How Plumbline meets the main technology requirement
Plumbline is a Forge app. Everything runs on Forge: the jira:issuePanel and jira:projectPage modules (UI Kit), the resolver functions, Forge storage, and the Rovo modules (rovo:agent, action, rovo:skill, rovo:mcp). It reads Jira and Confluence through the Forge product APIs and Teamwork Graph through requestTeamworkGraph. It calls no service outside Atlassian.
Links
- Demo video: https://youtu.be/Ww95x2hSvQ8
- Privacy, terms and support: https://github.com/Class-now/plumbline
Built With
- confluence
- cypher
- forge
- jira
- mcp
- node.js
- react
- rovo
- teamwork-graph
- typescript
- vitest