How to

How to build a feature request tracker

Requests arrive in six places, get promised in two of them, and the roadmap is argued from memory. Here is the model behind a tracker, the prompts to build it, and what it takes to run it.

The short answer

A feature request tracker is four parts: intake from every channel into one record, deduplication that merges rather than discards, demand weighted by the accounts behind each request, and a loop that tells requesters when something ships. The part teams skip is the last one. A tracker that collects requests and never reports back trains the field to stop submitting, and within two quarters it is measuring the enthusiasm of three people rather than the demand of a market.

feature-requests.helix-app.ai

Feature requests

214

Open requests

38

Merged this month

6

Blocked a deal

11

Shipped, loop closed

Received 94

Dark mode

67 people · 3 accounts · 190K

Custom fields

12 people · 5 accounts

Under consideration 61

Scheduled reports

44 people · 6 accounts · 410K

Planned 38

Bulk CSV export

31 people · 14 accounts · 2.10M

In progress 21

SSO for viewers

9 people · 9 accounts · 1.84M

A sketch of the board, ordered by weighted demand rather than vote count. Dark mode has the most requesters and the least money behind it, which is the distinction a vote count cannot make.

What matters here

  • A request tracker is four parts: intake, deduplication, weighted demand, and a loop back to whoever asked.
  • Merge duplicates, never discard them. The count of who asked is the signal, and deleting a duplicate deletes the evidence.
  • Weight by the accounts behind a request, not by the number of requests. Ten asks from one champion is one ask.
  • Separate the problem from the proposed solution at intake. People submit solutions, and the problem underneath is what you can actually address.
  • Closing the loop is what keeps intake honest. Silence trains the field to stop submitting.
  • The tracker reads CRM data to weight demand, so managed credentials and scoped access belong in the build.

Who this is for

You run product, or you sit between the field and the roadmap. You already have requests arriving faster than you can read them. What you want is one list, weighted by something real, and a way to tell people what happened.

How it works in practice

What happens to a request from the moment somebody types it to the moment they hear back.

  1. 1

    It lands from wherever it came

    Sales call, support ticket, community, field or internal. One record, with the original wording kept exactly as written.

  2. 2

    The problem is captured separately from the ask

    People submit solutions. The problem underneath is what you can actually address.

  3. 3

    Duplicates are merged, not closed

    Every requester and account stays attached to the surviving record, because that count is the signal.

  4. 4

    Demand is weighted by what is behind it

    Contract value of the accounts asking, renewal risk, whether it blocked a deal, and how recently it came up.

  5. 5

    Product argues with components, not a total

    Each part of the score is visible, so a disagreement is about an input rather than about the number.

  6. 6

    Everyone who asked hears what happened

    Shipped, planned, declined with a reason, or already possible. This is what keeps intake alive.

What a request tracker is made of

A request tracker is not a backlog with votes on it. It is four parts, and the third one is where most of them go wrong.

Intake from every channel

Sales calls, support tickets, community posts, the field, and product themselves. One record whatever the source, with the requester, the account and the original words kept intact.

Deduplication that merges

The same request arrives twenty times in twenty phrasings. Merging keeps every requester attached to the surviving record. Discarding throws away the demand signal.

Weighted demand

Not a vote count. Contract value of the accounts asking, whether they are at risk, whether it blocked a deal, and how recently it came up.

A loop back

When something ships, or is declined, everyone who asked hears about it. This is what keeps people submitting, and it is the part that gets cut.

These prompts start from a Helix project, which is what handles sign-in, credentials and hosting. Start with Helix

The prompts

Paste these into Claude Code, Codex or Cursor in order. Each one leaves you with something that runs, so you can stop after any step.

  1. One record, whatever the channel

    Intake, and separating what people asked for from what they need.

    In this Helix project, build me a feature request tracker.
    
    One record per request, whatever channel it arrived through: the
    requester, their account, the source (sales call, support ticket,
    community, field, internal), the date, and the original words exactly as
    they were written. Keep those verbatim. Paraphrasing at intake loses the
    thing you will want to read in six months.
    
    Then two separate fields, and this is the important part: the problem, and
    the proposed solution. People submit solutions. "We need a bulk export
    button" is a solution; "I spend two hours a month copying this into a
    spreadsheet" is the problem, and the problem is what you can actually
    address, sometimes in a way nobody asked for.
    
    Make the intake form take under a minute for someone on a sales call, and
    let me paste in a block of text and have you pull out the fields for me to
    confirm.
    
    I sign in through Helix, so do not build a login page. Read the signed-in
    user from the runtime. And do not put any key or connection string in the
    code: if this needs to reach another system, tell me and I will create the
    connection in my workspace.

    Worth knowing. Splitting problem from proposed solution at intake is a small field change that repeatedly saves you from building the wrong thing well.

  2. Merge, never discard

    Because the duplicate count is the signal.

    Now handle the fact that the same request will arrive twenty times in twenty
    different phrasings.
    
    Suggest likely duplicates on submission, matching on wording and on the
    problem field rather than exact text. Show me candidates rather than
    merging automatically.
    
    When I merge, keep every requester, every account and every original
    wording attached to the surviving record. Never delete a duplicate. The
    count of who asked and which accounts they came from is the entire demand
    signal, and discarding a duplicate throws it away.
    
    Let me split a merge back apart when I get it wrong, because I will.
  3. Weight it by something real

    Accounts behind a request, not the number of requests.

    Now score demand, and do not use a vote count.
    
    For each request, pull in the accounts asking and weight by what is
    actually at stake: total contract value of the requesting accounts,
    whether any of them are at risk or in a renewal window, whether it was
    named as blocking a deal and how large that deal was, and how recently it
    last came up.
    
    Ten asks from one enthusiastic champion is one account asking. One ask
    each from your five largest customers is a different fact entirely, and a
    vote count reports them the same way.
    
    Show the components as well as the total, so a score can be argued with
    specifically. And let me filter by segment, because a request that matters
    enormously to small customers and not at all to enterprise is a real and
    useful pattern rather than a contradiction.

    Worth knowing. Vote counts measure enthusiasm. Contract value behind a request measures demand, and they frequently disagree.

  4. Close the loop, or intake dies

    Statuses that mean something, and telling people what happened.

    Give each request a status that means something to the person who submitted
    it: received, under consideration, planned, in progress, shipped,
    declined, or already possible. Include that last one. A surprising share
    of requests are for something that already exists and nobody found.
    
    When a request changes status, notify everyone attached to it, including
    everyone whose duplicate was merged in. When something ships, say so and
    link to it. When something is declined, say why. A declined request with a
    reason keeps people submitting; silence does not.
    
    Then report: requests by theme over time, which themes have the most
    weighted demand, average age of open requests, and how many shipped items
    came from the tracker at all. That last number tells you whether this is
    a real input to the roadmap or a suggestion box.

    Worth knowing. The loop is the part that gets cut and the part that keeps the data honest. A tracker nobody hears back from stops receiving requests within two quarters.

  5. Connect it to real systems

    The step that turns a working prototype into something with your data in it.

    Now connect it to the systems we actually run, so it works on real data
    rather than the rows you seeded.
    
    Anything in angle brackets is a placeholder. Swap it for whatever we use
    instead, and have the app name the connection it wants rather than assume
    a vendor, so changing my mind later is a config change and not a rewrite.
    
    <Salesforce>. Read the contract value, renewal risk and open deals behind
    each requesting account.
    
    <Zendesk>. Pull requests that arrived as tickets, which is where a lot of
    them start.
    
    <Jira>. Link a planned request to the work, and read back when it ships.
    
    <Slack>. Tell everyone who asked when something ships, which is what keeps
    intake alive.
    
    <Okta>. Read group membership, which is what lets the app show the field a
    status while product sees the full deal context behind a request.
    
    <Amplitude>. Check whether the people asking actually use the area they
    are asking about.
    
    <Snowflake>. Read contract values in bulk, which is what makes weighting
    200 requests practical.
    
    <Notion>. Publish the shipped list where the field already looks for
    release notes.
    
    Only write where I have said to write. Everything else is read only.
    
    Do not write a key, a token or a connection string anywhere in the code,
    and do not ask me to paste one. Tell me which connections you need and I
    will create each as an authentication in my Helix workspace. Reference
    them by alias.

    Worth knowing. Every name in angle brackets is a placeholder for whatever you run. Helix holds the credential as a workspace authentication, so the app references an alias and never the secret itself.

  6. Ship it

    The last step of every build: a URL, and the right people on it.

    Deploy my app.

    Worth knowing. Your assistant runs helix deploy underneath and the app comes back as a URL. Requests carry customer names and deal context, so set Access Control before sharing: the field submits and reads status, product sees everything.

What it connects to

Weighting demand by the accounts behind a request is what makes this different from a vote count, and that needs the CRM.

  • Salesforce

    Read the contract value, renewal risk and open deals behind each requesting account.

  • Zendesk

    Pull requests that arrived as tickets, which is where a lot of them start.

  • Jira

    Link a planned request to the work, and read back when it ships.

  • Slack

    Tell everyone who asked when something ships, which is what keeps intake alive.

  • Okta

    Read group membership, which is what lets the app show the field a status while product sees the full deal context behind a request.

  • Amplitude

    Check whether the people asking actually use the area they are asking about.

  • Snowflake

    Read contract values in bulk, which is what makes weighting 200 requests practical.

  • Notion

    Publish the shipped list where the field already looks for release notes.

Each line says whether the app reads, writes or both. Anything not described as writing should be read only.

Named systems are the ones most teams actually run, not a list of the only ones that work. Swap in whatever you use.

Each connection is an authentication in your Helix workspace, referenced by alias. The app names the connection it wants and never holds the credential, so nothing here ends up in your code and any of it can be rotated or revoked without a redeploy.

Running it for real

The build gets you a working tracker. It reads CRM data to weight demand and it holds customer commentary, so it needs to be run properly.

AI Deployment

Get it to a URL people can open

One command takes the app from your assistant to a live address, so the people who need it get a link rather than instructions for running it locally.

App Security

Put your identity provider in front of it

Requests carry customer names, deal context and candid internal notes. SSO means people sign in with their existing account, and access is scoped so the field sees status while product sees the analysis.

App Security

Connect the system of record with managed credentials

Pulling account values, renewal dates and risk flags to weight demand needs real CRM access. Granting it to the app rather than pasting a key into it means it can be rotated or revoked without a redeploy.

App Registry

Put a name on it

Every app carries a named owner and an entry IT can see, so the tool does not become nobody's problem when the person who built it changes role.

Cost Management

Know what it costs to run

Per-app spend visibility, with budgets and caps, so an internal tool cannot quietly become a line item nobody can explain.

Questions people ask

What is a feature request tracker?

One place every request lands regardless of how it arrived, with duplicates merged rather than discarded, demand weighted by the accounts behind each request, and a loop that tells requesters what happened.

Should I use vote counts to prioritise?

No. Votes measure enthusiasm, and ten requests from one champion counts as ten. Weight by the contract value of the accounts asking, whether they are at risk, and whether the gap blocked a deal. That measures demand.

Why merge duplicates instead of closing them?

Because the count of who asked and which accounts they came from is the demand signal. Closing a duplicate deletes the evidence that made the surviving request important.

Why separate the problem from the proposed solution?

Because people submit solutions. "A bulk export button" is a solution. "Two hours a month copying this into a spreadsheet" is the problem, and it can sometimes be solved better in a way nobody asked for.

What kills a feature request tracker?

Silence. If people never hear what happened to a request, they stop submitting, and within two quarters the tracker measures the enthusiasm of the three people who still bother rather than the demand of a market.

Can I build this without an engineering team?

Yes. The prompts here are written for Claude Code, Codex or Cursor and stage the build. The judgement calls are your weighting inputs and your status list.

Last reviewed September 2026.

Build it, then run it properly

Helix is the governed runtime for AI-built apps. Deploy what you build, put SSO in front of it, connect it to your systems with managed credentials, and give it a named owner.