vibetree
A small, self-contained IT asset inventory system. The heart of vibetree is a nested folder tree — like a file manager — for organizing physical and virtual IT assets (servers, switches, laptops, printers, etc.).
- Single compiled Go binary, embedded HTML templates and static assets
- SQLite storage (WAL mode, foreign keys, migrations)
- Bootstrap 5 UI, minimal vanilla JavaScript (no Node/React/build step)
- Session-based auth with two roles: Admin and User
- Custom, admin-defined asset types with custom fields
- CSV import/export, full-text-ish search with breadcrumbs
Quick start
go build -o vibetree ./cmd/vibetree
./vibetree serve
Then open http://localhost:8080 and log in with:
Username: admin
Password: admin
(This default account is created intentionally on first run. Change or disable it via the Users admin page once you're up and running.)
The database file is created automatically at data/vibetree.db on first
run, with migrations applied and seed data (default statuses, item types,
and the admin account) inserted.
CLI
vibetree # same as `vibetree serve`
vibetree serve # start the web server
vibetree version # print the version
vibetree database migrate # apply pending migrations and exit
vibetree database backup [path] # write a consistent VACUUM INTO snapshot
serve flags:
| Flag | Default | Description |
|---|---|---|
-addr |
:8080 |
Listen address |
-db |
data/vibetree.db |
Path to the SQLite database file |
-secure-cookies |
false |
Mark the session cookie Secure (enable when serving over HTTPS) |
/healthz is available for load balancer / container health checks.
The inventory tree
The Inventory page is the default page after login and the center of the application: a folder/asset tree on the left, and a detail panel on the right that shows whatever is selected (a folder's contents, or a single asset).
- Folders can nest arbitrarily deep, and contain both subfolders and assets.
- Expand/collapse state is remembered per user (persisted server-side), and folder contents are fetched lazily via small AJAX requests — the page never fully reloads when you browse the tree.
- Drag and drop folders and assets onto another folder (or onto "Inventory" itself) to move them. Admin only.
- Right-click for everything: it's meant to feel like a native file manager. Right-click a folder, an asset, a breadcrumb crumb, or empty tree/panel background for the actions available there (New Subfolder, Add Asset, Rename, Check Out, Move, Print Label, Delete, …) instead of hunting for a toolbar button. The main panel itself stays blank until you actually click into a folder or asset — browsing happens in the tree.
- Deleting a folder that still contains subfolders or assets requires confirmation, and offers a safe "move contents elsewhere" option instead of an accidental cascade. A "permanently delete everything inside" option is also available for when that's genuinely what you want.
- Search (top of the tree pane) looks across asset ID, name, folder name, item type, assigned user, notes, and custom field values, and shows each result's full folder breadcrumb.
Item types and custom fields
Admins can define arbitrary asset types (Laptop, Switch, Firewall, …) under Item Types, each with its own set of custom fields (text, long text, number, date, boolean, dropdown, URL, IP address), marked required or not, with a default value and display order. A representative starter set of types and fields is seeded on first run — feel free to edit or delete it.
Checkout, quantity, and contacts
- Check out / check in: right-click an asset → Check Out… to assign it to a user (or clear the assignment to check it back in). Works from any asset row, not just its detail view.
- Quantity vs. unique: item types have a Unique flag (checked by default). Unique types — a laptop, a server — get one asset row per physical unit, same as before. Uncheck it for bulk/consumable types (a USB cable, a box of screws) and assets of that type are tracked as a single row with a Quantity and +/- steppers in the asset panel and folder tables, instead of one row per unit. Flipping a type back to Unique clamps any existing quantities back down to 1.
- Contacts: under Settings → Users, a third role alongside Admin and User. Contacts can't sign in at all — they exist purely so you can assign assets to end users (e.g. "this laptop belongs to Jane in Accounting") without creating them a login account. A blank password is fine when creating one.
QR/barcode asset tags and printable labels
Every asset can have a scannable label printed for it: right-click an asset for Print Label, or right-click a folder for Print Labels… (every asset in that folder, recursively). Choose the code format on the print page itself:
- QR code — encodes an absolute
/scan/<Asset ID>URL, so scanning it with a phone camera opens straight to that asset. - Barcode (Code128) — encodes the bare Asset ID, meant for a dedicated USB barcode scanner typing it into whatever's focused (e.g. the app's search box).
The print page also supports three label sheet layouts, switchable from a dropdown:
- Avery 5160 / 5260 (1" x 2-5/8", 30/sheet) — standard address labels (5260 is the same grid, just rounded corners), exact published dimensions.
- 61526 asset tag labels (3/4" x 2", ~48/sheet) — the grid/margins here are a best-effort layout, not a verified spec sheet, so print one test page on plain paper and check it against a real label before committing a full (often non-refundable) sheet.
Printing a batch without wasting sheet space: Ctrl/Cmd+click (toggle) or Shift+click (range) multiple folders/assets in the tree, the same way you would in a file manager, then right-click the selection for Print Labels (N) — along with Export CSV (N), Edit Status…, Check Out…, Duplicate, Move to…, and Delete, all bulk versions of the single-item actions. On the print page itself, Start at # lets you resume printing partway into an already-used sheet (position 1 = top-left, counting left-to-right, top-to-bottom) instead of starting a fresh one over a few peeled-off labels.
CSV import / export
- Export: from the tree's right-click menu, or
/export/assets.csv(optionally scoped to a folder, with?recursive=1to include subfolders). Includes aQuantitycolumn and onecf_<field_key>column per distinct custom field in use. - Folder-scoped import: right-click a folder → Import CSV… imports
every row directly into that folder. No
Foldercolumn needed — that's the whole point of doing it from a specific folder. Never available at the top level. - Global import: Settings → Import / Export has the full-featured
version — a CSV with a
Foldercolumn (a/-separated path, e.g.Main Office/Network) that can optionally auto-create missing folders — plus a separate CSV import for bulk-adding/updating Statuses (Name,Color). Both matching-by-name/Asset-ID semantics and full column references with examples are documented right on that page.
A full backup/restore of everything (folders, assets, types, custom fields,
statuses, users) is just vibetree database backup — it's a consistent
snapshot of the whole SQLite database.
Project layout
cmd/vibetree/ CLI entrypoint (serve, version, database migrate/backup)
internal/
auth/ session management, secure cookies
database/ SQLite connection, pragmas, migrations
migrations/ embedded .sql migration files
models/ shared domain types
folders/ nested folder tree
assets/ asset CRUD, search, CSV import/export
itemtypes/ admin-defined types + custom field definitions
users/ accounts
statuses/ configurable asset statuses
settings/ key/value app settings
web/ HTTP router, handlers, template rendering
web/
templates/ Go html/template pages and partials (embedded)
static/ Bootstrap 5, Bootstrap Icons, app.css, app.js (embedded)
deploy/ systemd unit example
Development
go build ./...
go vet ./...
go test ./...
The SQLite driver is modernc.org/sqlite,
a pure-Go implementation, so CGO_ENABLED=0 builds work out of the box and
the compiled binary has no C library dependencies.
Docker
docker compose up --build
This builds the image, starts vibetree on port 8080, and persists the
database in a named volume (vibetree-data, mounted at /app/data).
Or directly:
docker build -t vibetree .
docker run -p 8080:8080 -v vibetree-data:/app/data vibetree
systemd
See deploy/vibetree.service for an example unit. Adjust the paths, then:
sudo useradd --system --home /opt/vibetree --shell /usr/sbin/nologin vibetree
sudo mkdir -p /opt/vibetree/data
sudo cp vibetree /opt/vibetree/vibetree
sudo chown -R vibetree:vibetree /opt/vibetree
sudo cp deploy/vibetree.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now vibetree