vulgarian
v0.3.0
Published
Incremental log analysis as validated JSONL with rotating model CLI enrichment
Maintainers
Readme
Vulgarian
Vulgarian watches a growing log file and emits a bounded, versioned stream of JSON observations. Deterministic parsers run for every batch; installed model CLIs can then enrich successive batches in a Claude → Codex → Grok rotation. The same validated data drives an offline browser UI or any JSONL-aware TUI.
log file → complete-line tailer → deterministic parsers → rotating model CLI
↓
JSONL | latest JSON | HTTP/SSE | browser/TUIQuick start
npm install
node .\bin\vulgarian.js .\server.logJSONL observations go to stdout. Human-readable status goes to stderr, and the
browser UI is served on http://127.0.0.1:2025. The UI maps metric series to
locally served Chart.js charts and tables, tracked variables to a key/value
table, and events or diagnostics to typed tables.
Useful modes:
# Deterministic extraction only; no model receives log contents.
node .\bin\vulgarian.js .\server.log --providers none
# Append JSONL to a file and atomically replace a latest-snapshot file.
node .\bin\vulgarian.js .\server.log --jsonl .\observations.jsonl --snapshot .\latest.json
# Analyze all complete content present at startup, using bounded reads.
node .\bin\vulgarian.js .\server.log --once --no-server --from-start --providers none
# Machine-clean stdout for a TUI; diagnostics remain on stderr.
node .\bin\vulgarian.js .\server.log --no-server --jsonl - | your-tuiRun node .\bin\vulgarian.js --help for every option.
Built-in parsing
Every nonempty scheduled batch is parsed without a model. The deterministic passes recognize:
- JSON Lines fields such as
timestamp,level,message, numeric metrics, and primitive facts; - common ISO timestamps and
TRACE/DEBUG/INFO/WARN/ERROR/FATALlevels in text logs; key=valuetokens, including numbers, booleans, strings, and obvious units such asms,%, and bytes;- stable metric series across repeated keys, severity counts, source byte offsets, truncation, and file replacement.
Input is buffered by complete line, preserves split UTF-8 characters, and is bounded independently from the model cadence. A slow model does not overlap another model call; newly arrived lines are coalesced for the next batch.
Model rotation
At startup Vulgarian resolves default commands from absolute PATH
directories, then safely probes those absolute executables with --version.
Available providers rotate once per analysis batch in stable order:
| Provider | Commands | Fast default model |
| --- | --- | --- |
| Claude | claude | fable |
| Codex | codex | gpt-5.3-codex-spark |
| Grok | grok, then agent fallback | grok-build |
Override models with --model-claude, --model-codex, and --model-grok, or
the VULGARIAN_CLAUDE_MODEL, VULGARIAN_CODEX_MODEL, and
VULGARIAN_GROK_MODEL environment variables. The former PEACOCK_* names
remain supported as fallbacks. Restrict discovery with, for example,
--providers claude,codex.
Prompts never appear in command-line arguments and shell execution is disabled. Claude and Codex read stdin; Grok uses its documented headless prompt-file mode with a private temporary file that is removed after each run. Provider runs use isolated temporary working directories and have time and output limits. Claude tools are disabled, Codex runs read-only without user config, and Grok tools/web search/subagents are disabled. Invalid JSON, schema errors, timeouts, unavailable authentication, and nonzero exits become structured diagnostics; deterministic data and the last good accumulated values remain.
Each model is explicitly asked to extract every evidenced key/value variable
into bounded facts entries with stable keys. The Tracked Variables panel shows
their latest value, update time, and source; repeated numeric variables may also
be returned as chartable metric series.
An installed CLI can still be unauthenticated. In that case it stays in the rotation and reports a provider diagnostic until it is authenticated or excluded.
JSONL observation contract
Each line is one complete schemaVersion: 1 observation. Script and model
observations use exactly the same envelope:
{
"schemaVersion": 1,
"kind": "observation",
"id": "session-id:2",
"sequence": 2,
"generatedAt": "2026-07-18T12:00:01.000Z",
"source": {
"path": "C:\\logs\\server.log",
"generation": "0",
"fromOffset": 120,
"toOffset": 240,
"lineCount": 3,
"byteCount": 120
},
"generator": {
"kind": "model",
"name": "claude",
"provider": "claude",
"model": "fable",
"status": "ok",
"durationMs": 412
},
"summary": "Three healthy requests completed.",
"metrics": [
{
"id": "latency_ms",
"label": "Latency Ms",
"unit": "ms",
"points": [{ "at": "2026-07-18T12:00:00.000Z", "value": 12.5 }]
}
],
"facts": [{ "key": "service", "value": "api" }],
"events": [
{ "at": "2026-07-18T12:00:00.000Z", "level": "info", "message": "ready" }
],
"diagnostics": []
}The latest-snapshot file and /api/v1/snapshot contain the accumulated,
bounded form of these observations. /api/v1/events publishes the same
snapshots over Server-Sent Events. Consumers should reject unknown
schemaVersion values.
Startup and output semantics
- Default: inspect the most recent 64 KiB, aligned to complete lines.
--from-start: begin at byte zero, still using bounded reads.--from-end: ignore content that already exists.- JSONL files are append-only so sessions remain inspectable.
--snapshotwrites a complete temporary file and atomically renames it.- The HTTP server binds
127.0.0.1unless explicitly configured otherwise.
Data handling
Logs often contain credentials or private data. Deterministic mode keeps log
contents local. Enabling model providers sends each selected batch through the
corresponding CLI and may transmit it to that provider's service. Use
--providers none for sensitive logs that must remain local.
Development
npm test
npm pack --dry-runThe automated suite uses fixture child processes and never makes paid model requests.
