Commit Graph
17 Commits
Author SHA1 Message Date
Hugh KaznowskiandClaude Sonnet 5 c77404ba4e Resolve tickets 067-069: named sessions, MCP server, embedded SKILL.md
Adds a sessions/<name>.json registry (068) so a running ottyl instance can
be discovered by name; an `ottyl mcp --session <name>` subcommand (067)
that starts a short-lived MCP server over stdio (via the official rmcp
SDK), proxying query_logs/declare_param/declare_metric/create_dashboard/
add_panel/get_dashboard tool calls onto the existing HTTP API; and a
SKILL.md (069), embedded into the binary and served at GET /SKILL.md, that
documents how an agent connects to and drives a running instance.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1ZJ3SrayzLzVndhVq9BmS
2026-09-06 13:57:30 +01:00
Hugh Kaznowski 1a481d374b Auto derived format 2026-09-06 01:20:17 +01:00
Hugh KaznowskiandClaude Sonnet 5 3cef6dc8ae Remove unused tower-http dependency (ticket 029)
Audited every entry in Cargo.toml and webapp/package.json against actual
usage. tower-http was declared but never referenced in src/ (no ServeDir,
CorsLayer, or other tower_http usage) — it was only pulled in transitively
via reqwest anyway, so it's dead weight as a direct dependency. All other
Cargo.toml and package.json entries have live usage (including include_dir,
which looked unused via grep but is required transitively by the
fs_embed::fs_embed! macro, and tailwindcss, which is pulled in via
@import "tailwindcss" in src/index.css rather than a JS import).

cargo test (143 passed) and webapp npm run build both pass after pruning.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:50:54 +01:00
Hugh KaznowskiandClaude Sonnet 5 dd3320812c Add alert rules with FilterBar-based triggers and ntfy delivery (tickets 017-019)
Adds AlertRule/AlertCondition/AlertSink models with CRUD persisted on
Settings (mirroring CssEntry's shape), per-line trigger evaluation hooked
into the engine's ingest path (Immediate/Threshold/NewValue/Ratio
conditions), and best-effort ntfy delivery spawned off the ingest hot path.

Design notes:
- Alert queries reuse FilterBar syntax but only support the
  regex()/sequence/timestamp subset (no metric[param] comparisons), since
  resolving those would require a full bucket rescan per alert per ingested
  line rather than cost proportional to new logs.
- Ratio's zero-denominator case skips evaluation for that line rather than
  treating the ratio as infinite.
- NewValue's seen-value set is in-memory only and does not survive a
  restart, matching the engine's other non-persisted runtime state.

engine::run now takes a SettingsHandle (moved from api.rs to settings.rs so
engine.rs can depend on it without a circular import) to read the current
alert rules on each ingest.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:30:14 +01:00
Hugh KaznowskiandClaude Sonnet 5 7694dcf120 Embed webapp into the binary with fs-embed, drop --static-dir
ottyl was requiring webapp/dist to be shipped alongside the binary and
served via ServeDir/ServeFile pointed at a --static-dir CLI arg. Embed
the built webapp at compile time instead, so ottyl is a single
self-contained executable with no runtime static directory dependency.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 16:21:02 +01:00
Hugh Kaznowski ce711ab70e SImplify 2026-09-05 15:39:07 +01:00
Hugh KaznowskiandClaude Sonnet 5 49e8590cf3 Add Metrics API: declare/list params and metrics, query bucket values (ticket 004)
Exposes param/metric declarations and derived bucket data over HTTP:
POST /api/params and POST /api/metrics validate and declare against the
engine, persisting into the active profile (if any) so declarations survive
a restart; GET /api/metrics lists declarations; GET /api/metrics/:name
queries bucket values with label, time-range, sequence, and limit filters.
Adds a new EngineQuery::BucketValues variant that layers this filtering on
top of ticket 003's bucket_values helper.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 13:05:00 +01:00
Hugh Kaznowski 1d3bc0d0d6 Merge branch 'worktree-agent-a63474e92b05425a5'
# Conflicts:
#	Cargo.lock
#	Cargo.toml
2026-09-05 12:46:45 +01:00
Hugh Kaznowski 5b1e2fd5af Merge branch 'worktree-agent-a25bd4a44da9f00b3'
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	src/main.rs
2026-09-05 12:46:31 +01:00
Hugh Kaznowski f08c82c6ea Merge branch 'worktree-agent-a350079668e05192f'
# Conflicts:
#	Cargo.lock
#	Cargo.toml
2026-09-05 12:46:14 +01:00
Hugh KaznowskiandClaude Sonnet 5 202b1dcf9f Add FilterBar query language parser (pest grammar)
Introduces a standalone src/filter_parser.rs module (no dependency on
engine/index types) that parses the FilterBar query language into a
FilterExpr AST using a pest grammar (src/filter_parser.pest). Supports
regex("...") searches, metric_name[param] <op> value comparisons,
reserved sequence/timestamp metrics, and and/or combinators with
correct precedence (and binds tighter than or) and parenthesized
sub-expressions. Evaluation against real log data is left to a later
integration ticket.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 12:45:31 +01:00
Hugh KaznowskiandClaude Sonnet 5 22647620fa Add process-wide Settings model (ticket 008)
Introduces src/settings.rs with a single, process-wide Settings struct
(colour scheme, CSS entries shaped for imported-vs-linked, and a
profiles placeholder for ticket 009), JSON-serialized via serde_json to
keep deps minimal. Default settings path is computed with the
directories crate (ProjectDirs::from("", "", "ottyl")) and overridable
via a new --settings-path CLI arg. Settings::load creates and persists
a default file on first run; Settings::save persists changes.

Wires a single Arc<Mutex<Settings>> into main() and threads it through
api::router as an additive ApiState field for tickets 010/011 to build
on.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 12:42:53 +01:00
Hugh KaznowskiandClaude Sonnet 5 0311eeb712 Add filter_datetime module for FilterBar timestamp parsing
Standalone module (no engine/index/filter-grammar deps) that normalizes
relative humantime (5h, -3m), absolute time-of-day (12:00, resolved to
today in UTC), and full date/RFC3339 literals (2024-01-15,
2024-01-15T12:00:00Z) into a single Timestamp, given a passed-in `now`
for testability. Adds humantime and chrono dependencies.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 12:42:51 +01:00
Hugh KaznowskiandClaude Sonnet 5 f62830d8f7 Add param declaration storage and validation to engine index
Implements the ParamDeclaration slice of the primary index: DataValue::ParamDeclaration
holds a regex + named capture group + MetricPrimitiveKind, stored under
IndexKey::ParamDeclaration{name} between LogParamSplit and ParamMetricSplit.
EngineMessage gains DeclareParam (validates the regex compiles and the capture
group exists before storing, returning a clear error otherwise) and
RemoveParamDeclaration; EngineQuery gains ParamDeclarations to list them back out
as ParamDeclarationDto. No API wiring yet (separate ticket).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 12:42:38 +01:00
Hugh Kaznowski 68548911bc Webapp 2026-09-05 12:23:46 +01:00
Hugh Kaznowski 818f8d09ea Update readme and add some deps 2026-09-05 12:12:28 +01:00
Hugh Kaznowski cbdb145f68 Initial readme/spec 2026-09-05 11:58:01 +01:00