Anudeep
All work

Kuyil · AI assistant for PI-ERP / Product design case study

An AI assistant you can check.

Kuyil answers questions about live PI-ERP data: overdue work orders, stock, receipts. I redesigned it and built the new chat front end, so every answer shows where its data came from, every failure says what happened, and the assistant shares one design system with the web app and PiGo.

Role
Product design · front-end build (React, TypeScript)
Team & time
Only designer, with the chat-server engineers · Oct 2026
Scope
14 screens and states · 12 micro-flows
Status
Live in PI-ERP

RelatedPI-ERP: role-based UX at scale PiGo mobile platform

Final capture. Kuyil answering “Which work orders are overdue?” with a Results card (Table and Chart, copy, download), Open in PiERP record chips and a follow-up chip, beside the same answer in the narrow chat window as one card per record.

Kuyil answering “Which work orders are overdue?” with a Results card (Table and Chart, copy, download), Open in PiERP record chips and a follow-up chip, beside the same answer in the narrow chat window as one card per record.

Scroll horizontally on small screens to inspect details. Press Escape to close.

An answer with its data card and record links, and the same chat in PI-ERP's 420 × 600 window. Demo data.
The problem
Answers gave no source, a failure only said “I'm sorry, I encountered an error”, a “Clear” button with a trash icon deleted nothing, and a green dot stayed on even when Kuyil couldn't connect.
What I did
Redesigned all 14 screens and states and built the new chat front end: a data card, a source on every answer, honest failure, waiting and offline states, and one design system with PiGo and the web app.
The result
Live in PI-ERP. Every data answer names its source, time and row count, records open in PI-ERP in one click, and no state is left to a bare spinner or a generic apology.

01 / Starting point

Answers you had to take on faith.

Kuyil turns a question like “Which work orders are overdue?” into a query on live PI-ERP data. The old answer was a plain table with raw dates, five rows under “Showing 28 records”, and nothing to say where the data came from. Now the data sits in its own card with Table and Chart views, Copy and CSV, long tables fold behind Show more, and the records in the answer open in PI-ERP.

Before capture. Kuyil before: an answer in a bordered bubble with a plain table of work orders, ISO dates, status codes like DR and MW, “Showing 28 records”, a Clear button with a trash icon and a green status dot.

Kuyil before: an answer in a bordered bubble with a plain table of work orders, ISO dates, status codes like DR and MW, “Showing 28 records”, a Clear button with a trash icon and a green status dot.

Scroll horizontally on small screens to inspect details. Press Escape to close.

Before. Same demo data in both, drawn from the running build.

After capture. Kuyil after: the answer as readable text, a Results card with a count of 28, Table and Chart, copy and download, Open in PiERP record chips, Copy, Read aloud and Translate, and a follow-up chip above the message box.

Kuyil after: the answer as readable text, a Results card with a count of 28, Table and Chart, copy and download, Open in PiERP record chips, Copy, Read aloud and Translate, and a follow-up chip above the message box.

Scroll horizontally on small screens to inspect details. Press Escape to close.

After. The data card, record links and actions under every answer.

02 / The principle

If people act on an answer, they need to check it first.

People act on Kuyil's answers: which jobs to chase, which products to reorder. And an AI answer can be wrong. So the goal wasn't a friendlier chat. It was an answer you can verify and act on, and a screen that's honest about what it knows in every state, including the bad ones.

The question I started with
Did Kuyil answer?
The question it became
Can I check this answer, and act on it?

03 / Trust

Show the source, admit the limits.

Three decisions that make an answer something you can check.

  1. 01A source on every answer

    After capture. The Results card in Table view, sorted by Status, and in Chart view as horizontal bars per asset, each with the line “From the knowledge graph · live data as of 04:57 PM · 28 rows”.

    The Results card in Table view, sorted by Status, and in Chart view as horizontal bars per asset, each with the line “From the knowledge graph · live data as of 04:57 PM · 28 rows”.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    Table or chart, with the same source line under both.
    Evidence
    Answers came with no source, so there was no way to tell where a number came from or how fresh it was.
    Decision
    A source line under every data answer says where the data came from, when, and how many rows. Records in the answer become Open in PiERP chips, and the message box carries “Kuyil can make mistakes. Check the info.”
    Trade-off
    Inline [1][2] citations need chat-server work, so the source is per answer, not per sentence.
    Implemented result
    Every data answer can be traced to its source and time, and any record in it is one click from PI-ERP.
  2. 02Say what failed, and keep the question

    Before capture. Failed answer before: a generic apology asking the user to check the connection.

    Failed answer before: a generic apology asking the user to check the connection.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    Before: the same apology for every failure.

    After capture. Failed answer after: “Kuyil couldn't answer that” with the reason, Try again and Edit question.

    Failed answer after: “Kuyil couldn't answer that” with the reason, Try again and Edit question.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    After: the reason, and two ways forward.
    Evidence
    A failure only said “I'm sorry, I encountered an error while processing your request. Please check the connection and try again.”, whatever the cause.
    Decision
    Show the server's real reason, keep the question, and offer the next step: Try again resends it, Edit question puts it back in the box. Copy, Read aloud and Translate are hidden on a failure, because there's nothing to act on.
    Implemented result
    A failure now reads, for example: “Kuyil couldn't answer that. Kuyil is not configured — ask your administrator to set it up in the LLM Configuration window. Your question is kept.”
  3. 03Be honest about saved answers

    After capture. A reopened chat: the answer text with a note “Saved answer. The data may have changed since.” and an Ask again for live data button.

    A reopened chat: the answer text with a note “Saved answer. The data may have changed since.” and an Ask again for live data button.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    A reopened answer says it's saved, and offers live data.
    Evidence
    Past chats are saved as text only, so a reopened answer can show numbers that are no longer true. ERP data moves.
    Decision
    Label a reopened answer “Saved answer. The data may have changed since.” and offer Ask again for live data, which runs the question fresh in the same chat.
    Trade-off
    Keeping tables in reopened chats needs server work, so saved answers show text only.
    Implemented result
    An old answer is never mistaken for live data, and fresh data is one click away.

04 / Waiting and failing

Design the states the old screen left to chance.

Waiting for an answer and losing the connection happen every day. Each state now says what's going on and what you can do.

  1. 01Show the work while Kuyil thinks

    Before capture. Waiting before: a small “Retrieving data...” spinner under the question.

    Waiting before: a small “Retrieving data...” spinner under the question.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    Before: a spinner, however long it takes.

    After capture. Waiting after: “Kuyil working · 4s” with three steps, the first ticked, and a Stop button where Send was.

    Waiting after: “Kuyil working · 4s” with three steps, the first ticked, and a Stop button where Send was.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    After: named steps, seconds, and Stop.
    Evidence
    While answering, Kuyil showed a spinner and “Retrieving data...”. Past about three seconds, a bare spinner feels broken.
    Decision
    Three named steps with ticks (understanding the question, getting data from PI-ERP, writing the answer) and a seconds counter. Send becomes Stop, in the same place, so one button has one meaning at a time.
    Trade-off
    Stop only stops the waiting: the server still finishes its query, because there's no cancel API yet.
    Implemented result
    You can see progress and stop a slow answer, and the chat notes “You stopped this answer” with Ask again.
  2. 02Show the connection only when it's wrong

    Before capture. Offline before: the header's green dot still on while the empty screen says Unable to connect, with a Retry button.

    Offline before: the header's green dot still on while the empty screen says Unable to connect, with a Retry button.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    Before: “connected” and “unable to connect” at once.

    After capture. Offline after: an amber banner “Kuyil is not connected” with Retry now, the earlier answer still readable, and the message box reading “Waiting for connection…”.

    Offline after: an amber banner “Kuyil is not connected” with Retry now, the earlier answer still readable, and the message box reading “Waiting for connection…”.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    After: one honest banner; answers stay readable.
    Evidence
    A green dot stayed on in the header, even while the screen said “Unable to connect”.
    Decision
    Show nothing when the connection is fine. When it drops, a banner explains with Retry now, earlier answers stay readable, and the disabled message box says why: “Waiting for connection…”.
    Implemented result
    The only connection state on screen is one that needs you, and a disabled box always explains itself.

05 / Inside PI-ERP

The same assistant in a 420 × 600 window.

The floating Kuyil button in PI-ERP opens a narrow window. The old layout squeezed the conversation into a sliver beside a full sidebar. Now the sidebar starts as a 38px icon rail, tables become one card per record instead of scrolling sideways, and every action is still there.

Before capture. Narrow window before: a full sidebar takes half the width, the header wraps word by word, and the table is cut off at the right edge.

Narrow window before: a full sidebar takes half the width, the header wraps word by word, and the table is cut off at the right edge.

Press Escape to close.

Before: the sidebar takes half the window.

After capture. Narrow window after: an icon rail, then the answer with one card per work order, Show more, and the full message box.

Narrow window after: an icon rail, then the answer with one card per work order, Show more, and the full message box.

Press Escape to close.

After: one card per record.

06 / Writing

Every line says what will happen.

In an AI product, the words set expectations. Each line now says what a control does, or why something can't happen yet.

Header action
Before“Clear” with a trash icon (it never deleted anything)
After“New chat” at the top of the sidebar
New chat title
BeforeNone
After“Untitled chat” until the first question names it
Connection
BeforeGreen dot, always on
AfterNothing when fine; “Connecting to Kuyil…” in the message box; an offline banner with Retry now
Failed answer
Before“I'm sorry, I encountered an error…”
After“Kuyil couldn't answer that”, the reason, Try again and Edit question
Long table
Before“Showing 28 records”
AfterShow more / Show less
Below the message box
Before“Press Enter to send • Try asking about delayed orders…”
After“Enter to send · Shift + Enter for a new line” and “Kuyil can make mistakes. Check the info.”
Sidebar footer
BeforeNone
After“Info comes from your PiERP data.”
Your question, on hover
BeforeNo actions
AfterCopy · Ask again
Search, nothing found
BeforeNo search
After“No results”

07 / Built like the rest of the product

One design system, and ready before the server.

  1. 01The same tokens and icons as PiGo and the web app

    Before capture. Start screen before: a logo, “How can I help?” and one suggested question in a blue pill, with a green status dot and a Clear button.

    Start screen before: a logo, “How can I help?” and one suggested question in a blue pill, with a green status dot and a Clear button.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    Before: one suggestion and its own visual style.

    After capture. Start screen after: “How can I help today?” with six suggested questions grouped by work orders, inventory, orders and receiving, an Untitled chat in the sidebar, and the shared design tokens.

    Start screen after: “How can I help today?” with six suggested questions grouped by work orders, inventory, orders and receiving, an Untitled chat in the sidebar, and the shared design tokens.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    After: six starting points by area, on the shared tokens.
    Evidence
    Kuyil had its own look: raw color values, a generic icon library, and a fixed blue that ignored the tenant's brand.
    Decision
    Move Kuyil onto the Atlassian Design System tokens, type ramp and icon names that PiGo and the PI-ERP web UI use. Icons are copied path for path from PiGo, and the few PiGo doesn't have are drawn in the same 24px, 2px-stroke style.
    Implemented result
    No raw colors or generic icons left in the chat, and Kuyil takes the tenant's brand from the same Appearance & Branding setting as the web app and PiGo.
  2. 02Build ahead of the server, and switch on by itself

    Built · hidden capture. Delete chat confirmation naming the chat “How many work orders are open?”, saying it can't be undone, with Cancel focused and a red Delete button.

    Delete chat confirmation naming the chat “How many work orders are open?”, saying it can't be undone, with Cancel focused and a red Delete button.

    Scroll horizontally on small screens to inspect details. Press Escape to close.

    The delete confirmation names the chat, and Cancel has focus.
    Evidence
    Chats couldn't be renamed or deleted, and the chat server had no tools for either yet.
    Decision
    Build Rename and Delete in full but hidden, and show them the moment the server lists the two tools. Delete always confirms and names the chat, with Cancel focused so Enter never deletes by accident.
    Implemented result
    No front-end release is needed when the server is ready, and the server contract is written down for its owners.

08 / How I worked

One review page, every state.

I was the only designer, working with the engineers who own Kuyil's chat server. The review page showed all 14 screens and states before and after, with the same demo data in both panes so the only difference was the design, drawn to scale from the running build. Twelve micro-flows showed what the person does at each step and what the screen says back.

I built the front end in React and TypeScript with AI-assisted coding: formatting for dates, CSV and record links, a shared icon set in place of the generic library, and components for the answer, the data card, the sidebar and the thinking steps. Anything that needed the server went to its owners as a written contract instead of a workaround.

09 / Collaboration

I designed Kuyil and built its chat front end. Engineering owns the server and the AI underneath.

My contribution

  • UX and UI for 14 screens and states
  • Interface writing
  • Chat front end in React and TypeScript
  • Answer layout, data card, source line and actions
  • Design tokens and the shared icon set

Engineering

  • Kuyil's chat server and its tools
  • Data queries and the knowledge graph
  • LLM configuration
  • Deployment and infrastructure

10 / Status

Where it stands.

Kuyil redesign
Live in PI-ERP
Rename and Delete
Built; appears when the chat server offers it

Status as of late October 2026.

11 / Learning

Trust in an AI assistant isn't one feature. It's every state telling the truth: where the answer came from, how old it is, what went wrong, and what you can do next.

What I'd do differently

Agree the server contract first. Stop can't cancel a query, and Rename and Delete wait behind a switch, because the front end was designed before the server had those APIs. Settling the contract on day one would have let them ship together.

Next · needs chat-server work

Answer feedback, regenerate, inline [1][2] citations, keeping tables when a past chat is reopened, and a real cancel for Stop.