Skip to main content
This App Showcase post is an AI-generated test blog for evaluating quickstart candidates; treat it as draft application guidance, not final product documentation.
AI-generated test blog - HeavenBase Team - June 23, 2026 - ~1,300 words - ~7 min read
Imagine a small software company with two support requests waiting in the morning. One customer cannot log in, and another customer needs an invoice correction. A human can understand the difference quickly, but a busy team still needs a shared place to answer three questions: what is urgent, what should we do next, and what did we decide? Support Lens is a tiny HeavenBase app for that exact moment. It does not assume you know support operations. It treats the support desk as a collection of simple cards: tickets, runbooks, decisions, and one memory rule for the next agent or teammate.

1. Background and Goal

Without structure, a support handoff often becomes a chat thread: someone pastes the ticket, someone else remembers a checklist, and the final decision disappears into a message history. That works until the team needs to explain what happened later. The goal of this tutorial is to build a small local workflow where:
  • urgent tickets can be found by severity
  • runbooks can be matched by product area
  • the team can write down the decision
  • an agent-facing memory rule can be stored for later
In HeavenBase terms, the app is one workspace. You can think of a workspace as a named notebook that stores typed records and can later expose safe tools to an agent.

2. Scenario and Setting

We will use two fictional customers:
CustomerProblemWhy It Matters
AcmeAdmins cannot sign in with SAML.This blocks the customer’s own team, so it is urgent.
NorthstarAn invoice has a purchase-order typo.This matters, but it does not block product usage.
The support team also has two internal runbooks. A runbook is just a short checklist for a known type of problem.
If you are not a support expert, read “runbook” as “the saved checklist we want the next person to find.”

3. Step 1: Open a Workspace

The community example uses a helper named demo_workspace so each run writes to local .temp/ data and resets cleanly.
import heavenbase as hb

from community_runtime import demo_workspace, parse_reset, print_frame, seed

WS_ID = "community-app-support-lens"

ws, _ = demo_workspace(WS_ID, "apps-support-lens", parse_reset())
ws.enable_extension("agent")
The agent extension is enabled because the final step stores a small memory rule. The first four steps would still make sense without an LLM or a chat agent.

4. Step 2: Define the Cards

The app needs three kinds of cards. A SupportTicket is the incoming customer issue. A Runbook is the checklist. A TriageDecision is the handoff note written after review.
class SupportTicket(hb.Entity):
    """Ticket the support team needs to triage."""

    account = hb.field(hb.ShortText).desc("Customer account")
    issue = hb.field(hb.LongText).desc("Issue text")
    severity = hb.field(hb.Integer).desc("1 is low, 5 is urgent")
    product_area = hb.field(hb.ShortText).desc("Product area")
    status = hb.field(hb.ShortText).desc("open, watching, or closed")


class Runbook(hb.Entity):
    """Internal runbook card."""

    product_area = hb.field(hb.ShortText).desc("Area this runbook covers")
    title = hb.field(hb.ShortText).desc("Runbook title")
    steps = hb.field(hb.LongText).desc("Short action plan")


class TriageDecision(hb.Entity):
    """Decision recorded after a support review."""

    ticket_id = hb.field(hb.Identifier).desc("Ticket object_id")
    owner = hb.field(hb.ShortText).desc("Human owner")
    decision = hb.field(hb.LongText).desc("Next action")
This is the first HeavenBase idea: define the shape of the information before worrying about storage. You are not building database tables by hand; you are naming the records your app cares about.

5. Step 3: Register and Add Starter Data

Registration tells the workspace which cards exist. After that, seed(...) inserts a small realistic starting set.
ws.register(SupportTicket)
ws.register(Runbook)
ws.register(TriageDecision)

seed(
    ws,
    SupportTicket,
    [
        {"object_id": "ticket-login", "account": "Acme", "issue": "SAML login fails for all admins.", "severity": 5, "product_area": "auth", "status": "open"},
        {"object_id": "ticket-billing", "account": "Northstar", "issue": "Invoice PO number typo.", "severity": 1, "product_area": "billing", "status": "open"},
    ],
)
seed(
    ws,
    Runbook,
    [
        {"object_id": "runbook-auth", "product_area": "auth", "title": "SAML outage checklist", "steps": "Confirm IdP metadata, check cert rollover, collect trace id."},
        {"object_id": "runbook-billing", "product_area": "billing", "title": "Invoice correction", "steps": "Void draft, regenerate PDF, notify AP contact."},
    ],
)
The sample data is intentionally small. The point is not volume; the point is that every row has a clear job in the story.

6. Step 4: Ask the First Useful Question

Now ask the question a teammate would ask first: “Which ticket needs attention right now?” Severity 4 or 5 counts as urgent in this demo.
urgent = (
    ws.query(SupportTicket)
    .where(SupportTicket.severity >= 4)
    .select("account", "product_area", "issue")
    .execute()
)

runbooks = (
    ws.query(Runbook)
    .where({"product_area": "auth"})
    .select("title", "steps")
    .execute()
)
The query result is small enough for a human and structured enough for an agent:
Urgent tickets
object_id | account | product_area | issue
------------------------------------------
'ticket-login' | 'Acme' | 'auth' | 'SAML login fails for all admins.'

Matching runbooks
object_id | title | steps
-------------------------
'runbook-auth' | 'SAML outage checklist' | 'Confirm IdP metadata, check cert rollover, collect trace id.'
This is the second HeavenBase idea: the app reads like the user’s question. Query the ticket cards, filter by severity, and select the columns the reader needs.

7. Step 5: Record the Decision and Memory

After the team sees the urgent ticket and matching runbook, it records a decision. This turns a one-time conversation into a row the team can inspect later.
ws.upsert(
    TriageDecision,
    {
        "object_id": "decision-login",
        "ticket_id": "ticket-login",
        "owner": "platform-oncall",
        "decision": "Use SAML outage checklist before escalating.",
    },
)

memory = ws.to_mcp(profile="memory")
memory.run(
    "remember",
    key="support-lens-rule",
    text="Severity 4 or 5 tickets need a runbook lookup before handoff.",
)
The decision belongs to the support workflow. The memory rule belongs to the future agent or teammate. HeavenBase keeps both behind the same workspace boundary.
At the end of the script, the workspace contains the urgent ticket, the matching runbook, one recorded decision, and one remembered rule.

8. What This Teaches

Support Lens is a good quickstart candidate because the reader does not need to know databases, support jargon, or agent architecture. They only need to follow a familiar workflow: receive a problem, find the right checklist, write down the decision, and remember the rule. For a later production app, you could add service-level deadlines, real ticket imports, runbook ownership, or a narrower custom profile that exposes only selected tools to an agent.

Try It

From the community examples checkout, run:
rtk bash scripts/run.bash apps.support_lens
The script writes local data under .temp/ and resets by default, so repeated runs are safe for exploration.

Further Exploration

Related resources:
  • Workspace - The application boundary behind the example
  • Entities - Typed rows for tickets, runbooks, and decisions
  • Query - Filters, projections, and result frames
  • Agent Extension - Persisted agent rows and recipes
  • HeavenBase MCP - Expose workspace tools to agents