Changelog¶
Only user-visible changes are listed here. For the full commit log see the gitea repo (internal) or the GitHub mirror for public releases.
v0.21.1 — Per-skill LLM overrides, KB source-tier lifecycle, NetBox CSV sync¶
Status: in progress (post-rc4, prepping for tag).
Features¶
- Per-skill LLM overrides. Each
SKILL.md/AGENT.mdmay now carry an optionalllm:block with any subset ofmodel,temperature,max_tokens,base_url,model_provider,num_ctx,num_predict. Missing keys fall through to the globalapi.json.llm.*default. No profile indirection — single fall-through chain. Used in-tree by: sim,investigate,learner→temperature: 0.0(deterministic output)core/memory_curator→max_tokens: 4096(R102 HITL is short)analyzer(no override) — inherits global 32K- Global
max_tokensraised 16000 → 32768. gemma4:31b nothink can produce long structured tables/reports without truncation. Override per-skill if needed (memory_curator already does the opposite). - Source-tier KB lifecycle (
dev_docs/79). Every*.guide.yamlcarries asource_tierfield (vendor/platform/team/user). Priority + weight derived from the tier, not hand-set. - R102 conversational commits land at
source_tier: user(priority 3, weight 0.83) — operator-spoken rules can't outrank architectural invariants by accident - Schema v1 YAML still loads (default =
usertier with backward-compat for explicitpriority:field) - New CLI:
olav kb remove <intent> --reason "..."(tombstone YAML + LanceDB delete +kb_audit/<ts>_remove_<intent>.yamlrow),olav kb show <intent>,olav kb list-guides --tier <name> kb_audit/git-trackable audit chain. Every KB-mutating action (R102 commit,kb remove, NetBox push) drops onekb_audit/<iso-ts>_<verb>_<intent>.yamlrow withaction / intent / actor / timestamp / body_sha256+ outcome counters. Distinct fromaudit.duckdb— git-tracked so the change record survives independent of the runtime DB.olav userCLI. Friendly aliases forolav admin add-user/....olav user create <name>requires the Linux user to exist (pwd.getpwnam(name)) by default — OLAV's user model is aligned to the OS, no parallel identity. Token hash + salt stored, plaintext shown once. Override Linux check with--no-verifyfor containers.- Collection-time credential redaction (
olav.core.redaction.scrub, ADR-0008). Two-layer pipeline scrubs passwords / SNMP communities / BGP MD5 keys / IPSec PSK / TACACS / RADIUS shared secrets out of collected network config before it lands inaudit.duckdbor exported datasets, while keeping IP / hostname / ASN / topology intact so diff and diagnostic logic still work. - Collection layer:
olav.core.redaction.scrubwraps netconan (Batfish team, ~50 KB pure Python; 55 built-in sensitive-item regex + 5213 reserved words; per-workspace.redaction_saltchmod 600). Wired intonetops_init/run.py:_collect_cmd(collection boundary) andAuditEventRecorder.record_message(defense-in-depth for chat/LLM text). Replacement marker:netconanRemovedN. - Enterprise gate layer:
audit_recorder.redact_sensitive(5-pattern regex producing[REDACTED]) drives Layer 1 ofaudit_dataset_export.redact_audit_runand runs again at gate-check time as a final escape detector. - Configuration:
api.json.redaction.{enabled, anon_ip, extra_sensitive_words, extra_reserved_words}+OLAV_REDACTION=0env-var kill-switch. Install viapip install 'olav[redaction]'to pullnetconan>=0.13; without it OLAV still operates but Layer 1 fails open with a WARNING. - 16 governance tests in
tests/governance/test_redaction.pycover Cisco / Junos / salt management / fail-open semantics / idempotency. - NetBox CSV sync chain (
dev_docs/71Ch10). Three-phase workflow decoupling read (netops) from write (services) via a CSV intermediate: olav --agent netops "/export_netbox_csv"— produces NetBox-shaped CSV fromnetops.devices(column mapping innetops/guides/netbox_csv_export.guide.yaml)olav --agent services "/import_netbox_csv"— dry-run validates shape, writesexports/reports/netbox_import_dry_run.mdolav --agent services "/import_netbox_csv --write --endpoint ... --token ..."— actual POST to a running NetBox, 5-step idempotent lookup-or-create chain (site → manufacturer → device-type → device-role → platform → device); writeskb_audit/row per push
Fixes¶
- Audit tables populate from the CLI again. v0.20.3 flipped
OLAV_MIDDLEWARE_MODEdefault tomiddleware; the CLI invoke path never bound anOlavRunContexttoastream_events, soAuditMiddleware._get_context()returned None and silently no-op'd every tool call. Plusrecord_run_startwas called withoutthread_idso thesessionsUPSERT never fired. Both fixed: CLI now mirrors the API server's context-binding pattern, and athread_id=session_id or run_idis threaded through every turn. Net effect:audit_runs / sessions / audit_events / audit_messages / audit_tool_callsall populate after a single tool-using turn. reasoning_effort: minimalno longer sent. Ollama OpenAI-compat strictly validates this field and accepts onlyhigh / medium / low / max / none. Dropped — the siblingchat_template_kwargs.enable_thinking=falsealready handles the qwen3 / gemma4 nothink path.olav skill installrefuses to overwrite platform-owned workspaces. Domain-package installs (e.g.olav-netops) that carried a dev-mirror ofaudit/would silently clobber the platform's bundled audit/ onolav skill install. Now guarded by_PLATFORM_OWNED = {core, audit, services}skip list with a--force-overwriteescape./netops_initingest gate. Stage 4 now distinguishes "SSH collected" from "DB ingest" and prints❌ FAILED at the ingest stagewith non-zero exit when the staging JSON loaded 0 rows despite successful SSH collection. Previously printed✅ Network initialization completeeven when ingest erred.- 5 SQL view schema guides shipped (
netops/guides/sql_schema_*.guide.yaml) documenting BGP / OSPF / interface / route / device-and-topology view column names + worked examples. AutoRecall surfaces them on schema-discovery queries; gemma4 nothink lands first-try SQL instead of column-name trial-and-error. olav usersubparser added. Previously CLI had only the more verboseolav admin add-userpath;olav user create / list / token / revokeare the canonical user-facing form.- Platform audit workspace bundled into the wheel. Pre-v0.21.1
pip install olav==0.19.0 && olav initproduced only 2 agents (core+services); the audit/ workspace existed in dev but wasn't in the wheel's data path. Fresh install now ships 3 platform agents (audit / core / services).
Migration¶
- No flag-day. Schema v1
*.guide.yamlfiles continue to load, treated assource_tier: userwith a deprecation warning at prime time. Migrate at your leisure; the v2 form isschema_version: 2+ an explicitsource_tier:field. - R102 commits are demoted to
usertier. If you were relying on operator-spoken rules outranking platform guides, that no longer happens. Promote via git PR (edit the YAML tosource_tier: teamand commit through the normal review path). - Lab / CAB content moved out.
lab/sub-agent + CAB workflow + TCF schema demo + fault-injection scripts now live inolav-ent. The platform-base runsheet (dev_docs/71) drops former Ch7 + Ch8; the enterprise runsheet picks them up.
v0.21.0 — WebUI agent routing + service lifecycle hardening¶
Status: in progress (rc4 latest at time of writing).
Fixes¶
- Web GUI: agent dropdown now actually switches the running graph.
Pre-rc2 the FastAPI server kept a single
_agent_instancesingleton; clicking "ops" in the dropdown only re-tagged audit events but still executed the core graph.get_agent()is now a per-assistant_idcache; five agents coexist without cross-contamination. POST /reloadreturns 200 again. rc2 replaced the agent singleton with a cache dict but forgot to update the/reloadhandler; every reload raisedNameError. Handler now iterates the cache, best-effort- closes each agent, and clears state.- Audit in middleware mode sees run_id. v0.20.3 flipped
OLAV_MIDDLEWARE_MODEdefault tomiddleware; the web server never attached anOlavRunContexttoastream_events, soAuditMiddlewarehad norun_idto record against — every web request ran without audit. Fixed by wiring context through in both modes. - Thread + agent binding persists across page refresh. WebUI now
writes
currentThreadIdand each thread'sagentIdtolocalStorage; F5 restores state fully. corepinned first in/agents. Installing olav-netops adds 4 workspaces that all sort beforecorealphabetically, so the WebUI dropdown was auto-selectingauditas the default. Server now forcescoreto index 0.- Service lifecycle pins spawned processes to the workspace.
Pre-rc4
uvicorn/ the agent daemon / the syslog receiver derived their PID + log paths from a module-levelPROJECT_ROOTfrozen at module-import time. When olav was launched from inside another repo with apyproject.toml, the spawned processes silently inherited the wrong cwd and read the wrongusers.duckdb— every login 401'd. Resolution is now cwd-based, anchored on the.olav/marker, and re-resolved on every call;Popen(..., cwd=str(workspace_root))is passed explicitly. olav service start --allworks on a fresh wheel install. Not a bug — arg order isolav service <action> --all, which was always correct — but the demo runsheet examples have been re-verified.olav skill install <path>still works via a v0.21.0-rc4 deprecation shim. The singularskilldispatcher was removed in v0.20.3; the shim forwards verbatim toolav agent installand prints a one-line warning. See CLI reference for the migration note.
New in rc4¶
scripts/sync_netops_workspace.py— sync the platform-vendored.olav/workspace/ops/copy with the authoritativeolav-netops/.olav/workspace/ops/tree. Default direction: root → olav-netops;--reversepulls the other way;--checkis the CI drift guard.
v0.20.3 — deepagents migration complete (P7 final)¶
olav skill installsubcommand removed. Useolav agent install. (v0.21.0-rc4 adds a deprecation shim for back-compat; see above.)OLAV_MIDDLEWARE_MODEdefault flipped tomiddleware. The legacy callback plugins are still installable viaOLAV_MIDDLEWARE_MODE=callbackfor one release cycle whileAuditMiddlewareproves itself.parse_subcommand_argssweeping into 7 verbs. Shared helper for quoted/empty/--argparse edge cases.workspace_discovery.pyconsolidated. Three duplicate scanners merged into one; all consumers (CLI, web/agents, TUI) go through the same code path.
v0.20.2 — P1 + P2 + P6 cutover¶
- Native TUI (via
langgraph devsubprocess) is now default, replacing the in-process overlay.OLAV_TUI_MODE=overlayrolls back to the v0.19.x path for emergency cases. - Tool-loader auto-discovers
.deepagents/agents/<name>/tools/*.pyand.deepagents/agents/<name>/skills/<skill>/tools/*.pyat startup. - v0.20 workspace layout migration available via
olav migrate v0_20_layout(idempotent +--dry-run).
v0.20.1 — P3 middleware migration¶
AgentMiddlewaresubclasses for audit / guardrails / memory-capture / memory-recall / uks-capture, parallel with the callback plugin path.OLAV_MIDDLEWARE_MODEenv var selects.
v0.20.0 — P5 graph factory + olav agent install¶
olav agent install <path>introduced as the public install verb.olav skill installstill works (same dispatcher under the hood); this release is the start of the rename.graph_factory.build_graph()internal API for constructing the LangGraph perassistant_id— foundation for the per-id cache that landed in v0.21.0-rc2.
v0.19.0 — last pre-deepagents release¶
See DEMO_RUNSHEET (historical).