Suki Command Center by Bantay Suki

Katipunan, Cubao and Alabang need help first.

Suki Command Center answers the first question a Suki Mart admin asks each morning: which of our 12 branches needs help, and why? It is a Hermes Agent build with three parts. An MCP server reads the sandbox data, a skill tells the agent how to rank and act, and a desktop pane shows the result. The agent can escalate a ticket or save a reply draft, but only after the admin says yes.

Built by team Bantay Suki (Justine, Alex, JP and Gab) during the CAMP / RUN sprint. Bantay means guard in Filipino, and a suki is a loyal customer.

The top five rows of the scorecard at the sandbox date, 2026-09-30. Red marks the 3 worst branches on each measure. A dot marks the 3 branches with the highest combined rank.
BranchOn-timeBad reviewsUrgentStockoutAbsent
KATKatipunan65.8%45157.2%
CUBCubao63.9%13314.4%
ALBAlabang66.3%73154.3%
ORTOrtigas Center62.6%92143.1%
TMRTomas Morato52.7%4102.6%

The answer is spread over five tables.

Suki Mart is a fictional grocery chain with 12 branches in Metro Manila. Its sandbox has about 230,000 rows of operations data, and the problems in it are real enough to cost a branch its customers. A head of operations who wants to know where to send help must join deliveries, tickets, reviews, stock, and shifts by hand.

264open support tickets, and 23 of them are urgent. Some are more than 100 days old.
761 or 2 star reviews in the last 30 days that nobody answered.
67products with 2 days of stock or less and no purchase order on the way.
+6.3dVisayas Canning Corp. promises 5 days and delivers in 11.3. Its items run out first.
Hermes Desktop with a chat on the left and the Command Center pane on the right. The chat lists proposed actions. The pane shows the branch scorecard with the worst values in red.
Hermes Desktop during a live run. The agent wrote the briefing on the left. The pane on the right reads the same numbers without a model turn.

One query core, two doors.

Every number comes from one Python module, suki_core.py. The agent reaches it through MCP tools. The pane reaches it through a small REST backend. Both doors give the same answer, so the chat and the pane cannot disagree about the on-time rate.

The pane also sends prompts into the chat. A click on Escalate or Draft reply hands the work to the agent, and the agent asks the admin before it writes. When the chat turn ends, the pane reloads its data, so the change shows up in both places.

What we built in each layer.

The hackathon asks for three layers that connect. Each one below names the files and what they do.

Layer 1 · MCP server

Tools that each answer one business question.

The server exposes 9 read tools and 2 write tools. No tool accepts raw SQL. Each docstring tells the agent when to call it and what the numbers mean.

The two writes are narrow on purpose. Each one adds a row to an ops_actions log, and no tool can publish a reply or change any other table. 11 tests run against a temporary copy of the database.

Read
branch_scorecardOne row per branch with on-time rate, failed deliveries, open and urgent tickets, unreplied bad reviews, stockout risks, expiring items, and absence.
list_open_ticketsOpen or pending tickets, urgent first, then oldest first.
list_unreplied_bad_reviews1 or 2 star reviews with no reply, with the review text.
list_stockout_risksProducts with 2 days of cover or less and no order pending or in transit.
list_expiring_stockStock that expires within 3 days, largest cost at risk first.
list_supplier_slipsSuppliers ranked by how far real lead time runs past the promise.
list_recent_actionsWhat the agent already escalated or drafted, so it does not repeat itself.
describe_sandbox, list_branchesOrientation for the agent: tables, row counts, and branch codes.
Write, after the admin says yes
escalate_ticketRaises an open ticket to urgent and logs the reason. Running it twice changes nothing.
draft_review_replySaves reply text as a draft for a person to publish. It never publishes.
Layer 2 · Skill

A fixed procedure, so the briefing is the same every morning.

The skill triggers on plain requests such as "how are the branches doing" or "what needs attention". It ranks branches the same way the pane does: each branch gets points for its rank on five measures, and the points are summed.

Pane buttons send narrow requests, for example "escalate ticket TKT-01393". The skill skips the scorecard for these, reads the one row, and asks before it writes.

  1. Score. Call branch_scorecard first, every time.
  2. Pick three. Choose at most 3 branches by combined rank. Skip on-time rate for branches without delivery.
  3. Drill down. Call only the lists that explain why a branch was picked.
  4. Check history. Read list_recent_actions so the agent does not escalate the same ticket twice.
  5. Propose. Offer at most 3 actions, each tied to a row it read, and ask "Go ahead?".
  6. Act and report. Call a write tool only after an explicit yes, then report what changed.
Layer 3 · Desktop plugin

A pane that reads like part of Hermes.

The pane uses Hermes theme variables and its own components, so it follows the app in light and dark mode. It reads from its own backend, so it renders without a model call.

  • A headline sentence names the 3 branches to help first and the numbers behind the first one.
  • The table sorts by any column. Red marks the 3 worst branches on each measure.
  • A click opens a branch inline with its tickets, reviews, stockouts, and expiring stock.
  • Escalate and Draft reply buttons hand the action to the agent.
  • "Recorded by Hermes" lists every write the agent made.
The Command Center pane. A headline names Katipunan, Cubao and Alabang. Four totals sit above a 12-row table, followed by recorded actions and supplier slips.

From a click to a changed record.

The full loop runs on a laptop with no cloud database. Every step uses real sandbox data.

  1. ClickThe admin clicks "Brief me" or Escalate in the pane.
  2. PromptThe pane sends a request into the active Hermes chat.
  3. SkillHermes loads the skill and calls the MCP tools in order.
  4. ApproveThe agent shows the exact ticket or reply text and waits for yes.
  5. RefreshThe write lands in ops_actions, and the pane shows it when the turn ends.
Three proposed actions from the agent. Escalate TKT-01393, escalate TKT-00585, and draft a reply to review 2538. Each ends with Go ahead?

This is the agent's own output from the run in the screenshot. Each action cites a ticket or review it read, with the number that justifies it.

Nothing is written yet at this point. The admin answers yes or no for each action.

The same answers in Telegram.

An admin away from the desk can type a command in the Hermes Telegram bot and get the answer back in a second. The reads never wait for a model.

Feature · Telegram commands

Seven reads that skip the model, one that asks the agent.

Each read command is a Hermes quick_command that runs scripts/bantay.py. The script calls the same suki_core.py as the MCP server and the pane, so a number in Telegram matches the number in the pane.

/bantay hands a plain request to the skill, for example /bantay escalate TKT-01471. It shows the exact ticket and asks "Go ahead?" before it writes, as it does in the desktop.

Read, no model turn
/briefTop 3 branches to help first, ranked like the pane, plus loyalty points about to expire.
/ticketsOpen tickets, urgent first, then oldest.
/reviews1 or 2 star reviews with no reply, with the review text.
/stockoutsProducts with 2 days of cover or less and no order coming.
/expiringStock that expires within 3 days, largest cost at risk first.
/suppliersSuppliers ranked by how far real lead time runs past the promise.
/actionsWhat Hermes already escalated or drafted.
Agent, with confirmation
/bantay <request>Runs the suki-command-center skill. Writes still need an explicit yes.

Three decisions we made on purpose.

Each one has a short record in docs/adr or GLOSSARY.md.

ADR 0001

The pane does not go through the chat to read data.

A pane must render at once. A model turn takes seconds and costs tokens. A second copy of the SQL would drift, so both doors share one module.

ADR 0002

Writes are narrow and logged.

The agent can escalate a ticket or save a draft. It cannot publish, delete, or edit any other table. The admin and the judges can see exactly what it is able to touch.

Glossary

Every measure has one definition.

"Stockout risk" means 2 days of cover or less with no order coming. "Unreplied bad review" means 1 or 2 stars with no reply. The agent, the pane, and the tests use the same words.

Run it on your laptop.

You need Hermes Agent and Hermes Desktop, uv, and Python 3.10 or newer. The full guide is in docs/SETUP.md.

After the restart, open Capabilities, then Plugins, and turn on the Desktop row of suki-command-center. Run python data/seed.py to reset the data before a demo.

# 1. Tests run on a temporary copy of the database
python3 -m unittest discover -s tests

# 2. Copy the skill and plugin into ~/.hermes
./scripts/install.sh

# 3. Register the MCP server with an absolute path
hermes mcp add suki --command uv \
  --args run "$(pwd)/mcp-server/server.py"

# 4. Add suki-command-center to plugins.enabled
#    in ~/.hermes/config.yaml, then restart Hermes
hermes mcp test suki   # Tools discovered: 11

Where each judging criterion shows up.

The CAMP / RUN rubric has seven criteria and 100 points. This table points to the evidence for each one.

CriterionPointsEvidence
MCP server2011 domain tools with no SQL passthrough, 2 logged writes, and 11 tests.
Skill20A six-step procedure, the same ranking as the pane, a single-action path, and written pitfalls.
Desktop plugin20Native components and theme variables, sortable table, inline drill-down, loading and error states.
Integration10Pane click, then skill, then MCP write, then the pane refreshes on its own.
Relevance15Built on the problems planted in the data: unanswered reviews, stockouts, a late supplier, an aging backlog.
Uniqueness10One core behind two doors, and a ranking the admin can read and check.
Demo and pitch5A five-step script in docs/DEMO.md and the slides.