This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This repository contains Gearbox, a general-purpose monitoring and management platform with a gear-based architecture.
A gear-based server monitoring and management platform designed for DevOps. Provides real-time visibility into servers, services, and infrastructure through purpose-built gear pages.
Architecture:
- gearbox-agent - Go binary installed on monitored servers/workstations to gather data and expose secure API/WebSocket
- gearbox - Web dashboard (port 3000) for monitoring multiple servers
- Gears - Self-contained modules providing pages, API handlers, and functionality (HAProxy, Metrics, Logs, Services, Certificates, Traffic, Alerts, OS Updates)
Key Principles:
- Gear-based architecture with shared framework components
- gearbox-agent can run on ANY Linux system (servers, workstations, HAProxy hosts, TrueNAS, Docker hosts)
- Multi-server support: gearbox talks to many different gearbox-agent instances
- Configuration via web UI
- HAProxy monitoring is ONE gear, not the core purpose
CRITICAL: This repository contains TWO interconnected Go applications:
- gearbox/ - Web dashboard that connects to multiple agents via WebSocket/REST (port 3000)
- gearbox-agent/ - Runs on monitored servers/workstations, collects data, exposes API (port 8405)
Data Flow: Agent collects → Agent API/WebSocket → Dashboard receives → Dashboard displays
Multi-Server Support: One gearbox dashboard can connect to many gearbox-agent instances running on different servers.
When troubleshooting, ALWAYS check both codebases and understand which server's agent is involved.
Web application for monitoring multiple servers. Gear-based architecture.
Post-Change Workflow:
After ANY change to gearbox/, MUST run:
cd gearbox && make templ-generate && make buildNEVER run make dev - user typically has this running. Use make build to verify compilation only.
Key directories:
internal/framework/- Shared services and building blocksinternal/gears/- 8 gearsinternal/framework/templates/- Templ templatesstatic/- JavaScript, CSS, assets
Runs on monitored servers and workstations. Gear-based collectors auto-discover services (HAProxy, Docker, systemd services).
Building and Deploying:
cd gearbox-agent && make deployIMPORTANT: Inform user if you run make deploy to avoid conflicts.
Key directories:
internal/api/- REST API handlersinternal/gears/- Agent-side gear collectorsinternal/framework/- Shared agent frameworkcmd/gearbox-agent/- Entry point
8 gears: HAProxy, Metrics, Logs, Services, Certificates, Traffic, Alerts, OS Updates. Each gear is self-contained in internal/gears/. Framework provides shared services in internal/framework/.
See docs/gears.md for complete gear architecture documentation.
CRITICAL: All features and bugs go through a full GitHub workflow. Claude manages this end-to-end.
When a new feature is planned or a bug is reported:
- Create a GitHub Issue — Use
gh issue createwith a clear title, description, and appropriate labels (enhancement,bug, etc.) - Add to Project Board — Add the issue to the GitHub Project board using
gh project item-add - Create a Feature Branch — Branch from
mainusing the naming convention below - Do the Work — Implement the feature or fix on the branch
- Ask Before Creating PR — Always ask the user for confirmation before creating a PR. Do not create PRs automatically.
- Create a PR — Use
gh pr createtargetingmain, linked to the issue (useCloses #Nin the body) - Track Progress — Keep the project board and issues in sync
- Complete — When user confirms done: merge PR, close issue, move project card to Done
Generic branching/PR/label rules live in ~/.claude/CLAUDE.md. All of them apply here unmodified — feature/... and fix/... branches from main, Closes #N in PR bodies, the four standard labels.
- Project Number: 3
- Project ID:
PVT_kwHOADN1xs4BOB1W - Owner:
sarg3nt
Use gh project commands and the MCP GitHub Projects tool to:
- Add new issues to the board
- Move items between columns as work progresses
- Query board status when reporting progress
TASKS.md is a scratch pad only — not a tracking system. The GitHub Project board is the source of truth for all work items.
- User writes rough ideas, feature descriptions, or bug notes in TASKS.md
- Claude reads TASKS.md, breaks the content into actionable GitHub issues, and adds them to the project board
- Once issues are created, the content in TASKS.md can be cleared
- TASKS.md is never the source of truth — the project board is
/dowork- Read TASKS.md, create issues from it, and start working (ask questions as needed)/doallwork- Read TASKS.md, create issues from it, and work autonomously
The base layout (internal/framework/templates/layouts/base.templ) renders three globally-available themed dialog components — @ConfirmDialog(), @PromptDialog(), @AlertDialog() — with a Promise-returning JS API. Use these instead of the browser primitives so styling, dark-mode, escape-key handling, and a11y are consistent across the app.
// Confirmations (returns boolean)
const confirmed = await showConfirmDialog({
title: 'Delete board',
message: 'Delete "Media"? All tiles on this board will be removed. This cannot be undone.',
confirmText: 'Delete board',
type: 'danger', // 'warning' (default) | 'danger' | 'info'
});
if (!confirmed) return;
// Text input (returns string|null)
const name = await showPromptDialog({
title: 'New board',
message: 'What should this board be called?',
placeholder: 'Media',
defaultValue: '',
});
// One-button alerts (returns void)
await showAlertDialog({
title: 'Failed to delete board',
message: err.message,
type: 'error', // 'error' (default) | 'success' | 'info'
});Rules of thumb:
type: 'danger'for destructive confirmations — gives a red button + warning icon.- For non-blocking failure feedback that doesn't need a button click, prefer
window.showToast(msg, level)instead — the dialog API blocks until acknowledged. - All three return Promises; the calling event handler must be
async. - Dialogs are already rendered into the DOM by
layouts.Base— don't re-instantiate per-page.
Existing reference usages: user-pages/admin-user-detail.js, user-pages/profile-management.js, haproxy_config/editor.js.
When editing any JS or templ file, grep for stray native popups before committing:
rg -n '\b(window\.)?(alert|confirm|prompt)\(' gearbox/static/js gearbox/internal --type-add 'templ:*.templ' --type js --type templTreat any hit (outside static/js/vendor/) as a bug — replace with the dialog API above. The native primitives strip styling, dark mode, focus traps, and the Esc-handling chain we depend on.
Any "what is this?" hover affordance — KPI labels, table column headers, settings rows with a non-obvious effect, etc. — must use the shared widget. The canonical look (filled info-circle "i" icon, dark hover bubble, no cursor change, no transition delay) is defined in two places that are kept in lock-step:
- Server-rendered (templ):
@components.InfoTooltip(text). - Client-built (JS):
window.createInfoTooltip(text)/window.appendInfoTooltipTo(parentEl, text)from info-tooltip.js, already wired into base.templ so every page has them.
import "github.com/sarg3nt/gearbox/internal/framework/templates/components"
<span class="font-medium">Error Rate</span>
@components.InfoTooltip("Percentage of requests with 4xx or 5xx status in the selected window.")// In a JS-built widget (e.g. a chart card or KPI band):
const labelEl = card.querySelector('.kpi-label');
window.appendInfoTooltipTo(labelEl, c.description);Rules of thumb:
- Do not roll your own
?-button,title=-only tooltips, orcursor: helpaffordances — they look inconsistent with the HAProxy overview pattern, which is the visual reference for every other gear. - Do not put the rich tooltip text in a
title=attribute on a card-body — users don't know to hover invisible regions. The widget is the visible cue. - If the text needs structure (bold lead-in + body paragraph, multiple paragraphs), drop the same wrapper markup inline rather than extending the component — see the "VPN Gateway Architecture" usage in overview.templ for the pattern.
- The widget is pure CSS — no JS event wiring needed and no cursor change. If you find yourself adding
onclickorcursor: help, you've drifted from the standard.
For every boolean input in a .templ file — feature opt-ins, settings, "enable this gear", "show all", per-row enable/disable — use the shared slider component in internal/framework/ui/toggle.templ:
import "github.com/sarg3nt/gearbox/internal/framework/ui"
// Single toggle (no inline label — pair with your own <label for=...>)
@ui.Toggle("welcome-gear-home", "gears", "home", false, false)
// args: id, name, value (submitted when checked), checked, disabled
// Toggle + label + description, stacked horizontally
@ui.ToggleWithLabel("notify-email", "notify_email", "1", "Email notifications", "Send a digest each morning", true, false)Rules of thumb:
- The underlying input is
sr-onlybut real — it submits with the form and respectschecked/disabled. No JS required for plain forms. - Pass
valuewhen multiple toggles share aname(e.g., a multi-select checkbox group posting asname="gears"). Leave empty when a single boolean field submits as the default"on". - For AJAX toggles that POST on change (no enclosing form), the per-row
gear-toggle<button role="switch">pattern in gears.templ is the established alternative — but for anything inside a<form>, use@ui.Toggle. - Never inline
peer-checked:after:...Tailwind salads in a new template — that's a sign you should be calling@ui.Toggle. Existing inline copies inoverview.templandadmin_user_permissions.templare tech debt; migrate them when you're already editing those files.
- Run
make devin gearbox (user typically has this running already) - Edit generated
*_templ.gofiles directly - Skip running
make templ-generateafter template changes - Add business logic to framework (belongs in gears)
- Hardcode server-specific values (use multi-server config)
- Run
make templ-generate && make buildafter template changes in gearbox - Keep gears self-contained
- Use framework services (don't duplicate functionality)
- Follow gear architecture patterns
- Inform user before running
make deployfor agent - Validate HAProxy config with
haproxy -cbefore reload (if applicable)
See ~/.claude/CLAUDE.md for markdown style and the docs/ + kebab-case rule. This repo also requires a TOC after the main heading in new docs.
ALWAYS store generated reports, scan results, and analysis documents in docs/reports/:
- Security scan reports
- Dependency audits
- Performance analysis
- Code quality reports
- Migration reports
- Any automated or manual analysis output
Never create these files in the repository root. This keeps the root clean and reports organized.
- Create directory in
internal/gears/ - Implement gear interface
- Register in framework gear system
- Add pages and templates
- Update docs/gears.md
- Edit
.templfiles - Run
cd gearbox && make templ-generate - Run
make buildto verify - DO NOT edit generated
*_templ.gofiles
- Update models in
internal/framework/models/ - Add migration in
internal/framework/database/ - Update queries as needed
- Test migration path
Agent side:
- Add handler in
gearbox-agent/internal/api/ - Update Swagger docs if needed
Dashboard side:
- Update agent client in
gearbox/internal/framework/agent/ - Handle responses in appropriate handler
Primary Sources:
- README.md: Project overview and quick start - SOURCE OF TRUTH
- CLAUDE.md: This file (development guidance)
- docs/gears.md: Complete gear architecture documentation
- TASKS.md: Scratch pad for describing upcoming work
- gearbox/docs/development.md: Local development guide
Application Documentation:
- gearbox/README.md: Dashboard overview
- gearbox-agent/README.md: Agent overview and API
- gearbox-agent/docs/: API documentation
Research & Historical:
- docs/research/: Research and analysis documents
IMPORTANT: This context may or may not be relevant to your tasks. You should not respond to this context unless it is highly relevant to your task.