← All field notes

Hermes Hub / Field notes

The office my agents built for themselves

I run a team of six AI agents. Their work was scattered across chat sessions and folders, so I assigned two of them to design and build a private dashboard to catalog it all. I directed the work, reviewed the merges, and tested the builds.

Role
Project lead
Stack
Next.js, React, TypeScript, SQLite, Drizzle ORM
Timeline
September 2026
Status
Deployed
Scope
Private, local-first catalog of AI agent work. No cloud sync, no multi-user support.
Hermes Hub dashboard showing project stat cards, Continue Building, Recently Added, Quick Launch, and Needs Attention sections.
The deployed Hermes Hub dashboard with two active projects.

Where I started

I work with six Hermes agents on a Discord server: a chief of staff that orchestrates the others, a coder, a DevRel strategist, an AI architect, a Facebook scheduler, and a career copilot that emails me job shortlists on weekdays.

That setup produced a problem of its own. The agents were doing real work, building apps, drafting artifacts, running work sessions, and the output was scattered across chat threads and folders with no catalog, no memory, no front door. I needed a private place where all of it could land: projects, apps, artifacts, sessions. Local, because this is my working life, and I did not want it in anyone's cloud.

How it was built

Here is the part that makes this project different from everything else I have shipped: I did not build it alone, and I was not even the primary builder. The coder bot and the chief of staff led the Hermes Hub project. I set the direction, reviewed the changes, and tested the builds.

The result is a local-first dashboard: Next.js App Router, strict TypeScript, SQLite through Drizzle ORM, with all persistence confined to server modules, so the browser never touches the filesystem or the database. The catalog covers projects, apps, artifacts, an inbox, sessions, and tags, with an activity log over all of it.

The engineering is genuinely solid, which matters because "an agent built it" invites skepticism. The server is layered: routes call services, services call repositories, repositories talk to Drizzle. Input goes through Zod contracts. Merges go through pull requests with independent review. The recorded validation run shows 715 passing assertions across 62 files: tests, lint, typecheck, migrations, build, dependency audits.

Architecture diagram: six Discord agents feed work into the local-first Hermes Hub Next.js app, which reads a SQLite catalog through Drizzle ORM. Everything runs on one computer.
The architecture: agent work flows into a local Next.js app backed by a SQLite catalog. Nothing leaves the machine.

A three-layer diagram. Top: the six Hermes agents on Discord, with the Chief of Staff orchestrating the Career Copilot, Coder Bot, DevRel Strategist, AI Architect, and Facebook Scheduler; their work products flow into the catalog. Middle: Hermes Hub, a Next.js App Router app serving on 127.0.0.1:3000, with Dashboard, Projects, Apps, Artifacts, and Inbox pages; requests flow through Routes, Services, Repositories, and Drizzle ORM, and database-backed pages render per request. Bottom: the SQLite catalog, a local file holding projects, apps, artifacts, sessions, tags, and activity events. A boundary around the app and database notes loopback-only access with no phone or remote access; the catalog stays on the computer with no cloud sync.

Decisions and tradeoffs

Local-first and private by design

Why
The dashboard catalogs my actual working life. A cloud database would mean trusting a third party with all of it.
The tradeoff
One machine, no sync, no sharing. If I want the catalog on another computer, that is a problem I have not solved. Deliberately.
Notes & evidence

Catalog records live in a local SQLite database in the OS app-data directory. There is no cloud sync, no login, no external-service integration. Opening a saved app URL can still connect the browser to that app's destination.

Manual manifest import instead of automatic scanning

Why
The original instinct was automatic filesystem scanning. For a tool that sits next to private work, explicit consent beats convenience.
The tradeoff
More friction per import.
Notes & evidence

Artifacts enter through manifest preview and import: you look at exactly what will be cataloged before anything is recorded. No background filesystem collection. The privacy boundary is a feature, not a missing feature.

Sanitized demo data from day one

Why
The plan was always to make the repo public eventually, so the seed data is fictional from the start.
The tradeoff
Maintaining two datasets, the demo fiction and the real catalog, is ongoing work.
Notes & evidence

Three demo projects, four apps, eighteen artifacts, six inbox items, all with example.test URLs and paths like C:/fictional-workspaces/.... A clean-demo verifier spins up an isolated copy, runs the full pipeline (install, migrate, seed, tests, lint, typecheck, build), and tears it all down without touching the real catalog.

The Quick Launch fix: testing caught what review didn't

Why
When I tested the app, I found it myself: Quick Launch opened the catalog details page instead of the saved app URL. The button labeled 'launch' did not launch anything.
The tradeoff
It admits the shipped V1 had a first-use bug in a headline feature, found the one time I actually tested the build.
Notes & evidence

The fix separated 'Open app' from 'View details,' keeping the URL safety checks, and went through as a reviewed pull request. A follow-up made 'Open app' launch in a new tab. So this one was caught by testing, not by daily use. I would rather show the correction than pretend it was perfect.

The stale Projects page: the page was frozen, not the data

Why
The Projects page said 'No projects yet' while the database held two projects and the API returned both. The page was wrong and the data was right.
The tradeoff
It would be simpler to write 'all checks passed.' The first HTTP check failed on an overly broad assertion; the failure was preserved, not relabeled, and a narrower semantic check passed instead.
Notes & evidence

The verified cause: Next.js had statically prerendered /projects at build time, so production kept serving the build-time snapshot instead of querying the catalog on each request. The prerender manifest listed /projects as static with no revalidation window, and an async server component with a direct SQLite query was not, by itself, enough to prevent prerendering. Nothing was wrong with the records; what was stale was the generated page output.

The fix was one line per page: export const dynamic = "force-dynamic"; on four database-backed pages (/projects, /inbox, /apps/new, /artifacts/new), making them render at request time. No query, schema, or data handling changed. The dashboard and /apps already rendered dynamically, and a route audit confirmed the remaining database-backed pages were already dynamic.

Validation: 11 focused tests across three files, independently executed, covering the rendering declarations and actual SQLite-backed page behavior. The production build classified all four routes as dynamic, with none left in the static prerender entries. Post-build HTTP checks showed newly created projects rendering on all four pages. On the live deployment: HTTP 200 across the routes, catalog unchanged, backup hash unchanged. Real Chrome acceptance passed with both projects visible and the creation-form selectors working.

Shipped

The polished build is deployed and accepted: the approved visual pass, the Quick Launch fix, the dashboard feedback changes, and the rendering fix above, all serving in production with the live catalog preserved. Preflight, rehearsal, data-equality, and acceptance checks all passed, and the deployment receipt is retained.

Screenshots

Hermes Hub dashboard with stat cards, Continue Building, Recently Added, Quick Launch, and Needs Attention sections.
The dashboard: project stats, continue-building shortcuts, recent artifacts, quick launch, and a needs-attention panel with nothing to flag.
Projects page listing the Hermes Hub and Get a job! projects as active.
The Projects page after the rendering fix, with both projects listed and served fresh on every request.
Apps page with two pinned app cards; live URLs and the local folder path are redacted.
The Apps page. Live URLs and the local folder path are redacted for the portfolio.
Artifacts page showing the Nikema Job Search Tracker spreadsheet entry.
The Artifacts page: cataloged work, metadata only.

What the evidence says

Validation runverified

715 assertions passed across 62 files, plus typecheck, lint, migration, and build stages.

The repo's Windows validation docs (docs/windows-hosted-manual-validation.md and docs/windows-standalone-validation.md) record 715 passing assertions across 62 files. Confirmed against the private repository.View evidence ↗
Seed data countsverified

3 projects, 4 apps, and 18 artifact titles (12 published, 6 inbox).

src/server/demo/demo-data.ts defines 3 projects, 4 apps, and 18 artifact titles (12 published, 6 inbox-prefixed). Confirmed against the private repository.View evidence ↗
Quick Launch behaviorverified

Open app renders target=_blank with rel=noopener noreferrer; View details is a same-tab Next.js Link.

In src/components/dashboard/quick-launch-item.tsx, Open app renders an anchor with target="_blank" rel="noopener noreferrer"; View details is a Next.js Link to /apps/[id] that stays in the current tab. Confirmed against the private repository.View evidence ↗
Stale Projects page fixverified

11 focused tests passed; HTTP checks and real Chrome acceptance passed with both projects listed.

Root cause verified as build-time prerendering of /projects (static in the prerender manifest, no revalidation); the fix was force-dynamic on four database-backed pages with no query, schema, or data changes; validation covered 11 focused tests, production build route classification, HTTP checks, and real Chrome acceptance. Confirmed against the chief of staff's verified incident account and the deployment record.View evidence ↗
Deploymentverified

Deployment completed and accepted; preflight, rehearsal, data-equality, and acceptance checks passed with the live catalog preserved.

Polished build deployed and accepted; production serving with the live catalog preserved; preflight, rehearsal, data-equality, and acceptance checks passed. Confirmed against the retained deployment record.View evidence ↗

Remaining work, honestly stated: the portfolio packaging. There is no narrated demo yet, and the repository is still private. The product is ahead of its explanation, which is why this case study exists.

What I learned

Hermes Hub is evidence of a specific skill: directing agents the way you would direct engineers. I set the charter (private, local-first, catalog everything), held the privacy boundaries, reviewed the merges, and caught the headline bug by testing the build. When the Projects page went stale, I held the incident to the same standard: verified cause, minimal fix, honest validation record. The agents wrote the code. The judgment was mine.

The honest limits: the repo still needs its public debut, and this study still needs a real cover image before it can leave draft status.

That is the portfolio story. Not "I built a dashboard." It is "I ran the team that built the dashboard, and here is the proof I knew what I was doing."

← Back to selected workMore questions.
Better next steps.