Imported from BasuruK/OmniInspect (
AGENTS.md). Install upstream withnpx skills add BasuruK/OmniInspect. Copyright stays with the author.
Agent Guidelines for OmniView/OmniInspect
Response Style
- Concise. Short sentences, terse lists, tables over prose.
- Trade grammar for brevity. Drop filler words.
- No preamble, no restating the question.
- Code references via clickable links, never bare line numbers.
Project Overview
OmniView is a Message Passing TUI application that connects to Oracle Database and displays real-time trace messages via Oracle Advanced Queuing (AQ). Built with Go, Bubble Tea v2, and ODPI-C for Oracle connectivity.
Build Commands
# Build the application (REQUIRED - not 'go run')
make build # Build with default version
make build VERSION=v1.0.0 # Build with specific version
# Build ODPI-C library only
make odpi
# Run the application
make run # Build and run
# Run tests
make test # All tests
go test -v ./... # Equivalent
# Run a single test
go test -v ./internal/core/domain # Test a specific package
go test -v -run TestSubscriber ./... # Test matching pattern
# Lint and format
make lint # go vet
make fmt # go fmt
# Clean
make clean # Remove build artifacts
# Install dependencies
make install # go mod download && go mod tidy
Important Build Notes
- Always use
make buildormake run- nevergo run cmd/omniview/main.go - The Makefile sets required CGO environment variables and Oracle client linker paths
- On macOS ARM64, Oracle Instant Client is at
/opt/oracle/instantclient_23_7 - On Windows, Oracle Instant Client is at
C:\oracle_inst\instantclient_23_7
Architecture
Hexagonal (Ports and Adapters) architecture:
cmd/omniview/main.go (Composition Root)
│
▼
internal/service/ (Business Logic)
│
▼
internal/core/ports/ (Interfaces)
│
▼
internal/adapter/ (Implementations: storage/oracle, storage/boltdb, ui, config)
- Composition root:
cmd/omniview/main.go- wire dependencies here, not in adapters - Domain:
internal/core/domain- entities, value objects, sentinel errors - Ports:
internal/core/ports- repository interfaces - Services:
internal/service- business logic coordination - Adapters:
internal/adapter/storage/oracle,internal/adapter/storage/boltdb,internal/adapter/ui
Code Style Guidelines
Naming Conventions
- Constructor functions:
New...(e.g.,NewSubscriber,NewTracerService) - Interfaces:
...ersuffix (e.g.,SubscriberRepository,DatabaseRepository) - Package names: lowercase, single word or short phrase (e.g.,
tracer,permissions) - Go files: lowercase, underscore allowed (e.g.,
tracer_service.go) - Types: PascalCase (e.g.,
BatchSize,WaitTime) - Constants: PascalCase for typed, UPPER_SNAKE for untyped
Imports
import (
"OmniView/internal/core/domain" // Project imports
"OmniView/internal/core/ports"
"context"
"fmt"
"charm.land/bubbletea/v2" // Bubble Tea v2 (charm.land, NOT github.com/charmbracelet)
"charm.land/lipgloss/v2" // Lipgloss styling
"charm.land/bubbles/v2/spinner" // Bubbles components
)
Section Divider Comments
Use this style for major code sections:
// ==========================================
// Subscriber Entity
// ==========================================
// Or for subsections:
// ─────────────────────────
// Getters (Read-Only Accessors)
// ─────────────────────────
Error Handling
- Sentinel errors: Define in
internal/core/domain/errors.go - Wrap errors with context:
fmt.Errorf("operation: %w", err) - Domain validation errors: Use domain sentinel errors
- Do not introduce ad hoc error strings
// Good
var ErrSubscriberNotFound = errors.New("subscriber not found")
func (s *SubscriberRepository) GetByName(ctx context.Context, name string) (*Subscriber, error) {
if name == "" {
return nil, ErrInvalidSubscriberName
}
// ...
return nil, fmt.Errorf("GetByName: %w", ErrSubscriberNotFound)
}
Constructor Patterns
Constructors return pointers and handle validation:
func NewSubscriber(name string, batchSize BatchSize, waitTime WaitTime) (*Subscriber, error) {
if strings.TrimSpace(name) == "" {
return nil, ErrInvalidSubscriberName
}
// ...
return &Subscriber{...}, nil
}
func NewTracerService(
db ports.DatabaseRepository,
bolt ports.ConfigRepository,
eventChannel chan *domain.QueueMessage,
) *TracerService {
return &TracerService{...}
}
Dependency Injection
- Inject dependencies through constructor arguments
- Use option structs for optional dependencies
type ModelOpts struct {
App *app.App
BoltAdapter *boltdb.BoltAdapter
DBAdapter *oracle.OracleAdapter // Optional
PermissionService *permissions.PermissionService // Optional
TracerService *tracer.TracerService // Optional
AppConfig *domain.DatabaseSettings // Optional
EventChannel chan *domain.QueueMessage
}
func NewModel(opts ModelOpts) (*Model, error) {
if opts.App == nil {
return nil, fmt.Errorf("missing required dependency: App")
}
// ...
}
Pointer Receivers
Use pointer receivers for services and adapters:
func (ts *TracerService) StartEventListener(...) error { ... }
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { ... }
Value Objects
Immutable types with validation constructors:
type BatchSize int
const (
MinBatchSize BatchSize = 1
MaxBatchSize BatchSize = 10000
DefaultBatchSize BatchSize = 1000
)
func NewBatchSize(size int) (BatchSize, error) {
if size < int(MinBatchSize) || size > int(MaxBatchSize) {
return 0, fmt.Errorf("%w: must be between %d and %d", ErrInvalidBatchSize, MinBatchSize, MaxBatchSize)
}
return BatchSize(size), nil
}
func (b BatchSize) Int() int { return int(b) }
Entity Pattern
Entities encapsulate state and expose it through methods:
type Subscriber struct {
name string
batchSize BatchSize
waitTime WaitTime
createdAt time.Time
active bool
}
// Read-only accessors
func (s *Subscriber) Name() string { return s.name }
func (s *Subscriber) BatchSize() BatchSize { return s.batchSize }
func (s *Subscriber) IsActive() bool { return s.active }
Bubble Tea v2 Patterns
- Model:
internal/adapter/ui/model.go - Update:
internal/adapter/ui/messages.go- message handlers - View:
internal/adapter/ui/main_screen.go,welcome.go, etc. - Styles:
internal/adapter/ui/styles/styles.go
import (
tea "charm.land/bubbletea/v2"
"charm.land/bubbles/v2/viewport"
"charm.land/lipgloss/v2"
)
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { ... }
func (m *Model) View() tea.View { ... }
func (m *Model) Init() tea.Cmd { ... }
CGO / Oracle Code
When changing Oracle dequeueing or CGO code, keep Go and C sides aligned across:
internal/adapter/storage/oracle/oracle_adapter.gointernal/adapter/storage/oracle/dequeue_ops.cinternal/adapter/storage/oracle/dequeue_ops.h
File Organization
internal/
├── adapter/
│ ├── config/ # Settings loader
│ ├── storage/
│ │ ├── boltdb/ # BoltDB implementations
│ │ └── oracle/ # Oracle/ODPI-C implementations
│ └── ui/ # Bubble Tea TUI
├── app/ # Application entry point
├── core/
│ ├── domain/ # Entities, value objects, errors
│ └── ports/ # Repository interfaces
├── service/ # Business logic services
└── updater/ # Self-update functionality
Key Files for Reference
cmd/omniview/main.go- Composition rootinternal/core/domain/subscriber.go- Entity patterninternal/core/domain/errors.go- Sentinel errorsinternal/core/ports/repository.go- Interface definitionsinternal/adapter/ui/model.go- Bubble Tea model
Local Storage
- BoltDB database:
omniview.bolt(created on first run) - Stores: database connection settings, subscriber config, permissions
- Delete
omniview.boltand restart to switch databases
Testing
- Run all tests:
make test - Run package tests:
go test -v ./internal/core/domain - Run with coverage:
go test -v -cover ./...
context-mode — MANDATORY routing rules
You have context-mode MCP tools available. These rules are NOT optional — they protect your context window from flooding. A single unrouted command can dump tens of kilobytes of data into context and waste the entire session.
Think in Code — MANDATORY
When you need to analyze, count, filter, compare, search, parse, transform, or process data: write code that does the work via context-mode_ctx_execute(language, code) and console.log() only the answer. Do NOT read raw data into context to process mentally. Your role is to PROGRAM the analysis, not to COMPUTE it. Write robust, pure JavaScript - no npm dependencies, only Node.js built-ins (fs, path, child_process). Always use try/catch, handle null/undefined, and ensure compatibility with both Node.js and Bun. One script replaces ten tool calls and saves 100x context.
BLOCKED commands — do NOT attempt these
curl / wget — BLOCKED
Any shell command containing curl or wget will be intercepted and blocked by the context-mode plugin. Do NOT retry.
Instead use:
context-mode_ctx_fetch_and_index(url, source)to fetch and index web pagescontext-mode_ctx_execute(language: "javascript", code: "const r = await fetch(...)")to run HTTP calls in sandbox
Inline HTTP — BLOCKED
Any shell command containing fetch('http, requests.get(, requests.post(, http.get(, or http.request( will be intercepted and blocked. Do NOT retry with shell.
Instead use:
context-mode_ctx_execute(language, code)to run HTTP calls in sandbox — only stdout enters context
Direct web fetching — BLOCKED
Do NOT use any direct URL fetching tool. Use the sandbox equivalent. Instead use:
context-mode_ctx_fetch_and_index(url, source)thencontext-mode_ctx_search(queries)to query the indexed content
REDIRECTED tools — use sandbox equivalents
Shell (>20 lines output)
Shell is ONLY for: git, mkdir, rm, mv, cd, ls, npm install, pip install, make (including make build, make test, make run, make lint, make fmt), and go (including go test and similar test/package commands).
Heavy build/test commands are permitted in shell usage for normal CI and development workflows.
For everything else, use:
context-mode_ctx_batch_execute(commands, queries)— run multiple commands + search in ONE callcontext-mode_ctx_execute(language: "shell", code: "...")— run in sandbox, only stdout enters context
File reading (for analysis)
If you are reading a file to edit it → reading is correct (edit needs content in context).
If you are reading to analyze, explore, or summarize → use context-mode_ctx_execute_file(path, language, code) instead. Only your printed summary enters context.
grep / search (large results)
Search results can flood context. Use context-mode_ctx_execute(language: "shell", code: "grep ...") to run searches in sandbox. Only your printed summary enters context.
Tool selection hierarchy
- GATHER:
context-mode_ctx_batch_execute(commands, queries)— Primary tool. Runs all commands, auto-indexes output, returns search results. ONE call replaces 30+ individual calls. Each command:{label: "descriptive header", command: "..."}. Label becomes FTS5 chunk title - descriptive labels improve search. - FOLLOW-UP:
context-mode_ctx_search(queries: ["q1", "q2", ...])— Query indexed content. Pass ALL questions as array in ONE call. - PROCESSING:
context-mode_ctx_execute(language, code)|context-mode_ctx_execute_file(path, language, code)— Sandbox execution. Only stdout enters context. - WEB:
context-mode_ctx_fetch_and_index(url, source)thencontext-mode_ctx_search(queries)— Fetch, chunk, index, query. Raw HTML never enters context. - INDEX:
context-mode_ctx_index(content, source)— Store content in FTS5 knowledge base for later search.
Output constraints
- Keep responses under 500 words.
- Write artifacts (code, configs, PRDs) to FILES — never return them as inline text. Return only: file path + 1-line description.
- When indexing content, use descriptive source labels so others can
search(source: "label")later.
Code Review / Collaboration Mode
When the task is a code review, PR review, or iterative collaboration on a patch, the directives "Keep responses under 500 words" and "Write artifacts (code, configs, PRDs) to FILES — never return them as inline text" do not prohibit useful inline review material.
In Code Review / Collaboration Mode, reviewers may return inline diffs, multiple per-file comments, fuller explanations, and short code snippets or patch blocks when needed to make review feedback actionable. Large generated artifacts should still be written to files when practical, but review feedback should not be constrained in ways that weaken the quality or completeness of the review.
lean-ctx
lean-ctx is active — the MCP tools replace native equivalents. Full rules: LEAN-CTX.md (open on demand — do not auto-load).