Guidance for agents working in ai-dash.
- Binary entrypoint:
cmd/ai-dash(cobra CLI) - Core session model/sorting:
internal/session - Configuration:
internal/config(viper + cobra, JSON config file + env vars) - Source discovery and importers:
internal/sources - Per-tool native parsers:
internal/sources/claude— JSONL transcript parser with token/model/status extractioninternal/sources/opencode— SQLite reader with model extraction from message tableinternal/sources/codex— JSONL log parser with session metadata
- Shared source contracts/helpers:
internal/sources/shared - Theme system:
internal/ui/theme(Nord palette, styles, icons, Nerd Font autodetect) - Pure pane sizing helpers:
internal/ui/layout - Overlay rendering helpers:
internal/ui/overlay - Formatting and path helpers:
internal/ui/util - Pure page/pane rendering helpers:
internal/ui/views - TUI code:
internal/uisplit by concern:model.go— Model struct, Options, Init, constructor, focus cycling, filtering, fuzzy search, age/reload configupdate.go— Update loop, search handling, table sync orchestrationview.go— View orchestration, overlays, top bar/footer, sort headers, collapsed previewsessions.go— Session table resize/sync, source table resize/syncdetails.go— Detail table resize/sync, related sessions table, detail item buildersoverview.go— Projects table resize, right-pane table orchestrationstats.go— Overview stats rendering, project aggregation, project sort keyssort.go— Sort cycling, direction toggle, slice rotation helpersterminal.go— Terminal spawning, resume/new session commandspicker.go— Filter picker overlay (bubbles list with fuzzy search), Nord-styledkeys.go— Keybindings (keyMap), context-aware shorthelptables.go— Table constructors, detailItem typeoptions.go— Filter option lists and sort field helpers
- Native parsers for each tool — no heuristic/generic importers for known formats.
- Only official tool provider files are supported. Do not add generic/custom session JSON loaders.
- Each provider implements
SessionProviderand optionallySubagentClassifier. - Each provider implements
NewSessionArgs(projectDir)andResumeArgs(sessionID). - Source paths configurable via
config.json, no legacy env var overrides. - Prefer OSS Bubble Tea v2 ecosystem components over hand-rolled widgets.
- Local-first and terminal-first. No cloud, no HTTP API.
- Nord color scheme throughout. All colors and icon/theme definitions live in
internal/ui/theme. - Nerd Font icons auto-detected via
fc-list, fallback to Unicode. Opt-out via config. - Use
cobrafor CLI,viperfor configuration,sahilm/fuzzyfor search. - Use
humanizefor time/number formatting,lofor slice utilities.
- Use
charm.land/bubbletea/v2for runtime.View()returnstea.ViewwithAltScreen: true. - Prefer
charm.land/bubbles/v2components (table,list,textinput,help) before building custom UI. - Let bubbles components own their state: scrolling, cursor, viewport.
- Call
UpdateViewport()on tables afterSetRows/SetHeightto ensure rendering is current. - Do not shadow the table's cursor with manual
selected inttracking.
- Use
lipgloss.JoinVerticalandlipgloss.JoinHorizontalfor all layout composition. - Use
lipgloss.Placefor centering overlays. - Use
Margin*()/Padding*()for all spacing — never manual" ","\n", orstrings.Repeat. lipgloss.Height(n)sets total height including borders — not content height. UseHeight(h).MaxHeight(h)on panes to enforce exact dimensions.internal/ui/viewsowns the shared pane/page rendering helpers.
help.Model— footer key hints.shortHelpForFocus()returns context-aware bindings per focused pane.table.Model— all tabular data. Column headers include sort indicators viasortHeader().list.Model— filter pickers. ForwardFilterMatchesMsgback to the list by passing unhandled messages when picker is active. CheckFilterState()to avoid intercepting keys during filtering.lipgloss.Height()/lipgloss.Width()— measure rendered strings. Never count\nmanually.lipgloss.NewStyle().Padding()— use for spacing. Never use" "string concatenation.
- Nord color scheme defined in
internal/ui/theme. All semantic colors map toNord*/Color*constants. - Never hardcode
lipgloss.Color(...)outsideinternal/ui/theme(except one-off view-specific styles like the title). theme.TableStyles()for table appearance,theme.ApplyHelpStyles()for help component.- Picker delegate styles set in
newPicker()to match Nord scheme. - Filter chips use
badgestyle (yellow background) withPadding(0, 1).MarginRight(1).
- Top row: Projects table (70%) + Overview stats (30%), sharing
TopPaneHeight. - Bottom row: Sessions table (70%) + Details pane (30%), sharing
BottomPaneHeight. - Focus cycles between Sessions and Projects only (detail pane is display-only).
- Sorting is per-table:
scycles sort for the focused table.
- Each provider implements
SessionProvider:Name(),Discover(),ResumeArgs(),NewSessionArgs(). - Add compile-time check:
var _ shared.SessionProvider = Source{}. - Optional
SubagentClassifierinterface for parent-child detection. Discovery layer calls it after collecting sessions. - Source constructors take
config.Configfor configurable paths. - Claude: native JSONL parser extracts first user message as summary, model from assistant messages, tokens from usage, status from
stop_reason. - OpenCode: SQLite with model extracted from
message.dataJSON viajson_extract. Includessummary_additions/deletions/files. - Codex: JSONL parser with
session_meta,turn_context,response_item,event_msgtypes. Session.Meta(map[string]string) stores tool-specific metadata displayed in the detail pane.Session.Projectshould be the real path (not slug-encoded). Claude usescwdfrom transcript.
- Config file:
~/.config/ai-dash/config.json(viper auto-discovery) - Env vars:
AIDASH_prefix auto-bound by viper (e.g.AIDASH_OPENCODE_PATH) $TERMINALcontrols which terminal opens sessionsdefault_age_filtersupports day shorthand (14d) and Go durations (336h)age_presetsconfigures theDkey cycle optionsnerd_font: nullmeans auto-detect; setfalseto opt out./ai-dash schemagenerates JSON Schema for editor autocompletion
- Preserve the real schema and field relationships, but replace user/project-specific values.
- Rewrite absolute paths to neutral examples unless the path shape itself is under test.
- Replace IDs, slugs, titles, and prompts with safe stand-ins.
- Avoid storing secrets, API keys, internal hostnames, or personal names in fixtures.
- Use
testdata/directories within each source package for JSONL fixtures.
- Run
make fmt,make build, andmake testafter meaningful changes. - Run
golangci-lint run ./...to check for lint issues (errcheck, gofumpt, golines, unused). - Add provider-specific tests when touching importer/parser logic.
- OpenCode tests create an in-memory SQLite database with
sessionandmessagetables viacreateTestDB(). - Claude tests use
testdata/session.jsonlfixture with anonymized real-format JSONL. - UI tests use
resize()andsendKey()helpers, checkView().Contentfor output. TestViewFitsTerminalverifies layout doesn't exceed terminal bounds at multiple sizes.
- Use
internal/ui/utilfor formatting and path helpers likeFormatCost,FormatTokens,DurationLabel,TimeAgo,CleanProjectName, andHumanizeKey. TimeAgouseshumanize.Timefor relative timestamps.CleanProjectNameshortens absolute paths viaShortenPath(~substitution). No slug decoding needed since sources now provide real paths.HumanizeKeyconvertssnake_casemeta keys toTitle Casefor display.
- Follow existing Go package boundaries; avoid unnecessary new top-level packages.
- Keep comments sparse and only where they clarify non-obvious behavior.
- Prefer small helpers and standard library code where it keeps parsing logic clearer.
- Do not introduce destructive behavior or live external dependencies.
- Line length enforced by
golines. Break long lines by extracting variables or using multiline function calls.