This document provides a high-level introduction to the ShellTime CLI system, a DevOps workflow tracking and analysis tool. It covers the system's dual-architecture design (direct CLI mode and daemon-based mode), core subsystems for command tracking and synchronization, AI-powered features, and Claude Code integration capabilities. This overview is intended for developers and DevOps professionals who need to understand the system's architecture before diving into specific subsystems.
For detailed information on:
Sources: README.md1-121 CHANGELOG.md1-10
ShellTime CLI (version 0.1.76) implements a dual-mode architecture that allows operation as either a standalone CLI tool or with a background daemon process for enhanced performance and features.
Binary and package layout → runtime component mapping:
Comparison Table:
| Characteristic | Direct Mode | Daemon Mode |
|---|---|---|
| Implementation | commands/track.go → model/api.go | commands/track.go → daemon/socket.go → daemon/sync_handler.go |
| Latency | ~100ms+ per command | <8ms per command |
| Network blocking | Blocks shell prompt | Non-blocking (async) |
| Encryption | No | Yes (hybrid RSA/AES-GCM) |
| Retry logic | None | Circuit breaker with exponential backoff |
| Background services | None | SyncCircuitBreaker, CCInfoTimer, HeartbeatResync, AICodeOtelServer, CleanupTimer, CCUsage |
| IPC mechanism | Direct HTTP | Unix domain socket (/tmp/shelltime.sock) |
| Setup | shelltime init | shelltime daemon install |
Sources: README.md62-69 cmd/cli/main.go1-113 cmd/daemon/main.go
Function-level data flow through the tracking pipeline:
The tracking system captures shell commands in two phases:
Pre-execution phase:
DoSavePre() writes Command struct to ~/.shelltime/commands/pre.txtShouldExcludeCommand() with config.Exclude regex patternsPost-execution phase:
DoUpdate() writes TrackingMetaData to ~/.shelltime/commands/post.txtflushCount threshold reached (default: 10 commands)Daemon enhancements:
ResolveTerminal() walks PPID chain to identify terminal emulator and multiplexersync_pending.logSources: commands/track.go daemon/socket.go daemon/sync_handler.go
Configuration files are discovered in order: YAML takes precedence over TOML when both exist. The merge strategy applies selective override where only non-zero/non-empty values from higher-priority sources override lower-priority defaults.
Configuration locations:
~/.shelltime/config.yaml~/.shelltime/config.local.yamlSources: docs/CONFIG.md33-67 README.md34-60
Service types, interfaces, and API endpoints for AI features:
The AI subsystem provides three main capabilities:
1. Command Suggestions (commands/query.go)
shelltime q "how to find large files" invokes AIService.Query()sseAIService streams tokens via SSE from /api/v1/ai/command-suggestActionView, ActionEdit, or ActionDeleteconfig.Agent.View/Edit/Delete permission flagsconfig.ShowTips2. History Search (commands/grep.go)
shelltime rg "docker" calls SearchCommand() functionSendGraphQLRequest() with cursor-based paginationSearchCommandEdge results as formatted table or JSON--json flag for programmatic output3. Claude Code Integration
AICodeOtelServer on port 54027 (configurable)
ProcessMetrics() and ProcessLogs() map field names/otel endpointCCInfoTimerService with lazy initialization
gitCache: Per-working-directory git branch and dirty statusanthropicRateLimitCache: 5-hour and 7-day quota utilization (macOS only, 10-min TTL)ccStatuslineCache: Daily cost stats via GraphQLSources: commands/query.go commands/grep.go commands/cc_statusline.go model/ai_service.go daemon/aicode_otel.go daemon/cc_info_timer.go
End-to-end flow with function and type names:
Sources: README.md19 CHANGELOG.md8
The system uses cursor-based incremental sync with configurable batch size:
Sync triggers:
flushCount commands accumulateshelltime sync commandGarbage collection:
shelltime gc command cleans synced data older than gcTime days (default: 14)logCleanup.thresholdMB (default: 100MB)Sources: README.md26 docs/CONFIG.md92-111 CHANGELOG.md441-442
Protection layers:
dataMasking: true)exclude: [".*password.*"])encrypted: true)Sources: README.md106-111 docs/CONFIG.md125-171
When shelltime-daemon is running, the following background services are conditionally initialized based on configuration:
| Service | Implementation | Config Flag | Purpose |
|---|---|---|---|
| Socket Handler | daemon/socket.go | Always on | Unix domain socket IPC at /tmp/shelltime.sock (configurable via socketPath) |
| Sync Circuit Breaker | daemon/sync_handler.go | Always on | Retry logic for API failures with exponential backoff, offline persistence in sync_pending.log |
| Pub/Sub Router | daemon/main.go | Always on | Watermill message bus for inter-service communication |
| Cleanup Timer | daemon/cleanup_timer.go | logCleanup.enabled (default: true) | Daily cleanup of log.log exceeding logCleanup.thresholdMB (default: 100MB) |
| CCUsage Timer | daemon/ccusage_timer.go | ccusage.enabled | Hourly execution of bunx ccusage or npx ccusage --yes to collect Claude Code usage data |
| OTEL gRPC Server | daemon/aicode_otel.go | aiCodeOtel.enabled (default: true) | Receives OTLP data from AI coding tools on aiCodeOtel.grpcPort (default: 54027) |
| Heartbeat Resync | daemon/heartbeat.go | codeTracking.enabled (default: true) | Periodic coding activity heartbeat to track active sessions, offline buffering in heartbeat_pending.log |
| CC Info Timer | daemon/cc_info_timer.go | Lazy start | On-demand cache for statusline data (git info, rate limits, costs), auto-stops after 3-minute inactivity |
Daemon architecture:
socketPath config, default /tmp/shelltime.sock)message.Router for decoupled service communicationsetupDaemon() with conditional initializationResolveTerminal() walks PPID chain to identify terminal emulator and multiplexerSources: daemon/socket.go daemon/sync_handler.go daemon/cc_info_timer.go daemon/aicode_otel.go daemon/heartbeat.go daemon/cleanup_timer.go daemon/ccusage_timer.go daemon/main.go
Setup (commands/cc_install.go):
~/.shelltime/config.yaml:Generated Claude Code settings:
Statusline output (commands/cc_statusline.go):
🌿 main* | 🤖 Opus | 💰 $0.12 | 📊 $3.45 | 🚦 5h:23% 7d:12% | ⏱️ 5m30s | 📈 45%
| Field | Source | Description |
|---|---|---|
| 🌿 Git Branch | gitCache[cwd] (daemon/cc_info_timer.go) | Current branch from .git/HEAD, * if dirty |
| 🤖 Model | input.Model from Claude Code | Current AI model name |
| 💰 Session | input.Cost from Claude Code | Session cost with OSC8 link to session detail page |
| 📊 Daily | ccStatuslineCache GraphQL query | Today's total cost with OSC8 link to coding agent page |
| 🚦 Quota | anthropicRateLimitCache (daemon/cc_info_timer.go) | 5h and 7d rate limit utilization (macOS only, requires Anthropic OAuth), OSC8 link to usage settings |
| ⏱️ Duration | ccStatuslineCache.TotalTime | AI agent session duration with OSC8 link to user profile |
| 📈 Context | input.ContextWindow calculation | (inputTokens + outputTokens) / contextWindow * 100 |
OSC8 clickable links (commands/cc_statusline.go): Uses escape sequence \033]8;;URL\033\\TEXT\033]8;;\033\\ for terminal hyperlinks
Sources: commands/cc_statusline.go commands/cc_install.go daemon/cc_info_timer.go daemon/aicode_otel.go
shelltime qendpoints arraySources: README.md1-7 docs/CONFIG.md309-323
shelltime.xyz/ienableMetrics flagslog (migrated from logrus in v0.1.42)Sources: CHANGELOG.md1-10 CHANGELOG.md462-463 release-please-config.json1-22 .release-please-manifest.json1-3
Refresh this wiki